rnoth / edna

ed-like text editor
MIT License
16 stars 0 forks source link

Visual + line editor #2

Open ghost opened 7 years ago

ghost commented 7 years ago

I am having a strange idea:

It would be used like ed, but always with an overview of the lines above the prompt (like the z command), that can scroll with ^[FBUDEY] as in vi. It would be like having a pager always showing the result on top of ed.

As you enter ed ranges, the line numbers get highlighted (right when you type them). Maybe working on multiple ranges, separated by a ; like 2,13;32;34s/$/;/.

Maybe it could even only display the selected lines (and not the not-selected around) with a few lines of context (like git diff), skipping lines in-between. Then, while finished, focusing on the dot afterward (with highlighted line number), showing all the lines around.

This would be like vis multiple cursors + structural regex, without the cursors but with ranges instead.

I am keeping this in mind for when I will have some more time.

rnoth commented 7 years ago

^[FBUDEY]

this took me a good minute to parse

As you enter ed ranges, the line numbers get highlighted (right when you type them). Maybe working on multiple ranges, separated by a ; like 2,13;32;34s/$/;/.

this is an idea that's occured to me before. if you dig deep into edna's getaddr() function, you'll notice it's very complex for what should be something very simple (parsing some number, maybe with an infix expression or two). in fact, the backend in quite wasteful, using a big bitarray (take a look at the mess that is set.c) for storing single line-numbers.

but I had two goals with the design of getaddr() et al.

in ed, you cannot do 4+/foo/ (selecting the first line containing `foo' after line four), nor can you do /foo/ - /bar/ (selecting the first occurance of `bar' before the next occurance of `foo'. this is useful, however, so I want to add the capability

this is closely related to your syntax for composing addresses, but I avoid the ; because I have other uses for it (I'm torn between using it as a command seperator, as in sh (s/foo/bar/; /quux/d; w fn) or for macro invocation (;mac arg1 arg2))

instead, I planned to use the logical operators, in set-theoretic way

sel1 & sel2 -- intersection; selects every line in both sel1 and sel2

sel1 | sel2 -- union; selects every line in either sel1 or sel2 (this my answer to your ; proposal)

sel1 ^ sel2 -- symmetric difference; selects every line in sel1 and set2, but not both

the standard ed operators would be overloaded,

sel + line would shift each line in sel by line, which can be a number or pattern, sel + 1 shifts each line in sel forward one line, sel + /pat/ shifts each line to the next occurance of /pat/

sel - line behaves opposite +, which should not need too much explaining

sel1,sel2 produces a selection with every line between the end of sel1 and the begining of sel2 is selected, along with the union of sel1 and sel2.

Maybe it could even only display the selected lines (and not the not-selected around) with a few lines of context (like git diff), skipping lines in-between. Then, while finished, focusing on the dot afterward (with highlighted line number), showing all the lines around.

this is actually a very interesting idea. the lack of context is one thing that make ed somewhat awkward to use for quick edits.

"a visual editor without a cursor"

there is another, related idea I've had, which this reminded me of, which is being able to pass around arbitrary strings in the command mode of a vi-clone. the way I concieved of it was pressing the ' (single-quote) key and typing some stuff, then single quote again. this could then be passed to other commands, like counts or text-objects in vi{,m,s}.

you could take this idea farther, I considered a screen editor where the commands look just like ed'. (e.g. type15, and line fifteen is scrolled too and highlighted. type,18and the next three lines are highlighted. typesand little dialog pops up. typepatand as you type the pattern, each occurance matching what you typed is highlighed in a different color. hit return, and typerepl` and each sub-seletion is replaced with it.

the invocation of s would have to be changed, since it's a bit awkward decision where g and 2 and other options appended to end of the command in ed would go in this setup.

etc

I should mention I haven't been working on edna much lately. I had been working on overhauling the parser, and after three aborted attempts, I gave up. I do have a edna-next project sitting on my hard-drive, but it doesn't have much of note going for it.

of course, I mention this because you've inspired me to try another dive back into the codebase. I'll what I can do the polish it up today.

in a slightly related bit, I'll mention the ideas that have been piling up. I'll accept criticisms, particularly pointing out weird edges or possible limitations. other ideas are also appreciated

this is a small one, but it is implicit in most of my following snippets, so I'll be explicit essentially, it's that 1 + 1 s/this/that is the same as 1+1s/this/that

most commands implicitly work on lines. if they can be re-worked to instead work on whatever selection is handed to them, it opens the possibility of sub-line selections. this is the syntax I've considered:

/naet/v s/ae/ea

v would have an antonym in l, but it would be the default (or perhaps this could be a config.h switch?)

related to the above, is giving ordinary regex options.

/pat/i would be case-insensitive matching

/pat/g would be global search, like g/pat/ in ed

g would define macros. do g mac s/this/that, and then mac is equivalent to s/this/that

there would also be vi-style macros

: g mac
: s/this/that
: /foo/
: d
/* ... */
: g
recorded macro `mac'

g would be to escape macro-mode, so no nested macro-defintion.

macros also would not effect the actual state of the buffer until they're played. the rationale for this is simply that I try to choose the default behavior that's easy to reverse -- it'd be simple to write a g macro to define a macro and play it, but harder to write a macro to define one and then reverse every single side effect that could have been invoked, which may need to be revised if the set of potental side-effects grows or the behavior of undo changes

have vi-style registers, without th restriction to single-latter names

d reg move to register reg

y reg copy to register reg

x reg paste form register reg

"reg s/this/that do a substitution on the contents of a register

p reg print the contents of a register

special registers:

"" - anonymous register

"/ - search register, contains last search

"_ - black hole register

": - command register, contains last executed command

"? - help registers. contains last error message

when I said I was making a text editor in #unix, one of the first reactions was that undo-trees would be a pain to implement.

edna should support more than a single level of undo, but I'm not sure what the redo command should be called. r is for read files. R, perhaps.

some ideas

4u undo the last change to line 4

u 4 undo four times

"reg u undo register action. this could emulate emacs' kill rings, perhaps

h - could be a `history' command instead of help?

e.g.

h /this/ - search history for `this'

!cmd would execute cmd in a shell

!cmd % would write the buffer to a tmpfile, then call the cmd on it

/start/,/end/ !cmd would call cmd with the selection /start/,/end as standard input

end

and that's most of my notes. it feels kinda disingenuous to talk about things I haven't coded yet, but I wanted someone else's thoughts on them

ghost commented 7 years ago

Hi,

Maybe I will not have time enough to answer this weekend, so a quick answer for now.

I read it all, I liked the way of adresing the ranges and the way you can combine them.

I did try sam(1) yesterday, and it really looks like what I was proposing, and also have some of the features you talked about (commposing ranges, excluding some... se structural regular expressions). This could be of some help for the design.

Sam is an ed-like editor after all... And it has less lines of code than either vis(1) or ex-vi(1) (the original one).

Sorry for the ^[FBUDEY].

ghost commented 7 years ago

`getaddr()'

It looks like AST generation and exploitation. But it is important feature for an editor without a cursor.

set.c - bit array

Well, that just works ! It would be (1 / bits_per_wchar_t) * size_of_the_buffer. If we store the text as WCHAR_T, one bit needed to represent one wchar_t.

There may be implementation, or even whole books on the topic (or small articles).

infix expressions - power of line addresses

I do not know any tool but sam-style expressions, and they may even lack a few features.

syntax of line addresses

Do lines addresses works a bit like evaluation: with expressions evaluated to become ranges, and operators directly acting on ranges? With the range being 'Set' objects.

arbitrary strings in the command

Yes, in the end, why such a gap between vi and ex. That is two different ways to interact with an editor.

this idea farther

In sam, you can scroll the screen, the cursor will not follow. Then you can write somewhere, read elsewhere, and come back at the cursor: it did not move at all. This also makes sense if you work with ranges: there will be too much to fit into the screen.

invocation of s would have to be changed, since it's a bit awkward decision where g and 2 and other options appended to end

sam and vis:

x/pattern/ : To select all occurences of pattern (within active range, so % x/pattern/ to select all pattern in the file, . x/pattern/ for the current line...).

c/replacement/ : Your repl command

d : Delete the selection: not only replacement available.

working on edna

I am lacking time too. Hope there will be some holidays ahead (I am still a student).

sub-line selection

/naet/v s/ae/ea

In sam:

, x/naet/ x/ae/ c/ea/

macros

This is macro done right! There is no difference between function definition and macro. As edna is line-oriented, macro could be like an 'edna script' recorded to a new command name. Is that what you meant?

registers

With then "reg command a command on a range outside of the main buffer (on a register buffer).

I imagined it would be nice to store the registers as plain text files:

~/.cache/edna/registers/register1
~/.cache/edna/registers/register2
~/.cache/edna/registers/_ -> /dev/null
~/.cache/edna/registers/search
~/.cache/edna/registers/:
~/.cache/edna/registers/?

Maybe this could make registers hidden buffers also open in the editor. Making undos on the registers as hard as undo for plain files to implement.

things I haven't coded yet

I imagine: the earlier I change my decisions, the less work I have to change.

I quote sam too often. :-P But it is close to these ideas. Maybe it could be even be interesting to share the syntax with it, and extend it. This would make transition between vis/sam/edna simple. Other commands could still be added, like what vis(1) did.

Sam has a text-only version: sam -d.

Command language explained: http://sam.cat-v.org/ > Documentation and Manuals Structrual regular expressions: http://doc.cat-v.org/bell_labs/structural_regexps/

ghost commented 7 years ago

I first thought about displaying the ranges as they got typed, (e.g.: right after the , in 12,14 s/foo/bar/).

Maybe this is a bit too much. Maybe vis-style could be better:

Entering a range, if you type another command, nothing is changed on screen. If you type enter, the range is displayed on screen, and you can continue typing the command, which will act on the current selection.

[EDIT] I was repeating myself.