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
128
129
130
131
132
133
134
|
#include "ted.h"
struct DocumentLink {
char *target;
char *tooltip;
BufferPos start;
BufferPos end;
};
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;
}
|