summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-30 14:21:35 -0500
committerpommicket <pommicket@gmail.com>2022-12-30 14:21:35 -0500
commit91fc9b10e1700b482b13af1d25d95d80085a9b79 (patch)
tree8873099c6de0cefe8304f1d04c7be349e3e189ab
parent66367583a3b57e37e9198838222f45d99e77d8ae (diff)
go to definition
-rw-r--r--ide-definitions.c113
-rw-r--r--lsp.c2
-rw-r--r--main.c3
-rw-r--r--menu.c7
-rw-r--r--tags.c12
-rw-r--r--ted.c1
-rw-r--r--ted.h14
7 files changed, 110 insertions, 42 deletions
diff --git a/ide-definitions.c b/ide-definitions.c
index a9ff945..4dbe9d2 100644
--- a/ide-definitions.c
+++ b/ide-definitions.c
@@ -74,14 +74,48 @@ void definitions_frame(Ted *ted) {
}
static void definitions_clear_entries(Definitions *defs) {
- arr_foreach_ptr(defs->selector_all_entries, SelectorEntry, entry) {
- free((char*)entry->name);
+ arr_foreach_ptr(defs->selector_all_definitions, SymbolInfo, def) {
+ free(def->name);
}
- arr_clear(defs->selector_all_entries);
+ arr_clear(defs->selector_all_definitions);
arr_clear(defs->selector.entries);
defs->selector.n_entries = 0;
}
+static int definition_entry_qsort_cmp(const void *av, const void *bv) {
+ const SymbolInfo *a = av, *b = bv;
+ // first, sort by length
+ size_t a_len = strlen(a->name), b_len = strlen(b->name);
+ if (a_len < b_len) return -1;
+ if (a_len > b_len) return 1;
+ // then sort alphabetically
+ return strcmp(a->name, b->name);
+}
+
+// put the entries matching the search term into the selector.
+static void definitions_selector_filter_entries(Ted *ted) {
+ Definitions *defs = &ted->definitions;
+ Selector *sel = &defs->selector;
+
+ // create selector entries based on search term
+ char *search_term = str32_to_utf8_cstr(buffer_get_line(&ted->line_buffer, 0));
+
+ arr_clear(sel->entries);
+
+ arr_foreach_ptr(defs->selector_all_definitions, SymbolInfo, info) {
+ if (!search_term || stristr(info->name, search_term)) {
+ SelectorEntry *entry = arr_addp(sel->entries);
+ entry->name = info->name;
+ entry->color = info->color;
+ }
+ }
+ free(search_term);
+
+ arr_qsort(sel->entries, definition_entry_qsort_cmp);
+
+ sel->n_entries = arr_len(sel->entries);
+}
+
void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response) {
Definitions *defs = &ted->definitions;
@@ -117,16 +151,20 @@ void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *res
const u32 *colors = settings->colors;
definitions_clear_entries(defs);
- arr_set_len(defs->selector_all_entries, arr_len(symbols));
+ arr_set_len(defs->selector_all_definitions, arr_len(symbols));
for (size_t i = 0; i < arr_len(symbols); ++i) {
const LSPSymbolInformation *symbol = &symbols[i];
- SelectorEntry *entry = &defs->selector_all_entries[i];
+ SymbolInfo *def = &defs->selector_all_definitions[i];
- entry->name = str_dup(lsp_response_string(response, symbol->name));
+ def->name = str_dup(lsp_response_string(response, symbol->name));
SymbolKind kind = symbol_kind_to_ted(symbol->kind);
- entry->color = colors[color_for_symbol_kind(kind)];
+ def->color = colors[color_for_symbol_kind(kind)];
+ def->from_lsp = true;
+ def->position = lsp_location_start_position(symbol->location);
}
+ definitions_selector_filter_entries(ted);
+
} break;
default:
debug_println("?? bad request type in %s", __func__);
@@ -134,18 +172,33 @@ void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *res
}
}
+void definitions_send_request_if_needed(Ted *ted) {
+ LSP *lsp = buffer_lsp(ted->prev_active_buffer);
+ if (!lsp)
+ return;
+ Definitions *defs = &ted->definitions;
+ char *query = buffer_contents_utf8_alloc(&ted->line_buffer);
+ if (defs->last_request_query && strcmp(defs->last_request_query, query) == 0) {
+ free(query);
+ return; // no need to update symbols
+ }
+ LSPRequest request = {.type = LSP_REQUEST_WORKSPACE_SYMBOLS};
+ LSPRequestWorkspaceSymbols *syms = &request.data.workspace_symbols;
+ syms->query = str_dup(query);
+ defs->last_request_id = lsp_send_request(lsp, &request);
+ defs->last_request_time = ted->frame_time;
+ free(defs->last_request_query);
+ defs->last_request_query = query;
+}
+
void definitions_selector_open(Ted *ted) {
Definitions *defs = &ted->definitions;
definitions_clear_entries(defs);
LSP *lsp = buffer_lsp(ted->prev_active_buffer);
if (lsp) {
- LSPRequest request = {.type = LSP_REQUEST_WORKSPACE_SYMBOLS};
- LSPRequestWorkspaceSymbols *syms = &request.data.workspace_symbols;
- syms->query = str_dup("");
- defs->last_request_id = lsp_send_request(lsp, &request);
- defs->last_request_time = ted->frame_time;
+ definitions_send_request_if_needed(ted);
} else {
- defs->selector_all_entries = tags_get_entries(ted);
+ defs->selector_all_definitions = tags_get_symbols(ted);
}
ted_switch_to_buffer(ted, &ted->line_buffer);
buffer_select_all(ted->active_buffer);
@@ -158,27 +211,37 @@ void definitions_selector_close(Ted *ted) {
definitions_clear_entries(defs);
// @TODO : cancel
defs->last_request_id = 0;
+ free(defs->last_request_query);
+ defs->last_request_query = NULL;
}
-char *definitions_selector_update(Ted *ted) {
+void definitions_selector_update(Ted *ted) {
Definitions *defs = &ted->definitions;
Selector *sel = &defs->selector;
sel->enable_cursor = true;
- // create selector entries based on search term
- char *search_term = str32_to_utf8_cstr(buffer_get_line(&ted->line_buffer, 0));
-
- arr_clear(sel->entries);
+ definitions_selector_filter_entries(ted);
- arr_foreach_ptr(defs->selector_all_entries, SelectorEntry, entry) {
- if (!search_term || stristr(entry->name, search_term)) {
- arr_add(sel->entries, *entry);
+ // send new request if search term has changed.
+ // this is needed because e.g. clangd gives an incomplete list
+ definitions_send_request_if_needed(ted);
+
+ char *chosen = selector_update(ted, sel);
+ if (chosen) {
+ arr_foreach_ptr(defs->selector_all_definitions, SymbolInfo, info) {
+ if (strcmp(info->name, chosen) == 0) {
+ if (info->from_lsp) {
+ menu_close(ted);
+ ted_go_to_lsp_document_position(ted, NULL, info->position);
+ } else {
+ menu_close(ted);
+ tag_goto(ted, chosen);
+ }
+ }
}
+
+ free(chosen);
}
-
- sel->n_entries = arr_len(sel->entries);
-
- return selector_update(ted, sel);
}
void definitions_selector_render(Ted *ted, Rect bounds) {
diff --git a/lsp.c b/lsp.c
index 4b95179..c8de1a7 100644
--- a/lsp.c
+++ b/lsp.c
@@ -1,5 +1,5 @@
// print server-to-client communication
-#define LSP_SHOW_S2C 1
+#define LSP_SHOW_S2C 0
// print client-to-server communication
#define LSP_SHOW_C2S 0
diff --git a/main.c b/main.c
index 8048b3e..f010f91 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,7 @@
/*
@TODO:
+- show location in definitions menu
+- handle multiple symbols with same name
- cancelling requests e.g. in ide-definitions.c
- sort symbols by score (clangd extension?)
- more LSP stuff:
@@ -7,6 +9,7 @@
- find usages
- refactoring?
- ted_active_lsp should return something even when buffer isn't open
+- some way of opening + closing all C files in directory for clangd workspace/symbols to work
- test full unicode position handling
- check if there are any other non-optional/nice-to-have-support-for server-to-client requests
- better non-error window/showMessage(Request)
diff --git a/menu.c b/menu.c
index 139ae07..4c62768 100644
--- a/menu.c
+++ b/menu.c
@@ -238,12 +238,7 @@ static void menu_update(Ted *ted) {
}
break;
case MENU_GOTO_DEFINITION: {
- char *chosen_tag = definitions_selector_update(ted);
- if (chosen_tag) {
- menu_close(ted);
- tag_goto(ted, chosen_tag);
- free(chosen_tag);
- }
+ definitions_selector_update(ted);
} break;
case MENU_GOTO_LINE: {
char *contents = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0));
diff --git a/tags.c b/tags.c
index ebd5497..1d62f00 100644
--- a/tags.c
+++ b/tags.c
@@ -347,26 +347,26 @@ top:;
return success;
}
-SelectorEntry *tags_get_entries(Ted *ted) {
+SymbolInfo *tags_get_symbols(Ted *ted) {
// read tags file and extract tag names
char const *filename = tags_filename(ted, true);
if (!filename) return NULL;
FILE *file = fopen(filename, "rb");
if (!file) return NULL;
- SelectorEntry *entries = NULL;
+ SymbolInfo *infos = NULL;
u32 color = ted_color(ted, COLOR_TEXT);
if (file) {
char line[1024];
while (fgets(line, sizeof line, file)) {
if (line[0] != '!') { // tag metadata is formatted as tag names beginning with !
size_t len = strcspn(line, "\t");
- SelectorEntry *entry = arr_addp(entries);
- entry->name = strn_dup(line, len);
- entry->color = color;
+ SymbolInfo *info = arr_addp(infos);
+ info->name = strn_dup(line, len);
+ info->color = color;
}
}
fclose(file);
}
- return entries;
+ return infos;
}
diff --git a/ted.c b/ted.c
index 0bf0668..e98348d 100644
--- a/ted.c
+++ b/ted.c
@@ -535,6 +535,7 @@ void ted_go_to_position(Ted *ted, const char *path, u32 line, u32 index, bool is
}
void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition position) {
+ if (!lsp) lsp = ted_active_lsp(ted);
const char *path = lsp_document_path(lsp, position.document);
u32 line = position.pos.line;
u32 character = position.pos.character;
diff --git a/ted.h b/ted.h
index 393aee6..22a8362 100644
--- a/ted.h
+++ b/ted.h
@@ -414,6 +414,13 @@ typedef struct {
} Hover;
typedef struct {
+ char *name;
+ u32 color;
+ bool from_lsp;
+ LSPDocumentPosition position; // only set if from_lsp = true
+} SymbolInfo;
+
+typedef struct {
// ID of the last request which was sent out.
// used to process responses in chronological order (= ID order).
// if we got a response for the last request, or no requests have been made,
@@ -421,8 +428,9 @@ typedef struct {
LSPRequestID last_request_id;
struct timespec last_request_time;
+ char *last_request_query; // last query string which we sent a request for
Selector selector; // for "go to definition of..." menu
- SelectorEntry *selector_all_entries; // an array of all definitions
+ SymbolInfo *selector_all_definitions; // an array of all definitions
} Definitions;
@@ -583,8 +591,6 @@ void signature_help_retrigger(Ted *ted);
// alone isn't sufficient)
void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos);
void definitions_selector_open(Ted *ted);
-// returns tag selected (should be free'd), or NULL if none was.
-// if this is an LSP-based menu, this function will always return NULL.
-char *definitions_selector_update(Ted *ted);
+void definitions_selector_update(Ted *ted);
void definitions_selector_render(Ted *ted, Rect bounds);
void definitions_selector_close(Ted *ted);