README

August 11, 2026 ยท View on GitHub

Nextvi(1) General Commands Manual Nextvi(1)

NAME Nextvi - A small vi/ex terminal text editor

SYNOPSIS vi [-aemsv] [file ...]

DESCRIPTION Nextvi is a modern clone of the command-line text editor vi(1), initially developed by Bill Joy in 1976 for Unix-based systems. Nextvi builds upon many standard features from vi(1) including a unique modal interface that allows users to switch between normal, insert, and command modes for efficient text manipulation. Additional enhancements include an unrestricted macro system, syntax highlighting, keymaps, bidirectional UTF-8 support, and numerous other features. Nextvi remains highly efficient, portable, and hackable, ensuring its continued relevance and high quality for years to come.

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 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 < > Space separates alternatives in a closure # Decimal representation in a closure x-y Range from x to y

VI NORMAL [#]j Move # lines down [#]k Move # lines up [#]+ [#]<^M> [#] 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 move backward # times [#]; Repeat last 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 # times vw Toggle single-line mode for 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 section down # times [#]] Move to next section up # times ^ Move to start of line after indent 0 Move to start of line $ Move to end of line [#]| Goto # column [#] Move # characters forward [#]<^H> [#] Move # characters backward % Move to closest <] ) } [ ( {> pair {#}% Move to # percent line number '{} Move to a line mark `{} Move to a line mark with cursor position gg Goto first line in buffer [#]G Move to last line in buffer or # line H Move to highest line on a screen L Move to lowest line on a screen M Move to middle line on a screen z. Center screen at cursor z<^M> z Center screen at top row z- 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 numbers 2# Toggle show global line numbers permanently 4# Toggle show relative line numbers after indent permanently 8# Toggle show relative line numbers permanently V Toggle show hidden characters: <^C> Toggle show line motion numbers for {<1-5>}<^C> Select line motion number mode 1-5 <^V> Loop through line motion number modes [#]<^R> Redo # times [#]u Undo # times <^I> 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 [#]"{}{cmd} Execute normal cmd using register arg. # applies to cmd [#]"{}q Start recording and set rr ex option to arg register. # keeps register contents q Stop recording and set rr ex option to 0 R Print registers and their contents [#]&{} Execute arg register macro in non-blocking mode # times [#]@{} 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 recursively. # retains current horizontal scroll : Enter ex prompt [#]!{arg} Enter pipe ex prompt based on # or arg region vv Enter ex prompt with the last line from history buffer b-1 [#]vr Enter %s/ ex prompt. Insert # words from cursor [#]vt[#arg] Enter .,.+0s/ ex prompt. Insert # of lines from cursor. Insert #arg words from cursor [#]v/ Enter re ex prompt to set regex keyword. Insert # words from cursor v; 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 width vo Remove trailing white spaces and <\r> line endings <^G> Print buffer status info 1<^G> Enable permanent status row 2<^G> Disable permanent status row ga Print character info 1ga Enable permanent character info row 2ga 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 forward i Enter insert mode I Enter insert mode at start of line after indent A Enter insert mode at end of line a Enter insert mode 1 character forward o Create a new line down and enter insert mode O 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 mode C Delete from cursor to end of line and enter insert mode [#]d{arg} Delete arg region # times D Delete from cursor to end of line [#]x Delete # characters from cursor forward [#]X Delete # characters from cursor backward [#]di{} Delete inside arg pairs, skip # matches [#]ci{} Delete inside arg pairs and enter insert mode. Skip # matches [#]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 # times m{} 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, # reverses direction between forward and backward \ Swap to /fm/ buffer b-2 {#}\ Refresh secondary directory listing in b-2 vb Recurse into b-1 history buffer. Insert current line into ex prompt on exit z1 Set alternative keymap to Farsi keymap z2 Set alternative keymap to Russian keymap ze Switch to English keymap zf Switch to alternative keymap zL Set td ex option to 2 zl Set td ex option to 1 zr Set td ex option to -1 zR Set td ex option to -2 [#]/ Regex search prompt, move down 1 or # matches [#]? Regex search prompt, move up 1 or # matches [#]n Repeat regex search, move 1 or # matches [#]N Repeat regex search, inverted move 1 or # matches <^A> Regex search 1 word from cursor, no center, wraparound move up or down * Regex search, no center, wraparound move up or down {#}* {#}<^A> Regex search, set keyword to # words from cursor <^]> Filesystem regex search forward based on directory listing in b-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 dimensions [#]Z{} Exit and clean terminal, force quit # recursion levels [#]Zz Exit and submit history command, force quit # recursion levels ZZ Exit and write unsaved changes to a file <ESC ^C> Cancel any pending input or command

VI REGIONS Regions are vi normal commands that define [h v]range for vi motions. Commands described with the word "move" define a region.

 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 described with the word "region" consume a region. Motions can be prefixed or suffixed by [#].

 <^W> > < ! c d y g~ gu gU
         All motions

 dd yy cc g~~ guu gUU >> << <^W><^W> !!
         Special motions that can use [#] as number of lines

 Examples:
 3d/int  Delete text until 3rd instance of "int" keyword
 3dw     Delete 3 words (prefix [#])
 d3w     Delete 3 words (suffix [#])
 "ayl    Yank a character into <a> register
 "Ayw    Append a word to <a> register

VI/EX INSERT <^H> Delete a character, reset ex mode when empty <^U> Delete until <^X> mark or all <^W> Delete a word <^T> Increase indent <^D> Decrease indent <^]> Select paste register from 0-9 registers in a loop <^>{} Select paste register arg. <^> selects 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 into b-1 history buffer when in ex prompt. Insert current line into ex prompt on exit <^A> Loop through lines in a history buffer b-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>{} Read a literal character arg <^K>{arg} Read a digraph sequence arg <^C> Exit insert mode in vi, reset in ex <^M> Insert 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 serves as the backbone of vi, enabling it to execute commands, macros and even transform into a purely command-line interface (CLI) when desired.

EX PARSING Parsing follows the structure: [][prefix][cmd][][args] Ex commands are initiated and separated by . Fields can be padded by or . [prefix] is a field consumed by [cmd], which accepts [range] structure characters. Padding inside [prefix] structure is collapsed, except within nested blocks. 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] and [prefix] blocks will become regular when escaped with <>. Escapes are governed by a non-POSIX parity rule: escapes directly before a special are halved, an odd amount makes the special regular, and escapes anywhere else are literal.

 ( ^ ] -
         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.

 Example: make a copy of the current file and edit it
 :!cp % %_:e %_
 Example: insert current buffer pathname
 :&i%
 Example: echo the value of <a> register
 :!echo %@97

 <!> in [args] starts and optionally ends a block containing
 external commands. This block executes and expands to stdout
 and stderr produced.

 Example: substitute "int" with the value of $RANDOM
 :%s/int/!printf "%s" $RANDOM!
 Example: insert output of ls shell command
 :&i!ls
 Example: insert output of ls more efficiently
 :;c!ls!<^V><ESC>

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].

 [% |][, ;][#][. $ ' > <][- + * / %][#num]
         All ranges structure
 {|}{cmd}[|]
         Ex subcommand structure
 {>}[regex][>]
         Search forward structure
 {<}[regex][<]
         Search backward structure
 '{#mark}
         Mark structure

 %       Range from first to last line
 |       Begin ex subcommand block
 ,       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 block
 <       Begin search backward block
 -       Subtract following number
 +       Add following number
 *       Multiply by the following number
 /       Divide by the following number
 %       Modulo by the following number
 #num    Number or position

 Examples:
 :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
 :'100,'97p
         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
 :'97;'97
         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=
         +10 is relative to the initial current offset, not 5
 :;5;#+10=
         +10 is 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

         No argument uses previously set regex keyword.
         Returns error if target not found.

         Example: no range given, current line only
         :f>int
         Example: reverse
         :f<int
         Example: range given
         :10,100f>int

 [range]f+[regex]
 [vrange]f-[regex]
         Incrementing ranged search

         Equivalent to the :f> and :f< commands, except subsequent commands
         advance past match boundary. Cannot match inplace.

 [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 * 3 matches.

 [vrange]g[<Delim>][regex][<Delim>][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.

         Example: remove all empty lines
         :g/^$/d

         Example: print lines matching previously set regex keyword
         :g//p

         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+ 97

         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![<Delim>][regex][<Delim>][cmd]
         Inverted global command

 [range]re[regex]
         Set regex keyword

         Range escapes its text and uses it as the regex.

         Example: set keyword to "int"
         :re int
         Example: set keyword from lines 1 to 3
         :1,3re

 [vrange]i[str]
         Enter ex insert mode

         [str] specifies initial input into the insertion buffer.
         [str] in raw ex mode is injected directly and bypasses the
         interactive mode.

         Example: insert "hello" in vi/ex
         :i hello<^M><ESC>
         Example: insert "hello" in vi/ex trimming <Newline>
         :i hello<^M><^M><Backspace>
         Example: discard changes in vi/ex
         :i hello<^M><^C>
         Example: immediately insert "hello"
         :i hello<^V><ESC>
         Example: insert "hello" before specified position
         :-1i hello<^V><ESC>
         Example: insert "hello" before line 1 (special case)
         :0i hello<^V><ESC>
         Example: insert "hello" in raw ex mode
         i hello
         Example: insert two lines in raw ex mode
         i hello<^M>world
         Example: insert "hello" in raw ex mode (interactive)
         i<^M>hello<^M>.<^M>

 [range]c[str]
         Enter ex change mode

         In combination with seq and lim ex options, this command is
         optimal for modifying very long lines.
         Max insertion buffer is ~1.33GB on a 32 bit build.
         Max addressable line is 2.0GB on a 32 bit build.

         Example: replace current line with "hello"
         :c hello<^M><ESC>
         Example: replace lines 1-5 with "hello"
         :1,5c hello<^M><ESC>
         Example: insert "hello" at current character offset
         :;c hello<^M><ESC>
         Example: insert "hello" at end of line
         :;$c hello<^M><ESC>
         Example: insert "hello" at line 5 and end of line
         :5;$c hello<^M><ESC>
         Example: delete 5 characters from current position
         :;;+5c<^M><ESC>

 [range]d
         Delete line(s)

         Example: delete from current position to the start of the buffer
         :1,.;0;d
         Example: delete from current position to the end of the buffer
         :.,$;;$d

 [vrange]j[any]
         Join line(s)

         Any argument activates padding mode.
         Returns error if there is nothing to join.

         Example: join all lines
         :%-1j
         Example: join all lines with space padding
         :%-1j x

 [range]s[<Delim>][regex][<Delim>][str][<Delim>][<g>][<m>][#reg]
         Substitute

         Find and replace text in a range of lines that matches an
         enclosed regex with an enclosed replacement string.
         Returns error if no substitution is performed.

         Example: range scoping
         :1,5;5;5s/term1/term2/

         Example: replace matching previously set regex keyword
         :%s//term2/

         Substitution backreference in [str] inserts the text of matched
         group specified by \# where # is a group number. Digits are
         consumed greedily up to the highest existing group, rest are
         literal.

         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

         Example: global replacement with <g>
         :%s/term1/term2/g

         Example: multiline mode <m>
         :.,+1s/term1<^V><^M>term2/term3/m

         Example: edit register <a> inplace
         :s/term1/term2/97g

 ud      Undo

         Returns error if there is nothing to undo.

 rd      Redo

         Returns 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 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 current line from offset 5 to 10
         :.;5;10p
         Example: print buffer pathname
         :p %

 [range]=[<0-3 Any>][any]
         Print range numbers

         Argument 0-3 selects a specific number.
         Any non-<0-3> or extra argument bypasses the buffer range check.
         No argument prints all range numbers.

         Example: print current character offset only
         :;= 2
         Example: print value of mark <a>
         :'97=
         Example: calculate 75 - 100
         :,75-100=1p

 =?[any]
         Print last error

         Any argument forwards the error status.

 [range]m{#marks}
         Set line mark(s)

         Marks are ids separated by spaces, set alternating between start
         and end of the range.

         Example: store ranges in <a> and <s> for later reuse in :f>
         :>top>,#>bottom>m 97 115:'97,'115f>middle

 [range]ya[#reg]
         Yank into a register

         No argument yanks into default register.

         Example: yank into <a> using ranges
         :1,5;5;5ya 97

 [range]ya+[#reg]
         Yank and append to a register

         Example: append to register <1>
         :ya+ 49

 ya![#reg]
         Free a register

 [range]pu[#reg][any][\!{cmd}]
         Paste or pipe a register

         Example: paste <a> at line 1 character offset 5
         :1;5pu 97
         Example: paste <a> before line 1 (special case)
         :0pu 97
         Example: copy default register to X11 clipboard
         :pu \!xclip -selection clipboard
         Example: copy register <a> to X11 clipboard
         :pu 97 \!xclip -selection clipboard

 [#reg]reg[str]
         Print registers or put into a register

         Prefix selects a register and argument replaces its contents.
         Prefix with no argument reassigns the default register.

         Example: shift the printing position to view offscreen register parts
         :1left:reg
         Example: put "hello" into register <1>
         :49reg hello

 [#reg]reg+[str]
         Print registers or append to a register

 e[path]
         Open a file at a path

         No argument opens "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-2 using :fd
         :fd
         Example: backfill b-2 using find
         :b-2:%!find .

         Prompt behavior is equivalent to the :f command.

         Example: enter prompt & print entire listing
         :ef
         Example: search for 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 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 current buffer path.

         Example: write a file
         :w vi.c
         Example: pipe out all data into less
         :w \!less
         Example: pipe out only first 10 lines
         :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[0-255]
         Exit

         Prefix exits [#lvl] ex recursion levels.
         Argument specifies shell exit code.

         Example: conditionally exit this level and 1 above
         :%f>marker:??!p no marker\:1q:s/old/new/g:w

 [#lvl]q![0-255]
         Force quit

         Prefix force quits [#lvl] recursion levels.
         No prefix quits all recursion levels.

         Example: set register <#0> to "hello" 3 levels deep, force quit
         this level and 2 above, print the register outside
         :&Q&Q\\\:&Q0reg hello\\\\\\\:2q\\\\\\\!:p %@0

 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 resets 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 submodule directory that end with .c
         :inc submodule.*\.c$
         Example: exclude .git and 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.
         No range returns an error if shell exit code is not zero.

         Example: infamously sort a buffer
         :%!sort
         Example: replace "int" with "uint" using sed
         :%!sed -e 's/int/uint/g'
         Example: pipe in result of ls command without line replacement
         :;$+1!ls
         Example: capitalize word at 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 <:> 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]
         While loop

         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 defaults [#count] to 1.

         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

 [#count <$>]?![cond]
         Inverted while loop

 [prefix]??[then]
 {prefix}??
         Conditional

         Branching depends on the error status of the last command.
         Error status of [then] is forwarded.
         No prefix and no argument forwards the last error status.

         A prefix without arguments captures the current error status
         at that point in a command chain into 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 id has no capture, the branch is skipped.

         Prefix operators:
         Numerical id tag
         , AND (higher precedence)
         ; OR (lower precedence)

         Example: calculate directory only if :cd succeeded
         :cd /blah:?? fd
         Example: print a line only if it contains "int" at offset 5
         :;5;#>^int>:?? p
         Example: edit vi.c only if it exists
         :![ -f ./vi.c ]:??e ./vi.c:mpt1
         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

 [prefix]??![then]
 {prefix}??!
         Inverted conditional

         Example: inverted capture
         :f>int:1??!:1??p int was absent

 {prefix}???
         Evaluate prefix tags

         This is a nop command that evaluates a boolean expression
         at prefix and returns the result.

         Example: control while loop
         :$? \%f+int\:1??\:\%f+void\:2??\:1,2??p\:1,2???

 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 <#0>.

         Example: disable <exp> and <exe>
         :sc! \\\:

 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][<Space>][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. Variables hold a signed integer. Argument sets the value. A non-numeric argument yields its first byte. No argument logically inverts the current value, unless stated otherwise.

 Argument notation shows the default value.

 ai[1]   Indent new lines

         This is a max indent length multiplier: value * 128

 ic[1]   Ignore case in regular expressions

 ish[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:
                 .rc refers to a shell-specific filename, such as .bashrc
                 in Bash or .zshrc in Zsh.
         Precondition 2:
                 The environment variable $SHELL determines the default
                 shell, otherwise it defaults to /bin/sh.
         Precondition 3:
                 There must be no stdout or stderr output created by .rc
                 file for <!> commands to return expected results.

 grp[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[1]   Highlight text based on rules defined in conf.c
 hlr[0]  Highlight text in reverse direction
 hll[0]  Highlight current line based on filetype hl
 hlp[0]  Highlight "[]" "()" "{}" pairs based on filetype hl
 hlw[0]  Highlight current word based on filetype hl
 led[1]  Enable all terminal output

 vis[0]  Control startup flags

         bit 1: raw ex mode
         bit 2: ex mode
         bit 3: disable :e message
         bit 4: alternate terminal screen

         Example: enable raw ex mode
         :vis 3
         Example: disable raw ex mode
         :vis 2

 mpt[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: disable the prompt and the last print
         :p:p:p:mpt 0
         Example: disable the prompt but not the last print
         :p:p:p:mpt 1

 order[1]
         Reorder characters based on rules defined in conf.c
 shape[1]
         Perform Arabic script letter shaping
 pac[0]  Print autocomplete suggestions on the fly
 ts[8]   Number of spaces used to represent a tab
 td[1]   Current text direction context

         value  2: exclusively left-to-right
         value  1: follow dctxs[] in conf.c, default left-to-right
         value -1: follow dctxs[] in conf.c, default right-to-left
         value -2: exclusively right-to-left

 pr[0]   Print register

         Set a special register using a character or a number.
         Once the register is set, all ex printed output 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 :b command
         :pr A:ya! 65: b:pu 65
         Example: store a line printed with :p
         :pr A:ya! 65:p

 fr[0]   Find register

         Set a register using a character or a number.
         Once the register is set, the :f> and :f+ commands perform a
         multi-line search forward on the contents of the register instead
         of the current buffer. Range maps the match to a position in
         the current buffer. No range tests for a match inplace.

         Example: search register <a> for "int"
         :fr a:f>int:??p yes:??!p no:fr
         Example: search for "int" followed by "void" on next line
         :%ya97:fr 97:%f>int.void:fr

 rr[0]   Record register

         Set a register using a character or a number.
         Once the register is set, every byte read from the terminal is
         appended to the register. Input replayed from registers is not
         recorded, so replaying a recorded register cannot record itself.

         Example: record keystrokes into register <a>
         :rr a
         Example: stop recording
         :rr
         Example: replay recording from register <a>
         :& %@97

 lim[-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[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[0]
         Control horizontal scroll

         No argument calculates the value using current character offset.
         hscroll computes the value using: xcols / 2 * hscroll

 err[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 EXINIT defines a chain of ex commands to be performed at startup, executed once after all files are opened. This is the only way for scripting and customizing Nextvi outside of C or Unix pipes. Many standard text processing utils such as grep, awk, sed can be replaced by Nextvi with EXINIT in mind.

 printf with octal escapes is the standard way to embed control
 characters into EXINIT.

 Examples:

 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>

         @a macro creates <{> and closing <}> below the cursor leaving
         cursor in insert mode in between the braces.

 export EXINIT='98reg \:mpt-1\:;;$w \\\!xclip -selection clipboard\:mpt'
         Setup @ macro in register <b>

         @b macro pipes the current line into X11 clipboard.

 export EXINIT='rr z:vis 2:&Q:b-3:pu 122:wq! bugreport.txt'
         Capture session for a bug report

         Recording starts into register <z>. Setting vis 2 makes <Q>
         toggle straight into a regular vi session where the user takes
         over.  Quitting it with :q resumes the macro, which writes the
         recording to bugreport.txt.

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 is the input string length and 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 directly influencing the constant factor. This principle is similar to the concept utilized in radix sort algorithms.

 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.
 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.
 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 <#0> Default register <0> Previous value of default register (atomic) Atomic means the operation did not include a . <1-9> Previous value(s) of default register (nonatomic)

CODE MAP +--------------+----------------------+ | 537 kmap.h | keymap translation | | 552 vi.h | definitions/aux | +--------------+----------------------+ | 351 term.c | low level IO | | 372 conf.c | hl/ft/td config | | 460 ren.c | positioning/syntax | | 615 uc.c | UTF-8 support | | 666 lbuf.c | file/line buffer | | 735 led.c | insert mode/output | | 751 regex.c | pikevm | | 1903 vi.c | normal mode/general | | 1930 ex.c | ex options/commands | | 7783 total | wc -l *.c|sort | +--------------+----------------------+

COMPILING 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 DESTDIRDESTDIRPREFIX/bin ./cbuild.sh fetch Merge commits from upstream repository ./cbuild.sh bench Performance bench test 2000 word deletions on vi.c

PHILOSOPHY 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

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 nepeta nepeta@canaglie.net.

Nextvi 7.4 August 11, 2026 Nextvi 7.4