vis
a vi-like editor based on Plan 9's structural regular expressions
git clone https://9o.is/git/vis.git
commit ed8b3de21819dd51229c9ad7cbe9e55832119d03 parent 200d8b02407490ef386afc36c04d7898d15e15c4 Author: Marc André Tanner <mat@brain-dump.org> Date: Fri, 20 Jan 2017 09:11:41 +0100 vis: improve new line handling at end of file <Enter> at the end of the file now inserts two newlines, unless there is already one in place. This ensures that in 'normal' operation the file is always new line terminated (as mandated by POSIX). It also means that there is no problem displaying the right amount of ~ symbols at the end of the file. Unlike in vim the cell beyond the end of the file remains adressable even in normal mode. This means something like the following (starting from an empty file) might be a little confusing: o<Escape><Left>dd Because the starting position is beyond the last newline of the file, nothing will be deleted. For now we prefer to avoid the additional complexity, and difference in behavior between normal and insert mode, needed to fix this slight inconsistency. Fix #294 Diffstat:
| M | view.c | | | 17 | ++++++++++++----- |
| M | vis.c | | | 20 | ++++++++++++++++++-- |
2 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/view.c b/view.c @@ -328,11 +328,11 @@ void view_cursor_to(View *view, size_t pos) { void view_draw(View *view) { view_clear(view); /* read a screenful of text considering each character as 4-byte UTF character*/ - const size_t text_size = view->width * view->height * 4; + const size_t size = view->width * view->height * 4; /* current buffer to work with */ - char text[text_size+1]; + char text[size+1]; /* remaining bytes to process in buffer */ - size_t rem = text_bytes_get(view->text, view->start, text_size, text); + size_t rem = text_bytes_get(view->text, view->start, size, text); /* NUL terminate text section */ text[rem] = '\0'; /* absolute position of character currently being added to display */ @@ -361,7 +361,7 @@ void view_draw(View *view) { * wide character. advance file position and read * another junk into buffer. */ - rem = text_bytes_get(view->text, pos, text_size, text); + rem = text_bytes_get(view->text, pos, size, text); text[rem] = '\0'; cur = text; continue; @@ -404,7 +404,14 @@ void view_draw(View *view) { /* set end of vieviewg region */ view->end = pos; - view->lastline = view->line ? view->line : view->bottomline; + if (view->line) { + if (view->line->len == 0 && view->end == text_size(view->text) && view->line->prev) + view->lastline = view->line->prev; + else + view->lastline = view->line; + } else { + view->lastline = view->bottomline; + } /* clear remaining of line, important to show cursor at end of file */ if (view->line) { diff --git a/vis.c b/vis.c @@ -1421,8 +1421,24 @@ static void copy_indent_from_previous_line(Win *win, Cursor *cur) { } void vis_insert_nl(Vis *vis) { - const char *nl = text_newline_char(vis->win->file->text); - vis_insert_key(vis, nl, strlen(nl)); + Text *txt = vis->win->file->text; + const char *nl = text_newline_char(txt); + size_t len = strlen(nl); + for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c)) { + char byte; + size_t pos = view_cursors_pos(c); + /* insert second newline at end of file, except if there is already one */ + bool eof = pos == text_size(txt); + bool nl2 = eof && !(pos > 0 && text_byte_get(txt, pos-1, &byte) && byte == '\n'); + vis_insert(vis, pos, nl, len); + if (eof) { + if (nl2) + vis_insert(vis, pos, nl, len); + else + pos -= len; /* place cursor before, not after nl */ + } + view_cursors_scroll_to(c, pos + len); + } if (!vis->autoindent) return;