summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-02-19 14:23:43 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-02-19 14:23:43 -0500
commit34fa190c3d490dd8cfec37d27bc03182f2a725a2 (patch)
tree8e9746d787247bf22d0841df091db3888009bc29
parent2151df75cb8646381d3c4bf95379c8f568dcd9eb (diff)
ctrl+click to go to definition
-rw-r--r--buffer.c54
-rw-r--r--main.c86
-rw-r--r--tags.c9
-rw-r--r--ted.h1
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