Nextvi(1)
Nextvi(1) β from the General Commands Manual, bestie, and yes this is the whole vibe. Welcome to Nextvi, the manual page that's gonna make your terminal feel like main character energy. π«Ά
πΈ NAME πΈ
Nextvi β A small vi/ex terminal text editor
β¨ SYNOPSIS β¨
vi [-aemsv] [file ...]
π DESCRIPTION π
Okay so Nextvi is a modern clone of the command-line text editor vi(1), initially developed by Bill Joy in 1976 for Unix-based systems. The lore is real. π
Nextvi builds on a bunch of standard vi(1) features, including that iconic unique modal interface where you switch between normal, insert, and command modes for efficient text manipulation. The way it lets you switch modes? Obsessed.
Extra glow-up features include an unrestricted macro system, syntax highlighting, keymaps, bidirectional UTF-8 support, and numerous other features. Nextvi stays highly efficient, portable, and hackable, which keeps it relevant and high quality for years to come. Periodt.
π OPTIONS π
-aβ Enable alternate terminal screen-eβ Enter ex mode on startup-mβ Disable initial file read message-sβ Enter raw ex mode on startup-vβ Unset all options
π§ MANPAGE NOTATION π§
<x>β A closure where x represents a character literal[x]β A closure where x represents optional argument{x}β A closure where x represents required argument"x"β A closure where x represents a string<^X>β Represents a ctrl key X< >β Separates alternatives in a closurex-yβ Range from x to y
π₯ VI NORMAL π₯
Okay bestie, hydrate, because this is the big one. Every command below is exactly what it is, no cap. π§
[#]jβ Move # lines down[#]kβ Move # lines up[#]+,[#]<^M>,[#]<Enter>β Move # lines down, cursor after indent[#]-β Move # lines up, cursor after indent[#]hβ Move # columns left[#]lβ Move # columns right[#]f{arg}β Move to arg character found forward # times[#]F{arg}β Move to arg character found backward # times[#]t{arg}β Move until arg character found forward # times[#]T{arg}β Move until arg character found backward # times[#],β Repeat last<f F t T>move backward # times[#];β Repeat last<f F t T>move forward # times[#]Eβ Move to end of word # times, skip punctuation[#]eβ Move to end of word # times[#]Bβ Move to start of word backward # times, skip punctuation[#]bβ Move to start of word backward # times[#]Wβ Move to start of word forward # times, skip punctuation[#]wβ Move to start of word forward # timesvwβ Toggle single-line mode for<E e B b W w Space Backspace>regions[#](β Move to next sentence boundary down # times[#])β Move to next sentence boundary up # times[#]{β Move to next<{>section down # times[#]}β Move to next<{>section up # times[#][β Move to next<Newline>section down # times[#]]β Move to next<Newline>section up # times^β Move to start of line after indent0β Move to start of line$β Move to end of line[#]|β Goto # column[#]<Space>β Move # characters forward[#]<^H>,[#]<Backspace>β Move # characters backward%β Move to closest<] ) } [ ( {>pair{#}%β Move to # percent line number'{<a-z ` ' [ ] *>}β Move to a line mark`{<a-z ` ' [ ] *>}β Move to a line mark with cursor positionggβ Goto first line in buffer[#]Gβ Move to last line in buffer or # lineHβ Move to highest line on a screenLβ Move to lowest line on a screenMβ Move to middle line on a screenz.β Center screen at cursorz<^M>,z<Enter>β Center screen at top rowz-β Center screen at bottom row[#]<^E>β Scroll down 1 or # lines, retain # and cursor position[#]<^Y>β Scroll up 1 or # lines, retain # and cursor position[#]<^D>β Scroll down half a screen size. If[#], set scroll to # lines[#]<^U>β Scroll up half a screen size. If[#], set scroll to # lines<^B>β Scroll up full screen size<^F>β Scroll down full screen size#β Show global and relative line numbers2#β Toggle show global line numbers permanently4#β Toggle show relative line numbers after indent permanently8#β Toggle show relative line numbers permanentlyVβ Toggle show hidden characters:<Space Tab Newline><^C>β Toggle show line motion numbers for<l h e b E B w W>{<1-5>}<^C>β Select line motion number mode 1-5<^V>β Loop through line motion number modes[#]<^R>β Redo # times[#]uβ Undo # times<^I>,<Tab>β Open file path from cursor to end of line<^K>β Write current buffer to file. Force write on 2nd attempt[#]<^W>{arg}β Unindent arg region # times[#]<{arg}β Indent left arg region # times[#]>{arg}β Indent right arg region # times[#]"{<arg>}{cmd}β Execute normalcmdusing register arg. # applies tocmdRβ Print registers and their contents[#]&{<arg>}β Execute arg register macro in non-blocking mode # times[#]@{<arg>}β Execute arg register macro in blocking mode # times[#]@@β Execute last macro # times, blocking[#]&&β Execute last macro # times, non-blocking[#]@:,[#]&:β Execute<:>register as an ex command # times[#].β Repeat last normal command # times. Repeatable commands:<x X D C s S Y p P r d c ~ gu gU g~ ! > < ^W i I a A o O ci di J K>[#]v.β Repeat last normal command moving down across # lines[#]Qβ Enter ex mode. # retains current horizontal scroll:β Enter ex prompt[#]!{arg}β Enter pipe ex prompt based on # or arg regionvvβ Enter ex prompt with the last line from history bufferb-1[#]vrβ Enter%s/ex prompt. Insert # words from cursor[#]vt[#arg]β Enter.,.+0s/ex prompt. Insert # of lines from cursor. Insert#argwords from cursor[#]v/β Enterreex prompt to set regex keyword. Insert # words from cursorv;β Enter!ex prompt[#]viβ Enter%s/ex prompt. Contains regex for changing spaces to tabs. # modifies tab width[#]vIβ Enter%s/ex prompt. Contains regex for changing tabs to spaces. # modifies tab widthvoβ Remove trailing white spaces and<\r>line endings<^G>β Print buffer status info1<^G>β Enable permanent status row2<^G>β Disable permanent status rowgaβ Print character info1gaβ Enable permanent character info row2gaβ Disable permanent character info row[#]gwβ Hard word wrap a line to # column limit. Default: 80[#]gqβ Hard word wrap a buffer to # column limit. Default: 80[#]g~{arg}β Switch character case for arg region # times[#]gu{arg}β Switch arg region to lowercase # times[#]gU{arg}β Switch arg region to uppercase # times[#]~β Switch character case # times forwardiβ Enter insert modeIβ Enter insert mode at start of line after indentAβ Enter insert mode at end of lineaβ Enter insert mode 1 character forwardoβ Create a new line down and enter insert modeOβ Create a new line up and enter insert mode[#]sβ Delete # characters and enter insert mode[#]Sβ Delete all across # lines and enter insert mode[#]c{arg}β Delete arg region # times and enter insert modeCβ Delete from cursor to end of line and enter insert mode[#]d{arg}β Delete arg region # timesDβ Delete from cursor to end of line[#]xβ Delete # characters from cursor forward[#]Xβ Delete # characters from cursor backwarddi{<arg>}β Delete inside arg pairsci{<arg>}β Change inside arg pairs[#]r{arg}β Replace # characters with arg from cursor forward[#]Kβ Split a line # times[#]Jβ Join # lines[#]y{arg}β Yank arg region # times[#]Yβ Yank # lines[#]pβ Paste default register below current line or after cursor position # times[#]Pβ Paste default register above current line or before cursor position # timesm{<a-z ` ' [ ] *>}β Set buffer local line mark<^T>β Set global line mark 0. Global marks are always valid{<0 2 4 6 8>}<^T>β Set a global line mark #{<1 3 5 7 9>}<^T>β Switch to a global line mark #[#]<^7>{<0-9>},[#]<^_>{<0-9>},[#]<^/>{<0-9>}β Show buffer list and switch based on # or 0-9 index when prompted<^^>,<^6>β Swap to previous buffer[#]<^N>β Swap to next buffer, # changes direction[forward backward]\β Swap to/fm/bufferb-2{#}\β Refresh secondary directory listing inb-2vbβ Recurse intob-1history buffer. Insert current line into ex prompt on exitz1β Set alternative keymap to Farsi keymapz2β Set alternative keymap to Russian keymapzeβ Switch to English keymapzfβ Switch to alternative keymapzLβ Settdex option to 2zlβ Settdex option to 1zrβ Settdex option to -1zRβ Settdex option to -2[#]/β Regex search prompt, move down 1 or # matches[#]?β Regex search prompt, move up 1 or # matches[#]n,[#]Nβ Repeat regex search, move[down up]1 or # matches<^A>β Regex search 1 word from cursor, no center, wraparound move[up down]*β Regex search, no center, wraparound move[up down]{#}*,{#}<^A>β Regex search, set keyword to # words from cursor<^]>β Filesystem regex search forward based on directory listing inb-2. Sets global line mark 0 for<^P>fallback{#}<^]>β Filesystem regex search forward, set keyword to # words from cursor[#]<^P>β Filesystem regex search backward<^Z>β Suspend vi<^L>β Force redraw whole screen and update terminal dimensionsZ{<Any>}β Force exit and clean terminal, force quit in an¯oZzβ Force exit and submit history command, force quit in an¯oZZβ Exit and write unsaved changes to a file<ESC ^C>β Cancel any pending input or command
πΈ VI REGIONS πΈ
okay so regions are vi normal commands that define [h v]range for vi motions. Commands that say they "move" define a region, bestie. π
Hereβs the whole region squad, no cap:
j + <^M> <Enter> - k h l f F t T , ; B E b e W w ( ) { } [ ] ^ 0 $
<Space> <^H> <Backspace> % ' ` G H L M / ? n N * <^A>
All regions. β¨
π¦ VI MOTIONS π¦
Motions are vi normal commands that run in a [h v]range. Commands that say they "region" consume a region. Motions can be prefixed or suffixed by [#]. π
All motions:
<^W> > < ! c d y g~ gu gU
Special motions that can use [#] as number of lines:
dd yy cc g~~ guu gUU >> << <^W><^W> !!
Examples, because we love a demo:
3d/intβ delete text until the 3rd instance of the"int"keyword.3dwβ delete 3 words (prefix[#]).d3wβ delete 3 words (suffix[#])."aylβ yank a character into the<a>register."Aywβ append a word to the<a>register.
π VI/EX INSERT π
These keys go feral in insert mode:
<^H>,<Backspace>β delete a character, reset ex mode when empty.<^U>β delete until the<^X>mark or all.<^W>β delete a word.<^T>β increase indent.<^D>β decrease indent.<^]>β select paste register from 0-9 registers in a loop.<^\>{<arg>}β select paste registerarg.<^\>selects the default register.<^P>β paste a register.<^X>β mark autocomplete and<^U>starting position.<^X>resets the mark.<^G>β index current buffer for autocomplete.<^Y>β reset all indexed autocomplete data.<^R>β loop through autocomplete options backward.<^N>β loop through autocomplete options forward.<^B>β print autocomplete options when in vi insert.<^B>β recurse intob-1history buffer when in ex prompt. Insert current line into ex prompt on exit.<^A>β loop through lines in a history bufferb-1.<^Z>β suspend vi/ex.<^L>β redraw screen in vi mode, clean terminal in ex.<^O>β switch between vi and ex modes recursively.<^E>β switch to English keymap.<^F>β switch to alternative keymap.<^V>{<arg>}β read a literal characterarg.<^K>{arg}β read a digraph sequencearg.<^C>,<ESC>β exit insert mode in vi, reset in ex.<^M>,<Enter>β insert<Newline>in vi, submit command in ex.
π EX π
Ex is a powerful line editor for Unix systems, initially developed by Bill Joy in 1976. This essential tool is literally the backbone of vi, letting it execute commands, macros, and even transform into a purely command-line interface (CLI) when desired. π
β¨ EX PARSING β¨
Parsing follows this structure:
[<sep>][prefix][cmd][<pad>][args]
Ex commands are initiated and separated by <sep>. Fields can be padded by <Space> or <Tab>. [prefix] is a field consumed by [cmd], which accepts [range] structure characters. Padding inside [prefix] structure is collapsed, except within nested structures. There can only be one pad in between [cmd] and [args].
To avoid ambiguity in scripts, it is recommended to always use a pad between[cmd]and[args]. π
Examples:
:evi.cβ evaluates to":e vi.c".:efbcβ evaluates to":ef bc", not":e fbc".:e vi.cβ edit" vi.c".<pad>is required.
π₯ EX ESCAPES π₯
Special characters in [args] will become regular when escaped with <\>.
( ^ ] -β specials in regex"[]"expression.( ) { + * ? ^ $ [ ] | \ . < >β specials in regex.\ : % !β specials in ex.
π EX EXPANSION π
<%> in [args] expands to current buffer pathname or any buffer pathname when followed by a corresponding buffer number. "%#" expands to last swapped buffer pathname. "%@" expands to register specified. π¦
Examples:
:!cp % %_:e %_β make a copy of the current file and edit it.:&i%β insert current buffer pathname.:!echo "%@a"β echo the value of<a>register.
<!> in [args] starts and optionally ends a block containing external commands. This block executes and expands to stdout and stderr produced.
Examples:
:%s/int/!printf "%s" $RANDOM!β substitute"int"with the value of$RANDOM.:&i!lsβ insert output oflsshell command.:;c!ls!<^V><ESC>β insert output oflsmore efficiently.
β EX RANGES β
Some ex commands can be prefixed with ranges. [range] prefix implements vertical and horizontal ranges. [vrange] prefix implements vertical range and horizontal position. Without [cmd], [vrange] replaces [prefix].
Structures:
[% |][, ;][#][. $ ' > <][- + * / %][0-9]β all ranges structure.{|}{cmd}[|]β ex command structure.{>}[regex][>]β search forward structure.{<}[regex][<]β search backward structure.'{<mark>}β mark structure.
Character meanings:
%β range from first to last line.|β begin ex command structure.,β vertical range separator.;β horizontal range separator.#β rebase to previous value in range structure..β current position.$β last line of a buffer or end of line.'β begin mark structure.>β begin search forward structure.<β begin search backward structure.-β subtract following number.+β add following number.*β multiply by the following number./β divide by the following number.%β modulo by the following number.0-9β number or position.
Examples, aka the range vibe check:
:1,5pβ print lines 1,5.:.-5,.+5pβ print 5 lines around current position.:>int>pβ print first occurrence of"int".:<int<pβ print first occurrence of"int"in reverse.:.,>int>pβ print until"int"is found.:<int<,.pβ print until"int"is found in reverse.:>β search using previously set regex keyword.:'d,'apβ print lines from mark<d>to mark<a>.:%pβ print all lines in a buffer.:$pβ print last line in a buffer.:$*50/100+1β goto 50% of the file.:;50β goto character offset 50.:10;50β goto line 10 character offset 50.:10;.+5β goto line 10 +5 character offset.:'a;'aβ goto line mark<a>offset mark<a>.:;$β goto end of line.:5;>int>β search for"int"on line 5.:.;<int<β search for"int"in reverse on the current line.:;5;+10=β+10is relative to the initial current offset, not 5.:;5;#+10=β+10is relative to 5.:;>int>+3;#>>pβ print text enclosed by"int"on the current line.:|grp1|;>(a)+>+1|grp|;#>>pβ print text enclosed by a non-deterministic pattern"a+".
π EX COMMANDS π
[range]f>[regex],[vrange]f<[regex]β ranged search.- Horizontal range performs a scoped multi-line search forward.
- In multi-line mode,
<Newline>is a regular character. - Returns error if target not found.
- Examples:
- no range given, current line only:
:f>int - reverse:
:f<int - range given:
:10,100f>int - search for
"int"followed by"void"on next line::%;0f>int.void
- no range given, current line only:
[range]f+[regex],[vrange]f-[regex]β incrementing ranged search.- Equivalent to the
:f>and:f<commands, except subsequent commands within range move to the next match just like vi normal[#]nor[#]Ncommands.
- Equivalent to the
[vrange]f[regex]β fuzzy search prompt.- Enters a fuzzy search prompt with a list of matches.
- Matches are prefixed by selection numbers and line numbers.
- Match can be selected using numbers 0-9 if there are less than 10 matches.
<^C>or<ESC>to abort.<^M>or<Enter>to input a selection number larger than 9.- No range evaluates to
<%>range. - No range displays a maximum of
xrows * 3matches.
[vrange]g[<Any>][regex][<Any>][cmd]β global command.- Execute an ex command on a range of lines that matches an enclosed regex.
- Returns error if no line matches the pattern.
- No range evaluates to
<%>range or<.>range when nested. - Examples:
- remove all empty lines:
:g/^$/d - print lines matching previously set regex:
:g//p
- remove all empty lines:
- Multiple ex commands can be chained in one global command. To chain commands, the ex separator
<:>must be escaped once. - Example: print and append lines matching
"int"to register<a>::g/int/p\:ya ax - It is possible to nest global commands inside of global commands. The first global command will not be executed on lines that were changed by a nested global command.
- Example: nested global command β append
"has a semicolon"to all lines that contain"int"and end with<;>::g/int/g/;$/& A has a semicolon - Example: extract/print data enclosed in
"()":
:grp1:err4:g/./;0\:;>(\().+\)>;#>.+(\))>+1p:err1:grp
[vrange]g![<Any>][regex][<Any>][cmd]β inverted global command.[range]re[regex]β set regex keyword.- Range escapes its text and uses it as the regex.
- Examples:
- set keyword to
"int"::re int - set keyword from lines 1 to 3:
:1,3re
- set keyword to
[vrange]i[str]β enter ex insert mode before specified position.[str]specifies initial input into the insertion buffer.[str]in raw ex mode is injected directly and bypasses the interactive mode.- Examples:
- insert
"hello"in vi/ex::i hello<^M><ESC> - insert
"hello"in vi/ex trimming<Newline>::i hello<^M><^M><Backspace> - discard changes in vi/ex:
:i hello<^M><^C> - immediately insert
"hello"::i hello<^V><ESC> - insert
"hello"in raw ex mode:i hello - insert two lines in raw ex mode:
i hello<^M>world - insert
"hello"in raw ex mode (interactive):i<^M>hello<^M>.<^M>
- insert
[vrange]a[str]β enter ex insert mode after specified position.[range]c[str]β enter ex change mode.- In combination with
seqandlimex options, this command is optimal for modifying very long lines. - Max insertion buffer is
~1.33GBon a 32 bit build. - Max addressable line is
2.0GBon a 32 bit build.
- In combination with
For :c, the example set is giving exactly this energy:
- Example: replace the current line with
"hello":
:c hello<^M><ESC>
- Example: replace lines
1-5with"hello":
:1,5c hello<^M><ESC>
- Example: insert
"hello"at the current character offset:
:;c hello<^M><ESC>
- Example: insert
"hello"at the end of the line:
:;$c hello<^M><ESC>
- Example: insert
"hello"at line5and at the end of the line:
:5;$c hello<^M><ESC>
- Example: delete
5characters from the current position:
:;;+5c<^M><ESC>
[range]d β Delete line(s)
- Example: delete from the current position to the start of the buffer:
:1,.;0;d
- Example: delete from the current position to the end of the buffer:
:.,$;;$d
[vrange]j[any] β Join line(s)
Any argument activates padding mode. It lowkey returns an error if there is literally nothing to join.
- Example: join all lines:
:%-1j
- Example: join all lines with space padding:
:%-1j x
[vrange]s[<Any>][regex][<Any>][str][<Any>][<g>] β Substitute
Find and replace text in a range of lines that matches an enclosed regex with an enclosed replacement string. Returns an error if no substitution is performed. Periodt.
- Example: global replacement:
:%s/term1/term2/g
- Example: replace matching previously set regex:
:%s//term2/g
Substitution backreference inserts the text of the matched group specified by \x, where x is the group number. Obsessed.
- Example: substitution backreference:
this is an example text for subs and has int or void
:%s/(int)|(void)/pre\0after
this is an example text for subs and has preintafter or void
:%s/(int)|(void)/pre\2after/g
this is an example text for subs and has prepreafterafter or prevoidafter
ud β Undo
Returns an error if there is nothing to undo.
rd β Redo
Returns an error if there is nothing to redo.
[range]p[str] β Print line(s) from a buffer
No range prints a line based on the value of the left ex option. Argument prints the evaluated argument.
- Example: utilize character offset ranges:
:1,10;5;5p
- Example: interleaved character offset ranges:
:1;5,10;5p
- Example: print the current line from offset
5to10:
:.;5;10p
- Example: print buffer pathname:
:p %
[range]=[<0-3 Any>][any] β Print range numbers
Argument 0-3 selects a specific number. Any or any extra argument circumvents the buffer range check. No argument prints all range numbers.
- Example: print the current character offset only:
:;= 2
- Example: print the value of mark
<a>:
:'a=
- Example: calculate
75 - 100:
:,75-100=1p
=?[any] β Print last error
Any argument forwards the error status.
[range]m{marks} β Set line mark(s)
Valid marks: <a-z ' [ ] *>`
- Example: store ranges in
<a>and<s>for later reuse in:f>:
:>top>,#>bottom>m as:'a,'sf>middle
[range]ya[<reg>][any] β Yank into a register
Argument value range is 0x1-0xff and 0x0 without. Any extra argument appends to the register. The default register cannot be appended to.
- Example: append to register
<1>:
:ya 1x
- Example: yank into
<a>using ranges:
:1,5;5;5ya a
ya![<reg>] β Free a register
[range]pu[<reg>][any][\!{cmd}] β Paste or pipe a register
- Example: paste
<a>at line1, character offset5:
:1;5pu a
- Example: copy the default register to the X11 clipboard:
:pu \!xclip -selection clipboard
- Example: copy register
<a>to the X11 clipboard:
:pu a \!xclip -selection clipboard
[0-255]reg[str] β Print registers or put into a register
Prefix selects a register, and the argument replaces its contents.
- Example: shift the printing position to view offscreen register parts:
:1left:reg
- Example: put
"hello"into register<1>:
:49reg hello
[0-255]reg+[str] β Print registers or append to a register
e[path] β Open a file at a path
No argument opens the "unnamed" buffer. Files larger than 2.0GB are truncated on a 32 bit build. Line breaking happens until the first null terminator or EOF.
e![path] β Force open a file at a path
No argument re-reads the current buffer from the filesystem.
[vrange]ef[regex] β Open file using fuzzy search prompt
Requires the b-2 buffer to have a directory listing backfilled.
- Example: backfill
b-2using:fd:
:fd
- Example: backfill
b-2usingfind:
:b-2:%!find .
Prompt behavior is equivalent to the :f command.
- Example: enter prompt and print the entire listing:
:ef
- Example: search for a pathname containing
"v":
:ef v
[vrange]ef![regex] β Forced version of :ef
[range]r[path] / [range]r[\!{cmd}] β Read a file or a pipe
Range is computed on a target. No range evaluates to <%> range. No argument evaluates to the current buffer path.
- Example: read a file:
:r vi.c
- Example: pipe in all data:
:r \!ls
- Example: pipe in only lines
3,5:
:3,5r \!ls
[range]w[path] / [range]w[\!{cmd}] β Write a file or a pipe
No range evaluates to <%> range. No argument evaluates to the current buffer path.
- Example: write a file:
:w vi.c
- Example: pipe out all data into less:
:w \!less
- Example: pipe out only the first
10lines:
:1,10w \!less
[range]w![path] β Force write a file
[range]wq[path] / [range]wq[\!{cmd}] β Write a file or a pipe and exit
[range]wq![path] / [range]wq![\!{cmd}] β Force write a file or a pipe and force quit
[range]x[path] β Write unsaved changes and exit
[range]x![path] β Force write unsaved changes and force quit
[#lvl]q[#code] / [#lvl]q![#code] β Exit or force quit
[#code] specifies the shell exit code. [#lvl] defines the number of scopes to exit.
- Example: conditionally exit this scope and
1above:
:%f>marker:??!p no marker\:1q:s/old/new/g:w
b[index] β Print buffers or switch to a buffer
Temporary buffers are separate from the main buffers and are selected by a negative index.
- Example: switch to the 5th buffer:
:b5
- Example: switch to the
/hist/ex history buffer:
:b-1
- Example: switch to the
/fm/directory listing buffer:
:b-2
- Example: switch to the
/sc/scratch buffer:
:b-3
bp[path] β Set current buffer path
bs[any] β Set current buffer saved
Argument resets undo/redo history.
bx[#] β Set max number of buffers allowed
Buffers will be deallocated if the number specified is lower than the number of buffers currently in use. No argument will reset to the default value of 10.
cd[path] β Set a working directory
No argument relinks the current directory in case it got removed or unmounted.
Currently open buffers' file paths will be automatically adjusted to reflect a newly set working directory.
fp[path] β Clear or set a secondary directory path
fd[path] β Calculate directory listing in b-2 buffer
No argument uses secondary or a working directory path.
inc[regex] β Include regex for :fd calculation
No argument disables the filter.
- Example: include only files in the submodule directory that end with
.c:
:inc submodule.*\.c$
- Example: exclude
.gitand submodule folders:
:inc (^(?\:(?\!^\.git|^submodule).)+[^/]+$)
[range]![cmd] β Run an external program
When a range is specified, the buffer's data is piped to an external program. The resulting stdout and stderr are then piped back into the buffer, replacing the contents of the original range.
- Example: infamously sort a buffer:
:%!sort
- Example: replace
"int"with"uint"usingsed:
:%!sed -e 's/int/uint/g'
- Example: pipe in the result of an
lscommand without line replacement:
:;$+1!ls
- Example: capitalize the word at the current position using
tr:
:;;>\\>>!tr '[\:lower\:]' '[\:upper\:]'
&{macro} β Global non-blocking macro
Execute raw vi input sequence. A non-blocking macro shall not wait for input when the end of the sequence is reached. A non-blocking macro executing other macros will always reach a terminating point.
- Example: execute vi insert statement:
:& ihello
- Example: execute
:hello:
:& \:hello<^V><^M>
- Example: execute vi
"ci(int"macro:
:& ci(int
- Example: nest blocking macro inside non-blocking:
:& \:@ \\\:blocking<^V><^M>i continue in non-blocking
- Example: enable permanent vi line numbers:
:& 2#
@{macro} β Global blocking macro
Execute raw vi input sequence. A blocking macro shall wait for input when the end of the sequence is reached. A blocking macro executing other macros may cause input congestion.
- Example: execute vi insert statement:
:@ ihello
- Example: insert
"hello"into the<:>vi prompt:
:@ \:hello
- Example: execute vi
"ci(int"macro:
:@ ci(int
- Example: execute
"ci(int"exiting insert mode:
:@ ci(int<^V><^C>
- Example: execute
"ci)INT"as a follow-up:
:@ ci(int<^V><^C>ci)INT
- Example: execute vi
"dw"command after user exits insert:
:@i:@dw
[#count <$>]?[cond][<?>][then][<?>][else] β While loop conditional
Repeat [cond] [#count] times or infinite with [<$>]. While loop is broken once [cond] returns an error or count exceeded. Error status of [cond] is forwarded. No prefix creates a conditional with [#count] set to 1.
Like, the examples just keep coming, bestie:
- Example: attempt to join every line in file using arbitrary count β
:10000? & J - Example: undo everything β
:$? ud - Example: repeat chain of ex commands 10 times β
:10? 1p\:5p\:10p - Example: calculate directory only if
:cdsucceeded β:? cd /blah?fd - Example: print a line only if it contains
"int"at offset 5 β:? ;5;#>^int>?p - Example: edit
vi.conly if it exists β:? \![ -f ./vi.c ]?e ./vi.c:mpt1
[#count <$>]?![cond][<?>][else][<?>][then]β Inverted while loop conditional. Thatβs the whole vibe check on this one.[prefix]??[then][<?>][else]/{prefix}??β Conditional. Unlike the while loop conditional, branching depends on the error status of the last command, which lowkey reduces the number of escapes required.
A prefix without arguments captures the current error status at that point in a command chain into the id tag specified. Id tags are global across all nested command contexts.
A prefix with arguments branches based on the boolean expression in DNF over the most recent captures of each referenced id. If any id has no capture, neither branch executes.
Prefix operators:
- Numerical id tag
,AND (higher precedence);OR (lower precedence)- Example: capture error status at id 5, branch later β
:>int>:5??:;=:5??p - Example: skip if tag was never set β
:2??.=?.= - Example: AND β branch only if both ids captured success β
:f>int:1??:f>void:2??:1,2??p found both - Example: OR β branch if either id captured success β
:f>int:1??:f>void:2??:1;2??p found one - Example: DNF β
(1 AND 2) OR (3 AND 4)β:1,2;3,4??p then?p else - Example: inverted capture β capture NOT of last status β
:f>int:1??!:1??p int was absent
[prefix]??![else][<?>][then]/{prefix}??!β Inverted conditional. Same shape, opposite direction, periodt.{prefix}???β Evaluate prefix tags. This is anopcommand that evaluates a boolean expression at prefix and returns the result.- Example: control while loop from its
[then]argument β$?0\?\?\??+1\:0\?\?\:f>int\:\?\?p
- Example: control while loop from its
ft[filetype]β Set a filetype.
No argument prints the current file type. Reloads the highlight ft, which makes it possible to reset dynamic highlights created by options like hlw.
cm[keymap]β Set a keymap.
No argument prints the current keymap name.
cm![keymap]β Set an alternative keymap.ac[regex]β Set autocomplete filter regex.
No argument resets to the default word filter regex as defined in led.c.
- Example: autocomplete using whole lines from a buffer β
:ac .+
[<0-3>]sc[<esc>][<sep>][<exp>][<exe>]β Set ex special characters.
Prefix selects a specific character to change. Missing arguments default to <\ : % !>.
- Example: change
<%>to<a>β:2sc a - Example: utilize newly set separator in a single command chain β
:|1sc a|: p cmd1 a p cmd2 a|sc|a0?:p cmd3
[<0-3>]sc![<esc>][<sep>][<exp>][<exe>]β Set ex special characters. Missing arguments default to<0x0>.- Example: disable
<exp>and<exe>β:sc! \\\:
- Example: disable
ucβ Toggle multi-byte utf-8 decoding.
This command is particularly useful when editing files with mixed encodings, binary files, or when the terminal does not support UTF-8 or lacks the necessary fonts to display UTF-8 characters. It is often paired with :ph command to achieve hex editor-like functionality.
uzβ Toggle zero-width character placeholders. Hides zero-width characters rather than rendering them as placeholders.ubβ Toggle multi-codepoint sequence placeholders. Passes multi-codepoint sequences such as emojis to the terminal for native rendering rather than substituting placeholders.ph[#clow] [#chigh] [#width] [#blen][str]β Redefine placeholders.
This command replaces placeholders defined in conf.c and subsequent :ph commands expand the list of placeholders.
- Example: render 8 bit ascii (Extended ASCII) as
<~>β:ph 128 255 1 1~ - Example: flawless ISO/IEC 8859-1 (latin-1) support β
:uc:ph 128 160 1 1~ - Example: render control byte 03 as
"^C"β:ph 3 3 2 1^C - Example: reset to default as in
conf.cβ:ph - Example: disable default placeholders in
conf.cβ:ph:ph0
π EX OPTIONS π
Ex options are ex commands designed to alter global variables. Values hold a signed integer. Values may represent a character. Default value is specified in val= as part of an argument notation. No argument inverts the current value, unless stated otherwise.
ai[val=1]β Indent new lines. This is a max indent length multiplier:val * 128.ic[val=1]β Ignore case in regular expressions.ish[val=0]β Interactive shell.
Run every <!> command through an interactive shell. The shell will source the .rc file before command execution. This makes it possible to use predefined functions, aliases and ENV variables from the .rc file.
Precondition 1:
.rcrefers to a shell-specific filename, such as.bashrcin Bash or.zshrcin Zsh.
Precondition 2:
- The environment variable
$SHELLdetermines the default shell, otherwise it defaults to/bin/sh.
Precondition 3:
- There must be no stdout or stderr output created by
.rcfile for<!>commands to return expected results.
grp[val=0]β Regex search group.
Defines a target search group for any regex search operation. This becomes necessary when the result of a regex search is to be based on some group rather than the default match group.
- Example: position on a character prefixed by
"int"β:grp 1:%f+int(.):grp
hl[val=1]β Highlight text based on rules defined inconf.c.hlr[val=0]β Highlight text in reverse direction.hll[val=0]β Highlight current line based on filetype hl.hlp[val=0]β Highlight"[]""()""{}"pairs based on filetype hl.hlw[val=0]β Highlight current word based on filetype hl.led[val=1]β Enable all terminal output.vis[val=0]β Control startup flags.- bit 1: raw ex mode
- bit 2: ex mode
- bit 3: disable
:emessage - bit 4: alternate terminal screen
- Example: enable raw ex mode β
:vis 3 - Example: disable raw ex mode β
:vis 2
mpt[val=0]β Control vi prompts.
When set to 0 or 1 after an ex command is called from vi, disables the "[any key to continue]" prompt. If mpt is negative, the prompt will remain disabled.
- Example: block the prompt and the last print β
:p:p:p:mpt 0 - Example: block the prompt but not the last print β
:p:p:p:mpt 1
order[val=1]β Reorder characters based on rules defined inconf.c.shape[val=1]β Perform Arabic script letter shaping.pac[val=0]β Print autocomplete suggestions on the fly.ts[val=8]β Number of spaces used to represent a tab.td[val=1]β Current text direction context.
This option accepts four meaningful values:
2Exclusively left-to-right1Followdctxs[](inconf.c), defaulting to left-to-right-1Followdctxs[], defaulting to right-to-left-2Exclusively right-to-left
pr[val=0]β Print register.
Set a special register using a character or a number. Once the register is set, all data passed into ex_print will be stored in the register.
If the register is uppercase, <Newline> characters are added to match the exact output that was printed.
Print register contents cannot be displayed with R or :reg command when register is assigned (self-referential problem).
- Example: paste current buffer list exactly like from
:bcommand β:pr A:ya! A: b:pu A - Example: store a line printed with
:pβ:pr A:ya! A:p
lim[val=-1]β Line length render limit.
Set render cutoff length for non cursor lines in vi and all lines in ex mode.
Improves redraw performance when editing a file containing one or many long lines (1MB+ per line).
- Example: reasonable value β
:lim 5000 - Example: render only the cursor line β
:lim 0 - Example: disable the limit β
:lim -1
seq[val=1]β Control Undo/Redo.
When seq is 0, multiple distinct operations undo/redo in a single step.
To optimize memory usage under heavy workloads, undo/redo tracking can be disabled by setting seq to a negative value.
- Example: test undo/redo operations in a single step β
:&ocontrol test:seq 0:&a step1:&a step2:&a step3:seq - Example: completely disable undo/redo β
:seq -1
[hscroll]left[val=0]β Control horizontal scroll.
No argument calculates the value using current character offset. hscroll computes the value using: xcols / 2 * hscroll.
err[val=1]β Control ex errors.- bit 1: print errors
- bit 2: early return
- bit 3: ignore errors
- Example: silence and ignore errors β
:err 4 - Example: report and return on first error β
:err 3 - Example: report and consider only last command for error status β
:err 1
EXINIT ENV VAR π«Ά
Okay bestie, EXINIT is literally the glow-up button for your startup. It defines a chain of ex commands that get performed at startup, executed once after all files are opened. That's it β that's the whole magic. It's the only way to script and customize Nextvi outside of C or Unix pipes, so if you're not writing C today, this is your moment.
And like⦠many standard text processing utils such as grep, awk, sed can be replaced by Nextvi with EXINIT in mind. Iconic behavior, honestly.
printf with octal escapes is the standard way to embed control characters into EXINIT. That's the trick, iykyk.
Examples, because we love a demo:
export EXINIT='td 2:order 0:lim 5000'
Set ex options for optimal long line performance β¨
export EXINIT='b-1:r ./vi.c:b-1'
Load vi.c into a history buffer π
export EXINIT="$(printf 'e ./vi.c:& i\007\003:bx 1:bx')"
Index vi.c for autocomplete π
export EXINIT="$(printf '97reg o{\n}\003kA\n\t')"
Setup @ macro in register <a> π¦
The @a macro creates <{> and closing <}> below the cursor leaving cursor in insert mode in between the braces. Chef's kiss, no notes.
export EXINIT='98reg \:mpt-1\:;;$w \\\!xclip -selection clipboard\:mpt'
Setup @ macro in register <b> πΈ
The @b macro pipes the current line into X11 clipboard. Go off.
REGEX π
Pikevm is a fast non-backtracking NFA simulation regex engine developed for Nextvi. It ensures regular expressions are evaluated in constant space and O(n * k) time complexity where <n> is the input string length and <k> represents the regex's structural complexity (e.g., state transitions or alternations). While this does not guarantee strict O(n) linear runtime performance, it ensures computational and memory resources are distributed linearly and evenly across the input, with <k> directly influencing the constant factor. This principle is similar to the concept utilized in radix sort algorithms.
So like, lowkey the point is: resources stay chill and evenly spread instead of spiking. Not literally O(n), don't come for me β <k> is right there in the math.
Pikevm's syntax is akin to regexp(7) from Plan 9. Disregard manpage notation in this section.
.β Match any single character[N-M]β Match a set of alternate ranges N to M{N,M}β Match N to M times()β Capture grouping(?:)β Non capture grouping*β Repeated zero or more times+β Repeated one or more times|β Union, alternative branch?β One or zero matches greedy??β One or zero matches lazy^β Assert start of line$β Assert end of line\<β Assert start of word\>β Assert end of word(?=)β Assert positive lookahead(?!)β Assert negative lookahead(?>)β Assert positive lookbehind(?<)β Assert negative lookbehind(?#)β Lookbehind offset in bytes
Lookaround expressions enable the creation of regular expressions that would be impossible to construct without them. They can be used anywhere within a regex, though some considerations must be taken into account. Here's the vibe check:
Aspect 1: Lookarounds contain a full regular expression.
Aspect 2: Lookarounds can have nested lookarounds.
Aspect 3: Static lookarounds like (?=^word) are optimized, bypassing the regex engine. Free speed, we love her.
Aspect 4: Lookarounds are best suited for asserting near the end of a complex pattern, where the engine has already narrowed down potential matches.
Aspect 5: Lookbehind without offset or 0 offset begins at previous character. Offset begins scanning from current position minus specified value. Negative offset begins at the start of the string.
SPECIAL MARKS β
*β Position of previous ex command[β First position of previous change]β Last position of previous change'β Position of previous line region`β Position of previous line region
SPECIAL REGISTERS π
/β Previous regex keyword:β Previous ex command<0x0>β Default register<0>β Previous value of default register (atomic)
Atomic means the operation did not include a <Newline>.
<1-9>β Previous value(s) of default register (nonatomic)
CODE MAP πΊοΈ
Where everything lives, so you can go snoop:
βββββββββββββββββββββ¬βββββββββββββββββββββββ
β 537 kmap.h β keymap translation β
β 540 vi.h β definitions/aux β
βββββββββββββββββββββΌβββββββββββββββββββββββ€
β 353 term.c β low level IO β
β 367 conf.c β hl/ft/td config β
β 444 ren.c β positioning/syntax β
β 614 uc.c β UTF-8 support β
β 646 lbuf.c β file/line buffer β
β 725 led.c β insert mode/output β
β 766 regex.c β pikevm β
β 1758 ex.c β ex options/commands β
β 1879 vi.c β normal mode/general β
β 2997 patch2vi.c β patch converter β
β 10549 total β wc -l *.c|sort β
βββββββββββββββββββββ΄βββββββββββββββββββββββ
COMPILING π§
Bestie, build time. Watch:
export CC='g++ -x c'
Set compiler, g++ example.
export CFLAGS='-s'
Set CFLAGS, strip example.
./cbuild.sh
Build once.
./cbuild.sh build
Build.
./cbuild.sh debug
Build with symbols, static analysis, dynamic analysis, and no optimizations.
./cbuild.sh pgobuild
PGO build can lead to a significant performance boost on some application specific tasks. π₯
./cbuild.sh install
Install vi to $DESTDIR$PREFIX/bin.
./cbuild.sh fetch
Merge commits from upstream repository.
./cbuild.sh bench
Performance bench test 2000 word deletions on vi.c.
PHILOSOPHY π
Okay so this is the part where it gets deep, and honestly? She ate.
Most text editors accumulate significant technical debt. They cannot be quickly mastered, deeply understood, or easily changed. Nextvi is designed around three pillars: fundamental, lean, and flexible.
- Fundamental means a complete yet minimal command set for unlimited text transformation.
- Lean means a concise, efficient, coherent implementation with a bus factor of zero.
- Flexible means deep composability and a versatile, extensible C codebase.
By conventional wisdom, these three pillars would be considered oxymoronic. Maintaining all three challenges the notion that a text editor must sacrifice one for another. Nextvi proves that coexistence is not only possible but essential to what a great text editor should be.
"All software sucks, but some do more than others." β Kyryl Melekhin
Not the founder being brutally honest π but like, respectfully, correct.
SEE ALSO π
New functionality can be obtained through optional patches provided in the patches branch. If you have a meaningful contribution and would love to make it public, the patch can be submitted via email or GitHub pull request. https://github.com/kyx0r/nextvi/tree/patches
Patch2vi support utility https://github.com/kyx0r/nextvi/tree/patch2vi
Unit tests https://github.com/kyx0r/nextvi/tree/test
Scripts used to generate this manual https://github.com/kyx0r/nextvi/tree/manual
Unified tagged releases https://github.com/kyx0r/nextvi/tree/release
Original Neatvi repository https://github.com/aligrudi/neatvi
Posix vi(1) https://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html
Posix ex(1) https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html
NFA regular expressions by Russ Cox https://swtch.com/~rsc/regexp/regexp1.html
Plan 9 regexp(7) https://man.cat-v.org/p9p/7/regexp
AUTHORS π
Nextvi was written by Kyryl Melekhin <k.melekhin@gmail.com>. It is based on neatvi(1), which was written by Ali Gholami Rudi <ali@rudi.ir>. This manual page was inspired by nΓ©pΓ©ta <nepeta@canaglie.net>.
And that's the whole page, bestie β you made it to the end π«Ά this is Nextvi 5.3, dated Jun 7, 2026, and you just read Nextvi(1). Go forth and transform some text. π β¨
π¦ where this page comes from
- alpine 3.24: nextvi-doc 5.3-r0 Β· ISC
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms