diff --git a/Makefile b/Makefile index 7988e37..03a2ad4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ APP_NAME := graptos APP_ID := io.github.graptos.Editor -VERSION := 0.23.82 +VERSION := 0.23.83 PREFIX ?= /usr/local CC ?= cc BUILD_DIR := build diff --git a/data/plugins/beancount-tools/beancount_tools.c b/data/plugins/beancount-tools/beancount_tools.c index a25aaa0..caa6c17 100644 --- a/data/plugins/beancount-tools/beancount_tools.c +++ b/data/plugins/beancount-tools/beancount_tools.c @@ -44,7 +44,7 @@ gboolean graptos_plugin_register(GraptosPluginHost *host) { t_done = graptos_plugin_host_register_editor_line_command_with_shortcut(host, "beancount-complete", "Beancount Complete", - "Ctrl+Alt+B", + "Ctrl+Shift+X", show_beancount_completion, NULL, NULL) && t_done; diff --git a/src/codex_panel.c b/src/codex_panel.c index 857757e..a6bc12f 100644 --- a/src/codex_panel.c +++ b/src/codex_panel.c @@ -709,12 +709,15 @@ CodexPanel *codex_panel_new(EditorWindow *win) { gtk_revealer_set_transition_duration(GTK_REVEALER(panel->revealer), 0u); gtk_revealer_set_reveal_child(GTK_REVEALER(panel->revealer), FALSE); gtk_widget_set_size_request(panel->revealer, 340, -1); + gtk_widget_set_hexpand(panel->revealer, FALSE); + gtk_widget_set_halign(panel->revealer, GTK_ALIGN_FILL); gtk_widget_set_visible(panel->revealer, FALSE); panel->visible = FALSE; GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); gtk_widget_add_css_class(box, "graptos-codex-panel"); gtk_widget_set_size_request(box, 340, -1); + gtk_widget_set_hexpand(box, FALSE); GtkWidget *header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); GtkWidget *title = gtk_label_new("Codex"); @@ -792,7 +795,25 @@ CodexPanel *codex_panel_new(EditorWindow *win) { g_object_set_data(G_OBJECT(allow), "decision", "accept"); gtk_box_append(GTK_BOX(approval_actions), deny); gtk_box_append(GTK_BOX(approval_actions), allow); - gtk_box_append(GTK_BOX(panel->approval_box), panel->approval_label); + GtkWidget *approval_scroll = gtk_scrolled_window_new(); + gtk_widget_add_css_class(approval_scroll, "graptos-codex-approval-scroll"); + gtk_widget_set_size_request(approval_scroll, -1, 120); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(approval_scroll), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(approval_scroll), + FALSE); + gtk_scrolled_window_set_propagate_natural_width(GTK_SCROLLED_WINDOW(approval_scroll), + FALSE); + gtk_label_set_wrap_mode(GTK_LABEL(panel->approval_label), + PANGO_WRAP_WORD_CHAR); + gtk_label_set_max_width_chars(GTK_LABEL(panel->approval_label), 42); + gtk_label_set_selectable(GTK_LABEL(panel->approval_label), TRUE); + gtk_widget_set_hexpand(panel->approval_label, TRUE); + gtk_widget_set_halign(panel->approval_label, GTK_ALIGN_FILL); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(approval_scroll), + panel->approval_label); + gtk_box_append(GTK_BOX(panel->approval_box), approval_scroll); gtk_box_append(GTK_BOX(panel->approval_box), approval_actions); gtk_widget_set_visible(panel->approval_box, FALSE); gtk_box_append(GTK_BOX(box), panel->approval_box); diff --git a/src/editor_tab_keys.c b/src/editor_tab_keys.c index 6b2e8e1..5fcbf1b 100644 --- a/src/editor_tab_keys.c +++ b/src/editor_tab_keys.c @@ -476,6 +476,39 @@ static gboolean key_event_is_plain_editor_text(GdkModifierType state) { return (state & blocked) == 0; } +static char *plugin_shortcut_for_key_event(guint keyval, + GdkModifierType state) { + gboolean ctrl = (state & GDK_CONTROL_MASK) != 0; + gboolean alt = (state & GDK_ALT_MASK) != 0; + gboolean shift = (state & GDK_SHIFT_MASK) != 0; + gboolean meta = (state & GDK_META_MASK) != 0; + gboolean super = (state & GDK_SUPER_MASK) != 0; + gboolean hyper = (state & GDK_HYPER_MASK) != 0; + if (!ctrl && !alt && !shift && !meta && !super && !hyper) return NULL; + + guint key = gdk_keyval_to_upper(keyval); + if (key == GDK_KEY_Control_L || key == GDK_KEY_Control_R || + key == GDK_KEY_Alt_L || key == GDK_KEY_Alt_R || + key == GDK_KEY_Shift_L || key == GDK_KEY_Shift_R || + key == GDK_KEY_Meta_L || key == GDK_KEY_Meta_R || + key == GDK_KEY_Super_L || key == GDK_KEY_Super_R || + key == GDK_KEY_Hyper_L || key == GDK_KEY_Hyper_R) { + return NULL; + } + + const char *name = gdk_keyval_name(key); + if (!name || !name[0]) return NULL; + GString *shortcut = g_string_new(NULL); + if (ctrl) g_string_append(shortcut, "Ctrl+"); + if (alt) g_string_append(shortcut, "Alt+"); + if (shift) g_string_append(shortcut, "Shift+"); + if (meta) g_string_append(shortcut, "Meta+"); + if (super) g_string_append(shortcut, "Super+"); + if (hyper) g_string_append(shortcut, "Hyper+"); + g_string_append(shortcut, name); + return g_string_free(shortcut, FALSE); +} + /** * @brief Text for keyval. * @details Editor code runs in response to fast input, delayed timeouts, and background language work. The notes here mark the boundary between immediate GTK state and deferred refresh paths so latency fixes do not turn into stale-widget bugs. @@ -733,6 +766,18 @@ gboolean on_text_view_key_pressed(GtkEventControllerKey *controller, if (debug_typing) g_message("Typing: key-handled action=add-note"); return TRUE; } + g_autofree char *plugin_shortcut = plugin_shortcut_for_key_event(keyval, state); + if (plugin_shortcut && tab->win && tab->win->plugins && + graptos_plugin_registry_run_shortcut(tab->win->plugins, + tab, + plugin_shortcut, + 0u)) { + if (debug_typing) { + g_message("Typing: key-handled action=plugin-shortcut shortcut=%s", + plugin_shortcut); + } + return TRUE; + } if (ctrl && alt && key == GDK_KEY_p) { gboolean handled = tab->win && tab->win->plugins ? graptos_plugin_registry_run_shortcut(tab->win->plugins, diff --git a/src/ui/ui_base_css.inc.c b/src/ui/ui_base_css.inc.c index d1c802a..cb86162 100644 --- a/src/ui/ui_base_css.inc.c +++ b/src/ui/ui_base_css.inc.c @@ -229,6 +229,10 @@ void graptos_apply_css(void) { " background: alpha(currentColor, 0.10);" " padding: 8px;" "}" + ".graptos-codex-approval-scroll {" + " min-height: 72px;" + " max-height: 160px;" + "}" ".graptos-codex-review {" " border: 1px solid alpha(currentColor, 0.55);" " background: alpha(currentColor, 0.08);"