summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-05-11 12:11:44 -0400
committerpommicket <pommicket@gmail.com>2023-05-11 12:11:54 -0400
commit8f23762128bebda1e8e07058f905363954ac9c61 (patch)
treed1e78fa4020de61b34cf4600bebcf40dc0cc7322
parentba8d08d0eef98e1950f8c96c12fe8de3f0f059ae (diff)
:matching-bracket, fix matching bracket highlighting in some cases
-rw-r--r--buffer.c73
-rw-r--r--command.c6
-rw-r--r--command.h2
-rw-r--r--ide-autocomplete.c2
-rw-r--r--main.c2
-rw-r--r--ted.cfg2
-rw-r--r--ted.h12
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?