Commit Graph

355 Commits

Author SHA1 Message Date
Ron Yorston
38e9c8c95b vi: don't right shift empty lines
The right shift command ('>') shouldn't affect empty lines.

function                                             old     new   delta
do_cmd                                              4860    4894     +34
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 34/0)               Total: 34 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-08-20 15:26:09 +02:00
Ron Yorston
f9217cd235 vi: support ~/.exrc
Run initialisation commands from ~/.exrc.  As with EXINIT these
commands are processed before the first file is loaded.

Commands starting with double quotes are ignored.  This is how
comments are often included in .exrc.

function                                             old     new   delta
vi_main                                              268     406    +138
colon                                               4033    4071     +38
.rodata                                           108411  108442     +31
packed_usage                                       34128   34118     -10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 207/-10)           Total: 197 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-08-20 15:26:09 +02:00
Ron Yorston
f07772f19e vi: changes to handling of -c and EXINIT
Rewrite handling of command line arguments so any number of -c
commands will be processed.  Previously only two -c commands
were allowed (or one if EXINIT was set).

Process commands from EXINIT before the first file is read into
memory, as specified by POSIX.

function                                             old     new   delta
run_cmds                                               -      77     +77
.rodata                                           108410  108411      +1
vi_main                                              305     268     -37
edit_file                                            816     764     -52
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/2 up/down: 78/-89)            Total: -11 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-08-20 15:26:09 +02:00
Denys Vlasenko
d6a7203042 vi: fix compile-time error if !ENABLE_FEATURE_VI_SETOPTS
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-08-16 01:31:32 +02:00
Denys Vlasenko
95fffd8a7f vi: remove redundant assignment
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-14 16:32:19 +02:00
Ron Yorston
e6f4145f29 vi: fix regex search compilation error
Building with FEATURE_VI_REGEX_SEARCH enabled fails.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
2021-07-13 18:23:43 +02:00
Denys Vlasenko
36feb26824 vi: somewhat more readable code, no logic changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-13 16:16:21 +02:00
Ron Yorston
2759201401 vi: allow delimiter in ':s' to be escaped
When regular expressions are allowed in search commands it becomes
possible to escape the delimiter in search/replace commands.  For
example, this command will replace '/abc' with '/abc/':

   :s/\/abc/\/abc\//g

The code to split the command into 'find' and 'replace' strings
should allow for this possibility.

VI_REGEX_SEARCH isn't enabled by default.  When it is:

function                                             old     new   delta
strchr_backslash                                       -      38     +38
colon                                               4378    4373      -5
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/1 up/down: 38/-5)              Total: 33 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-13 14:42:20 +02:00
Denys Vlasenko
95ac4a48f1 vi: allow regular expressions in ':s' commands
BusyBox vi has never supported the use of regular expressions in
search/replace (':s') commands.  Implement this using GNU regex
when VI_REGEX_SEARCH is enabled.

The implementation:

- uses basic regular expressions, to match those used in the search
  command;

- only supports substitution of back references ('\0' - '\9') in the
  replacement string.  Any other character following a backslash is
  treated as that literal character.

VI_REGEX_SEARCH isn't enabled in the default build.  In that case:

function                                             old     new   delta
colon                                               4036    4033      -3
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-3)               Total: -3 bytes

When VI_REGEX_SEARCH is enabled:

function                                             old     new   delta
colon                                               4036    4378    +342
.rodata                                           108207  108229     +22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 364/0)             Total: 364 bytes

v2: Rebase.  Code shrink.  Ensure empty replacement string is null terminated.

Signed-off-by: Andrey Dobrovolsky <andrey.dobrovolsky.odessa@gmail.com>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-13 14:38:20 +02:00
Ron Yorston
c76c78740a vi: improve handling of anchored searches
Suppose we search for a git conflict marker '<<<<<<< HEAD' using
the command '/^<<<'.  Using 'n' to go to the next match finds
'<<<' on the current line, apparently ignoring the '^' anchor.

Set a flag in the compiled regular expression to indicate that the
start of the string should not be considered a beginning-of-line
anchor.  An exception has to be made when the search starts from
the beginning of the file.  Make a similar change for end-of-line
anchors.

This doesn't affect a default build with VI_REGEX_SEARCH disabled.
When it's enabled:

function                                             old     new   delta
char_search                                          247     285     +38

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-13 13:50:59 +02:00
Ron Yorston
2916443ab6 vi: use basic regular expressions for search
Both traditional vi and vim use basic regular expressions for
search.  Also, they don't allow matches to extend across line
endings.  Thus with the file:

   123
   234

the search '/2.*4$' should find the second '2', not the first.

Make BusyBox vi do the same.

Whether or not VI_REGEX_SEARCH is enabled:

function                                             old     new   delta
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0)                 Total: 0 bytes

Signed-off-by: Andrey Dobrovolsky <andrey.dobrovolsky.odessa@gmail.com>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-13 13:36:29 +02:00
Ron Yorston
b50ac07cba vi: allow 'gg' to specify a range
Commit 7b93e317c (vi: enable 'dG' command. Closes 11801) allowed
'G' to be used as a range specifier for change/yank/delete
operations.

Add similar support for 'gg'.  This requires setting the 'cmd_error'
flag if 'g' is followed by any character other than another 'g'.

function                                             old     new   delta
do_cmd                                              4852    4860      +8
.rodata                                           108179  108180      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 9/0)                 Total: 9 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-13 13:32:13 +02:00
Ron Yorston
5dbbd0a6f5 vi: stored search pattern applies to ':s'
The same stored search pattern applies to both search ('/') and
search/replace (':s') operations.

A search/replace operation with an empty "find" string (':s//abc/')
should use the last stored search pattern, if available, and issue an
error message if there is none.

If the "find" string is not empty it should replace the stored search
pattern.

function                                             old     new   delta
colon                                               3952    4024     +72
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 72/0)               Total: 72 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-27 13:36:49 +02:00
S Harris
5c89e5a04e vi: fix read outside of text buffer during insert
Signed-off-by: S Harris <S.E.Harris@kent.ac.uk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-23 19:15:07 +02:00
Ron Yorston
51358757c7 vi: fix backward search with GNU regex
With FEATURE_VI_REGEX_SEARCH enabled backward searches don't work.
This is problematic on distros that enable regexes, such as Tiny
Core Linux and Fedora.

When calling GNU re_search() with a negative range parameter
(indicating a backward search) the start offset must be set to
the end of the area being searched.

The return value of re_search() is the offset of the matched pattern
from the start of the area being searched.  For a successful search
(positive return value) char_search() can return the pointer to
the start of the area plus the offset.

FEATURE_VI_REGEX_SEARCH isn't enabled by default but when it is:

function                                             old     new   delta
char_search                                          256     247      -9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-9)               Total: -9 bytes

Signed-off-by: Andrey Dobrovolsky <andrey.dobrovolsky.odessa@gmail.com>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-21 15:37:28 +02:00
Ron Yorston
038d400709 vi: reject change command when motion fails
If the motion command used to define the range of a change, yank or
delete fails the whole command should be rejected.  BusyBox vi already
handled failed searches in these circumstances.  Add some more cases:

- non-existent mark: d'x

- movement beyond end of file: c99999+ or 99999<<

This is implemented using a global variable which is set when a command
error is detected.  Unlike the case of motion within a line it's
insufficient to check that the motion command doesn't move the cursor:
this fails to process 'LyL' correctly, for example, as the second 'L'
doesn't move the cursor.

function                                             old     new   delta
indicate_error                                        75      82      +7
find_range                                           686     692      +6
do_cmd                                              4851    4852      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 14/0)               Total: 14 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 23:53:03 +02:00
Ron Yorston
ac04eb3657 vi: up/down motion beyond end of file should fail
In traditional vi and vim line motion commands ('+'/'-'/'j'/'k')
fail if the movement would exceed the bounds of the file.  BusyBox vi
allowed such commands to succeed, leaving the cursor on the first or
last character of the file.

Make BusyBox vi work like vi/vim.

For the 'G'/'H'/'L' commands traditional vi treats an out of bounds
result as an error, vim doesn't.  BusyBox vi behaves like vim, both
before and after this patch.

function                                             old     new   delta
do_cmd                                              4785    4851     +66
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 66/0)               Total: 66 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 23:53:03 +02:00
Ron Yorston
f1d21b7434 vi: keep autoindent if line isn't empty
When ESC is entered to leave insert mode any autoindent should only
be removed if there's no content beyond the indent.  This may be the
case if a line has been split by entering insert mode and then
entering a CR.

Add a check to ensure there's only a newline after the indent.

function                                             old     new   delta
char_insert                                          912     929     +17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 17/0)               Total: 17 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 23:53:03 +02:00
Ron Yorston
52c4b7ac3b vi: initialise tabstop once not for each file
The default tabstop value should be set during early start up,
not reset for each new file.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-14 20:58:17 +02:00
Ron Yorston
f7ed0e8ae0 vi: ':r' should insert text after current line
When no line number is specified ':read' should place the inserted
text after the current line, not before.

This used to be correct but was broken when commit 0c42a6b07
(vi: fix empty line range regression) revealed a bug in commit
7a8ceb4eb (vi: changes to line addresses for colon commands).

function                                             old     new   delta
colon                                               3960    3952      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-8)               Total: -8 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-14 20:58:17 +02:00
Denys Vlasenko
6b6826f0b8 *: --help tweaks
function                                             old     new   delta
.rodata                                           103190  103189      -1
packed_usage                                       33590   33566     -24
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-25)             Total: -25 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-13 01:08:48 +02:00
Ron Yorston
9659a8db1d vi: remove autoindent from otherwise empty lines
Lines that have no content apart from automatic indentation should
be treated as empty when the user hits return or ESC.

The implementation uses the global variable 'indentcol'.  Usually
this is zero.  It can also be -1 to indicate an 'O' (open above)
command, replacing the overloading of the tabstop option bit.

A value greater than zero indicates that the current line has
been autoindented to the given column (or that the autoindent has
been adjusted with ctrl-D).  Any other change to the line resets
'indentcol' to zero.

Replace strspn() with ident_len().  The latter handles the unlikely
case that it's called on the last line of a file which doesn't have
a terminating newline.

function                                             old     new   delta
char_insert                                          741     912    +171
indent_len                                             -      42     +42
do_cmd                                              4781    4785      +4
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/0 up/down: 217/0)             Total: 217 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-02 06:29:34 +02:00
Ron Yorston
16e2fa9049 vi: make autoindent respect expandtab setting
Autoindent took a copy of the indent from a neighbouring line, which
may not have respected the expandtab setting.

Determine the target column and construct a suitable indent.  This
will consist entirely of spaces if expandtab is enabled or an
efficient combination of tabs and spaces otherwise.

function                                             old     new   delta
char_insert                                          719     741     +22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 22/0)               Total: 22 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-02 06:16:36 +02:00
Ron Yorston
d95f89ec57 vi: make cursor positioning more vi compatible
Commit 24effc7a3 (vi: cursor positioning after whole-line 'y')
tried to save a few bytes by treating whole-line deletion the
same as whole-line yank.  If the deletion removed the last lines
of the file the cursor was left beyond the end of the file.
Revert the part of the commit related to whole-line deletion.

Position the cursor on the first non-whitespace character of the
line when whole lines are 'put'.

function                                             old     new   delta
do_cmd                                              4759    4781     +22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 22/0)               Total: 22 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-02 06:16:36 +02:00
Ron Yorston
8e71f2aab8 vi: :wq/:x should warn if there are more files to edit
':wq' or ':x' should issue a warning if there are more files to edit,
unless they're followed by '!'.

function                                             old     new   delta
colon                                               3911    3960     +49
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 49/0)               Total: 49 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-05-04 14:51:48 +02:00
Ron Yorston
24effc7a3f vi: cursor positioning after whole-line 'y'
The 'y' command to yank text should leave the cursor at the start
of the range.  This mostly works correctly in BusyBox vi but not
for whole-line yanks with backward motion, e.g. '2yk' to yank two
lines backwards.  In this case the cursor is left at the end of the
range.

Fix this by returning the actual range from find_range().  Cursor
positioning following whole-line deletion is inconsistent between
vim and traditional vi.  For BusyBox vi chose the option that uses
least code without being exactly compatible with either.

Also, find_range() preserved the value of 'dot', the current cursor
position.  Since this isn't used by either caller of find_range()
we can save a few bytes by not bothering.

function                                             old     new   delta
do_cmd                                              4730    4759     +29
find_range                                           749     686     -63
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 29/-63)            Total: -34 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-05-04 14:51:48 +02:00
Denys Vlasenko
74e1f321c1 vi: trivial code shrink
function                                             old     new   delta
get_input_line                                       178     176      -2

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-05-01 14:00:09 +02:00
Ron Yorston
0c42a6b072 vi: fix empty line range regression
Commit 7a8ceb4eb (vi: changes to line addresses for colon commands)
was supposed to address the issue:

  When the last address is empty it should refer to the current line.

This was intended to allow ranges of the form '1,' with an empty
last address.  It should have been expressed as:

  When the last address is empty *and the second last isn't* it
  should refer to the current line.

Otherwise a command like ':w' only writes the current line resulting
in serious loss of data.

function                                             old     new   delta
colon                                               3906    3911      +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 5/0)                 Total: 5 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-30 01:40:27 +02:00
Ron Yorston
acd3079fd1 vi: expand '%' and '#' in colon commands
Track the current and alternate filenames.  The placeholders '%'
and '#' can be used in arguments to colon commands to represent
the current and alternate filenames respectively.  Backslash can
be used to allow literal '%' and '#' characters to be entered.

This feature is controlled by the configuration option
FEATURE_VI_COLON_EXPAND.

function                                             old     new   delta
expand_args                                            -     198    +198
colon                                               3751    3927    +176
update_filename                                        -      70     +70
init_filename                                          -      48     +48
.rodata                                           105218  105239     +21
get_one_char                                         115     124      +9
edit_file                                            835     838      +3
do_cmd                                              4724    4727      +3
init_text_buffer                                     190     172     -18
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 5/1 up/down: 528/-18)           Total: 510 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
852ffbee34 vi: fix buffer overrun; code shrink
It was possible for get_input_line() to store its NUL terminator
one character beyond the end of its buffer.

Code shrink in colon():

- Certain colon commands can be matched exactly, as any shorter
  string would be matched earlier, e.g. ':wq' versus ':write'.

- Command matching is now case sensitive so there's no need to
  check for 'N' or 'Q' suffixes.

- Rewrite how commands and arguments are split.

function                                             old     new   delta
colon                                               3848    3751     -97
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-97)             Total: -97 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
dadd909746 vi: improvements to ':read' command
Improvements to ':read':

- When a file is read into the current buffer the cursor should be
  placed on the first line read.

- If invoked without supplying a filename the current filename should
  be used.  This is similar to how ':edit' works.

- The code for ':edit' included an explicit check that the current
  filename was non-empty.  Both vim and traditional vi accept non-empty
  filenames, only issuing an error message when an attempt to use such
  a name fails.

- Allow undo of a file read.

function                                             old     new   delta
file_insert                                          367     382     +15
colon                                               3841    3848      +7
.rodata                                           105236  105218     -18
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 22/-18)              Total: 4 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
e6bc8a29a9 vi: preserve state when switching file
When a new file is opened from an existing editing session the
following details should be preserved:

- the last command used;
- the last character searched for on a line.

function                                             old     new   delta
edit_file                                            849     835     -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-14)             Total: -14 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
b9aaa375a3 vi: 'ZZ' should warn if there are more files to edit
When 'ZZ' was used to save the current file and more files were
available to edit BusyBox vi immediately moved on to the next file.
The correct behaviour is to issue a warning.

function                                             old     new   delta
do_cmd                                              4673    4724     +51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 51/0)               Total: 51 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
09172582da vi: saving unnamed file in readonly mode
Suppose vi is started with the command 'vi -R', that is, in readonly
mode with no filename.  Attempting to save the file with 'ZZ' or ':w'
results in the message:

   '(null)' is read only

Skip the code which prints this if no filename was provided, thus
falling through to file_write() which gives the more helpful message
'No current filename'.

function                                             old     new   delta
colon                                               3867    3874      +7
do_cmd                                              4668    4673      +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 12/0)               Total: 12 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
3b9233f05f vi: adjust conditional compilation of modifying_cmds
Since commit 74d565ff1 (vi: make context marks more like vi) the
list of commands that modify the text is no longer required when
FEATURE_VI_YANKMARK is enabled, only FEATURE_VI_DOT_CMD.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
7a8ceb4eb2 vi: changes to line addresses for colon commands
Make line addresses behave more like vi:

- Vi allows the user to enter an arbitrary number of addresses,
  though only the last two are used.  This simplifies get_address()
  by reducing the amount of state that needs to be carried.

- When a command requires a single address the last one entered is
  used.

- If addresses are separated by a ';' instead of a ',' the current
  line is updated to the left address.  This may be useful when a
  search is used to specify a range, e.g. ':/first/;/last/d'.

- When the last address is empty it should refer to the current line.

function                                             old     new   delta
colon                                               3855    3834     -21
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-21)             Total: -21 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
f277c9eebb vi: make de-indentation with ctrl-D more like vim
Commit ac6495f6f (vi: allow ctrl-D to reduce indentation) treated
ctrl-D during autoindent as a backspace.  This was adequate for
indentation using tabs but doesn't work well with the expandtab
option.  In the latter case it's necessary to backspace over all
the spaces.

Make ctrl-D work correctly when spaces are present in the indent.

Also, make it behave more like vim:

- ctrl-D is independent of autoindent;
- indentation is reduced even when the cursor isn't positioned at
  the end of the indent.

function                                             old     new   delta
char_insert                                          679     717     +38
get_column                                             -      37     +37
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 75/0)               Total: 75 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-20 11:21:43 +02:00
Ron Yorston
310ef23280 vi: add expandtab option
This implements the vim option expandtab in BusyBox vi.  From
vim help:

  In Insert mode: Use the appropriate number of spaces to insert a
  <Tab>.  Spaces are used in indents with the '>' and '<' commands and
  when 'autoindent' is on.  To insert a real tab when 'expandtab' is
  on, use CTRL-V<Tab>.

This implementation doesn't change how BusyBox vi handles autoindent:
it continues to copy the indentation from a neighbouring line.  If
that line has tabs in its indentation so too will the new line.

function                                             old     new   delta
char_insert                                          563     679    +116
next_column                                            -      48     +48
.rodata                                           105211  105236     +25
colon                                               3844    3855     +11
refresh                                             1000     982     -18
move_to_col                                           83      59     -24
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/2 up/down: 200/-42)           Total: 158 bytes

Signed-off-by: Peter D <urmum69@snopyta.org>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-20 11:21:43 +02:00
Denys Vlasenko
b65e7f629e vi: move undo_queue_state in globals to other byte-sized members
function                                             old     new   delta
vi_main                                              278     275      -3
undo_queue_commit                                     62      56      -6
undo_push                                            374     362     -12
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-21)             Total: -21 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 23:18:40 +02:00
Ron Yorston
f227726838 vi: allow line addresses to have an offset
Line addresses in colon commands can be defined using an expression
that includes '+' or '-' operators.  The implementation follows
traditional vi:

- The first term in the expression defines an address.  It can be
  an absolute line number, '.', '$', a search or a marker.

- The second and subsequent terms must be non-negative integers.

- If the first term is missing '.' is assumed.  If the operator is
  missing addition is assumed.  If the final term in missing an
  offset of 1 is assumed.

Thus the following are valid addresses:

  .+1   .+   +   .1
  .-1   .-   -

The following are not valid (though they are in vim):

  .+$   .$   2+.

function                                             old     new   delta
colon                                               3701    3844    +143
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 143/0)             Total: 143 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
47f78913f7 vi: allow backward search to specify line address
It should be possible to use a backward search as a line address
in colon commands.

function                                             old     new   delta
colon                                               3661    3701     +40
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 40/0)               Total: 40 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
d488def0e4 vi: detect and warn about invalid line addresses
BusyBox vi didn't have proper handling for invalid markers or
unsuccessful searches in colon line addresses.  This could result
in the wrong lines being affected by a change.

Detect when an invalid address is specified, propagate an error
indicator up the call chain and issue a warning.

function                                             old     new   delta
colon                                               3604    3661     +57
.rodata                                           105195  105211     +16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 73/0)               Total: 73 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
5d1bb58b13 vi: code shrink colon line addresses
Remove some unnecessary code in get_one_address() and rewrite
get_address().

function                                             old     new   delta
colon                                               3325    3604    +279
get_one_address                                      342       -    -342
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/0 up/down: 279/-342)          Total: -63 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
74d565ff1f vi: make context marks more like vi
The context marks that are automatically updated and can be used
with the "''" command didn't behave the same as in vi.  Marks
were only being set for certain editing commands when they should
have been set on successful movement commands.

Make BusyBox vi behave more like vi.

function                                             old     new   delta
.rodata                                           105179  105194     +15
do_cmd                                              4723    4668     -55
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 15/-55)            Total: -40 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
47c3eaa22f vi: correct autoindent for 'O' command
Opening a line above the current line with the 'O' command should
use the current, not previous, line to determine how much to
autoindent.

function                                             old     new   delta
char_insert                                          531     563     +32
do_cmd                                              4746    4723     -23
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 32/-23)              Total: 9 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
ac6495f6fb vi: allow ctrl-D to reduce indentation
When whitespace has been automatically added to a new line due to
autoindent entering ctrl-D should reduce the level of indentation.

Implement an approximation of this by treating ctrl-D as backspace.
For the common case of indentation using tabs this is good enough.
My attempt at a full implementation was three times bigger.

function                                             old     new   delta
char_insert                                          476     531     +55
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 55/0)               Total: 55 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
d6e653d667 vi: don't move cursor when yanking whole lines
When whole lines are yanked using 'yy' or 'Y' vi doesn't change the
cursor position.  Make BusyBox vi do the same.

function                                             old     new   delta
do_cmd                                              4776    4786     +10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 10/0)               Total: 10 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
38ae0f3e3e vi: reset command count when specifying '0' range
Since commit a54450248 (vi: allow the '.' command to have a
repetition count) using '0' to specify a range doesn't work with
a non-zero repeat count, e.g. '1d0'.  Users wouldn't normally try
to do that but the '.' command does.

Add a special case in get_motion_char() to handle this.

function                                             old     new   delta
find_range                                           737     746      +9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 9/0)                 Total: 9 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
033fa3d5c6 vi: code shrink motion by paragraph
Use a hand-coded loop to search for paragraph boundaries instead
of calling char_search().  We were using a loop anyway to skip
consecutive newlines.

function                                             old     new   delta
do_cmd                                              4792    4752     -40
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-40)             Total: -40 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
d9d19896a9 vi: position cursor on last column of tab
Vi places the cursor on the last column of a tab character whereas
BusyBox vi puts it on the first.  This is disconcerting for
experienced vi users and makes it impossible to distinguish
visually between an empty line and one containing just a tab.

It wasn't always this way.  Prior to commit e3cbfb91d (vi: introduce
FEATURE_VI_8BIT) BusyBox vi also put the cursor on the last column.
However there were problems with cursor positioning when text was
inserted before a tab.  Commit eaabf0675 (vi: multiple fixes by
Natanael Copa) includes a partial attempt to fix this.  (The code is
still present but it's never executed.  Clever compilers optimise it
away.)

Revert the changes of commit e3cbfb91d and fix the insert problem
for all tabs, not just the first.

To quote Natanael:  "Costs a few bytes but its worth it imho".

function                                             old     new   delta
refresh                                              974    1000     +26
move_to_col                                           81      83      +2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 28/0)               Total: 28 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00