Add alt+arrow support

This commit is contained in:
2025-12-14 10:52:56 +00:00
parent aa25bf0ac3
commit 5fae2f3bb6
3 changed files with 106 additions and 5 deletions

View File

@@ -6,7 +6,6 @@ A TUI IDE.
# TODO
- [ ] Add alt+arrows to move line/block up/down.
- [ ] Add `hooks` in files that can be set/unset/jumped to.
- [ ] Add folding support at tree-sitter level (basic folding is done).
- [ ] Add feature where doing enter uses tree-sitter to add newline with indentation.
@@ -25,3 +24,4 @@ A TUI IDE.
- [ ] Add codeium/copilot support.
- [ ] Normalize / validate unicode on file open.
- [ ] Add git stuff.
- [ ] Fix bug where alt+up at eof adds extra line.

View File

@@ -130,6 +130,8 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len);
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y);
char *get_selection(Editor *editor, uint32_t *out_len);
void editor_worker(Editor *editor);
void move_line_down(Editor *editor);
void move_line_up(Editor *editor);
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters);

View File

@@ -165,10 +165,10 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
nullptr);
switch (event.special_key) {
case KEY_DOWN:
cursor_down(editor, 1);
cursor_down(editor, 5);
break;
case KEY_UP:
cursor_up(editor, 1);
cursor_up(editor, 5);
break;
case KEY_LEFT:
editor->cursor_preffered = UINT32_MAX;
@@ -187,8 +187,20 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
}
break;
case ALT:
// TODO: For up/down in insert/normal move line and in select move lines
// overlapping selection up/down. right/left are normal
switch (event.special_key) {
case KEY_DOWN:
move_line_down(editor);
break;
case KEY_UP:
move_line_up(editor);
break;
case KEY_LEFT:
cursor_left(editor, 8);
break;
case KEY_RIGHT:
cursor_right(editor, 8);
break;
}
break;
}
}
@@ -777,6 +789,93 @@ void cursor_left(Editor *editor, uint32_t number) {
editor->cursor_preffered = UINT32_MAX;
}
void move_line_up(Editor *editor) {
if (!editor || !editor->root || editor->cursor.row == 0)
return;
if (mode == NORMAL || mode == INSERT) {
uint32_t line_len, line_cluster_len;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
char *line = next_line(it, &line_len);
free(it);
if (!line) {
lock.unlock();
return;
}
line_cluster_len = count_clusters(line, line_len, 0, line_len);
lock.unlock();
Coord cursor = editor->cursor;
edit_erase(editor, {cursor.row, 0}, line_cluster_len);
edit_insert(editor, {cursor.row - 1, 0}, line, line_len);
free(line);
editor->cursor = {cursor.row - 1, cursor.col};
} else if (mode == SELECT) {
uint32_t start_row = MIN(editor->cursor.row, editor->selection.row);
uint32_t end_row = MAX(editor->cursor.row, editor->selection.row);
uint32_t start_byte = line_to_byte(editor->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(editor->root, end_row + 1, nullptr);
char *selected_text = read(editor->root, start_byte, end_byte - start_byte);
if (!selected_text)
return;
uint32_t selected_len = count_clusters(selected_text, end_byte - start_byte,
0, end_byte - start_byte);
Coord cursor = editor->cursor;
Coord selection = editor->selection;
edit_erase(editor, {start_row, 0}, selected_len);
edit_insert(editor, {start_row - 1, 0}, selected_text,
end_byte - start_byte);
free(selected_text);
editor->cursor = {cursor.row - 1, cursor.col};
editor->selection = {selection.row - 1, selection.col};
}
}
void move_line_down(Editor *editor) {
if (!editor || !editor->root)
return;
if (mode == NORMAL || mode == INSERT) {
if (editor->cursor.row >= editor->root->line_count - 1)
return;
uint32_t line_len, line_cluster_len;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
char *line = next_line(it, &line_len);
free(it);
if (!line) {
lock.unlock();
return;
}
line_cluster_len = count_clusters(line, line_len, 0, line_len);
lock.unlock();
Coord cursor = editor->cursor;
edit_erase(editor, {cursor.row, 0}, line_cluster_len);
edit_insert(editor, {cursor.row + 1, 0}, line, line_len);
free(line);
editor->cursor = {cursor.row + 1, cursor.col};
} else if (mode == SELECT) {
if (editor->cursor.row >= editor->root->line_count - 1 ||
editor->selection.row >= editor->root->line_count - 1)
return;
uint32_t start_row = MIN(editor->cursor.row, editor->selection.row);
uint32_t end_row = MAX(editor->cursor.row, editor->selection.row);
uint32_t start_byte = line_to_byte(editor->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(editor->root, end_row + 1, nullptr);
char *selected_text = read(editor->root, start_byte, end_byte - start_byte);
if (!selected_text)
return;
uint32_t selected_len = count_clusters(selected_text, end_byte - start_byte,
0, end_byte - start_byte);
Coord cursor = editor->cursor;
Coord selection = editor->selection;
edit_erase(editor, {start_row, 0}, selected_len);
edit_insert(editor, {start_row + 1, 0}, selected_text,
end_byte - start_byte);
free(selected_text);
editor->cursor = {cursor.row + 1, cursor.col};
editor->selection = {selection.row + 1, selection.col};
}
}
void edit_erase(Editor *editor, Coord pos, int64_t len) {
if (len == 0)
return;