summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-30 12:41:46 -0400
committerpommicket <pommicket@gmail.com>2025-09-30 12:41:46 -0400
commitf7993d24a0dfd4762f84378722bd39b07c0fe405 (patch)
tree0bedeb9afcd54c8c5b09f5cd64c46148626b3845
parent13143e9d1a78c8e0135336bbfcc922ef28c0196a (diff)
Use a cursor for code actions
-rw-r--r--command.c17
-rw-r--r--command.h1
-rw-r--r--ide-code-action.c41
-rw-r--r--lsp-parse.c2
-rw-r--r--main.c1
-rw-r--r--ted.cfg3
-rw-r--r--ted.h8
7 files changed, 49 insertions, 24 deletions
diff --git a/command.c b/command.c
index 0f1c303..703f4bd 100644
--- a/command.c
+++ b/command.c
@@ -112,6 +112,7 @@ static CommandName command_names[] = {
{"set-tab-width", CMD_SET_TAB_WIDTH},
{"debug-print-undo-history", CMD_DEBUG_PRINT_UNDO_HISTORY},
{"code-action", CMD_CODE_ACTION},
+ {"code-action-prev", CMD_CODE_ACTION_PREV},
};
static_assert_if_possible(arr_count(command_names) == CMD_COUNT)
@@ -345,6 +346,8 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
buffer_select_all(buffer);
} else if (autocomplete_is_open(ted) || autocomplete_has_phantom(ted)) {
autocomplete_select_completion(ted);
+ } else if (code_action_is_open(ted)) {
+ code_action_select(ted);
} else if (buffer) {
if (buffer_has_selection(buffer))
buffer_indent_selection(buffer);
@@ -369,9 +372,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
break;
case CMD_NEWLINE:
case CMD_NEWLINE_BACK:
- if (code_action_is_open(ted)) {
- code_action_select_best(ted);
- } else if (ted->find) {
+ if (ted->find) {
if (buffer == ted->find_buffer || buffer == ted->replace_buffer) {
if (c == CMD_NEWLINE)
find_next(ted);
@@ -380,6 +381,8 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
} else if (buffer) {
buffer_newline(buffer);
}
+ } else if (code_action_is_open(ted)) {
+ code_action_select(ted);
} else if (buffer) {
buffer_newline(buffer);
}
@@ -746,7 +749,13 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
buffer_print_undo_history(buffer);
break;
case CMD_CODE_ACTION:
- code_action_open(ted);
+ if (code_action_is_open(ted))
+ code_action_next(ted);
+ else
+ code_action_open(ted);
+ break;
+ case CMD_CODE_ACTION_PREV:
+ code_action_prev(ted);
break;
}
}
diff --git a/command.h b/command.h
index 2f60a7a..7a141a7 100644
--- a/command.h
+++ b/command.h
@@ -108,6 +108,7 @@ typedef enum {
CMD_FIND_USAGES,
CMD_RENAME_SYMBOL,
CMD_CODE_ACTION,
+ CMD_CODE_ACTION_PREV,
/// "go to definition of..." menu
CMD_GOTO_DEFINITION,
diff --git a/ide-code-action.c b/ide-code-action.c
index 6244756..4eef1ef 100644
--- a/ide-code-action.c
+++ b/ide-code-action.c
@@ -13,6 +13,7 @@ struct CodeAction {
BufferPos cursor_pos;
LSPResponse response;
Action *actions;
+ u32 cursor;
};
static bool ranges_touch(BufferPos p1, BufferPos p2, BufferPos q1, BufferPos q2) {
@@ -41,6 +42,7 @@ void code_action_open(Ted *ted) {
LSP *lsp = buffer_lsp(buffer);
if (!lsp) return;
autocomplete_close(ted);
+ c->cursor = 0;
c->which_buffer = buffer_lsp_document_id(buffer);
c->cursor_pos = buffer_cursor_pos(buffer);
BufferPos range_start = {0}, range_end = {0};
@@ -72,6 +74,20 @@ void code_action_open(Ted *ted) {
c->last_request = lsp_send_request(lsp, &req);
}
+void code_action_next(Ted *ted) {
+ CodeAction *c = ted->code_action;
+ u32 actions_count = arr_len(c->actions);
+ if (actions_count)
+ c->cursor = (c->cursor + 1) % actions_count;
+}
+
+void code_action_prev(Ted *ted) {
+ CodeAction *c = ted->code_action;
+ u32 actions_count = arr_len(c->actions);
+ if (actions_count)
+ c->cursor = c->cursor ? c->cursor - 1 : actions_count - 1;
+}
+
bool code_action_is_open(Ted *ted) {
CodeAction *c = ted->code_action;
return arr_len(c->response.data.code_action.actions) != 0;
@@ -151,10 +167,10 @@ static void code_action_perform(Ted *ted, const LSPCodeAction *action) {
code_action_close(ted);
}
-void code_action_select_best(Ted *ted) {
+void code_action_select(Ted *ted) {
CodeAction *c = ted->code_action;
- if (arr_len(c->actions))
- code_action_perform(ted, c->actions[0].lsp);
+ if (c->cursor < arr_len(c->actions))
+ code_action_perform(ted, c->actions[c->cursor].lsp);
}
void code_action_frame(Ted *ted) {
@@ -183,7 +199,7 @@ void code_action_frame(Ted *ted) {
return;
}
const Settings *settings = ted_active_settings(ted);
- Font *font = ted->font, *font_bold = ted->font_bold;
+ Font *font = ted->font;
float char_height = text_font_char_height(font);
float padding = settings->padding;
float border_thickness = settings->border_thickness;
@@ -214,8 +230,9 @@ void code_action_frame(Ted *ted) {
const Action *selected_action = NULL;
arr_foreach_ptr(c->actions, const Action, action) {
Rect entry_rect = {{x, y}, {panel_width, char_height}};
- if (rect_contains_point(entry_rect, ted->mouse_pos)) {
- // hovering over this entry
+ if (rect_contains_point(entry_rect, ted->mouse_pos)
+ || c->cursor == (u32)(action - c->actions)) {
+ // hovering/cursoring over this entry
ted->cursor = ted->cursor_hand;
gl_geometry_rect(entry_rect, settings_color(settings, COLOR_AUTOCOMPLETE_HL));
}
@@ -228,20 +245,12 @@ void code_action_frame(Ted *ted) {
gl_geometry_rect(border, settings_color(settings, COLOR_AUTOCOMPLETE_BORDER));
y += border_thickness;
};
- text_utf8(action == c->actions ? font_bold : font,
- action->name, x + padding, y, settings_color(settings, COLOR_TEXT));
- if (action == c->actions) {
- // action we think is best
- text_utf8_anchored(font, "(Enter)",
- panel_rect.pos.x + panel_rect.size.x - padding, y,
- settings_color(settings, COLOR_COMMENT),
- ANCHOR_TOP_RIGHT);
- }
+ text_utf8(font, action->name, x + padding, y,
+ settings_color(settings, COLOR_TEXT));
y += char_height;
}
gl_geometry_draw();
text_render(font);
- text_render(font_bold);
if (selected_action) {
code_action_perform(ted, selected_action->lsp);
} else {
diff --git a/lsp-parse.c b/lsp-parse.c
index bb4a10d..3c956e9 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -1109,7 +1109,7 @@ static bool parse_command(LSP *lsp, LSPResponse *response, const JSON *json, JSO
command_out->kind = LSP_COMMAND_WORKSPACE_EDIT;
return true;
}
- lsp_set_error(lsp, "Unrecognized command: %s\n", command);
+ fprintf(stderr, "Unrecognized command: %s\n", command);
(void)command_out;
return false;
}
diff --git a/main.c b/main.c
index 25cfca0..718430c 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
FUTURE FEATURES:
-- LSP "actions"
- wrap-text command
- path-specific extensions
- more tests
diff --git a/ted.cfg b/ted.cfg
index 5565c82..970eeb9 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -346,7 +346,10 @@ Ctrl+Space = :autocomplete
Ctrl+Shift+Space = :autocomplete-back
Ctrl+u = :find-usages
Ctrl+r = :rename-symbol
+# Show "code action" suggestions (refactoring, quick fixes, etc.) / move code action cursor forwards
Alt+Space = :code-action
+# Move code action cursor backwards
+Alt+Shift+Space = :code-action-prev
Ctrl+z = :undo
Ctrl+Shift+z = :redo
diff --git a/ted.h b/ted.h
index 5432411..b465ab7 100644
--- a/ted.h
+++ b/ted.h
@@ -935,8 +935,12 @@ void code_action_open(Ted *ted);
void code_action_close(Ted *ted);
/// Are code actions being shown?
bool code_action_is_open(Ted *ted);
-/// Select best code action
-void code_action_select_best(Ted *ted);
+/// Select current code action
+void code_action_select(Ted *ted);
+/// Move code action cursor forwards
+void code_action_next(Ted *ted);
+/// Move code action cursor backwards
+void code_action_prev(Ted *ted);
// === ide-definitions.c ===
/// cancel the last go-to-definition / find symbols request.