# @(#)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 ===
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=