diff --git a/src/app.h b/src/app.h index 8980062..bcbdcb6 100644 --- a/src/app.h +++ b/src/app.h @@ -1,3 +1,8 @@ +/** + * @file src/app.h + * @brief Main application window state and public window API. + */ + #ifndef CLEAF_APP_H #define CLEAF_APP_H @@ -6,125 +11,173 @@ #include "syntax.h" #ifndef APP_VERSION -#define APP_VERSION "0.16.6" +#define APP_VERSION "0.16.3" #endif +/** + * @brief Cleaf app id macro. + */ #define CLEAF_APP_ID "io.github.cleaf.Editor" +/** + * @brief App type definition. + */ typedef struct _EditorWindow { - GtkApplication *application; - GtkWidget *window; - GtkWidget *top_title_label; - GtkWidget *notebook; - GtkWidget *project_revealer; - GtkWidget *project_list; - GHashTable *project_expanded; - GHashTable *locked_paths; - GHashTable *git_file_status; /* short Git marker */ - GtkWidget *status_label; - GtkWidget *syntax_combo; - GtkWidget *indent_status_label; - GtkWidget *indent_dropdown; - GtkWidget *autocomplete_button; - GtkWidget *autosave_button; - GtkWidget *backup_button; - GtkWidget *minimap_button; - GtkWidget *preview_button; - GtkWidget *syntax_override_button; - GtkWidget *search_revealer; - GtkWidget *tool_revealer; - GtkWidget *tool_panel; - GtkWidget *find_entry; - GtkWidget *replace_label; - GtkWidget *replace_entry; - GtkWidget *replace_button; - GtkWidget *replace_all_button; - GPtrArray *syntaxes; /* Syntax definitions */ - gboolean syntax_combo_updating; - gboolean controls_updating; - gboolean replace_mode; - guint tab_width; - gboolean insert_spaces; - gboolean autocomplete_enabled; - gboolean auto_save_enabled; - gboolean backup_enabled; - gboolean use_system_interface_font; - gboolean minimap_enabled; - gboolean preview_enabled; - gboolean use_gtksourceview_highlighting; /* GtkSourceView stays enabled */ - gboolean use_yaml_style_overrides; - char *editor_bg_color; - char *editor_fg_color; - char *editor_gutter_bg_color; - char *editor_gutter_fg_color; - char *editor_current_line_bg_color; - char *editor_selection_bg_color; - char *editor_selection_fg_color; - char *editor_cursor_color; - char *sidebar_bg_color; - char *tabbar_bg_color; - char *tabbar_fg_color; - char *tab_active_bg_color; - char *tab_active_fg_color; - char *topbar_bg_color; - char *topbar_fg_color; - char *bottombar_bg_color; - char *bottombar_fg_color; - char *button_bg_color; - char *button_fg_color; - char *button_hover_bg_color; - char *button_active_bg_color; - char *input_bg_color; - char *input_fg_color; - char *input_border_color; - char *project_tree_fg_color; - char *project_tree_selected_bg_color; - char *project_tree_selected_fg_color; - char *scroll_preview_bg_color; - char *scroll_preview_fg_color; - char *popover_bg_color; - char *ref_popover_bg_color; - char *ref_popover_fg_color; - char *ref_popover_heading_color; - char *ref_popover_title_color; - char *ref_popover_kind_color; - char *ref_popover_snippet_color; - char *completion_popover_bg_color; - char *completion_popover_fg_color; - char *completion_popover_detail_color; - char *completion_selection_bg_color; - char *completion_selection_fg_color; - char *dialog_bg_color; - char *dialog_fg_color; - char *dialog_border_color; - char *dialog_title_color; - char *search_match_bg_color; - char *search_match_fg_color; - char *diagnostic_warning_bg_color; - char *diagnostic_warning_fg_color; - char *codex_preview_bg_color; - char *codex_preview_fg_color; - char *codex_prompt_bg_color; - char *project_root; - GPtrArray *project_roots; /* char*: all open project root */ - guint auto_save_timeout; - struct _CodexClient *codex_client; - struct _CodexPanel *codex_panel; + GtkApplication *application; /**< Application. */ + GtkWidget *window; /**< Window. */ + GtkWidget *top_title_label; /**< Top title label. */ + GtkWidget *notebook; /**< Notebook. */ + GtkWidget *project_revealer; /**< Project revealer. */ + GtkWidget *project_list; /**< Project list. */ + GHashTable *project_expanded; /**< Project expanded. */ + GHashTable *locked_paths; /**< Locked paths. */ + GHashTable *git_file_status; /**< short Git marker. */ + GtkWidget *status_label; /**< Status label. */ + GtkWidget *syntax_combo; /**< Syntax combo. */ + GtkWidget *indent_status_label; /**< Indent status label. */ + GtkWidget *indent_dropdown; /**< Indent dropdown. */ + GtkWidget *autocomplete_button; /**< Autocomplete button. */ + GtkWidget *autosave_button; /**< Autosave button. */ + GtkWidget *backup_button; /**< Backup button. */ + GtkWidget *minimap_button; /**< Minimap button. */ + GtkWidget *preview_button; /**< Preview button. */ + GtkWidget *syntax_override_button; /**< Syntax override button. */ + GtkWidget *search_revealer; /**< Search revealer. */ + GtkWidget *tool_revealer; /**< Tool revealer. */ + GtkWidget *tool_panel; /**< Tool panel. */ + GtkWidget *find_entry; /**< Find entry. */ + GtkWidget *replace_label; /**< Replace label. */ + GtkWidget *replace_entry; /**< Replace entry. */ + GtkWidget *replace_button; /**< Replace button. */ + GtkWidget *replace_all_button; /**< Replace all button. */ + GPtrArray *syntaxes; /**< Syntax definitions. */ + gboolean syntax_combo_updating; /**< Syntax combo updating. */ + gboolean controls_updating; /**< Controls updating. */ + gboolean replace_mode; /**< Replace mode. */ + guint tab_width; /**< Tab width. */ + gboolean insert_spaces; /**< Insert spaces. */ + gboolean autocomplete_enabled; /**< Autocomplete enabled. */ + gboolean auto_save_enabled; /**< Auto save enabled. */ + gboolean backup_enabled; /**< Backup enabled. */ + gboolean use_system_interface_font; /**< Use system interface font. */ + gboolean minimap_enabled; /**< Minimap enabled. */ + gboolean preview_enabled; /**< Preview enabled. */ + gboolean use_gtksourceview_highlighting; /**< GtkSourceView stays enabled. */ + gboolean use_yaml_style_overrides; /**< Use yaml style overrides. */ + char *editor_bg_color; /**< Editor bg color. */ + char *editor_fg_color; /**< Editor fg color. */ + char *editor_gutter_bg_color; /**< Editor gutter bg color. */ + char *editor_gutter_fg_color; /**< Editor gutter fg color. */ + char *editor_current_line_bg_color; /**< Editor current line bg color. */ + char *editor_selection_bg_color; /**< Editor selection bg color. */ + char *editor_selection_fg_color; /**< Editor selection fg color. */ + char *editor_cursor_color; /**< Editor cursor color. */ + char *sidebar_bg_color; /**< Sidebar bg color. */ + char *tabbar_bg_color; /**< Tabbar bg color. */ + char *tabbar_fg_color; /**< Tabbar fg color. */ + char *tab_active_bg_color; /**< Tab active bg color. */ + char *tab_active_fg_color; /**< Tab active fg color. */ + char *topbar_bg_color; /**< Topbar bg color. */ + char *topbar_fg_color; /**< Topbar fg color. */ + char *bottombar_bg_color; /**< Bottombar bg color. */ + char *bottombar_fg_color; /**< Bottombar fg color. */ + char *button_bg_color; /**< Button bg color. */ + char *button_fg_color; /**< Button fg color. */ + char *button_hover_bg_color; /**< Button hover bg color. */ + char *button_active_bg_color; /**< Button active bg color. */ + char *input_bg_color; /**< Input bg color. */ + char *input_fg_color; /**< Input fg color. */ + char *input_border_color; /**< Input border color. */ + char *project_tree_fg_color; /**< Project tree fg color. */ + char *project_tree_selected_bg_color; /**< Project tree selected bg color. */ + char *project_tree_selected_fg_color; /**< Project tree selected fg color. */ + char *scroll_preview_bg_color; /**< Scroll preview bg color. */ + char *scroll_preview_fg_color; /**< Scroll preview fg color. */ + char *popover_bg_color; /**< Popover bg color. */ + char *ref_popover_bg_color; /**< Ref popover bg color. */ + char *ref_popover_fg_color; /**< Ref popover fg color. */ + char *ref_popover_heading_color; /**< Ref popover heading color. */ + char *ref_popover_title_color; /**< Ref popover title color. */ + char *ref_popover_kind_color; /**< Ref popover kind color. */ + char *ref_popover_snippet_color; /**< Ref popover snippet color. */ + char *completion_popover_bg_color; /**< Completion popover bg color. */ + char *completion_popover_fg_color; /**< Completion popover fg color. */ + char *completion_popover_detail_color; /**< Completion popover detail color. */ + char *completion_selection_bg_color; /**< Completion selection bg color. */ + char *completion_selection_fg_color; /**< Completion selection fg color. */ + char *dialog_bg_color; /**< Dialog bg color. */ + char *dialog_fg_color; /**< Dialog fg color. */ + char *dialog_border_color; /**< Dialog border color. */ + char *dialog_title_color; /**< Dialog title color. */ + char *search_match_bg_color; /**< Search match bg color. */ + char *search_match_fg_color; /**< Search match fg color. */ + char *diagnostic_warning_bg_color; /**< Diagnostic warning bg color. */ + char *diagnostic_warning_fg_color; /**< Diagnostic warning fg color. */ + char *codex_preview_bg_color; /**< Codex preview bg color. */ + char *codex_preview_fg_color; /**< Codex preview fg color. */ + char *codex_prompt_bg_color; /**< Codex prompt bg color. */ + char *project_root; /**< Project root. */ + GPtrArray *project_roots; /**< char*: all open project root. */ + guint auto_save_timeout; /**< Auto save timeout. */ + struct _CodexClient *codex_client; /**< Codex client. */ + struct _CodexPanel *codex_panel; /**< Codex panel. */ } EditorWindow; +/** + * @brief App window new. + */ EditorWindow *app_window_new(GtkApplication *application); +/** + * @brief App window free. + */ void app_window_free(EditorWindow *win); +/** + * @brief App window update ui. + */ void app_window_update_ui(EditorWindow *win); +/** + * @brief App window reload syntaxes. + */ void app_window_reload_syntaxes(EditorWindow *win); +/** + * @brief App window open file. + */ gboolean app_window_open_file(EditorWindow *win, const char *path); +/** + * @brief App window current tab. + */ EditorTab *app_window_current_tab(EditorWindow *win); +/** + * @brief App window add tab. + */ void app_window_add_tab(EditorWindow *win, EditorTab *tab, gboolean switch_to_tab); +/** + * @brief App window close tab. + */ void app_window_close_tab(EditorWindow *win, EditorTab *tab); +/** + * @brief App window close all tabs. + */ gboolean app_window_close_all_tabs(EditorWindow *win); +/** + * @brief App window set status. + */ void app_window_set_status(EditorWindow *win, const char *text); +/** + * @brief App window is file locked. + */ gboolean app_window_is_file_locked(EditorWindow *win, const char *path); +/** + * @brief App window set file locked. + */ void app_window_set_file_locked(EditorWindow *win, const char *path, gboolean locked); +/** + * @brief App window note path renamed. + */ void app_window_note_path_renamed(EditorWindow *win, const char *old_path, const char *new_path); +/** + * @brief App window gtk. + */ GtkWindow *app_window_gtk(EditorWindow *win); #endif /* CLEAF_APP_H */ diff --git a/src/app_actions.c b/src/app_actions.c index e84d368..cb68645 100644 --- a/src/app_actions.c +++ b/src/app_actions.c @@ -1,3 +1,8 @@ +/** + * @file src/app_actions.c + * @brief Application action implementation composition unit. + */ + #include "app_private.h" #include diff --git a/src/app_core.c b/src/app_core.c index 2ca9d39..2944134 100644 --- a/src/app_core.c +++ b/src/app_core.c @@ -1,3 +1,8 @@ +/** + * @file src/app_core.c + * @brief Application window implementation composition unit. + */ + #include "app_private.h" diff --git a/src/app_layout.c b/src/app_layout.c index e0b9da4..afdcea0 100644 --- a/src/app_layout.c +++ b/src/app_layout.c @@ -1,7 +1,15 @@ +/** + * @file src/app_layout.c + * @brief Top, bottom, and tool panel layout construction. + */ + #include "app_private.h" #include +/** + * @brief Menu small label. + */ GtkWidget *menu_small_label(const char *text) { GtkWidget *label = gtk_label_new(text ? text : ""); gtk_label_set_xalign(GTK_LABEL(label), 0.0f); @@ -10,6 +18,9 @@ GtkWidget *menu_small_label(const char *text) { } +/** + * @brief Build top bar. + */ GtkWidget *build_top_bar(EditorWindow *win) { GtkWidget *top = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); gtk_widget_add_css_class(top, "cleaf-top"); @@ -32,6 +43,9 @@ GtkWidget *build_top_bar(EditorWindow *win) { } +/** + * @brief Build search panel. + */ GtkWidget *build_search_panel(EditorWindow *win) { win->search_revealer = gtk_revealer_new(); gtk_revealer_set_transition_type(GTK_REVEALER(win->search_revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP); @@ -71,6 +85,9 @@ GtkWidget *build_search_panel(EditorWindow *win) { } +/** + * @brief Tool button new. + */ static GtkWidget *tool_button_new(const char *label, const char *tooltip, GCallback callback, @@ -78,12 +95,18 @@ static GtkWidget *tool_button_new(const char *label, return cleaf_flat_button_new(label, tooltip, callback, data); } +/** + * @brief Action toggle codex panel. + */ void action_toggle_codex_panel(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; if (win) codex_panel_toggle(win->codex_panel); } +/** + * @brief Tool title new. + */ static GtkWidget *tool_title_new(const char *title) { GtkWidget *label = gtk_label_new(title ? title : ""); gtk_label_set_xalign(GTK_LABEL(label), 0.0f); @@ -91,6 +114,9 @@ static GtkWidget *tool_title_new(const char *title) { return label; } +/** + * @brief Tool panel reset widget pointers. + */ static void tool_panel_reset_widget_pointers(EditorWindow *win) { if (!win) return; win->syntax_combo = NULL; @@ -104,6 +130,9 @@ static void tool_panel_reset_widget_pointers(EditorWindow *win) { win->syntax_override_button = NULL; } +/** + * @brief Tool panel clear. + */ static void tool_panel_clear(EditorWindow *win) { if (!win || !win->tool_panel) return; tool_panel_reset_widget_pointers(win); @@ -115,6 +144,9 @@ static void tool_panel_clear(EditorWindow *win) { } } +/** + * @brief Tool panel begin. + */ static void tool_panel_begin(EditorWindow *win, const char *title) { if (!win || !win->tool_panel) return; tool_panel_clear(win); @@ -122,6 +154,9 @@ static void tool_panel_begin(EditorWindow *win, const char *title) { gtk_box_append(GTK_BOX(win->tool_panel), cleaf_separator_new()); } +/** + * @brief Hide tool panel. + */ static void hide_tool_panel(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -130,6 +165,9 @@ static void hide_tool_panel(GtkWidget *widget, gpointer user_data) { } } +/** + * @brief Tool panel show ready. + */ static void tool_panel_show_ready(EditorWindow *win) { if (!win || !win->tool_panel || !win->tool_revealer) return; GtkWidget *spacer = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); @@ -139,6 +177,9 @@ static void tool_panel_show_ready(EditorWindow *win) { gtk_revealer_set_reveal_child(GTK_REVEALER(win->tool_revealer), TRUE); } +/** + * @brief Tool switch new. + */ static GtkWidget *tool_switch_new(const char *label_text, gboolean active, GCallback notify_cb, @@ -163,6 +204,9 @@ static GtkWidget *tool_switch_new(const char *label_text, return row; } +/** + * @brief On indent dropdown changed. + */ static void on_indent_dropdown_changed(GtkDropDown *drop_down, GParamSpec *pspec, gpointer user_data) { @@ -188,6 +232,9 @@ static void on_indent_dropdown_changed(GtkDropDown *drop_down, } } +/** + * @brief On autocomplete switch changed. + */ static void on_autocomplete_switch_changed(GtkSwitch *sw, GParamSpec *pspec, gpointer user_data) { @@ -199,6 +246,9 @@ static void on_autocomplete_switch_changed(GtkSwitch *sw, cleaf_config_save(win); } +/** + * @brief On autosave switch changed. + */ static void on_autosave_switch_changed(GtkSwitch *sw, GParamSpec *pspec, gpointer user_data) { @@ -210,6 +260,9 @@ static void on_autosave_switch_changed(GtkSwitch *sw, cleaf_config_save(win); } +/** + * @brief On backup switch changed. + */ static void on_backup_switch_changed(GtkSwitch *sw, GParamSpec *pspec, gpointer user_data) { @@ -221,6 +274,9 @@ static void on_backup_switch_changed(GtkSwitch *sw, cleaf_config_save(win); } +/** + * @brief On minimap switch changed. + */ static void on_minimap_switch_changed(GtkSwitch *sw, GParamSpec *pspec, gpointer user_data) { @@ -232,6 +288,9 @@ static void on_minimap_switch_changed(GtkSwitch *sw, cleaf_config_save(win); } +/** + * @brief On preview switch changed. + */ static void on_preview_switch_changed(GtkSwitch *sw, GParamSpec *pspec, gpointer user_data) { @@ -243,6 +302,9 @@ static void on_preview_switch_changed(GtkSwitch *sw, cleaf_config_save(win); } +/** + * @brief On yaml override switch changed. + */ static void on_yaml_override_switch_changed(GtkSwitch *sw, GParamSpec *pspec, gpointer user_data) { @@ -265,6 +327,9 @@ static void on_yaml_override_switch_changed(GtkSwitch *sw, cleaf_config_save(win); } +/** + * @brief Show file tools. + */ static void show_file_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -276,6 +341,9 @@ static void show_file_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Show edit tools. + */ static void show_edit_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -287,6 +355,9 @@ static void show_edit_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Show indent tools. + */ static void show_indent_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -304,6 +375,9 @@ static void show_indent_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Show syntax tools. + */ static void show_syntax_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -324,6 +398,9 @@ static void show_syntax_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Show intelligence tools. + */ static void show_intelligence_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -336,6 +413,9 @@ static void show_intelligence_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Show safety tools. + */ static void show_safety_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -348,6 +428,9 @@ static void show_safety_tools(GtkWidget *widget, gpointer user_data) { } +/** + * @brief Show git tools. + */ static void show_git_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -367,6 +450,9 @@ static void show_git_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Show view tools. + */ static void show_view_tools(GtkWidget *widget, gpointer user_data) { (void)widget; EditorWindow *win = user_data; @@ -381,6 +467,9 @@ static void show_view_tools(GtkWidget *widget, gpointer user_data) { tool_panel_show_ready(win); } +/** + * @brief Build tool panel. + */ GtkWidget *build_tool_panel(EditorWindow *win) { win->tool_revealer = gtk_revealer_new(); gtk_revealer_set_transition_type(GTK_REVEALER(win->tool_revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP); @@ -394,6 +483,9 @@ GtkWidget *build_tool_panel(EditorWindow *win) { return win->tool_revealer; } +/** + * @brief Build bottom bar. + */ GtkWidget *build_bottom_bar(EditorWindow *win) { GtkWidget *bottom = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); gtk_widget_add_css_class(bottom, "cleaf-bottom"); diff --git a/src/app_private.h b/src/app_private.h index b486a6f..762d3da 100644 --- a/src/app_private.h +++ b/src/app_private.h @@ -1,3 +1,8 @@ +/** + * @file src/app_private.h + * @brief Internal application window helpers and action declarations. + */ + #ifndef CLEAF_APP_PRIVATE_H #define CLEAF_APP_PRIVATE_H @@ -11,68 +16,251 @@ #include "codex_panel.h" #include "codex_review.h" +/** + * @brief Update policy buttons. + */ void update_policy_buttons(EditorWindow *win); +/** + * @brief Apply tab policy to all tabs. + */ void apply_tab_policy_to_all_tabs(EditorWindow *win); +/** + * @brief App window apply css. + */ void app_window_apply_css(EditorWindow *win); +/** + * @brief Apply preferences to all tabs. + */ void apply_preferences_to_all_tabs(EditorWindow *win); +/** + * @brief Auto save timeout cb. + */ gboolean auto_save_timeout_cb(gpointer user_data); +/** + * @brief Restart auto save timer. + */ void restart_auto_save_timer(EditorWindow *win); +/** + * @brief Menu small label. + */ GtkWidget *menu_small_label(const char *text); +/** + * @brief Build top bar. + */ GtkWidget *build_top_bar(EditorWindow *win); +/** + * @brief Build search panel. + */ GtkWidget *build_search_panel(EditorWindow *win); +/** + * @brief Build tool panel. + */ GtkWidget *build_tool_panel(EditorWindow *win); +/** + * @brief Build bottom bar. + */ GtkWidget *build_bottom_bar(EditorWindow *win); +/** + * @brief Action toggle codex panel. + */ void action_toggle_codex_panel(GtkWidget *widget, gpointer user_data); +/** + * @brief Combo index for syntax. + */ int combo_index_for_syntax(EditorWindow *win, SyntaxDef *syntax); +/** + * @brief Populate syntax combo. + */ void populate_syntax_combo(EditorWindow *win, EditorTab *tab); +/** + * @brief Set search panel. + */ void set_search_panel(EditorWindow *win, gboolean visible, gboolean replace_mode); +/** + * @brief Action new. + */ void action_new(GtkWidget *widget, gpointer user_data); +/** + * @brief Action open. + */ void action_open(GtkWidget *widget, gpointer user_data); +/** + * @brief Action open folder. + */ void action_open_folder(GtkWidget *widget, gpointer user_data); +/** + * @brief Action open folder new instance. + */ void action_open_folder_new_instance(GtkWidget *widget, gpointer user_data); +/** + * @brief Action save. + */ void action_save(GtkWidget *widget, gpointer user_data); +/** + * @brief Action save as. + */ void action_save_as(GtkWidget *widget, gpointer user_data); +/** + * @brief Action show find. + */ void action_show_find(GtkWidget *widget, gpointer user_data); +/** + * @brief Action show replace. + */ void action_show_replace(GtkWidget *widget, gpointer user_data); +/** + * @brief Action hide search. + */ void action_hide_search(GtkWidget *widget, gpointer user_data); +/** + * @brief Action find next. + */ void action_find_next(GtkWidget *widget, gpointer user_data); +/** + * @brief Action find prev. + */ void action_find_prev(GtkWidget *widget, gpointer user_data); +/** + * @brief Action replace. + */ void action_replace(GtkWidget *widget, gpointer user_data); +/** + * @brief Action replace all. + */ void action_replace_all(GtkWidget *widget, gpointer user_data); +/** + * @brief Action comment. + */ void action_comment(GtkWidget *widget, gpointer user_data); +/** + * @brief Action reload syntax. + */ void action_reload_syntax(GtkWidget *widget, gpointer user_data); +/** + * @brief Action syntax diagnostics. + */ void action_syntax_diagnostics(GtkWidget *widget, gpointer user_data); +/** + * @brief Set tab policy. + */ void set_tab_policy(EditorWindow *win, guint width, gboolean insert_spaces); +/** + * @brief Action tab spaces 2. + */ void action_tab_spaces_2(GtkWidget *widget, gpointer user_data); +/** + * @brief Action tab spaces 4. + */ void action_tab_spaces_4(GtkWidget *widget, gpointer user_data); +/** + * @brief Action tab spaces 8. + */ void action_tab_spaces_8(GtkWidget *widget, gpointer user_data); +/** + * @brief Action tab hard tabs. + */ void action_tab_hard_tabs(GtkWidget *widget, gpointer user_data); +/** + * @brief Action toggle autocomplete. + */ void action_toggle_autocomplete(GtkWidget *widget, gpointer user_data); +/** + * @brief Action toggle autosave. + */ void action_toggle_autosave(GtkWidget *widget, gpointer user_data); +/** + * @brief Action toggle backup. + */ void action_toggle_backup(GtkWidget *widget, gpointer user_data); +/** + * @brief Rgba to hex. + */ char *rgba_to_hex(const GdkRGBA *rgba); +/** + * @brief Choose color for slot. + */ void choose_color_for_slot(EditorWindow *win, GtkWidget *parent_widget, const char *title, char **slot); +/** + * @brief Action choose background. + */ void action_choose_background(GtkWidget *widget, gpointer user_data); +/** + * @brief Action choose sidebar background. + */ void action_choose_sidebar_background(GtkWidget *widget, gpointer user_data); +/** + * @brief Action choose tabbar background. + */ void action_choose_tabbar_background(GtkWidget *widget, gpointer user_data); +/** + * @brief Action choose scroll preview background. + */ void action_choose_scroll_preview_background(GtkWidget *widget, gpointer user_data); +/** + * @brief Action choose popover background. + */ void action_choose_popover_background(GtkWidget *widget, gpointer user_data); +/** + * @brief Action reset background. + */ void action_reset_background(GtkWidget *widget, gpointer user_data); +/** + * @brief Action reset all backgrounds. + */ void action_reset_all_backgrounds(GtkWidget *widget, gpointer user_data); +/** + * @brief Pref section. + */ GtkWidget *pref_section(const char *text); +/** + * @brief Pref tab label. + */ GtkWidget *pref_tab_label(const char *text); +/** + * @brief Action about. + */ void action_about(GtkWidget *widget, gpointer user_data); +/** + * @brief Action show preferences. + */ void action_show_preferences(GtkWidget *widget, gpointer user_data); +/** + * @brief Action project search. + */ void action_project_search(GtkWidget *widget, gpointer user_data); +/** + * @brief Action toggle minimap. + */ void action_toggle_minimap(GtkWidget *widget, gpointer user_data); +/** + * @brief Action toggle preview. + */ void action_toggle_preview(GtkWidget *widget, gpointer user_data); +/** + * @brief Action render latex. + */ void action_render_latex(GtkWidget *widget, gpointer user_data); +/** + * @brief On switch page. + */ void on_switch_page(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data); +/** + * @brief On syntax changed. + */ void on_syntax_changed(GtkDropDown *drop_down, GParamSpec *pspec, gpointer user_data); +/** + * @brief On window close request. + */ gboolean on_window_close_request(GtkWindow *window, gpointer user_data); +/** + * @brief Switch page delta. + */ void switch_page_delta(EditorWindow *win, int delta); +/** + * @brief On window key pressed. + */ gboolean on_window_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data); #endif /* CLEAF_APP_PRIVATE_H */ diff --git a/src/app_state.c b/src/app_state.c index 0026a6e..1216122 100644 --- a/src/app_state.c +++ b/src/app_state.c @@ -1,8 +1,16 @@ +/** + * @file src/app_state.c + * @brief Application preference, policy, and timer state helpers. + */ + #include "app_private.h" #include +/** + * @brief App window apply css. + */ void app_window_apply_css(EditorWindow *win) { if (!win) return; cleaf_apply_editor_css(win->editor_bg_color, win->editor_fg_color, @@ -52,11 +60,17 @@ void app_window_apply_css(EditorWindow *win) { win->use_system_interface_font); } +/** + * @brief Set switch active safely. + */ static void set_switch_active_safely(GtkWidget *widget, gboolean active) { if (!widget || !GTK_IS_SWITCH(widget)) return; gtk_switch_set_active(GTK_SWITCH(widget), active); } +/** + * @brief Update indent dropdown. + */ static void update_indent_dropdown(EditorWindow *win) { if (!win || !win->indent_dropdown || !GTK_IS_DROP_DOWN(win->indent_dropdown)) return; @@ -67,6 +81,9 @@ static void update_indent_dropdown(EditorWindow *win) { gtk_drop_down_set_selected(GTK_DROP_DOWN(win->indent_dropdown), selected); } +/** + * @brief Update policy buttons. + */ void update_policy_buttons(EditorWindow *win) { if (!win) return; @@ -92,6 +109,9 @@ void update_policy_buttons(EditorWindow *win) { } +/** + * @brief Apply tab policy to all tabs. + */ void apply_tab_policy_to_all_tabs(EditorWindow *win) { if (!win || !win->notebook) return; gint pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(win->notebook)); @@ -109,6 +129,9 @@ void apply_tab_policy_to_all_tabs(EditorWindow *win) { } +/** + * @brief Apply preferences to all tabs. + */ void apply_preferences_to_all_tabs(EditorWindow *win) { if (!win || !win->notebook) return; app_window_apply_css(win); @@ -128,6 +151,9 @@ void apply_preferences_to_all_tabs(EditorWindow *win) { } +/** + * @brief Auto save timeout cb. + */ gboolean auto_save_timeout_cb(gpointer user_data) { EditorWindow *win = user_data; if (!win || !win->auto_save_enabled || !win->notebook) return G_SOURCE_CONTINUE; @@ -147,6 +173,9 @@ gboolean auto_save_timeout_cb(gpointer user_data) { } +/** + * @brief Restart auto save timer. + */ void restart_auto_save_timer(EditorWindow *win) { if (!win) return; if (win->auto_save_timeout != 0u) { diff --git a/src/codex_client.c b/src/codex_client.c index 10b35a1..7876737 100644 --- a/src/codex_client.c +++ b/src/codex_client.c @@ -1,48 +1,39 @@ +/** + * @file src/codex_client.c + * @brief Codex process client and event bridge. + */ + #include "codex_client.h" #include #include "codex_protocol.h" -/* - * Note-to-self: Codex can use legacy applyPatchApproval: approved-denied - * We were sending accept-decline - * So clicking Allow once did not resume the Codex action correctly. - * We were also reading optional JSON fields with json_object_get_object_member() and json_object_get_array_member() - * without checking that the member existed first. Codex can send string IDs too. - * Allow once and Deny could send a response with the wrong ID and appear to do nothing. - * We now store the original approval request ID as a JsonNode. - * Send approval responses using the exact original ID type and value. - * Clear approval state safely after response or server resolution. - * This should fix the Codex freeze. - * - * We need to modulate AI-assistance. When implementing Claude or Mind2, - * we should not rewrite everything from scratch. At some point, all Codex code - * will be split into AI-UI and AI-specifics. +/** + * @brief Codex client type definition. */ - struct _CodexClient { - GSubprocess *process; - GDataInputStream *output; - GOutputStream *input; - GCancellable *cancellable; - CodexClientStatusFunc status_func; - CodexClientEventFunc event_func; - gpointer user_data; - CodexClientState state; - guint ref_count; - gboolean disposing; - guint64 next_request_id; - guint64 turn_request_id; - guint64 interrupt_request_id; - char *cwd; - char *thread_id; - char *turn_id; - gboolean turn_pending; - gboolean interrupt_pending; - guint64 approval_request_id; - JsonNode *approval_request_id_node; /* Storing exact ID node to prevent legacy string-ID drops */ - char *approval_method; + GSubprocess *process; /**< Process. */ + GDataInputStream *output; /**< Output. */ + GOutputStream *input; /**< Input. */ + GCancellable *cancellable; /**< Cancellable. */ + CodexClientStatusFunc status_func; /**< Status func. */ + CodexClientEventFunc event_func; /**< Event func. */ + gpointer user_data; /**< User data. */ + CodexClientState state; /**< State. */ + guint ref_count; /**< Ref count. */ + gboolean disposing; /**< Disposing. */ + guint64 next_request_id; /**< Next request id. */ + guint64 turn_request_id; /**< Turn request id. */ + guint64 interrupt_request_id; /**< Interrupt request id. */ + char *cwd; /**< Cwd. */ + char *thread_id; /**< Thread id. */ + char *turn_id; /**< Turn id. */ + gboolean turn_pending; /**< Turn pending. */ + gboolean interrupt_pending; /**< Interrupt pending. */ + guint64 approval_request_id; /**< Approval request id. */ + JsonNode *approval_request_id_node; /**< Approval request id node. */ + char *approval_method; /**< Approval method. */ }; enum { @@ -50,13 +41,22 @@ enum { THREAD_START_REQUEST_ID = 2 }; +/** + * @brief Codex client read next. + */ static void codex_client_read_next(CodexClient *client); +/** + * @brief Codex client ref. + */ static CodexClient *codex_client_ref(CodexClient *client) { if (client) client->ref_count++; - return client; + return client; /**< Client. */ } +/** + * @brief Codex client unref. + */ static void codex_client_unref(CodexClient *client) { if (!client || --client->ref_count != 0u) return; g_free(client->cwd); @@ -67,6 +67,9 @@ static void codex_client_unref(CodexClient *client) { g_free(client); } +/** + * @brief Codex client emit. + */ static void codex_client_emit(CodexClient *client, CodexClientEvent event, const char *text) { @@ -75,6 +78,9 @@ static void codex_client_emit(CodexClient *client, } } +/** + * @brief Codex client set state. + */ static void codex_client_set_state(CodexClient *client, CodexClientState state, const char *detail) { @@ -85,10 +91,13 @@ static void codex_client_set_state(CodexClient *client, } } +/** + * @brief Codex client write. + */ static gboolean codex_client_write(CodexClient *client, char *message) { if (!client || !client->input || !message) { g_free(message); - return FALSE; + return FALSE; /**< False. */ } GError *error = NULL; gboolean written = g_output_stream_write_all(client->input, @@ -103,9 +112,12 @@ static gboolean codex_client_write(CodexClient *client, char *message) { error ? error->message : "write failed"); g_clear_error(&error); } - return written; + return written; /**< Written. */ } +/** + * @brief Codex client start thread. + */ static void codex_client_start_thread(CodexClient *client) { JsonNode *params = codex_protocol_object_params(); JsonObject *object = json_node_get_object(params); @@ -116,7 +128,9 @@ static void codex_client_start_thread(CodexClient *client) { (void)codex_client_write(client, request); } -/* Legacy decline fallback wrapper for simple ID-based responses */ +/** + * @brief Codex client decline request. + */ static void codex_client_decline_request(CodexClient *client, guint64 id) { JsonNode *result = codex_protocol_object_params(); json_object_set_string_member(json_node_get_object(result), @@ -126,6 +140,9 @@ static void codex_client_decline_request(CodexClient *client, guint64 id) { (void)codex_client_write(client, response); } +/** + * @brief Codex client clear approval. + */ static void codex_client_clear_approval(CodexClient *client) { if (!client) return; client->approval_request_id = 0u; @@ -133,7 +150,9 @@ static void codex_client_clear_approval(CodexClient *client) { g_clear_pointer(&client->approval_method, g_free); } -/* Reconstructs a response by explicitly mirroring the exact incoming id type/node */ +/** + * @brief Codex client response for id. + */ static char *codex_client_response_for_id(JsonNode *id_node, JsonNode *result) { if (!id_node || !result) return NULL; JsonBuilder *builder = json_builder_new(); @@ -154,9 +173,12 @@ static char *codex_client_response_for_id(JsonNode *id_node, JsonNode *result) { json_node_free(root); g_object_unref(generator); g_object_unref(builder); - return line; + return line; /**< Line. */ } +/** + * @brief Codex json object member. + */ static JsonObject *codex_json_object_member(JsonObject *object, const char *member) { if (!object || !member || !json_object_has_member(object, member)) return NULL; @@ -164,6 +186,9 @@ static JsonObject *codex_json_object_member(JsonObject *object, return node && JSON_NODE_HOLDS_OBJECT(node) ? json_node_get_object(node) : NULL; } +/** + * @brief Codex json array member. + */ static JsonArray *codex_json_array_member(JsonObject *object, const char *member) { if (!object || !member || !json_object_has_member(object, member)) return NULL; @@ -171,7 +196,9 @@ static JsonArray *codex_json_array_member(JsonObject *object, return node && JSON_NODE_HOLDS_ARRAY(node) ? json_node_get_array(node) : NULL; } -/* Checks if incoming method string matches any known approval flavors */ +/** + * @brief Codex client method is approval. + */ static gboolean codex_client_method_is_approval(const char *method) { return method && (g_str_equal(method, "item/commandExecution/requestApproval") || @@ -180,13 +207,18 @@ static gboolean codex_client_method_is_approval(const char *method) { g_str_equal(method, "applyPatchApproval")); } +/** + * @brief Codex client method uses review decision. + */ static gboolean codex_client_method_uses_review_decision(const char *method) { return method && (g_str_equal(method, "execCommandApproval") || g_str_equal(method, "applyPatchApproval")); } -/* Maps internal accept/decline states into legacy approved/denied text strings */ +/** + * @brief Codex client response decision. + */ static const char *codex_client_response_decision(const char *method, const char *decision) { if (!codex_client_method_uses_review_decision(method)) return decision; @@ -194,9 +226,12 @@ static const char *codex_client_response_decision(const char *method, if (g_str_equal(decision, "acceptForSession")) return "approved_for_session"; if (g_str_equal(decision, "decline")) return "denied"; if (g_str_equal(decision, "cancel")) return "abort"; - return NULL; + return NULL; /**< Null. */ } +/** + * @brief Codex client command text. + */ static char *codex_client_command_text(JsonObject *params) { if (!params) return NULL; const char *command = json_object_get_string_member_with_default( @@ -215,6 +250,9 @@ static char *codex_client_command_text(JsonObject *params) { return g_string_free(out, FALSE); } +/** + * @brief Codex client file change count. + */ static guint codex_client_file_change_count(JsonObject *params) { if (!params) return 0u; JsonObject *changes = codex_json_object_member(params, "fileChanges"); @@ -223,6 +261,9 @@ static guint codex_client_file_change_count(JsonObject *params) { return array ? json_array_get_length(array) : 0u; } +/** + * @brief Codex client approval detail. + */ static char *codex_client_approval_detail(const char *method, JsonObject *params) { const char *reason = params @@ -239,7 +280,7 @@ static char *codex_client_approval_detail(const char *method, command ? command : reason ? reason : "", grant_root ? " (extra permissions requested)" : ""); g_free(command); - return detail; + return detail; /**< Detail. */ } guint count = codex_client_file_change_count(params); if (grant_root && grant_root[0] != '\0') { @@ -255,6 +296,9 @@ static char *codex_client_approval_detail(const char *method, reason ? ": " : "", reason ? reason : ""); } +/** + * @brief Codex client item summary. + */ static char *codex_client_item_summary(JsonObject *item) { const char *type = json_object_get_string_member_with_default( item, "type", "activity"); @@ -277,6 +321,9 @@ static char *codex_client_item_summary(JsonObject *item) { status ? status : "started"); } +/** + * @brief Codex client handle notification. + */ static void codex_client_handle_notification(CodexClient *client, JsonObject *object) { const char *method = json_object_get_string_member_with_default( @@ -352,6 +399,9 @@ static void codex_client_handle_notification(CodexClient *client, client->interrupt_request_id = 0u; } +/** + * @brief Codex client handle message. + */ static void codex_client_handle_message(CodexClient *client, JsonNode *root) { JsonObject *object = json_node_get_object(root); if (!json_object_has_member(object, "id")) { @@ -454,6 +504,9 @@ static void codex_client_handle_message(CodexClient *client, JsonNode *root) { codex_client_set_state(client, CODEX_CLIENT_READY, NULL); } +/** + * @brief Codex client line ready. + */ static void codex_client_line_ready(GObject *source, GAsyncResult *result, gpointer user_data) { @@ -484,6 +537,9 @@ static void codex_client_line_ready(GObject *source, codex_client_unref(client); } +/** + * @brief Codex client read next. + */ static void codex_client_read_next(CodexClient *client) { if (!client || !client->output || !client->cancellable) return; g_data_input_stream_read_line_async(client->output, @@ -493,6 +549,9 @@ static void codex_client_read_next(CodexClient *client) { codex_client_ref(client)); } +/** + * @brief Codex client new. + */ CodexClient *codex_client_new(CodexClientStatusFunc status_func, gpointer user_data) { CodexClient *client = g_new0(CodexClient, 1); @@ -504,11 +563,17 @@ CodexClient *codex_client_new(CodexClientStatusFunc status_func, return client; } +/** + * @brief Codex client set event func. + */ void codex_client_set_event_func(CodexClient *client, CodexClientEventFunc event_func) { if (client) client->event_func = event_func; } +/** + * @brief Codex client send prompt. + */ gboolean codex_client_send_prompt(CodexClient *client, const char *prompt) { if (!client || client->state != CODEX_CLIENT_READY || client->turn_id || client->turn_pending || @@ -531,6 +596,9 @@ gboolean codex_client_send_prompt(CodexClient *client, const char *prompt) { return sent; } +/** + * @brief Codex client interrupt. + */ gboolean codex_client_interrupt(CodexClient *client) { if (!client || !client->thread_id) return FALSE; if (!client->turn_id && client->turn_pending) { @@ -549,6 +617,9 @@ gboolean codex_client_interrupt(CodexClient *client) { return codex_client_write(client, request); } +/** + * @brief Codex client new thread. + */ gboolean codex_client_new_thread(CodexClient *client) { if (!client || client->state != CODEX_CLIENT_READY || client->turn_id || client->turn_pending) { @@ -560,6 +631,9 @@ gboolean codex_client_new_thread(CodexClient *client) { return TRUE; } +/** + * @brief Codex client resume thread. + */ gboolean codex_client_resume_thread(CodexClient *client, const char *thread_id) { if (!client || client->state != CODEX_CLIENT_READY || client->turn_id || @@ -575,6 +649,9 @@ gboolean codex_client_resume_thread(CodexClient *client, return codex_client_write(client, request); } +/** + * @brief Codex client resolve approval. + */ gboolean codex_client_resolve_approval(CodexClient *client, const char *decision) { if (!client || !client->approval_request_id_node || !decision) return FALSE; @@ -597,6 +674,9 @@ gboolean codex_client_resolve_approval(CodexClient *client, return sent; } +/** + * @brief Codex client start. + */ void codex_client_start(CodexClient *client, const char *cwd) { if (!client || client->process) return; codex_client_set_state(client, CODEX_CLIENT_CONNECTING, NULL); @@ -636,6 +716,9 @@ void codex_client_start(CodexClient *client, const char *cwd) { (void)codex_client_write(client, request); } +/** + * @brief Codex client stop. + */ void codex_client_stop(CodexClient *client) { if (!client) return; if (client->cancellable) g_cancellable_cancel(client->cancellable); @@ -647,6 +730,9 @@ void codex_client_stop(CodexClient *client) { client->state = CODEX_CLIENT_STOPPED; } +/** + * @brief Codex client free. + */ void codex_client_free(CodexClient *client) { if (!client) return; client->disposing = TRUE; @@ -657,10 +743,16 @@ void codex_client_free(CodexClient *client) { codex_client_unref(client); } +/** + * @brief Codex client get state. + */ CodexClientState codex_client_get_state(const CodexClient *client) { return client ? client->state : CODEX_CLIENT_STOPPED; } +/** + * @brief Codex client get thread id. + */ const char *codex_client_get_thread_id(const CodexClient *client) { return client ? client->thread_id : NULL; } diff --git a/src/codex_client.h b/src/codex_client.h index 6d5f496..02210e3 100644 --- a/src/codex_client.h +++ b/src/codex_client.h @@ -1,54 +1,110 @@ +/** + * @file src/codex_client.h + * @brief Codex process client and event bridge. + */ + #ifndef CLEAF_CODEX_CLIENT_H #define CLEAF_CODEX_CLIENT_H #include +/** + * @brief Codex client type definition. + */ typedef struct _CodexClient CodexClient; +/** + * @brief Codex client type definition. + */ typedef enum { - CODEX_CLIENT_STOPPED, - CODEX_CLIENT_CONNECTING, - CODEX_CLIENT_READY, - CODEX_CLIENT_FAILED + CODEX_CLIENT_STOPPED, /**< Codex client stopped. */ + CODEX_CLIENT_CONNECTING, /**< Codex client connecting. */ + CODEX_CLIENT_READY, /**< Codex client ready. */ + CODEX_CLIENT_FAILED /**< Codex client failed. */ } CodexClientState; +/** + * @brief Void. + */ typedef void (*CodexClientStatusFunc)(CodexClient *client, CodexClientState state, const char *detail, gpointer user_data); +/** + * @brief Codex client type definition. + */ typedef enum { - CODEX_EVENT_TURN_STARTED, - CODEX_EVENT_AGENT_DELTA, - CODEX_EVENT_TURN_COMPLETED, - CODEX_EVENT_TURN_INTERRUPTED, - CODEX_EVENT_TURN_FAILED, - CODEX_EVENT_ACTIVITY, - CODEX_EVENT_APPROVAL_REQUESTED, - CODEX_EVENT_APPROVAL_RESOLVED, - CODEX_EVENT_DIFF_UPDATED + CODEX_EVENT_TURN_STARTED, /**< Codex event turn started. */ + CODEX_EVENT_AGENT_DELTA, /**< Codex event agent delta. */ + CODEX_EVENT_TURN_COMPLETED, /**< Codex event turn completed. */ + CODEX_EVENT_TURN_INTERRUPTED, /**< Codex event turn interrupted. */ + CODEX_EVENT_TURN_FAILED, /**< Codex event turn failed. */ + CODEX_EVENT_ACTIVITY, /**< Codex event activity. */ + CODEX_EVENT_APPROVAL_REQUESTED, /**< Codex event approval requested. */ + CODEX_EVENT_APPROVAL_RESOLVED, /**< Codex event approval resolved. */ + CODEX_EVENT_DIFF_UPDATED /**< Codex event diff updated. */ } CodexClientEvent; +/** + * @brief Void. + */ typedef void (*CodexClientEventFunc)(CodexClient *client, CodexClientEvent event, const char *text, gpointer user_data); +/** + * @brief Codex client new. + */ CodexClient *codex_client_new(CodexClientStatusFunc status_func, gpointer user_data); +/** + * @brief Codex client start. + */ void codex_client_start(CodexClient *client, const char *cwd); +/** + * @brief Codex client set event func. + */ void codex_client_set_event_func(CodexClient *client, CodexClientEventFunc event_func); +/** + * @brief Codex client send prompt. + */ gboolean codex_client_send_prompt(CodexClient *client, const char *prompt); +/** + * @brief Codex client interrupt. + */ gboolean codex_client_interrupt(CodexClient *client); +/** + * @brief Codex client new thread. + */ gboolean codex_client_new_thread(CodexClient *client); +/** + * @brief Codex client resume thread. + */ gboolean codex_client_resume_thread(CodexClient *client, const char *thread_id); +/** + * @brief Codex client resolve approval. + */ gboolean codex_client_resolve_approval(CodexClient *client, const char *decision); +/** + * @brief Codex client stop. + */ void codex_client_stop(CodexClient *client); +/** + * @brief Codex client free. + */ void codex_client_free(CodexClient *client); +/** + * @brief Codex client get state. + */ CodexClientState codex_client_get_state(const CodexClient *client); +/** + * @brief Codex client get thread id. + */ const char *codex_client_get_thread_id(const CodexClient *client); #endif /* CLEAF_CODEX_CLIENT_H */ diff --git a/src/codex_markdown.c b/src/codex_markdown.c index b4b7856..3801753 100644 --- a/src/codex_markdown.c +++ b/src/codex_markdown.c @@ -1,9 +1,20 @@ +/** + * @file src/codex_markdown.c + * @brief Codex response markdown renderer. + */ + #include "codex_markdown.h" #include #include +/** + * @brief Codex markdown type definition. + */ typedef struct { GtkTextBuffer *buffer; GtkTextIter iter; } Writer; +/** + * @brief Tag ensure. + */ static void tag_ensure(GtkTextBuffer *buffer, const char *name, const char *first, ...) { GtkTextTagTable *table = gtk_text_buffer_get_tag_table(buffer); @@ -17,6 +28,9 @@ static void tag_ensure(GtkTextBuffer *buffer, const char *name, g_object_unref(tag); } +/** + * @brief Tags ensure. + */ static void tags_ensure(GtkTextBuffer *buffer) { tag_ensure(buffer, "ai-h1", "weight", PANGO_WEIGHT_BOLD, "scale", 1.55, "foreground", "#89b4fa", "pixels-above-lines", 10, NULL); @@ -34,10 +48,16 @@ static void tags_ensure(GtkTextBuffer *buffer) { "underline", PANGO_UNDERLINE_SINGLE, NULL); } +/** + * @brief Put. + */ static void put(Writer *writer, const char *text) { gtk_text_buffer_insert(writer->buffer, &writer->iter, text ? text : "", -1); } +/** + * @brief Put tag. + */ static void put_tag(Writer *writer, const char *text, const char *tag) { gint offset = gtk_text_iter_get_offset(&writer->iter); put(writer, text); @@ -46,6 +66,9 @@ static void put_tag(Writer *writer, const char *text, const char *tag) { gtk_text_buffer_apply_tag_by_name(writer->buffer, tag, &start, &writer->iter); } +/** + * @brief Inline render. + */ static void inline_render(Writer *writer, const char *line) { const char *p = line ? line : ""; while (*p) { @@ -73,6 +96,9 @@ static void inline_render(Writer *writer, const char *line) { } } +/** + * @brief Line render. + */ static void line_render(Writer *writer, const char *line, gboolean *code) { if (g_str_has_prefix(line, "```") || g_str_has_prefix(line, "~~~")) { *code = !*code; return; @@ -88,6 +114,9 @@ static void line_render(Writer *writer, const char *line, gboolean *code) { put(writer, "\n"); } +/** + * @brief Codex markdown render. + */ void codex_markdown_render(GtkTextBuffer *buffer, const char *markdown) { if (!buffer) return; gtk_text_buffer_set_text(buffer, "", 0); diff --git a/src/codex_markdown.h b/src/codex_markdown.h index dda31a5..2b5c387 100644 --- a/src/codex_markdown.h +++ b/src/codex_markdown.h @@ -1,5 +1,13 @@ +/** + * @file src/codex_markdown.h + * @brief Codex response markdown renderer. + */ + #ifndef CLEAF_CODEX_MARKDOWN_H #define CLEAF_CODEX_MARKDOWN_H #include +/** + * @brief Codex markdown render. + */ void codex_markdown_render(GtkTextBuffer *buffer, const char *markdown); #endif diff --git a/src/codex_panel.c b/src/codex_panel.c index df6ea2b..ff4be48 100644 --- a/src/codex_panel.c +++ b/src/codex_panel.c @@ -1,3 +1,8 @@ +/** + * @file src/codex_panel.c + * @brief Codex sidebar panel and chat review UI. + */ + #include "codex_panel.h" #include "app.h" @@ -7,46 +12,58 @@ #include "git.h" #include "ui.h" +/** + * @brief Codex panel type definition. + */ typedef struct { - struct _CodexPanel *panel; - GtkWidget *page; - GtkWidget *view; - GtkTextBuffer *buffer; - char *thread_id; - GString *markdown; - gboolean render_dirty; + struct _CodexPanel *panel; /**< Panel. */ + GtkWidget *page; /**< Page. */ + GtkWidget *view; /**< View. */ + GtkTextBuffer *buffer; /**< Buffer. */ + char *thread_id; /**< Thread id. */ + GString *markdown; /**< Markdown. */ + gboolean render_dirty; /**< Render dirty. */ } CodexChat; +/** + * @brief Codex panel type definition. + */ struct _CodexPanel { - EditorWindow *win; - GtkWidget *revealer; - GtkWidget *status_label; - GtkWidget *transcript_view; - GtkTextBuffer *transcript; - GtkWidget *chat_notebook; - GPtrArray *chats; - CodexChat *current_chat; - gboolean switching_chat; - GtkWidget *composer_view; - GtkTextBuffer *composer; - GtkWidget *send_button; - GtkWidget *stop_button; - GtkWidget *new_button; - GtkWidget *file_context; - GtkWidget *selection_context; - GtkWidget *context_label; - GtkWidget *approval_box; - GtkWidget *approval_label; - GtkWidget *review_box; - GtkWidget *changed_files; - gboolean turn_active; - gboolean visible; - char *turn_diff; - guint render_timeout; + EditorWindow *win; /**< Win. */ + GtkWidget *revealer; /**< Revealer. */ + GtkWidget *status_label; /**< Status label. */ + GtkWidget *transcript_view; /**< Transcript view. */ + GtkTextBuffer *transcript; /**< Transcript. */ + GtkWidget *chat_notebook; /**< Chat notebook. */ + GPtrArray *chats; /**< Chats. */ + CodexChat *current_chat; /**< Current chat. */ + gboolean switching_chat; /**< Switching chat. */ + GtkWidget *composer_view; /**< Composer view. */ + GtkTextBuffer *composer; /**< Composer. */ + GtkWidget *send_button; /**< Send button. */ + GtkWidget *stop_button; /**< Stop button. */ + GtkWidget *new_button; /**< New button. */ + GtkWidget *file_context; /**< File context. */ + GtkWidget *selection_context; /**< Selection context. */ + GtkWidget *context_label; /**< Context label. */ + GtkWidget *approval_box; /**< Approval box. */ + GtkWidget *approval_label; /**< Approval label. */ + GtkWidget *review_box; /**< Review box. */ + GtkWidget *changed_files; /**< Changed files. */ + gboolean turn_active; /**< Turn active. */ + gboolean visible; /**< Visible. */ + char *turn_diff; /**< Turn diff. */ + guint render_timeout; /**< Render timeout. */ }; +/** + * @brief Codex context limit macro. + */ #define CODEX_CONTEXT_LIMIT 65536 +/** + * @brief Panel render now. + */ static void panel_render_now(CodexPanel *panel) { if (!panel || !panel->current_chat || !panel->current_chat->render_dirty) return; @@ -61,14 +78,20 @@ static void panel_render_now(CodexPanel *panel) { } } +/** + * @brief Panel render timeout cb. + */ static gboolean panel_render_timeout_cb(gpointer user_data) { CodexPanel *panel = user_data; if (!panel) return G_SOURCE_REMOVE; panel->render_timeout = 0u; panel_render_now(panel); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; /**< G source remove. */ } +/** + * @brief Panel schedule render. + */ static void panel_schedule_render(CodexPanel *panel) { if (!panel || panel->render_timeout != 0u || !panel->current_chat) return; gsize length = panel->current_chat->markdown->len; @@ -76,6 +99,9 @@ static void panel_schedule_render(CodexPanel *panel) { panel->render_timeout = g_timeout_add(delay, panel_render_timeout_cb, panel); } +/** + * @brief Codex chat free. + */ static void codex_chat_free(gpointer data) { CodexChat *chat = data; if (!chat) return; @@ -84,8 +110,14 @@ static void codex_chat_free(gpointer data) { g_free(chat); } +/** + * @brief Panel close chat. + */ static void panel_close_chat(GtkWidget *widget, gpointer user_data); +/** + * @brief Panel add chat. + */ static CodexChat *panel_add_chat(CodexPanel *panel) { CodexChat *chat = g_new0(CodexChat, 1); chat->panel = panel; @@ -119,9 +151,12 @@ static CodexChat *panel_add_chat(CodexPanel *panel) { panel->transcript_view = chat->view; panel->transcript = chat->buffer; panel_render_now(panel); - return chat; + return chat; /**< Chat. */ } +/** + * @brief Panel activate chat. + */ static void panel_activate_chat(CodexPanel *panel, guint index) { if (!panel || index >= panel->chats->len) return; CodexChat *chat = g_ptr_array_index(panel->chats, index); @@ -138,6 +173,9 @@ static void panel_activate_chat(CodexPanel *panel, guint index) { } } +/** + * @brief Panel close chat. + */ static void panel_close_chat(GtkWidget *widget, gpointer user_data) { (void)widget; CodexChat *chat = user_data; @@ -170,6 +208,9 @@ static void panel_close_chat(GtkWidget *widget, gpointer user_data) { panel_activate_chat(panel, next); } +/** + * @brief Panel chat switched. + */ static void panel_chat_switched(GtkNotebook *notebook, GtkWidget *page, guint page_num, @@ -201,6 +242,9 @@ static void panel_chat_switched(GtkNotebook *notebook, } } +/** + * @brief Panel append. + */ static void panel_append(CodexPanel *panel, const char *text) { if (!panel || !panel->transcript || !text) return; if (!panel->current_chat || !panel->current_chat->markdown) return; @@ -209,6 +253,9 @@ static void panel_append(CodexPanel *panel, const char *text) { panel_schedule_render(panel); } +/** + * @brief Panel set turn active. + */ static void panel_set_turn_active(CodexPanel *panel, gboolean active) { if (!panel) return; panel->turn_active = active; @@ -218,6 +265,9 @@ static void panel_set_turn_active(CodexPanel *panel, gboolean active) { gtk_text_view_set_editable(GTK_TEXT_VIEW(panel->composer_view), !active); } +/** + * @brief Panel editor context. + */ static char *panel_editor_context(CodexPanel *panel) { EditorTab *tab = panel && panel->win ? app_window_current_tab(panel->win) : NULL; @@ -226,8 +276,8 @@ static char *panel_editor_context(CodexPanel *panel) { GTK_CHECK_BUTTON(panel->file_context)); gboolean include_selection = gtk_check_button_get_active( GTK_CHECK_BUTTON(panel->selection_context)); - GtkTextIter start; - GtkTextIter end; + GtkTextIter start; /**< Start. */ + GtkTextIter end; /**< End. */ gboolean selected = gtk_text_buffer_get_selection_bounds(tab->buffer, &start, &end); if (!include_file && (!include_selection || !selected)) return g_strdup(""); @@ -244,14 +294,17 @@ static char *panel_editor_context(CodexPanel *panel) { path, selected && include_selection ? "selected text" : "current buffer", content); g_free(content); - return context; + return context; /**< Context. */ } +/** + * @brief Codex panel refresh context. + */ void codex_panel_refresh_context(CodexPanel *panel) { EditorTab *tab = panel && panel->win ? app_window_current_tab(panel->win) : NULL; - GtkTextIter start; - GtkTextIter end; + GtkTextIter start; /**< Start. */ + GtkTextIter end; /**< End. */ gboolean selected = tab && tab->buffer && gtk_text_buffer_get_selection_bounds(tab->buffer, &start, &end); gtk_widget_set_sensitive(panel->selection_context, selected); @@ -262,12 +315,15 @@ void codex_panel_refresh_context(CodexPanel *panel) { g_free(label); } +/** + * @brief Panel send. + */ static void panel_send(GtkWidget *widget, gpointer user_data) { (void)widget; CodexPanel *panel = user_data; if (!panel || !panel->win || !panel->win->codex_client) return; - GtkTextIter start; - GtkTextIter end; + GtkTextIter start; /**< Start. */ + GtkTextIter end; /**< End. */ gtk_text_buffer_get_bounds(panel->composer, &start, &end); char *prompt = gtk_text_buffer_get_text(panel->composer, &start, &end, FALSE); g_strstrip(prompt); @@ -294,6 +350,9 @@ static void panel_send(GtkWidget *widget, gpointer user_data) { g_free(prompt); } +/** + * @brief Panel stop. + */ static void panel_stop(GtkWidget *widget, gpointer user_data) { (void)widget; CodexPanel *panel = user_data; @@ -308,6 +367,9 @@ static void panel_stop(GtkWidget *widget, gpointer user_data) { } } +/** + * @brief Panel new thread. + */ static void panel_new_thread(GtkWidget *widget, gpointer user_data) { (void)widget; CodexPanel *panel = user_data; @@ -318,11 +380,17 @@ static void panel_new_thread(GtkWidget *widget, gpointer user_data) { } } +/** + * @brief Panel close. + */ static void panel_close(GtkWidget *widget, gpointer user_data) { (void)widget; codex_panel_toggle(user_data); } +/** + * @brief Panel approval. + */ static void panel_approval(GtkWidget *widget, gpointer user_data) { CodexPanel *panel = user_data; const char *decision = g_object_get_data(G_OBJECT(widget), "decision"); @@ -331,6 +399,9 @@ static void panel_approval(GtkWidget *widget, gpointer user_data) { } } +/** + * @brief Panel clear children. + */ static void panel_clear_children(GtkWidget *box) { GtkWidget *child = box ? gtk_widget_get_first_child(box) : NULL; while (child) { @@ -340,6 +411,9 @@ static void panel_clear_children(GtkWidget *box) { } } +/** + * @brief Panel open changed file. + */ static void panel_open_changed_file(GtkWidget *widget, gpointer user_data) { CodexPanel *panel = user_data; const char *relative = g_object_get_data(G_OBJECT(widget), "codex-path"); @@ -351,6 +425,9 @@ static void panel_open_changed_file(GtkWidget *widget, gpointer user_data) { g_free(path); } +/** + * @brief Panel update changed files. + */ static void panel_update_changed_files(CodexPanel *panel) { panel_clear_children(panel->changed_files); if (!panel->turn_diff) return; @@ -374,6 +451,9 @@ static void panel_update_changed_files(CodexPanel *panel) { g_hash_table_destroy(seen); } +/** + * @brief Panel add changed path. + */ static void panel_add_changed_path(CodexPanel *panel, GPtrArray *paths, GHashTable *seen, @@ -395,6 +475,9 @@ static void panel_add_changed_path(CodexPanel *panel, g_ptr_array_add(paths, canonical); } +/** + * @brief Panel changed paths. + */ static GPtrArray *panel_changed_paths(CodexPanel *panel) { GPtrArray *paths = g_ptr_array_new_with_free_func(g_free); if (!panel || !panel->turn_diff) return paths; @@ -413,6 +496,9 @@ static GPtrArray *panel_changed_paths(CodexPanel *panel) { return paths; } +/** + * @brief Path in array. + */ static gboolean path_in_array(GPtrArray *paths, const char *path) { if (!paths || !path) return FALSE; for (guint i = 0u; i < paths->len; i++) { @@ -421,6 +507,9 @@ static gboolean path_in_array(GPtrArray *paths, const char *path) { return FALSE; } +/** + * @brief Panel reload kept tabs. + */ static void panel_reload_kept_tabs(CodexPanel *panel, guint *reloaded_out, guint *skipped_modified_out, @@ -460,6 +549,9 @@ static void panel_reload_kept_tabs(CodexPanel *panel, g_ptr_array_free(paths, TRUE); } +/** + * @brief Panel review diff. + */ static void panel_review_diff(GtkWidget *widget, gpointer user_data) { (void)widget; CodexPanel *panel = user_data; @@ -468,6 +560,9 @@ static void panel_review_diff(GtkWidget *widget, gpointer user_data) { } } +/** + * @brief Panel keep diff. + */ static void panel_keep_diff(GtkWidget *widget, gpointer user_data) { (void)widget; CodexPanel *panel = user_data; @@ -499,6 +594,9 @@ static void panel_keep_diff(GtkWidget *widget, gpointer user_data) { } } +/** + * @brief Panel revert diff. + */ static void panel_revert_diff(GtkWidget *widget, gpointer user_data) { (void)widget; CodexPanel *panel = user_data; @@ -519,6 +617,9 @@ static void panel_revert_diff(GtkWidget *widget, gpointer user_data) { g_clear_error(&error); } +/** + * @brief Codex panel new. + */ CodexPanel *codex_panel_new(EditorWindow *win) { CodexPanel *panel = g_new0(CodexPanel, 1); panel->win = win; @@ -646,6 +747,9 @@ CodexPanel *codex_panel_new(EditorWindow *win) { return panel; } +/** + * @brief Codex panel free. + */ void codex_panel_free(CodexPanel *panel) { if (panel && panel->render_timeout != 0u) { g_source_remove(panel->render_timeout); @@ -656,10 +760,16 @@ void codex_panel_free(CodexPanel *panel) { g_free(panel); } +/** + * @brief Codex panel widget. + */ GtkWidget *codex_panel_widget(CodexPanel *panel) { return panel ? panel->revealer : NULL; } +/** + * @brief Codex panel toggle. + */ void codex_panel_toggle(CodexPanel *panel) { if (!panel) return; panel->visible = !panel->visible; @@ -672,6 +782,9 @@ void codex_panel_toggle(CodexPanel *panel) { gtk_widget_queue_resize(panel->revealer); } +/** + * @brief Codex panel set connection. + */ void codex_panel_set_connection(CodexPanel *panel, CodexClientState state, const char *detail) { @@ -696,6 +809,9 @@ void codex_panel_set_connection(CodexPanel *panel, } } +/** + * @brief Codex panel handle event. + */ void codex_panel_handle_event(CodexClient *client, CodexClientEvent event, const char *text, diff --git a/src/codex_panel.h b/src/codex_panel.h index e44fa35..2360b03 100644 --- a/src/codex_panel.h +++ b/src/codex_panel.h @@ -1,3 +1,8 @@ +/** + * @file src/codex_panel.h + * @brief Codex sidebar panel and chat review UI. + */ + #ifndef CLEAF_CODEX_PANEL_H #define CLEAF_CODEX_PANEL_H @@ -5,17 +10,44 @@ #include "codex_client.h" +/** + * @brief Codex panel type definition. + */ typedef struct _EditorWindow EditorWindow; +/** + * @brief Codex panel type definition. + */ typedef struct _CodexPanel CodexPanel; +/** + * @brief Codex panel new. + */ CodexPanel *codex_panel_new(EditorWindow *win); +/** + * @brief Codex panel free. + */ void codex_panel_free(CodexPanel *panel); +/** + * @brief Codex panel widget. + */ GtkWidget *codex_panel_widget(CodexPanel *panel); +/** + * @brief Codex panel toggle. + */ void codex_panel_toggle(CodexPanel *panel); +/** + * @brief Codex panel refresh context. + */ void codex_panel_refresh_context(CodexPanel *panel); +/** + * @brief Codex panel set connection. + */ void codex_panel_set_connection(CodexPanel *panel, CodexClientState state, const char *detail); +/** + * @brief Codex panel handle event. + */ void codex_panel_handle_event(CodexClient *client, CodexClientEvent event, const char *text, diff --git a/src/codex_protocol.c b/src/codex_protocol.c index c88500a..fc36d5d 100644 --- a/src/codex_protocol.c +++ b/src/codex_protocol.c @@ -1,5 +1,13 @@ +/** + * @file src/codex_protocol.c + * @brief Codex JSON line protocol helpers. + */ + #include "codex_protocol.h" +/** + * @brief Codex protocol message. + */ static char *codex_protocol_message(gboolean has_id, guint64 id, const char *method, @@ -33,16 +41,25 @@ static char *codex_protocol_message(gboolean has_id, return line; } +/** + * @brief Codex protocol request. + */ char *codex_protocol_request(guint64 id, const char *method, JsonNode *params) { return codex_protocol_message(TRUE, id, method, params); } +/** + * @brief Codex protocol notification. + */ char *codex_protocol_notification(const char *method, JsonNode *params) { return codex_protocol_message(FALSE, 0u, method, params); } +/** + * @brief Codex protocol response. + */ char *codex_protocol_response(guint64 id, JsonNode *result) { JsonBuilder *builder = json_builder_new(); json_builder_begin_object(builder); @@ -63,12 +80,18 @@ char *codex_protocol_response(guint64 id, JsonNode *result) { return line; } +/** + * @brief Codex protocol object params. + */ JsonNode *codex_protocol_object_params(void) { JsonNode *node = json_node_new(JSON_NODE_OBJECT); json_node_take_object(node, json_object_new()); return node; } +/** + * @brief Codex protocol parse. + */ gboolean codex_protocol_parse(const char *line, JsonNode **root_out, GError **error) { diff --git a/src/codex_protocol.h b/src/codex_protocol.h index 9ec786a..9d2c874 100644 --- a/src/codex_protocol.h +++ b/src/codex_protocol.h @@ -1,14 +1,34 @@ +/** + * @file src/codex_protocol.h + * @brief Codex JSON line protocol helpers. + */ + #ifndef CLEAF_CODEX_PROTOCOL_H #define CLEAF_CODEX_PROTOCOL_H #include +/** + * @brief Codex protocol request. + */ char *codex_protocol_request(guint64 id, const char *method, JsonNode *params); +/** + * @brief Codex protocol notification. + */ char *codex_protocol_notification(const char *method, JsonNode *params); +/** + * @brief Codex protocol response. + */ char *codex_protocol_response(guint64 id, JsonNode *result); +/** + * @brief Codex protocol object params. + */ JsonNode *codex_protocol_object_params(void); +/** + * @brief Codex protocol parse. + */ gboolean codex_protocol_parse(const char *line, JsonNode **root_out, GError **error); diff --git a/src/codex_review.c b/src/codex_review.c index 4817dec..c03498c 100644 --- a/src/codex_review.c +++ b/src/codex_review.c @@ -1,3 +1,8 @@ +/** + * @file src/codex_review.c + * @brief Codex diff review tab helpers. + */ + #include "codex_review.h" #include @@ -6,6 +11,9 @@ #include "editor_tab.h" #include "git.h" +/** + * @brief Review diff syntax. + */ static SyntaxDef *review_diff_syntax(EditorWindow *win) { if (!win || !win->syntaxes) return NULL; for (guint i = 0u; i < win->syntaxes->len; i++) { @@ -16,6 +24,9 @@ static SyntaxDef *review_diff_syntax(EditorWindow *win) { return NULL; } +/** + * @brief Codex review open diff. + */ void codex_review_open_diff(EditorWindow *win, const char *diff) { if (!win || !diff) return; EditorTab *tab = editor_tab_new(win); @@ -34,6 +45,9 @@ void codex_review_open_diff(EditorWindow *win, const char *diff) { } } +/** + * @brief Run reverse apply. + */ static gboolean run_reverse_apply(const char *cwd, const char *diff, gboolean check, @@ -67,6 +81,9 @@ static gboolean run_reverse_apply(const char *cwd, return success; } +/** + * @brief Codex review revert. + */ gboolean codex_review_revert(EditorWindow *win, const char *diff, GError **error) { diff --git a/src/codex_review.h b/src/codex_review.h index bf14da0..8c2c0ff 100644 --- a/src/codex_review.h +++ b/src/codex_review.h @@ -1,11 +1,25 @@ +/** + * @file src/codex_review.h + * @brief Codex diff review tab helpers. + */ + #ifndef CLEAF_CODEX_REVIEW_H #define CLEAF_CODEX_REVIEW_H #include +/** + * @brief Codex review type definition. + */ typedef struct _EditorWindow EditorWindow; +/** + * @brief Codex review open diff. + */ void codex_review_open_diff(EditorWindow *win, const char *diff); +/** + * @brief Codex review revert. + */ gboolean codex_review_revert(EditorWindow *win, const char *diff, GError **error); diff --git a/src/completion.c b/src/completion.c index 9da9c29..69f1d8d 100644 --- a/src/completion.c +++ b/src/completion.c @@ -1,19 +1,36 @@ +/** + * @file src/completion.c + * @brief Text completion candidate extraction helpers. + */ + #include "completion.h" #include +/** + * @brief Ascii word start. + */ static gboolean ascii_word_start(unsigned char ch) { return g_ascii_isalpha((gchar)ch) || ch == '_'; } +/** + * @brief Ascii word char. + */ static gboolean ascii_word_char(unsigned char ch) { return g_ascii_isalnum((gchar)ch) || ch == '_'; } +/** + * @brief Completion is word char. + */ gboolean completion_is_word_char(gunichar ch) { return g_unichar_isalnum(ch) || ch == (gunichar)'_'; } +/** + * @brief Completion prefix at cursor. + */ char *completion_prefix_at_cursor(GtkTextBuffer *buffer, GtkTextIter *prefix_start, GtkTextIter *cursor) { if (!buffer) return NULL; @@ -36,6 +53,9 @@ char *completion_prefix_at_cursor(GtkTextBuffer *buffer, GtkTextIter *prefix_sta return gtk_text_buffer_get_text(buffer, &start, &iter, FALSE); } +/** + * @brief Candidate matches. + */ static gboolean candidate_matches(const char *word, const char *prefix) { if (!word || !prefix || prefix[0] == '\0') return FALSE; gsize prefix_len = strlen(prefix); @@ -44,6 +64,9 @@ static gboolean candidate_matches(const char *word, const char *prefix) { return strncmp(word, prefix, prefix_len) == 0; } +/** + * @brief Candidate exists. + */ static gboolean candidate_exists(GPtrArray *out, const char *word) { if (!out || !word) return FALSE; for (guint i = 0; i < out->len; i++) { @@ -53,6 +76,9 @@ static gboolean candidate_exists(GPtrArray *out, const char *word) { return FALSE; } +/** + * @brief Completion candidates add. + */ void completion_candidates_add(GPtrArray *out, const char *word, const char *prefix, guint max_results) { if (!out || !word || !prefix) return; if (out->len >= max_results) return; @@ -61,6 +87,9 @@ void completion_candidates_add(GPtrArray *out, const char *word, const char *pre g_ptr_array_add(out, g_strdup(word)); } +/** + * @brief Collect words from text. + */ static void collect_words_from_text(GPtrArray *out, const char *text, const char *prefix, guint max_results) { if (!out || !text || !prefix) return; @@ -85,6 +114,9 @@ static void collect_words_from_text(GPtrArray *out, const char *text, const char } } +/** + * @brief Collect syntax completions. + */ static void collect_syntax_completions(GPtrArray *out, SyntaxDef *syntax, const char *prefix, guint max_results) { if (!out || !syntax || !prefix) return; @@ -104,6 +136,9 @@ static void collect_syntax_completions(GPtrArray *out, SyntaxDef *syntax, const } } +/** + * @brief Collect buffer words. + */ static void collect_buffer_words(GPtrArray *out, GtkTextBuffer *buffer, const char *prefix, guint max_results) { if (!out || !buffer || !prefix) return; GtkTextIter start; @@ -118,12 +153,18 @@ static void collect_buffer_words(GPtrArray *out, GtkTextBuffer *buffer, const ch g_free(text); } +/** + * @brief Compare candidate words. + */ static gint compare_candidate_words(gconstpointer a, gconstpointer b) { const char *sa = *(char * const *)a; const char *sb = *(char * const *)b; return g_ascii_strcasecmp(sa ? sa : "", sb ? sb : ""); } +/** + * @brief Completion candidates new. + */ GPtrArray *completion_candidates_new(GtkTextBuffer *buffer, SyntaxDef *syntax, const char *prefix, guint max_results) { if (max_results == 0u) max_results = CLEAF_COMPLETION_DEFAULT_MAX_RESULTS; GPtrArray *out = g_ptr_array_new_with_free_func(g_free); diff --git a/src/completion.h b/src/completion.h index 9e990d3..1c4654c 100644 --- a/src/completion.h +++ b/src/completion.h @@ -1,15 +1,38 @@ +/** + * @file src/completion.h + * @brief Text completion candidate extraction helpers. + */ + #ifndef CLEAF_COMPLETION_H #define CLEAF_COMPLETION_H #include #include "syntax.h" +/** + * @brief Cleaf completion max scan chars macro. + */ #define CLEAF_COMPLETION_MAX_SCAN_CHARS 65536 +/** + * @brief Cleaf completion default max results macro. + */ #define CLEAF_COMPLETION_DEFAULT_MAX_RESULTS 64u +/** + * @brief Completion is word char. + */ gboolean completion_is_word_char(gunichar ch); +/** + * @brief Completion prefix at cursor. + */ char *completion_prefix_at_cursor(GtkTextBuffer *buffer, GtkTextIter *prefix_start, GtkTextIter *cursor); +/** + * @brief Completion candidates add. + */ void completion_candidates_add(GPtrArray *out, const char *word, const char *prefix, guint max_results); +/** + * @brief Completion candidates new. + */ GPtrArray *completion_candidates_new(GtkTextBuffer *buffer, SyntaxDef *syntax, const char *prefix, guint max_results); #endif /* CLEAF_COMPLETION_H */ diff --git a/src/config.c b/src/config.c index 9dc0e74..e7909a4 100644 --- a/src/config.c +++ b/src/config.c @@ -1,8 +1,16 @@ +/** + * @file src/config.c + * @brief Persistent Cleaf configuration loading and saving. + */ + #include "config.h" #include #include +/** + * @brief Parse bool. + */ static gboolean parse_bool(GKeyFile *key_file, const char *key, gboolean fallback) { GError *error = NULL; gboolean value = g_key_file_get_boolean(key_file, "Editor", key, &error); @@ -13,6 +21,9 @@ static gboolean parse_bool(GKeyFile *key_file, const char *key, gboolean fallbac return value; } +/** + * @brief Parse uint. + */ static guint parse_uint(GKeyFile *key_file, const char *key, guint fallback, guint min_value, guint max_value) { GError *error = NULL; gint value = g_key_file_get_integer(key_file, "Editor", key, &error); @@ -25,6 +36,9 @@ static guint parse_uint(GKeyFile *key_file, const char *key, guint fallback, gui return (guint)value; } +/** + * @brief Load color. + */ static void load_color(GKeyFile *key_file, const char *key, char **slot) { if (!key_file || !key || !slot) return; char *value = g_key_file_get_string(key_file, "Editor", key, NULL); @@ -36,17 +50,26 @@ static void load_color(GKeyFile *key_file, const char *key, char **slot) { g_free(value); } +/** + * @brief Save color. + */ static void save_color(GKeyFile *key_file, const char *key, const char *value) { if (!key_file || !key || !value || value[0] == '\0') return; g_key_file_set_string(key_file, "Editor", key, value); } +/** + * @brief Cleaf config path. + */ char *cleaf_config_path(void) { const char *base = g_get_user_config_dir(); if (!base || base[0] == '\0') return NULL; return g_build_filename(base, "cleaf", "config.ini", NULL); } +/** + * @brief Cleaf config load. + */ void cleaf_config_load(EditorWindow *win) { if (!win) return; char *path = cleaf_config_path(); @@ -142,6 +165,9 @@ void cleaf_config_load(EditorWindow *win) { g_free(path); } +/** + * @brief Cleaf config save. + */ void cleaf_config_save(EditorWindow *win) { if (!win) return; char *path = cleaf_config_path(); diff --git a/src/config.h b/src/config.h index b61837f..f9af460 100644 --- a/src/config.h +++ b/src/config.h @@ -1,10 +1,24 @@ +/** + * @file src/config.h + * @brief Persistent Cleaf configuration loading and saving. + */ + #ifndef CLEAF_CONFIG_H #define CLEAF_CONFIG_H #include "app.h" +/** + * @brief Cleaf config load. + */ void cleaf_config_load(EditorWindow *win); +/** + * @brief Cleaf config save. + */ void cleaf_config_save(EditorWindow *win); +/** + * @brief Cleaf config path. + */ char *cleaf_config_path(void); #endif /* CLEAF_CONFIG_H */ diff --git a/src/dialogs.c b/src/dialogs.c index 30ceb81..4ff12fc 100644 --- a/src/dialogs.c +++ b/src/dialogs.c @@ -1,6 +1,14 @@ +/** + * @file src/dialogs.c + * @brief Dialog helper declarations and implementation. + */ + #include "dialogs.h" #include "ui.h" +/** + * @brief Dialog window new. + */ static GtkWidget *dialog_window_new(GtkWindow *parent, const char *title, int width, @@ -14,6 +22,9 @@ static GtkWidget *dialog_window_new(GtkWindow *parent, return window; } +/** + * @brief Dialog content new. + */ static GtkWidget *dialog_content_new(GtkWidget *window) { GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); gtk_widget_add_css_class(box, "cleaf-root"); @@ -22,6 +33,9 @@ static GtkWidget *dialog_content_new(GtkWidget *window) { return box; } +/** + * @brief Dialog label new. + */ static GtkWidget *dialog_label_new(const char *text, gboolean title) { GtkWidget *label = gtk_label_new(text ? text : ""); gtk_label_set_wrap(GTK_LABEL(label), TRUE); @@ -30,12 +44,18 @@ static GtkWidget *dialog_label_new(const char *text, gboolean title) { return label; } +/** + * @brief Button row new. + */ static GtkWidget *button_row_new(void) { GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_set_halign(row, GTK_ALIGN_END); return row; } +/** + * @brief Show message. + */ static void show_message(GtkWindow *parent, const char *title, const char *primary, @@ -57,15 +77,24 @@ static void show_message(GtkWindow *parent, cleaf_widget_destroy(window); } +/** + * @brief Dialog error. + */ void dialog_error(GtkWindow *parent, const char *primary, const char *detail) { show_message(parent, "Error", primary ? primary : "Error", detail); } +/** + * @brief Dialog info. + */ void dialog_info(GtkWindow *parent, const char *primary, const char *detail) { show_message(parent, "Information", primary ? primary : "Information", detail); } +/** + * @brief Dialog prompt text. + */ char *dialog_prompt_text(GtkWindow *parent, const char *title, const char *label, @@ -101,6 +130,9 @@ char *dialog_prompt_text(GtkWindow *parent, return result; } +/** + * @brief Dialog confirm yes no. + */ gboolean dialog_confirm_yes_no(GtkWindow *parent, const char *title, const char *message) { diff --git a/src/dialogs.h b/src/dialogs.h index 595e433..811f6c1 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -1,11 +1,28 @@ +/** + * @file src/dialogs.h + * @brief Dialog helper declarations and implementation. + */ + #ifndef CLEAF_DIALOGS_H #define CLEAF_DIALOGS_H #include +/** + * @brief Dialog error. + */ void dialog_error(GtkWindow *parent, const char *primary, const char *detail); +/** + * @brief Dialog info. + */ void dialog_info(GtkWindow *parent, const char *primary, const char *detail); +/** + * @brief Dialog prompt text. + */ char *dialog_prompt_text(GtkWindow *parent, const char *title, const char *label, const char *initial); +/** + * @brief Dialog confirm yes no. + */ gboolean dialog_confirm_yes_no(GtkWindow *parent, const char *title, const char *message); #endif /* CLEAF_DIALOGS_H */ diff --git a/src/editor_tab.h b/src/editor_tab.h index 9a25667..c160d90 100644 --- a/src/editor_tab.h +++ b/src/editor_tab.h @@ -1,3 +1,8 @@ +/** + * @file src/editor_tab.h + * @brief Editor tab public API and state structure. + */ + #ifndef CLEAF_EDITOR_TAB_H #define CLEAF_EDITOR_TAB_H @@ -6,125 +11,260 @@ #include "syntax.h" #include "completion.h" +/** + * @brief Editor tab type definition. + */ typedef struct _EditorWindow EditorWindow; +/** + * @brief Editor tab type definition. + */ typedef struct _EditorTab EditorTab; +/** + * @brief Editor tab type definition. + */ struct _EditorTab { - EditorWindow *win; - GtkWidget *box; - GtkWidget *editor_area; - GtkWidget *gutter; - GtkWidget *scrolled; - GtkWidget *text_view; - GtkWidget *popover_parent; - GtkTextBuffer *buffer; - GtkSourceBuffer *source_buffer; - GtkWidget *completion_popover; - GtkWidget *completion_list; - GtkWidget *completion_scrolled; - GtkWidget *hover_popover; - GtkWidget *hover_list; - GtkWidget *minimap_scrolled; - GtkWidget *minimap_view; - GtkTextBuffer *minimap_buffer; - GtkWidget *preview_scrolled; - GtkWidget *preview_view; - GtkTextBuffer *preview_buffer; - GtkWidget *tab_widget; - GtkWidget *tab_title; + EditorWindow *win; /**< Win. */ + GtkWidget *box; /**< Box. */ + GtkWidget *editor_area; /**< Editor area. */ + GtkWidget *gutter; /**< Gutter. */ + GtkWidget *scrolled; /**< Scrolled. */ + GtkWidget *text_view; /**< Text view. */ + GtkWidget *popover_parent; /**< Popover parent. */ + GtkTextBuffer *buffer; /**< Buffer. */ + GtkSourceBuffer *source_buffer; /**< Source buffer. */ + GtkWidget *completion_popover; /**< Completion popover. */ + GtkWidget *completion_list; /**< Completion list. */ + GtkWidget *completion_scrolled; /**< Completion scrolled. */ + GtkWidget *hover_popover; /**< Hover popover. */ + GtkWidget *hover_list; /**< Hover list. */ + GtkWidget *minimap_scrolled; /**< Minimap scrolled. */ + GtkWidget *minimap_view; /**< Minimap view. */ + GtkTextBuffer *minimap_buffer; /**< Minimap buffer. */ + GtkWidget *preview_scrolled; /**< Preview scrolled. */ + GtkWidget *preview_view; /**< Preview view. */ + GtkTextBuffer *preview_buffer; /**< Preview buffer. */ + GtkWidget *tab_widget; /**< Tab widget. */ + GtkWidget *tab_title; /**< Tab title. */ - char *file_path; - char *last_snapshot; - char *kill_buffer; - char *search_text; - char *completion_prefix; - char *hover_word; - SyntaxDef *active_syntax; + char *file_path; /**< File path. */ + char *last_snapshot; /**< Last snapshot. */ + char *kill_buffer; /**< Kill buffer. */ + char *search_text; /**< Search text. */ + char *completion_prefix; /**< Completion prefix. */ + char *hover_word; /**< Hover word. */ + SyntaxDef *active_syntax; /**< Active syntax. */ - GPtrArray *undo_stack; /* char* */ - GPtrArray *redo_stack; /* char* */ - guint highlight_timeout; - guint completion_timeout; - guint minimap_timeout; - guint preview_timeout; - guint diagnostics_timeout; - guint selection_match_timeout; - guint hover_timeout; - guint hover_hide_timeout; - guint ui_refresh_timeout; - guint tab_width; - guint diagnostic_warnings; - guint cached_gutter_width; - GdkRGBA color_preview_rgba; - gint hover_x; - gint hover_y; - gdouble pointer_x; - gdouble pointer_y; - gboolean modified; - gboolean applying_change; - gboolean manual_syntax_override; - gboolean backup_enabled; - gboolean wrap_enabled; - gboolean autocomplete_enabled; - gboolean completion_manual; - gboolean insert_spaces; - gboolean color_preview_valid; - gboolean hover_pointer_inside; - gboolean hover_pinned; - gboolean inspect_reference_active; - gboolean minimap_updating; - gboolean preview_updating; - gboolean locked; - gboolean hover_popover_locked; - gboolean pointer_valid; - gboolean selection_matches_active; - gboolean diagnostics_active; - gboolean custom_highlight_active; - gboolean low_latency_mode_active; + GPtrArray *undo_stack; /**< char*. */ + GPtrArray *redo_stack; /**< char*. */ + guint highlight_timeout; /**< Highlight timeout. */ + guint completion_timeout; /**< Completion timeout. */ + guint minimap_timeout; /**< Minimap timeout. */ + guint preview_timeout; /**< Preview timeout. */ + guint diagnostics_timeout; /**< Diagnostics timeout. */ + guint selection_match_timeout; /**< Selection match timeout. */ + guint hover_timeout; /**< Hover timeout. */ + guint hover_hide_timeout; /**< Hover hide timeout. */ + guint ui_refresh_timeout; /**< Ui refresh timeout. */ + guint tab_width; /**< Tab width. */ + guint diagnostic_warnings; /**< Diagnostic warnings. */ + guint cached_gutter_width; /**< Cached gutter width. */ + GdkRGBA color_preview_rgba; /**< Color preview rgba. */ + gint hover_x; /**< Hover x. */ + gint hover_y; /**< Hover y. */ + gdouble pointer_x; /**< Pointer x. */ + gdouble pointer_y; /**< Pointer y. */ + gboolean modified; /**< Modified. */ + gboolean applying_change; /**< Applying change. */ + gboolean manual_syntax_override; /**< Manual syntax override. */ + gboolean backup_enabled; /**< Backup enabled. */ + gboolean wrap_enabled; /**< Wrap enabled. */ + gboolean autocomplete_enabled; /**< Autocomplete enabled. */ + gboolean completion_manual; /**< Completion manual. */ + gboolean insert_spaces; /**< Insert spaces. */ + gboolean color_preview_valid; /**< Color preview valid. */ + gboolean hover_pointer_inside; /**< Hover pointer inside. */ + gboolean hover_pinned; /**< Hover pinned. */ + gboolean inspect_reference_active; /**< Inspect reference active. */ + gboolean minimap_updating; /**< Minimap updating. */ + gboolean preview_updating; /**< Preview updating. */ + gboolean locked; /**< Locked. */ + gboolean hover_popover_locked; /**< Hover popover locked. */ + gboolean pointer_valid; /**< Pointer valid. */ + gboolean selection_matches_active; /**< Selection matches active. */ + gboolean diagnostics_active; /**< Diagnostics active. */ + gboolean custom_highlight_active; /**< Custom highlight active. */ + gboolean low_latency_mode_active; /**< Low latency mode active. */ }; +/** + * @brief Editor tab new. + */ EditorTab *editor_tab_new(EditorWindow *win); +/** + * @brief Editor tab destroy popovers. + */ void editor_tab_destroy_popovers(EditorTab *tab); +/** + * @brief Editor tab free. + */ void editor_tab_free(EditorTab *tab); +/** + * @brief Editor tab load file. + */ gboolean editor_tab_load_file(EditorTab *tab, const char *path); +/** + * @brief Editor tab save. + */ gboolean editor_tab_save(EditorTab *tab, gboolean force_dialog); +/** + * @brief Editor tab confirm close. + */ gboolean editor_tab_confirm_close(EditorTab *tab); +/** + * @brief Editor tab update title. + */ void editor_tab_update_title(EditorTab *tab); +/** + * @brief Editor tab update status. + */ void editor_tab_update_status(EditorTab *tab); +/** + * @brief Editor tab set locked. + */ void editor_tab_set_locked(EditorTab *tab, gboolean locked); +/** + * @brief Editor tab is locked. + */ gboolean editor_tab_is_locked(EditorTab *tab); +/** + * @brief Editor tab set syntax. + */ void editor_tab_set_syntax(EditorTab *tab, SyntaxDef *syntax, gboolean manual); +/** + * @brief Editor tab auto select syntax. + */ void editor_tab_auto_select_syntax(EditorTab *tab); +/** + * @brief Editor tab schedule highlight. + */ void editor_tab_schedule_highlight(EditorTab *tab); +/** + * @brief Editor tab apply highlight. + */ void editor_tab_apply_highlight(EditorTab *tab); +/** + * @brief Editor tab update highlight engine. + */ void editor_tab_update_highlight_engine(EditorTab *tab); +/** + * @brief Editor tab find. + */ void editor_tab_find(EditorTab *tab, const char *query, gboolean backwards); +/** + * @brief Editor tab replace current. + */ void editor_tab_replace_current(EditorTab *tab, const char *find, const char *replace); +/** + * @brief Editor tab replace all. + */ void editor_tab_replace_all(EditorTab *tab, const char *find, const char *replace); +/** + * @brief Editor tab toggle comment. + */ void editor_tab_toggle_comment(EditorTab *tab); +/** + * @brief Editor tab go to line. + */ void editor_tab_go_to_line(EditorTab *tab); +/** + * @brief Editor tab justify paragraph. + */ void editor_tab_justify_paragraph(EditorTab *tab); +/** + * @brief Editor tab cut line. + */ void editor_tab_cut_line(EditorTab *tab); +/** + * @brief Editor tab paste cut line. + */ void editor_tab_paste_cut_line(EditorTab *tab); +/** + * @brief Editor tab undo. + */ void editor_tab_undo(EditorTab *tab); +/** + * @brief Editor tab redo. + */ void editor_tab_redo(EditorTab *tab); +/** + * @brief Editor tab select all. + */ void editor_tab_select_all(EditorTab *tab); +/** + * @brief Editor tab show completion. + */ void editor_tab_show_completion(EditorTab *tab, gboolean manual); +/** + * @brief Editor tab hide completion. + */ void editor_tab_hide_completion(EditorTab *tab); +/** + * @brief Editor tab set tab policy. + */ void editor_tab_set_tab_policy(EditorTab *tab, guint width, gboolean insert_spaces); +/** + * @brief Editor tab apply preferences. + */ void editor_tab_apply_preferences(EditorTab *tab); +/** + * @brief Editor tab set minimap visible. + */ void editor_tab_set_minimap_visible(EditorTab *tab, gboolean visible); +/** + * @brief Editor tab set preview visible. + */ void editor_tab_set_preview_visible(EditorTab *tab, gboolean visible); +/** + * @brief Editor tab update preview. + */ void editor_tab_update_preview(EditorTab *tab); +/** + * @brief Editor tab is latex. + */ gboolean editor_tab_is_latex(EditorTab *tab); +/** + * @brief Editor tab render latex. + */ void editor_tab_render_latex(EditorTab *tab); +/** + * @brief Editor tab set backup enabled. + */ void editor_tab_set_backup_enabled(EditorTab *tab, gboolean enabled); +/** + * @brief Editor tab auto save. + */ gboolean editor_tab_auto_save(EditorTab *tab); +/** + * @brief Editor tab cut clipboard. + */ void editor_tab_cut_clipboard(EditorTab *tab); +/** + * @brief Editor tab copy clipboard. + */ void editor_tab_copy_clipboard(EditorTab *tab); +/** + * @brief Editor tab paste clipboard. + */ void editor_tab_paste_clipboard(EditorTab *tab); +/** + * @brief Editor tab basename. + */ char *editor_tab_basename(EditorTab *tab); +/** + * @brief Editor tab jump to line. + */ void editor_tab_jump_to_line(EditorTab *tab, guint line); #endif /* CLEAF_EDITOR_TAB_H */ diff --git a/src/editor_tab_build.c b/src/editor_tab_build.c index 9239a07..f739c88 100644 --- a/src/editor_tab_build.c +++ b/src/editor_tab_build.c @@ -1,5 +1,13 @@ +/** + * @file src/editor_tab_build.c + * @brief Cleaf editor tab build module. + */ + #include "editor_tab_private.h" +/** + * @brief Tab init state. + */ static void tab_init_state(EditorTab *tab, EditorWindow *win) { tab->win = win; tab->backup_enabled = win ? win->backup_enabled : TRUE; @@ -11,6 +19,9 @@ static void tab_init_state(EditorTab *tab, EditorWindow *win) { tab->redo_stack = g_ptr_array_new_with_free_func(g_free); } +/** + * @brief Tab create text area. + */ static void tab_create_text_area(EditorTab *tab, EditorWindow *win) { tab->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_add_css_class(tab->box, "cleaf-tab-page"); @@ -53,6 +64,9 @@ static void tab_create_text_area(EditorTab *tab, EditorWindow *win) { } +/** + * @brief Tab create preview. + */ static void tab_create_preview(EditorTab *tab, EditorWindow *win) { tab->preview_buffer = gtk_text_buffer_new(NULL); tab->preview_view = gtk_text_view_new_with_buffer(tab->preview_buffer); @@ -116,6 +130,9 @@ static void tab_create_minimap(EditorTab *tab, EditorWindow *win) { if (win && !win->minimap_enabled) gtk_widget_set_visible(tab->minimap_scrolled, FALSE); } +/** + * @brief Tab create completion popover. + */ static void tab_create_completion_popover(EditorTab *tab) { tab->completion_popover = gtk_popover_new(); cleaf_popover_attach(tab->completion_popover, tab->popover_parent); @@ -148,6 +165,9 @@ static void tab_create_completion_popover(EditorTab *tab) { cleaf_popover_hide(tab->completion_popover); } +/** + * @brief Tab create hover popover. + */ static void tab_create_hover_popover(EditorTab *tab) { tab->hover_popover = gtk_popover_new(); cleaf_popover_attach(tab->hover_popover, tab->popover_parent); @@ -200,6 +220,9 @@ static void tab_create_hover_popover(EditorTab *tab) { cleaf_popover_hide(tab->hover_popover); } +/** + * @brief Tab pack widgets. + */ static void tab_pack_widgets(EditorTab *tab) { gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(tab->scrolled), tab->text_view); @@ -216,6 +239,9 @@ static void tab_pack_widgets(EditorTab *tab) { gtk_box_append(GTK_BOX(tab->box), tab->editor_area); } +/** + * @brief Tab create tab label. + */ static void tab_create_tab_label(EditorTab *tab) { tab->tab_widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); gtk_widget_set_size_request(tab->tab_widget, 150, -1); @@ -287,6 +313,9 @@ static void tab_connect_signals(EditorTab *tab) { gtk_widget_add_controller(tab->text_view, keys); } +/** + * @brief Editor tab new. + */ EditorTab *editor_tab_new(EditorWindow *win) { EditorTab *tab = g_new0(EditorTab, 1); if (!tab) return NULL; diff --git a/src/editor_tab_completion.c b/src/editor_tab_completion.c index 7f791d5..997c7f8 100644 --- a/src/editor_tab_completion.c +++ b/src/editor_tab_completion.c @@ -1,7 +1,18 @@ +/** + * @file src/editor_tab_completion.c + * @brief Cleaf editor tab completion module. + */ + #include "editor_tab_private.h" +/** + * @brief Completion add row with detail. + */ static void completion_add_row_with_detail(EditorTab *tab, const char *word, const char *detail); +/** + * @brief Completion contains. + */ static gboolean completion_contains(GPtrArray *items, const char *word) { if (!items || !word) return FALSE; for (guint i = 0u; i < items->len; i++) { @@ -11,6 +22,9 @@ static gboolean completion_contains(GPtrArray *items, const char *word) { return FALSE; } +/** + * @brief Completion copy candidates. + */ static void completion_copy_candidates(GPtrArray *dst, GPtrArray *src) { if (!dst || !src) return; for (guint i = 0u; i < src->len; i++) { @@ -21,6 +35,9 @@ static void completion_copy_candidates(GPtrArray *dst, GPtrArray *src) { } } +/** + * @brief Completion merge imports. + */ static void completion_merge_imports(GPtrArray *dst, GPtrArray *imports) { if (!dst || !imports) return; for (guint i = 0u; i < imports->len; i++) { @@ -32,6 +49,9 @@ static void completion_merge_imports(GPtrArray *dst, GPtrArray *imports) { } } +/** + * @brief Completion merge indexed. + */ static void completion_merge_indexed(EditorTab *tab, GPtrArray *dst, const char *prefix) { if (!tab || !dst || !prefix) return; @@ -47,6 +67,9 @@ static void completion_merge_indexed(EditorTab *tab, GPtrArray *dst, g_ptr_array_free(indexed, TRUE); } +/** + * @brief Completion build candidates. + */ static GPtrArray *completion_build_candidates(EditorTab *tab, const char *prefix, gboolean import_context, @@ -68,6 +91,9 @@ static GPtrArray *completion_build_candidates(EditorTab *tab, return items; } +/** + * @brief Completion line has word boundary. + */ static gboolean completion_line_has_word_boundary(const char *line, const char *word) { if (!line || !word || word[0] == '\0') return FALSE; @@ -85,6 +111,9 @@ static gboolean completion_line_has_word_boundary(const char *line, return FALSE; } +/** + * @brief Completion line looks like definition. + */ static gboolean completion_line_looks_like_definition(const char *trim, const char *word) { if (!trim || !word || !completion_line_has_word_boundary(trim, word)) { @@ -102,6 +131,9 @@ static gboolean completion_line_looks_like_definition(const char *trim, return FALSE; } +/** + * @brief Completion clean comment line. + */ static char *completion_clean_comment_line(const char *line) { if (!line) return NULL; char *copy = g_strdup(line); @@ -129,6 +161,9 @@ static char *completion_clean_comment_line(const char *line) { return out; } +/** + * @brief Completion detail from current buffer. + */ static char *completion_detail_from_current_buffer(EditorTab *tab, const char *word) { if (!tab || !word || word[0] == '\0') return NULL; @@ -174,6 +209,9 @@ static char *completion_detail_from_current_buffer(EditorTab *tab, return detail; } +/** + * @brief Completion update popup size. + */ static void completion_update_popup_size(EditorTab *tab, guint row_count, gboolean has_details) { @@ -189,6 +227,9 @@ static void completion_update_popup_size(EditorTab *tab, : GTK_POLICY_NEVER); } +/** + * @brief Completion populate rows. + */ static void completion_populate_rows(EditorTab *tab, GPtrArray *candidates) { completion_clear_rows(tab); if (!candidates) { @@ -210,6 +251,9 @@ static void completion_populate_rows(EditorTab *tab, GPtrArray *candidates) { has_details); } +/** + * @brief Completion place popover. + */ static void completion_place_popover(EditorTab *tab, GtkTextIter *cursor, gboolean manual) { if (!tab || !tab->text_view || !tab->popover_parent || @@ -242,11 +286,17 @@ static void completion_place_popover(EditorTab *tab, GtkTextIter *cursor, GTK_LIST_BOX(tab->completion_list), first); } +/** + * @brief Completion is visible. + */ gboolean completion_is_visible(EditorTab *tab) { return tab && tab->completion_popover && gtk_widget_get_visible(tab->completion_popover); } +/** + * @brief Editor tab hide completion. + */ void editor_tab_hide_completion(EditorTab *tab) { if (!tab) return; if (tab->completion_timeout != 0u) { @@ -257,11 +307,17 @@ void editor_tab_hide_completion(EditorTab *tab) { g_clear_pointer(&tab->completion_prefix, g_free); } +/** + * @brief Completion clear rows. + */ void completion_clear_rows(EditorTab *tab) { if (!tab || !tab->completion_list) return; cleaf_list_box_clear(tab->completion_list); } +/** + * @brief Completion insert word. + */ void completion_insert_word(EditorTab *tab, const char *word) { if (!tab || tab->locked || !word || word[0] == '\0') return; @@ -283,6 +339,9 @@ void completion_insert_word(EditorTab *tab, const char *word) { editor_tab_hide_completion(tab); } +/** + * @brief Completion row activated. + */ void completion_row_activated(GtkListBox *box, GtkListBoxRow *row, gpointer user_data) { (void)box; @@ -292,6 +351,9 @@ void completion_row_activated(GtkListBox *box, GtkListBoxRow *row, completion_insert_word(tab, word); } +/** + * @brief Completion add row with detail. + */ static void completion_add_row_with_detail(EditorTab *tab, const char *word, const char *detail) { @@ -328,10 +390,16 @@ static void completion_add_row_with_detail(EditorTab *tab, gtk_list_box_insert(GTK_LIST_BOX(tab->completion_list), row, -1); } +/** + * @brief Completion add row. + */ void completion_add_row(EditorTab *tab, const char *word) { completion_add_row_with_detail(tab, word, NULL); } +/** + * @brief Editor tab show completion. + */ void editor_tab_show_completion(EditorTab *tab, gboolean manual) { if (!tab || !tab->autocomplete_enabled) return; if (!manual && !editor_tab_live_features_allowed(tab)) return; @@ -373,6 +441,9 @@ void editor_tab_show_completion(EditorTab *tab, gboolean manual) { completion_place_popover(tab, &cursor, manual); } +/** + * @brief Completion timeout cb. + */ gboolean completion_timeout_cb(gpointer user_data) { EditorTab *tab = user_data; if (!tab) return G_SOURCE_REMOVE; @@ -381,6 +452,9 @@ gboolean completion_timeout_cb(gpointer user_data) { return G_SOURCE_REMOVE; } +/** + * @brief Editor tab schedule completion. + */ void editor_tab_schedule_completion(EditorTab *tab) { if (!tab || !tab->autocomplete_enabled || !tab->buffer) return; cleaf_source_cancel(&tab->completion_timeout); @@ -403,6 +477,9 @@ void editor_tab_schedule_completion(EditorTab *tab) { NULL); } +/** + * @brief Completion accept selected. + */ void completion_accept_selected(EditorTab *tab) { if (!tab || !tab->completion_list) return; GtkListBox *list = GTK_LIST_BOX(tab->completion_list); @@ -413,6 +490,9 @@ void completion_accept_selected(EditorTab *tab) { completion_insert_word(tab, word); } +/** + * @brief Completion select delta. + */ void completion_select_delta(EditorTab *tab, int delta) { if (!tab || !tab->completion_list) return; GtkListBox *list = GTK_LIST_BOX(tab->completion_list); diff --git a/src/editor_tab_core.c b/src/editor_tab_core.c index 93baa77..b2bc31b 100644 --- a/src/editor_tab_core.c +++ b/src/editor_tab_core.c @@ -1,3 +1,8 @@ +/** + * @file src/editor_tab_core.c + * @brief Cleaf editor tab core module. + */ + #include "editor_tab_private.h" #include "editor/editor_tab_lifecycle.inc.c" diff --git a/src/editor_tab_diagnostics.c b/src/editor_tab_diagnostics.c index ea9184a..e0d92b3 100644 --- a/src/editor_tab_diagnostics.c +++ b/src/editor_tab_diagnostics.c @@ -1,15 +1,29 @@ +/** + * @file src/editor_tab_diagnostics.c + * @brief Cleaf editor tab diagnostics module. + */ + #include "editor_tab_private.h" +/** + * @brief Editor tab diagnostics type definition. + */ typedef struct { - gunichar open_char; - gunichar close_char; - gint offset; + gunichar open_char; /**< Open char. */ + gunichar close_char; /**< Close char. */ + gint offset; /**< Offset. */ } DiagnosticFrame; +/** + * @brief Ptr array has entries. + */ static gboolean ptr_array_has_entries(GPtrArray *array) { return array && array->len > 0u; } +/** + * @brief Str ends with. + */ static gboolean str_ends_with(const char *text, const char *suffix) { if (!text || !suffix) return FALSE; gsize text_len = strlen(text); @@ -17,10 +31,16 @@ static gboolean str_ends_with(const char *text, const char *suffix) { return suffix_len <= text_len && strcmp(text + text_len - suffix_len, suffix) == 0; } +/** + * @brief Str starts with. + */ static gboolean str_starts_with(const char *text, const char *prefix) { return text && prefix && g_str_has_prefix(text, prefix); } +/** + * @brief String list matches prefix. + */ static gboolean string_list_matches_prefix(GPtrArray *items, const char *text) { if (!items || !text) return FALSE; for (guint i = 0u; i < items->len; i++) { @@ -30,6 +50,9 @@ static gboolean string_list_matches_prefix(GPtrArray *items, const char *text) { return FALSE; } +/** + * @brief String list matches suffix. + */ static gboolean string_list_matches_suffix(GPtrArray *items, const char *text) { if (!items || !text) return FALSE; for (guint i = 0u; i < items->len; i++) { @@ -39,6 +62,9 @@ static gboolean string_list_matches_suffix(GPtrArray *items, const char *text) { return FALSE; } +/** + * @brief Strip inline line comment. + */ static char *strip_inline_line_comment(const char *line, const char *comment) { if (!line) return g_strdup(""); if (!comment || comment[0] == '\0') return g_strdup(line); @@ -48,6 +74,9 @@ static char *strip_inline_line_comment(const char *line, const char *comment) { return g_strndup(line, (gsize)(hit - line)); } +/** + * @brief Line needs statement ender. + */ static gboolean line_needs_statement_ender(SyntaxDef *syntax, const char *line) { if (!syntax || !ptr_array_has_entries(syntax->statement_required_enders) || !line) return FALSE; @@ -69,6 +98,9 @@ static gboolean line_needs_statement_ender(SyntaxDef *syntax, const char *line) return TRUE; } +/** + * @brief Line missing required closer. + */ static gboolean line_missing_required_closer(SyntaxDef *syntax, const char *line) { if (!syntax || !ptr_array_has_entries(syntax->line_close_pairs) || !line) return FALSE; @@ -83,6 +115,9 @@ static gboolean line_missing_required_closer(SyntaxDef *syntax, const char *line return FALSE; } +/** + * @brief Apply diagnostic line. + */ static void apply_diagnostic_line(EditorTab *tab, gint line_no, guint *count) { if (!tab || !tab->buffer || line_no < 0) return; GtkTextIter start; @@ -94,6 +129,9 @@ static void apply_diagnostic_line(EditorTab *tab, gint line_no, guint *count) { if (count) (*count)++; } +/** + * @brief Apply diagnostic offset. + */ static void apply_diagnostic_offset(EditorTab *tab, gint offset, guint *count) { if (!tab || !tab->buffer || offset < 0) return; GtkTextIter iter; @@ -101,6 +139,9 @@ static void apply_diagnostic_offset(EditorTab *tab, gint offset, guint *count) { apply_diagnostic_line(tab, gtk_text_iter_get_line(&iter), count); } +/** + * @brief Syntax pair is single char. + */ static gboolean syntax_pair_is_single_char(SyntaxPair *pair, gunichar *open_char, gunichar *close_char) { @@ -116,6 +157,9 @@ static gboolean syntax_pair_is_single_char(SyntaxPair *pair, return TRUE; } +/** + * @brief Pair index for open. + */ static gint pair_index_for_open(SyntaxDef *syntax, gunichar ch, gunichar *close_char) { if (!syntax || !syntax->close_pairs) return -1; for (guint i = 0u; i < syntax->close_pairs->len; i++) { @@ -131,6 +175,9 @@ static gint pair_index_for_open(SyntaxDef *syntax, gunichar ch, gunichar *close_ return -1; } +/** + * @brief Is any close char. + */ static gboolean is_any_close_char(SyntaxDef *syntax, gunichar ch) { if (!syntax || !syntax->close_pairs) return FALSE; for (guint i = 0u; i < syntax->close_pairs->len; i++) { @@ -143,6 +190,9 @@ static gboolean is_any_close_char(SyntaxDef *syntax, gunichar ch) { return FALSE; } +/** + * @brief Frame array push. + */ static void frame_array_push(GArray *stack, gunichar open_char, gunichar close_char, gint offset) { DiagnosticFrame frame; @@ -152,6 +202,9 @@ static void frame_array_push(GArray *stack, gunichar open_char, g_array_append_val(stack, frame); } +/** + * @brief Frame array pop if matches. + */ static gboolean frame_array_pop_if_matches(GArray *stack, gunichar close_char) { if (!stack || stack->len == 0u) return FALSE; DiagnosticFrame frame = g_array_index(stack, DiagnosticFrame, stack->len - 1u); @@ -160,6 +213,9 @@ static gboolean frame_array_pop_if_matches(GArray *stack, gunichar close_char) { return TRUE; } +/** + * @brief Apply unbalanced pair diagnostics. + */ static void apply_unbalanced_pair_diagnostics(EditorTab *tab, const char *text, guint *count) { @@ -225,6 +281,9 @@ static void apply_unbalanced_pair_diagnostics(EditorTab *tab, g_array_free(stack, TRUE); } +/** + * @brief Apply line diagnostics. + */ static void apply_line_diagnostics(EditorTab *tab, guint *count) { if (!tab || !tab->buffer || !tab->active_syntax) return; SyntaxDef *syntax = tab->active_syntax; @@ -247,13 +306,16 @@ static void apply_line_diagnostics(EditorTab *tab, guint *count) { } } +/** + * @brief Ensure diagnostic tag. + */ void ensure_diagnostic_tag(EditorTab *tab) { if (!tab || !tab->buffer) return; const char *bg = tab->win && tab->win->diagnostic_warning_bg_color ? tab->win->diagnostic_warning_bg_color : "#5f4b24"; const char *fg = tab->win && tab->win->diagnostic_warning_fg_color ? tab->win->diagnostic_warning_fg_color : "#ffd166"; - GdkRGBA underline = { 1.0, 0.70, 0.15, 1.0 }; + GdkRGBA underline = { 1.0f, 0.70f, 0.15f, 1.0f }; if (fg && fg[0] == '#') (void)gdk_rgba_parse(&underline, fg); GtkTextTagTable *table = gtk_text_buffer_get_tag_table(tab->buffer); GtkTextTag *tag = gtk_text_tag_table_lookup(table, "cleaf-diagnostic-warning"); @@ -274,6 +336,9 @@ void ensure_diagnostic_tag(EditorTab *tab) { NULL); } +/** + * @brief Clear syntax diagnostics. + */ void clear_syntax_diagnostics(EditorTab *tab) { if (!tab || !tab->buffer) return; if (tab->diagnostics_active) { @@ -289,6 +354,9 @@ void clear_syntax_diagnostics(EditorTab *tab) { tab->diagnostic_warnings = 0u; } +/** + * @brief Editor tab apply syntax diagnostics. + */ void editor_tab_apply_syntax_diagnostics(EditorTab *tab) { if (!tab || !tab->buffer) return; if (!editor_tab_live_features_allowed(tab)) { @@ -325,6 +393,9 @@ void editor_tab_apply_syntax_diagnostics(EditorTab *tab) { editor_tab_schedule_lightweight_ui_refresh(tab); } +/** + * @brief Diagnostics timeout cb. + */ gboolean diagnostics_timeout_cb(gpointer user_data) { EditorTab *tab = user_data; if (!tab) return G_SOURCE_REMOVE; @@ -333,6 +404,9 @@ gboolean diagnostics_timeout_cb(gpointer user_data) { return G_SOURCE_REMOVE; } +/** + * @brief Editor tab schedule syntax diagnostics. + */ void editor_tab_schedule_syntax_diagnostics(EditorTab *tab) { if (!tab) return; cleaf_source_cancel(&tab->diagnostics_timeout); diff --git a/src/editor_tab_edit.c b/src/editor_tab_edit.c index 5d3bcef..b4d0654 100644 --- a/src/editor_tab_edit.c +++ b/src/editor_tab_edit.c @@ -1,5 +1,13 @@ +/** + * @file src/editor_tab_edit.c + * @brief Cleaf editor tab edit module. + */ + #include "editor_tab_private.h" +/** + * @brief Editor tab cut clipboard. + */ void editor_tab_cut_clipboard(EditorTab *tab) { if (!tab || tab->locked) return; GdkClipboard *clipboard = gtk_widget_get_clipboard(tab->text_view); @@ -7,6 +15,9 @@ void editor_tab_cut_clipboard(EditorTab *tab) { } +/** + * @brief Editor tab copy clipboard. + */ void editor_tab_copy_clipboard(EditorTab *tab) { if (!tab) return; GdkClipboard *clipboard = gtk_widget_get_clipboard(tab->text_view); @@ -14,6 +25,9 @@ void editor_tab_copy_clipboard(EditorTab *tab) { } +/** + * @brief Editor tab paste clipboard. + */ void editor_tab_paste_clipboard(EditorTab *tab) { if (!tab || tab->locked) return; GdkClipboard *clipboard = gtk_widget_get_clipboard(tab->text_view); @@ -21,6 +35,9 @@ void editor_tab_paste_clipboard(EditorTab *tab) { } +/** + * @brief Editor tab select all. + */ void editor_tab_select_all(EditorTab *tab) { if (!tab) return; GtkTextIter start; @@ -30,6 +47,9 @@ void editor_tab_select_all(EditorTab *tab) { } +/** + * @brief Editor tab cut line. + */ void editor_tab_cut_line(EditorTab *tab) { if (!tab || tab->locked) return; GtkTextIter iter; @@ -48,6 +68,9 @@ void editor_tab_cut_line(EditorTab *tab) { } +/** + * @brief Editor tab paste cut line. + */ void editor_tab_paste_cut_line(EditorTab *tab) { if (!tab || tab->locked || !tab->kill_buffer) return; GtkTextIter iter; @@ -57,6 +80,9 @@ void editor_tab_paste_cut_line(EditorTab *tab) { } +/** + * @brief Select match. + */ gboolean select_match(EditorTab *tab, GtkTextIter *start, GtkTextIter *end) { if (!tab || !start || !end) return FALSE; gtk_text_buffer_select_range(tab->buffer, start, end); @@ -65,6 +91,9 @@ gboolean select_match(EditorTab *tab, GtkTextIter *start, GtkTextIter *end) { } +/** + * @brief Editor tab find. + */ void editor_tab_find(EditorTab *tab, const char *query, gboolean backwards) { if (!tab || !query || query[0] == '\0') return; g_free(tab->search_text); @@ -103,6 +132,9 @@ void editor_tab_find(EditorTab *tab, const char *query, gboolean backwards) { } +/** + * @brief Editor tab replace current. + */ void editor_tab_replace_current(EditorTab *tab, const char *find, const char *replace) { if (!tab || tab->locked || !find || find[0] == '\0' || !replace) return; GtkTextIter start; @@ -121,6 +153,9 @@ void editor_tab_replace_current(EditorTab *tab, const char *find, const char *re } +/** + * @brief Editor tab replace all. + */ void editor_tab_replace_all(EditorTab *tab, const char *find, const char *replace) { if (!tab || tab->locked || !find || find[0] == '\0' || !replace) return; GtkTextIter search_from; @@ -146,6 +181,9 @@ void editor_tab_replace_all(EditorTab *tab, const char *find, const char *replac } +/** + * @brief Editor tab toggle comment. + */ void editor_tab_toggle_comment(EditorTab *tab) { if (!tab || tab->locked) return; const char *comment = "#"; @@ -201,6 +239,9 @@ void editor_tab_toggle_comment(EditorTab *tab) { } +/** + * @brief Editor tab go to line. + */ void editor_tab_go_to_line(EditorTab *tab) { if (!tab) return; char *line_text = dialog_prompt_text(app_window_gtk(tab->win), "Go to Line", "Line:", NULL); @@ -220,6 +261,9 @@ void editor_tab_go_to_line(EditorTab *tab) { } +/** + * @brief Editor tab justify paragraph. + */ void editor_tab_justify_paragraph(EditorTab *tab) { if (!tab || tab->locked) return; GtkTextIter insert; diff --git a/src/editor_tab_gutter.c b/src/editor_tab_gutter.c index b073b03..7386812 100644 --- a/src/editor_tab_gutter.c +++ b/src/editor_tab_gutter.c @@ -1,5 +1,13 @@ +/** + * @file src/editor_tab_gutter.c + * @brief Cleaf editor tab gutter module. + */ + #include "editor_tab_private.h" +/** + * @brief Decimal digits. + */ int decimal_digits(int value) { int digits = 1; while (value >= 10) { @@ -10,6 +18,9 @@ int decimal_digits(int value) { } +/** + * @brief Update gutter width. + */ void update_gutter_width(EditorTab *tab) { if (!tab || !tab->buffer || !tab->gutter) return; if (!gtk_widget_get_visible(tab->gutter)) return; @@ -25,6 +36,9 @@ void update_gutter_width(EditorTab *tab) { } +/** + * @brief Gutter draw background. + */ static void gutter_draw_background(GtkWidget *widget, cairo_t *cr, gint width, gint height) { (void)widget; @@ -37,6 +51,9 @@ static void gutter_draw_background(GtkWidget *widget, cairo_t *cr, cairo_fill(cr); } +/** + * @brief Gutter draw line number. + */ static void gutter_draw_line_number(cairo_t *cr, PangoLayout *layout, gint gutter_width, gint draw_y, gint line_height, int line_no, @@ -65,6 +82,9 @@ static void gutter_draw_line_number(cairo_t *cr, PangoLayout *layout, g_free(num); } +/** + * @brief On gutter draw. + */ void on_gutter_draw(GtkDrawingArea *area, cairo_t *cr, int draw_width, int draw_height, gpointer user_data) { GtkWidget *widget = GTK_WIDGET(area); @@ -113,6 +133,9 @@ void on_gutter_draw(GtkDrawingArea *area, cairo_t *cr, int draw_width, } +/** + * @brief Sync minimap scroll. + */ static void sync_minimap_scroll(EditorTab *tab, GtkAdjustment *main_adj) { if (!tab || !tab->minimap_scrolled || !main_adj) return; GtkAdjustment *mini_adj = gtk_scrolled_window_get_vadjustment( @@ -135,6 +158,9 @@ static void sync_minimap_scroll(EditorTab *tab, GtkAdjustment *main_adj) { gtk_adjustment_set_value(mini_adj, ratio * mini_max); } +/** + * @brief On vadjustment value changed. + */ void on_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer user_data) { EditorTab *tab = user_data; if (tab && tab->gutter) gtk_widget_queue_draw(tab->gutter); @@ -145,6 +171,9 @@ void on_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer user_data) } +/** + * @brief Ensure match tag. + */ void ensure_match_tag(EditorTab *tab) { if (!tab || !tab->buffer) return; const char *bg = tab->win && tab->win->search_match_bg_color ? @@ -166,16 +195,25 @@ void ensure_match_tag(EditorTab *tab) { } +/** + * @brief Ensure minimap match tag. + */ void ensure_minimap_match_tag(EditorTab *tab) { (void)tab; } +/** + * @brief Clear minimap matches. + */ void clear_minimap_matches(EditorTab *tab) { if (tab && tab->minimap_view) gtk_widget_queue_draw(tab->minimap_view); } +/** + * @brief Clear selection matches. + */ void clear_selection_matches(EditorTab *tab) { if (!tab || !tab->buffer) return; if (tab->selection_matches_active) { @@ -192,6 +230,9 @@ void clear_selection_matches(EditorTab *tab) { } +/** + * @brief Apply minimap match. + */ void apply_minimap_match(EditorTab *tab, GtkTextIter *start, GtkTextIter *end) { (void)start; (void)end; @@ -199,6 +240,9 @@ void apply_minimap_match(EditorTab *tab, GtkTextIter *start, GtkTextIter *end) { } +/** + * @brief Update selection matches. + */ void update_selection_matches(EditorTab *tab) { if (!tab || !tab->buffer) return; ensure_match_tag(tab); @@ -238,6 +282,9 @@ void update_selection_matches(EditorTab *tab) { } +/** + * @brief Selection match timeout cb. + */ gboolean selection_match_timeout_cb(gpointer user_data) { EditorTab *tab = user_data; if (!tab) return G_SOURCE_REMOVE; @@ -247,6 +294,9 @@ gboolean selection_match_timeout_cb(gpointer user_data) { } +/** + * @brief Editor tab schedule selection matches. + */ void editor_tab_schedule_selection_matches(EditorTab *tab) { if (!tab || !tab->buffer) return; cleaf_source_cancel(&tab->selection_match_timeout); @@ -277,6 +327,9 @@ void editor_tab_schedule_selection_matches(EditorTab *tab) { } +/** + * @brief Update minimap text. + */ void update_minimap_text(EditorTab *tab) { if (!tab || !tab->minimap_view || tab->minimap_updating) return; if (!tab->win || !tab->win->minimap_enabled) return; @@ -291,6 +344,9 @@ void update_minimap_text(EditorTab *tab) { } +/** + * @brief Minimap line is comment. + */ static gboolean minimap_line_is_comment(const char *text) { if (!text) return FALSE; while (*text == ' ' || *text == '\t') text++; @@ -298,16 +354,25 @@ static gboolean minimap_line_is_comment(const char *text) { g_str_has_prefix(text, "*") || g_str_has_prefix(text, "#"); } +/** + * @brief Minimap line has string. + */ static gboolean minimap_line_has_string(const char *text) { return text && (strchr(text, '"') || strchr(text, '\'')); } +/** + * @brief Minimap line is preprocessor. + */ static gboolean minimap_line_is_preprocessor(const char *text) { if (!text) return FALSE; while (*text == ' ' || *text == '\t') text++; return text[0] == '#'; } +/** + * @brief Minimap set line colour. + */ static void minimap_set_line_colour(cairo_t *cr, const char *line) { if (minimap_line_is_preprocessor(line)) { cairo_set_source_rgb(cr, 0.77, 0.53, 0.78); @@ -320,6 +385,9 @@ static void minimap_set_line_colour(cairo_t *cr, const char *line) { } } +/** + * @brief On minimap draw. + */ void on_minimap_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) { (void)area; @@ -382,6 +450,9 @@ void on_minimap_draw(GtkDrawingArea *area, cairo_t *cr, int width, } +/** + * @brief On minimap click. + */ void on_minimap_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data) { (void)n_press; diff --git a/src/editor_tab_hover.c b/src/editor_tab_hover.c index 9f7e627..d6cba92 100644 --- a/src/editor_tab_hover.c +++ b/src/editor_tab_hover.c @@ -1,3 +1,8 @@ +/** + * @file src/editor_tab_hover.c + * @brief Cleaf editor tab hover module. + */ + #include "editor_tab_private.h" #include "editor/editor_tab_hover_refs.inc.c" diff --git a/src/editor_tab_io.c b/src/editor_tab_io.c index da6f675..61ba480 100644 --- a/src/editor_tab_io.c +++ b/src/editor_tab_io.c @@ -1,9 +1,17 @@ +/** + * @file src/editor_tab_io.c + * @brief Cleaf editor tab io module. + */ + #include "editor_tab_private.h" #include "git.h" #include #include +/** + * @brief Write all fd. + */ gboolean write_all_fd(int fd, const char *data, gsize len) { const char *cursor = data; gsize remaining = len; @@ -22,6 +30,9 @@ gboolean write_all_fd(int fd, const char *data, gsize len) { } +/** + * @brief Write text atomic. + */ gboolean write_text_atomic(const char *path, const char *text, GError **error) { if (!path || path[0] == '\0' || !text) return FALSE; @@ -82,6 +93,9 @@ gboolean write_text_atomic(const char *path, const char *text, GError **error) { } +/** + * @brief Autosave path for tab. + */ char *autosave_path_for_tab(EditorTab *tab) { if (!tab) return NULL; const char *cache = g_get_user_cache_dir(); @@ -106,6 +120,9 @@ char *autosave_path_for_tab(EditorTab *tab) { +/** + * @brief Cleanup legacy tilde backup. + */ static void cleanup_legacy_tilde_backup(const char *path) { if (!path || path[0] == '\0') return; char *legacy = g_strdup_printf("%s~", path); @@ -115,6 +132,9 @@ static void cleanup_legacy_tilde_backup(const char *path) { g_free(legacy); } +/** + * @brief Editor tab load file. + */ gboolean editor_tab_load_file(EditorTab *tab, const char *path) { if (!tab || !path) return FALSE; char *contents = NULL; @@ -159,6 +179,9 @@ gboolean editor_tab_load_file(EditorTab *tab, const char *path) { } +/** + * @brief Write backup if needed. + */ gboolean write_backup_if_needed(EditorTab *tab, const char *path) { if (!tab || !tab->backup_enabled || !path || !g_file_test(path, G_FILE_TEST_EXISTS)) return TRUE; @@ -212,6 +235,9 @@ gboolean write_backup_if_needed(EditorTab *tab, const char *path) { } +/** + * @brief Save to path. + */ gboolean save_to_path(EditorTab *tab, const char *path) { if (!tab || !path || path[0] == '\0') return FALSE; @@ -254,6 +280,9 @@ gboolean save_to_path(EditorTab *tab, const char *path) { } +/** + * @brief Editor tab save. + */ gboolean editor_tab_save(EditorTab *tab, gboolean force_dialog) { if (!tab) return FALSE; if (tab->locked) { @@ -275,12 +304,18 @@ gboolean editor_tab_save(EditorTab *tab, gboolean force_dialog) { } +/** + * @brief Close dialog button. + */ static GtkWidget *close_dialog_button(const char *label, int response) { return cleaf_flat_button_new(label, NULL, G_CALLBACK(cleaf_modal_window_respond), GINT_TO_POINTER(response)); } +/** + * @brief Editor tab confirm close. + */ gboolean editor_tab_confirm_close(EditorTab *tab) { if (!tab || !tab->modified) return TRUE; @@ -332,6 +367,9 @@ gboolean editor_tab_confirm_close(EditorTab *tab) { } +/** + * @brief Editor tab auto save. + */ gboolean editor_tab_auto_save(EditorTab *tab) { if (!tab || !tab->modified) return TRUE; if (tab->file_path) return save_to_path(tab, tab->file_path); diff --git a/src/editor_tab_keys.c b/src/editor_tab_keys.c index 5527c3e..83cd58c 100644 --- a/src/editor_tab_keys.c +++ b/src/editor_tab_keys.c @@ -1,6 +1,14 @@ +/** + * @file src/editor_tab_keys.c + * @brief Cleaf editor tab keys module. + */ + #include "editor_tab_private.h" +/** + * @brief Text between iters. + */ static char *text_between_iters(GtkTextBuffer *buffer, const GtkTextIter *start, const GtkTextIter *end) { @@ -8,6 +16,9 @@ static char *text_between_iters(GtkTextBuffer *buffer, return gtk_text_buffer_get_text(buffer, start, end, FALSE); } +/** + * @brief Line leading indent. + */ static char *line_leading_indent(const char *line) { if (!line) return g_strdup(""); const char *p = line; @@ -15,12 +26,18 @@ static char *line_leading_indent(const char *line) { return g_strndup(line, (gsize)(p - line)); } +/** + * @brief Trimmed copy. + */ static char *trimmed_copy(const char *text) { char *copy = g_strdup(text ? text : ""); if (!copy) return NULL; return g_strstrip(copy); } +/** + * @brief Syntax has suffix token. + */ static gboolean syntax_has_suffix_token(GPtrArray *tokens, const char *text, const char *fallback) { @@ -35,6 +52,9 @@ static gboolean syntax_has_suffix_token(GPtrArray *tokens, return fallback && g_str_has_suffix(text, fallback); } +/** + * @brief Syntax has prefix token. + */ static gboolean syntax_has_prefix_token(GPtrArray *tokens, const char *text, const char *fallback) { @@ -49,6 +69,9 @@ static gboolean syntax_has_prefix_token(GPtrArray *tokens, return fallback && g_str_has_prefix(text, fallback); } +/** + * @brief First indent opener. + */ static const char *first_indent_opener(EditorTab *tab) { if (tab && tab->active_syntax && tab->active_syntax->indent_openers && tab->active_syntax->indent_openers->len > 0u) { @@ -58,6 +81,9 @@ static const char *first_indent_opener(EditorTab *tab) { return "{"; } +/** + * @brief First indent closer. + */ static const char *first_indent_closer(EditorTab *tab) { if (tab && tab->active_syntax && tab->active_syntax->indent_closers && tab->active_syntax->indent_closers->len > 0u) { @@ -67,10 +93,16 @@ static const char *first_indent_closer(EditorTab *tab) { return "}"; } +/** + * @brief Auto indent enabled. + */ static gboolean auto_indent_enabled(EditorTab *tab) { return !tab || !tab->active_syntax || tab->active_syntax->auto_indent; } +/** + * @brief Insert block newline. + */ static void insert_block_newline(EditorTab *tab, GtkTextIter *iter, const char *base_indent, @@ -91,6 +123,9 @@ static void insert_block_newline(EditorTab *tab, gtk_text_buffer_delete_mark(buffer, cursor_mark); } +/** + * @brief Line before has adjacent indent pair. + */ static gboolean line_before_has_adjacent_indent_pair(EditorTab *tab, const char *trimmed_before) { if (!tab || !trimmed_before) return FALSE; @@ -110,6 +145,9 @@ static gboolean line_before_has_adjacent_indent_pair(EditorTab *tab, return result; } +/** + * @brief Handle return key. + */ static gboolean handle_return_key(EditorTab *tab) { if (!tab || tab->locked || !tab->buffer || !auto_indent_enabled(tab)) return FALSE; @@ -163,27 +201,60 @@ static gboolean handle_return_key(EditorTab *tab) { return TRUE; } +/** + * @brief Menu undo. + */ void menu_undo(GtkWidget *w, gpointer data) { (void)w; editor_tab_undo(data); } +/** + * @brief Menu redo. + */ void menu_redo(GtkWidget *w, gpointer data) { (void)w; editor_tab_redo(data); } +/** + * @brief Menu cut. + */ void menu_cut(GtkWidget *w, gpointer data) { (void)w; editor_tab_cut_clipboard(data); } +/** + * @brief Menu copy. + */ void menu_copy(GtkWidget *w, gpointer data) { (void)w; editor_tab_copy_clipboard(data); } +/** + * @brief Menu paste. + */ void menu_paste(GtkWidget *w, gpointer data) { (void)w; editor_tab_paste_clipboard(data); } +/** + * @brief Menu select all. + */ void menu_select_all(GtkWidget *w, gpointer data) { (void)w; editor_tab_select_all(data); } +/** + * @brief Menu cut line. + */ void menu_cut_line(GtkWidget *w, gpointer data) { (void)w; editor_tab_cut_line(data); } +/** + * @brief Menu paste line. + */ void menu_paste_line(GtkWidget *w, gpointer data) { (void)w; editor_tab_paste_cut_line(data); } +/** + * @brief Menu comment. + */ void menu_comment(GtkWidget *w, gpointer data) { (void)w; editor_tab_toggle_comment(data); } +/** + * @brief Menu complete. + */ void menu_complete(GtkWidget *w, gpointer data) { (void)w; editor_tab_show_completion(data, TRUE); } +/** + * @brief Tab unit. + */ char *tab_unit(EditorTab *tab) { if (!tab || !tab->insert_spaces) return g_strdup("\t"); guint width = tab->tab_width == 0u ? 4u : tab->tab_width; @@ -192,6 +263,9 @@ char *tab_unit(EditorTab *tab) { } +/** + * @brief Selection line bounds. + */ void selection_line_bounds(EditorTab *tab, int *start_line_out, int *end_line_out, gboolean *has_selection_out) { GtkTextIter start; GtkTextIter end; @@ -210,6 +284,9 @@ void selection_line_bounds(EditorTab *tab, int *start_line_out, int *end_line_ou } +/** + * @brief Insert tab or indent. + */ void insert_tab_or_indent(EditorTab *tab) { if (!tab || tab->locked) return; char *unit = tab_unit(tab); @@ -238,6 +315,9 @@ void insert_tab_or_indent(EditorTab *tab) { } +/** + * @brief Unindent line. + */ void unindent_line(EditorTab *tab, int line) { if (!tab || tab->locked || line < 0) return; GtkTextIter start; @@ -261,6 +341,9 @@ void unindent_line(EditorTab *tab, int line) { } +/** + * @brief Unindent selection or line. + */ void unindent_selection_or_line(EditorTab *tab) { if (!tab || tab->locked) return; int start_line = 0; @@ -275,6 +358,9 @@ void unindent_selection_or_line(EditorTab *tab) { } +/** + * @brief On text view key pressed. + */ gboolean on_text_view_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, @@ -328,6 +414,9 @@ gboolean on_text_view_key_pressed(GtkEventControllerKey *controller, } +/** + * @brief On text view key released. + */ void on_text_view_key_released(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data) { @@ -336,11 +425,9 @@ void on_text_view_key_released(GtkEventControllerKey *controller, (void)state; EditorTab *tab = user_data; if (!tab) return; - guint key = gdk_keyval_to_lower(keyval); if (keyval == GDK_KEY_Alt_L || keyval == GDK_KEY_Alt_R) { tab->inspect_reference_active = FALSE; if (!tab->hover_pointer_inside) hide_hover_preview(tab); } } - diff --git a/src/editor_tab_latex.c b/src/editor_tab_latex.c index 532c778..f2b03a9 100644 --- a/src/editor_tab_latex.c +++ b/src/editor_tab_latex.c @@ -1,10 +1,21 @@ +/** + * @file src/editor_tab_latex.c + * @brief Cleaf editor tab latex module. + */ + #include "editor_tab_private.h" #include #include +/** + * @brief Latex build dir macro. + */ #define LATEX_BUILD_DIR ".cleaf-latex-build" +/** + * @brief Has space. + */ static gboolean has_space(const char *text) { const unsigned char *p = (const unsigned char *)text; while (p && *p != '\0') { @@ -14,6 +25,9 @@ static gboolean has_space(const char *text) { return FALSE; } +/** + * @brief Find latex command. + */ static char *find_latex_command(void) { const char *env = g_getenv("CLEAF_LATEX_COMMAND"); if (env && env[0] != '\0' && !has_space(env)) return g_strdup(env); @@ -35,6 +49,9 @@ static char *find_latex_command(void) { return NULL; } +/** + * @brief Basename without suffix. + */ static char *basename_without_suffix(const char *path) { char *base = g_path_get_basename(path ? path : "document.tex"); char *dot = base ? strrchr(base, '.') : NULL; @@ -46,6 +63,9 @@ static char *basename_without_suffix(const char *path) { return base; } +/** + * @brief Ensure saved source. + */ static gboolean ensure_saved_source(EditorTab *tab, char **source_path_out) { if (!tab || !source_path_out) return FALSE; @@ -84,6 +104,9 @@ static gboolean ensure_saved_source(EditorTab *tab, char **source_path_out) { return TRUE; } +/** + * @brief Build output dir for source. + */ static char *build_output_dir_for_source(const char *source_path) { char *dir = g_path_get_dirname(source_path); if (!dir) return NULL; @@ -97,6 +120,9 @@ static char *build_output_dir_for_source(const char *source_path) { return output; } +/** + * @brief Latex log message. + */ static char *latex_log_message(const char *command, const char *stdout_text, const char *stderr_text) { @@ -116,6 +142,9 @@ static char *latex_log_message(const char *command, return g_string_free(msg, FALSE); } +/** + * @brief Run latex. + */ static gboolean run_latex(EditorTab *tab, const char *command, const char *source_path, @@ -157,6 +186,9 @@ static gboolean run_latex(EditorTab *tab, return TRUE; } +/** + * @brief Open pdf. + */ static void open_pdf(EditorTab *tab, const char *pdf_path) { GError *error = NULL; char *uri = g_filename_to_uri(pdf_path, NULL, &error); @@ -175,6 +207,9 @@ static void open_pdf(EditorTab *tab, const char *pdf_path) { g_free(uri); } +/** + * @brief Editor tab render latex. + */ void editor_tab_render_latex(EditorTab *tab) { if (!tab || !tab->win) return; if (!editor_tab_is_latex(tab)) { diff --git a/src/editor_tab_preview.c b/src/editor_tab_preview.c index 7b8a46e..5074d5c 100644 --- a/src/editor_tab_preview.c +++ b/src/editor_tab_preview.c @@ -1,20 +1,37 @@ +/** + * @file src/editor_tab_preview.c + * @brief Cleaf editor tab preview module. + */ + #include "editor_tab_private.h" #include #include +/** + * @brief Preview max bytes macro. + */ #define PREVIEW_MAX_BYTES (2u * 1024u * 1024u) +/** + * @brief Editor tab preview type definition. + */ typedef struct { - GtkTextBuffer *buffer; - GtkTextIter iter; + GtkTextBuffer *buffer; /**< Buffer. */ + GtkTextIter iter; /**< Iter. */ } PreviewWriter; +/** + * @brief Editor tab preview type definition. + */ typedef struct { - GtkWidget *scrolled; - gdouble value; + GtkWidget *scrolled; /**< Scrolled. */ + gdouble value; /**< Value. */ } PreviewScrollRestore; +/** + * @brief Preview restore scroll cb. + */ static gboolean preview_restore_scroll_cb(gpointer user_data) { PreviewScrollRestore *restore = user_data; if (!restore || !restore->scrolled) { @@ -33,6 +50,9 @@ static gboolean preview_restore_scroll_cb(gpointer user_data) { return G_SOURCE_REMOVE; } +/** + * @brief Preview restore scroll later. + */ static void preview_restore_scroll_later(GtkWidget *scrolled, gdouble value) { if (!scrolled) return; PreviewScrollRestore *restore = g_new0(PreviewScrollRestore, 1); @@ -41,34 +61,55 @@ static void preview_restore_scroll_later(GtkWidget *scrolled, gdouble value) { g_idle_add_full(G_PRIORITY_LOW, preview_restore_scroll_cb, restore, NULL); } +/** + * @brief Str has prefix. + */ static gboolean str_has_prefix(const char *text, const char *prefix) { return text && prefix && g_str_has_prefix(text, prefix); } +/** + * @brief Syntax name is. + */ static gboolean syntax_name_is(EditorTab *tab, const char *name) { const char *syntax = NULL; if (tab && tab->active_syntax) syntax = tab->active_syntax->name; return syntax && name && g_ascii_strcasecmp(syntax, name) == 0; } +/** + * @brief Path has suffix. + */ static gboolean path_has_suffix(EditorTab *tab, const char *suffix) { return tab && tab->file_path && suffix && g_str_has_suffix(tab->file_path, suffix); } +/** + * @brief Preview is markdown. + */ static gboolean preview_is_markdown(EditorTab *tab) { return syntax_name_is(tab, "Markdown") || path_has_suffix(tab, ".md") || path_has_suffix(tab, ".markdown"); } +/** + * @brief Editor tab is latex. + */ gboolean editor_tab_is_latex(EditorTab *tab) { return syntax_name_is(tab, "LaTeX") || syntax_name_is(tab, "Tex") || path_has_suffix(tab, ".tex") || path_has_suffix(tab, ".latex"); } +/** + * @brief Preview is supported. + */ gboolean preview_is_supported(EditorTab *tab) { return preview_is_markdown(tab) || editor_tab_is_latex(tab); } +/** + * @brief Ensure tag. + */ static void ensure_tag(GtkTextBuffer *buffer, const char *name, const char *first_property, @@ -85,6 +126,9 @@ static void ensure_tag(GtkTextBuffer *buffer, g_object_unref(tag); } +/** + * @brief Preview ensure tags. + */ void preview_ensure_tags(EditorTab *tab) { if (!tab || !tab->preview_buffer) return; GtkTextBuffer *buffer = tab->preview_buffer; @@ -106,15 +150,24 @@ void preview_ensure_tags(EditorTab *tab) { "foreground", "#4EC9B0", NULL); } +/** + * @brief Writer init. + */ static void writer_init(PreviewWriter *writer, GtkTextBuffer *buffer) { writer->buffer = buffer; gtk_text_buffer_get_end_iter(buffer, &writer->iter); } +/** + * @brief Writer insert. + */ static void writer_insert(PreviewWriter *writer, const char *text) { gtk_text_buffer_insert(writer->buffer, &writer->iter, text ? text : "", -1); } +/** + * @brief Writer insert tag. + */ static void writer_insert_tag(PreviewWriter *writer, const char *text, const char *tag) { @@ -130,6 +183,9 @@ static void writer_insert_tag(PreviewWriter *writer, gtk_text_buffer_apply_tag_by_name(writer->buffer, tag, &start, &end); } +/** + * @brief Line without prefix. + */ static char *line_without_prefix(const char *line, guint count) { const char *p = line ? line : ""; while (*p == ' ' || *p == '\t') p++; @@ -141,6 +197,9 @@ static char *line_without_prefix(const char *line, guint count) { return g_strdup(p); } +/** + * @brief Render markdown inline. + */ static void render_markdown_inline(PreviewWriter *writer, const char *line) { const char *p = line ? line : ""; while (*p != '\0') { @@ -182,6 +241,9 @@ static void render_markdown_inline(PreviewWriter *writer, const char *line) { } } +/** + * @brief Render markdown line. + */ static void render_markdown_line(PreviewWriter *writer, const char *line, gboolean *in_code) { @@ -224,6 +286,9 @@ static void render_markdown_line(PreviewWriter *writer, } } +/** + * @brief Preview render markdown. + */ void preview_render_markdown(EditorTab *tab, const char *text) { PreviewWriter writer; writer_init(&writer, tab->preview_buffer); @@ -235,6 +300,9 @@ void preview_render_markdown(EditorTab *tab, const char *text) { g_strfreev(lines); } +/** + * @brief Latex arg. + */ static char *latex_arg(const char *line, const char *command) { const char *start = strstr(line ? line : "", command); if (!start) return NULL; @@ -245,11 +313,17 @@ static char *latex_arg(const char *line, const char *command) { return g_strndup(start + 1, (gsize)(end - start - 1)); } +/** + * @brief Latex is math line. + */ static gboolean latex_is_math_line(const char *line) { return str_has_prefix(line, "$$") || str_has_prefix(line, "\\[") || str_has_prefix(line, "\\(") || strchr(line ? line : "", '$'); } +/** + * @brief Render latex line. + */ static void render_latex_line(PreviewWriter *writer, const char *line) { char *text = NULL; if ((text = latex_arg(line, "\\section"))) { @@ -275,6 +349,9 @@ static void render_latex_line(PreviewWriter *writer, const char *line) { g_free(text); } +/** + * @brief Preview render latex. + */ void preview_render_latex(EditorTab *tab, const char *text) { PreviewWriter writer; writer_init(&writer, tab->preview_buffer); @@ -285,6 +362,9 @@ void preview_render_latex(EditorTab *tab, const char *text) { g_strfreev(lines); } +/** + * @brief Editor tab update preview. + */ void editor_tab_update_preview(EditorTab *tab) { if (!tab || !tab->preview_buffer || !tab->win) return; if (!tab->win->preview_enabled || !preview_is_supported(tab)) { diff --git a/src/editor_tab_private.h b/src/editor_tab_private.h index 4ead00c..be4e62d 100644 --- a/src/editor_tab_private.h +++ b/src/editor_tab_private.h @@ -1,3 +1,8 @@ +/** + * @file src/editor_tab_private.h + * @brief Internal editor tab helpers and callbacks. + */ + #ifndef CLEAF_EDITOR_TAB_PRIVATE_H #define CLEAF_EDITOR_TAB_PRIVATE_H @@ -16,126 +21,477 @@ #include #include +/** + * @brief Cleaf max undo states macro. + */ #define CLEAF_MAX_UNDO_STATES 100u +/** + * @brief Cleaf live feature max chars macro. + */ #define CLEAF_LIVE_FEATURE_MAX_CHARS (32u * 1024u) +/** + * @brief Cleaf full highlight max chars macro. + */ #define CLEAF_FULL_HIGHLIGHT_MAX_CHARS (256u * 1024u) +/** + * @brief Cleaf max undo capture bytes macro. + */ #define CLEAF_MAX_UNDO_CAPTURE_BYTES (32u * 1024u) +/** + * @brief Cleaf highlight delay ms macro. + */ #define CLEAF_HIGHLIGHT_DELAY_MS 180u +/** + * @brief Cleaf completion delay ms macro. + */ #define CLEAF_COMPLETION_DELAY_MS 900u +/** + * @brief Cleaf minimap delay ms macro. + */ #define CLEAF_MINIMAP_DELAY_MS 1500u +/** + * @brief Cleaf preview delay ms macro. + */ #define CLEAF_PREVIEW_DELAY_MS 1500u +/** + * @brief Cleaf diagnostics delay ms macro. + */ #define CLEAF_DIAGNOSTICS_DELAY_MS 1500u +/** + * @brief Cleaf selection match delay ms macro. + */ #define CLEAF_SELECTION_MATCH_DELAY_MS 750u +/** + * @brief Cleaf hover delay ms macro. + */ #define CLEAF_HOVER_DELAY_MS 650u +/** + * @brief Cleaf diagnostics max chars macro. + */ #define CLEAF_DIAGNOSTICS_MAX_CHARS CLEAF_LIVE_FEATURE_MAX_CHARS +/** + * @brief Cleaf minimap max bytes macro. + */ #define CLEAF_MINIMAP_MAX_BYTES (256u * 1024u) +/** + * @brief Cleaf selection match max chars macro. + */ #define CLEAF_SELECTION_MATCH_MAX_CHARS CLEAF_LIVE_FEATURE_MAX_CHARS +/** + * @brief Cleaf auto completion max chars macro. + */ #define CLEAF_AUTO_COMPLETION_MAX_CHARS (16u * 1024u) +/** + * @brief Buffer text. + */ char *buffer_text(EditorTab *tab); +/** + * @brief Write all fd. + */ gboolean write_all_fd(int fd, const char *data, gsize len); +/** + * @brief Write text atomic. + */ gboolean write_text_atomic(const char *path, const char *text, GError **error); +/** + * @brief Autosave path for tab. + */ char *autosave_path_for_tab(EditorTab *tab); +/** + * @brief Clear stack. + */ void clear_stack(GPtrArray *stack); +/** + * @brief Push limited. + */ void push_limited(GPtrArray *stack, char *state); +/** + * @brief Pop stack. + */ char *pop_stack(GPtrArray *stack); +/** + * @brief Reset undo state. + */ void reset_undo_state(EditorTab *tab); +/** + * @brief Decimal digits. + */ int decimal_digits(int value); +/** + * @brief Editor tab large file mode. + */ gboolean editor_tab_large_file_mode(EditorTab *tab); +/** + * @brief Editor tab live features allowed. + */ gboolean editor_tab_live_features_allowed(EditorTab *tab); +/** + * @brief Editor tab highlighting allowed. + */ gboolean editor_tab_highlighting_allowed(EditorTab *tab); +/** + * @brief Editor tab reference features allowed. + */ gboolean editor_tab_reference_features_allowed(EditorTab *tab); +/** + * @brief Editor tab cancel live work. + */ void editor_tab_cancel_live_work(EditorTab *tab); +/** + * @brief Editor tab schedule lightweight ui refresh. + */ void editor_tab_schedule_lightweight_ui_refresh(EditorTab *tab); +/** + * @brief Editor tab lightweight ui timeout cb. + */ gboolean editor_tab_lightweight_ui_timeout_cb(gpointer user_data); +/** + * @brief Update gutter width. + */ void update_gutter_width(EditorTab *tab); +/** + * @brief Insert text tagless. + */ void insert_text_tagless(GtkTextBuffer *buffer, GtkTextIter *where, const char *text); +/** + * @brief Popup append item. + */ void popup_append_item(GtkWidget *menu, const char *label, GCallback callback, gpointer data); +/** + * @brief Menu undo. + */ void menu_undo(GtkWidget *w, gpointer data); +/** + * @brief Menu redo. + */ void menu_redo(GtkWidget *w, gpointer data); +/** + * @brief Menu cut. + */ void menu_cut(GtkWidget *w, gpointer data); +/** + * @brief Menu copy. + */ void menu_copy(GtkWidget *w, gpointer data); +/** + * @brief Menu paste. + */ void menu_paste(GtkWidget *w, gpointer data); +/** + * @brief Menu select all. + */ void menu_select_all(GtkWidget *w, gpointer data); +/** + * @brief Menu cut line. + */ void menu_cut_line(GtkWidget *w, gpointer data); +/** + * @brief Menu paste line. + */ void menu_paste_line(GtkWidget *w, gpointer data); +/** + * @brief Menu comment. + */ void menu_comment(GtkWidget *w, gpointer data); +/** + * @brief Menu complete. + */ void menu_complete(GtkWidget *w, gpointer data); +/** + * @brief Hex to rgba. + */ gboolean hex_to_rgba(const char *text, GdkRGBA *rgba); +/** + * @brief On color swatch draw. + */ void on_color_swatch_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data); +/** + * @brief Hide color preview. + */ void hide_color_preview(EditorTab *tab); +/** + * @brief Cancel hover hide. + */ void cancel_hover_hide(EditorTab *tab); +/** + * @brief Hide hover preview. + */ void hide_hover_preview(EditorTab *tab); +/** + * @brief Hover transition timeout cb. + */ gboolean hover_transition_timeout_cb(gpointer user_data); +/** + * @brief Schedule hover transition hide. + */ void schedule_hover_transition_hide(EditorTab *tab); +/** + * @brief Word at iter. + */ char *word_at_iter(GtkTextBuffer *buffer, GtkTextIter *iter); +/** + * @brief Hover clear rows. + */ void hover_clear_rows(EditorTab *tab); +/** + * @brief Editor tab jump to line internal. + */ void editor_tab_jump_to_line_internal(EditorTab *tab, guint line); +/** + * @brief Hover row activated. + */ void hover_row_activated(GtkListBox *box, GtkListBoxRow *row, gpointer user_data); +/** + * @brief Reference row new. + */ GtkWidget *reference_row_new(IndexReference *ref); +/** + * @brief Hover timeout cb. + */ gboolean hover_timeout_cb(gpointer user_data); +/** + * @brief On text view motion. + */ void on_text_view_motion(GtkEventControllerMotion *controller, double x, double y, gpointer user_data); +/** + * @brief On text view leave. + */ void on_text_view_leave(GtkEventControllerMotion *controller, gpointer user_data); +/** + * @brief On hover popover enter. + */ void on_hover_popover_enter(GtkEventControllerMotion *controller, double x, double y, gpointer user_data); +/** + * @brief On hover popover leave. + */ void on_hover_popover_leave(GtkEventControllerMotion *controller, gpointer user_data); +/** + * @brief Color preview row new. + */ GtkWidget *color_preview_row_new(EditorTab *tab, const char *hex); +/** + * @brief Show color preview in hover. + */ void show_color_preview_in_hover(EditorTab *tab, const char *hex, GtkTextIter *where); +/** + * @brief Maybe show color preview. + */ void maybe_show_color_preview(EditorTab *tab); +/** + * @brief Editor tab show reference at pointer or cursor. + */ void editor_tab_show_reference_at_pointer_or_cursor(EditorTab *tab); +/** + * @brief On text view right click. + */ void on_text_view_right_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); +/** + * @brief On minimap click. + */ void on_minimap_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer user_data); +/** + * @brief On minimap draw. + */ void on_minimap_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data); +/** + * @brief On gutter draw. + */ void on_gutter_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data); +/** + * @brief On vadjustment value changed. + */ void on_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer user_data); +/** + * @brief Ensure match tag. + */ void ensure_match_tag(EditorTab *tab); +/** + * @brief Ensure minimap match tag. + */ void ensure_minimap_match_tag(EditorTab *tab); +/** + * @brief Clear minimap matches. + */ void clear_minimap_matches(EditorTab *tab); +/** + * @brief Clear selection matches. + */ void clear_selection_matches(EditorTab *tab); +/** + * @brief Apply minimap match. + */ void apply_minimap_match(EditorTab *tab, GtkTextIter *start, GtkTextIter *end); +/** + * @brief Update selection matches. + */ void update_selection_matches(EditorTab *tab); +/** + * @brief Selection match timeout cb. + */ gboolean selection_match_timeout_cb(gpointer user_data); +/** + * @brief Editor tab schedule selection matches. + */ void editor_tab_schedule_selection_matches(EditorTab *tab); +/** + * @brief Ensure diagnostic tag. + */ void ensure_diagnostic_tag(EditorTab *tab); +/** + * @brief Clear syntax diagnostics. + */ void clear_syntax_diagnostics(EditorTab *tab); +/** + * @brief Editor tab apply syntax diagnostics. + */ void editor_tab_apply_syntax_diagnostics(EditorTab *tab); +/** + * @brief Diagnostics timeout cb. + */ gboolean diagnostics_timeout_cb(gpointer user_data); +/** + * @brief Editor tab schedule syntax diagnostics. + */ void editor_tab_schedule_syntax_diagnostics(EditorTab *tab); +/** + * @brief Update minimap text. + */ void update_minimap_text(EditorTab *tab); +/** + * @brief Minimap timeout cb. + */ gboolean minimap_timeout_cb(gpointer user_data); +/** + * @brief Preview timeout cb. + */ gboolean preview_timeout_cb(gpointer user_data); +/** + * @brief Editor tab schedule minimap update. + */ void editor_tab_schedule_minimap_update(EditorTab *tab); +/** + * @brief Editor tab schedule preview update. + */ void editor_tab_schedule_preview_update(EditorTab *tab); +/** + * @brief Preview ensure tags. + */ void preview_ensure_tags(EditorTab *tab); +/** + * @brief Preview is supported. + */ gboolean preview_is_supported(EditorTab *tab); +/** + * @brief Editor tab is latex. + */ gboolean editor_tab_is_latex(EditorTab *tab); +/** + * @brief Preview render markdown. + */ void preview_render_markdown(EditorTab *tab, const char *text); +/** + * @brief Preview render latex. + */ void preview_render_latex(EditorTab *tab, const char *text); +/** + * @brief Completion is visible. + */ gboolean completion_is_visible(EditorTab *tab); +/** + * @brief Completion clear rows. + */ void completion_clear_rows(EditorTab *tab); +/** + * @brief Completion insert word. + */ void completion_insert_word(EditorTab *tab, const char *word); +/** + * @brief Completion row activated. + */ void completion_row_activated(GtkListBox *box, GtkListBoxRow *row, gpointer user_data); +/** + * @brief Completion add row. + */ void completion_add_row(EditorTab *tab, const char *word); +/** + * @brief Completion timeout cb. + */ gboolean completion_timeout_cb(gpointer user_data); +/** + * @brief Editor tab schedule completion. + */ void editor_tab_schedule_completion(EditorTab *tab); +/** + * @brief Completion accept selected. + */ void completion_accept_selected(EditorTab *tab); +/** + * @brief Completion select delta. + */ void completion_select_delta(EditorTab *tab, int delta); +/** + * @brief Tab unit. + */ char *tab_unit(EditorTab *tab); +/** + * @brief Selection line bounds. + */ void selection_line_bounds(EditorTab *tab, int *start_line_out, int *end_line_out, gboolean *has_selection_out); +/** + * @brief Insert tab or indent. + */ void insert_tab_or_indent(EditorTab *tab); +/** + * @brief Unindent line. + */ void unindent_line(EditorTab *tab, int line); +/** + * @brief Unindent selection or line. + */ void unindent_selection_or_line(EditorTab *tab); +/** + * @brief On text view key pressed. + */ gboolean on_text_view_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data); +/** + * @brief On text view key released. + */ void on_text_view_key_released(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data); +/** + * @brief On close button clicked. + */ void on_close_button_clicked(GtkWidget *widget, gpointer user_data); +/** + * @brief Highlight timeout cb. + */ gboolean highlight_timeout_cb(gpointer user_data); +/** + * @brief On mark set. + */ void on_mark_set(GtkTextBuffer *buffer, GtkTextIter *location, GtkTextMark *mark, gpointer user_data); +/** + * @brief On buffer changed. + */ void on_buffer_changed(GtkTextBuffer *buffer, gpointer user_data); +/** + * @brief Write backup if needed. + */ gboolean write_backup_if_needed(EditorTab *tab, const char *path); +/** + * @brief Save to path. + */ gboolean save_to_path(EditorTab *tab, const char *path); +/** + * @brief Select match. + */ gboolean select_match(EditorTab *tab, GtkTextIter *start, GtkTextIter *end); +/** + * @brief Editor tab text rect to popover parent. + */ gboolean editor_tab_text_rect_to_popover_parent(EditorTab *tab, GdkRectangle *rect); diff --git a/src/editor_tab_sourceview.c b/src/editor_tab_sourceview.c index a1c6f22..7177641 100644 --- a/src/editor_tab_sourceview.c +++ b/src/editor_tab_sourceview.c @@ -1,5 +1,13 @@ +/** + * @file src/editor_tab_sourceview.c + * @brief Cleaf editor tab sourceview module. + */ + #include "editor_tab_private.h" +/** + * @brief Source language id for syntax. + */ static const char *source_language_id_for_syntax(SyntaxDef *syntax) { if (!syntax || !syntax->name) return NULL; if (g_ascii_strcasecmp(syntax->name, "C") == 0) return "c"; @@ -25,6 +33,9 @@ static const char *source_language_id_for_syntax(SyntaxDef *syntax) { return NULL; } +/** + * @brief Source language for tab. + */ static GtkSourceLanguage *source_language_for_tab(EditorTab *tab) { GtkSourceLanguageManager *manager = gtk_source_language_manager_get_default(); if (!manager || !tab) return NULL; @@ -42,6 +53,9 @@ static GtkSourceLanguage *source_language_for_tab(EditorTab *tab) { return language; } +/** + * @brief Colour is dark. + */ static gboolean colour_is_dark(const char *colour) { GdkRGBA rgba; if (!colour || !gdk_rgba_parse(&rgba, colour)) return TRUE; @@ -51,6 +65,9 @@ static gboolean colour_is_dark(const char *colour) { return luminance < 0.50; } +/** + * @brief Source style scheme for window. + */ static GtkSourceStyleScheme *source_style_scheme_for_window(EditorWindow *win) { GtkSourceStyleSchemeManager *manager = gtk_source_style_scheme_manager_get_default(); @@ -72,6 +89,9 @@ static GtkSourceStyleScheme *source_style_scheme_for_window(EditorWindow *win) { } +/** + * @brief Source parent scheme id for window. + */ static const char *source_parent_scheme_id_for_window(EditorWindow *win) { GtkSourceStyleSchemeManager *manager = gtk_source_style_scheme_manager_get_default(); @@ -91,6 +111,9 @@ static const char *source_parent_scheme_id_for_window(EditorWindow *win) { return preferred[0]; } +/** + * @brief String contains ci. + */ static gboolean string_contains_ci(const char *text, const char *needle) { if (!text || !needle || needle[0] == '\0') return FALSE; char *lower_text = g_ascii_strdown(text, -1); @@ -101,6 +124,9 @@ static gboolean string_contains_ci(const char *text, const char *needle) { return found; } +/** + * @brief Style names add. + */ static void style_names_add(GPtrArray *names, const char *name) { if (!names || !name || name[0] == '\0') return; for (guint i = 0u; i < names->len; i++) { @@ -217,12 +243,18 @@ static GPtrArray *gtksource_styles_for_yaml_rule(const char *rule_name) { return names; } +/** + * @brief Append xml escaped. + */ static void append_xml_escaped(GString *out, const char *text) { char *escaped = g_markup_escape_text(text ? text : "", -1); g_string_append(out, escaped ? escaped : ""); g_free(escaped); } +/** + * @brief Append style from rule. + */ static void append_style_from_rule(GString *xml, const char *style_name, SyntaxRule *rule) { if (!xml || !style_name || !rule || !rule->color || rule->color[0] == '\0') return; g_string_append(xml, "