From 979ab795bc9d19524be524c79265c6b952199a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Thu, 28 Jan 2016 23:02:19 +0100 Subject: [PATCH] Improve Lua error reporting Display Lua errors in a dedicated window/file. A typo or missing dependency (e.g. lpeg) in visrc.lua will no longer silently fail without any indication. The Lua integration in view.h is not yet converted. --- ui-curses.c | 6 ++++++ ui.h | 1 + vis-core.h | 1 + vis-lua.c | 36 +++++++++++++++++++++++++++++------- vis-prompt.c | 23 +++++++++++++++++++++++ vis.c | 7 +++++-- vis.h | 6 +++++- 7 files changed, 70 insertions(+), 10 deletions(-) diff --git a/ui-curses.c b/ui-curses.c index 40e5c1379..671fa61ec 100644 --- a/ui-curses.c +++ b/ui-curses.c @@ -988,6 +988,11 @@ static void ui_info_hide(Ui *ui) { static bool ui_init(Ui *ui, Vis *vis) { UiCurses *uic = (UiCurses*)ui; uic->vis = vis; + return true; +} + +static bool ui_start(Ui *ui) { + Vis *vis = ((UiCurses*)ui)->vis; const char *theme = getenv("VIS_THEME"); if (theme && theme[0]) { if (!vis_theme_load(vis, theme)) @@ -1087,6 +1092,7 @@ Ui *ui_curses_new(void) { *ui = (Ui) { .init = ui_init, + .start = ui_start, .free = ui_curses_free, .termkey_get = ui_termkey_get, .suspend = ui_suspend, diff --git a/ui.h b/ui.h index 6c5b63de5..61fa4dfed 100644 --- a/ui.h +++ b/ui.h @@ -44,6 +44,7 @@ enum UiStyles { struct Ui { bool (*init)(Ui*, Vis*); + bool (*start)(Ui*); void (*free)(Ui*); void (*resize)(Ui*); UiWin* (*window_new)(Ui*, View*, File*, enum UiOption); diff --git a/vis-core.h b/vis-core.h index 9010ea43f..91bdf5886 100644 --- a/vis-core.h +++ b/vis-core.h @@ -132,6 +132,7 @@ struct Vis { File *search_file; /* special internal file used to store /,? search prompt */ Win *windows; /* all windows currently managed by this editor instance */ Win *win; /* currently active/focused window */ + Win *message_window; /* special window to display multi line messages */ Register registers[VIS_REG_INVALID]; /* registers used for yank and put */ Macro macros[VIS_MACRO_INVALID]; /* recorded macros */ Macro *recording, *last_recording; /* currently (if non NULL) and least recently recorded macro */ diff --git a/vis-lua.c b/vis-lua.c index 5b44ea1ad..7549cc187 100644 --- a/vis-lua.c +++ b/vis-lua.c @@ -78,6 +78,28 @@ static void stack_dump(lua_State *L, const char *format, ...) { #endif +static int error_function(lua_State *L) { + Vis *vis = lua_touserdata(L, lua_upvalueindex(1)); + size_t len; + const char *msg = lua_tostring(L, 1); + if (msg) + luaL_traceback(L, L, msg, 1); + msg = lua_tolstring(L, 1, &len); + vis_message_show(vis, msg); + return 1; +} + +static int pcall(Vis *vis, lua_State *L, int nargs, int nresults) { + /* insert a custom error function below all arguments */ + int msgh = lua_gettop(L) - nargs; + lua_pushlightuserdata(L, vis); + lua_pushcclosure(L, error_function, 1); + lua_insert(L, msgh); + int ret = lua_pcall(L, nargs, nresults, msgh); + lua_remove(L, msgh); + return ret; +} + static void *obj_new(lua_State *L, size_t size, const char *type) { void *obj = lua_newuserdata(L, size); luaL_getmetatable(L, type); @@ -586,10 +608,10 @@ void vis_lua_start(Vis *vis) { lua_getglobal(L, "require"); lua_pushstring(L, "visrc"); - lua_pcall(L, 1, 0, 0); + pcall(vis, L, 1, 0); vis_lua_event(vis, "start"); if (lua_isfunction(L, -1)) - lua_pcall(L, 0, 0, 0); + pcall(vis, L, 0, 0); lua_pop(L, 1); } @@ -599,7 +621,7 @@ void vis_lua_quit(Vis *vis) { return; vis_lua_event(vis, "quit"); if (lua_isfunction(L, -1)) - lua_pcall(L, 0, 0, 0); + pcall(vis, L, 0, 0); lua_pop(L, 1); lua_close(L); } @@ -617,7 +639,7 @@ void vis_lua_file_close(Vis *vis, File *file) { vis_lua_event(vis, "file_close"); if (lua_isfunction(L, -1)) { obj_ref_new(L, file, "vis.file"); - lua_pcall(L, 1, 0, 0); + pcall(vis, L, 1, 0); } obj_ref_free(L, file->text); obj_ref_free(L, file); @@ -629,7 +651,7 @@ void vis_lua_win_open(Vis *vis, Win *win) { vis_lua_event(vis, "win_open"); if (lua_isfunction(L, -1)) { obj_ref_new(L, win, "vis.window"); - lua_pcall(L, 1, 0, 0); + pcall(vis, L, 1, 0); } lua_pop(L, 1); } @@ -639,7 +661,7 @@ void vis_lua_win_close(Vis *vis, Win *win) { vis_lua_event(vis, "win_close"); if (lua_isfunction(L, -1)) { obj_ref_new(L, win, "vis.window"); - lua_pcall(L, 1, 0, 0); + pcall(vis, L, 1, 0); } obj_ref_free(L, win->view); obj_ref_free(L, win); @@ -663,7 +685,7 @@ bool vis_theme_load(Vis *vis, const char *name) { lua_pop(L, 2); lua_getglobal(L, "require"); lua_pushvalue(L, -2); - if (lua_pcall(L, 1, 0, 0)) + if (pcall(vis, L, 1, 0)) return false; for (Win *win = vis->windows; win; win = win->next) view_syntax_set(win->view, view_syntax_get(win->view)); diff --git a/vis-prompt.c b/vis-prompt.c index 4db10573a..2441fa4b3 100644 --- a/vis-prompt.c +++ b/vis-prompt.c @@ -187,3 +187,26 @@ void vis_info_hide(Vis *vis) { vis->ui->info_hide(vis->ui); } +void vis_message_show(Vis *vis, const char *msg) { + if (!msg) + return; + if (!vis->message_window) { + if (!vis_window_new(vis, NULL)) + return; + vis->message_window = vis->win; + } + + Win *win = vis->message_window; + Text *txt = win->file->text; + size_t pos = text_size(txt); + text_appendf(txt, "%s\n", msg); + text_save(txt, NULL); + view_cursor_to(win->view, pos); +} + +void vis_message_hide(Vis *vis) { + if (!vis->message_window) + return; + vis_window_close(vis->message_window); + vis->message_window = NULL; +} diff --git a/vis.c b/vis.c index 1602674c1..2c0d625e1 100644 --- a/vis.c +++ b/vis.c @@ -297,6 +297,8 @@ void vis_window_close(Win *win) { vis->windows = win->next; if (vis->win == win) vis->win = win->next ? win->next : win->prev; + if (win == vis->message_window) + vis->message_window = NULL; window_free(win); if (vis->win) vis->ui->window_focus(vis->win->ui); @@ -309,8 +311,6 @@ Vis *vis_new(Ui *ui, VisEvent *event) { Vis *vis = calloc(1, sizeof(Vis)); if (!vis) return NULL; - if (event && event->vis_start) - event->vis_start(vis); vis->ui = ui; vis->ui->init(vis->ui, vis); vis->tabwidth = 8; @@ -324,6 +324,9 @@ Vis *vis_new(Ui *ui, VisEvent *event) { goto err; vis->mode_prev = vis->mode = &vis_modes[VIS_MODE_NORMAL]; vis->event = event; + if (event && event->vis_start) + event->vis_start(vis); + vis->ui->start(vis->ui); return vis; err: vis_free(vis); diff --git a/vis.h b/vis.h index 477ffe488..f749a6365 100644 --- a/vis.h +++ b/vis.h @@ -81,10 +81,14 @@ void vis_window_prev(Vis*); /* display a user prompt with a certain title and default text */ void vis_prompt_show(Vis*, const char *title); -/* display a message to the user */ +/* display a one line message to the user, will be hidden upon keypress */ void vis_info_show(Vis*, const char *msg, ...); void vis_info_hide(Vis*); +/* display an arbitrary long message in a special window/file */ +void vis_message_show(Vis*, const char *msg); +void vis_message_hide(Vis*); + /* these function operate on the currently focused window but make sure * that all windows which show the affected region are redrawn too. */ void vis_insert(Vis*, size_t pos, const char *data, size_t len);