diff options
-rw-r--r-- | buffer.c | 17 | ||||
-rw-r--r-- | build.c | 104 | ||||
-rw-r--r-- | command.c | 6 | ||||
-rw-r--r-- | command.h | 4 | ||||
-rw-r--r-- | ted.cfg | 2 | ||||
-rw-r--r-- | ted.h | 6 |
6 files changed, 122 insertions, 17 deletions
@@ -1889,7 +1889,8 @@ void buffer_reload(TextBuffer *buffer) { BufferPos cursor_pos = buffer->cursor_pos; float x1 = buffer->x1, y1 = buffer->y1, x2 = buffer->x2, y2 = buffer->y2; double scroll_x = buffer->scroll_x; double scroll_y = buffer->scroll_y; - if (buffer_load_file(buffer, buffer->filename)) { + char *filename = str_dup(buffer->filename); + if (buffer_load_file(buffer, filename)) { buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2; buffer->cursor_pos = cursor_pos; buffer->scroll_x = scroll_x; @@ -1897,6 +1898,7 @@ void buffer_reload(TextBuffer *buffer) { buffer_validate_cursor(buffer); buffer_correct_scroll(buffer); } + free(filename); } } @@ -2051,7 +2053,6 @@ void buffer_render(TextBuffer *buffer, Rect r) { float render_start_y = y1 - (float)(buffer->scroll_y - start_line) * char_height; // where the 1st line is rendered - bool render_cursor = buffer == ted->active_buffer; // line numbering if (!buffer->is_line_buffer && settings->line_numbers) { @@ -2062,7 +2063,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { text_state.max_y = y2; float y = render_start_y; - u32 cursor_line = render_cursor ? buffer->cursor_pos.line : U32_MAX; + u32 cursor_line = buffer->cursor_pos.line; for (u32 line = start_line; line < nlines; ++line) { char str[32] = {0}; strbuf_printf(str, U32_FMT, line + 1); // convert line number to string @@ -2085,6 +2086,11 @@ void buffer_render(TextBuffer *buffer, Rect r) { buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2; + if (buffer->center_cursor_next_frame) { + buffer_center_cursor(buffer); + buffer->center_cursor_next_frame = false; + } + // handle mouse clicks for (u32 i = 0; i < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++i) { v2 point = ted->mouse_clicks[SDL_BUTTON_LEFT][i]; @@ -2122,8 +2128,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { // the rectangle that the cursor is rendered as Rect cursor_rect = rect(cursor_display_pos, V2(settings->cursor_width, char_height)); - if (render_cursor) { - // highlight line cursor is on + { // highlight line cursor is on Rect hl_rect = rect(V2(x1, cursor_display_pos.y), V2(x2-x1-1, char_height)); buffer_clip_rect(buffer, &hl_rect); gl_geometry_rect(hl_rect, colors[COLOR_CURSOR_LINE_BG]); @@ -2265,7 +2270,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { text_render(font); - if (render_cursor) { + if (ted->active_buffer == buffer) { // render cursor float time_on = settings->cursor_blink_time_on; float time_off = settings->cursor_blink_time_off; @@ -1,4 +1,15 @@ +// clear build errors. +static void build_clear(Ted *ted) { + arr_foreach_ptr(ted->build_errors, BuildError, err) { + free(err->filename); + } + arr_clear(ted->build_errors); +} + static void build_start(Ted *ted) { + // get rid of any old build errors + build_clear(ted); + chdir(ted->cwd); #if __unix__ char *program = "/bin/sh"; @@ -13,20 +24,55 @@ static void build_start(Ted *ted) { ted->building = true; ted->build_shown = true; buffer_new_file(&ted->build_buffer, NULL); - ted->build_buffer.store_undo_events = false; + ted->build_buffer.store_undo_events = false; // don't need undo events for build output buffer ted->build_buffer.view_only = true; } static void build_stop(Ted *ted) { if (ted->building) process_kill(&ted->build_process); - arr_foreach_ptr(ted->build_errors, BuildError, err) { - free(err->filename); - } ted->building = false; ted->build_shown = false; + build_clear(ted); } +static void build_go_to_error(Ted *ted) { + if (ted->build_error < arr_len(ted->build_errors)) { + BuildError error = ted->build_errors[ted->build_error]; + // open the file where the error happened + if (ted_open_file(ted, error.filename)) { + TextBuffer *buffer = ted->active_buffer; + assert(buffer); + // move cursor to error + buffer_cursor_move_to_pos(buffer, error.pos); + buffer->center_cursor_next_frame = true; + + // move cursor to error in build output + TextBuffer *build_buffer = &ted->build_buffer; + BufferPos error_pos = {.line = error.build_output_line, .index = 0}; + buffer_cursor_move_to_pos(build_buffer, error_pos); + buffer_center_cursor(build_buffer); + } + } +} + +static void build_next_error(Ted *ted) { + if (ted->build_errors) { + ted->build_error += 1; + ted->build_error %= arr_len(ted->build_errors); + build_go_to_error(ted); + } +} + +static void build_prev_error(Ted *ted) { + if (ted->build_errors) { + ted->build_error += arr_len(ted->build_errors) - 1; + ted->build_error %= arr_len(ted->build_errors); + build_go_to_error(ted); + } +} + + static void build_frame(Ted *ted, float x1, float y1, float x2, float y2) { TextBuffer *buffer = &ted->build_buffer; Process *process = &ted->build_process; @@ -82,6 +128,7 @@ static void build_frame(Ted *ted, float x1, float y1, float x2, float y2) { } if (any_text_inserted) { + // show bottom of output (only relevant if there are no build errors) buffer->cursor_pos = buffer_end_of_file(buffer); buffer_scroll_to_cursor(buffer); } @@ -132,23 +179,60 @@ static void build_frame(Ted *ted, float x1, float y1, float x2, float y2) { } if (i >= len) is_error = false; if (line_number_len == 0) is_error = false; + if (is_error) { char *line_number_str = str32_to_utf8_cstr(str32(str + filename_len + 1, line_number_len)); if (line_number_str) { int line_number = atoi(line_number_str); free(line_number_str); - - char *filename = str32_to_utf8_cstr(str32(str, filename_len)); - if (filename) { - char full_path[TED_PATH_MAX]; - ted_full_path(ted, filename, full_path, sizeof full_path); - printf("File %s line %d\n",full_path,line_number); + + if (line_number > 0) { + // it's an error + + // check if there's a column number + u32 column_len = 0; + ++i; + while (i < len) { + if (str[i] >= '0' && str[i] <= '9') + ++column_len; + else + break; + ++i; + } + int column = 0; + if (column_len) { + // file:line:column syntax + char *column_str = str32_to_utf8_cstr(str32(str + filename_len + 1 + line_number_len + 1, column_len)); + if (column_str) { + column = atoi(column_str); + column -= 1; + if (column < 0) column = 0; + free(column_str); + } + } + + line_number -= 1; // line numbers in output start from 1. + char *filename = str32_to_utf8_cstr(str32(str, filename_len)); + if (filename) { + char full_path[TED_PATH_MAX]; + ted_full_path(ted, filename, full_path, sizeof full_path); + BuildError error = { + .filename = str_dup(full_path), + .pos = {.line = (u32)line_number, .index = (u32)column}, + .build_output_line = line_idx + }; + arr_add(ted->build_errors, error); + } } } } } } + + // go to the first error (if there is one) + ted->build_error = 0; + build_go_to_error(ted); } buffer->view_only = true; } @@ -310,5 +310,11 @@ void command_execute(Ted *ted, Command c, i64 argument) { } build_start(ted); break; + case CMD_BUILD_NEXT_ERROR: + build_next_error(ted); + break; + case CMD_BUILD_PREV_ERROR: + build_prev_error(ted); + break; } } @@ -66,6 +66,8 @@ ENUM_U16 { CMD_VIEW_ONLY, // toggle view-only mode CMD_BUILD, + CMD_BUILD_PREV_ERROR, + CMD_BUILD_NEXT_ERROR, CMD_ESCAPE, // by default this is the escape key. closes menus, etc. @@ -131,6 +133,8 @@ static CommandName const command_names[CMD_COUNT] = { {"decrease-text-size", CMD_TEXT_SIZE_DECREASE}, {"view-only", CMD_VIEW_ONLY}, {"build", CMD_BUILD}, + {"build-prev-error", CMD_BUILD_PREV_ERROR}, + {"build-next-error", CMD_BUILD_NEXT_ERROR}, {"escape", CMD_ESCAPE}, }; @@ -112,6 +112,8 @@ Ctrl+- = 3 :decrease-text-size Ctrl+Alt+Shift+v = :view-only F4 = :build +Ctrl+[ = :build-prev-error +Ctrl+] = :build-next-error Escape = :escape @@ -137,6 +137,9 @@ typedef struct { bool will_chain_edits; bool chaining_edits; // are we chaining undo events together? bool view_only; + // If set to true, buffer will be scrolled to the cursor position next frame. + // This is to fix the problem that x1,y1,x2,y2 are not updated until the buffer is rendered. + bool center_cursor_next_frame; float x1, y1, x2, y2; u32 nlines; u32 lines_capacity; @@ -204,7 +207,7 @@ typedef struct { typedef struct { char *filename; - u32 line; + BufferPos pos; u32 build_output_line; // which line in the build output corresponds to this error } BuildError; @@ -251,6 +254,7 @@ typedef struct Ted { bool building; // is the build process running? BuildError *build_errors; // dynamic array of build errors + u32 build_error; // build error we are currently "on" Process build_process; // When we read the stdout from the build process, the tail end of the read could be an |