summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-08-04 21:39:13 -0400
committerpommicket <pommicket@gmail.com>2023-08-04 21:42:53 -0400
commit49ab483be3e7af88a3932a43f222aa42cacd3515 (patch)
tree9ad0157a22ed6cd9c54458b6c75ffa7eaa2253e7
parentce199f9384f9f9376417110574a07cfd731e3a79 (diff)
document links seem to be working
-rw-r--r--buffer.c3
-rw-r--r--config.c1
-rw-r--r--gl.c2
-rw-r--r--ide-definitions.c16
-rw-r--r--ide-document-link.c102
-rw-r--r--main.c2
-rw-r--r--os-posix.c20
-rw-r--r--os-win.c5
-rw-r--r--os.h5
-rw-r--r--ted.cfg3
-rw-r--r--ted.h22
-rw-r--r--test/lsp/multidef.cpp2
12 files changed, 162 insertions, 21 deletions
diff --git a/buffer.c b/buffer.c
index 39bc1dd..379bda1 100644
--- a/buffer.c
+++ b/buffer.c
@@ -207,8 +207,7 @@ BufferPos buffer_pos_end_of_file(TextBuffer *buffer) {
return (BufferPos){.line = buffer->nlines - 1, .index = buffer->lines[buffer->nlines-1].len};
}
-// Get the font used for this buffer.
-static Font *buffer_font(TextBuffer *buffer) {
+Font *buffer_font(TextBuffer *buffer) {
return buffer->ted->font;
}
diff --git a/config.c b/config.c
index 3544273..4109fb7 100644
--- a/config.c
+++ b/config.c
@@ -91,6 +91,7 @@ static const SettingBool settings_bool[] = {
{"identifier-trigger-characters", &settings_zero.identifier_trigger_characters, true},
{"phantom-completions", &settings_zero.phantom_completions, true},
{"signature-help-enabled", &settings_zero.signature_help_enabled, true},
+ {"document-links", &settings_zero.document_links, true},
{"lsp-enabled", &settings_zero.lsp_enabled, true},
{"lsp-log", &settings_zero.lsp_log, true},
{"hover-enabled", &settings_zero.hover_enabled, true},
diff --git a/gl.c b/gl.c
index 4b41f42..c1ec812 100644
--- a/gl.c
+++ b/gl.c
@@ -230,6 +230,8 @@ void gl_geometry_init(void) {
}
void gl_geometry_rect(Rect r, u32 color_rgba) {
+ if (r.size.x <= 0 || r.size.y <= 0)
+ return;
vec4 color = rgba_u32_to_vec4(color_rgba);
vec2 p1 = r.pos;
diff --git a/ide-definitions.c b/ide-definitions.c
index 103d8c4..f5e37b6 100644
--- a/ide-definitions.c
+++ b/ide-definitions.c
@@ -176,7 +176,21 @@ void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *res
const LSPResponseDefinition *response_def = &response->data.definition;
if (!arr_len(response_def->locations)) {
- // no definition. do the error cursor.
+ // no definition.
+ const char* link = NULL;
+
+ // check for document links
+ TextBuffer *buffer = ted->active_buffer;
+ if (buffer) {
+ BufferPos pos = buffer_pos_from_lsp(buffer, response->request.data.definition.position.pos);
+ link = document_link_at_buffer_pos(ted, pos);
+ if (link) {
+ open_with_default_application(link);
+ return;
+ }
+ }
+
+ // do the error cursor.
ted_flash_error_cursor(ted);
return;
}
diff --git a/ide-document-link.c b/ide-document-link.c
index 9d4803f..2328a6b 100644
--- a/ide-document-link.c
+++ b/ide-document-link.c
@@ -1,11 +1,61 @@
#include "ted.h"
+void document_link_clear(Ted *ted) {
+ DocumentLinks *dl = &ted->document_links;
+ arr_foreach_ptr(dl->links, DocumentLink, l) {
+ free(l->target);
+ free(l->tooltip);
+ }
+ arr_clear(dl->links);
+ dl->requested_document = 0;
+}
+
+static bool document_link_activation_key_down(Ted *ted) {
+ return ted_is_ctrl_down(ted);
+}
+
+
+static Rect document_link_get_rect(Ted *ted, DocumentLink *link) {
+ TextBuffer *buffer = ted->active_buffer;
+ DocumentLinks *dl = &ted->document_links;
+ if (buffer_lsp_document_id(buffer) != dl->requested_document) {
+ return (Rect){0};
+ }
+
+ vec2 a = buffer_pos_to_pixels(buffer, link->start);
+ vec2 b = buffer_pos_to_pixels(buffer, link->end);
+ if (a.y != b.y) {
+ // multi-line link. let's ignore it because it'd be tough to deal with.
+ return (Rect){0};
+ }
+
+ if (a.x > b.x) {
+ // swap positions
+ vec2 temp = a;
+ a = b;
+ b = temp;
+ }
+
+ float y0 = a.y;
+ float char_height = text_font_char_height(buffer_font(buffer));
+ return (Rect) {
+ .pos = {a.x, y0},
+ .size = {b.x - a.x, char_height}
+ };
+}
+
void document_link_frame(Ted *ted) {
- DocumentLink *document_link = &ted->document_link;
+ Settings *settings = ted_active_settings(ted);
+ if (!settings->document_links) {
+ document_link_clear(ted);
+ return;
+ }
+ DocumentLinks *dl = &ted->document_links;
- bool key_down = ted_is_ctrl_down(ted);
+ bool key_down = document_link_activation_key_down(ted);
if (!key_down) {
- ted_cancel_lsp_request(ted, &document_link->last_request);
+ ted_cancel_lsp_request(ted, &dl->last_request);
+ document_link_clear(ted);
return;
}
@@ -17,38 +67,60 @@ void document_link_frame(Ted *ted) {
if (!lsp)
return;
- if (!document_link->last_request.id) {
+ if (!dl->last_request.id) {
// send the request
LSPRequest request = {.type = LSP_REQUEST_DOCUMENT_LINK};
LSPRequestDocumentLink *lnk = &request.data.document_link;
lnk->document = buffer_lsp_document_id(buffer);
- document_link->last_request = lsp_send_request(lsp, &request);
+ dl->last_request = lsp_send_request(lsp, &request);
+ dl->requested_document = lnk->document;
+ }
+
+ arr_foreach_ptr(dl->links, DocumentLink, l) {
+ Rect r = document_link_get_rect(ted, l);
+ if (rect_contains_point(r, ted->mouse_pos)) {
+ ted->cursor = ted->cursor_hand;
+ }
}
}
void document_link_process_lsp_response(Ted *ted, const LSPResponse *response) {
- DocumentLink *document_link = &ted->document_link;
+ DocumentLinks *dl = &ted->document_links;
if (response->request.type != LSP_REQUEST_DOCUMENT_LINK)
return;
- if (!document_link->last_request.id)
+ if (!dl->last_request.id)
return; // request was cancelled
- bool key_down = ted_is_ctrl_down(ted);
+ bool key_down = document_link_activation_key_down(ted);
if (!key_down)
return;
TextBuffer *buffer = ted->active_buffer;
if (!buffer)
return;
- if (buffer_lsp_document_id(buffer) != response->request.data.document_link.document)
+ if (buffer_lsp_document_id(buffer) != dl->requested_document)
return; // request was for a different document
const LSPResponseDocumentLink *response_data = &response->data.document_link;
arr_foreach_ptr(response_data->links, const LSPDocumentLink, link) {
- BufferPos start = buffer_pos_from_lsp(buffer, link->range.start);
- BufferPos end = buffer_pos_from_lsp(buffer, link->range.end);
- printf("%d:%d — %d:%d\t: %s\n",
- start.line, start.index, end.line, end.index,
- lsp_response_string(response, link->target));
-
+ DocumentLink *l = arr_addp(dl->links);
+ l->start = buffer_pos_from_lsp(buffer, link->range.start);
+ l->end = buffer_pos_from_lsp(buffer, link->range.end);
+ l->target = str_dup(lsp_response_string(response, link->target));
+ const char *tooltip = lsp_response_string(response, link->tooltip);
+ l->tooltip = *tooltip ? str_dup(tooltip) : NULL;
+ }
+}
+
+const char *document_link_at_buffer_pos(Ted *ted, BufferPos pos) {
+ DocumentLinks *dl = &ted->document_links;
+ TextBuffer *buffer = ted->active_buffer;
+ if (buffer_lsp_document_id(buffer) != dl->requested_document) {
+ return NULL;
+ }
+
+ arr_foreach_ptr(dl->links, DocumentLink, l) {
+ if (buffer_pos_cmp(pos, l->start) >= 0 && buffer_pos_cmp(pos, l->end) < 0)
+ return l->target;
}
+ return NULL;
}
diff --git a/main.c b/main.c
index 23e6071..2b7a051 100644
--- a/main.c
+++ b/main.c
@@ -5,7 +5,6 @@ TODO:
FUTURE FEATURES:
- autodetect indentation (tabs vs spaces)
- robust find (results shouldn't move around when you type things)
-- document links using LSP textDocument/documentLink request
- rename using LSP (textDocument/rename)
- we have request writing & response parsing support for it, but that hasn't been tested yet
- i'm putting this off for now since it seems hard to have undo support for it.
@@ -1196,6 +1195,7 @@ int main(int argc, char **argv) {
autocomplete_close(ted);
highlights_close(ted);
session_write(ted);
+ document_link_clear(ted);
for (int i = 0; i < TED_LSP_MAX; ++i) {
if (!ted->lsps[i]) break;
diff --git a/os-posix.c b/os-posix.c
index ca950b1..4485845 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -388,3 +388,23 @@ int process_check_status(Process **pproc, ProcessExitInfo *info) {
return -1;
}
}
+
+bool open_with_default_application(const char *path) {
+ const char *cmd = NULL;
+#if __linux__
+ cmd = "xdg-open";
+#elif __APPLE__
+ cmd = "open";
+#endif
+ if (!cmd)
+ return false;
+ switch (fork()) {
+ case 0:
+ execlp(cmd, cmd, path, NULL);
+ abort();
+ case -1:
+ return false;
+ default:
+ return true;
+ }
+}
diff --git a/os-win.c b/os-win.c
index 043d54f..7d335c7 100644
--- a/os-win.c
+++ b/os-win.c
@@ -411,3 +411,8 @@ int process_check_status(Process **pprocess, ProcessExitInfo *info) {
return -1;
}
}
+
+
+bool open_with_default_application(const char *path) {
+ todo
+}
diff --git a/os.h b/os.h
index 48d67c3..3542ffe 100644
--- a/os.h
+++ b/os.h
@@ -155,5 +155,10 @@ int process_check_status(Process **process, ProcessExitInfo *info);
/// `*process` will be set to NULL.
void process_kill(Process **process);
+/// runs xdg-open or equivalent on the given path, which can be a URL.
+///
+/// returns `true` on success.
+bool open_with_default_application(const char *path);
+
#endif // OS_H_
diff --git a/ted.cfg b/ted.cfg
index ae7c370..81cdd43 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -56,6 +56,9 @@ trigger-characters = on
identifier-trigger-characters = off
# display "phantom completions"? (if there is only one completion, display it next to the cursor)
phantom-completions = on
+# "document links" LSP functionality. if enabled, ctrl+clicking on web links
+# and such will open them.
+document-links = on
# enable LSP support (for autocompletion, etc.)
# you can also set `lsp = ""` but this is a quick way to disable LSP servers for all langauges
lsp-enabled = yes
diff --git a/ted.h b/ted.h
index 2a78e1f..c872697 100644
--- a/ted.h
+++ b/ted.h
@@ -272,6 +272,7 @@ typedef struct {
bool hover_enabled;
bool highlight_enabled;
bool highlight_auto;
+ bool document_links;
bool vsync;
bool save_backup;
bool crlf_windows;
@@ -665,10 +666,19 @@ typedef struct {
Signature signatures[SIGNATURE_HELP_MAX];
} SignatureHelp;
+typedef struct {
+ char *target;
+ char *tooltip;
+ BufferPos start;
+ BufferPos end;
+} DocumentLink;
+
/// "document link" information (LSP)
typedef struct {
+ LSPDocumentID requested_document;
LSPServerRequestID last_request;
-} DocumentLink;
+ DocumentLink *links;
+} DocumentLinks;
/// "hover" information from LSP server
typedef struct {
@@ -834,7 +844,7 @@ typedef struct Ted {
bool building;
Autocomplete autocomplete;
SignatureHelp signature_help;
- DocumentLink document_link;
+ DocumentLinks document_links;
Hover hover;
Definitions definitions;
Highlights highlights;
@@ -969,6 +979,8 @@ bool buffer_pos_valid(TextBuffer *buffer, BufferPos p);
Language buffer_language(TextBuffer *buffer);
/// clip the rectangle so it's all inside the buffer. returns true if there's any rectangle left.
bool buffer_clip_rect(TextBuffer *buffer, Rect *r);
+/// Get the font used for this buffer.
+Font *buffer_font(TextBuffer *buffer);
/// get LSP server which deals with this buffer
LSP *buffer_lsp(TextBuffer *buffer);
/// Get the settings used for this buffer.
@@ -1511,6 +1523,12 @@ void definitions_frame(Ted *ted);
// === ide-document-link.c ===
void document_link_frame(Ted *ted);
void document_link_process_lsp_response(Ted *ted, const LSPResponse *response);
+/// get document link at this position in the active buffer.
+///
+/// the returned pointer won't be freed immediately, but could be on the next frame,
+/// so don't keep it around long.
+const char *document_link_at_buffer_pos(Ted *ted, BufferPos pos);
+void document_link_clear(Ted *ted);
// === ide-highlights.c ===
void highlights_close(Ted *ted);
diff --git a/test/lsp/multidef.cpp b/test/lsp/multidef.cpp
index b9511d0..da612fc 100644
--- a/test/lsp/multidef.cpp
+++ b/test/lsp/multidef.cpp
@@ -1,3 +1,5 @@
+#include <stddef.h>
+
class V {
void f(int x, int y) {
}