Using Vim with Leo

This chapter discusses these topics:

  • How to enable and use Leo’s new vim-emulation mode.

  • How to import and export vim’s .otl files.

  • How to install and use stand-alone vim-like bindings.

Using Leo’s native vim mode

In general, vim-mode in Leo works much as in the real vim. There are three modes, insert, normal and visual.

Supported commands

  • Cursor motions: ^,$,0,b,e,f,F,gg,gG,j,h,k,l,t,T,w.

  • The gb,ge,gh commands are synonyms for 0,$,^.

  • The h,j,k,l commands work on outlines when entered in the outline pane.

  • 0 in outline pane: goto-first-visible-node

  • e in outline pane: goto-last-visible-node.

  • Deleting text: d{motion},{motion}d,v{motion}d,diw,x.

  • Insert commands: a,A,i,o,O and switch to insert mode if entered in the outline pane.

  • Yank & paste commands: y,p. These act on outlines if entered in the outline pane.

  • Search commands: /,?,n,*,#. These commands are node-only searches.

  • The dot command ‘.’ works for motions, but not yet for inserts or searches.

  • v: start/end visual mode.

Notes:

  • Except as noted above, all vim-mode commands must be entered in the body pane.

  • <Return> in headlines switches to the outline pane.

  • <Return> in the outline pane switches to the body pane.

Differences from the real vim

  • The gb,ge,gh commands are synonyms for 0,$,^.

  • The h,j,k,l commands work on outlines when entered in the outline pane.

  • The a,A,i,o,O commands switch to insert mode if entered in the outline pane.

  • The y,p commands act on outlines if entered in the outline pane.

  • Ending visual mode with ‘v’ retains the selection range.

  • Ctrl-H puts the headline in insert mode.

  • Mouse clicks never change vim’s state.

Abbreviations

  • The jj abbreviation switches to normal mode, preserving the changed status of the .leo file.

  • Return in visual/normal mode enters insert mode.

Colon commands

The ‘:’ command enters Leo’s minibuffer, with ‘:’ pre-inserted. You may backspace over the ‘:’. Here are the commands:

:! Execute a shell command.
:e! Revert all changes to a .leo file, prompting if there have been changes.
:gt cycle-focus
:q Quit, prompting for saves.
:qa Quit only if there are no unsaved changes.
:r Prompt for a file name.  Insert it at the cursor.
:tabnew Prompt for a file name, and open a new tab.
:w Save the .leo file.
:wa Save all changed  .leo files.
:wq Save all open files and exit.
:xa ave all open files and exit.

The following colon commands are unique to Leo:

:print-vim-dot
:toggle-vim-mode
:toggle-vim-trainer-mode

Settings

@bool vim-mode = False: Enables Leo’s vim mode when True.

@bool vim-crosses-lines = True: When True the f,F,h,l,t,T,x commands may cross line boundaries.

Using vimoutline (.otl) files in Leo

Leo can automatically import and export vimoutline (.otl) files. Nodes like:

@auto-otl <path to .otl file>

or equivalently:

@auto-vimoutline <path to .otl file>

import the .otl as a Leo outline.

These nodes work like other @auto nodes: when Leo loads an outline, Leo reads the .otl file into the @auto-otl tree. When Leo writes an outline, Leo writes any @auto-otl tree back to the .otl file.

After creating an @auto-otl node by hand, be sure to use Leo’s refresh-from-disk command to populate the node. Do this before saving the .leo file. If you try to save an empty @auto-otl node Leo will warn you that you are about to overwrite the file.

The refresh-from-disk command creates an @auto-otl node whose children represent the contents of the external .otl file. Leo does not write the @auto-otl node itself. This allows you to put Leo directives in the node.

Using stand-alone vim bindings

Installing vim bindings

Place a copy of the “@keys Vim bindings” node and its sub-nodes, located in the leoSettings.leo file, under the “@settings” node in the myLeoSettings.leo file

The same procedure is performed to update to a new version.

Note: Place any local customized key bindings in a separate “@keys My Vi” node in the myLeoSettings.leo file to prevent them from being overwritten when updating to a new version.

General commands

The following commands are always available.

State change commands:

i           Change state to insert from command state
Esc         Change state to command from insert state
Ctrl-[      Same as ESC

Save/Exit/Quite commands:

:e          Revert
:w<return>  Save '.leo' file
:wq<return> Save '.leo' file and quit Leo
:q<return>  Quit Leo   (Leo will prompt if file not saved)
ZZ          Save leo file and exit

Undo/Redo commands:

u           Undo previous command
Ctrl-r      Redo previous command

Search options:

Ctrl-/      Prompt for option to change
            Options:
                a   Search all nodes (also <cr> key)
                h   Toggle headline search
                b   Toggle body search
                m   Toggle marking of nodes (specify sub-option)
                    f   Toggle marking of nodes with found text
                    c   Toggle marking of nodes with changed text
                        (only supported with 'Alt-/', 'Alt-p')
                r   Toggle regex matches
                    ('/' key turns off regex. 'n' key uses regex if turned on)

Note: Whether a search is limited to node's body or the node's sub-outline
      is determined by which pane has focus when search text specified.
      (See "Find text commands:" sub-sections in Outline/Body Pane sections)

Miscellaneous commands:

Tab         Toggle focus between Outline and Body pane
=           Simulate double-click on current node's icon box
Alt-G       Go to specified line number (relative to external file)
Ctrl-:      Enter Leo's command line

Body pane commands

Move cursor commands:

h           Go back 1 character
   LtArrow  Mapped to "h" for convenience
j           Go down 1 line
   DnArrow  Mapped to "j" for convenience
k           Go up 1 line
   UpArrow  Mapped to "k" for convenience
l           Go forward 1 character
   RtArrow  Mapped to "l" for convenience

w           Go to beginning of next word
   W        Mapped to "w" until "stop after blank characters" supported
b           Go to beginning of current/previous word
   B        Mapped to "b" until "stop at blank character" supported
e           Go to end of current/next word
   E        Mapped to "e" until "stop at blank character" supported

Note: Move by word commands stop at non-alpha characters

|           Goto beginning of current line
^           Go to 1st non-blank character on current line
$           Goto end of current line

%           Go to matching bracket

(           Go to beginning of current sentence
)           Go to beginning of next sentence
{           Go to beginning of current paragraph
}           Go to beginning of next paragraph

gg          Go to the first line (Cursor at column 1)
G           Go to the last line  (Cursor at column 1)

Mark commands:

m<label>    Assign cursor location to a single character label
`<label>    Go to location associated with label

  Note: Only character count is tracked. Any inserts or deletes will change mark.
      Mark's are not node specific; `<label> will go to location in current node.

Select commands:

Ctrl-v      Toggle text select mode (Vim's "visual" mode)
   V        Mapped to 'Ctrl-v' for convenience (Should toggle line select)

Insert/substitute commands:

a           Insert at cursor
i           Mapped to "a" until "cursor on a character" supported
A           Insert at end of line
I           Insert at first non-space
o           Open new line below current line
O           Open new line above current line
R           Overwrite text
s           Substitute character (Delete character, enter insert state)
S           Substitute line (Delete line, enter insert state)

Change commands:

C           Change to end of line
cc          Change all of current line
cw          Change to end of word
cb          Change to beginning of word
c)          Delete to end of sentence
c(          Delete to beginning of sentence
c}          Delete to end of paragraph
c{          Delete to beginning of paragraph
c%          Change from current bracket type its matching bracket type
ct<char>    Selects forward to <char> (follow with 'i' to change selection)
cT<char>    Selects backward to <char> (follow with 'i' to change selection)
c<cr>       Change selected text

Delete commands:

x           Delete next character
delete      Delete next character
D           Delete to the end of the current line
dd          Delete current line
dw          Delete to end of word
db          Delete to beginning of word
d)          Delete to end of sentence
d(          Delete to beginning of sentence
d}          Delete to end of paragraph
d{          Delete to start of paragraph
d%          Delete from current bracket type to its apposing bracket
dt<ch>      Delete to character (not limited to current line)
d<cr>       Delete selected text

J           Join next line to end of current line (deletes carriage return)

Yank text commands:

Y           Yank to end of line
yy          Yank line
yw          Yank to beginning of next word
yb          Yank to beginning of current word
y)          Yank to end of sentence
y(          Yank to beginning of sentence
y}          Yank to end of paragraph
y{          Yank to beginning of paragraph
y%          Yank from current bracket type to its opposing bracket
yt<char>    Select forward to <char>  (use 'y<cr>' to yank selection)
yT<char>    Select backward to <char> (use 'y<cr>' to yank selection)
y<cr>       Yank selected text (Vim uses 'y' in visual mode)

Find character commands:

f           Find next occurrence of user specified character
F           Find previous occurrence of user specified character

Find text commands:

/           Search forward within current node's body text
?           Search backward within current node's body text
n           Find next (same scope, same direction)
N           Find next (same scope, other direction)

Note: See "Search options" in General Commands section to change options.

Replace [and find next] commands:

Commands using Paste buffer (clipboard)
P           Paste text before cursor.
p           Mapped to "P" until character based cursor supported.
Ctrl-p      Paste then find next match
            Note: Use 'pn' instead of 'Ctrl-p' in headlines (Leo limitation)
                  Command will continue to paste when match no longer found.

Commands prompting for replace string
Note: Scope and direction taken from last use of '/','?' or 'Ctrl-/'(scope only)
Alt-/       Prompt for search & replace string
Alt-p       Replace then search (use after Alt-/)
            Note: Works in headlines and body panes.
                  Doesn't paste unless last search found a match.

Indent/Unindent line commands:

>>          Indent the current line
>)          Indent to the end of sentence
>(          Indent to the beginning of sentence
>}          Indent to the end of paragraph
>{          Indent to the beginning of paragraph
>g          Indent to the start of buffer
>G          Indent to the end of buffer

<>          Unindent the current line
<)          Unindent to the end of sentence
<(          Unindent to the beginning of sentence
<}          Unindent to the end of paragraph
<{          Unindent to the beginning of paragraph
<g          Unindent to the start of buffer
<G          Unindent to the end of buffer

Format commands:

gqap        Split long line into separate lines
gwap        Split long line into separate lines
gqq         Split long line into separate lines
gww         Split long line into separate lines

Note: 'gwap' and 'gww' should not move cursor but do.

Scroll commands:

Ctrl-b      Scroll text up by pane's height
Ctrl-f      Scroll text down by pane's height
   Ctrl-y   Mapped to Ctrl-b until scroll up one line is supported
   Ctrl-e   Mapped to Ctrl-f until scroll down one line is supported
   Ctrl-u   Mapped to Ctrl-b until scroll up half a pane height is supported
   Ctrl-d   Mapped to Ctrl-f until scroll down half a pane height is supported

Window commands:

Ctrl-w s    Open another view into current node's body (Vim: Split window)
   Ctrl-w n Mapped to "Ctrl-w s" (Vim: New buffer in split window)
Ctrl-w w    Switch to next view (Vim: Go to up/left window w/wrapping)
   Ctrl-w p Mapped to "Ctrl-w w" (Vim: Cycle through windows)
   Ctrl-w k Mapped to "Ctrl-w w" (Vim: Go to window above current window)
   Ctrl-w j Mapped to "Ctrl-w w" (Vim: Go to window below current window)
Ctrl-w c    Close current view in body pane (Vim: Close current window)
   Ctrl-w q Mapped to "Ctrl-w c" (Vim: Quit current window)

Node commands:

Go to another node while focus remains in the body pane.
Ctrl-j      Go to next visible node
Ctrl-k      Go to previous visible node
Ctrl-h      Hide sub-nodes or, if hidden, go up 1 level
Ctrl-l      Display sub-nodes or, if displayed, go down 1 level
   Ctrl-DnArrow    Mapped to "Ctrl-j" for convenience
   Ctrl-UpArrow    Mapped to "Ctrl-k" for convenience
   Ctrl-LtArrow    Mapped to "Ctrl-h" for convenience
   Ctrl-RtArrow    Mapped to "Ctrl-l" for convenience

Outline commands

The following commands are supported when in a headline’s command mode.

State change commands:

Ctrl-i      Change state to command from grayed state
return      Change state to command from insert state
Ctrl-]      Change state to grayed from command state

Cursor movement commands:

h           Go to previous character
   LtArrow  Mapped to 'h' for convenience
l           Go to next character
   RtArrow  Mapped to "l" for convenience

Note: 'j' and 'k' will scroll the buffer contents up and down;
      leaving the focus in the outline pane.

w           Go to beginning of next word
   W        Mapped to "w" until "stop after blank characters" supported
b           Go to beginning of current/previous word
   B        Mapped to "b" until "stop at blank character" supported
e           Go to end of current/next word
   E        Mapped to "e" until "stop at blank character" supported

Note: Move by word commands stop at non-alpha characters

|           Go to beginning of line
^           Go to beginning of line
$           Go to end of line

%           Go to matching bracket

Edit commands:

x           Delete next character
delete      Delete next character
dd          kill-line

s           Select current character

v           Toggle text select mode (issue cursor movement commands)
y<return>   Yank selected text

C           Select to end of line (follow with 'i' to change text)
cc          Delete line (follow with 'i' to change text)

D           Select to end of line (follow with 'x' to delete text)
dd          Delete line

Y           Select to end of line (follow with 'y<return>' to yank text)
yy          Select line (follow with 'y<return>' to yank text)

Find character commands:

f           Find next occurrence of user specified character
F           Find previous occurrence of user specified character

Find text commands:

/           Search forward within current node and its subnodes
n           Find next (same scope, same direction)
N           Find next (same scope, other direction)

Note: See "Search options" section above to change options using 'Ctrl-/'

Replace [and find next] commands:

Commands that use Paste buffer (clipboard)
Note: Paste-then-search command not possible in headlines (Use 'pn')
P           Paste text before cursor.
p           Mapped to "P" until character based cursor supported.

Commands that prompt for the replace string
Alt-/       Prompt for search & replace string
Alt-p       Replace then search (use after Alt-/)
            Note: Works in headlines and body panes.
                  Doesn't paste unless last search found a match.

Node edit commands:

o           Insert node after current node

Ctrl-x      Delete current node
Ctrl-c      Yank current node
Ctrl-v      Paste current node

Node goto commands:

G           Go to the outline's last node
gg          Go to the outline's first node

Ctrl-j      Go to next visible node
Ctrl-k      Go to previous visible node
Ctrl-h      Hide sub-nodes or, if hidden, go up 1 level
Ctrl-l      Display sub-nodes or, if displayed, go down 1 level

   DnArrow  Mapped to "Ctrl-j" for convenience
   UpArrow  Mapped to "Ctrl-k" for convenience

   Ctrl-DnArrow Mapped to "Ctrl-j" for convenience
   Ctrl-UpArrow Mapped to "Ctrl-k" for convenience
   Ctrl-LtArrow Mapped to "Ctrl-h" for convenience
   Ctrl-RtArrow Mapped to "Ctrl-l" for convenience

Node move commands:

Ctrl-Shift-k    Move node down
Ctrl-Shift-h    Move node left
Ctrl-Shift-l    Move node right
Ctrl-Shift-j    Move node up

   Ctrl-Shift-DnArrow    Mapped to "Ctrl-Shift-k" for convenience
   Ctrl-Shift-LtArrow    Mapped to "Ctrl-Shift-h" for convenience
   Ctrl-Shift-RtArrow    Mapped to "Ctrl-Shift-l" for convenience
   Ctrl-Shift-UpArrow    Mapped to "Ctrl-Shift-j" for convenience

Node mark commands:

m           Toggle node mark
Ctrl-m      Go to next marked node
Alt-m       Clear all marked nodes

Outline scroll commands:

Ctrl-y       Scroll outline up one line
Ctrl-e       scroll outline down one line
Ctrl-u       Scroll outline up one half page
Ctrl-d       scroll outline down one half page
Ctrl-b       Scroll outline up one page
Ctrl-f       scroll outline down one page

Commands not supported

Notable missing editing commands:

t<char>     Move cursor to character before specified character
r           Replace a single character with a single character
0           Go to 1st column in current line (Use '|' instead)
bksp        Move one character to the left
~           Toggle character's case
.           Repeat last editing command
;           Repeat last cursor movement command
<n><cmd>    Perform command 'n' number of times
<cmd><n><object>    Perform the command on the n'th or up to the n'th object

Notable missing body pane commands:

<num>G      Go to specified line number
z<movement> Slide buffer to put current line at top/middle/bottom of pane
'<command>  Go to line of last edit, jump, ...
`<command>  Go to character of last edit, jump, ...

Avoiding changes to ‘tag’ files

If you use the open-with command to open a node text in Vim and your Vim’s “tag” file refers to external files then there is a risk that a external file that is initially displayed via the “tag” command” in Vim is accidentally edited and saved from the external Vim editor while your Leo session still contains the external file’s original text that may later recreate the original external file during a Leo save operation (overwriting the changes saved from the Vim editor).

To prevent this problem, modifications to external files can be avoided by using Vim’s “modeline” feature to disable editing of external files.

Vim’s “modeline” feature scans each loaded buffer for text at the top or bottom of the file containing “ vim:” followed by a series of Vim options. The text is usually embedded within a comment. The following example prevents modifications to a buffer in a Python file:

# vim:noma (A space is required between the '#' and "vim:noma")

If this line is placed in a separate Leo node at the top or bottom of the list of nodes under a external file node (ex: @file) then any external file saved and then later loaded into Vim will, by default, not be modifiable. If a derived file does need to be edited then modifications can be re-enabled on a file-by-file basis by issuing Vim’s “:ma” command while viewing the derived file.

The number of lines that Vim checks at the top and bottom of the buffer is configurable. The following Vim command must be placed in the vimrc file to allow for Leo’s trailing sentinel lines:

set modelines=8

Issue the “:help modeline” command within Vim for the more information about modelines.