start showing call stack on errors

It turns out Lua has been providing us this information all along! I'd
just not created the space on screen to show it. Make it persist better.

Kilo now no longer tracks its own status messages, which is a regression
in a rare condition.
This commit is contained in:
Kartik K. Agaram 2021-12-04 14:11:44 -08:00
parent 810e160136
commit d9cf3433d9
7 changed files with 69 additions and 47 deletions

View File

@ -137,6 +137,7 @@ function init_colors()
curses.init_pair(13, 7, 5) curses.init_pair(13, 7, 5)
curses.init_pair(14, 7, 6) curses.init_pair(14, 7, 6)
curses.init_pair(15, -1, 15) curses.init_pair(15, -1, 15)
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
end]==], end]==],
}, },
{ {

View File

@ -219,6 +219,7 @@ function init_colors()
curses.init_pair(6, dark_piece, light_last_moved_square) curses.init_pair(6, dark_piece, light_last_moved_square)
curses.init_pair(7, light_piece, dark_last_moved_square) curses.init_pair(7, light_piece, dark_last_moved_square)
curses.init_pair(8, dark_piece, dark_last_moved_square) curses.init_pair(8, dark_piece, dark_last_moved_square)
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
end]==], end]==],
}, },
{ {

View File

@ -51,6 +51,7 @@ function main()
for i=1,7 do for i=1,7 do
curses.init_pair(i, 0, i) curses.init_pair(i, 0, i)
end end
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
while true do while true do
render(window) render(window)

View File

@ -88,6 +88,7 @@ function main()
for i=1,7 do for i=1,7 do
curses.init_pair(i, 0, i) curses.init_pair(i, 0, i)
end end
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
while true do while true do
render(window) render(window)

View File

@ -266,6 +266,7 @@ function main()
for i=1,7 do for i=1,7 do
curses.init_pair(i, i, -1) curses.init_pair(i, i, -1)
end end
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
-- initialize grid based on commandline args -- initialize grid based on commandline args
if (#arg == 0) then if (#arg == 0) then

View File

@ -95,15 +95,11 @@ struct editorConfig {
erow *row; /* Rows */ erow *row; /* Rows */
int dirty; /* File modified but not saved. */ int dirty; /* File modified but not saved. */
char *filename; /* Currently open filename */ char *filename; /* Currently open filename */
char statusmsg[80];
time_t statusmsg_time;
struct editorSyntax *syntax; /* Current syntax highlight, or NULL. */ struct editorSyntax *syntax; /* Current syntax highlight, or NULL. */
}; };
static struct editorConfig E; static struct editorConfig E;
static void editorSetStatusMessage(const char *fmt, ...);
/* =========================== Syntax highlights DB ========================= /* =========================== Syntax highlights DB =========================
* *
* In order to add a new syntax, define two arrays with a list of file name * In order to add a new syntax, define two arrays with a list of file name
@ -642,13 +638,16 @@ static int editorSaveToDisk(void) {
close(fd); close(fd);
free(buf); free(buf);
E.dirty = 0; E.dirty = 0;
memset(E.statusmsg, '\0', 80);
return 0; return 0;
writeerr: writeerr:
free(buf); free(buf);
if (fd != -1) close(fd); if (fd != -1) close(fd);
editorSetStatusMessage("Can't save! I/O error: %s",strerror(errno)); /* TODO: better error handling. */
/* I haven't gotten to this yet since we have version control. */
endwin();
printf("Can't save! I/O error: %s",strerror(errno));
exit(1);
return 1; return 1;
} }
@ -720,6 +719,7 @@ static void editorGoMenu(void) {
attrset(A_NORMAL); attrset(A_NORMAL);
} }
extern int render_previous_error();
static void editorRefreshScreen(void (*menu_func)(void)) { static void editorRefreshScreen(void (*menu_func)(void)) {
int y; int y;
erow *r; erow *r;
@ -771,12 +771,9 @@ static void editorRefreshScreen(void (*menu_func)(void)) {
} }
} }
(*menu_func)(); render_previous_error();
attrset(A_REVERSE); (*menu_func)();
addstr(" ");
addstr(E.statusmsg);
attrset(A_NORMAL);
/* Put cursor at its current position. Note that the horizontal position /* Put cursor at its current position. Note that the horizontal position
* at which the cursor is displayed may be different compared to 'E.cx' * at which the cursor is displayed may be different compared to 'E.cx'
@ -795,16 +792,6 @@ static void editorRefreshScreen(void (*menu_func)(void)) {
curs_set(1); curs_set(1);
} }
/* Set an editor status message for the second line of the status, at the
* end of the screen. */
static void editorSetStatusMessage(const char *fmt, ...) {
va_list ap;
va_start(ap,fmt);
vsnprintf(E.statusmsg,sizeof(E.statusmsg),fmt,ap);
va_end(ap);
E.statusmsg_time = time(NULL);
}
/* =============================== Find mode ================================ */ /* =============================== Find mode ================================ */
#define KILO_QUERY_LEN 256 #define KILO_QUERY_LEN 256
@ -843,7 +830,6 @@ static void editorFind() {
E.coloff = saved_coloff; E.rowoff = saved_rowoff; E.coloff = saved_coloff; E.rowoff = saved_rowoff;
} }
FIND_RESTORE_HL; FIND_RESTORE_HL;
editorSetStatusMessage("");
return; return;
} else if (c == CTRL_U) { } else if (c == CTRL_U) {
qlen = 0; qlen = 0;
@ -1040,7 +1026,6 @@ static void editorGo(lua_State* L) {
if (c == KEY_BACKSPACE || c == DELETE || c == CTRL_H) { if (c == KEY_BACKSPACE || c == DELETE || c == CTRL_H) {
if (qlen != 0) query[--qlen] = '\0'; if (qlen != 0) query[--qlen] = '\0';
} else if (c == CTRL_X || c == ENTER) { } else if (c == CTRL_X || c == ENTER) {
editorSetStatusMessage("");
if (c == ENTER) { if (c == ENTER) {
save_to_current_definition_and_editor_buffer(L, query); save_to_current_definition_and_editor_buffer(L, query);
clearEditor(); clearEditor();
@ -1182,12 +1167,11 @@ static void initEditor(void) {
} }
/* return true if user chose to back into the big picture view */ /* return true if user chose to back into the big picture view */
int edit(lua_State* L, char* filename, const char* message) { int edit(lua_State* L, char* filename) {
Quit = 0; Quit = 0;
Back_to_big_picture = 0; Back_to_big_picture = 0;
initEditor(); initEditor();
editorOpen(filename); editorOpen(filename);
editorSetStatusMessage(message);
while(!Quit) { while(!Quit) {
editorRefreshScreen(editorMenu); editorRefreshScreen(editorMenu);
editorProcessKeypress(L); editorProcessKeypress(L);
@ -1196,7 +1180,7 @@ int edit(lua_State* L, char* filename, const char* message) {
} }
/* return true if user chose to back into the big picture view */ /* return true if user chose to back into the big picture view */
int edit_from(lua_State* L, char* filename, const char* message, int rowoff, int coloff, int cy, int cx) { int edit_from(lua_State* L, char* filename, int rowoff, int coloff, int cy, int cx) {
Quit = 0; Quit = 0;
Back_to_big_picture = 0; Back_to_big_picture = 0;
initEditor(); initEditor();
@ -1205,7 +1189,6 @@ int edit_from(lua_State* L, char* filename, const char* message, int rowoff, int
E.cy = cy; E.cy = cy;
E.cx = cx; E.cx = cx;
editorOpen(filename); editorOpen(filename);
editorSetStatusMessage(message);
while(!Quit) { while(!Quit) {
editorRefreshScreen(editorMenu); editorRefreshScreen(editorMenu);
editorProcessKeypress(L); editorProcessKeypress(L);
@ -1216,7 +1199,6 @@ int edit_from(lua_State* L, char* filename, const char* message, int rowoff, int
int resumeEdit(lua_State* L) { int resumeEdit(lua_State* L) {
Quit = 0; Quit = 0;
Back_to_big_picture = 0; Back_to_big_picture = 0;
editorSetStatusMessage(Previous_error);
while(!Quit) { while(!Quit) {
editorRefreshScreen(editorMenu); editorRefreshScreen(editorMenu);
editorProcessKeypress(L); editorProcessKeypress(L);

View File

@ -81,21 +81,56 @@ static int report (lua_State *L, int status) {
} }
char *strdup(const char *s); /* return final y containing text */
extern void developer_mode (lua_State *L, const char *status_message); static int render_wrapped_text (int y, int xmin, int xmax, const char *text) {
int x = xmin;
move(y, x);
for (int j = 0; j < strlen(text); ++j) {
char c = text[j];
if (c != '\n') {
addch(text[j]);
++x;
if (x >= xmax) {
++y;
x = xmin;
move(y, x);
}
}
else {
/* newline */
++y;
x = xmin;
move(y, x);
}
}
return y;
}
const char *Previous_error = NULL;
void render_previous_error (void) {
if (!Previous_error) return;
attrset(COLOR_PAIR(255));
render_wrapped_text(LINES-10, COLS/2, COLS, Previous_error);
attrset(A_NORMAL);
}
extern char *strdup(const char *s);
extern void developer_mode (lua_State *L);
static int report_in_developer_mode (lua_State *L, int status) { static int report_in_developer_mode (lua_State *L, int status) {
if (status && !lua_isnil(L, -1)) { if (status && !lua_isnil(L, -1)) {
const char *msg = strdup(lua_tostring(L, -1)); /* memory leak */ Previous_error = strdup(lua_tostring(L, -1)); /* memory leak */
if (msg == NULL) msg = "(error object is not a string)"; if (Previous_error == NULL) Previous_error = "(error object is not a string)";
lua_pop(L, 1); lua_pop(L, 1);
for (int x = 0; x < COLS; ++x) { for (int x = 0; x < COLS; ++x) {
mvaddch(LINES-2, x, ' '); mvaddch(LINES-2, x, ' ');
mvaddch(LINES-1, x, ' '); mvaddch(LINES-1, x, ' ');
} }
mvaddstr(LINES-2, 0, msg); render_previous_error();
mvaddstr(LINES-1, 0, "press any key to continue"); mvaddstr(LINES-1, 0, "press any key to continue");
getch(); getch();
developer_mode(L, msg); developer_mode(L);
} }
return status; return status;
} }
@ -413,11 +448,10 @@ int load_editor_buffer_to_current_definition_in_image(lua_State *L) {
/* return true if user chose to back into the big picture view */ /* return true if user chose to back into the big picture view */
/* But only if there are no errors. Otherwise things can get confusing. */ /* But only if there are no errors. Otherwise things can get confusing. */
const char *Previous_error = NULL; extern int edit (lua_State *L, char *filename);
extern int edit (lua_State *L, char *filename, const char *message);
extern int resumeEdit (lua_State *L); extern int resumeEdit (lua_State *L);
int edit_current_definition (lua_State *L) { int edit_current_definition (lua_State *L) {
int back_to_big_picture = edit(L, "teliva_editor_buffer", /*status message*/ ""); int back_to_big_picture = edit(L, "teliva_editor_buffer");
// error handling // error handling
while (1) { while (1) {
int status; int status;
@ -482,7 +516,7 @@ static int render_wrapped_lua_text (int y, int xmin, int xmax, const char *text)
else { else {
/* newline */ /* newline */
++y; ++y;
x = 0; x = xmin;
move(y, x); move(y, x);
attroff(FG(6)); attroff(FG(6));
} }
@ -625,7 +659,7 @@ void recent_changes_view (lua_State *L) {
save_note_to_editor_buffer(L, cursor); save_note_to_editor_buffer(L, cursor);
/* big picture hotkey unnecessarily available here */ /* big picture hotkey unnecessarily available here */
/* TODO: go hotkey is misleading. edits will not be persisted until you return to recent changes */ /* TODO: go hotkey is misleading. edits will not be persisted until you return to recent changes */
edit(L, "teliva_editor_buffer", /*status message*/ ""); edit(L, "teliva_editor_buffer");
load_note_from_editor_buffer(L, cursor); load_note_from_editor_buffer(L, cursor);
save_image(L); save_image(L);
break; break;
@ -697,7 +731,7 @@ void draw_definition_name (const char *definition_name) {
} }
/* return true if submitted */ /* return true if submitted */
void big_picture_view (lua_State *L, const char *status_message) { void big_picture_view (lua_State *L) {
restart: restart:
clear(); clear();
luaL_newmetatable(L, "__teliva_call_graph_depth"); luaL_newmetatable(L, "__teliva_call_graph_depth");
@ -804,7 +838,7 @@ restart:
} }
lua_settop(L, 0); lua_settop(L, 0);
mvprintw(LINES-3, 0, status_message); render_previous_error();
char query[CURRENT_DEFINITION_LEN+1] = {0}; char query[CURRENT_DEFINITION_LEN+1] = {0};
int qlen = 0; int qlen = 0;
@ -858,8 +892,8 @@ int editor_view_in_progress (lua_State *L) {
return result; return result;
} }
extern int edit_from(lua_State *L, char *filename, const char *message, int rowoff, int coloff, int cy, int cx); extern int edit_from(lua_State *L, char *filename, int rowoff, int coloff, int cy, int cx);
int restore_editor_view (lua_State *L, const char *status_message) { int restore_editor_view (lua_State *L) {
lua_getglobal(L, "__teliva_editor_state"); lua_getglobal(L, "__teliva_editor_state");
int editor_state_index = lua_gettop(L); int editor_state_index = lua_gettop(L);
lua_getfield(L, editor_state_index, "definition"); lua_getfield(L, editor_state_index, "definition");
@ -874,7 +908,7 @@ int restore_editor_view (lua_State *L, const char *status_message) {
lua_getfield(L, editor_state_index, "cx"); lua_getfield(L, editor_state_index, "cx");
int cx = lua_tointeger(L, -1); int cx = lua_tointeger(L, -1);
lua_settop(L, editor_state_index); lua_settop(L, editor_state_index);
int back_to_big_picture = edit_from(L, "teliva_editor_buffer", status_message, rowoff, coloff, cy, cx); int back_to_big_picture = edit_from(L, "teliva_editor_buffer", rowoff, coloff, cy, cx);
// error handling // error handling
while (1) { while (1) {
int status; int status;
@ -892,18 +926,19 @@ int restore_editor_view (lua_State *L, const char *status_message) {
char **Argv = NULL; char **Argv = NULL;
extern void cleanup_curses (void); extern void cleanup_curses (void);
void developer_mode (lua_State *L, const char *status_message) { void developer_mode (lua_State *L) {
/* clobber the app's ncurses colors; we'll restart the app when we rerun it. */ /* clobber the app's ncurses colors; we'll restart the app when we rerun it. */
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
init_pair(i, i, 15); init_pair(i, i, 15);
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
init_pair(i+8, 0, i); init_pair(i+8, 0, i);
init_pair(255, /*white fg*/ 15, /*red bg*/ 1); /* for teliva error messages */
nodelay(stdscr, 0); /* make getch() block */ nodelay(stdscr, 0); /* make getch() block */
int switch_to_big_picture_view = 1; int switch_to_big_picture_view = 1;
if (editor_view_in_progress(L)) if (editor_view_in_progress(L))
switch_to_big_picture_view = restore_editor_view(L, status_message); switch_to_big_picture_view = restore_editor_view(L);
if (switch_to_big_picture_view) if (switch_to_big_picture_view)
big_picture_view(L, status_message); big_picture_view(L);
cleanup_curses(); cleanup_curses();
execv(Argv[0], Argv); execv(Argv[0], Argv);
/* never returns */ /* never returns */