vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit beae46d67e1a34c8b48bdef0cc38d21b52d1b379
parent 74dfcb2634c92c403ebceb43b0923b35b904b70d
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Tue,  4 Feb 2020 18:08:58 +0100

vis: make core code more robust

The core vis code was originally written under the assumption that there
always exists at least one window. However, when being called from the
Lua configuration file during start up this is not yet the case.

In general, Lua code should always be placed within appropriate event
handlers e.g. vis.events.INIT for global configuration. Invoking API
functions depending on an active window from top level statements is
not supported. Where before the editor simply crashed, these changes
turn such code sections into NOPs.

Fix #561

Diffstat:
Mvis-lua.c | 2+-
Mvis-modes.c | 43+++++++++++++++++++++++++++----------------
Mvis.c | 54+++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 69 insertions(+), 30 deletions(-)

diff --git a/vis-lua.c b/vis-lua.c @@ -2852,7 +2852,7 @@ void vis_lua_quit(Vis *vis) { */ static bool vis_lua_input(Vis *vis, const char *key, size_t len) { lua_State *L = vis->lua; - if (!L || vis->win->file->internal) + if (!L || !vis->win || vis->win->file->internal) return false; bool ret = false; vis_lua_event_get(L, "input"); diff --git a/vis-modes.c b/vis-modes.c @@ -141,11 +141,14 @@ bool vis_window_mode_map(Win *win, enum VisMode id, bool force, const char *key, /** mode switching event handlers */ static void vis_mode_normal_enter(Vis *vis, Mode *old) { + Win *win = vis->win; + if (!win) + return; if (old != mode_get(vis, VIS_MODE_INSERT) && old != mode_get(vis, VIS_MODE_REPLACE)) return; if (vis->autoindent && strcmp(vis->key_prev, "<Enter>") == 0) { - Text *txt = vis->win->file->text; - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) { + Text *txt = win->file->text; + for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); size_t start = text_line_start(txt, pos); size_t end = text_line_end(txt, pos); @@ -160,7 +163,7 @@ static void vis_mode_normal_enter(Vis *vis, Mode *old) { } } macro_operator_stop(vis); - if (!vis->win->parent && vis->action_prev.op == &vis_operators[VIS_OP_MODESWITCH] && + if (!win->parent && vis->action_prev.op == &vis_operators[VIS_OP_MODESWITCH] && vis->action_prev.count > 1) { /* temporarily disable motion, in something like `5atext` * we should only move the cursor once then insert the text */ @@ -174,7 +177,7 @@ static void vis_mode_normal_enter(Vis *vis, Mode *old) { vis->action_prev.movement = motion; } /* make sure we can recover the current state after an editing operation */ - vis_file_snapshot(vis, vis->win->file); + vis_file_snapshot(vis, win->file); } static void vis_mode_operator_input(Vis *vis, const char *str, size_t len) { @@ -184,15 +187,17 @@ static void vis_mode_operator_input(Vis *vis, const char *str, size_t len) { } static void vis_mode_visual_enter(Vis *vis, Mode *old) { - if (!old->visual) { - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) + Win *win = vis->win; + if (!old->visual && win) { + for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) view_selections_anchor(s, true); } } static void vis_mode_visual_line_enter(Vis *vis, Mode *old) { - if (!old->visual) { - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) + Win *win = vis->win; + if (!old->visual && win) { + for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) view_selections_anchor(s, true); } if (!vis->action.op) @@ -200,25 +205,29 @@ static void vis_mode_visual_line_enter(Vis *vis, Mode *old) { } static void vis_mode_visual_line_leave(Vis *vis, Mode *new) { + Win *win = vis->win; + if (!win) + return; if (!new->visual) { if (!vis->action.op) - window_selection_save(vis->win); - view_selections_clear_all(vis->win->view); + window_selection_save(win); + view_selections_clear_all(win->view); } else { - view_cursor_to(vis->win->view, view_cursor_get(vis->win->view)); + view_cursor_to(win->view, view_cursor_get(win->view)); } } static void vis_mode_visual_leave(Vis *vis, Mode *new) { - if (!new->visual) { + Win *win = vis->win; + if (!new->visual && win) { if (!vis->action.op) - window_selection_save(vis->win); - view_selections_clear_all(vis->win->view); + window_selection_save(win); + view_selections_clear_all(win->view); } } static void vis_mode_insert_replace_enter(Vis *vis, Mode *old) { - if (vis->win->parent) + if (!vis->win || vis->win->parent) return; if (!vis->action.op) { action_reset(&vis->action_prev); @@ -229,7 +238,9 @@ static void vis_mode_insert_replace_enter(Vis *vis, Mode *old) { } static void vis_mode_insert_idle(Vis *vis) { - vis_file_snapshot(vis, vis->win->file); + Win *win = vis->win; + if (win) + vis_file_snapshot(vis, win->file); } static void vis_mode_insert_input(Vis *vis, const char *str, size_t len) { diff --git a/vis.c b/vis.c @@ -755,12 +755,18 @@ void vis_free(Vis *vis) { } void vis_insert(Vis *vis, size_t pos, const char *data, size_t len) { - text_insert(vis->win->file->text, pos, data, len); - vis_window_invalidate(vis->win); + Win *win = vis->win; + if (!win) + return; + text_insert(win->file->text, pos, data, len); + vis_window_invalidate(win); } void vis_insert_key(Vis *vis, const char *data, size_t len) { - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) { + Win *win = vis->win; + if (!win) + return; + for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); vis_insert(vis, pos, data, len); view_cursors_scroll_to(s, pos + len); @@ -768,7 +774,10 @@ void vis_insert_key(Vis *vis, const char *data, size_t len) { } void vis_replace(Vis *vis, size_t pos, const char *data, size_t len) { - Text *txt = vis->win->file->text; + Win *win = vis->win; + if (!win) + return; + Text *txt = win->file->text; Iterator it = text_iterator_get(txt, pos); int chars = text_char_count(data, len); for (char c; chars-- > 0 && text_iterator_byte_get(&it, &c) && c != '\n'; ) @@ -779,7 +788,10 @@ void vis_replace(Vis *vis, size_t pos, const char *data, size_t len) { } void vis_replace_key(Vis *vis, const char *data, size_t len) { - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) { + Win *win = vis->win; + if (!win) + return; + for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); vis_replace(vis, pos, data, len); view_cursors_scroll_to(s, pos + len); @@ -787,8 +799,11 @@ void vis_replace_key(Vis *vis, const char *data, size_t len) { } void vis_delete(Vis *vis, size_t pos, size_t len) { - text_delete(vis->win->file->text, pos, len); - vis_window_invalidate(vis->win); + Win *win = vis->win; + if (!win) + return; + text_delete(win->file->text, pos, len); + vis_window_invalidate(win); } bool vis_action_register(Vis *vis, const KeyAction *action) { @@ -813,6 +828,8 @@ bool vis_interrupt_requested(Vis *vis) { void vis_do(Vis *vis) { Win *win = vis->win; + if (!win) + return; File *file = win->file; Text *txt = file->text; View *view = win->view; @@ -1497,7 +1514,9 @@ bool vis_macro_replay(Vis *vis, enum VisRegister id) { vis_cancel(vis); for (int i = 0; i < count; i++) macro_replay(vis, macro); - vis_file_snapshot(vis, vis->win->file); + Win *win = vis->win; + if (win) + vis_file_snapshot(vis, win->file); return true; } @@ -1526,7 +1545,9 @@ void vis_repeat(Vis *vis) { vis->action_prev = action_prev; } vis_cancel(vis); - vis_file_snapshot(vis, vis->win->file); + Win *win = vis->win; + if (win) + vis_file_snapshot(vis, win->file); } int vis_count_get(Vis *vis) { @@ -1571,15 +1592,18 @@ void vis_exit(Vis *vis, int status) { } void vis_insert_tab(Vis *vis) { + Win *win = vis->win; + if (!win) + return; if (!vis->expandtab) { vis_insert_key(vis, "\t", 1); return; } char spaces[9]; int tabwidth = MIN(vis->tabwidth, LENGTH(spaces) - 1); - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); - int width = text_line_width_get(vis->win->file->text, pos); + int width = text_line_width_get(win->file->text, pos); int count = tabwidth - (width % tabwidth); for (int i = 0; i < count; i++) spaces[i] = ' '; @@ -1630,6 +1654,8 @@ size_t vis_text_insert_nl(Vis *vis, Text *txt, size_t pos) { void vis_insert_nl(Vis *vis) { Win *win = vis->win; + if (!win) + return; View *view = win->view; Text *txt = win->file->text; for (Selection *s = view_selections(view); s; s = view_selections_next(s)) { @@ -1936,11 +1962,13 @@ void vis_file_snapshot(Vis *vis, File *file) { } Text *vis_text(Vis *vis) { - return vis->win->file->text; + Win *win = vis->win; + return win ? win->file->text : NULL; } View *vis_view(Vis *vis) { - return vis->win->view; + Win *win = vis->win; + return win ? win->view : NULL; } Win *vis_window(Vis *vis) {