From 8f23762128bebda1e8e07058f905363954ac9c61 Mon Sep 17 00:00:00 2001 From: pommicket Date: Thu, 11 May 2023 12:11:44 -0400 Subject: :matching-bracket, fix matching bracket highlighting in some cases --- buffer.c | 73 ++++++++++++++++++++++++++++++++---------------------- command.c | 6 ++++- command.h | 2 ++ ide-autocomplete.c | 2 +- main.c | 2 -- ted.cfg | 2 ++ ted.h | 12 +++++---- 7 files changed, 60 insertions(+), 39 deletions(-) diff --git a/buffer.c b/buffer.c index f607f10..5ecdf4f 100644 --- a/buffer.c +++ b/buffer.c @@ -177,30 +177,25 @@ bool buffer_unsaved_changes(TextBuffer *buffer) { char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos pos) { if (!buffer_pos_valid(buffer, pos)) return 0; - Line *line = &buffer->lines[pos.line]; + if (pos.index >= line->len) + return 0; return line->str[pos.index]; } char32_t buffer_char_before_pos(TextBuffer *buffer, BufferPos pos) { - assert(buffer_pos_valid(buffer, pos)); + if (!buffer_pos_valid(buffer, pos)) + return 0; if (pos.index == 0) return 0; return buffer->lines[pos.line].str[pos.index - 1]; } -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]; -} - char32_t buffer_char_before_cursor(TextBuffer *buffer) { return buffer_char_before_pos(buffer, buffer->cursor_pos); } -char32_t buffer_char_after_cursor(TextBuffer *buffer) { - return buffer_char_after_pos(buffer, buffer->cursor_pos); +char32_t buffer_char_at_cursor(TextBuffer *buffer) { + return buffer_char_at_pos(buffer, buffer->cursor_pos); } BufferPos buffer_pos_start_of_file(TextBuffer *buffer) { @@ -1940,7 +1935,7 @@ bool buffer_change_number_at_pos(TextBuffer *buffer, BufferPos *ppos, i64 by) { if (is32_alnum(buffer_char_before_pos(buffer, pos))) { buffer_pos_move_left_words(buffer, &pos, 1); } - char32_t c = buffer_char_after_pos(buffer, pos); + char32_t c = buffer_char_at_pos(buffer, pos); if (c >= 127 || !isdigit((char)c)) { if (c != '-') { // not a number @@ -2864,6 +2859,38 @@ bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times) { return false; } +bool buffer_pos_move_to_matching_bracket(TextBuffer *buffer, BufferPos *pos) { + Language language = buffer_language(buffer); + char32_t bracket_char = buffer_char_at_pos(buffer, *pos); + char32_t matching_char = syntax_matching_bracket(language, bracket_char); + if (bracket_char && matching_char) { + int direction = syntax_is_opening_bracket(language, bracket_char) ? +1 : -1; + int depth = 1; + while (buffer_pos_move_right(buffer, pos, direction)) { + char32_t c = buffer_char_at_pos(buffer, *pos); + if (c == bracket_char) depth += 1; + else if (c == matching_char) depth -= 1; + if (depth == 0) break; + } + return true; + } else { + return false; + } +} + +bool buffer_cursor_move_to_matching_bracket(TextBuffer *buffer) { + // it's more natural here to consider the character to the left of the cursor + BufferPos pos = buffer->cursor_pos; + if (pos.index == 0) return false; + buffer_pos_move_left(buffer, &pos, 1); + if (buffer_pos_move_to_matching_bracket(buffer, &pos)) { + buffer_pos_move_right(buffer, &pos, 1); + buffer_cursor_move_to_pos(buffer, pos); + return true; + } + return false; +} + // Render the text buffer in the given rectangle void buffer_render(TextBuffer *buffer, Rect r) { @@ -3123,25 +3150,11 @@ void buffer_render(TextBuffer *buffer, Rect r) { if (ted->active_buffer == buffer) { // 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; + BufferPos pos = buffer->cursor_pos; + if (pos.index > 0) { + // it's more natural to consider the bracket to the left of the cursor 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 + if (buffer_pos_move_to_matching_bracket(buffer, &pos)) { vec2 gl_pos = buffer_pos_to_pixels(buffer, pos); Rect hl_rect = rect(gl_pos, Vec2(char_width, char_height)); if (buffer_clip_rect(buffer, &hl_rect)) { diff --git a/command.c b/command.c index 5b3411b..fd75189 100644 --- a/command.c +++ b/command.c @@ -37,6 +37,7 @@ static CommandName command_names[] = { {"select-all", CMD_SELECT_ALL}, {"select-up-blank-line", CMD_SELECT_UP_BLANK_LINE}, {"select-down-blank-line", CMD_SELECT_DOWN_BLANK_LINE}, + {"matching-bracket", CMD_MATCHING_BRACKET}, {"clear-selection", CMD_CLEAR_SELECTION}, {"page-up", CMD_PAGE_UP}, {"page-down", CMD_PAGE_DOWN}, @@ -292,7 +293,10 @@ void command_execute_ex(Ted *ted, Command c, CommandArgument full_argument, Comm if (buffer) buffer_cursor_move_to_prev_pos(buffer); break; - + case CMD_MATCHING_BRACKET: + if (buffer) + buffer_cursor_move_to_matching_bracket(buffer); + break; case CMD_INSERT_TEXT: { const char *str = argument_str; if (str && buffer) { diff --git a/command.h b/command.h index 408bfbe..97a7c43 100644 --- a/command.h +++ b/command.h @@ -46,6 +46,8 @@ typedef enum { CMD_END_OF_FILE, /// go to previous position CMD_PREVIOUS_POSITION, + /// move cursor to matching bracket + CMD_MATCHING_BRACKET, CMD_SELECT_START_OF_FILE, CMD_SELECT_END_OF_FILE, /// select entire buffer diff --git a/ide-autocomplete.c b/ide-autocomplete.c index db9645c..3d5e24c 100644 --- a/ide-autocomplete.c +++ b/ide-autocomplete.c @@ -33,7 +33,7 @@ static bool autocomplete_should_display_phantom(Ted *ted) { && !buffer->is_line_buffer && buffer_settings(buffer)->phantom_completions && is32_word(buffer_char_before_cursor(buffer)) - && !is32_word(buffer_char_after_cursor(buffer)); + && !is32_word(buffer_char_at_cursor(buffer)); if (!show) autocomplete_clear_phantom(ac); return show; diff --git a/main.c b/main.c index e2c795b..64bf3ca 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,4 @@ /* -TODO: -- :go-to-matching-bracket FUTURE FEATURES: - highlight TODO, FIXME, XXX, others(?) in comments - autodetect indentation (tabs vs spaces) diff --git a/ted.cfg b/ted.cfg index 83662da..3b6909b 100644 --- a/ted.cfg +++ b/ted.cfg @@ -232,6 +232,8 @@ Ctrl+Shift+End = :select-end-of-file Ctrl+a = :select-all # go to previous cursor position Ctrl+p = :previous-position +# move cursor to matching bracket +Ctrl+Shift+5 = :matching-bracket # Ctrl+Shift+d = :clear-selection # insertion diff --git a/ted.h b/ted.h index de00472..bed54fe 100644 --- a/ted.h +++ b/ted.h @@ -917,20 +917,22 @@ void buffer_create(TextBuffer *buffer, Ted *ted); void line_buffer_create(TextBuffer *buffer, Ted *ted); /// does this buffer have unsaved changes? bool buffer_unsaved_changes(TextBuffer *buffer); -/// returns the character at position pos, or 0 if pos is invalid +/// returns the character after position pos, or 0 if pos is invalid char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos pos); +/// returns the character after the cursor +char32_t buffer_char_at_cursor(TextBuffer *buffer); /// returns the character before position pos, or 0 if pos is invalid or at the start of a line char32_t buffer_char_before_pos(TextBuffer *buffer, BufferPos pos); -/// returns the character after position pos, or 0 if pos is invalid or at the end of a line -char32_t buffer_char_after_pos(TextBuffer *buffer, BufferPos pos); /// 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); -/// returns the character to the right of the cursor, 0 if cursor is at end of line -char32_t buffer_char_after_cursor(TextBuffer *buffer); /// buffer position of start of file BufferPos buffer_pos_start_of_file(TextBuffer *buffer); /// buffer position of end of file BufferPos buffer_pos_end_of_file(TextBuffer *buffer); +/// move position to matching bracket. returns true if there was a bracket at the position, otherwise returns false and does nothing. +bool buffer_pos_move_to_matching_bracket(TextBuffer *buffer, BufferPos *pos); +/// move cursor to matching bracket. returns true if cursor was to the right of a bracket. +bool buffer_cursor_move_to_matching_bracket(TextBuffer *buffer); /// 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? -- cgit v1.2.3