summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-29 13:38:46 -0500
committerpommicket <pommicket@gmail.com>2022-12-29 13:38:46 -0500
commit6e6b407550db47d3f9c85875c0f69444cf640796 (patch)
tree433d70ad1857744cad830b141c9cabd1e7ddf7d6
parentf1e2e8382cc09bacb5da9e3c9463fea983a9e146 (diff)
hover highlight
-rw-r--r--buffer.c42
-rw-r--r--build.c4
-rw-r--r--colors.h2
-rw-r--r--find.c2
-rw-r--r--hover.c76
-rw-r--r--lsp-parse.c2
-rw-r--r--main.c2
-rw-r--r--ted.cfg1
-rw-r--r--ui.c2
9 files changed, 98 insertions, 35 deletions
diff --git a/buffer.c b/buffer.c
index 70483a8..4562219 100644
--- a/buffer.c
+++ b/buffer.c
@@ -233,12 +233,12 @@ char32_t buffer_char_after_cursor(TextBuffer *buffer) {
return buffer_char_after_pos(buffer, buffer->cursor_pos);
}
-BufferPos buffer_start_of_file(TextBuffer *buffer) {
+BufferPos buffer_pos_start_of_file(TextBuffer *buffer) {
(void)buffer;
return (BufferPos){.line = 0, .index = 0};
}
-BufferPos buffer_end_of_file(TextBuffer *buffer) {
+BufferPos buffer_pos_end_of_file(TextBuffer *buffer) {
return (BufferPos){.line = buffer->nlines - 1, .index = buffer->lines[buffer->nlines-1].len};
}
@@ -493,7 +493,7 @@ static BufferPos buffer_pos_advance(TextBuffer *buffer, BufferPos pos, size_t nc
index = 0;
++line;
}
- return buffer_end_of_file(buffer);
+ return buffer_pos_end_of_file(buffer);
}
@@ -947,6 +947,7 @@ void buffer_scroll(TextBuffer *buffer, double dx, double dy) {
// returns the position of the character at the given position in the buffer.
v2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos) {
+ buffer_pos_validate(buffer, &pos);
u32 line = pos.line, index = pos.index;
// we need to convert the index to a column
u32 col = buffer_index_to_column(buffer, line, index);
@@ -1105,7 +1106,7 @@ i64 buffer_pos_move_horizontally(TextBuffer *buffer, BufferPos *p, i64 by) {
} else if (by > 0) {
i64 by_start = by;
if (p->line >= buffer->nlines)
- *p = buffer_end_of_file(buffer); // invalid position; move to end of buffer
+ *p = buffer_pos_end_of_file(buffer); // invalid position; move to end of buffer
Line *line = &buffer->lines[p->line];
while (by > 0) {
if (by <= line->len - p->index) {
@@ -1386,11 +1387,11 @@ void buffer_cursor_move_to_end_of_line(TextBuffer *buffer) {
}
void buffer_cursor_move_to_start_of_file(TextBuffer *buffer) {
- buffer_cursor_move_to_pos(buffer, buffer_start_of_file(buffer));
+ buffer_cursor_move_to_pos(buffer, buffer_pos_start_of_file(buffer));
}
void buffer_cursor_move_to_end_of_file(TextBuffer *buffer) {
- buffer_cursor_move_to_pos(buffer, buffer_end_of_file(buffer));
+ buffer_cursor_move_to_pos(buffer, buffer_pos_end_of_file(buffer));
}
@@ -1454,9 +1455,22 @@ LSPDocumentPosition buffer_pos_to_lsp_document_position(TextBuffer *buffer, Buff
}
BufferPos buffer_pos_from_lsp(TextBuffer *buffer, LSPPosition lsp_pos) {
- BufferPos pos = {.line = lsp_pos.line};
- abort(); // @TODO
- return pos;
+ if (lsp_pos.line >= buffer->nlines) {
+ return buffer_pos_end_of_file(buffer);
+ }
+ const Line *line = &buffer->lines[lsp_pos.line];
+ const char32_t *str = line->str;
+ u32 character = 0;
+ for (u32 i = 0; i < line->len; ++i) {
+ if (character >= lsp_pos.character)
+ return (BufferPos){.line = lsp_pos.line, .index = i};
+ if (str[i] < 0x10000)
+ character += 1;
+ else
+ character += 2;
+ }
+
+ return buffer_pos_end_of_line(buffer, lsp_pos.line);
}
LSPPosition buffer_cursor_pos_as_lsp_position(TextBuffer *buffer) {
@@ -1680,11 +1694,11 @@ void buffer_select_to_end_of_line(TextBuffer *buffer) {
}
void buffer_select_to_start_of_file(TextBuffer *buffer) {
- buffer_select_to_pos(buffer, buffer_start_of_file(buffer));
+ buffer_select_to_pos(buffer, buffer_pos_start_of_file(buffer));
}
void buffer_select_to_end_of_file(TextBuffer *buffer) {
- buffer_select_to_pos(buffer, buffer_end_of_file(buffer));
+ buffer_select_to_pos(buffer, buffer_pos_end_of_file(buffer));
}
// select the word the cursor is inside of
@@ -1710,8 +1724,8 @@ void buffer_select_line(TextBuffer *buffer) {
}
void buffer_select_all(TextBuffer *buffer) {
- buffer_cursor_move_to_pos(buffer, buffer_start_of_file(buffer));
- buffer_select_to_pos(buffer, buffer_end_of_file(buffer));
+ buffer_cursor_move_to_pos(buffer, buffer_pos_start_of_file(buffer));
+ buffer_select_to_pos(buffer, buffer_pos_end_of_file(buffer));
}
// stop selecting
@@ -2372,7 +2386,7 @@ bool buffer_save(TextBuffer *buffer) {
// if the last line isn't empty, add a newline to the end of the file
char32_t c = '\n';
String32 s = {&c, 1};
- buffer_insert_text_at_pos(buffer, buffer_end_of_file(buffer), s);
+ buffer_insert_text_at_pos(buffer, buffer_pos_end_of_file(buffer), s);
}
}
diff --git a/build.c b/build.c
index 07d57eb..9c5ee7a 100644
--- a/build.c
+++ b/build.c
@@ -207,7 +207,7 @@ static void build_frame(Ted *ted, float x1, float y1, float x2, float y2) {
} else {
if (ret == 0) ret = 1;
// got a code point
- buffer_insert_char_at_pos(buffer, buffer_end_of_file(buffer), c);
+ buffer_insert_char_at_pos(buffer, buffer_pos_end_of_file(buffer), c);
p += ret;
}
}
@@ -216,7 +216,7 @@ static void build_frame(Ted *ted, float x1, float y1, float x2, float y2) {
if (any_text_inserted) {
// show bottom of output (only relevant if there are no build errors)
- buffer->cursor_pos = buffer_end_of_file(buffer);
+ buffer->cursor_pos = buffer_pos_end_of_file(buffer);
buffer_scroll_to_cursor(buffer);
}
diff --git a/colors.h b/colors.h
index 46d03fd..8bfdc03 100644
--- a/colors.h
+++ b/colors.h
@@ -35,6 +35,7 @@ typedef enum {
COLOR_HOVER_BG,
COLOR_HOVER_BORDER,
COLOR_HOVER_TEXT,
+ COLOR_HOVER_HL,
COLOR_YES,
COLOR_NO,
@@ -102,6 +103,7 @@ static ColorName const color_names[] = {
{COLOR_HOVER_BORDER, "hover-border"},
{COLOR_HOVER_BG, "hover-bg"},
{COLOR_HOVER_TEXT, "hover-text"},
+ {COLOR_HOVER_HL, "hover-hl"},
{COLOR_YES, "yes"},
{COLOR_NO, "no"},
{COLOR_CANCEL, "cancel"},
diff --git a/find.c b/find.c
index 5834c04..abdfc3e 100644
--- a/find.c
+++ b/find.c
@@ -136,7 +136,7 @@ void find_update(Ted *ted, bool force) {
find_free_pattern(ted);
if (find_compile_pattern(ted)) {
- BufferPos pos = buffer_start_of_file(buffer);
+ BufferPos pos = buffer_pos_start_of_file(buffer);
BufferPos best_scroll_candidate = {U32_MAX, U32_MAX};
BufferPos cursor_pos = buffer->cursor_pos;
// find all matches
diff --git a/hover.c b/hover.c
index 708e009..e9f8e36 100644
--- a/hover.c
+++ b/hover.c
@@ -24,6 +24,7 @@ static bool get_hover_position(Ted *ted, LSPDocumentPosition *pos, TextBuffer **
}
return false;
}
+
void hover_send_request(Ted *ted) {
Hover *hover = &ted->hover;
LSPRequest request = {.type = LSP_REQUEST_HOVER};
@@ -42,12 +43,23 @@ void hover_process_lsp_response(Ted *ted, LSPResponse *response) {
Hover *hover = &ted->hover;
LSPResponseHover *hover_response = &response->data.hover;
- free(hover->text);
TextBuffer *buffer=0;
- get_hover_position(ted, NULL, &buffer, NULL);
+ LSPDocumentPosition pos={0};
+ LSP *lsp=0;
+ get_hover_position(ted, &pos, &buffer, &lsp);
+
+ if (hover->text // we already have hover text
+ && (
+ lsp->id != hover->requested_lsp // this request is from a different LSP
+ || !lsp_document_position_eq(response->request.data.hover.position, pos) // this request is for a different position
+ )) {
+ // this is a stale request. ignore it
+ return;
+ }
+
+ free(hover->text); hover->text = NULL;
- hover->text = NULL;
if (buffer) {
hover->range_start = buffer_pos_from_lsp(buffer, hover_response->range.start);
hover->range_end = buffer_pos_from_lsp(buffer, hover_response->range.end);
@@ -106,23 +118,65 @@ void hover_frame(Ted *ted, double dt) {
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;
+ float x = ted->mouse_pos.x, y = ted->mouse_pos.y + font->char_height;
+ float char_height = font->char_height;
+ BufferPos range_start = hover->range_start, range_end = hover->range_end;
+ if (!buffer_pos_eq(range_start, range_end)) {
+ // draw the highlight
+ if (range_start.line == range_end.line) {
+ v2 a = buffer_pos_to_pixels(buffer, range_start);
+ v2 b = buffer_pos_to_pixels(buffer, range_end);
+ b.y += char_height;
+ gl_geometry_rect(rect_endpoints(a, b), colors[COLOR_HOVER_HL]);
+ } else if (range_end.line - range_start.line < 1000) { // prevent gigantic highlights from slowing things down
+ // multiple lines.
+ v2 a = buffer_pos_to_pixels(buffer, range_start);
+ v2 b = buffer_pos_to_pixels(buffer, buffer_pos_end_of_line(buffer, range_start.line));
+ b.y += char_height;
+ gl_geometry_rect(rect_endpoints(a, b), colors[COLOR_HOVER_HL]);
+
+ for (u32 line = range_start.line + 1; line < range_end.line; ++line) {
+ // these lines are fully contained in the range.
+ BufferPos start = buffer_pos_start_of_line(buffer, line);
+ BufferPos end = buffer_pos_end_of_line(buffer, line);
+ a = buffer_pos_to_pixels(buffer, start);
+ b = buffer_pos_to_pixels(buffer, end);
+ b.y += char_height;
+ gl_geometry_rect(rect_endpoints(a, b), colors[COLOR_HOVER_HL]);
+ }
+
+ // last line
+ a = buffer_pos_to_pixels(buffer, buffer_pos_start_of_line(buffer, range_end.line));
+ b = buffer_pos_to_pixels(buffer, range_end);
+ b.y += char_height;
+ gl_geometry_rect(rect_endpoints(a, b), colors[COLOR_HOVER_HL]);
+ }
+
+ }
if (hover->text) {
+ float max_width = 400;
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_x = x + max_width;
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;
+ float height = (float)(state.y_largest - y) + char_height;
if (height > 300) {
height = 300;
}
- state.x = x;
+
+ if (x + width > ted->window_width)
+ x -= width; // open left
+ if (y + height > ted->window_height)
+ y -= height + char_height * 2; // open up
+ state.x = state.min_x = x;
+ state.y = state.min_y = y;
+ state.max_x = x + max_width;
state.y = y;
state.render = true;
state.max_y = y + height;
@@ -133,14 +187,6 @@ void hover_frame(Ted *ted, double dt) {
rgba_u32_to_floats(colors[COLOR_HOVER_TEXT], state.color);
text_utf8_with_state(font, &state, text);
}
- if (!buffer_pos_eq(hover->range_start, hover->range_end)) {
- // draw the highlight
- v2 range_start = buffer_pos_to_pixels(buffer, hover->range_start);
- v2 range_end = buffer_pos_to_pixels(buffer, hover->range_end);
- range_end.y += font->char_height;
- Rect rect = rect_endpoints(range_start, range_end);
- gl_geometry_rect(rect, colors[COLOR_HOVER_BG]);//@TODO: HOVER_HL color
- }
gl_geometry_draw();
text_render(font);
diff --git a/lsp-parse.c b/lsp-parse.c
index c89a8c4..4b05f29 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -63,7 +63,7 @@ static bool parse_position(LSP *lsp, const JSON *json, JSONValue pos_value, LSPP
|| !lsp_expect_number(lsp, character, "document column number"))
return false;
pos->line = (u32)line.val.number;
- pos->character = (u32)line.val.number;
+ pos->character = (u32)character.val.number;
return true;
}
diff --git a/main.c b/main.c
index 2087c8e..9f0fef7 100644
--- a/main.c
+++ b/main.c
@@ -3,8 +3,8 @@
- more LSP stuff:
- go to definition using LSP
- find usages
+ - refactoring?
- test full unicode position handling
-- highlight hover range
- hover-enabled, hover-time settings
- check if there are any other non-optional/nice-to-have-support-for server-to-client requests
- better non-error window/showMessage(Request)
diff --git a/ted.cfg b/ted.cfg
index f954a48..42a0d14 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -307,6 +307,7 @@ autocomplete-hl = #f6a3
hover-bg = #000a
hover-border = #fffa
hover-text = #fff
+hover-hl = #ffc4
# these control the text color for various kinds of completions
autocomplete-variable = #bfb
autocomplete-function = #aaf
diff --git a/ui.c b/ui.c
index 583962e..94648f8 100644
--- a/ui.c
+++ b/ui.c
@@ -365,7 +365,7 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) {
*p = PATH_SEPARATOR;
if (file_selector_cd(ted, fs, dir_name)) {
- buffer_delete_chars_at_pos(line_buffer, buffer_start_of_file(line_buffer), last_path_sep + 1); // delete up to and including the last path separator
+ buffer_delete_chars_at_pos(line_buffer, buffer_pos_start_of_file(line_buffer), last_path_sep + 1); // delete up to and including the last path separator
buffer_clear_undo_redo(line_buffer);
} else {
// delete up to first path separator in line buffer