From 34fa190c3d490dd8cfec37d27bc03182f2a725a2 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Fri, 19 Feb 2021 14:23:43 -0500 Subject: ctrl+click to go to definition --- buffer.c | 54 ++++++++++++++++++++-------------------- main.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- tags.c | 9 +++++-- ted.h | 1 + 4 files changed, 105 insertions(+), 45 deletions(-) diff --git a/buffer.c b/buffer.c index 7c468b8..776c9dd 100644 --- a/buffer.c +++ b/buffer.c @@ -1133,6 +1133,33 @@ i64 buffer_cursor_move_right_words(TextBuffer *buffer, i64 nwords) { return ret; } +// Returns a string of word characters (see is_word) around the position, +// or an empty string if neither of the characters to the left and right of the cursor are word characters. +// NOTE: The string is invalidated when the buffer is changed!!! +String32 buffer_word_at_pos(TextBuffer *buffer, BufferPos pos) { + buffer_pos_validate(buffer, &pos); + Line *line = &buffer->lines[pos.line]; + char32_t *str = line->str; + i64 word_start, word_end; + for (word_start = pos.index; word_start > 0; --word_start) { + if (!is_word(str[word_start - 1])) + break; + } + for (word_end = pos.index; word_end < line->len; ++word_end) { + if (!is_word(str[word_end])) + break; + } + u32 len = (u32)(word_end - word_start); + if (len == 0) + return str32(NULL, 0); + else + return str32(str + word_start, len); +} + +String32 buffer_word_at_cursor(TextBuffer *buffer) { + return buffer_word_at_pos(buffer, buffer->cursor_pos); +} + // Returns the position corresponding to the start of the given line. BufferPos buffer_pos_start_of_line(TextBuffer *buffer, u32 line) { (void)buffer; @@ -2087,37 +2114,12 @@ 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]; - u8 times = ted->mouse_click_times[SDL_BUTTON_LEFT][i]; - BufferPos pos; - if (buffer_pixels_to_pos(buffer, point, &pos)) { - // user clicked on buffer - if (!ted->menu) - ted->active_buffer = buffer; - if (buffer == ted->active_buffer) { - buffer_cursor_move_to_pos(buffer, pos); - - switch ((times - 1) % 3) { - case 0: break; // single-click - case 1: // double-click: select word - buffer_select_word(buffer); - break; - case 2: // triple-click: select line - buffer_select_line(buffer); - break; - } - ted->drag_buffer = buffer; - } - } - } - if (rect_contains_point(rect4(x1, y1, x2, y2), ted->mouse_pos)) { // scroll with mouse wheel double scroll_speed = 2.5; diff --git a/main.c b/main.c index 2321dbf..2a47545 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,7 @@ // @TODO: -// - go to definition (with ctags) -- ctrl+click would be nice +// - Ctrl+D = :find-definition --- tag menu (see all tags, select one) + +// - goto line // - :run -- if .html file, open in browser, otherwise figure out a way of sending a command to shell // running in terminal emulator?? (don't want to implement stdin/ANSI codes/etc.) @@ -59,6 +61,7 @@ no_warn_end #include "string32.c" #include "syntax.c" +bool tag_goto(Ted *ted, char const *tag); #include "buffer.c" #include "ted.c" #include "tags.c" @@ -366,8 +369,6 @@ int main(int argc, char **argv) { Uint32 time_at_last_frame = SDL_GetTicks(); - tag_goto(ted, "buffer_create"); - while (!ted->quit) { #if DEBUG //printf("\033[H\033[2J"); @@ -392,12 +393,14 @@ int main(int argc, char **argv) { ted->scroll_total_x = ted->scroll_total_y = 0; ted_update_window_dimensions(ted); - - while (SDL_PollEvent(&event)) { - TextBuffer *buffer = ted->active_buffer; - u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT + u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT | (u32)shift_down << KEY_MODIFIER_SHIFT_BIT | (u32)alt_down << KEY_MODIFIER_ALT_BIT; + ted->key_modifier = key_modifier; + + while (SDL_PollEvent(&event)) { + TextBuffer *buffer = ted->active_buffer; + switch (event.type) { case SDL_QUIT: command_execute(ted, CMD_QUIT, 1); @@ -410,7 +413,7 @@ int main(int argc, char **argv) { } break; case SDL_MOUSEBUTTONDOWN: { Uint32 button = event.button.button; - + u8 times = event.button.clicks; // number of clicks float x = (float)event.button.x, y = (float)event.button.y; if (button < arr_count(ted->nmouse_clicks) && ted->nmouse_clicks[button] < arr_count(ted->mouse_clicks[button])) { @@ -427,10 +430,64 @@ int main(int argc, char **argv) { add = false; } } - if (add) { - ted->mouse_clicks[button][ted->nmouse_clicks[button]] = pos; - ted->mouse_click_times[button][ted->nmouse_clicks[button]] = event.button.clicks; - ++ted->nmouse_clicks[button]; + + if (add) { + // handle mouse click + // we need to do this here, and not in buffer_render, because ctrl+click (go to definition) + // could switch to a different buffer. + for (u32 i = 0; i < TED_MAX_NODES; ++i) { + if (ted->nodes_used[i]) { + Node *node = &ted->nodes[i]; + if (node->tabs) { + buffer = &ted->buffers[node->tabs[node->active_tab]]; + + BufferPos buffer_pos; + if (buffer_pixels_to_pos(buffer, pos, &buffer_pos)) { + // user clicked on buffer + if (!ted->menu) + ted->active_buffer = buffer; + if (buffer == ted->active_buffer) { + add = false; + switch (ted->key_modifier) { + case KEY_MODIFIER_SHIFT: + // select to position + buffer_select_to_pos(buffer, buffer_pos); + break; + case KEY_MODIFIER_CTRL: { + buffer_cursor_move_to_pos(buffer, buffer_pos); + String32 word = buffer_word_at_cursor(buffer); + if (word.len) { + char *tag = str32_to_utf8_cstr(word); + if (tag) { + tag_goto(buffer->ted, tag); + free(tag); + } + } + } break; + case 0: + buffer_cursor_move_to_pos(buffer, buffer_pos); + switch ((times - 1) % 3) { + case 0: break; // single-click + case 1: // double-click: select word + buffer_select_word(buffer); + break; + case 2: // triple-click: select line + buffer_select_line(buffer); + break; + } + ted->drag_buffer = buffer; + break; + } + } + } + } + } + } + if (add) { + ted->mouse_clicks[button][ted->nmouse_clicks[button]] = pos; + ted->mouse_click_times[button][ted->nmouse_clicks[button]] = times; + ++ted->nmouse_clicks[button]; + } } } } break; @@ -507,11 +564,6 @@ int main(int argc, char **argv) { } } - - u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT - | (u32)shift_down << KEY_MODIFIER_SHIFT_BIT - | (u32)alt_down << KEY_MODIFIER_ALT_BIT; - double frame_dt; { Uint32 time_this_frame = SDL_GetTicks(); diff --git a/tags.c b/tags.c index 5d3fca5..c7330b3 100644 --- a/tags.c +++ b/tags.c @@ -13,7 +13,7 @@ static int tag_try(FILE *fp, char const *tag) { long pos = ftell(fp); if (fgets(line, sizeof line, fp)) { fseek(fp, pos, SEEK_SET); - size_t len = strspn(line, "\t"); + size_t len = strcspn(line, "\t"); if (tag_len > len) len = tag_len; return strncmp(tag, line, len); @@ -22,14 +22,19 @@ static int tag_try(FILE *fp, char const *tag) { return -1; } +// returns true if the tag exists. bool tag_goto(Ted *ted, char const *tag) { change_directory(ted->cwd); Settings const *settings = &ted->settings; char const *tags_filename = settings->tags_filename; FILE *file = fopen(tags_filename, "rb"); + if (!file) { + ted_seterr(ted, "No tags file. Try running ctags."); + return false; + } fseek(file, 0, SEEK_END); size_t file_size = (size_t)ftell(file); - + // binary search for tag in file size_t lo = 0; size_t hi = file_size; bool success = false; diff --git a/ted.h b/ted.h index b713d3f..e9b8904 100644 --- a/ted.h +++ b/ted.h @@ -227,6 +227,7 @@ typedef struct Ted { Node *active_node; Settings settings; float window_width, window_height; + u32 key_modifier; // which of shift, alt, ctrl are down right now. v2 mouse_pos; u8 nmouse_clicks[4]; // nmouse_clicks[i] = length of mouse_clicks[i] v2 mouse_clicks[4][32]; // mouse_clicks[SDL_BUTTON_RIGHT], for example, is all the right mouse-clicks that have happened this frame -- cgit v1.2.3