Add alt+arrow support
This commit is contained in:
@@ -6,7 +6,6 @@ A TUI IDE.
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
- [ ] Add alt+arrows to move line/block up/down.
|
|
||||||
- [ ] Add `hooks` in files that can be set/unset/jumped to.
|
- [ ] Add `hooks` in files that can be set/unset/jumped to.
|
||||||
- [ ] Add folding support at tree-sitter level (basic folding is done).
|
- [ ] Add folding support at tree-sitter level (basic folding is done).
|
||||||
- [ ] Add feature where doing enter uses tree-sitter to add newline with indentation.
|
- [ ] Add feature where doing enter uses tree-sitter to add newline with indentation.
|
||||||
@@ -25,3 +24,4 @@ A TUI IDE.
|
|||||||
- [ ] Add codeium/copilot support.
|
- [ ] Add codeium/copilot support.
|
||||||
- [ ] Normalize / validate unicode on file open.
|
- [ ] Normalize / validate unicode on file open.
|
||||||
- [ ] Add git stuff.
|
- [ ] Add git stuff.
|
||||||
|
- [ ] Fix bug where alt+up at eof adds extra line.
|
||||||
|
|||||||
@@ -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);
|
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y);
|
||||||
char *get_selection(Editor *editor, uint32_t *out_len);
|
char *get_selection(Editor *editor, uint32_t *out_len);
|
||||||
void editor_worker(Editor *editor);
|
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,
|
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
|
||||||
uint32_t *next_col, uint32_t *prev_clusters,
|
uint32_t *next_col, uint32_t *prev_clusters,
|
||||||
uint32_t *next_clusters);
|
uint32_t *next_clusters);
|
||||||
|
|||||||
@@ -165,10 +165,10 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
|
|||||||
nullptr);
|
nullptr);
|
||||||
switch (event.special_key) {
|
switch (event.special_key) {
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
cursor_down(editor, 1);
|
cursor_down(editor, 5);
|
||||||
break;
|
break;
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
cursor_up(editor, 1);
|
cursor_up(editor, 5);
|
||||||
break;
|
break;
|
||||||
case KEY_LEFT:
|
case KEY_LEFT:
|
||||||
editor->cursor_preffered = UINT32_MAX;
|
editor->cursor_preffered = UINT32_MAX;
|
||||||
@@ -187,8 +187,20 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ALT:
|
case ALT:
|
||||||
// TODO: For up/down in insert/normal move line and in select move lines
|
switch (event.special_key) {
|
||||||
// overlapping selection up/down. right/left are normal
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -777,6 +789,93 @@ void cursor_left(Editor *editor, uint32_t number) {
|
|||||||
editor->cursor_preffered = UINT32_MAX;
|
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) {
|
void edit_erase(Editor *editor, Coord pos, int64_t len) {
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user