------------------------------------------------------------------------
If you go Z[Esc], from then on [Ctrl-Z] stops working.
You can make it start working again by going:
:suspend
fg
------------------------------------------------------------------------
Make it able to handle the format of TAGS files.
------------------------------------------------------------------------
You can't edit or even see lines longer than a windowful.
We need to scroll the whole line within the space available to display it
with some indicator on the status line.
------------------------------------------------------------------------
When you :e! with split windows, they all go to line 1.
Stay on the same line in each view.
------------------------------------------------------------------------
POSIX says:

     * POSIX: "Commands that store text into buffers shall store the text
     * into the unnamed buffer as well as any specified buffer."
     * This only applies to the letter-named buffers, not the automatic ones.

but it's unclear whether just the appended text should be put in the unnamed
buffer or the whole contents of the buffer appended to.
------------------------------------------------------------------------
Moving left with count prefix to Replace gets repetition wrong

Xvi allows you to move left and right within the replacement text
while you are doing an R command, but if there was a repeat count
before the R, only the part left of the cursor's final position
is repeated, and after the cursor position, not the end of the
replacement text to boot!

The easy solution is to remove the left & right arrow keys from
replace mode.

In classic vi and nvi, pressing an arrow key while in R mode
terminates the replacement and respects a preceding count.
------------------------------------------------------------------------
An asterisk as the first char of a pattern should match a literal *

If you have a buffer:
	abcde
	prows
	hello *prows
	there
and say
	1G/*prows
it should go to the * on line 3. Instead it says
	?+* follows nothing

Similarly, :.,$s/^*/#/ should work, and it does in classic vi.

diff --git a/src/regexp.c b/src/regexp.c
index a0aa6af..65927c4 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -615,10 +619,16 @@ int *flagp;
     case ')':
 	FAIL("Internal urp");	/* Supposed to be caught earlier. */
 	break;
+
+	/* A pattern "*" or "^*" takes it as a literal character */
     case '?':
     case '+':
     case '*':
-	FAIL("?+* follows nothing");
+	ret = regnode(EXACTLY);
+	regc(regparse[-1]);
+	regc('\0');
+	*flagp |= HASWIDTH|SIMPLE;
+	//FAIL("?+* follows nothing");
 	break;
     case '\\':
 	switch (*regparse)

works for /? /+ /* /^? /^+ but /^* spits an error.
For the last three, ? and + call regbranch() twice and regpiece() is not called
and the last one calls regbranch() once which calls regpiece(),
------------------------------------------------------------------------
:!! doesn't re-execute the last command. It just executes !

nvi re-executes the last command; POSIX-ex says:

Non- <backslash>-escaped '!' characters in the arguments to either the ex
! command or the open and visual mode ! command, or in the arguments to
the ex read command, where the first non- <blank> after the command name
is a '!' character, or in the arguments to the ex write command where the
command name is followed by one or more <blank> characters and the first
non- <blank> after the command name is a '!' character, shall be replaced
with the arguments to the last of those three commands as they appeared
after all unescaped '%', '#', and '!' characters were replaced. It shall
be an error if '!' characters appear unescaped in one of these commands
and there has been no previous execution of one of these commands.

...if you can understand that!
------------------------------------------------------------------------
:@ and :* with a line range only execute the named buffer on the last line

They should execute the commands in the named buffer for each line in the range.

Repeat-by:
Put "s/a/b/" in buffer "a, create some lines with a's in them then :1,$@a
should change the first a on each line; instead it only changes the last line.
Similarly, 2,4@a ony changes line 4.

POSIX says:

"If no buffer is specified or is specified as '@' or '*', the last
buffer executed shall be used. If no previous buffer has been executed,
it shall be an error.

For each line specified by the addresses, set the current line ( '.' )
to the specified line, and execute the contents of the named buffer (as
they were at the time the @ command was executed) as ex commands. For each
line of a line-mode buffer, and all but the last line of a character-mode
buffer, the ex command parser shall behave as if the line was terminated
by a newline.

If an error occurs during this process, or a line specified by the
addresses does not exist when the current line would be set to it, or
more than a single line was specified by the addresses, and the contents
of the edit buffer are replaced (for example, by the ex :edit command)
an error message shall be written, and no more commands resulting from
the execution of this command shall be processed."
------------------------------------------------------------------------
Filename completion on the command line garbles names including spaces

In a directory with files
	Stanotte.ly
	Non lo so.ly
go
	xvi Stanotte.ly
	:b Non*ly
and it says "Inappropriate arguments given"
or
	:b Non[tab]
and it leaves
	:b _Non
(where _ is a space with the cursor on it). The "Non" is
garbage left on the screen and doesn't form part of the
command line.

This seems to be because in unix.c it just passes "echo %s" with the
pattern, so spaces in filenames are indistinguishable from spaces
between filenames. It would be better to use "ls -1" and split on \n
as having \n in filenames is rarer than spaces.
------------------------------------------------------------------------
xvi doesn't understand TAGS files created by etags

Xvi understands classic
	symbol\tfile\tlineno
"tags" files and ctags'
	F_OK    unix.h  134;"   d
	Flexbuf xvi.h   /^Flexbuf;$/;"  t       typeref:struct:__anon25
but doesn't grok etags' "TAGS" files.
For example, "make tags" in sox creates "TAGS" containing lines like:
	} priv_t;^?priv_t^A19,500
	static int start(sox_effect_t * effp)^?start^A21,511
	#define fifo_included^?fifo_included^A19,847
	UNUSED static void fifo_clear(fifo_t * f)^?fifo_clear^A37,1268
and
	/home/martin/score/sox/src/TAGS,include

I'm not sure where one is supposed to find the symbol in that;
from the DEL to the Ctrl-A?
------------------------------------------------------------------------
Pressing F11 and F12 go out of insert mode and do [23~ and [24~
------------------------------------------------------------------------
Pressing the arrow keys, Ins, Del, Home, End and others in insert mode
inserts their internal xvi command codes from 128 to 140.

The arrow keys in insert mode could move the cursor
instead of inserting .

The internal key codes for special keys mask valid characters

The codes for K_HELP, the arrow keys, Home, End, Page Up/Down,
Insert, Delete, are 0x80 to 0x8c, which are valid accented characters
on MSDOS and can be the second char of UTF-8 characters.

For example, left arrow, \206, is the second char of the AE ligature
in UTF-8 and down arrow, \204, is a-grave on MSDOS CP437.

One idea is to use rarer character codes, say from 0xFF down.
F8-FF are impossible first char values in UTF-8 and rare chars in CP437
except for F8, which is the degree symbol.
Unfortunately, cmdtab.c currently relies on the codes being sequential
to ASCII, i.e. starting from 0x80.

Another answer is to widen the input character type and use values outside
the 0-255 range for the special key codes. That won't affect file lines
or what it remembers as the command line: the special chars are never
inserted into these but are acted on beforehand.
That would be more expensive on memory, but does pave the way for
UTF-32 support.
------------------------------------------------------------------------
The g/re/p mechanism needs rewriting

The "global" mechanism can only apply a limited set of commands [dlps&~]
that it re-implements separately inside exGlobal().

What it should do is mark every matching line in some way, then apply
any command to each marked line, using the same code as is used for
: commands.

POSIX says: "The global, v, and undo commands cannot be used in
	commands. Marked lines may be deleted by commands executed for lines
	occurring earlier in the file than the marked lines. In this case,
	no commands shall be executed for the deleted lines."

See the "if" and commentary at cmdline.c:491 which may be the right place to
implement this.

When this is done, it will be much easier to do colon-@-or-*-with-line-range.
------------------------------------------------------------------------
Implement abbreviate and unabbreviate commands

As well as "map", xvi has a word-based mechanism to expand abbreviations.

POSIX says:

"Abbreviate

Synopsis: ab[breviate][lhs rhs]

If lhs and rhs are not specified, write the current list of abbreviations
and do nothing more.

Implementations may restrict the set of characters accepted in lhs
or rhs, except that printable characters and characters shall not be
restricted. Additional restrictions shall be implementation-defined.

In both lhs and rhs, any character may be escaped with a -V, in which
case the character shall not be used to delimit lhs from rhs, and the
escaping -V shall be discarded.

In open and visual text input mode, if a non-word or character that
is not escaped by a -V character is entered after a word character,
a check shall be made for a set of characters matching lhs, in the text
input entered during this command. If it is found, the effect shall be
as if rhs was entered instead of lhs.

The set of characters that are checked is defined as follows:

If there are no characters inserted before the word and non-word or <ESC>
characters that triggered the check, the set of characters shall consist
of the word character.

If the character inserted before the word and non-word or <ESC> characters
that triggered the check is a word character, the set of characters shall
consist of the characters inserted immediately before the triggering
characters that are word characters, plus the triggering word character.

If the character inserted before the word and non-word or <ESC> characters
that triggered the check is not a word character, the set of characters
shall consist of the characters that were inserted before the triggering
characters that are neither <blank> characters nor word characters,
plus the triggering word character.

It is unspecified whether the lhs argument entered for the ex abbreviate
and unabbreviate commands is replaced in this fashion. Regardless of
whether or not the replacement occurs, the effect of the command shall
be as if the replacement had not occurred."
------------------------------------------------------------------------
xvi should recognise multiple commands separated by |

Xvi doesn't recognise multiple commands on one line, separated by |,
when typing a : command, nor in -c option.

The only place | is recognised is in the XVINIT string.
------------------------------------------------------------------------
UTF-8 characters are not supported

You can type an e-grave character but it displays as \303\250.

On Jan 29 3016, http://github.com/ullman wrote:
This works in DOS builds, è input is displayed as è.
In linux the behaviour is like the one above.
This is a display issue as saving a file displaying characters incorrectly
writes the correct bits and the characters will display correctly in other
editors.
------------------------------------------------------------------------
In input mode, using the stty kill character should be the same as saying ^U

POSIX says: "The current kill character (see stty) shall cause an
equivalent action to the -U command, unless the previously inserted
character was a , in which case it shall be as if the literal current
kill character had been inserted instead of the ."

On Linux, the kill character seems to be ^U by default. If you change it:

stty kill ^X

In classic vi, ^U then just inserts a ^U and ^X becomes the line-kill character.
In nvi, both ^U and ^X become kill characters, both escapable with backslash.
------------------------------------------------------------------------
Display of a line that is longer than the screen could be improved

When a line that's longer than will fit on-screen is the current line,
it displays as a column of @ signs down the left edge but the cursor
moves about the screen as if the line were displayed.

Classic vi just maks a mess.
nvi and vim display some of the line (they don't display it as @s)
------------------------------------------------------------------------
it would be nice if it repainted the status line when you press ^L or ^R

If the screen gets corrupted while entering a command line, it would be nice
to be able to repaint it by pressing ^L or ^R.
------------------------------------------------------------------------
Executing macros is noisy on the command/status line

While running "hanoi", it echoes the mapped characters on the command line,
only to overwrite them immediately with "No file [Modified]" repeatedly.

It would be better if it didn't echo macro-expanded input on the command line.
------------------------------------------------------------------------
:map! ee &egrave;[Enter]
aee

produces &eraveg; !!!
------------------------------------------------------------------------
The maze test often (always?) leaves test/data/#sample.maz.tmp

The maze test leaves xvi's preserve file in test/data/
------------------------------------------------------------------------
:g/bla/m$ doesn't work

It says "Invalid command character".  Same for g/bla/t$
------------------------------------------------------------------------
Opening many files in an odd-length screen, all except the first open at line 2

If you try to open more files than will fit, and the screen height is an
odd number, the first window has 3 lines (2 of the file and the status
line) and all the other files open displaying line 2 instead of line 1.

The culprit seems to be the call to xvEqualiseWindows() in exNext(). At
least, without that they all open at line 1. In fact, if you open a load
of files in a terminal with an even number of lines using

	xvi -s autosplit=1000 *.c

resize the terminal window to add one more line and then say :equalise,
all the files except the first shift to displaying line 2 (with their
status lines saying "line 1 of 571" to add insult to injury!)

This seems to be caused by the way that xvi behaves when the top of a
window moves: it moves the top of the window down (or the status line
of the above window down, as you prefer to see it) and the starting
line and cursor position move down withint the file such that the text
displayed on the screen doesn't move.

We'd resolve this issue by making it keep the first displayed line as
the first displayed line of each window.
It also changes the current line if a window gets smaller and the cursor's
line is no longer displayed, which I find annoying. I'd rather it kept
the cursor on the same line and ensures that line remains visible. If that
happens anyway, keep the first displayed line as the first displayed line.
------------------------------------------------------------------------
On NetBSD, all tests appear to succeed but in reality none are run

On NetBSD 5.1 (gcc70.fsffrance.org) All the tests seem to succeed quickly.
In reality, the scripts are exiting 0 without running any of the tests.
------------------------------------------------------------------------
The test suite fails to execute on OpenSUSE, with internal errors

"make check" pukes:

0000-startup                    FAILED with status 100
0017-crtl-w+u                   FAILED with status 100
0020-literal-next-^             FAILED with status 100
0041-yl-at-eol                  FAILED with status 100
0066-\u&                        FAILED with status 100
0071-wrap-garbling              FAILED with status 100
0082-autowrite                  can't read "termdata(0)": no such element in arr
ay
    while executing
"set middle $termdata($reprow)"
    (procedure "term_replace" line 3)
    invoked from within
"term_replace $cur_row $cur_col  [string range $s 0 [expr $space_rem_on_line-1]]
"
    (procedure "term_insert" line 12)
    invoked from within
"term_insert $expect_out(0,string)"
FAILED with status 100

and the same pair or errors for most of the following tests except for the final

Interrupted                     FAILED with status 101
N-tilde                         FAILED with status 100
hanoi                           FAILED with status 100
maze                            DISABLED
showmode                        FAILED with status 100
------------------------------------------------------------------------
Implement per-buffer parameters

Some parameters, line readonly and format, would be better specified per buffer
instead of being a single parameter that applies to all buffers.

For example if you set a file read-only, all open files become read-only.
Similarly, if you merely insert an msdos file into another with autodetect on,
all the buffers will then be written in msdos mode.

Interestingly, there are already per-buffer flags, they are just not attached
to the parameters mechanism.
------------------------------------------------------------------------
Compare xvi against POSIX spec

It would be good to try xvi against each paragraph of the POSIX specs for ex
and vi and create an issue for each deviance from it.

The VSC POSIX Compilance Test Suite 2016-2.12 has a set of tests for vi
in test group POSIX.upe/vi but it only pumps commands into vi, the last
of which is to write a file whose contents it examines.
Many tests that it would like to run are skipped, e.g.
        Assertion #4 (D): vi updates screen to reflect file contents
        TEST NOT WRITTEN - untestable
but with our screen-scraping test mechanism it should now be possible
to implement them.

The VSC POSIX Compliance Test software can be obtained by signing a
personal license, but it's hard to make it run. If you want to get it
and try, see my notes in data/POSIX-VSC-HOWTO

Summary of results:

On AIX 7.2 for IBM POWER8 CPU:

            |    TOTALS     Succeed               Untested      NotImpl
Section     |Expect Actual          Fail  Unresolved     NotInUse
____________|________________________________________________________
            |
vi_01       |     0     79     27     15      0     32      1      4
vi_02       |     0     60     16     22      0     22      0      0
vi_03       |     0     59     37     14      0      8      0      0
vi_04       |     0     54     37     10      0      6      0      1
vi_05       |     0     61     29     18      0     12      1      1
vi_06       |     0     12      0      6      0      4      0      2
____________|________________________________________________________

On Ubuntu Xenial amd64:

            |    TOTALS     Succeed               Untested       NotImpl
Section     |Expect Actual          Fail  Unresolved      NotInUse
____________|________________________________________________________
            |
vi_01       |     0     79     27     14       1     32      1      4
vi_02       |     0     60     17     21       0     22      0      0
vi_03       |     0     59     37     14       0      8      0      0
vi_04       |     0     54     37     10       0      6      0      1
vi_05       |     0     61     29     18       0     12      1      1
vi_06       |     0     12      0      6       0      4      0      2
____________|________________________________________________________

For the full reports, see data/POSIX-VSC-* which need checking
test by test.

Ideally, we would implement their unimplemented tests using our test harness.
------------------------------------------------------------------------
If you repeat a "dFa" with ".", the second time, it deletes forwards

Repeat-by:

On file:
    audio_file->sample_rate
    audio_file->sample_rate
/sample_rate
dFa
n
.

Result:
    sample_rate
    audio_file->mple_rate
------------------------------------------------------------------------
If you type half a : command-line and then resize the window shorter,
the half-complete command line is not redrawn.
------------------------------------------------------------------------
When xvi runs out of memory, you can't save the buffer

When xvi runs out of RAM (like in issue #130) you can't write the file.
To ":w foo" it says "Cannot open preserve file /tmp/#foo.tmp".

If you force the write ``:w! foo"...

If you bypass the preserve file when forcing:

--- a/src/fileio.c
+++ b/src/fileio.c
@@ -612,7 +612,9 @@ bool_t     force;
     /*
      * Preserve the buffer here so if the write fails it will at
-     * least have been saved.
+     * least have been saved.  The exception when forcing is to
+     * improve the chances of being able to save the buffer
+     * when xvi has run out of memory.
      */
-    if (need_preserve && !preservebuf(window)) {
+    if (!force && need_preserve && !preservebuf(window)) {
        return(FALSE);
     }

It says "Can't write foo" instead because the fopen() fails for lack of RAM.

Test using:
	(ulimit -v 2500; src/xvi)
	80aa[esc]
	yyppppppppppppp...  until it barfs
	:w foo
------------------------------------------------------------------------
On Unix. Control-\ makes xvi dump core immediately

even if you insert ^V^\

POSIX says nothing about SIGQUIT but it should probably work like SIGINT,
i.e. we should catch it to be able to insert it with ^V.

Dying immediately is a bit harsh (if sometime useful!)
------------------------------------------------------------------------
If you paste a very long line into xvi, it gets incredibly slow

It consumed 100% CPU and slobbers the screen with @s down the left edge
and a moving cursor on the penultimate line for minutes and minutes.
------------------------------------------------------------------------
You should be able to insert newlines into the rhs of a substitution

If I remember correctly, with ^V^M. This should split the line into two
but xvi currently inserts a literal control-M (or control-J if you use ^V^J)
forcing you to write the file out in mac format and read it back in.
------------------------------------------------------------------------
Tab in replacement text of :s over undefined marks corrupts status line

If you say
	:'m,'ns/, /,^I/
when 'm and (or?) 'n are undefined, as soon as you press the Tab,
the start of the status line is overwritten with "Unknown mark"
and the cursor remains at the end of the status line still to be executed.
When you press Enter, it says "Bad address ranje"

If the marks are both defined, it works OK.
------------------------------------------------------------------------
When the tags file changes, xvi carries on using the old one.

If the tag file is stale and doesn't index a new function, you can
(Control-Z, make tags, fg) and repeat the ^] but it still doesn't find it.

e.g. If you fail to find a tag because there isn't a tag file, suspend xvi
and "make tags", then foreground xvi and repeat the tag search, it
still doesn't find the tag until you say ":se tags=tags" to make it reread
the file.

Check the modification date or something, rather than having to say
:se tags=tags to force this.

It needs to check if the tag file has been updated since we read it or, on
systems that don't have datestamps, before doing a tag search, re-read the
tag file if the previous tag search failed.

Or we could check the modification date each time and update if it changes,
but causing disk activity all the time isn't so great.
------------------------------------------------------------------------
If you redo a "4~" command with ".", it only does "~"
------------------------------------------------------------------------
After an undo, set the cursor position according to POSIX

xvi sets the cursor to where it was before the action being undone happened.

POSIX has a detailed description of what *it* wants, and xvi's current
strategy is not ideal. For example, you can't go undo-undo to go back to
the last thing you changed.

POSIX says, of the cursor position after an undo:
#
# "Current line:
#
#  Set to the first line added or changed if any;
#  otherwise, move to the line preceding any deleted text if one exists;
#  otherwise, move to line 1.
#
#  Current column:
#
#  If undoing an ex command, set to the first non-<blank>.
#
#  Otherwise, if undoing a text input command:
#
#  1. If the command was a C, c, O, o, R, S, or s command, the
#     current column shall be set to the value it held when the text
#     input command was entered.
#
#  2. Otherwise, set to the last column in which any portion of the
#         first character after the deleted text is displayed,
#     or, if no non-<newline> characters follow the text deleted
#         from this line, set to the last column in which any portion
#         of the last non-<newline> in the line is displayed,
#     or 1 if the line is empty.
#
#  Otherwise, if a single line was modified (that is, not added
#  or deleted) by the u command:
#
#  1. If text was added or changed, set to the last column in
#     which any portion of the first character added or changed
#     is displayed.
#
#  2. If text was deleted, set to the last column in which any portion
#         of the first character after the deleted text is displayed,
#     or, if no non-<newline> characters follow the deleted text,
#         set to the last column in which any portion of the last
#         non-<newline> in the line is displayed,
#     or 1 if the line is empty.
#
#  Otherwise, set to non-<blank>."

Which sounds like:

if undoing an ex-mode command, set to first non-blank of the line from the
  rules above.

For undoing vi commands:

if undoing a text-input command (which is the below and a i A I ?)
  if CcOoRSs, leave it to undo's current setting of the position,
    which is where the cursor was when text input mode was entered
  or on the following character following what you removed for the undo
    (cos AaIi always add text), sticking at eol
else
  if a single line was modified by the u command:
    if it added or changed text, set to last char of the added or changed text
    if it deleted text, set to first char after deleted text, sticking at eol
  "Otherwise set to non-blank" ???

what if several lines were modified by the command?
To the first non-blank of the modified lines?

What if I undo a vi-mode macro execution
(Though xvi doesn't currently implement undo of a map execution yet)?

Text input commands are, for xvi, the do_ins family [AIOaioK_INSERT]
while c is do-operator line d and y, s R r are do_cmd like P p
Add a flag to cmdtab TEXT_INPUT and remember it in the change structure
at start_command invocation level 0?

xvi differs from this:
- undoing a "%s/make/MAKE/" or "g/make/s//MAKE/" leaves the cursor at line 1
- When undoing an undo, it restores the cursor to where it was before the
  first undo.
- when deleting lines, it leaves the cursor on the line after the deleted
  text, not the one before.

------------------------------------------------------------------------
In src/signal.c, prefer using POSIX sigaction() instead of signal()

Xvi uses signal() to catch signals, while sigaction() is better.
See man 2 signal
------------------------------------------------------------------------
Control characters display as faces and sex signs on MS-DOS

In the edit buffer and on the command line, most of characters
1 to 31 display as single characters: funny faces and symbols.

They should display as ^A, ^M and so on.

For characters with the top bit set, this behaviour is OK
because it makes accented characters work.

This is because the default value of mchars on MSDOS is TRUE
but I would rather it displayed control characters and DEL as ^X
and top-bit-set character literally.
------------------------------------------------------------------------
When windows are resized, the current line is not maintained

When using ^T ^W ^O :equalise :split and :b, at present
what was the current line can end up off the displayed region of the buffer
and xvi moves the cursor on-screen. It would be better if it kept the
current line the same and scrolled the window if necessary.
------------------------------------------------------------------------
