From aafa05522d2ddb67cd0d8ad9839bf4662c20ea47 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 31 Jan 2026 08:04:58 +0900 Subject: [PATCH] mirb_editor.c: refactor duplicated indent calculation logic Extract three helpers (calc_expected_indent, adjust_line_indent, insert_indent_spaces) to eliminate repeated indent computation and whitespace adjustment code in perform_dedent, reindent_line, handle_tab_indent, and the Enter key handler. Co-authored-by: Claude --- .../mruby-bin-mirb/tools/mirb/mirb_editor.c | 229 ++++++------------ 1 file changed, 74 insertions(+), 155 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb_editor.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb_editor.c index 406927168..a350a56cb 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb_editor.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb_editor.c @@ -153,6 +153,66 @@ calc_indent_level(const char *code) return level; } +/* + * Calculate expected indent level for the given line index. + * Uses code up to line_idx-1 to determine nesting depth. + */ +static int +calc_expected_indent(mirb_buffer *buf, size_t line_idx) +{ + int indent = 0; + char *partial; + + if (line_idx == 0) return 0; + partial = mirb_buffer_to_string_upto_line(buf, line_idx - 1); + if (partial) { + indent = calc_indent_level(partial); + free(partial); + } + return indent; +} + +/* + * Adjust current line's leading whitespace to target_spaces. + * Preserves cursor position relative to line content. + */ +static void +adjust_line_indent(mirb_buffer *buf, size_t target_spaces) +{ + size_t current_spaces = leading_spaces(mirb_buffer_current_line(buf)); + size_t saved_col = buf->cursor_col; + + if (target_spaces == current_spaces) return; + + if (target_spaces > current_spaces) { + size_t add = target_spaces - current_spaces; + buf->cursor_col = 0; + for (size_t i = 0; i < add; i++) { + mirb_buffer_insert_char(buf, ' '); + } + buf->cursor_col = saved_col + add; + } + else { + size_t to_remove = current_spaces - target_spaces; + buf->cursor_col = 0; + for (size_t i = 0; i < to_remove; i++) { + mirb_buffer_delete_forward(buf); + } + buf->cursor_col = (saved_col > to_remove) ? (saved_col - to_remove) : 0; + } +} + +/* + * Insert indent spaces at cursor position + */ +static void +insert_indent_spaces(mirb_buffer *buf, int indent_level) +{ + for (int i = 0; i < indent_level * 2; i++) { + mirb_buffer_insert_char(buf, ' '); + } +} + /* * Check if we should dedent after typing a character * Returns TRUE if current line starts with 'end' or '}' after only whitespace @@ -212,41 +272,14 @@ should_dedent(mirb_buffer *buf, char last_char) } /* - * Perform dedentation - remove one level (2 spaces) of leading whitespace + * Perform dedentation - adjust indent for dedent keyword */ static void perform_dedent(mirb_buffer *buf) { - const char *line = mirb_buffer_current_line(buf); - size_t current_spaces = leading_spaces(line); - int expected_indent = 0; - - /* Calculate expected indent from code up to previous line */ - if (buf->cursor_line > 0) { - char *partial = mirb_buffer_to_string_upto_line(buf, buf->cursor_line - 1); - if (partial) { - expected_indent = calc_indent_level(partial); - free(partial); - } - } - - /* Dedent one level for keywords like end, else, etc. */ - if (expected_indent > 0) expected_indent--; - - size_t target_spaces = (size_t)(expected_indent * 2); - - /* Only dedent if we have more spaces than target */ - if (current_spaces > target_spaces) { - size_t to_remove = current_spaces - target_spaces; - size_t saved_col = buf->cursor_col; - /* Move cursor to start of line and delete leading spaces */ - buf->cursor_col = 0; - for (size_t i = 0; i < to_remove; i++) { - mirb_buffer_delete_forward(buf); - } - /* Restore cursor position, adjusted for removed spaces */ - buf->cursor_col = (saved_col > to_remove) ? (saved_col - to_remove) : 0; - } + int indent = calc_expected_indent(buf, buf->cursor_line); + if (indent > 0) indent--; + adjust_line_indent(buf, (size_t)(indent * 2)); } @@ -258,55 +291,12 @@ static void reindent_line(mirb_buffer *buf) { mirb_line *line = &buf->lines[buf->cursor_line]; - size_t current_spaces = 0; - int expected_indent = 0; - const char *content; - - /* Count current leading whitespace */ - for (size_t i = 0; i < line->len && (line->data[i] == ' ' || line->data[i] == '\t'); i++) { - current_spaces++; - } - - /* Calculate expected indent from code up to previous line */ - if (buf->cursor_line > 0) { - char *partial = mirb_buffer_to_string_upto_line(buf, buf->cursor_line - 1); - if (partial) { - expected_indent = calc_indent_level(partial); - free(partial); - } - } - - /* Check if line content starts with dedenting keyword */ - content = line->data + current_spaces; + int indent = calc_expected_indent(buf, buf->cursor_line); + const char *content = line->data + leading_spaces(line->data); if (is_dedent_keyword(content)) { - if (expected_indent > 0) expected_indent--; - } - - size_t target_spaces = (size_t)(expected_indent * 2); - - /* Adjust indentation if needed */ - if (target_spaces != current_spaces) { - size_t saved_col = buf->cursor_col; - - if (target_spaces > current_spaces) { - /* Need to add spaces */ - size_t add = target_spaces - current_spaces; - buf->cursor_col = 0; - for (size_t i = 0; i < add; i++) { - mirb_buffer_insert_char(buf, ' '); - } - buf->cursor_col = saved_col + add; - } - else { - /* Need to remove spaces */ - size_t remove = current_spaces - target_spaces; - buf->cursor_col = current_spaces; - for (size_t i = 0; i < remove; i++) { - mirb_buffer_delete_back(buf); - } - buf->cursor_col = (saved_col > remove) ? (saved_col - remove) : 0; - } + if (indent > 0) indent--; } + adjust_line_indent(buf, (size_t)(indent * 2)); } /* @@ -425,67 +415,7 @@ mirb_editor_set_tab_complete(mirb_editor *ed, static void handle_tab_indent(mirb_editor *ed) { - mirb_line *line = &ed->buf.lines[ed->buf.cursor_line]; - int expected_indent = 0; - size_t current_spaces = 0; - size_t i; - const char *content; - size_t saved_cursor_col = ed->buf.cursor_col; - - /* Calculate expected indent from code up to previous line */ - if (ed->buf.cursor_line > 0) { - char *partial = mirb_buffer_to_string_upto_line(&ed->buf, ed->buf.cursor_line - 1); - if (partial) { - expected_indent = calc_indent_level(partial); - free(partial); - } - } - - /* Count current leading whitespace */ - for (i = 0; i < line->len && (line->data[i] == ' ' || line->data[i] == '\t'); i++) { - current_spaces++; - } - - /* Check if line content starts with dedenting keyword */ - content = line->data + current_spaces; - if (is_dedent_keyword(content)) { - if (expected_indent > 0) expected_indent--; - } - - /* Calculate target spaces (2 spaces per indent level) */ - size_t target_spaces = (size_t)(expected_indent * 2); - - /* Adjust indentation */ - if (target_spaces > current_spaces) { - /* Need to add spaces - insert at beginning */ - size_t add = target_spaces - current_spaces; - ed->buf.cursor_col = 0; - for (i = 0; i < add; i++) { - mirb_buffer_insert_char(&ed->buf, ' '); - } - } - else if (target_spaces < current_spaces) { - /* Need to remove spaces */ - size_t remove = current_spaces - target_spaces; - ed->buf.cursor_col = current_spaces; - for (i = 0; i < remove; i++) { - mirb_buffer_delete_back(&ed->buf); - } - } - - /* Restore cursor position adjusted for indent change */ - if (target_spaces >= current_spaces) { - ed->buf.cursor_col = saved_cursor_col + (target_spaces - current_spaces); - } - else { - size_t removed = current_spaces - target_spaces; - if (saved_cursor_col >= removed) { - ed->buf.cursor_col = saved_cursor_col - removed; - } - else { - ed->buf.cursor_col = 0; - } - } + reindent_line(&ed->buf); } static mrb_bool @@ -725,19 +655,14 @@ handle_key(mirb_editor *ed, int key, mirb_edit_result *result) mirb_line *next_line = &ed->buf.lines[next_line_idx]; if (is_line_blank(next_line)) { /* Move to existing blank last line with proper indentation */ - char *code = mirb_buffer_to_string(&ed->buf); - int indent = code ? calc_indent_level(code) : 0; - free(code); - + int indent = calc_expected_indent(&ed->buf, ed->buf.line_count); mirb_buffer_cursor_down(&ed->buf); /* Clear existing whitespace and set correct indent */ mirb_line *line = &ed->buf.lines[ed->buf.cursor_line]; line->len = 0; line->data[0] = '\0'; ed->buf.cursor_col = 0; - for (int i = 0; i < indent * 2; i++) { - mirb_buffer_insert_char(&ed->buf, ' '); - } + insert_indent_spaces(&ed->buf, indent); return TRUE; } } @@ -768,18 +693,14 @@ handle_key(mirb_editor *ed, int key, mirb_edit_result *result) int indent = calc_indent_level(code); free(code); mirb_buffer_newline(&ed->buf); - for (int i = 0; i < indent * 2; i++) { - mirb_buffer_insert_char(&ed->buf, ' '); - } + insert_indent_spaces(&ed->buf, indent); return TRUE; } } /* Not at end of last line - just insert/split with appropriate indent */ { - char *partial = mirb_buffer_to_string_upto_line(&ed->buf, ed->buf.cursor_line); - int indent = partial ? calc_indent_level(partial) : 0; - free(partial); + int indent = calc_expected_indent(&ed->buf, ed->buf.cursor_line + 1); mirb_buffer_newline(&ed->buf); /* Check if new line starts with dedenting keyword */ @@ -788,9 +709,7 @@ handle_key(mirb_editor *ed, int key, mirb_edit_result *result) if (indent > 0) indent--; } - for (int i = 0; i < indent * 2; i++) { - mirb_buffer_insert_char(&ed->buf, ' '); - } + insert_indent_spaces(&ed->buf, indent); return TRUE; } }