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
|
// LSP hover information (textDocument/hover request)
void hover_close(Ted *ted) {
Hover *hover = &ted->hover;
hover->open = false;
free(hover->text);
hover->text = NULL;
}
static bool get_hover_position(Ted *ted, LSPDocumentPosition *pos, LSP **lsp) {
// find the buffer where the mouse is
for (int i = 0; i < TED_MAX_BUFFERS; ++i) {
TextBuffer *buffer = &ted->buffers[i];
if (!buffer->filename) continue;
LSP *l = buffer_lsp(buffer);
if (!l) continue;
BufferPos mouse_pos = {0};
if (buffer_pixels_to_pos(buffer, ted->mouse_pos, &mouse_pos)) {
*pos = buffer_pos_to_lsp_document_position(buffer, mouse_pos);
*lsp = l;
return true;
}
}
return false;
}
void hover_send_request(Ted *ted) {
Hover *hover = &ted->hover;
LSPRequest request = {.type = LSP_REQUEST_HOVER};
LSPRequestHover *h = &request.data.hover;
LSP *lsp = NULL;
if (get_hover_position(ted, &h->position, &lsp)) {
hover->requested_position = h->position;
hover->requested_lsp = lsp->id;
lsp_send_request(lsp, &request);
}
}
void hover_process_lsp_response(Ted *ted, LSPResponse *response) {
if (!response) return;
if (response->request.type != LSP_REQUEST_HOVER) return;
Hover *hover = &ted->hover;
LSPResponseHover *hover_response = &response->data.hover;
free(hover->text);
hover->text = NULL;
const char *contents = lsp_response_string(response, hover_response->contents);
if (*contents) {
hover->text = str_dup(contents);
char *p = hover->text + strlen(hover->text) - 1;
// remove trailing whitespace
// (rust-analyzer gives us trailing newlines for local variables)
for (; p > hover->text && isspace(*p); --p)
*p = '\0';
}
}
void hover_frame(Ted *ted, double dt) {
Hover *hover = &ted->hover;
bool shift_down = SDL_GetKeyboardState(NULL)[SDL_SCANCODE_LSHIFT]
|| SDL_GetKeyboardState(NULL)[SDL_SCANCODE_RSHIFT];
if (!shift_down) {
hover_close(ted);
}
(void)dt;
if (!hover->open) {
if (shift_down) {
hover_send_request(ted);
hover->open = true;
}
return;
}
{
LSPDocumentPosition pos={0};
LSP *lsp=0;
if (get_hover_position(ted, &pos, &lsp)) {
if (lsp->id != hover->requested_lsp
|| !lsp_document_position_eq(pos, hover->requested_position)) {
// refresh hover
hover_send_request(ted);
}
} else {
hover_close(ted);
return;
}
}
if (!hover->text)
return;
const Settings *settings = ted_active_settings(ted);
const float padding = settings->padding;
const float border = settings->border_thickness;
const u32 *colors = settings->colors;
const char *text = hover->text;
Font *font = ted->font;
float x = ted->mouse_pos.x, y = ted->mouse_pos.y;
TextRenderState state = text_render_state_default;
state.x = state.min_x = x;
state.y = state.min_y = y;
state.render = false;
state.wrap = true;
state.max_x = x + 400;
state.max_y = ted->window_height;
text_utf8_with_state(font, &state, text);
float width = (float)(state.x_largest - x);
float height = (float)(state.y_largest - y) + font->char_height;
if (height > 300) {
height = 300;
}
state.x = x;
state.y = y;
state.render = true;
state.max_y = y + height;
Rect rect = rect_xywh(x - padding, y - padding, width + 2*padding, height + 2*padding);
gl_geometry_rect(rect, colors[COLOR_HOVER_BG]);
gl_geometry_rect_border(rect, border, colors[COLOR_HOVER_BORDER]);
rgba_u32_to_floats(colors[COLOR_HOVER_TEXT], state.color);
text_utf8_with_state(font, &state, text);
gl_geometry_draw();
text_render(font);
}
|