351 lines
9.1 KiB
Text
351 lines
9.1 KiB
Text
|
# @(#)input 5.5 (Berkeley) 7/2/94
|
||
|
|
||
|
MAPS, EXECUTABLE BUFFERS AND INPUT IN EX/VI:
|
||
|
|
||
|
The basic rule is that input in ex/vi is a stack. Every time a key which
|
||
|
gets expanded is encountered, it is expanded and the expansion is treated
|
||
|
as if it were input from the user. So, maps and executable buffers are
|
||
|
simply pushed onto the stack from which keys are returned. The exception
|
||
|
is that if the "remap" option is turned off, only a single map expansion
|
||
|
is done. I intend to be fully backward compatible with this.
|
||
|
|
||
|
Historically, if the mode of the editor changed (ex to vi or vice versa),
|
||
|
any queued input was silently discarded. I don't see any reason to either
|
||
|
support or not support this semantic. I intend to retain the queued input,
|
||
|
mostly because it's simpler than throwing it away.
|
||
|
|
||
|
Historically, neither the initial command on the command line (the + flag)
|
||
|
or the +cmd associated with the ex and edit commands was subject to mapping.
|
||
|
Also, while the +cmd appears to be subject to "@buffer" expansion, once
|
||
|
expanded it doesn't appear to work correctly. I don't see any reason to
|
||
|
either support or not support these semantics, so, for consistency, I intend
|
||
|
to pass both the initial command and the command associated with ex and edit
|
||
|
commands through the standard mapping and @ buffer expansion.
|
||
|
|
||
|
One other difference between the historic ex/vi and nex/nvi is that nex
|
||
|
displays the executed buffers as it executes them. This means that if
|
||
|
the file is:
|
||
|
|
||
|
set term=xterm
|
||
|
set term=yterm
|
||
|
set term=yterm
|
||
|
|
||
|
the user will see the following during a typical edit session:
|
||
|
|
||
|
nex testfile
|
||
|
testfile: unmodified: line 3
|
||
|
:1,$yank a
|
||
|
:@a
|
||
|
:set term=zterm
|
||
|
:set term=yterm
|
||
|
:set term=xterm
|
||
|
:q!
|
||
|
|
||
|
This seems like a feature and unlikely to break anything, so I don't
|
||
|
intend to match historic practice in this area.
|
||
|
|
||
|
The rest of this document is a set of conclusions as to how I believe
|
||
|
the historic maps and @ buffers work. The summary is as follows:
|
||
|
|
||
|
1: For buffers that are cut in "line mode", or buffers that are not cut
|
||
|
in line mode but which contain portions of more than a single line, a
|
||
|
trailing <newline> character appears in the input for each line in the
|
||
|
buffer when it is executed. For buffers not cut in line mode and which
|
||
|
contain portions of only a single line, no additional characters
|
||
|
appear in the input.
|
||
|
2: Executable buffers that execute other buffers don't load their
|
||
|
contents until they execute them.
|
||
|
3: Maps and executable buffers are copied when they are executed --
|
||
|
they can be modified by the command but that does not change their
|
||
|
actions.
|
||
|
4: Historically, executable buffers are discarded if the editor
|
||
|
switches between ex and vi modes.
|
||
|
5: Executable buffers inside of map commands are expanded normally.
|
||
|
Maps inside of executable buffers are expanded normally.
|
||
|
6: If an error is encountered while executing a mapped command or buffer,
|
||
|
the rest of the mapped command/buffer is discarded. No user input
|
||
|
characters are discarded.
|
||
|
7: Characters in executable buffers are remapped.
|
||
|
8: Characters in executable buffers are not quoted.
|
||
|
|
||
|
Individual test cases follow. Note, in the test cases, control characters
|
||
|
are not literal and will have to be replaced to make the test cases work.
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
1: For buffers that are cut in "line mode", or buffers that are not cut
|
||
|
in line mode but which contain portions of more than a single line, a
|
||
|
trailing <newline> character appears in the input for each line in the
|
||
|
buffer when it is executed. For buffers not cut in line mode and which
|
||
|
contain portions of only a single line, no additional characters
|
||
|
appear in the input.
|
||
|
|
||
|
=== test file ===
|
||
|
3Gw
|
||
|
w
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
=== end test file ===
|
||
|
|
||
|
If the first line is loaded into 'a' and executed:
|
||
|
|
||
|
1G"ayy@a
|
||
|
|
||
|
The cursor ends up on the '2', a result of pushing "3Gw^J" onto
|
||
|
the stack.
|
||
|
|
||
|
If the first two lines are loaded into 'a' and executed:
|
||
|
|
||
|
1G2"ayy@a
|
||
|
|
||
|
The cursor ends up on the 'f' in "foo" in the fifth line of the
|
||
|
file, a result of pushing "3Gw^Jw^J" onto the stack.
|
||
|
|
||
|
If the first line is loaded into 'a', but not using line mode,
|
||
|
and executed:
|
||
|
|
||
|
1G"ay$@a
|
||
|
|
||
|
The cursor ends up on the '1', a result of pushing "3Gw" onto
|
||
|
the stack
|
||
|
|
||
|
If the first two lines are loaded into 'a', but not using line mode,
|
||
|
and executed:
|
||
|
|
||
|
1G2"ay$@a
|
||
|
|
||
|
The cursor ends up on the 'f' in "foo" in the fifth line of the
|
||
|
file, a result of pushing "3Gw^Jw^J" onto the stack.
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
2: Executable buffers that execute other buffers don't load their
|
||
|
contents until they execute them.
|
||
|
|
||
|
=== test file ===
|
||
|
cwLOAD B^[
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
@a@b
|
||
|
"byy
|
||
|
=== end test file ===
|
||
|
|
||
|
The command is loaded into 'e', and then executed. 'e' executes
|
||
|
'a', which loads 'b', then 'e' executes 'b'.
|
||
|
|
||
|
5G"eyy6G"ayy1G@e
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
cwLOAD B^[
|
||
|
LOAD B 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
@a@b
|
||
|
"byy
|
||
|
=== end output file ===
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
3: Maps and executable buffers are copied when they are executed --
|
||
|
they can be modified by the command but that does not change their
|
||
|
actions.
|
||
|
|
||
|
Executable buffers:
|
||
|
|
||
|
=== test file ===
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
@a@b
|
||
|
"eyy
|
||
|
cwEXECUTE B^[
|
||
|
=== end test file ===
|
||
|
|
||
|
4G"eyy5G"ayy6G"byy1G@eG"ep
|
||
|
|
||
|
The command is loaded into 'e', and then executed. 'e' executes
|
||
|
'a', which loads 'e', then 'e' executes 'b' anyway.
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
line 1 foo bar baz
|
||
|
EXECUTE B 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
@a@b
|
||
|
"eyy
|
||
|
cwEXECUTE B^[
|
||
|
line 1 foo bar baz
|
||
|
=== end output file ===
|
||
|
|
||
|
Maps:
|
||
|
|
||
|
=== test file ===
|
||
|
Cine 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
=== end test file ===
|
||
|
|
||
|
Entering the command ':map = :map = rB^V^MrA^M1G==' shows that
|
||
|
the first time the '=' is entered the '=' map is set and the
|
||
|
character is changed to 'A', the second time the character is
|
||
|
changed to 'B'.
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
4: Historically, executable buffers are discarded if the editor
|
||
|
switches between ex and vi modes.
|
||
|
|
||
|
=== test file ===
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
cwCHANGE^[Q:set
|
||
|
set|visual|1Gwww
|
||
|
=== end test file ===
|
||
|
|
||
|
vi testfile
|
||
|
4G"ayy@a
|
||
|
|
||
|
ex testfile
|
||
|
$p
|
||
|
yank a
|
||
|
@a
|
||
|
|
||
|
In vi, the command is loaded into 'a' and then executed. The command
|
||
|
subsequent to the 'Q' is (historically, silently) discarded.
|
||
|
|
||
|
In ex, the command is loaded into 'a' and then executed. The command
|
||
|
subsequent to the 'visual' is (historically, silently) discarded. The
|
||
|
first set command is output by ex, although refreshing the screen usually
|
||
|
causes it not to be seen.
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
5: Executable buffers inside of map commands are expanded normally.
|
||
|
Maps inside of executable buffers are expanded normally.
|
||
|
|
||
|
Buffers inside of map commands:
|
||
|
|
||
|
=== test file ===
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
cwREPLACE BY A^[
|
||
|
=== end test file ===
|
||
|
|
||
|
4G"ay$:map x @a
|
||
|
1Gx
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
REPLACE BY A 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
cwREPLACE BY A^[
|
||
|
=== end output file ===
|
||
|
|
||
|
Maps commands inside of executable buffers:
|
||
|
|
||
|
=== test file ===
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
X
|
||
|
=== end test file ===
|
||
|
|
||
|
:map X cwREPLACE BY XMAP^[
|
||
|
4G"ay$1G@a
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
REPLACE BY XMAP 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
X
|
||
|
=== end output file ===
|
||
|
|
||
|
Here's a test that does both, repeatedly.
|
||
|
|
||
|
=== test file ===
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
X
|
||
|
Y
|
||
|
cwREPLACED BY C^[
|
||
|
blank line
|
||
|
=== end test file ===
|
||
|
|
||
|
:map x @a
|
||
|
4G"ay$
|
||
|
:map X @b
|
||
|
5G"by$
|
||
|
:map Y @c
|
||
|
6G"cy$
|
||
|
1Gx
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
REPLACED BY C 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
X
|
||
|
Y
|
||
|
cwREPLACED BY C^[
|
||
|
blank line
|
||
|
=== end output file ===
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
6: If an error is encountered while executing a mapped command or
|
||
|
a buffer, the rest of the mapped command/buffer is discarded. No
|
||
|
user input characters are discarded.
|
||
|
|
||
|
=== test file ===
|
||
|
line 1 foo bar baz
|
||
|
line 2 foo bar baz
|
||
|
line 3 foo bar baz
|
||
|
:map = 10GcwREPLACMENT^V^[^[
|
||
|
=== end test file ===
|
||
|
|
||
|
The above mapping fails, however, if the 10G is changed to 1, 2,
|
||
|
or 3G, it will succeed.
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
7: Characters in executable buffers are remapped.
|
||
|
|
||
|
=== test file ===
|
||
|
abcdefghijklmnnop
|
||
|
ggg
|
||
|
=== end test file ===
|
||
|
|
||
|
:map g x
|
||
|
2G"ay$1G@a
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
defghijklmnnop
|
||
|
ggg
|
||
|
=== end output file ===
|
||
|
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||
|
8: Characters in executable buffers are not quoted.
|
||
|
|
||
|
=== test file ===
|
||
|
iFOO^[
|
||
|
|
||
|
=== end test file ===
|
||
|
|
||
|
1G"ay$2G@a
|
||
|
|
||
|
The output should be:
|
||
|
|
||
|
=== output file ===
|
||
|
iFOO^[
|
||
|
FOO
|
||
|
=== end output file ===
|
||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|