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
<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
< > 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>
[#]<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 # times
vw  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 indent
0   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
'{<mark>}
    Move to a line mark
`{<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<Enter>
    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:<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 normal cmd using register arg. # applies to cmd
R   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 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{<arg>}
    Delete inside arg pairs
ci{<arg>}
    Delete inside arg pairs and enter insert mode
[#]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{<mark>}
    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/ 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
[#]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 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{<Any>}
    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>
<Backspace>
    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
<^\>{<arg>}
    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>{<arg>}
    Read a literal character arg
<^K>{arg}
    Read a digraph sequence arg
<^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 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:
    [<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 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

        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
        :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

[vrange]s[<Delim>][regex][<Delim>][str][<Delim>][<g>]
    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: global replacement
        :%s/term1/term2/g
        Example: replace matching previously set regex
        :%s//term2/g
        Substitution backreference inserts the text of matched group
        specified by \x where x is group number.
        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 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 or any extra argument circumvents 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 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 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 any id has no capture, neither branch executes.
        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.
    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:
        	.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[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 in conf.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 :e message
        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 in conf.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:
    2   Exclusively left-to-right
    1   Follow dctxs[] (in conf.c), defaulting to left-to-right
    -1  Follow dctxs[], defaulting to right-to-left
    -2  Exclusively 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 :b command
        :pr A:ya! 65: b:pu 65
        Example: store a line printed with :p
        :pr A:ya! 65:p

fr[val=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[val=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[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

    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="$(printf 'rr z:vis 2:&Q\n: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 <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.
    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 <Newline>.

<1-9>
    Previous value(s) of default register (nonatomic)

CODE MAP
537 kmap.h | keymap translation
550 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
665 lbuf.c | file/line buffer
730 led.c | insert mode/output
751 regex.c | pikevm
1870 ex.c | ex options/commands
1884 vi.c | normal mode/general
5335 patch2vi.c | patch converter
13033 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 $DESTDIR$PREFIX/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
-nosplit 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>.