summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-09-07 15:18:45 -0400
committerpommicket <pommicket@gmail.com>2023-09-07 22:49:53 -0400
commit5cad1bee9b72610d9d97b5f97e7f1a245a2d2ba5 (patch)
tree5ee6f155f6900be4eeec07ad33417d2d9992a80f
parent815d652b570f53c989f62d0c7db847d7d6dfd940 (diff)
more diagnostics
-rw-r--r--buffer.c168
-rw-r--r--colors.c30
-rw-r--r--find.c4
-rw-r--r--ide-autocomplete.c4
-rw-r--r--ide-document-link.c2
-rw-r--r--ide-hover.c2
-rw-r--r--lsp-parse.c2
-rw-r--r--main.c8
-rw-r--r--node.c8
-rw-r--r--ted-internal.h3
-rw-r--r--ted.c31
-rw-r--r--ted.h23
-rw-r--r--ui.c4
13 files changed, 241 insertions, 48 deletions
diff --git a/buffer.c b/buffer.c
index 1d8effd..8d48c6d 100644
--- a/buffer.c
+++ b/buffer.c
@@ -28,6 +28,14 @@ struct BufferEdit {
double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
};
+typedef struct {
+ MessageType severity;
+ BufferPos pos;
+ char *message;
+ // may be NULL
+ char *url;
+} Diagnostic;
+
struct TextBuffer {
/// NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers)
char *path;
@@ -98,6 +106,8 @@ struct TextBuffer {
/// see \ref frame_earliest_line_modified.
u32 frame_latest_line_modified;
+ Diagnostic *diagnostics;
+
/// lines
Line *lines;
/// last error
@@ -974,6 +984,19 @@ static void buffer_line_free(Line *line) {
free(line->str);
}
+static void diagnostic_free(Diagnostic *diagnostic) {
+ free(diagnostic->message);
+ free(diagnostic->url);
+ memset(diagnostic, 0, sizeof *diagnostic);
+}
+
+static void buffer_diagnostics_clear(TextBuffer *buffer) {
+ arr_foreach_ptr(buffer->diagnostics, Diagnostic, d) {
+ diagnostic_free(d);
+ }
+ arr_clear(buffer->diagnostics);
+}
+
static void buffer_free_inner(TextBuffer *buffer) {
Ted *ted = buffer->ted;
if (!ted->quit) { // don't send didClose on quit (calling buffer_lsp would actually create a LSP if this is called after destroying all the LSPs which isnt good)
@@ -995,7 +1018,7 @@ static void buffer_free_inner(TextBuffer *buffer) {
buffer_edit_free(edit);
arr_foreach_ptr(buffer->redo_history, BufferEdit, edit)
buffer_edit_free(edit);
-
+ buffer_diagnostics_clear(buffer);
arr_free(buffer->undo_history);
arr_free(buffer->redo_history);
memset(buffer, 0, sizeof *buffer);
@@ -1386,6 +1409,24 @@ i64 buffer_pos_move_down(TextBuffer *buffer, BufferPos *pos, i64 by) {
return +buffer_pos_move_vertically(buffer, pos, +by);
}
+bool buffer_pos_move_according_to_edit(BufferPos *pos, const EditInfo *edit) {
+ if (buffer_pos_cmp(*pos, edit->pos) <= 0)
+ return true;
+ if (edit->chars_inserted) {
+ if (edit->pos.line == pos->line) {
+ pos->index += edit->end.index - edit->pos.index;
+ }
+ pos->line += edit->end.line - edit->pos.line;
+ } else {
+ if (buffer_pos_cmp(*pos, edit->end) < 0)
+ return false;
+ if (pos->line == edit->end.line)
+ pos->index += edit->pos.index - edit->end.index;
+ pos->line -= edit->end.line - edit->pos.line;
+ }
+ return true;
+}
+
static bool buffer_line_is_blank(Line *line) {
for (u32 i = 0; i < line->len; ++i)
if (!is32_space(line->str[i]))
@@ -1947,11 +1988,14 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
const EditInfo info = {
.pos = pos,
+ .end = b,
.chars_deleted = 0,
- .newlines_deleted = 0,
.chars_inserted = insertion_len,
- .newlines_inserted = n_added_lines,
};
+ // move diagnostics around as needed
+ arr_foreach_ptr(buffer->diagnostics, Diagnostic, d) {
+ buffer_pos_move_according_to_edit(&d->pos, &info);
+ }
signature_help_retrigger(buffer->ted);
arr_foreach_ptr(buffer->ted->edit_notifys, EditNotifyInfo, n) {
@@ -2424,8 +2468,8 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
u32 line_idx = pos.line;
u32 index = pos.index;
Line *line = &buffer->lines[line_idx], *lines_end = &buffer->lines[buffer->nlines];
- u32 newlines_deleted = 0;
-
+ const BufferPos end_pos = buffer_pos_advance(buffer, pos, nchars);
+
if (nchars + index > line->len) {
// delete rest of line
nchars -= line->len - index + 1; // +1 for the newline that got deleted
@@ -2440,7 +2484,6 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
// delete everything to the end of the file
for (u32 idx = line_idx + 1; idx < buffer->nlines; ++idx) {
buffer_line_free(&buffer->lines[idx]);
- ++newlines_deleted;
}
buffer_shorten(buffer, line_idx + 1);
} else {
@@ -2453,7 +2496,7 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
// remove all lines between line + 1 and last_line (inclusive).
buffer_delete_lines(buffer, line_idx + 1, (u32)(last_line - line));
- newlines_deleted = (u32)(last_line - line);
+ const u32 newlines_deleted = (u32)(last_line - line);
buffer_shorten(buffer, buffer->nlines - newlines_deleted);
}
} else {
@@ -2474,11 +2517,14 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
const EditInfo info = {
.pos = pos,
+ .end = end_pos,
.chars_inserted = 0,
- .newlines_inserted = 0,
.chars_deleted = deletion_len,
- .newlines_deleted = newlines_deleted,
};
+ // move diagnostics around as needed
+ arr_foreach_ptr(buffer->diagnostics, Diagnostic, d) {
+ buffer_pos_move_according_to_edit(&d->pos, &info);
+ }
arr_foreach_ptr(buffer->ted->edit_notifys, EditNotifyInfo, n) {
n->fn(n->context, buffer, &info);
}
@@ -3268,9 +3314,10 @@ void buffer_render(TextBuffer *buffer, Rect r) {
float render_start_y = y1 - (float)(buffer->scroll_y - start_line) * char_height; // where the 1st line is rendered
-
+ const Diagnostic *hover_diagnostic = NULL;
// line numbering
if (!buffer->is_line_buffer && settings->line_numbers) {
+ const Diagnostic *diagnostic = arr_len(buffer->diagnostics) ? buffer->diagnostics : NULL;
float max_digit_width = 0;
for (char32_t digit = '0'; digit <= '9'; ++digit) {
max_digit_width = maxf(max_digit_width, text_font_char_width(font, digit));
@@ -3285,23 +3332,56 @@ void buffer_render(TextBuffer *buffer, Rect r) {
text_state.max_y = y2;
float y = render_start_y;
- u32 cursor_line = buffer->cursor_pos.line;
+ const u32 cursor_line = buffer->cursor_pos.line;
+ const float diagnostic_x2 = x1 + line_number_width + 2;
for (u32 line = start_line; line < nlines; ++line) {
char str[32] = {0};
strbuf_printf(str, "%" PRIu32, line + 1); // convert line number to string
- float x = x1 + line_number_width - text_get_size_vec2(font, str).x; // right justify
+ const float x = x1 + line_number_width - text_get_size_vec2(font, str).x; // right justify
+ u32 line_number_color = settings_color(settings, line == cursor_line ? COLOR_CURSOR_LINE_NUMBER : COLOR_LINE_NUMBERS);
+ if (diagnostic) {
+ while (diagnostic->pos.line < line) {
+ ++diagnostic;
+ if (diagnostic == buffer->diagnostics + arr_len(buffer->diagnostics)) {
+ diagnostic = NULL;
+ break;
+ }
+ }
+ }
+ if (diagnostic && diagnostic->pos.line == line) {
+ // show diagnostic
+ ColorSetting color_setting=0;
+ ted_color_settings_for_message_type(diagnostic->severity, NULL, &color_setting);
+ u32 color = settings_color(settings, color_setting) | 0xff;
+ u32 alt_line_number_color = line == cursor_line ? 0xffffffff : 0x000000ff;
+ if (color_contrast_ratio_u32(color, line_number_color)
+ < color_contrast_ratio_u32(color, alt_line_number_color)) {
+ // change color so that line number is still visible
+ line_number_color = alt_line_number_color;
+ }
+ const Rect rect = rect4(x1, y, diagnostic_x2, y + char_height);
+ gl_geometry_rect(
+ rect,
+ color & 0xffffff7f
+ );
+ if (ted_mouse_in_rect(ted, rect)) {
+ hover_diagnostic = diagnostic;
+ if (diagnostic->url && ted_clicked_in_rect(ted, rect))
+ open_with_default_application(diagnostic->url);
+ ted->cursor = ted->cursor_hand;
+ }
+ }
// set color
- settings_color_floats(settings, line == cursor_line ? COLOR_CURSOR_LINE_NUMBER : COLOR_LINE_NUMBERS,
- text_state.color);
+ rgba_u32_to_floats(line_number_color, text_state.color);
text_state.x = x; text_state.y = y;
text_state_break_kerning(&text_state);
text_utf8_with_state(font, &text_state, str);
y += char_height;
+
if (y > y2) break;
}
- x1 += line_number_width;
- x1 += 2; // a little bit of padding
+ x1 = diagnostic_x2;
// line separating line numbers from text
gl_geometry_rect(rect_xywh(x1, y1, border_thickness, y2 - y1), settings_color(settings, COLOR_LINE_NUMBERS_SEPARATOR));
x1 += border_thickness;
@@ -3321,7 +3401,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
}
// change cursor to ibeam when it's hovering over the buffer
- if ((!menu_is_any_open(ted) || buffer == ted->line_buffer) && rect_contains_point(rect4(x1, y1, x2, y2), ted->mouse_pos)) {
+ if ((!menu_is_any_open(ted) || buffer == ted->line_buffer) && ted_mouse_in_rect(ted, rect4(x1, y1, x2, y2))) {
ted->cursor = ted->cursor_ibeam;
}
@@ -3331,7 +3411,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
buffer->center_cursor_next_frame = false;
}
- if (rect_contains_point(rect4(x1, y1, x2, y2), ted->mouse_pos) && !menu_is_any_open(ted)) {
+ if (ted_mouse_in_rect(ted, rect4(x1, y1, x2, y2)) && !menu_is_any_open(ted)) {
// scroll with mouse wheel
double scroll_speed = 2.5;
buffer_scroll(buffer, ted->scroll_total_x * scroll_speed, ted->scroll_total_y * scroll_speed);
@@ -3521,6 +3601,8 @@ void buffer_render(TextBuffer *buffer, Rect r) {
}
gl_geometry_draw();
}
+
+ //TODO(hover_diagnostic);
}
@@ -3745,3 +3827,53 @@ void buffer_highlight_lsp_range(TextBuffer *buffer, LSPRange range, ColorSetting
gl_geometry_rect(r2, settings_color(settings, COLOR_HOVER_HL));
}
}
+
+static MessageType diagnostic_severity(const LSPDiagnostic *diagnostic) {
+ switch (diagnostic->severity) {
+ case LSP_DIAGNOSTIC_SEVERITY_ERROR:
+ return MESSAGE_ERROR;
+ case LSP_DIAGNOSTIC_SEVERITY_WARNING:
+ return MESSAGE_WARNING;
+ case LSP_DIAGNOSTIC_SEVERITY_INFORMATION:
+ case LSP_DIAGNOSTIC_SEVERITY_HINT:
+ return MESSAGE_INFO;
+ }
+ assert(0);
+ return MESSAGE_INFO;
+}
+
+static int diagnostic_cmp(const void *av, const void *bv) {
+ const Diagnostic *a = av, *b = bv;
+ // first sort by line
+ if (a->pos.line < b->pos.line) return -1;
+ if (a->pos.line > b->pos.line) return 1;
+
+ // then put higher severity diagnostics first
+ if (a->severity < b->severity) return 1;
+ if (a->severity > b->severity) return -1;
+
+ return 0;
+}
+
+void buffer_publish_diagnostics(TextBuffer *buffer, const LSPRequest *request, LSPDiagnostic *diagnostics) {
+ buffer_diagnostics_clear(buffer);
+ arr_foreach_ptr(diagnostics, const LSPDiagnostic, diagnostic) {
+ Diagnostic *d = arr_addp(buffer->diagnostics);
+ d->pos = buffer_pos_from_lsp(buffer, diagnostic->range.start);
+ d->severity = diagnostic_severity(diagnostic);
+ char message[280];
+ const char *code = lsp_request_string(request, diagnostic->code);
+ if (*code) {
+ str_printf(message, sizeof message - 4, "[%s] %s", code,
+ lsp_request_string(request, diagnostic->message));
+ } else {
+ str_cpy(message, sizeof message - 4,
+ lsp_request_string(request, diagnostic->message));
+ }
+ strcpy(&message[sizeof message - 4], "...");
+ d->message = str_dup(message);
+ const char *url = lsp_request_string(request, diagnostic->code_description_uri);
+ d->url = *url ? str_dup(url) : NULL;
+ }
+ arr_qsort(buffer->diagnostics, diagnostic_cmp);
+}
diff --git a/colors.c b/colors.c
index 3e704e9..d9ef7aa 100644
--- a/colors.c
+++ b/colors.c
@@ -169,3 +169,33 @@ u32 color_apply_opacity(u32 color, float opacity) {
opacity = clampf(opacity, 0.0f, 1.0f);
return (color & 0xffffff00) | (u32)((color & 0xff) * opacity);
}
+
+
+static float color_relative_luminance(const float rgb[3]) {
+ // see https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ float c[3];
+ for (int i = 0; i < 3; ++i) {
+ const float x = rgb[i];
+ c[i] = x <= 0.03928f ? x * (1.0f / 12.92f) : powf((x + 0.055f) * (1.0f / 1.055f), 2.4f);
+ }
+ return 0.2126f * c[0] + 0.7152f * c[1] + 0.0722f * c[2];
+}
+
+float color_contrast_ratio(const float rgb1[3], const float rgb2[3]) {
+ // see https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
+ float l1 = color_relative_luminance(rgb1);
+ float l2 = color_relative_luminance(rgb2);
+ if (l1 < l2) {
+ float temp = l1;
+ l1 = l2;
+ l2 = temp;
+ }
+ return (l1 + 0.05f) / (l2 + 0.05f);
+}
+
+float color_contrast_ratio_u32(u32 color1, u32 color2) {
+ float rgb1[4], rgb2[4];
+ rgba_u32_to_floats(color1, rgb1);
+ rgba_u32_to_floats(color2, rgb2);
+ return color_contrast_ratio(rgb1, rgb2);
+}
diff --git a/find.c b/find.c
index f5fd9ce..b5fee08 100644
--- a/find.c
+++ b/find.c
@@ -538,7 +538,7 @@ static void find_edit_notify(void *context, TextBuffer *buffer, const EditInfo *
const u32 line = info->pos.line;
if (info->chars_inserted) {
- const u32 newlines_inserted = info->newlines_inserted;
+ const u32 newlines_inserted = info->end.line - info->pos.line;
if (newlines_inserted) {
// update line numbers for find results after insertion.
@@ -553,7 +553,7 @@ static void find_edit_notify(void *context, TextBuffer *buffer, const EditInfo *
find_research_lines(ted, line, line + newlines_inserted);
} else if (info->chars_deleted) {
- const u32 newlines_deleted = info->newlines_deleted;
+ const u32 newlines_deleted = info->end.line - info->pos.line;
if (newlines_deleted) {
// update line numbers for find results after deletion.
diff --git a/ide-autocomplete.c b/ide-autocomplete.c
index 6f67506..295dcda 100644
--- a/ide-autocomplete.c
+++ b/ide-autocomplete.c
@@ -616,7 +616,7 @@ void autocomplete_frame(Ted *ted) {
ac->rect = menu_rect;
}
- i32 mouse_entry = scroll + (i32)((ted->mouse_pos.y - start_y) / char_height);
+ i32 mouse_entry = scroll + (i32)((ted_mouse_pos(ted).y - start_y) / char_height);
Autocompletion *document = NULL;
if (ncompletions) {
@@ -629,7 +629,7 @@ void autocomplete_frame(Ted *ted) {
}
}
if (mouse_entry >= 0 && mouse_entry < (i32)ncompletions
- && rect_contains_point(ac->rect, ted->mouse_pos)) {
+ && ted_mouse_in_rect(ted, ac->rect)) {
// highlight moused over entry
Rect r = rect_xywh(x, start_y + (float)(mouse_entry - scroll) * char_height, menu_width, char_height);
gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]);
diff --git a/ide-document-link.c b/ide-document-link.c
index 2d43807..71307b5 100644
--- a/ide-document-link.c
+++ b/ide-document-link.c
@@ -101,7 +101,7 @@ void document_link_frame(Ted *ted) {
arr_foreach_ptr(dl->links, DocumentLink, l) {
Rect r = document_link_get_rect(ted, l);
- if (rect_contains_point(r, ted->mouse_pos)) {
+ if (ted_mouse_in_rect(ted, r)) {
ted->cursor = ted->cursor_hand;
}
}
diff --git a/ide-hover.c b/ide-hover.c
index ae870c3..59498f7 100644
--- a/ide-hover.c
+++ b/ide-hover.c
@@ -159,7 +159,7 @@ void hover_frame(Ted *ted, double dt) {
const char *text = hover->text;
Font *font = ted->font;
float char_height = text_font_char_height(font);
- float x = ted->mouse_pos.x, y = ted->mouse_pos.y + char_height;
+ float x = ted_mouse_pos(ted).x, y = ted_mouse_pos(ted).y + char_height;
buffer_highlight_lsp_range(buffer, hover->range, COLOR_HOVER_HL);
diff --git a/lsp-parse.c b/lsp-parse.c
index 5337de5..df87a13 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -714,7 +714,7 @@ static bool parse_diagnostic(LSP *lsp, LSPRequest *request, const JSON *json, JS
return false;
diagnostic_out->message = lsp_request_add_json_string(
request, json,
- json_object_get_string(json, diagnostic_in, "request")
+ json_object_get_string(json, diagnostic_in, "message")
);
JSONValue severity_val = json_object_get(json, diagnostic_in, "severity");
LSPDiagnosticSeverity severity = LSP_DIAGNOSTIC_SEVERITY_INFORMATION;
diff --git a/main.c b/main.c
index 12324ce..dbfb6a1 100644
--- a/main.c
+++ b/main.c
@@ -641,7 +641,7 @@ int main(int argc, char **argv) {
} else if (key_modifier == 0) {
// scroll with mouse wheel
Sint32 dx = event.wheel.x, dy = -event.wheel.y;
- if (autocomplete_box_contains_point(ted, ted->mouse_pos)) {
+ if (autocomplete_box_contains_point(ted, ted_mouse_pos(ted))) {
autocomplete_scroll(ted, dy);
} else {
ted->scroll_total_x += dx;
@@ -886,7 +886,7 @@ int main(int argc, char **argv) {
ted_log(ted, "%s\n", lsp_request_string(r, m->message));
} break;
case LSP_REQUEST_PUBLISH_DIAGNOSTICS: {
- ted_process_publish_diagnostics(ted, r);
+ ted_process_publish_diagnostics(ted, lsp, r);
} break;
default: break;
}
@@ -984,7 +984,7 @@ int main(int argc, char **argv) {
if (ted->resizing_build_output) {
if (ted->mouse_state & SDL_BUTTON_LMASK) {
// resize it
- ted->build_output_height = clampf((y2 - ted->mouse_pos.y) / ted->window_height, 0.05f, 0.8f);
+ ted->build_output_height = clampf((y2 - ted_mouse_pos(ted).y) / ted->window_height, 0.05f, 0.8f);
} else {
// stop resizing build output
ted->resizing_build_output = false;
@@ -996,7 +996,7 @@ int main(int argc, char **argv) {
// start resizing build output
ted->resizing_build_output = true;
}
- if (rect_contains_point(gap, ted->mouse_pos)) {
+ if (ted_mouse_in_rect(ted, gap)) {
ted->cursor = ted->cursor_resize_v;
}
}
diff --git a/node.c b/node.c
index ee99883..aaa730f 100644
--- a/node.c
+++ b/node.c
@@ -383,7 +383,8 @@ void node_frame(Ted *ted, Node *node, Rect r) {
if (node == ted->dragging_tab_node && i == ted->dragging_tab_idx) {
// make tab follow mouse
- tab_rect.pos = vec2_add(tab_rect.pos, vec2_sub(ted->mouse_pos, ted->dragging_tab_origin));
+ tab_rect.pos = vec2_add(tab_rect.pos,
+ vec2_sub(ted_mouse_pos(ted), ted->dragging_tab_origin));
}
// tab border
@@ -447,7 +448,8 @@ void node_frame(Ted *ted, Node *node, Rect r) {
ted->resizing_split = NULL;
} else {
// resize the split
- float mouse_coord = node->split_vertical ? ted->mouse_pos.y : ted->mouse_pos.x;
+ const vec2 mouse_pos = ted_mouse_pos(ted);
+ float mouse_coord = node->split_vertical ? mouse_pos.y : mouse_pos.x;
float rect_coord1 = (node->split_vertical ? rect_y1 : rect_x1)(r);
float rect_coord2 = (node->split_vertical ? rect_y2 : rect_x2)(r);
// make sure the split doesn't make one of the sides too small
@@ -469,7 +471,7 @@ void node_frame(Ted *ted, Node *node, Rect r) {
r2.size.x = r.size.x - split_pos - padding;
r_between = rect_xywh(r.pos.x + split_pos - padding, r.pos.y, 2 * padding, r.size.y);
}
- if (rect_contains_point(r_between, ted->mouse_pos)) {
+ if (ted_mouse_in_rect(ted, r_between)) {
ted->cursor = resize_cursor;
}
if (ted_clicked_in_rect(ted, r_between))
diff --git a/ted-internal.h b/ted-internal.h
index 49ca912..e5b9874 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -464,6 +464,7 @@ bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times);
void buffer_center_cursor_next_frame(TextBuffer *buffer);
/// perform a series of checks to make sure the buffer doesn't have any invalid values
void buffer_check_valid(TextBuffer *buffer);
+void buffer_publish_diagnostics(TextBuffer *buffer, const LSPRequest *request, LSPDiagnostic *diagnostics);
// === build.c ===
void build_frame(Ted *ted, float x1, float y1, float x2, float y2);
@@ -712,6 +713,6 @@ void ted_load_fonts(Ted *ted);
/// Free all of ted's fonts.
void ted_free_fonts(Ted *ted);
/// process textDocument/publishDiagnostics request
-void ted_process_publish_diagnostics(Ted *ted, LSPRequest *request);
+void ted_process_publish_diagnostics(Ted *ted, LSP *lsp, LSPRequest *request);
#endif // TED_INTERNAL_H_
diff --git a/ted.c b/ted.c
index 7ce2e87..ec04e0b 100644
--- a/ted.c
+++ b/ted.c
@@ -745,7 +745,7 @@ bool ted_get_mouse_buffer_pos(Ted *ted, TextBuffer **pbuffer, BufferPos *ppos) {
arr_foreach_ptr(ted->buffers, TextBufferPtr, pbuf) {
TextBuffer *buffer = *pbuf;
BufferPos pos = {0};
- if (buffer_pixels_to_pos(buffer, ted->mouse_pos, &pos)) {
+ if (buffer_pixels_to_pos(buffer, ted_mouse_pos(ted), &pos)) {
if (ppos) *ppos = pos;
if (pbuffer) *pbuffer = buffer;
return true;
@@ -826,16 +826,16 @@ MessageType ted_message_type_from_lsp(LSPWindowMessageType type) {
void ted_color_settings_for_message_type(MessageType type, ColorSetting *bg_color, ColorSetting *border_color) {
switch (type) {
case MESSAGE_ERROR:
- *bg_color = COLOR_ERROR_BG;
- *border_color = COLOR_ERROR_BORDER;
+ if (bg_color) *bg_color = COLOR_ERROR_BG;
+ if (border_color) *border_color = COLOR_ERROR_BORDER;
break;
case MESSAGE_WARNING:
- *bg_color = COLOR_WARNING_BG;
- *border_color = COLOR_WARNING_BORDER;
+ if (bg_color) *bg_color = COLOR_WARNING_BG;
+ if (border_color) *border_color = COLOR_WARNING_BORDER;
break;
case MESSAGE_INFO:
- *bg_color = COLOR_INFO_BG;
- *border_color = COLOR_INFO_BORDER;
+ if (bg_color) *bg_color = COLOR_INFO_BG;
+ if (border_color) *border_color = COLOR_INFO_BORDER;
break;
}
}
@@ -876,8 +876,21 @@ bool ted_close_buffer_with_file(Ted *ted, const char *path) {
return true;
}
-void ted_process_publish_diagnostics(Ted *ted, LSPRequest *request) {
+void ted_process_publish_diagnostics(Ted *ted, LSP *lsp, LSPRequest *request) {
assert(request->type == LSP_REQUEST_PUBLISH_DIAGNOSTICS);
LSPRequestPublishDiagnostics *pub = &request->data.publish_diagnostics;
- printf("%u diagnostics\n",arr_len(pub->diagnostics));
+ const char *path = lsp_document_path(lsp, pub->document);
+ TextBuffer *buffer = ted_get_buffer_with_file(ted, path);
+ if (buffer) {
+ buffer_publish_diagnostics(buffer, request, pub->diagnostics);
+ }
+}
+
+
+vec2 ted_mouse_pos(Ted *ted) {
+ return ted->mouse_pos;
+}
+
+bool ted_mouse_in_rect(Ted *ted, Rect r) {
+ return rect_contains_point(r, ted->mouse_pos);
}
diff --git a/ted.h b/ted.h
index d35fd74..8de7fc4 100644
--- a/ted.h
+++ b/ted.h
@@ -314,6 +314,11 @@ typedef struct {
typedef struct {
/// position where the edit took place
BufferPos pos;
+ /// "end" position
+ ///
+ /// for insertions, this is the position of one past the last character inserted,
+ /// for deletions, this is the position of the end of the deletion prior to applying the edit
+ BufferPos end;
/// number of characters (unicode codepoints, including newlines) deleted
///
/// if this is non-zero, \ref chars_inserted will be zero.
@@ -322,10 +327,6 @@ typedef struct {
///
/// if this is non-zero, \ref chars_deleted will be zero.
u32 chars_inserted;
- /// number of newlines deleted
- u32 newlines_deleted;
- /// number of newlines inserted
- u32 newlines_inserted;
} EditInfo;
/// this type of callback is called right after an edit is made to the buffer.
@@ -423,6 +424,10 @@ char32_t buffer_pos_move_to_matching_bracket(TextBuffer *buffer, BufferPos *pos)
///
/// \returns `true` if cursor was to the right of a bracket.
bool buffer_cursor_move_to_matching_bracket(TextBuffer *buffer);
+/// move `*pos` so that it stays in the same place after `edit` is applied.
+///
+/// if `pos` was deleted by `edit`, returns `false`.
+bool buffer_pos_move_according_to_edit(BufferPos *pos, const EditInfo *edit);
/// ensures that `p` refers to a valid position, moving it if needed.
void buffer_pos_validate(TextBuffer *buffer, BufferPos *p);
/// is this a valid buffer position?
@@ -796,6 +801,12 @@ Status color_from_str(const char *str, u32 *color);
u32 color_blend(u32 bg, u32 fg);
/// multiply color's alpha value by `opacity`.
u32 color_apply_opacity(u32 color, float opacity);
+/// get WCAG contrast ratio between colors
+float color_contrast_ratio(const float rgb1[3], const float rgb2[3]);
+/// get WCAG contrast ratio between colors.
+///
+/// the "alpha" components (i.e. lowest 8 bits) of `color1`, `color2` are ignored
+float color_contrast_ratio_u32(u32 color1, u32 color2);
// === command.c ===
/// parse command
@@ -1138,6 +1149,10 @@ void ted_close_buffer(Ted *ted, TextBuffer *buffer);
bool ted_close_buffer_with_file(Ted *ted, const char *path);
/// save all buffers
bool ted_save_all(Ted *ted);
+/// get mouse position
+vec2 ted_mouse_pos(Ted *ted);
+/// test whether mouse is in rect
+bool ted_mouse_in_rect(Ted *ted, Rect r);
/// reload all buffers from their files
void ted_reload_all(Ted *ted);
/// Change ted's font size.
diff --git a/ui.c b/ui.c
index f359241..3dd7875 100644
--- a/ui.c
+++ b/ui.c
@@ -324,7 +324,7 @@ void selector_render(Ted *ted, Selector *s) {
float x = r_unclipped.pos.x, y = r_unclipped.pos.y;
text_state.x = x; text_state.y = y;
- if (rect_contains_point(r_clipped, ted->mouse_pos) || (s->enable_cursor && s->cursor == i)) {
+ if (ted_mouse_in_rect(ted, r_clipped) || (s->enable_cursor && s->cursor == i)) {
// highlight it
gl_geometry_rect(r_clipped, settings_color(settings, COLOR_MENU_HL));
}
@@ -661,7 +661,7 @@ vec2 button_get_size(Ted *ted, const char *text) {
}
void button_render(Ted *ted, Rect button, const char *text, u32 color) {
- if (rect_contains_point(button, ted->mouse_pos)) {
+ if (ted_mouse_in_rect(ted, button)) {
// highlight button when hovering over it
u32 new_color = (color & 0xffffff00) | ((color & 0xff) / 3);
gl_geometry_rect(button, new_color);