diff options
-rw-r--r-- | colors.c | 5 | ||||
-rw-r--r-- | colors.h | 5 | ||||
-rw-r--r-- | command.c | 6 | ||||
-rw-r--r-- | config.c | 25 | ||||
-rw-r--r-- | lsp.h | 8 | ||||
-rw-r--r-- | main.c | 93 | ||||
-rw-r--r-- | ted.c | 91 | ||||
-rw-r--r-- | ted.cfg | 7 | ||||
-rw-r--r-- | ted.h | 33 |
9 files changed, 168 insertions, 105 deletions
@@ -24,9 +24,12 @@ static ColorName const color_names[] = { {COLOR_MENU_BACKDROP, "menu-backdrop"}, {COLOR_MENU_BG, "menu-bg"}, {COLOR_MENU_HL, "menu-hl"}, - {COLOR_ERROR_TEXT, "error-text"}, {COLOR_ERROR_BG, "error-bg"}, {COLOR_ERROR_BORDER, "error-border"}, + {COLOR_INFO_BG, "info-bg"}, + {COLOR_INFO_BORDER, "info-border"}, + {COLOR_WARNING_BG, "warning-bg"}, + {COLOR_WARNING_BORDER, "warning-border"}, {COLOR_ACTIVE_TAB_HL, "active-tab-hl"}, {COLOR_SELECTED_TAB_HL, "selected-tab-hl"}, {COLOR_FIND_HL, "find-hl"}, @@ -21,9 +21,12 @@ typedef enum { COLOR_MENU_BACKDROP, COLOR_MENU_BG, COLOR_MENU_HL, - COLOR_ERROR_TEXT, COLOR_ERROR_BG, COLOR_ERROR_BORDER, + COLOR_WARNING_BG, + COLOR_WARNING_BORDER, + COLOR_INFO_BG, + COLOR_INFO_BORDER, COLOR_ACTIVE_TAB_HL, COLOR_SELECTED_TAB_HL, COLOR_FIND_HL, @@ -516,9 +516,9 @@ void command_execute(Ted *ted, Command c, i64 argument) { case CMD_ESCAPE: definition_cancel_lookup(ted); usages_cancel_lookup(ted); - if (*ted->error_shown) { - // dismiss error box - *ted->error_shown = '\0'; + if (*ted->message_shown) { + // dismiss message box + *ted->message_shown = '\0'; } else if (ted->autocomplete.open) { autocomplete_close(ted); } else if (ted->menu) { @@ -147,16 +147,6 @@ static void setting_string_set(Settings *settings, const SettingString *set, con } - - - -// all worth it for the -Wformat warnings -#define config_err(cfg, ...) do {\ - if ((cfg)->error) break;\ - snprintf((cfg)->ted->error, sizeof (cfg)->ted->error - 1, "%s:%u: ", (cfg)->filename, (cfg)->line_number), \ - snprintf((cfg)->ted->error + strlen((cfg)->ted->error), sizeof (cfg)->ted->error - 1 - strlen((cfg)->ted->error), __VA_ARGS__), \ - (cfg)->error = true; } while (0) - typedef struct { Ted *ted; const char *filename; @@ -164,6 +154,16 @@ typedef struct { bool error; } ConfigReader; +static void config_err(ConfigReader *cfg, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); +static void config_err(ConfigReader *cfg, const char *fmt, ...) { + char error[1024] = {0}; + strbuf_printf(error, "%s:%u: ", cfg->filename, cfg->line_number); + va_list args; + va_start(args, fmt); + vsnprintf(error + strlen(error), sizeof error - strlen(error) - 1, fmt, args); + va_end(args); +} + static void context_copy(SettingsContext *dest, const SettingsContext *src) { *dest = *src; if (src->path) @@ -647,7 +647,10 @@ uniform sampler2D t_texture;\n\ gl_rc_sab_decref(&s->bg_shader); - GLuint shader = gl_compile_and_link_shaders(ted->error, vshader, fshader); + char error[512] = {0}; + GLuint shader = gl_compile_and_link_shaders(error, vshader, fshader); + if (*error) + ted_seterr(ted, "%s", error); if (shader) { GLuint buffer = 0, array = 0; glGenBuffers(1, &buffer); @@ -119,10 +119,10 @@ typedef struct { } LSPRequestDidChange; typedef enum { - ERROR = 1, - WARNING = 2, - INFO = 3, - LOG = 4 + LSP_WINDOW_MESSAGE_ERROR = 1, + LSP_WINDOW_MESSAGE_WARNING = 2, + LSP_WINDOW_MESSAGE_INFO = 3, + LSP_WINDOW_MESSAGE_LOG = 4 } LSPWindowMessageType; typedef struct { @@ -1,5 +1,8 @@ /* @TODO: +- rename ted_seterr to ted_error +- use keycodes instead of scancodes (maybe that will make numlock modifier no longer necessary) +- go to declaration with LSP - ted.h documentation - handle multiple symbols with same name in go-to-definition menu - better non-error window/showMessage(Request) @@ -26,8 +29,8 @@ - rust-analyzer bug reports: - bad json can give "Unexpected error: client exited without proper shutdown sequence" FUTURE FEATURES: +- add numlock as a key modifier? (but make sure "Ctrl+S" handles both "No NumLock+Ctrl+S" and "NumLock+Ctrl+S") - comment-start + comment-end settings -- go to declaration with LSP - robust find (results shouldn't move around when you type things) - multiple files with command line arguments - :set-build-command @@ -37,7 +40,6 @@ FUTURE FEATURES: - i'm putting this off for now since it seems hard to have undo support for it. - possible idea: open all files altered, and create undo chains for each of them. if there are too many files, give an error like "use a different tool for this" -- add numlock as a key modifier? (but make sure "Ctrl+S" handles both "No NumLock+Ctrl+S" and "NumLock+Ctrl+S") - better undo chaining (dechain on backspace?) - allow multiple fonts (fonts directory?) - regenerate tags for completion too if there are no results @@ -117,7 +119,7 @@ FUTURE FEATURES: #endif -static Rect error_box_rect(Ted *ted) { +static Rect message_box_rect(Ted *ted) { Font *font = ted->font; const Settings *settings = ted_active_settings(ted); float padding = settings->padding; @@ -431,9 +433,6 @@ int main(int argc, char **argv) { // (for testing on Unix systems without /proc) ted->search_cwd = true; #endif - - - char config_err[sizeof ted->error] = {0}; PROFILE_TIME(misc_end) @@ -508,10 +507,6 @@ int main(int argc, char **argv) { PROFILE_TIME(configs_start) ted_load_configs(ted, false); - if (ted_haserr(ted)) { - strcpy(config_err, ted->error); - ted_clearerr(ted); // clear the error so later things (e.g. loading font) don't detect an error - } PROFILE_TIME(configs_end) PROFILE_TIME(fonts_start) @@ -519,8 +514,6 @@ int main(int argc, char **argv) { PROFILE_TIME(fonts_end) PROFILE_TIME(create_start) - if (ted_haserr(ted)) - die("Error loading font: %s", ted_geterr(ted)); { TextBuffer *lbuffer = &ted->line_buffer; line_buffer_create(lbuffer, ted); @@ -535,17 +528,9 @@ int main(int argc, char **argv) { { if (starting_filename) { if (fs_file_exists(starting_filename)) { - if (!ted_open_file(ted, starting_filename)) { - char err[512] = {0}; - sprintf(err, "%.500s", ted_geterr(ted)); // -Wrestrict (rightly) complains without this intermediate step - ted_seterr(ted, "Couldn't load file: %s", err); - } + ted_open_file(ted, starting_filename); } else { - if (!ted_new_file(ted, starting_filename)) { - char err[512] = {0}; - sprintf(err, "%.500s", ted_geterr(ted)); - ted_seterr(ted, "Couldn't create file: %s", err); - } + ted_new_file(ted, starting_filename); } } else { session_read(ted); @@ -567,8 +552,6 @@ int main(int argc, char **argv) { PROFILE_TIME(get_ready_start) Uint32 time_at_last_frame = SDL_GetTicks(); - - strbuf_cpy(ted->error, config_err); SDL_GL_SetSwapInterval(1); // vsync @@ -659,12 +642,12 @@ int main(int argc, char **argv) { && ted->nmouse_clicks[button] < arr_count(ted->mouse_clicks[button])) { vec2 pos = Vec2(x, y); bool add = true; - if (*ted->error_shown) { - if (rect_contains_point(error_box_rect(ted), pos)) { - // clicked on error + if (*ted->message_shown) { + if (rect_contains_point(message_box_rect(ted), pos)) { + // clicked on message if (button == SDL_BUTTON_LEFT) { - // dismiss error - *ted->error_shown = '\0'; + // dismiss message + *ted->message_shown = '\0'; } // don't let anyone else use this event add = false; @@ -848,13 +831,12 @@ int main(int argc, char **argv) { switch (r->type) { case LSP_REQUEST_SHOW_MESSAGE: { LSPRequestMessage *m = &r->data.message; - // @TODO: multiple messages - ted_seterr(ted, "%s", m->message); + MessageType type = ted_message_type_from_lsp(m->type); + ted_set_message(ted, type, "%s", m->message); } break; case LSP_REQUEST_LOG_MESSAGE: { LSPRequestMessage *m = &r->data.message; - // @TODO: actual logging - printf("%s\n", m->message); + ted_log(ted, "%s\n", m->message); } break; default: break; } @@ -1011,39 +993,36 @@ int main(int argc, char **argv) { } for (int i = 0; ted->lsps[i]; ++i) { LSP *lsp = ted->lsps[i]; - if (lsp_get_error(lsp, NULL, 0, false)) { - lsp_get_error(lsp, ted->error, sizeof ted->error, true); + char error[512] = {0}; + if (lsp_get_error(lsp, error, sizeof error, true)) { + ted_seterr(ted, "%s", error); } } // check if there's a new error - if (ted_haserr(ted)) { - ted->error_time = ted->frame_time; - str_cpy(ted->error_shown, sizeof ted->error_shown, ted->error); - - // output error to log file - char tstr[256]; - time_t t = time(NULL); - struct tm *tm = localtime(&t); - strftime(tstr, sizeof tstr, "%Y-%m-%d %H:%M:%S", tm); - ted_log(ted, "[ERROR %s] %s\n", tstr, ted->error); - - ted_clearerr(ted); + if (*ted->message) { + ted->message_time = ted->frame_time; + str_cpy(ted->message_shown, sizeof ted->message_shown, ted->message); + ted->message_shown_type = ted->message_type; + *ted->message = '\0'; } - // error box - if (*ted->error_shown) { - double time_passed = ted->frame_time - ted->error_time; + // message box + if (*ted->message_shown) { + double time_passed = ted->frame_time - ted->message_time; Settings *settings = ted_active_settings(ted); if (time_passed > settings->error_display_time) { // stop showing error - *ted->error_shown = '\0'; + *ted->message_shown = '\0'; } else { - Rect r = error_box_rect(ted); + Rect r = message_box_rect(ted); float padding = settings->padding; - - gl_geometry_rect(r, ted_color(ted, COLOR_ERROR_BG)); - gl_geometry_rect_border(r, settings->border_thickness, ted_color(ted, COLOR_ERROR_BORDER)); + ColorSetting bg_color=0, border_color=0; + + ted_color_settings_for_message_type(ted->message_type, &bg_color, &border_color); + + gl_geometry_rect(r, ted_color(ted, bg_color)); + gl_geometry_rect_border(r, settings->border_thickness, ted_color(ted, border_color)); float text_x1 = rect_x1(r) + padding, text_x2 = rect_x2(r) - padding; float text_y1 = rect_y1(r) + padding; @@ -1055,8 +1034,8 @@ int main(int argc, char **argv) { text_state.x = text_x1; text_state.y = text_y1; text_state.wrap = true; - rgba_u32_to_floats(ted_color(ted, COLOR_ERROR_TEXT), text_state.color); - text_utf8_with_state(font, &text_state, ted->error_shown); + rgba_u32_to_floats(ted_color(ted, COLOR_TEXT), text_state.color); + text_utf8_with_state(font, &text_state, ted->message_shown); gl_geometry_draw(); text_render(font); } @@ -16,10 +16,48 @@ void die(const char *fmt, ...) { exit(EXIT_FAILURE); } +static void ted_vset_message(Ted *ted, MessageType type, const char *fmt, va_list args) { + char message[sizeof ted->message] = {0}; + vsnprintf(message, sizeof message - 1, fmt, args); + + // output error to log file + char tstr[256]; + time_t t = time(NULL); + struct tm *tm = localtime(&t); + strftime(tstr, sizeof tstr, "%Y-%m-%d %H:%M:%S", tm); + ted_log(ted, "[ERROR %s] %s\n", tstr, message); + + if (type >= ted->message_type) { + ted->message_type = type; + strbuf_cpy(ted->message, message); + } +} + +void ted_set_message(Ted *ted, MessageType type, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + ted_vset_message(ted, type, fmt, args); + va_end(args); +} + void ted_seterr(Ted *ted, const char *fmt, ...) { va_list args; va_start(args, fmt); - vsnprintf(ted->error, sizeof ted->error - 1, fmt, args); + ted_vset_message(ted, MESSAGE_ERROR, fmt, args); + va_end(args); +} + +void ted_warn(Ted *ted, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + ted_vset_message(ted, MESSAGE_WARNING, fmt, args); + va_end(args); +} + +void ted_info(Ted *ted, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + ted_vset_message(ted, MESSAGE_INFO, fmt, args); va_end(args); } @@ -34,24 +72,9 @@ void ted_log(Ted *ted, const char *fmt, ...) { void ted_seterr_to_buferr(Ted *ted, TextBuffer *buffer) { - size_t size = sizeof ted->error; - if (sizeof buffer->error < size) size = sizeof buffer->error; - memcpy(ted->error, buffer->error, size); -} - -bool ted_haserr(Ted *ted) { - return ted->error[0] != '\0'; + ted_seterr(ted, "%s", buffer->error); } -const char *ted_geterr(Ted *ted) { - return ted->error; -} - -void ted_clearerr(Ted *ted) { - ted->error[0] = '\0'; -} - - void ted_out_of_mem(Ted *ted) { ted_seterr(ted, "Out of memory."); } @@ -235,11 +258,10 @@ static void ted_load_font(Ted *ted, const char *filename, Font **out) { } *out = font; } else { - ted_seterr(ted, "Couldn't load font: %s", text_get_err()); - text_clear_err(); + die("Couldn't load font: %s", text_get_err()); } } else { - ted_seterr(ted, "Couldn't find font file. There is probably a problem with your ted installation."); + die("Couldn't find font file. There is probably a problem with your ted installation."); } } @@ -624,3 +646,32 @@ void ted_check_for_node_problems(Ted *ted) { } } } + +MessageType ted_message_type_from_lsp(LSPWindowMessageType type) { + switch (type) { + case LSP_WINDOW_MESSAGE_ERROR: return MESSAGE_ERROR; + case LSP_WINDOW_MESSAGE_WARNING: return MESSAGE_WARNING; + case LSP_WINDOW_MESSAGE_INFO: + case LSP_WINDOW_MESSAGE_LOG: + return MESSAGE_INFO; + } + assert(0); + return MESSAGE_ERROR; +} + +void ted_color_settings_for_message_type(MessageType type, ColorSetting *bg_color, ColorSetting *border_color) { + switch (type) { + case MESSAGE_ERROR: + *bg_color = COLOR_ERROR_BG; + *border_color = COLOR_ERROR_BORDER; + break; + case MESSAGE_WARNING: + *bg_color = COLOR_WARNING_BG; + *border_color = COLOR_WARNING_BORDER; + break; + case MESSAGE_INFO: + *bg_color = COLOR_INFO_BG; + *border_color = COLOR_INFO_BORDER; + break; + } +} @@ -310,7 +310,12 @@ menu-hl = #afa2 # error box colors error-border = #f00 error-bg = #800 -error-text = #fdd +# warning box colors +warning-border = #ff0 +warning-bg = #660 +# info box colors +info-border = #00f +info-bg = #004 # color to highlight search results with find-hl = #fff4 yes = #afa @@ -482,6 +482,14 @@ typedef struct { LSPDocumentPosition requested_position; } Highlights; +// more severe message types should have higher numbers. +// they will override less severe messages. +typedef enum { + MESSAGE_INFO, + MESSAGE_WARNING, + MESSAGE_ERROR +} MessageType; + typedef struct Ted { LSP *lsps[TED_LSP_MAX + 1]; // current time (see time_get_seconds), as of the start of this frame @@ -518,7 +526,6 @@ typedef struct Ted { TextBuffer replace_buffer; // "replace" for find+replace TextBuffer build_buffer; // buffer for build output (view only) TextBuffer argument_buffer; // used for command selector - double error_time; // time error box was opened (in seconds -- see time_get_seconds) double cursor_error_time; // time which the cursor error animation started (cursor turns red, e.g. when there's no autocomplete suggestion) bool search_start_cwd; // should start_cwd be searched for files? set to true if the executable isn't "installed" char start_cwd[TED_PATH_MAX]; @@ -598,8 +605,13 @@ typedef struct Ted { u32 nstrings; char *strings[TED_MAX_STRINGS]; char window_title[256]; - char error[512]; - char error_shown[512]; // error display in box on screen + + // little box used to display errors and info. + double message_time; // time message box was opened + MessageType message_type; + char message[512]; + MessageType message_shown_type; + char message_shown[512]; } Ted; // === buffer.c === @@ -1034,8 +1046,14 @@ SymbolInfo *tags_get_symbols(Ted *ted); // === ted.c === // for fatal errors void die(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2); -// for non-fatal errors that should be displayed to the user +// display a message to the user +void ted_set_message(Ted *ted, MessageType type, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4); +// display an error to the user void ted_seterr(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); +// display a warning to the user +void ted_warn(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); +// display information to the user +void ted_info(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); // for information that should be logged void ted_log(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); // set error to "out of memory" message. @@ -1048,15 +1066,12 @@ Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz); void ted_path_full(Ted *ted, const char *relpath, char *abspath, size_t abspath_size); void ted_reset_active_buffer(Ted *ted); void ted_seterr_to_buferr(Ted *ted, TextBuffer *buffer); -bool ted_haserr(Ted *ted); // Returns the buffer containing the file at `path`, or NULL if there is none. TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path); bool ted_save_all(Ted *ted); void ted_reload_all(Ted *ted); -const char *ted_geterr(Ted *ted); // Load all the fonts ted will use. void ted_load_fonts(Ted *ted); -void ted_clearerr(Ted *ted); char *ted_get_root_dir_of(Ted *ted, const char *path); char *ted_get_root_dir(Ted *ted); // the settings of the active buffer, or the default settings if there is no active buffer @@ -1093,6 +1108,10 @@ void ted_cancel_lsp_request(Ted *ted, LSPID lsp, LSPRequestID request); float ted_line_buffer_height(Ted *ted); // check for orphaned nodes and node cycles void ted_check_for_node_problems(Ted *ted); +// convert LSPWindowMessageType to MessageType +MessageType ted_message_type_from_lsp(LSPWindowMessageType type); +// get colors to use for message box +void ted_color_settings_for_message_type(MessageType type, ColorSetting *bg_color, ColorSetting *border_color); // === ui.c === void selector_up(Ted *ted, Selector *s, i64 n); |