Skip to content

Commit

Permalink
Multi-line editing and other updates
Browse files Browse the repository at this point in the history
  • Loading branch information
NotTheDr01ds committed Dec 21, 2024
1 parent 767baa8 commit 08ed206
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 154 deletions.
355 changes: 201 additions & 154 deletions book/line_editor.md
Original file line number Diff line number Diff line change
@@ -1,124 +1,212 @@
# Reedline, Nu's Line Editor

Nushell's line editor [Reedline](https://github.com/nushell/reedline) is a
cross-platform line reader designed to be modular and flexible. The engine is
in charge of controlling the command history, validations, completions, hints
and screen paint.
Nushell's line-editor [Reedline](https://github.com/nushell/reedline) is
cross-platform and designed to be modular and flexible. The line-editor is
in charge of controlling the command history, validations, completions, hints,
screen paint, and more.

## Configuration
[[toc]]

### Editing Mode
## Multi-line Editing

Reedline allows you to edit text using two modes: vi and emacs. If not
specified, the default edit mode is emacs mode. In order to select your
favorite you need to modify your config file and write down your preferred
mode.
Reedline allows Nushell commandlines to extend across multiple lines. This can be accomplished using several methods:

For example:
1. Pressing <kbd>Enter</kbd> when a bracketed expression is open.

For example:

```nu
def my-command [] {
```

Pressing <kbd>Enter </kbd> after the open-bracket will insert a newline. This will also occur with opening (and valid) `(` and `[` expressions.

This is commonly used to create blocks and closures (as above), but also list, record, and table literals:

```nu
let file = {
name: 'repos.sqlite'
hash: 'b939a3fa4ca011ca1aa3548420e78cee'
version: '1.4.2'
}
```

It can even be used to continue a single command across multiple lines:

```nu
(
ffmpeg
-i input.mp4
-vf "scale=1280:720,setsar=1:1"
-b:v 1500k
-preset veryfast
-crf 23
-c:a aac
-b:a 192k
-movflags +faststart
-y
output.mp4
)
```

2. Pressing <kbd>Enter</kbd> at the end of a line with a trailing pipe-symbol (`|`).

```nu
ls |
where name =~ '^[0-9]' | # filenames starting with a digit
get name | # get the filenames
mv ...$in ./backups/ # and move to backups folder
```

3. Manually insert a newline using <kbd>Alt</kbd>+<kbd>Enter</kbd> or <kbd>Shift</kbd>+<kbd>Enter</kbd>.

This can be used to create a somewhat more readable version of the previous commandline:

```nu
ls
| where name =~ '^[0-9]' # filenames starting with a digit
| get name # get the filenames
| mv ...$in ./backups/ # and move to backups folder
```

::: tip
It's possible that one or both of these keybindings may be intercepted by the terminal application or window-manager. For instance, Windows Terminal (and most other terminal applications on Windows) assign <kbd>Alt</kbd>+<kbd>Enter</kbd> to expand the terminal to full-screen. If neither of the above keybindings work in your terminal, you can assign a different keybinding to:

```nu
event: { edit: insertnewline }
```

See [Keybindings](#keybindings) below for more details.

:::

4. Pressing <kbd>Ctrl</kbd>+<kbd>O</kbd> opens the current commandline in your editor. Saving the resulting file and exiting the editor will update the commandline with the results.

## Setting the Editing Mode

Reedline allows you to edit text using two modes — Vi and Emacs. If not
specified, the default mode is Emacs. To change the mode, use the
`edit_mode` setting.

```nu
$env.config = {
...
edit_mode: emacs
...
}
$env.config.edit_mode = 'vi'
```

#### Default Keybindings

Each edit mode comes with the usual keybinding for vi and emacs text editing.

Emacs and Vi Insert keybindings

| Key | Event |
| ----------- | --------------------- |
| Esc | Esc |
| Backspace | Backspace |
| End | Move to end of line |
| End | Complete history hint |
| Home | Move to line start |
| Ctr + c | Cancel current line |
| Ctr + l | Clear screen |
| Ctr + r | Search history |
| Ctr + Right | Complete history word |
| Ctr + Right | Move word right |
| Ctr + Left | Move word left |
| Up | Move menu up |
| Up | Move up |
| Down | Move menu down |
| Down | Move down |
| Left | Move menu left |
| Left | Move left |
| Right | History hint complete |
| Right | Move menu right |
| Right | Move right |
| Ctr + b | Move menu left |
| Ctr + b | Move left |
| Ctr + f | History hint complete |
| Ctr + f | Move menu right |
| Ctr + f | Move right |
| Ctr + p | Move menu up |
| Ctr + p | Move up |
| Ctr + n | Move menu down |
| Ctr + n | Move down |

Vi Normal keybindings

| Key | Event |
| ------- | ------------------- |
| Ctr + c | Cancel current line |
| Ctr + l | Clear screen |
| Up | Move menu up |
| Up | Move up |
| Down | Move menu down |
| Down | Move down |
| Left | Move menu left |
| Left | Move left |
| Right | Move menu right |
| Right | Move right |

Besides the previous keybindings, while in Vi normal mode you can use the classic
vi mode of executing actions by selecting a motion or an action. The available
options for the combinations are:

Vi Normal motions

| Key | motion |
| --- | ----------------- |
| w | Word |
| 0 | Line start |
| $ | Line end |
| f | Right until char |
| t | Right before char |
| F | Left until char |
| T | Left before char |

Vi Normal actions

| Key | action |
| --- | ------------------------------- |
| d | Delete |
| p | Paste after |
| P | Paste before |
| h | Move left |
| l | Move right |
| j | Move down |
| k | Move up |
| w | Move word right |
| b | Move word left |
| i | Enter Vi insert at current char |
| a | Enter Vi insert after char |
| 0 | Move to start of line |
| ^ | Move to start of line |
| $ | Move to end of line |
| u | Undo |
| c | Change |
| x | Delete char |
| s | History search |
| D | Delete to end |
| A | Append to end |

### Command History
This can be changed at the commandline or persisted in `config.nu`.

::: note
Vi is a "modal" editor with "normal" mode and an "insert" mode. We recommend
becoming familiar with these modes through the use of the Vim or Neovim editors
before using Vi mode in Nushell. Each has a built-in tutorial covering the basics
(and more) of modal editing.
:::

## Default Keybindings

Each edit mode comes with common keybindings for Vi and Emacs text editing.

### Emacs and Vi-insert Keybindings

| Key | Event |
| ------------------------------------------ | ----------------------------------- |
| <kbd>Shift</kbd>+<kbd>Enter</kbd> | Insert newline |
| <kbd>Alt</kbd>+<kbd>Enter</kbd> | Insert newline |
| <kbd>Backspace</kbd> | Backspace |
| <kbd>End</kbd> | Move to end of line |
| <kbd>End</kbd> | Complete history hint |
| <kbd>Home</kbd> | Move to line start |
| <kbd>Ctrl</kbd>+<kbd>C</kbd> | Cancel current line |
| <kbd>Ctrl</kbd>+<kbd>L</kbd> | Clear screen |
| <kbd>Ctrl</kbd>+<kbd>R</kbd> | Search history |
| <kbd>Ctrl</kbd>+<kbd>→</kbd> (Right Arrow) | Complete history word |
| <kbd>Ctrl</kbd>+<kbd>→</kbd> (Right Arrow) | Move word right |
| <kbd>Ctrl</kbd>+<kbd>←</kbd> (Left Arrow) | Move word left |
| <kbd>↑</kbd> (Up Arrow) | Move up |
| <kbd>Ctrl</kbd>+<kbd>P</kbd> | Move up |
| <kbd>↑</kbd> (Up Arrow) | Move menu up |
| <kbd>Ctrl</kbd>+<kbd>P</kbd> | Move menu up |
| <kbd>↓</kbd> (Down Arrow) | Move down |
| <kbd>Ctrl</kbd>+<kbd>N</kbd> | Move down |
| <kbd>↓</kbd> (Down Arrow) | Move menu down |
| <kbd>Ctrl</kbd>+<kbd>N</kbd> | Move menu down |
| <kbd>←</kbd> (Left Arrow) | Move left |
| <kbd>Ctrl</kbd>+<kbd>B</kbd> | Move left |
| <kbd>←</kbd> (Left Arrow) | Move menu left |
| <kbd>Ctrl</kbd>+<kbd>B</kbd> | Move menu left |
| <kbd>→</kbd> (Right Arrow) | Move right |
| <kbd>Ctrl</kbd>+<kbd>F</kbd> | Move right |
| <kbd>→</kbd> (Right Arrow) | Move menu right |
| <kbd>Ctrl</kbd>+<kbd>F</kbd> | Move menu right |
| <kbd>→</kbd> (Right Arrow) | History-hint complete |
| <kbd>Ctrl</kbd>+<kbd>F</kbd> | History-hint complete |
| <kbd>Alt</kbd>+<kbd>F</kbd> | History-hint complete one word |
| <kbd>Alt</kbd>+<kbd>←</kbd> (Left Arrow) | History-hint complete one word less |

### Vi-insert Keybindings

| Key | Event |
| -------------- | ------------------------ |
| <kbd>Esc</kbd> | Switch to Vi-normal mode |

### Vi-normal Keybindings

| Key | Event |
| ------------------------------------------- | ------------------- |
| <kbd>Ctrl</kbd>+<kbd>C</kbd> | Cancel current line |
| <kbd>Ctrl</kbd>+<kbd>L</kbd> | Clear screen |
| <kbd>↑</kbd> (Up Arrow) | Move menu up |
| <kbd>↑</kbd> (Up Arrow) | Move up |
| <kbd>↓</kbd> (Down Arrow) | Move menu down |
| <kbd>↓</kbd> (Down Arrow) | Move down |
| <kbd>←</kbd> (Left Arrow) | Move menu left |
| <kbd>←</kbd> (Left Arrow) | Move left |
| <kbd>→</kbd> (Right Arrow) | Move menu right |
| <kbd>→</kbd> (Right Arrow) | Move right |
| <kbd>Ctrl></kbd>+<kbd>→</kbd> (Right Arrow) | Move right one word |
| <kbd>Ctrl></kbd>+<kbd>←</kbd> (Left Arrow) | Move left one word |

As with Vi, many motions and actions can be combined with an optional count in normal-mode. For example, <kbd>3</kbd><kbd>d</kbd><kbd>w</kbd> deletes the next three words.

### Vi-normal Motions

| Key | Motion |
| -------------------------------------- | --------------------------------------------- |
| <kbd>w</kbd> | Move to beginning of next word |
| <kbd>e</kbd> | Move to end of current or next word |
| <kbd>b</kbd> | Move to beginning of current or previous word |
| <kbd>0</kbd> | Move to start of line |
| <kbd>$</kbd> | Move to end of line |
| <kbd>h</kbd> | Move left |
| <kbd>l</kbd> | Move right |
| <kbd>j</kbd> | Move down |
| <kbd>k</kbd> | Move up |
| <kbd>f</kbd>+\<char\> | Move right to \<char\> |
| <kbd>t</kbd>+\<char\> | Move right to before \<char\> |
| <kbd>Shift</kbd>+<kbd>F</kbd>+\<char\> | Move left to \<char\> |
| <kbd>Shift</kbd>+<kbd>T</kbd>+\<char\> | Move left to after \<char\> |

### Vi-normal Actions

| Key | Action |
| ----------------------------- | -------------------------------------------------- |
| <kbd>d</kbd> | Delete |
| <kbd>Shift</kbd>+<kbd>D</kbd> | Delete to end of line |
| <kbd>p</kbd> | Paste after current character |
| <kbd>Shift</kbd>+<kbd>P</kbd> | Paste before current character |
| <kbd>i</kbd> | Enter Vi insert-mode (append) at current character |
| <kbd>Shift</kbd>+<kbd>I</kbd> | Enter insert-mode at beginning of line |
| <kbd>a</kbd> | Append after current character |
| <kbd>Shift</kbd>+<kbd>A</kbd> | Append to end of line |
| <kbd>0</kbd> | Move to start of line |
| <kbd>^</kbd> | Move to start of line |
| <kbd>$</kbd> | Move to end of line |
| <kbd>c</kbd> | Change |
| <kbd>r</kbd> | Replace |
| <kbd>s</kbd> | Substitute character(s) |
| <kbd>x</kbd> | Delete character |
| <kbd>u</kbd> | Undo |

## Command History

As mentioned before, Reedline manages and stores all the commands that are
edited and sent to Nushell. To configure the max number of records that
Expand All @@ -136,50 +224,9 @@ Reedline should store you will need to adjust this value in your config file:
}
```

### Customizing your Prompt

Reedline prompt is also highly customizable. In order to construct your perfect
prompt, you could define the next environment variables in your config file:

```nu
# Use nushell functions to define your right and left prompt
def create_left_prompt [] {
let path_segment = ($env.PWD)
$path_segment
}
def create_right_prompt [] {
let time_segment = ([
(date now | format date '%m/%d/%Y %r')
] | str join)
$time_segment
}
$env.PROMPT_COMMAND = { create_left_prompt }
$env.PROMPT_COMMAND_RIGHT = { create_right_prompt }
```

::: tip
You don't have to define the environment variables using Nushell
functions. You can use simple strings to define them.
:::

You can also customize the prompt indicator for the line editor by modifying
the next env variables.
## Customizing the Prompt

```nu
$env.PROMPT_INDICATOR = "〉"
$env.PROMPT_INDICATOR_VI_INSERT = ": "
$env.PROMPT_INDICATOR_VI_NORMAL = "〉"
$env.PROMPT_MULTILINE_INDICATOR = "::: "
```

::: tip
The prompt indicators are environment variables that represent the
state of the prompt
:::
The Reedline prompt is configured using a number of environment variables. See [Prompt Configuration](./configuration.md#prompt-configuration) for details.

## Keybindings

Expand Down
1 change: 1 addition & 0 deletions book/quick_tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ Nushell commands can extend across multiple lines for readability. The above is
ls | sort-by size | reverse | first | get name | cp $in ~
```

See Also: [Multi-line Editing](./line_editor.md#multi-line-editing)
:::

The first three lines are the same commands we used in the second example above, so let's examine the last three:
Expand Down
1 change: 1 addition & 0 deletions book/thinking_in_nu.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ echo 50
echo 60
```

See Also: [Multi-line Editing](./line_editor.md#multi-line-editing)
:::

In all of the above:
Expand Down

0 comments on commit 08ed206

Please sign in to comment.