README.md
3c9dbf75
 # [`readline-vim`][]
 
8321f193
 Upgrade [Readline][] from [vi][] to [Vim][].
3c9dbf75
 
8321f193
 [`readline-vim`][] is a [Python][] script that generates [Readline][] macros
 (4658 of them) that provide [Vim][] [motions][], [operators][] and [text
 objects][] (the ones that are useful on a single line) as well as functionality
 from the popular [`vim-surround`][].
3c9dbf75
 
 [`readline-vim`]: https://git.rcrnstn.net/rcrnstn/readline-vim
 [Readline]: https://en.wikipedia.org/wiki/Readline
8321f193
 [vi]: https://en.wikipedia.org/wiki/vi
 [Vim]: https://en.wikipedia.org/wiki/Vim_(text_editor)
 [Python]: https://www.python.org
3c9dbf75
 [motions]: https://vimhelp.org/motion.txt.html
 [operators]: https://vimhelp.org/motion.txt.html#operator
 [text objects]: https://vimhelp.org/motion.txt.html#text-objects
8321f193
 [`vim-surround`]: https://github.com/tpope/vim-surround
aadee78f
 
69a03099
 ## Background
 
 [Readline][] is a library that provides line-editing for interactive
 command-line programs. It is used in a great many places, including shells such
8321f193
 as [Bash][] (where it originated) and [REPL][]s such as [Python][]'s or
 [Octave][]'s. Using [`rlwrap`][], Readline can even be used with programs that
 don't have built-in support for it, such as [MATLAB][] (as in `rlwrap -a matlab
 -nodesktop -nosplash`). There are bindings in many languages, so if you're a
 developer you can easily use it in your own projects. These factors make it
 fairly ubiquitous.
69a03099
 
8321f193
 Readline can be configured with an [`inputrc`][] file, usually placed at
 [`~/.inputrc`][], which supports an [`$include`][] directive useful for
 including other files, e.g. from `~/.inputrc.d/`.
69a03099
 
 Readline uses [Emacs][]-like key bindings by default. If you're a Vim fan
8321f193
 though, you probably use its vi mode, activated by `set editing-mode vi` in the
 configuration or through some mechanism in the containing program, such as
69a03099
 Bash's `set -o vi`.
 
 If you *are* a Vim fan though, this has the potential of landing you in a sort
8321f193
 of [uncanny valley][] since (Readline's) vi (mode) does not include the many
69a03099
 improvements contained in Vim that you have come to rely on, mainly [text
8321f193
 objects][] and the related plugins. This is especially bad if you're using
 Readline inside Vim's own [`:terminal`][]. [`readline-vim`][] aims to fix this.
 
 [Bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell)
 [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
 [Octave]: https://en.wikipedia.org/wiki/GNU_Octave
 [`rlwrap`]: https://manpages.debian.org/rlwrap/rlwrap.1.html
 [MATLAB]: https://en.wikipedia.org/wiki/MATLAB
 [`inputrc`]: https://www.mankier.com/3/readline#Initialization_File
 [`~/.inputrc`]: https://www.mankier.com/3/readline#Files-~/.inputrc
 [`$include`]: https://www.mankier.com/3/readline#Initialization_File-Conditional_Constructs
 [Emacs]: https://en.wikipedia.org/wiki/Emacs
 [uncanny valley]: https://en.wikipedia.org/wiki/Uncanny_valley
 [`:terminal`]: https://vimhelp.org/terminal.txt.html#:terminal
69a03099
 
740b74e0
 ## Usage
 
 Clone the repository
 
 ```sh
 git clone https://git.rcrnstn.net/rcrnstn/readline-vim
 cd readline-vim
 ```
 
8321f193
 and either append the output to your `~/.inputrc`
740b74e0
 
 ```sh
 ./readline-vim >> ~/.inputrc
 ```
 
8321f193
 or use a separate file and include it (recommended)
 
 ```sh
 mkdir -p ~/.inputrc.d
 ./readline-vim >| ~/.inputrc.d/readline-vim.inputrc
 ```
 
 ```sh
 cat >> ~/.inputrc << 'EOF'
 
 ## `readline-vim`
 $include ~/.inputrc.d/readline-vim.inputrc
 EOF
 ```
 
 ### Use vi mode by default
 
 ```sh
 cat >> ~/.inputrc << 'EOF'
 
 ## Use vi editing mode
 set editing-mode vi
 EOF
 ```
 
 ### Indicate mode with cursor shape
 
 ```sh
 cat >> ~/.inputrc << 'EOF'
 
 ## Indicate mode with cursor shape
 set show-mode-in-prompt On
 $if term=linux
     # https://www.kernel.org/doc/Documentation/admin-guide/vga-softcursor.rst
     set vi-cmd-mode-string \1\e[?8c\2
     set vi-ins-mode-string \1\e[?0c\2
     set emacs-mode-string  \1\e[?0c\2
 $else
     # https://vt100.net/docs/vt510-rm/DECSCUSR
     # http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
     set vi-cmd-mode-string \1\e[1 q\2
     set vi-ins-mode-string \1\e[5 q\2
     set emacs-mode-string  \1\e[5 q\2
 $endif
 EOF
 ```
 
 ## Features
 
 -   Motions
     -   vi (built-in)
         -   Word (upper and lower case versions)
             -   `w` *word beginning, forwards*
             -   `e` *word end, forwards*
             -   `b` *word beginning, backwards*
         -   Other
             -   `h`, `l` *left, right*
             -   `0`, `^`, `$` *line beginning, first non-whitespace character,
                 end*.
             -   `|` *(first) column*
             -   `;`, `,` *next, previous searched character*
             -   `%` *matching pair character*
     -   Vim
         -   Word (upper and lower case versions)
             -   `ge` *word end, backwards*
         -   Other
             -   `g_` *last non-whitespace character*
             -   `)`, `(` *sentence, forwards, backwards* (only works with
                 sentences after ".")
 -   Operators
     -   vi
         -   `d` *delete*
         -   `c` *change*
         -   `y` *[yank][]*
     -   [`vim-surround`][]
         -   `ds` *delete surroundings*
         -   `cs` *change surroundings*
         -   `ys` *add surroundings ("you surround")*
 -   Text objects
     -   Motions (vi and Vim)
     -   Implicit line (repeat last character of operator)
     -   Vim words (`a` *an* and `i` *inner*, upper and lower case versions)
         -   `w` *word*
     -   Vim pairs (`a` *an* and `i` *inner* versions)
         -   Distinct
             -   Matching
                 -   `(`, `)`, `b`
                 -   `{`, `}`, `B`
                 -   `[`, `]`
             -   Other
                 -   `<`, `>`
         -   Nondistinct
             -   Quotes
                 -   `"`, `'`, `` ` ``
             -   Punctuation
                 -   `#`, `$`, `%`, `&`, `@`, `\\`, `^` `_`, `|`, `~`
                 -   `.`, `,`, `:`, `;`, `!`, `?`
                 -   `+`, `-`, `*`, `/`, `=`
 
 [yank]: https://en.wiktionary.org/wiki/yank
 
 ## Bugs
 
 Some macros clobber the `a`, `b` and/or `c` marks.
 
 Only forward motions work as expected with the surround operators.
 
 Most known bugs exhibit themselves at the end, and sometimes the beginning, of
 line. This is sometimes unavoidable, sometimes a trade-off to produce correct
 behavior elsewhere, mostly single-character words and/or whitespace:
 
 -   `ge`/`gE` motions: Jumps past last word on line, does not jump past first
     word on line.
 -   word/WORD text objects: Always excludes the last character on line.
 -   Implicit line text object (as used in e.g. `yss)`): Includes whitespace at
     the beginning and end of line.
 
 ## Implementation notes
 
 This is an honest attempt to solve this problem "optimally". However, Readline
 macros are not [Turing complete][Turing completeness] (in contrast to e.g.
 VimScript) which makes this kind of hard (and more fun :smile:).
866cd07a
 
8321f193
 Testing suggests that marks are not supported by all applications when combined
 with operators in macros. No workaround has been found.
 
 Counts used in macros have to come before the operator. That is, `2cl` works
 but `c2l` does not.
 
 Macros are what Vim calls recursive, i.e. they can make use of other macros in
 their expansion. To use Readline commands (such as `upcase-word`) they need to
 be bound to a key sequence (if no binding exists already) before being used in
 macros.
 
 [Turing completeness]: https://en.wikipedia.org/wiki/Turing_completeness
 
 ## Related projects
 
 -   [`bash-surround`][]
866cd07a
 
     Defines the macros manually and therefore "only" provides 234 of them,
     missing some functionality.
 
     The instructions are Bash centric, although it uses general Readline
     macros.
 
8321f193
 -   [Athame][]
866cd07a
 
     Patches Readline to route keystrokes through an actual Vim process. Also
     provides patches for [Zsh][]. This means that whatever your local Vim
     supports, Athame supports (including plugins)!
 
     Can be a little unreliable if your local Vim has a ton of plugins,
     especially if they interact with the terminal in non-obvious ways.
 
8321f193
 -   [Zsh][]
 
     Has built-in [text objects][Zsh text objects] and [surround][Zsh surround]
     support. It even has a Vim-like [Visual mode][Zsh Visual mode]. The popular
     [Oh My Zsh][] Zsh configuration framework extends this with its
     [`vi-mode`][Oh My Zsh `vi-mode`] plugin. There are also several other
     plugins:
 
     -   [`softmoth/zsh-vim-mode`][]
     -   [`jeffreytse/zsh-vi-mode`][]
 
 -   [`thlorenz/readline-vim`][]
866cd07a
 
     Exclusive to [Node.js][] [`readline`][Node.js `readline`] and only defines
8321f193
     vi bindings, not Vim bindings.
866cd07a
 
8321f193
 [`bash-surround`]: https://github.com/liloman/bash-surround
 [Athame]: https://github.com/ardagnir/athame
 [Zsh]: https://en.wikipedia.org/wiki/Zsh
 [Zsh text objects]: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Text-Objects
 [Zsh surround]: https://sourceforge.net/p/zsh/code/ci/master/tree/Functions/Zle/surround
 [Zsh Visual mode]: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#index-visual_002dmode
 [Oh My Zsh]: https://ohmyz.sh
 [Oh My Zsh `vi-mode`]: https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/vi-mode
 [`softmoth/zsh-vim-mode`]: https://github.com/softmoth/zsh-vim-mode
 [`jeffreytse/zsh-vi-mode`]: https://github.com/jeffreytse/zsh-vi-mode
 [`thlorenz/readline-vim`]: https://github.com/thlorenz/readline-vim
866cd07a
 [Node.js]: https://nodejs.org
 [Node.js `readline`]: https://nodejs.org/api/readline.html#readline_readline
 
aadee78f
 ## License
 
 Licensed under the [ISC License][], see the [`LICENSE`](LICENSE) file.
 
 [ISC License]: https://choosealicense.com/licenses/isc/