diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2021-02-11 14:19:38 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2021-02-11 14:50:02 -0500 |
commit | aaebf30ccd75ba27ec55bc45ed886cdae2ca58ef (patch) | |
tree | 7dc6e7c752dacdd916a96f304fa51edd61db0cb0 | |
parent | 90b4b08717730733402df25190bba0cc5d2fd952 (diff) |
highlight matching parentheses
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | buffer.c | 57 | ||||
-rw-r--r-- | colors.h | 3 | ||||
-rw-r--r-- | gl.c | 1 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | syntax.c | 26 | ||||
-rw-r--r-- | ted.cfg | 2 |
7 files changed, 92 insertions, 3 deletions
@@ -2,8 +2,8 @@ ALL_CFLAGS=$(CFLAGS) -Wall -Wextra -Wshadow -Wconversion -Wpedantic -pedantic -s -Wno-unused-function -Wno-fixed-enum-extension -Wimplicit-fallthrough -Wno-format-truncation -Wno-unknown-warning-option LIBS=-lSDL2 -lGL -ldl -lm libpcre2-32.a -Ipcre2-10.36/build DEBUG_CFLAGS=$(ALL_CFLAGS) -DDEBUG -O0 -g -RELEASE_CFLAGS=$(ALL_CFLAGS) -O3 -PROFILE_CFLAGS=$(ALL_CFLAGS) -O3 -DPROFILE=1 +RELEASE_CFLAGS=$(ALL_CFLAGS) -O3 -g +PROFILE_CFLAGS=$(ALL_CFLAGS) -O3 -g -DPROFILE=1 GLOBAL_DATA_DIR=/usr/share/ted LOCAL_DATA_DIR=/home/`logname`/.local/share/ted INSTALL_BIN_DIR=/usr/bin @@ -160,6 +160,31 @@ char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos p) { } } +// returns 0 if pos is at the start of a line +char32_t buffer_char_before_pos(TextBuffer *buffer, BufferPos pos) { + assert(buffer_pos_valid(buffer, pos)); + if (pos.index == 0) return 0; + return buffer->lines[pos.line].str[pos.index - 1]; +} + +// returns 0 if pos is at the end of a line (unlike buffer_char_at_pos) +char32_t buffer_char_after_pos(TextBuffer *buffer, BufferPos pos) { + assert(buffer_pos_valid(buffer, pos)); + Line *line = &buffer->lines[pos.line]; + if (pos.index >= line->len) return 0; + return line->str[pos.index]; +} + +// returns the character to the left of the cursor, or 0 if the cursor at the start of the line. +char32_t buffer_char_before_cursor(TextBuffer *buffer) { + return buffer_char_before_pos(buffer, buffer->cursor_pos); +} + +// returns 0 if cursor is at end of line +char32_t buffer_char_after_cursor(TextBuffer *buffer) { + return buffer_char_after_pos(buffer, buffer->cursor_pos); +} + BufferPos buffer_start_of_file(TextBuffer *buffer) { (void)buffer; return (BufferPos){.line = 0, .index = 0}; @@ -2184,12 +2209,42 @@ void buffer_render(TextBuffer *buffer, Rect r) { double t = fmod(absolute_time, period); is_on = t < time_on; // are we in the "on" part of the period? } + + // highlight matching brackets + char32_t cursor_bracket = buffer_char_before_cursor(buffer); + char32_t matching_bracket = syntax_matching_bracket(language, cursor_bracket); + if (cursor_bracket && matching_bracket) { + int direction = syntax_is_opening_bracket(language, cursor_bracket) ? +1 : -1; + int depth = 1; + BufferPos pos = buffer->cursor_pos; + buffer_pos_move_left(buffer, &pos, 1); + while (pos.line >= start_line) { + if (buffer_pos_move_right(buffer, &pos, direction)) { + char32_t c = buffer_char_after_pos(buffer, pos); + if (c == cursor_bracket) depth += 1; + else if (c == matching_bracket) depth -= 1; + if (depth == 0) break; + } else { + break; + } + } + if (depth == 0) { + // highlight it + v2 gl_pos = buffer_pos_to_pixels(buffer, pos); + Rect hl_rect = rect(gl_pos, V2(char_width, char_height)); + if (buffer_clip_rect(buffer, &hl_rect)) { + gl_geometry_rect(hl_rect, colors[COLOR_MATCHING_BRACKET_HL]); + } + } + } + + if (is_on) { if (buffer_clip_rect(buffer, &cursor_rect)) { gl_geometry_rect(cursor_rect, colors[COLOR_CURSOR]); - gl_geometry_draw(); } } + gl_geometry_draw(); } } @@ -7,6 +7,7 @@ ENUM_U16 { COLOR_HL, COLOR_CURSOR, COLOR_CURSOR_LINE_BG, + COLOR_MATCHING_BRACKET_HL, COLOR_BORDER, COLOR_TEXT_FOLDER, COLOR_TEXT_OTHER, @@ -35,6 +36,7 @@ ENUM_U16 { COLOR_LINE_NUMBERS, COLOR_CURSOR_LINE_NUMBER, COLOR_LINE_NUMBERS_SEPARATOR, + COLOR_COUNT } ENUM_U16_END(ColorSetting); @@ -52,6 +54,7 @@ static ColorName const color_names[COLOR_COUNT] = { {COLOR_HL, "hl"}, {COLOR_CURSOR, "cursor"}, {COLOR_CURSOR_LINE_BG, "cursor-line-bg"}, + {COLOR_MATCHING_BRACKET_HL, "matching-bracket-hl"}, {COLOR_BORDER, "border"}, {COLOR_TEXT_FOLDER, "text-folder"}, {COLOR_TEXT_OTHER, "text-other"}, @@ -222,6 +222,7 @@ static void gl_geometry_rect_border(Rect r, float border_thickness, u32 color) { static void gl_geometry_draw(void) { size_t ntriangles = arr_len(gl_geometry_triangles); + if (ntriangles == 0) return; // convert coordinates to NDC for (size_t i = 0; i < ntriangles; ++i) { @@ -4,6 +4,8 @@ // - completion // - view-only // - Windows installation +// - restore previously opened files (setting: restore-session) +// - on crash, output backtrace to log, save buffers to temp directory #include "base.h" no_warn_start @@ -45,6 +45,32 @@ static inline bool syntax_keyword_matches(char32_t *text, size_t len, char const } } +// returns ')' for '(', etc., or 0 if c is not an opening bracket +char32_t syntax_matching_bracket(Language lang, char32_t c) { + (void)lang; // not needed yet + switch (c) { + case '(': return ')'; + case ')': return '('; + case '[': return ']'; + case ']': return '['; + case '{': return '}'; + case '}': return '{'; + } + return 0; +} + +// returns true for opening brackets, false for closing brackets/non-brackets +bool syntax_is_opening_bracket(Language lang, char32_t c) { + (void)lang; + switch (c) { + case '(': + case '[': + case '{': + return true; + } + return false; +} + // lookup the given string in the keywords table static Keyword const *syntax_keyword_lookup(Keyword const *const *all_keywords, size_t n_all_keywords, char32_t *str, size_t len) { if (!len) return NULL; @@ -116,6 +116,8 @@ border = #a77 active-tab-hl = #a77a cursor-line-bg = #222 cursor = #3ff +# color to highlight matching brackets with +matching-bracket-hl = #fda8 selection-bg = #36aa hl = #ccc text = #fff |