mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-bin-mirb: add TAB auto-indentation
TAB now performs auto-indentation instead of completion when: - cursor is at start of line - cursor is at end of line - character before cursor is whitespace Auto-indent calculates expected indent level from previous lines and adjusts current line. Dedenting keywords (end, else, elsif, when, rescue, ensure, }) reduce indent by one level. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -311,6 +311,79 @@ mirb_editor_set_tab_complete(mirb_editor *ed,
|
||||
* Handle tab completion
|
||||
* Returns TRUE if completion was performed
|
||||
*/
|
||||
|
||||
/*
|
||||
* Handle tab auto-indent
|
||||
* Adjusts current line's indentation to match the expected level
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Calculate expected indent from code up to previous line */
|
||||
if (ed->buf.cursor_line > 0) {
|
||||
char *partial = 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 ((strncmp(content, "end", 3) == 0 &&
|
||||
(content[3] == '\0' || content[3] == ' ' || content[3] == '\t' ||
|
||||
content[3] == '.' || content[3] == ')')) ||
|
||||
(strncmp(content, "else", 4) == 0 &&
|
||||
(content[4] == '\0' || content[4] == ' ' || content[4] == '\t')) ||
|
||||
(strncmp(content, "elsif", 5) == 0 && content[5] == ' ') ||
|
||||
(strncmp(content, "when", 4) == 0 && content[4] == ' ') ||
|
||||
(strncmp(content, "rescue", 6) == 0 &&
|
||||
(content[6] == '\0' || content[6] == ' ' || content[6] == '\t')) ||
|
||||
(strncmp(content, "ensure", 6) == 0 &&
|
||||
(content[6] == '\0' || content[6] == ' ' || content[6] == '\t')) ||
|
||||
content[0] == '}') {
|
||||
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, ' ');
|
||||
}
|
||||
ed->buf.cursor_col = target_spaces;
|
||||
}
|
||||
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);
|
||||
}
|
||||
ed->buf.cursor_col = target_spaces;
|
||||
}
|
||||
else {
|
||||
/* Already correct, move cursor to end of indent */
|
||||
ed->buf.cursor_col = target_spaces;
|
||||
}
|
||||
}
|
||||
|
||||
static mrb_bool
|
||||
handle_tab_completion(mirb_editor *ed)
|
||||
{
|
||||
@@ -732,8 +805,32 @@ handle_key(mirb_editor *ed, int key, mirb_edit_result *result)
|
||||
return TRUE;
|
||||
|
||||
case MIRB_KEY_TAB:
|
||||
/* Tab completion */
|
||||
handle_tab_completion(ed);
|
||||
/* Auto-indent if at start/end of line or preceded by whitespace */
|
||||
{
|
||||
mirb_line *line = &ed->buf.lines[ed->buf.cursor_line];
|
||||
mrb_bool do_indent = FALSE;
|
||||
|
||||
if (ed->buf.cursor_col == 0) {
|
||||
do_indent = TRUE;
|
||||
}
|
||||
else if (ed->buf.cursor_col == line->len) {
|
||||
/* At end of line */
|
||||
do_indent = TRUE;
|
||||
}
|
||||
else {
|
||||
char prev_char = line->data[ed->buf.cursor_col - 1];
|
||||
if (prev_char == ' ' || prev_char == '\t') {
|
||||
do_indent = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_indent) {
|
||||
handle_tab_indent(ed);
|
||||
}
|
||||
else {
|
||||
handle_tab_completion(ed);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user