1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#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) {
Settings *settings = ted_active_settings(ted);
if (!settings->document_links) {
document_link_clear(ted);
return;
}
DocumentLinks *dl = &ted->document_links;
bool key_down = document_link_activation_key_down(ted);
if (!key_down) {
ted_cancel_lsp_request(ted, &dl->last_request);
document_link_clear(ted);
return;
}
TextBuffer *buffer = ted->active_buffer;
if (!buffer)
return;
LSP *lsp = buffer_lsp(buffer);
if (!lsp)
return;
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);
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) {
DocumentLinks *dl = &ted->document_links;
if (response->request.type != LSP_REQUEST_DOCUMENT_LINK
|| response->request.id != dl->last_request.id)
return;
if (!dl->last_request.id)
return; // request was cancelled
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) != 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) {
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;
}
|