Skip to content

Commit

Permalink
Nearing a stable release now, so some less clean features are remade …
Browse files Browse the repository at this point in the history
…in this

release to be easier to maintain in a stable manner forward.

- New command documentation.
- Update the README.md and add more in-repo documentation.
- Add proper macro support under ':', with support for arguments and tests to
  verify its behaviour. This also changed the macro methods on `Ed` struct.
- Make '!' forbid selection, instead require using '|' for filtering text
  through a shell command.
- Cut down on less meaningful variant commands to make it easier to add more
  diverse features without breaking the command language in the future.
  - 'J' has been removed, as it is functionally equivalent or inferior to
    `<selection>!fmt -w 80`.
  - 'L' and 'N' have been combined into a 'P' command, which uses the flags
    themselves to toggle their defaults in a single command. This allows adding
    more flags with toggle-able defaults in the future without needing more
    commands.
  - 'M' and 'T' removed. As you already need to give an index to move/copy to
    you might as well just give that index - 1 to prepend.
- Started testing with insight into undo history, so undo snapshot creation is
  now testable and verified.
- Made some exported structs impossible to create aside from constructors, to
  enable maintaining compability by just keeping the same constructors as the
  member variables change.
- Limit nesting depth when running commands than run commands. (Mainly to
  prevent macros from doing infinite recursion.)
  • Loading branch information
David Sid Olofsson committed Oct 24, 2023
1 parent 30810de commit 41c352f
Show file tree
Hide file tree
Showing 56 changed files with 1,294 additions and 554 deletions.
180 changes: 180 additions & 0 deletions COMMANDS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# Command notation
Short representations to keep this documentation concise.

(Note that the descriptions of what a shorthand should be replaced by will use
the previously presented shorthands.)

- `(x)` An optional `x`.
- `x|y` `x` or `y`, and not both.
- `[abc]` Any combination of `a`, `b` or `c`, but no duplicates.
- `.` An index. Can be any of
- `.` Interpreted as the start of the currently viewed selection in most cases
but as the end of the currently viewed selection when given to an appending
command (or as end of a selection).
- `<positive integer>` Interpreted as index of a line.
- `$` Interpreted as index of the last line, or 0 there are no lines.
- `'<char>` Interpreted as index of first line tagged with
the given character.
- `/<pattern>/` Interpreted as index of nearest following
line matching the given regex pattern.
- `?<pattern>?` same as above but nearest preceeding.
- `(<any index>)+(<positive integer>`) Interpreted as the other index plus
the positive integer. If no other index given treated as `.`. If no integer
given treated as `1`.
- `(<any index>)-(<positive integer>)` Same as above but minus.
- `<nothing>` Is generally equivalent to `.` if an index is accepted.
(Exceptions exist, as noted by the commands below.)
- `.,.` A selection. Can be any of
- `.` Any lone index, which selects only that line. Errors if no line exists
at the index.
- `.,.` Two indices separated by a comma, which selects both those lines and
all lines between. Errors if any of the selected lines doesn't exist.
(Empty indices are interpreted as index `1` and `$` respectively.)
- `.;.` Two indices separated by a semicolon, which selects both those lines
and all lines between them. Erors if any of the selected lines doesn't
exist.
(Empty indices are interpreted as index `1` and `.` respectively.)
- `<nothing>` Interpreted as the currently viewed selection. Use the `=`
command to print the currently viewed selection.
- `/` A separator. Can be any character (except newline), but for each command
invocation you must use the same separator. Traditionally `/` or `_`.


# Printing flags:
All the printing commands and most other commands accept *printing flags*. These
are `[pnl]`.
- `p` prints the selection after the command.
- `n` prints the selection after the command with line numbers (or without, if
the `N` default is on).
- `l` prints the selection after the command with `$` before newlines, `--->`
instead of tabs and `$$` instead of `$`. (Or not, if the `L` default is on).


# Printing commands
Commands to print buffer contents.

- `<nothing>` Prints as many lines after the currently selected as you have
selected. (Intended so you can print the first 20 lines and press enter to do
so again.)
- `(.,.)[pnl]` Print given selection.
(`p` is used to distinct the invocation from `<nothing>` when not giving an
explicit selection, it doesn't affect the printing.)
- `(.,.)z(<positive integer>)[pnl]` Prints the given number of lines following
the given selection with the given printing configuration.


# Basic editing commands
Simple commands to edit the text in the editing buffer.

- `(.)a[pnl]` Append text after given line. Enters input mode terminated by '.'.
After running the inserted text is selected.
- `(.)i[pnl]` Insert text before given line. Otherwise same behaviour as `a`.
- `(.,.)d[pnl]` Cut the selected lines into (editor internal) clipboard. Selects
the nearest following line if any, otherwise the nearest preceeding. If
deleting all of the buffer there is no selection after running, wherefore
doing so with print flags will error.
- `(.,.)y[pnl]` Copy the selected lines into (editor internal) clipboard.
Selects the given selection.
- `(.)x[pnl]` Paste the contents of the (editor internal) clipboard after given
index. Selects the pasted lines.
- `(.)X[pnl]` Same as `x` except pastes before the given index.
- `(.,.)j[pnl]` Joins the selected lines into a single line (simply removes the
newline characters, everything else is kept). Selects the resulting line.


# Combined editing commands
Commands that kind of combine two basic editing commands.

- `(.,.)c[pnl]` Change out the selected lines. Enters input mode terminated by
'.'. Equivalent to `.,.d` followed by `i`. Selects the inserted text if any
given, if none given behaves like `d`.
- `(.,.)C[pnl]` ONLY IF *initial_input_data* FEATURE IS ENABLED!!!
Behaves just like `c` except the selected lines are put into the input field,
allowing you to edit them directly.
- `(.,.)m(.)[pnl]` Move selected lines directly to given index. If no index
given it moves to the end of the buffer by default. Kind of equivalent to
`.,.d` followed by `x.`, except it doesn't affect the (editor internal)
clipboard. Selects the moved lines in their new location.
- `(.,.)t(.)[pnl]` Copy selected lines directly to given index. If no index
given it copies to the end of the buffer by default. Kind of equivalent to
`.,.y` followed by `x.`, except it doesn't affect the (editor internal)
clipboard. Selects the copied lines in their new location.


# File and shell commands
Commands to read and write to the surrounding system, both directly to/from
files and using shell commands.

Note that most of these commands accept a shell command (prefixed by `!`). If
such is given it will be run as a child process and read from (stdout)/written
to (stdin) in place of the file path otherwise accepted. The last shell command
run is saved (no matter its success or failure) and can be re-run if no command
is given. (For commands taking a path or a command you still need to give a `!`
to indicate to run a command.)

- `e(<path>|!<shell command>)` Replace buffer contents with data read from
given path/command. If no path/command given uses the default path. Sets the
default path to given path if path given, leaves default path unchanged
otherwise. Selects all lines in the buffer after reading in.
If the buffer contains unsaved edits aborts with error, capitalize `e` to `E`
to override the warning.
- `(.)r(<path>|!<shell command>)` Read in data from give path/command and
insert it after the given index. If no index given defaults to inserting after
current selection. If no path or shell command given uses default path.
Selects the added lines after running.
- `wq` Save the whole buffer to the default path and quit the editor. Errors if
it is given a selection other that the whole buffer.
- `(.,.)w(<path>|!<shell command>)` Write selected lines to given
path/command. If no selection given writes the whole buffer. If no path given
writes to default path. If selection was explicitly given selects that,
otherwise leaves selection unchanged. If selection was not given and a path
was given that path is set as default path.
- `(.,.)W(<path>)` Append the selected lines to the given path. If no path
given appends to default path. If no selection given appends whole buffer.
Selects the appended lines after running.
- `(.,.)|(<shell command>)` Transform selection via given shell command. If no
selection is given the default selection is used. The original line data is
placed in the clipboard and the new lines are selected.
- `!(<shell command>)` Run the given shell command interactively.


# Batch editing commands
More advanced commands to apply the same or similar changes many times.

- `(.,.)s(/<regex>/<substitution>/[gpnl])` Replaces text within selection that
matches the regex with the substitution. If the `g` flag is given replaces all
occurences of the regex, if not only the first is replaced. Selects the
selection, whatever size it ends up being after replacing.
- `(.,.)g/<regex>/<command>(/)` Runs commands on all lines matching the regex.
If the last separator is given the commands are run immediately, if not it
enters input mode terminated by the separator. The matching line is selected
(using default selection, the commands will run them on the matched line) and
run in the order given. Doesn't set selection, but the commands run through
it do.
- `(.,.)v/<regex>/<command>(/)` Inverse of `g`. Runs given commands on lines
that **don't** match the given regex.
- `(.,.)G/<regex>/` Interactive version of `g`. For each matching line prints it
and enters input mode terminated by the separator. The given commands are run
on that line, same as `g`.
- `(.,.)V/<regex>/` Inverse of `G`. Does the same for lines that don't match the
given regex.
- `(.,.):<macro-name>(<space separated arguments>)` Set selection to given
selection (if any) and run given macro. Same as `g` it doesn't set selection,
but the commands in the macro will probably do so.


# Status commands
For printing information about and changing editor state.

- `help` Print a short list of commands.
- `Help` Print this documentation.
- `q` Quits the editor. If the buffer contains unsaved edits aborts with error.
Capitalize 'q' to 'Q' to override and quit anyways.
- `h` Print last previous error.
- `H` Toggle between printing the error or only `?` when an error occurs.
- `(.,.)=` Prints selection. If none given prints the current selection.
- `(.,.)#(<anything>)` If no selection is given it does nothing, to enable
inlining comments in scripts. If a selection is given that selection is set
without printing (this is the only way to do this, as even no command prints).
- `f(<path>)` If no path given prints the default path, otherwise sets the given
path as default path.
38 changes: 38 additions & 0 deletions COMMANDS_SHORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Basic editing commands:
- `a/i` Insert lines after/before index.
- `d` Cut lines into clipboard.
- `y` Copy lines into clipboard.
- `x/X` Paste clipboard after/before index.
- `j` Join selection into one line.

# Combined editing commands:
- `A/I` As `a`/`i` but join first/last line with indexed line.
- `c` Replace selection with input. Like `d` and `i`.
- `C` As `c` but with selection as initial input.
- `m` Move selection to index. Like `d` and `x`.
- `t` Copy selection to index. Like `y` and `x`.

# File and shell commands:
- `e` Open given file.
- `r` Read from given file to given index.
- `w` Write to given file.
- `W` Append to given file.
- `|` Pipe data through given command.
- `!` Run given shell command.

# Batch editing commands:
- `s` Search and replace
- `g/v` Run commands on matching/not-matching lines.
- `G/V` Interactively run commands on matching/not-matching lines.
- `:` Run macro.

# Status commands:
- `help` Print this help section.
- `Help` Print commands documentation.
- `q` Quit the editor, warns on unsaved changes.
- `Q` Quit ignoring unsaved changes.
- `h` Print last occured error.
- `H` Toggle printing error or `?` on error.
- `=` Print current selection.
- `#` Do nothing (start of comment)
- `f` Print default file, or replace if one given.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "add-ed"
description = "Embeddable pure rust editor based on ED"
version = "0.11.0-alpha"
version = "0.11.0"
repository = "https://github.com/sidju/add-ed"
readme = "README.md"
categories = ["text-editors"]
Expand Down
45 changes: 45 additions & 0 deletions POTENTIAL_FEATURES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Plugin support, `@`:
Using a specific Macro trait and a `HashMap<&str, &mut dyn Macro>`.

Intended to be compiled in with the editor, but if someone could do something
clean and *stable* with dynamic library loading I'd be open to it.

Not implemented yet since shell interaction and macros can mostly emulate the
behaviour without running external code within the editor process. But since
plugins could have significant performance advantages (as they don't need to
pipe all the data out and in again, breaking all the Rc links preventing
duplication of line data) this is intended to be implemented eventually.

# Multi-buffer support (as part of UI), `b`:
Allow opening a file as a different buffer. The arguments for this command would
be handed into a specific feature enabled `UI` method, allowing the UI to create
or switch to another instance of `add_ed::Ed`.

For some examples of how this could work look into how `qed`, `sam` and `vim`
handle multiple open files. This feature should fit all those approaches.

Not implemented yet as I (sidju) don't have any interest in this feature. If you
want to use this feature, tell me and give me two weeks.

# Command failover into UI or other object:
A more flexible way to extent functionality than plugins under `@`. Every time a
command isn't recognized (more or less) the partially parsed command data would
be handed into a "`CommandExtender`" or similar, which can then hold
implementations for any command not defined in add-ed itself.

Not implemented since I (sidju) don't need it, this might be a bit complex to
implement. Further it might be better to keep non-`add-ed` commands more
clearly separate. If you want to use this feature please provide an example
implementation and settle in for some discussion, so the feature is implemented
in a clean way that fits your use-case.

# More variant commands:
There are loads of potential variations on existing commands. I (sidju) have
decided to be restrictive on what I add initially, so that any further built-in
commands can be decided upon through discussion with users later.

Though some variants were added and have implementations ready in the codebase
none of them are enabled, as they were found to not be that useful. Any further
commands will need to be significant distincts (not just prepend to an index
instead of appending, but using start of selection instead of end of selection
is sufficiently distinct if relevant).
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,9 @@ from GNU Ed. This strives to be a list of these changes.
- 'g' and related commands take command list in input mode (with the regex
separator as terminator instead of '.').
(Also, the 'I' suffix for case insensitive matching isn't implemented)
- '!' accepts a selection and will pipe those lines through the given shell
command, replacing them with the output. Without a selection it acts as in GNU
Ed.
- '#' accepts a selection and will set state.selection to it without printing
anything. This is added to be able to set selection without printing.

## Early APIs
Currently it is based on both my experiences with hired and the hired repo specifically (a manual fork, so it has the whole history).
This may well mean the API is ill suited for your use. If that is the case I'd be happy to make some changes to make it more general.

In line with this, the help text is often a bit outdated. I'll get to that, and
improve on the error type, before the first stable release.

## Core concepts
### The selection:
The original ED keeps track of the last line you interacted with and defaults to working on that for most commands.
Expand All @@ -42,12 +32,10 @@ or a GUI frontend implementing the UI trait.
Perfect for commenting out a single line or adding a forgotten ;.
- 'C' command, acts as 'c' but hands out previous value to the Ui's input method.
This enables you to edit the selection instead of replacing it (depends on UI).
- 'N' and 'L' commands, toggle the default print conf. Line numbers and escapes respectively.
- 'P' command, toggle the default print flags.
- ':' command, runs the macro with the name given as argument (whitespace trimmed).
Macro execution behaves like 'g' execution. 'q' or error returns early.
- 'J' command, joins all lines in selection and then splits them so they all are
shorter than the number of columns given after 'J'. Splits on word boundaries.
It doesn't understand indentation, but improvement PRs are very welcome.
- '|' command, pipes selection through given shell command.

## Feature flags:
### local_io:
Expand All @@ -58,3 +46,19 @@ Add 'C' command. This modifies the UI trait.

## Attributions:
This project is essentially built upon the regex crate, as regex is the heart of Ed.

## Contributing:
There are two main contributions welcomed as of now.

1. Adding tests. Though core uses for command are tested, more behaviours should
be validated. If you have the time, add test cases that validate that:
- Commands behave as [COMMANDS.md](COMMANDS.md) states.
- Commands behave same as in GNU Ed, unless otherwise documented in the
*Differences from GNU Ed* section above.
2. Checking off ToDo:s. Look into the [TODOS.md](TODOS.md) file, pick a task to
do and go wild. You can add a PR to prevent others from working on the same
task (mark it as WIP until relevant to review).
3. Create issues for undocumented or unexpected behaviour.
4. Request support for your use-cases. Create a feature request issue for what
you need. (Look into [POTENTIAL_FEATURES.md](POTENTIAL_FEATURES.md) to see if
a similar feature is prepared and if so note it in the feature request.)
28 changes: 28 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# 0.11.0
Nearing a stable release now, so some less clean features are remade in this
release to be easier to maintain in a stable manner forward.

- New command documentation.
- Update the README.md and add more in-repo documentation.
- Add proper macro support under ':', with support for arguments and tests to
verify its behaviour. This also changed the macro methods on `Ed` struct.
- Make '!' forbid selection, instead require using '|' for filtering text
through a shell command.
- Cut down on less meaningful variant commands to make it easier to add more
diverse features without breaking the command language in the future.
- 'J' has been removed, as it is functionally equivalent or inferior to
`<selection>!fmt -w 80`.
- 'L' and 'N' have been combined into a 'P' command, which uses the flags
themselves to toggle their defaults in a single command. This allows adding
more flags with toggle-able defaults in the future without needing more
commands.
- 'M' and 'T' removed. As you already need to give an index to move/copy to
you might as well just give that index - 1 to prepend.
- Started testing with insight into undo history, so undo snapshot creation is
now testable and verified.
- Made some exported structs impossible to create aside from constructors, to
enable maintaining compability by just keeping the same constructors as the
member variables change.
- Limit nesting depth when running commands than run commands. (Mainly to
prevent macros from doing infinite recursion.)

# 0.10.0
- Add a first sketch of undo/redo. Feedback on behaviour is requested in the
"Undo behaviour" issue (#3) on github
Expand Down
Loading

0 comments on commit 41c352f

Please sign in to comment.