Reedline, Nu's Line Editor
Nushell's line-editor 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.
Multi-line Editing
Reedline allows Nushell commandlines to extend across multiple lines. This can be accomplished using several methods:
Pressing Enter when a bracketed expression is open.
For example, you can type this command over three lines:
def my-command [] { print "Hello from my-command" }Pressing Enter after the open-bracket will insert a newline instead of running the command. 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:
let file = { name: 'repos.sqlite' hash: 'b939a3fa4ca011ca1aa3548420e78cee' version: '1.4.2' }It can even be used to continue a single command across multiple lines:
Example
( tar -cvz -f archive.tgz --exclude='*.temp' --directory=../project/ ./ )Pressing Enter at the end of a line with a trailing pipe-symbol (
|).ls | where name =~ '^[0-9]' | # Comments after a trailing pipe are okay get name | mv ...$in ./backups/Manually insert a newline using Alt+Enter or Shift+Enter.
This can be used to create a somewhat more readable version of the previous commandline:
ls | where name =~ '^[0-9]' # Files starting with a digit | get name | mv ...$in ./backups/Tips
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 Alt+Enter to expand the terminal to full-screen. If neither of the above keybindings work in your terminal, you can assign a different keybinding to the
insertnewlineedit (event: { edit: insertnewline }).See Edit Type below for an example, and Keybindings for more details.
Pressing Ctrl+O 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 three modes — Emacs, Vi and Helix. If not specified, the default mode is Emacs. To change the mode, use the edit_mode setting, which accepts emacs, vi or helix.
$env.config.edit_mode = 'vi'This can be changed at the commandline or persisted in config.nu.
Note
Vi is a "modal" editor with a "normal" mode, an "insert" mode and a "visual" 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.
Helix mode follows the Helix editor, which is also modal but "selection-first": you first select text with a motion, and then act on the selection. See Helix Mode below.
The cursor shape can be set separately for each mode with $env.config.cursor_shape, which has the keys emacs, vi_insert, vi_normal, vi_visual, helix_normal, helix_select and helix_insert. Each accepts block, underscore, line, blink_block, blink_underscore, blink_line or inherit (keep the terminal's cursor shape):
$env.config.cursor_shape.vi_insert = 'line'
$env.config.cursor_shape.vi_normal = 'block'Default Keybindings
Each of the three edit modes is built from a few shared sets of keybindings plus its own additions. The tables below follow Reedline's keybinding reference for the Reedline version that ships with Nushell. Run keybindings default to list the built-in keybindings of every mode.
Some keys are a fallback chain: Reedline tries each step and takes the first one that applies. The tables write those with "otherwise". For example, → accepts a history hint if one is showing, otherwise moves right in an open menu, otherwise moves the cursor right.
Keybindings Added by Nushell
Nushell adds the following keybindings on top of Reedline's defaults. They are defined in $env.config.keybindings, so you can change or remove them, and they apply in every edit mode:
| Key | Action |
|---|---|
| Tab | Open the completion menu, otherwise select the next item, otherwise complete |
| Shift+Tab | Select the previous item in the menu |
| Ctrl+Space | Open the IDE-style completion menu, otherwise select the next item, otherwise complete |
| Ctrl+R | Open the history menu (this replaces Reedline's Ctrl+R history search) |
| Ctrl+Q | Search the history |
| Ctrl+X | Show the next page of an open menu |
| Ctrl+Z | Show the previous page of an open menu, otherwise undo |
| F1 | Open the help menu |
$env.config.keybindings | select name modifier keycode
# => ╭───┬────────────────────────────┬──────────┬─────────╮
# => │ # │ name │ modifier │ keycode │
# => ├───┼────────────────────────────┼──────────┼─────────┤
# => │ 0 │ completion_menu │ none │ tab │
# => │ 1 │ ide_completion_menu │ control │ space │
# => │ 2 │ completion_previous │ shift │ backtab │
# => │ 3 │ history_menu │ control │ char_r │
# => │ 4 │ next_page_menu │ control │ char_x │
# => │ 5 │ undo_or_previous_page_menu │ control │ char_z │
# => │ 6 │ help_menu │ none │ f1 │
# => │ 7 │ search_history │ control │ char_q │
# => ╰───┴────────────────────────────┴──────────┴─────────╯Common Keybindings
Four sets of keybindings are shared between the edit modes:
| Set | Emacs | Vi insert | Vi normal / visual | Helix insert | Helix normal / select |
|---|---|---|---|---|---|
| Control | yes | yes | yes | yes | yes |
| Navigation | yes | yes | yes, rebound in visual | yes | yes, rebound in select |
| Editing | yes | yes | no | yes | no |
| Selection | yes | yes | yes | yes | yes |
A mode without the editing set rebinds Backspace and Delete itself. Modes may also override single keys within a set; those keys are noted in the mode's own tables.
Control Keybindings
| Key | Action |
|---|---|
| Esc | Close an open menu and clear the selection; in Vi and Helix modes, also switch mode |
| Ctrl+C | Cancel the current input |
| Ctrl+D | Delete the character under the cursor, or exit Nushell when the line is empty |
| Ctrl+L | Clear the screen, keeping the current input |
| Ctrl+R | Search the history (Nushell binds this key to the history menu instead, see above) |
| Ctrl+O | Open the current input in your editor (see $env.config.buffer_editor) |
Navigation Keybindings
| Key | Action |
|---|---|
| ↑, Ctrl+P | Move up in an open menu, otherwise move one line up, walking back through the history from the first line |
| ↓, Ctrl+N | Move down in an open menu, otherwise move one line down, walking forward through the history from the last line |
| ← | Move left in an open menu, otherwise move one character left |
| → | Accept a history hint, otherwise move right in an open menu, otherwise move one character right |
| Ctrl+← | Move one word left |
| Ctrl+→ | Accept one word of a history hint, otherwise move one word right |
| Home, Ctrl+A | Move to the start of the line |
| End, Ctrl+E | Accept a history hint, otherwise move to the end of the line |
| Ctrl+Home, Alt+< | Move to the start of the buffer |
| Ctrl+End, Alt+> | Move to the end of the buffer |
On terminals that use the Kitty keyboard protocol, Shift+Alt+, and Shift+Alt+. also work for Alt+< and Alt+>.
Editing Keybindings
| Key | Action |
|---|---|
| Backspace, Ctrl+H | Delete the character to the left |
| Delete | Delete the character under the cursor |
| Ctrl+Backspace, Ctrl+W | Delete the word to the left |
| Ctrl+Delete | Delete the word to the right |
| Shift+Enter, Alt+Enter | Insert a newline without running the input |
| Ctrl+J | Run the input, or insert a newline if it is incomplete |
None of these fill the cut buffer (Emacs mode rebinds Ctrl+W to a cut, so there it does). When Nushell is built with the system-clipboard feature, this set also has Ctrl+Shift+X, Ctrl+Shift+C and Ctrl+Shift+V to cut, copy and paste the selection with the system clipboard.
Selection Keybindings
| Key | Action |
|---|---|
| Shift+←, Shift+→ | Extend the selection by one character |
| Shift+↑, Shift+↓ | Extend the selection by one line |
| Ctrl+Shift+←, Ctrl+Shift+→ | Extend the selection by one word |
| Shift+Home, Shift+End | Extend the selection to the line start or end |
| Ctrl+Shift+Home, Ctrl+Shift+End | Extend the selection to the buffer start or end |
| Ctrl+Shift+A | Select the whole buffer |
Emacs Mode
Emacs mode is the default. It has all four common sets, plus:
| Key | Action |
|---|---|
| Ctrl+B | Move left in an open menu, otherwise move one character left |
| Ctrl+F | Accept a history hint, otherwise move right in an open menu, otherwise move one character right |
| Alt+←, Alt+B | Move one word left |
| Alt+→, Alt+F | Accept one word of a history hint, otherwise move one word right |
| Enter | Run the input, or insert a newline if it is incomplete |
| Alt+Backspace, Alt+M | Delete the word to the left |
| Alt+Delete | Delete the word to the right |
| Ctrl+W | Cut the word to the left |
| Alt+D | Cut the word to the right |
| Ctrl+K | Cut to the end of the line, or join the next line when already at the end |
| Ctrl+U | Cut from the start of the line to the cursor |
| Ctrl+Y | Paste the cut buffer before the cursor |
| Ctrl+T | Swap the two characters around the cursor |
| Ctrl+Z | Undo (Nushell binds this key to "previous menu page, otherwise undo", see above) |
| Ctrl+G | Redo |
| Alt+U | Uppercase the word under the cursor |
| Alt+L | Lowercase the word under the cursor |
| Alt+C | Capitalize the character under the cursor |
Vi Mode
Vi mode starts in insert mode. Esc switches to normal mode, i and its siblings return to insert mode, and v enters visual mode from normal mode. In visual mode, Esc returns to normal mode; in normal mode it cancels a half-typed command.
An operator waits for a motion, and the motion picks the range the operator acts on: d then w cuts a word. A count can prefix a motion or a command, and counts on an operator and its motion multiply: 2d3w cuts six words.
In every Vi mode, an Alt+<char> chord that isn't bound is read as Esc followed by <char> (the "meta" convention of readline and zsh). For example, Alt+k in insert mode recalls the previous line. This is also how you can use a terminal that doesn't send Alt: press Esc first, then the key.
Vi Insert Mode
Insert mode has all four common sets, plus:
| Key | Action |
|---|---|
| Enter | Run the input, or insert a newline if it is incomplete |
| Esc | Switch to normal mode, moving the cursor back onto the last typed character |
The Emacs cut and case commands (Ctrl+K, Ctrl+U, Ctrl+Y, Ctrl+T, Alt+D, Alt+U, Alt+L and Alt+C) are not bound in insert mode. Because of the meta convention, Alt+u undoes, and Alt+d leaves insert mode and starts a d operator. Ctrl+W deletes the word to the left without cutting it.
Vi Normal Mode
Normal mode and visual mode have the control, navigation and selection sets, but not the editing set. In its place:
| Key | Action |
|---|---|
| Backspace | Move one character left in normal mode; extend the selection one character left in visual mode |
| Delete | Delete the character under the cursor in normal mode; in visual mode, cut the selection like d |
These motions move the cursor in normal mode. In visual mode, they extend the selection instead:
| Key | Motion |
|---|---|
| h, l | Move one character left or right |
| j, k | Move one line down or up, walking through the history at the edge of the buffer |
| w, W | Move to the start of the next word or WORD |
| e, E | Move to the end of the next word or WORD |
| b, B | Move to the start of the previous word or WORD |
| 0 | Move to the start of the line |
| ^ | Move to the first non-blank character of the line |
| $ | Move to the end of the line |
| gg, G | Move to the start or end of the buffer |
| f<char>, F<char> | Move onto the next or previous occurrence of <char> |
| t<char>, T<char> | Move just before the next or previous occurrence of <char> |
| ;, , | Repeat the last f/t/F/T search, forwards or reversed |
A WORD is delimited only by whitespace; a word is also delimited by punctuation. In normal mode, h, j, k and l follow the same fallback chain as the arrow keys: an open menu takes the key first, and l accepts a history hint before it moves.
Normal mode commands:
| Key | Action |
|---|---|
| i, a | Insert before or after the cursor |
| I, A | Insert at the start or at the end of the line |
| o, O | Open a line below or above, and insert |
| v | Enter visual mode |
| x, X | Cut the character under or before the cursor |
| s | Cut the character under the cursor and insert |
| r<char> | Replace the character under the cursor with <char> |
| C | Change to the end of the line, without filling the cut buffer |
| S | Change the whole line |
| D | Cut to the end of the line |
| p, P | Paste the cut buffer after or before the cursor |
| u | Undo |
| ~ | Switch the case of the character under the cursor |
| . | Repeat the last change |
| ? | Search the history and switch to insert mode |
| Enter | Run the input, or insert a newline and switch to insert mode if it is incomplete |
Vi Operators and Text Objects
d, c and y take any motion, and cut, change or copy the range it covers. Doubling an operator applies it to the whole line: dd, cc, yy.
An operator can also take a text object, with i for "inside" or a for "around":
| Object | Selects |
|---|---|
| w, W | A word or WORD |
| b | The enclosing brackets |
| q | The enclosing quotes |
A delimiter works as a text object too: (, ), [, ], {, }, <, >, ", ', ` and $. Either half of a pair does the same thing, so di( is the same as di). All three operators take the inside form; only d and y take the around form.
Vi Visual Mode
Pressing v in normal mode starts visual mode, which selects text as you move the cursor with the motions. Visual mode rebinds the navigation set so each key extends the selection the way its Vi counterpart does: the arrows follow h/j/k/l, Ctrl+←/→ follow b/w, Home/End follow 0/$, and so on. In visual mode, ↑ and ↓ never walk through the history, and history hints are not accepted.
The normal mode commands apply in visual mode too, except for these keys, which act on the selection:
| Key | Action |
|---|---|
| d, x | Cut the selection and return to normal mode |
| X | Cut the selected lines, staying in visual mode |
| c, s | Change the selection and switch to insert mode |
| y | Copy the selection and return to normal mode |
| p, P | Replace the selection with the cut buffer, staying in visual mode |
| u, U | Make the selection lowercase or uppercase, then return to normal mode |
| ~ | Switch the case of the selection, then return to normal mode |
| o, O | Move the cursor to the other end of the selection |
| r<char> | Replace every selected character with <char>, then return to normal mode |
| Esc | Drop the selection and return to normal mode |
Normal mode and visual mode have separate keybinding tables. Keybindings for visual mode use the vi_visual mode name, and bindings for vi_normal don't apply in visual mode.
Helix Mode
With $env.config.edit_mode = 'helix', the line editor follows the Helix editor. A motion carries a selection with it, and a command acts on what is selected. There is no operator-pending state: w selects a word, and d then deletes it.
Helix mode starts in insert mode. Esc switches to normal mode, i and its siblings return to insert mode, and v toggles select mode, where a motion extends the selection instead of replacing it. A count can prefix any key except g.
Insert mode has all four common sets, plus Enter (run the input, or insert a newline if it is incomplete) and Esc (switch to normal mode).
Normal mode and select mode have the control, navigation and selection sets, but not the editing set. In its place:
| Key | Action |
|---|---|
| Backspace | Move one character left in normal mode; extend one left in select mode |
| Delete | Delete the character under the cursor |
| Alt+D | Delete the selection without yanking it |
| Alt+` | Make the selected text uppercase |
As in Vi visual mode, select mode rebinds the navigation set so each key extends the selection like its Helix counterpart, and ↑/↓ never walk through the history.
Motions:
| Key | Action |
|---|---|
| h, l | Move left / right |
| j, k | Move down / up (walking through the history at the buffer's edge) |
| w, b, e | Move to the next word start / previous word start / next word end |
| W, B, E | Move to the next WORD start / previous WORD start / next WORD end |
| f<char>, F<char> | Find the next / previous <char> |
| t<char>, T<char> | Find till the next / previous <char> |
| gh, gl | Go to the start / end of the line |
| gs | Go to the first non-whitespace character of the line |
| gg, ge | Go to the start / end of the buffer |
h, l and the g motions collapse the selection onto the new position, while w, b, e, f and t select the text they move over.
Selection:
| Key | Action |
|---|---|
| x | Select the current line; if it is already selected, extend to the next line |
| % | Select the whole buffer |
| v | Toggle select mode |
| Esc | Collapse the selection in normal mode; leave select mode in select mode |
Changes:
| Key | Action |
|---|---|
| i, a | Insert before / after the selection |
| I, A | Insert at the first non-blank character of the line / at the end of the line |
| o, O | Open a new line below / above the selection |
| d | Delete the selection |
| c | Change the selection (delete it and enter insert mode) |
| y | Yank (copy) the selection |
| p, P | Paste after / before the selection |
| r<char> | Replace the selection with <char> |
| ~ | Switch the case of the selected text |
| ` | Make the selected text lowercase |
| u, U | Undo / redo |
| Enter | Run the input, or insert a newline and switch to insert mode if it is incomplete |
d, y and p return to normal mode, and c switches to insert mode. These Helix keys are not available yet: ;, ,, J, G, X, >, <, the /, n and N search commands, match mode (m), and the multi-cursor commands.
Keybindings for Helix mode use the helix_normal, helix_select and helix_insert mode names. The prompt uses PROMPT_INDICATOR_VI_INSERT in Helix insert mode, and PROMPT_INDICATOR_VI_NORMAL in normal and select mode.
Tips
The selection in Vi visual mode and Helix mode is styled with $env.config.color_config.selection (reverse video by default). $env.config.color_config.selection_cursor styles the character under the cursor inside a selection:
$env.config.color_config.selection = { bg: '#44475a' }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 Reedline should store you will need to adjust this value in your config file:
# in config.nu
$env.config.history.max_size = 1000Note
The history.max_size, history.file_format, history.isolation and history.path settings must be set in config.nu. They can't be changed once the REPL has started. Setting $env.config.history.path to null turns off the history file.
Hints
As you type, Reedline shows a hint in a dimmed color ($env.config.color_config.hints) after the cursor. By default the hint is the most recent matching command from your history. Press → or End to accept the whole hint, or Ctrl+→ to accept one word of it. Set $env.config.show_hints = false to turn hints off.
To compute hints yourself, set $env.config.hinter.closure to a closure. It receives a record with the current line, the cursor position pos and the working directory cwd, and returns the text to show after the cursor, or null for no hint. It can also return a record {hint: string, next_token: string}, where next_token is the part that Ctrl+→ accepts. The closure runs on every keystroke, so keep it fast.
let snippets = ["git status", "git switch -c", "cargo build --release"]
$env.config.hinter.closure = {|ctx|
let match = $snippets | where $it starts-with $ctx.line | first
if ($ctx.line | is-empty) or $match == null {
null
} else {
$match | str substring ($ctx.line | str length)..
}
}Set $env.config.hinter.closure = null to go back to the built-in history hints.
Customizing the Prompt
The Reedline prompt is configured using a number of environment variables. See Prompt Configuration for details.
Keybindings
Reedline keybindings are powerful constructs that let you build chains of events that can be triggered with a specific combination of keys.
For example, let's say that you would like to map the completion menu to the Ctrl + t keybinding (default is tab). You can add the next entry to your config file.
$env.config.keybindings ++= [{
name: completion_menu_ctrl_t
modifier: control
keycode: char_t
mode: emacs
event: { send: menu name: completion_menu }
}]After loading this new config.nu, your new keybinding (Ctrl + t) will open the completion command.
Each keybinding requires the next elements:
- name: A unique name for your keybinding. Assigning to
$env.config.keybindingsmerges the new entries into the existing bindings by name: an entry with the same name and key as an existing binding replaces it, while an entry that reuses a name for a different key is added as another binding and prints aMultiple keybindings share a namewarning. To clear every keybinding, assign an empty list ($env.config.keybindings = []). - modifier: A key modifier for the keybinding. The options are:
- none
- control
- alt
- shift
- shift_alt
- alt_shift
- control_alt
- alt_control
- control_shift
- shift_control
- control_alt_shift
- control_shift_alt
- keycode: This represent the key to be pressed
- mode: emacs, vi_insert, vi_normal, vi_visual, helix_insert, helix_normal or helix_select (a single string or a list. e.g. [
vi_insertvi_normal]) - event: The type of event that is going to be sent by the keybinding. The options are:
- send
- edit
- until
Tips
All of the available modifiers, keycodes and events can be found with the command keybindings list
Tips
The keybindings added to vi_insert mode will be available when the line editor is in insert mode (when you can write text), and the keybindings marked with vi_normal mode will be available when in normal (when the cursor moves using h, j, k or l)
The event section of the keybinding entry is where the actions to be performed are defined. In this field you can use either a record or a list of records. For example, this keybinding sends a single event, which opens the current command line in your editor when you press Alt+E
$env.config.keybindings ++= [{
name: open_editor_alt_e
modifier: alt
keycode: char_e
mode: emacs
event: { send: OpenEditor }
}]and this one sends a list of events, which moves the cursor to the start of the line and inserts sudo there when you press Alt+S
$env.config.keybindings ++= [{
name: prepend_sudo_alt_s
modifier: alt
keycode: char_s
mode: emacs
event: [
{ edit: MoveToLineStart }
{ edit: InsertString, value: "sudo " }
]
}]The first keybinding example shown in this page follows the first case; a single event is sent to the engine.
The next keybinding is an example of a series of events sent to the engine. It first clears the prompt, inserts a string and then enters that value
$env.config.keybindings ++= [{
name: change_dir_with_fzf
modifier: CONTROL
keycode: Char_t
mode: emacs
event: [
{ edit: Clear }
{
edit: InsertString,
value: "cd (ls | where type == dir | each { |row| $row.name} | str join (char nl) | fzf | decode utf-8 | str trim)"
}
{ send: Enter }
]
}]One disadvantage of the previous keybinding is the fact that the inserted text will be processed by the validator and saved in the history, making the keybinding a bit slow and populating the command history with the same command. For that reason there is the executehostcommand type of event. The next example does the same as the previous one in a simpler way, sending a single event to the engine
$env.config.keybindings ++= [{
name: change_dir_with_fzf_host_command
modifier: CONTROL
keycode: Char_y
mode: emacs
event: {
send: executehostcommand,
cmd: "cd (ls | where type == dir | each { |row| $row.name} | str join (char nl) | fzf | decode utf-8 | str trim)"
}
}]Before we continue you must have noticed that the syntax changes for edits and sends, and for that reason it is important to explain them a bit more. A send is all the Reedline events that can be processed by the engine and an edit are all the EditCommands that can be processed by the engine.
Send Type
To find all the available options for send you can use
keybindings list | where type == eventsAnd the syntax for send events is event: { send: <NAME OF EVENT FROM LIST> }.
Tips
You can write the name of the events with capital letters. The keybinding parser is case insensitive
There are three exceptions to this rule: Menu, ExecuteHostCommand and SwitchMode. Those events require an extra field to be complete. The Menu needs the name of the menu to be activated (such as completion_menu or history_menu)
$env.config.keybindings ++= [{
name: history_menu_alt_h
modifier: alt
keycode: char_h
mode: emacs
event: {
send: menu
name: history_menu
}
}]and the ExecuteHostCommand requires a valid command that will be sent to the engine
$env.config.keybindings ++= [{
name: go_home_alt_g
modifier: alt
keycode: char_g
mode: emacs
event: {
send: executehostcommand
cmd: "cd ~"
}
}]and the SwitchMode event needs the mode to switch to. It accepts the same mode names as the keybinding's mode field (such as vi_normal or helix_normal). This keybinding leaves Vi insert mode with Ctrl+G:
$env.config.keybindings ++= [{
name: vi_normal_ctrl_g
modifier: control
keycode: char_g
mode: vi_insert
event: {
send: switchmode
mode: vi_normal
}
}]A SwitchMode event can only switch between the modes of the current edit_mode, so a switch to vi_normal does nothing in Helix mode. A switch to the mode that is already active also does nothing. The older ViChangeMode (with mode: normal, insert or visual) and HelixChangeMode (with mode: normal, insert or select) events are still accepted and work like SwitchMode.
It is worth mentioning that the events list also shows event: { edit: <edit> }, event: { send: list<event> } and event: { until: list<event> }. These are not events that you send by name. They show the other forms that the event field can take: an edit record (the edit type that was mentioned), a list of events that are all sent one after another, and the until type mentioned later.
Edit Type
The edit type sends one of Reedline's edit commands, which change the text of the command line or move the cursor. To list the available options you can use the next command
keybindings list | where type == editsThe usual syntax for an edit is event: { edit: <NAME OF EDIT FROM LIST> }. For example, this keybinding inserts a newline when you press Alt+N, which is useful if your terminal intercepts Alt+Enter and Shift+Enter
$env.config.keybindings ++= [{
name: insert_newline_alt_n
modifier: alt
keycode: char_n
mode: [emacs vi_insert helix_insert]
event: { edit: insertnewline }
}]Some edits in the list are followed by extra fields, such as InsertString value: <string>. Those edits need the extra fields to be fully defined. For example, if we would like to insert a string at the cursor, then you will have to use
$env.config.keybindings ++= [{
name: insert_to_json_alt_j
modifier: alt
keycode: char_j
mode: emacs
event: {
edit: insertstring
value: " | to json"
}
}]or say you want to move right until the next |
$env.config.keybindings ++= [{
name: move_to_pipe_alt_p
modifier: alt
keycode: char_p
mode: emacs
event: {
edit: moverightuntil
value: "|"
}
}]As you can see, these two types will allow you to construct any type of keybinding that you require
Until Type
To complete this keybinding tour we need to discuss the until type for event. As you have seen so far, you can send a single event or a list of events. And as we have seen, when a list of events is sent, each and every one of them is processed.
However, there may be cases when you want to assign different events to the same keybinding. This is especially useful with Nushell menus. For example, say you still want to activate your completion menu with Ctrl + t but you also want to move to the next element in the menu once it is activated using the same keybinding.
For these cases, we have the until keyword. The events listed inside the until event will be processed one by one with the difference that as soon as one is successful, the event processing is stopped.
The next keybinding represents this case.
$env.config.keybindings ++= [{
name: completion_menu_ctrl_t
modifier: control
keycode: char_t
mode: emacs
event: {
until: [
{ send: menu name: completion_menu }
{ send: menunext }
]
}
}]The previous keybinding will first try to open a completion menu. If the menu is not active, it will activate it and send a success signal. If the keybinding is pressed again, since there is an active menu, then the next event it will send is MenuNext, which means that it will move the selector to the next element in the menu.
As you can see the until keyword allows us to define two events for the same keybinding. An event only lets until move on to the next one when it had nothing to do. The menu event does this when a menu is already open, the other menu events (such as menunext) when no menu is open, up and down when there is no line or history entry to move to, left and right at the ends of the line, the history-hint events when there is no hint to accept, and SwitchMode when it can't switch (see Send Type). Most other events always succeed, so the until event stops as soon as it reaches them.
For example, the next keybinding sends a down whenever there is a line or a newer history entry to move to, and only opens the completion menu when there isn't
$env.config.keybindings ++= [{
name: completion_menu_ctrl_t
modifier: control
keycode: char_t
mode: emacs
event: {
until: [
{ send: down }
{ send: menu name: completion_menu }
{ send: menunext }
]
}
}]The SwitchMode event makes one keybinding work in more than one edit mode. The next keybinding uses Ctrl+G to leave insert mode in both Vi and Helix mode: in Vi mode the first event switches to vi_normal, and in Helix mode the first event has nothing to do, so the second one switches to helix_normal
$env.config.keybindings ++= [{
name: leave_insert_mode
modifier: control
keycode: char_g
mode: [vi_insert helix_insert]
event: {
until: [
{ send: SwitchMode, mode: vi_normal }
{ send: SwitchMode, mode: helix_normal }
]
}
}]Removing a Default Keybinding
If you want to remove a certain default keybinding without replacing it with a different action, you can set event: null.
e.g. to disable screen clearing with Ctrl + l for all edit modes
$env.config.keybindings ++= [{
modifier: control
keycode: char_l
mode: [emacs, vi_normal, vi_insert, vi_visual, helix_normal, helix_select, helix_insert]
event: null
}]Troubleshooting Keybinding Problems
Your terminal environment may not always propagate your key combinations on to Nushell the way you expect it to. You can use the command keybindings listen to determine if certain keypresses are actually received by Nushell, and how.
Menus
Thanks to Reedline, Nushell has menus that can help you with your day to day shell scripting. Next we present the default menus that are always available when using Nushell
Menus are configured in $env.config.menus. Assigning to this list merges your entries into the default menus by name, so an entry named completion_menu replaces the default completion menu instead of adding a second one, and $env.config.menus = [] does not remove the default menus.
Each menu sets input_mode, which controls the text that the menu searches:
diff- only the text typed after the menu was activatedcursor_prefix- the line from its start up to the cursorfull_buffer- the whole line, including any text after the cursor
It can also set output_mode, which controls what an accepted suggestion replaces:
suggested_span- the part of the line that the suggestion names (the default)full_buffer- the whole lineextend_to_end- from the start of the suggestion's span to the end of the line
Older configurations use only_buffer_difference instead of input_mode. It still works: true is the same as input_mode: diff, and false is the same as input_mode: cursor_prefix.
By default, erasing text while a menu is open can close the menu. Set $env.config.completions.persistent_menus = true to keep menus open while you edit. The menu then updates its suggestions instead, and only closes when you accept a suggestion or press Esc or Ctrl+C.
Menu Keybindings
When a menu is active, some keybindings change based on the keybinding until specifier discussed above. Common keybindings for menus are:
| Key | Event |
|---|---|
| Tab | Select next item |
| Shift+Tab | Select previous item |
| Enter | Accept selection |
| ↑ (Up Arrow) | Move menu up |
| ↓ (Down Arrow) | Move menu down |
| ← (Left Arrow) | Move menu left |
| → (Right Arrow) | Move menu right |
| Ctrl+P | Move menu up |
| Ctrl+N | Move menu down |
| Ctrl+B | Move menu left |
| Ctrl+F | Move menu right |
Note
Menu direction behavior varies based on the menu type (see below). For example, in a description menu, "Up" and "Down" apply to the "Extra" list, but in a list menu the directions apply to the selection.
Help Menu
The help menu is there to ease your transition into Nushell. Say you are putting together an amazing pipeline and then you forgot the internal command that would reverse a string for you. Instead of deleting your pipe, you can activate the help menu with F1. Once active just type keywords for the command you are looking for and the menu will show you commands that match your input. The matching is done on the name of the commands or the commands description.
To navigate the menu you can select the next element by using tab, you can scroll the description by pressing left or right and you can even paste into the line the available command examples.
The help menu can be configured by modifying the next parameters
$env.config.menus ++= [{
name: help_menu
input_mode: diff # Search is done on the text written after activating the menu
marker: "? " # Indicator that appears with the menu is active
type: {
layout: description # Type of menu
columns: 4 # Number of columns where the options are displayed
col_width: 20 # Optional value. If missing all the screen width is used to calculate column width
col_padding: 2 # Padding between columns
selection_rows: 4 # Number of rows allowed to display found options
description_rows: 20 # Number of rows allowed to display command description
}
style: {
text: green # Text style
selected_text: green_reverse # Text style for selected option
description_text: yellow # Text style for description
}
}]Completion Menu
The completion menu is a context sensitive menu that will present suggestions based on the status of the prompt. These suggestions can range from path suggestions to command alternatives. While writing a command, you can activate the menu to see available flags for an internal command. Also, if you have defined your custom completions for external commands, these will appear in the menu as well.
The completion menu by default is accessed by pressing tab and it can be configured by modifying these values from the config object:
$env.config.menus ++= [{
name: completion_menu
input_mode: cursor_prefix # Search is done on the text from the start of the line up to the cursor
marker: "| " # Indicator that appears with the menu is active
type: {
layout: columnar # Type of menu
columns: 4 # Number of columns where the options are displayed
col_width: 20 # Optional value. If missing all the screen width is used to calculate column width
col_padding: 2 # Padding between columns
tab_traversal: "vertical" # Direction in which pressing <Tab> will cycle through options, "horizontal" or "vertical"
}
style: {
text: green # Text style
selected_text: green_reverse # Text style for selected option
description_text: yellow # Text style for description
match_text: { attr: u } # Matched style
selected_match_text: { attr: ur } } # Selected matched style
}]By modifying these parameters you can customize the layout of your menu to your liking.
Ide Completion Menu
The ide_completion_menu works much like the completion_menu but has an ide look and feel about it.
{
name: ide_completion_menu
input_mode: cursor_prefix
marker: "| "
type: {
layout: ide
min_completion_width: 0,
max_completion_width: 50,
max_completion_height: 10, # will be limited by the available lines in the terminal
padding: 0,
border: true,
cursor_offset: 0,
description_mode: "prefer_right"
min_description_width: 15
max_description_width: 50
max_description_height: 10
description_offset: 1
# If true, the cursor pos will be corrected, so the suggestions match up with the typed text
#
# C:\> str
# str join
# str trim
# str split
correct_cursor_pos: false
}
style: {
text: green
selected_text: { attr: r }
description_text: yellow
match_text: { attr: u }
selected_match_text: { attr: ur }
}
}History Menu
The history menu is a handy way to access the editor history. When activating the menu (default Ctrl+r) the command history is presented in reverse chronological order, making it extremely easy to select a previous command.
The history menu can be configured by modifying these values from the config object:
$env.config.menus ++= [{
name: history_menu
input_mode: diff # Search is done on the text written after activating the menu
marker: "? " # Indicator that appears with the menu is active
type: {
layout: list # Type of menu
page_size: 10 # Number of entries that will presented when activating the menu
}
style: {
text: green # Text style
selected_text: green_reverse # Text style for selected option
description_text: yellow # Text style for description
}
}]When the history menu is activated, it pulls page_size records from the history and presents them in the menu. If there is space in the terminal, when you press Ctrl+x again the menu will pull the same number of records and append them to the current page. If it isn't possible to present all the pulled records, the menu will create a new page. The pages can be navigated by pressing Ctrl+z to go to previous page or Ctrl+x to go to next page.
Searching the History
To search in your history you can start typing key words for the command you are looking for. Once the menu is activated, anything that you type will be replaced by the selected command from your history. for example, say that you have already typed this
let a = ()you can place the cursor inside the () and activate the menu. You can filter the history by typing key words and as soon as you select an entry, the typed words will be replaced
let a = (ls | where size > 10MiB)Menu Quick Selection
Another nice feature of the menu is the ability to quick select something from it. Say you have activated your menu and it looks like this
>
0: ls | where size > 10MiB
1: ls | where size > 20MiB
2: ls | where size > 30MiB
3: ls | where size > 40MiBInstead of pressing down to select the fourth entry, you can type !3 and press enter. This will insert the selected text in the prompt position, saving you time scrolling down the menu.
History search and quick selection can be used together. You can activate the menu, do a quick search, and then quick select using the quick selection character.
User Defined Menus
In case you find that the default menus are not enough for you and you have the need to create your own menu, Nushell can help you with that.
In order to add a new menu that fulfills your needs, you can use one of the default layouts as a template. The templates available in nushell are columnar, list or description.
The columnar menu will show you data in a columnar fashion adjusting the column number based on the size of the text displayed in your columns.
The list type of menu will always display suggestions as a list, giving you the option to select values using ! plus number combination.
The description type will give you more space to display a description for some values, together with extra information that could be inserted into the buffer.
Let's say we want to create a menu that displays all the variables created during your session, we are going to call it vars_menu. This menu will use a list layout (layout: list). To search for values, we want to use only the things that are written after the menu has been activated (input_mode: diff).
With that in mind, the desired menu would look like this
$env.config.menus ++= [{
name: vars_menu
input_mode: diff
marker: "# "
type: {
layout: list
page_size: 10
}
style: {
text: green
selected_text: green_reverse
description_text: yellow
}
source: { |token|
scope variables
| where ($it.name | str contains $token.text)
| sort-by name
| each { |row| {value: $row.name description: $row.type} }
}
}]As you can see, the new menu is identical to the history_menu previously described. The only huge difference is the new field called source. The source field is a closure that returns the values you want to display in the menu. For this menu we are extracting the data from scope variables and we are using it to create records that will be used to populate the menu.
The required structure for the record is the next one
{
value: "$foo" # The value that will be inserted in the buffer
description: "int" # Optional. Description that will be displayed with the selected value
display_override: "foo (int)" # Optional. Text shown in the menu in place of the value
style: green # Optional. Color of the value in the menu
span: { start: 5, end: 7 } # Optional. Byte range of the line that the value replaces
extra: ["first", "second"] # Optional. A list of strings that will be displayed with the selected value. Only works with a description menu
}For the menu to display something, at least the value field has to be present in the resulting record. The source can also return a plain list of strings, or null to show nothing. It can return the same values as a custom completer, except that the options of a {completions, options} record are ignored.
In order to make the menu interactive, the source closure receives the same inputs as a custom completer. It asks for them by naming its parameters:
token- the token under the cursor, as{text, kind, span}. Thevars_menuabove filters on$token.text, so typingfooafter activating the menu shows$fooand$food.place- what is being completed.$place.cursoris the cursor position, and$place.targetis the part of the line that a suggestion replaces by default.buffer- the whole line up to the cursor, whatever the menu'sinput_modeis.
Warning
Before Nushell 0.116, a menu source was written as {|buffer, position| ... }, and with only_buffer_difference: true, $buffer held only the text typed after the menu was activated. A source that declares buffer now always receives the whole line up to the cursor, and a source that declares position still receives the cursor position but prints a deprecation warning. Use $token.text for the text being completed, and $place.cursor for the cursor position.
Using this information, you can design your menu to present the information you require and to replace that value in the location you need it. The only thing extra that you need to play with your menu is to define a keybinding that will activate your brand new menu. For example, to open it with Alt+O:
$env.config.keybindings ++= [{
name: vars_menu
modifier: alt
keycode: char_o
mode: [emacs, vi_normal, vi_insert]
event: { send: menu name: vars_menu }
}]Menu Keybindings
In case you want to change the default way both menus are activated, you can change that by defining new keybindings. For example, the next two keybindings assign the completion and history menu to Ctrl+t and Ctrl+y respectively
$env.config.keybindings ++= [
{
name: completion_menu_ctrl_t_vi
modifier: control
keycode: char_t
mode: [vi_insert vi_normal]
event: {
until: [
{ send: menu name: completion_menu }
{ send: menupagenext }
]
}
}
{
name: history_menu_ctrl_y_vi
modifier: control
keycode: char_y
mode: [vi_insert vi_normal]
event: {
until: [
{ send: menu name: history_menu }
{ send: menupagenext }
]
}
}
]Abbreviations
Reedline abbreviations are a convenient way to expand a command into a different command that is often longer and/or more complex. This is similar to an alias with two main exceptions: (1) the expanded command is what gets stored to history, (2) the expanded command can be edited before being used.
Abbreviations are expanded on space or enter and you can add them to your config like this
$env.config.abbreviations = {
ll: "ls -l"
gs: "git status"
ptop: "ps | sort-by cpu -r | first 15"
}You can see the currently active abbreviations with abbr list:
abbr list
# => ╭───┬──────┬────────────────────────────────╮
# => │ # │ name │ expansion │
# => ├───┼──────┼────────────────────────────────┤
# => │ 0 │ gs │ git status │
# => │ 1 │ ll │ ls -l │
# => │ 2 │ ptop │ ps | sort-by cpu -r | first 15 │
# => ╰───┴──────┴────────────────────────────────╯