summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c2
-rw-r--r--find.c2
-rw-r--r--ide-definitions.c128
-rw-r--r--lsp-parse.c2
-rw-r--r--lsp-write.c3
-rw-r--r--lsp.c2
-rw-r--r--main.c73
-rw-r--r--menu.c8
-rw-r--r--tags.c66
-rw-r--r--ted.c2
-rw-r--r--ted.h21
11 files changed, 180 insertions, 129 deletions
diff --git a/buffer.c b/buffer.c
index 8079bf5..b4c85d5 100644
--- a/buffer.c
+++ b/buffer.c
@@ -312,6 +312,8 @@ static void buffer_send_lsp_did_open(TextBuffer *buffer, LSP *lsp, char *buffer_
}
LSP *buffer_lsp(TextBuffer *buffer) {
+ if (!buffer)
+ return NULL;
if (!buffer_is_named_file(buffer))
return NULL;
if (buffer->view_only)
diff --git a/find.c b/find.c
index abdfc3e..13d1a24 100644
--- a/find.c
+++ b/find.c
@@ -10,7 +10,7 @@ static u32 find_replace_flags(Ted *ted) {
}
// which buffer will be searched?
-static TextBuffer *find_search_buffer(Ted *ted) {
+TextBuffer *find_search_buffer(Ted *ted) {
if (ted->active_buffer && ted->active_buffer != &ted->find_buffer && ted->active_buffer != &ted->replace_buffer) {
return ted->active_buffer;
}
diff --git a/ide-definitions.c b/ide-definitions.c
index e63e977..a9ff945 100644
--- a/ide-definitions.c
+++ b/ide-definitions.c
@@ -51,6 +51,7 @@ void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition p
LSPRequest request = {.type = LSP_REQUEST_DEFINITION};
request.data.definition.position = position;
LSPRequestID id = lsp_send_request(lsp, &request);
+ // @TODO : cancel old request
defs->last_request_id = id;
defs->last_request_time = ted->frame_time;
} else {
@@ -64,38 +65,125 @@ void definition_cancel_lookup(Ted *ted) {
defs->last_request_id = 0;
}
+
+void definitions_frame(Ted *ted) {
+ Definitions *defs = &ted->definitions;
+ if (defs->last_request_id && timespec_sub(ted->frame_time, defs->last_request_time) > 0.2) {
+ ted->cursor = ted->cursor_wait;
+ }
+}
+
+static void definitions_clear_entries(Definitions *defs) {
+ arr_foreach_ptr(defs->selector_all_entries, SelectorEntry, entry) {
+ free((char*)entry->name);
+ }
+ arr_clear(defs->selector_all_entries);
+ arr_clear(defs->selector.entries);
+ defs->selector.n_entries = 0;
+}
+
+
void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response) {
- if (response->request.type != LSP_REQUEST_DEFINITION)
- return;
-
- const LSPResponseDefinition *response_def = &response->data.definition;
Definitions *defs = &ted->definitions;
-
if (response->request.id != defs->last_request_id) {
- // response to an old request
+ // response to an old/irrelevant request
return;
}
defs->last_request_id = 0;
- if (!arr_len(response_def->locations)) {
- // no definition. do the error cursor.
- ted_flash_error_cursor(ted);
- return;
+ switch (response->request.type) {
+ case LSP_REQUEST_DEFINITION: {
+ const LSPResponseDefinition *response_def = &response->data.definition;
+
+ if (!arr_len(response_def->locations)) {
+ // no definition. do the error cursor.
+ ted_flash_error_cursor(ted);
+ return;
+ }
+ LSPLocation location = response_def->locations[0];
+ const char *path = lsp_document_path(lsp, location.document);
+ if (!ted_open_file(ted, path)) {
+ ted_flash_error_cursor(ted);
+ return;
+ }
+ LSPDocumentPosition position = lsp_location_start_position(location);
+ ted_go_to_lsp_document_position(ted, lsp, position);
+ } break;
+ case LSP_REQUEST_WORKSPACE_SYMBOLS: {
+ const LSPResponseWorkspaceSymbols *response_syms = &response->data.workspace_symbols;
+ const LSPSymbolInformation *symbols = response_syms->symbols;
+ const Settings *settings = ted_active_settings(ted);
+ const u32 *colors = settings->colors;
+
+ definitions_clear_entries(defs);
+ arr_set_len(defs->selector_all_entries, 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];
+
+ entry->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)];
+ }
+
+ } break;
+ default:
+ debug_println("?? bad request type in %s", __func__);
+ break;
}
- LSPLocation location = response_def->locations[0];
- const char *path = lsp_document_path(lsp, location.document);
- if (!ted_open_file(ted, path)) {
- ted_flash_error_cursor(ted);
- return;
+}
+
+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;
+ } else {
+ defs->selector_all_entries = tags_get_entries(ted);
}
- LSPDocumentPosition position = lsp_location_start_position(location);
- ted_go_to_lsp_document_position(ted, lsp, position);
+ ted_switch_to_buffer(ted, &ted->line_buffer);
+ buffer_select_all(ted->active_buffer);
+ defs->selector.cursor = 0;
}
-void definitions_frame(Ted *ted) {
+
+void definitions_selector_close(Ted *ted) {
Definitions *defs = &ted->definitions;
- if (defs->last_request_id && timespec_sub(ted->frame_time, defs->last_request_time) > 0.2) {
- ted->cursor = ted->cursor_wait;
+ definitions_clear_entries(defs);
+ // @TODO : cancel
+ defs->last_request_id = 0;
+}
+
+char *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);
+
+ arr_foreach_ptr(defs->selector_all_entries, SelectorEntry, entry) {
+ if (!search_term || stristr(entry->name, search_term)) {
+ arr_add(sel->entries, *entry);
+ }
}
+
+ sel->n_entries = arr_len(sel->entries);
+
+ return selector_update(ted, sel);
+}
+
+void definitions_selector_render(Ted *ted, Rect bounds) {
+ Definitions *defs = &ted->definitions;
+ Selector *sel = &defs->selector;
+ sel->bounds = bounds;
+ selector_render(ted, sel);
}
diff --git a/lsp-parse.c b/lsp-parse.c
index c98ae85..f720d12 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -569,7 +569,7 @@ static bool parse_symbol_information(LSP *lsp, const JSON *json, JSONValue value
static bool parse_workspace_symbols(LSP *lsp, const JSON *json, LSPResponse *response) {
LSPResponseWorkspaceSymbols *syms = &response->data.workspace_symbols;
- JSONArray result = json_force_array(json_root(json));
+ JSONArray result = json_force_array(json_get(json, "result"));
arr_set_len(syms->symbols, result.len);
for (size_t i = 0; i < result.len; ++i) {
LSPSymbolInformation *info = &syms->symbols[i];
diff --git a/lsp-write.c b/lsp-write.c
index 58c5a8f..b8167b4 100644
--- a/lsp-write.c
+++ b/lsp-write.c
@@ -622,9 +622,6 @@ static void write_message(LSP *lsp, LSPMessage *message) {
write_response(lsp, &message->u.response);
break;
}
- // it's okay to free the message here since the request/response part has been zeroed.
- // (as i'm writing this, this won't do anything but it might in the future)
- lsp_message_free(message);
}
#undef write_bool
diff --git a/lsp.c b/lsp.c
index c8de1a7..4b95179 100644
--- a/lsp.c
+++ b/lsp.c
@@ -1,5 +1,5 @@
// print server-to-client communication
-#define LSP_SHOW_S2C 0
+#define LSP_SHOW_S2C 1
// print client-to-server communication
#define LSP_SHOW_C2S 0
diff --git a/main.c b/main.c
index 61b319d..8048b3e 100644
--- a/main.c
+++ b/main.c
@@ -1,10 +1,12 @@
/*
@TODO:
- cancelling requests e.g. in ide-definitions.c
+- sort symbols by score (clangd extension?)
- more LSP stuff:
- go to definition using LSP
- find usages
- refactoring?
+- ted_active_lsp should return something even when buffer isn't open
- 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)
@@ -14,6 +16,7 @@
- what to do if initialize request takes a long time?
- delete old sent requests? but make sure requests that just take a long time are okay.
(if the server never sends a response)
+- make tags_dir the root folder
- check that tags still works
- TESTING: make rust-analyzer-slow (waits 10s before sending response)
- run everything through valgrind ideally with leak checking
@@ -868,45 +871,43 @@ int main(int argc, char **argv) {
menu_update(ted);
}
- {
- LSP *lsp = ted_get_active_lsp(ted);
- if (lsp) {
- LSPMessage message = {0};
- while (lsp_next_message(lsp, &message)) {
- switch (message.type) {
- case LSP_REQUEST: {
- LSPRequest *r = &message.u.request;
- switch (r->type) {
- case LSP_REQUEST_SHOW_MESSAGE: {
- LSPRequestMessage *m = &r->data.message;
- // @TODO: multiple messages
- ted_seterr(ted, "%s", m->message);
- } break;
- case LSP_REQUEST_LOG_MESSAGE: {
- LSPRequestMessage *m = &r->data.message;
- // @TODO: actual logging
- printf("%s\n", m->message);
- } break;
- default: break;
- }
+ for (int i = 0; ted->lsps[i]; ++i) {
+ LSP *lsp = ted->lsps[i];
+ LSPMessage message = {0};
+ while (lsp_next_message(lsp, &message)) {
+ switch (message.type) {
+ case LSP_REQUEST: {
+ LSPRequest *r = &message.u.request;
+ switch (r->type) {
+ case LSP_REQUEST_SHOW_MESSAGE: {
+ LSPRequestMessage *m = &r->data.message;
+ // @TODO: multiple messages
+ ted_seterr(ted, "%s", m->message);
} break;
- case LSP_RESPONSE: {
- LSPResponse *r = &message.u.response;
- if (r->error) {
- // not displaying this right now
- // idk it might be spammy
- //ted_seterr(ted, "%s", r->error);
- }
- // it's important that we send error responses here too.
- // we don't want to be waiting around for a response that's never coming.
- autocomplete_process_lsp_response(ted, r);
- signature_help_process_lsp_response(ted, r);
- hover_process_lsp_response(ted, r);
- definitions_process_lsp_response(ted, lsp, r);
+ case LSP_REQUEST_LOG_MESSAGE: {
+ LSPRequestMessage *m = &r->data.message;
+ // @TODO: actual logging
+ printf("%s\n", m->message);
} break;
+ default: break;
+ }
+ } break;
+ case LSP_RESPONSE: {
+ LSPResponse *r = &message.u.response;
+ if (r->error) {
+ // not displaying this right now
+ // idk it might be spammy
+ //ted_seterr(ted, "%s", r->error);
}
- lsp_message_free(&message);
+ // it's important that we send error responses here too.
+ // we don't want to be waiting around for a response that's never coming.
+ autocomplete_process_lsp_response(ted, r);
+ signature_help_process_lsp_response(ted, r);
+ hover_process_lsp_response(ted, r);
+ definitions_process_lsp_response(ted, lsp, r);
+ } break;
}
+ lsp_message_free(&message);
}
}
@@ -1172,7 +1173,7 @@ int main(int argc, char **argv) {
SDL_DestroyWindow(window);
SDL_Quit();
if (log) fclose(log);
- tag_selector_close(ted);
+ definitions_selector_close(ted);
for (u16 i = 0; i < TED_MAX_BUFFERS; ++i)
if (ted->buffers_used[i])
buffer_free(&ted->buffers[i]);
diff --git a/menu.c b/menu.c
index 2e04d49..139ae07 100644
--- a/menu.c
+++ b/menu.c
@@ -23,7 +23,7 @@ static void menu_close_with_next(Ted *ted, Menu next) {
*ted->ask_reload = 0;
break;
case MENU_GOTO_DEFINITION:
- tag_selector_close(ted);
+ definitions_selector_close(ted);
break;
case MENU_GOTO_LINE:
buffer_clear(&ted->line_buffer);
@@ -77,7 +77,7 @@ void menu_open(Ted *ted, Menu menu) {
assert(*ted->ask_reload);
break;
case MENU_GOTO_DEFINITION:
- tag_selector_open(ted);
+ definitions_selector_open(ted);
break;
case MENU_GOTO_LINE:
ted_switch_to_buffer(ted, &ted->line_buffer);
@@ -238,7 +238,7 @@ static void menu_update(Ted *ted) {
}
break;
case MENU_GOTO_DEFINITION: {
- char *chosen_tag = tag_selector_update(ted);
+ char *chosen_tag = definitions_selector_update(ted);
if (chosen_tag) {
menu_close(ted);
tag_goto(ted, chosen_tag);
@@ -394,7 +394,7 @@ static void menu_render(Ted *ted) {
file_selector_render(ted, fs);
} break;
case MENU_GOTO_DEFINITION: {
- tag_selector_render(ted, rect4(x1, y1, x2, y2));
+ definitions_selector_render(ted, rect4(x1, y1, x2, y2));
} break;
case MENU_GOTO_LINE: {
float menu_height = char_height + 2 * padding;
diff --git a/tags.c b/tags.c
index 66ed36e..ebd5497 100644
--- a/tags.c
+++ b/tags.c
@@ -1,6 +1,6 @@
-static char const *tags_filename(Ted *ted, bool error_if_does_not_exist) {
+static const char *tags_filename(Ted *ted, bool error_if_does_not_exist) {
change_directory(ted->cwd);
- char const *filename = "tags";
+ const char *filename = "tags";
ted_path_full(ted, ".", ted->tags_dir, sizeof ted->tags_dir);
if (!fs_file_exists(filename)) {
filename = "../tags";
@@ -347,70 +347,26 @@ top:;
return success;
}
-static void tag_selector_open(Ted *ted) {
+SelectorEntry *tags_get_entries(Ted *ted) {
// read tags file and extract tag names
char const *filename = tags_filename(ted, true);
- if (!filename) return;
+ if (!filename) return NULL;
FILE *file = fopen(filename, "rb");
- if (!file) return;
+ if (!file) return NULL;
- arr_clear(ted->tag_selector_entries);
+ SelectorEntry *entries = 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");
- arr_add(ted->tag_selector_entries, strn_dup(line, len));
+ SelectorEntry *entry = arr_addp(entries);
+ entry->name = strn_dup(line, len);
+ entry->color = color;
}
}
- ted_switch_to_buffer(ted, &ted->line_buffer);
- buffer_select_all(ted->active_buffer);
-
- ted->tag_selector.cursor = 0;
-
fclose(file);
}
-}
-
-static void tag_selector_close(Ted *ted) {
- Selector *sel = &ted->tag_selector;
- arr_clear(sel->entries);
- sel->n_entries = 0;
- arr_foreach_ptr(ted->tag_selector_entries, char *, entry) {
- free(*entry);
- }
- arr_clear(ted->tag_selector_entries);
-}
-
-// returns tag selected (should be free'd), or NULL if none was.
-static char *tag_selector_update(Ted *ted) {
- Selector *sel = &ted->tag_selector;
- u32 color = ted_color(ted, COLOR_TEXT);
- 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);
-
- arr_foreach_ptr(ted->tag_selector_entries, char *, tagp) {
- char const *tag = *tagp;
- if (!search_term || stristr(tag, search_term)) {
- SelectorEntry entry = {
- .name = tag,
- .color = color
- };
- arr_add(sel->entries, entry);
- }
- }
-
- sel->n_entries = arr_len(sel->entries);
-
- return selector_update(ted, sel);
-}
-
-static void tag_selector_render(Ted *ted, Rect bounds) {
- Selector *sel = &ted->tag_selector;
- sel->bounds = bounds;
- selector_render(ted, sel);
+ return entries;
}
diff --git a/ted.c b/ted.c
index 4a89e8f..0bf0668 100644
--- a/ted.c
+++ b/ted.c
@@ -143,7 +143,7 @@ LSP *ted_get_lsp(Ted *ted, const char *path, Language language) {
return NULL;
}
-LSP *ted_get_active_lsp(Ted *ted) {
+LSP *ted_active_lsp(Ted *ted) {
if (!ted->active_buffer)
return NULL;
return buffer_lsp(ted->active_buffer);
diff --git a/ted.h b/ted.h
index 6f4174a..393aee6 100644
--- a/ted.h
+++ b/ted.h
@@ -420,11 +420,14 @@ typedef struct {
// last_request_id is set to 0.
LSPRequestID last_request_id;
struct timespec last_request_time;
+
+ Selector selector; // for "go to definition of..." menu
+ SelectorEntry *selector_all_entries; // an array of all definitions
} Definitions;
typedef struct Ted {
- struct LSP *lsps[TED_LSP_MAX + 1];
+ LSP *lsps[TED_LSP_MAX + 1];
// current time, as of the start of this frame
struct timespec frame_time;
@@ -453,7 +456,6 @@ typedef struct Ted {
int scroll_total_x, scroll_total_y; // total amount scrolled in the x and y direction this frame
Menu menu;
FileSelector file_selector;
- Selector tag_selector; // for "go to definition of..." menu
Selector command_selector;
TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus
TextBuffer find_buffer; // use for "find" term in find/find+replace
@@ -502,7 +504,6 @@ typedef struct Ted {
// if not NULL, points to the node whose split the user is currently resizing.
Node *resizing_split;
- char **tag_selector_entries; // an array of all tags (see tag_selector_open)
char **shell_history; // dynamic array of history of commands run with :shell (UTF-8)
u32 shell_history_pos; // for keeping track of where we are in the shell history.
@@ -549,10 +550,10 @@ void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer);
Settings *ted_active_settings(Ted *ted);
Settings *ted_get_settings(Ted *ted, const char *path, Language lang);
void ted_load_configs(Ted *ted, bool reloading);
-struct LSP *ted_get_lsp(Ted *ted, const char *path, Language lang);
-struct LSP *ted_active_lsp(Ted *ted);
-struct LSP *ted_get_lsp_by_id(Ted *ted, u32 id);
-static TextBuffer *find_search_buffer(Ted *ted);
+LSP *ted_get_lsp(Ted *ted, const char *path, Language lang);
+LSP *ted_active_lsp(Ted *ted);
+LSP *ted_get_lsp_by_id(Ted *ted, u32 id);
+TextBuffer *find_search_buffer(Ted *ted);
// first, we read all config files, then we parse them.
// this is because we want less specific settings (e.g. settings applied
// to all languages instead of one particular language) to be applied first,
@@ -581,3 +582,9 @@ void signature_help_retrigger(Ted *ted);
// Note: the document position is required for LSP requests because of overloading (where the name
// 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_render(Ted *ted, Rect bounds);
+void definitions_selector_close(Ted *ted);