From cc5993757493caf4b10ece0c427459f912754725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 10 Aug 2026 11:47:45 -0700 Subject: [PATCH 1/2] FuzzySearch: cleanup styles --- data/Application.css | 39 ++--------------- plugins/fuzzy-search/file-item.vala | 42 +++++++++---------- .../fuzzy-search/fuzzy-search-popover.vala | 3 +- 3 files changed, 27 insertions(+), 57 deletions(-) diff --git a/data/Application.css b/data/Application.css index 7bab5b8cab..eae9ef22db 100644 --- a/data/Application.css +++ b/data/Application.css @@ -20,54 +20,23 @@ textview.scrubber { border: 0; } -.fuzzy-popover { - padding-top: 0.5rem; - padding-bottom: 1rem; -} - .fuzzy-popover entry { margin-left: 1rem; margin-right: 1rem; -} - -.fuzzy-popover scrolledwindow { - margin-top: 1rem; -} - -.fuzzy-list { - background-color: transparent; + margin-bottom: 1rem; } .fuzzy-item { padding: 0.5rem; - margin-left: 10px; - margin-right: 10px; - background-color: transparent; } -.fuzzy-item.preselect-fuzzy, .fuzzy-item:hover { - border-radius: 0.5rem; -} - -.fuzzy-item:hover { - background-color: @theme_unfocused_selected_bg_color; + background-color: @theme_unfocused_selected_bg_color; } .fuzzy-item.preselect-fuzzy { - background-color: @selected_bg_color; -} - -.fuzzy-item .fuzzy-file-icon { - margin-right: 0.5rem; -} - -.fuzzy-item label:nth-child(1) { - font-weight: 700; -} - -.fuzzy-item.preselect-fuzzy label { - opacity: 0.7; + background-color: @selected_bg_color; + color: @selected_fg_color; } .symbol-outline > box.horizontal { diff --git a/plugins/fuzzy-search/file-item.vala b/plugins/fuzzy-search/file-item.vala index e5f6563fde..b1c3415578 100644 --- a/plugins/fuzzy-search/file-item.vala +++ b/plugins/fuzzy-search/file-item.vala @@ -7,7 +7,7 @@ */ public class FileItem : Gtk.ListBoxRow { - public SearchResult result { get; private set; } + public SearchResult result { get; construct; } public string filepath { get { @@ -15,24 +15,23 @@ public class FileItem : Gtk.ListBoxRow { } } - public FileItem (SearchResult res, bool should_distinguish_project = false) { - this.get_style_context ().add_class ("fuzzy-item"); - this.get_style_context ().add_class ("flat"); + public FileItem (SearchResult result, bool should_distinguish_project = false) { + Object (result: result); - result = res; - Icon icon; - var path_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 1); - path_box.valign = Gtk.Align.CENTER; + var filename_label = new Gtk.Label (Path.get_basename (result.relative_path)) { + halign = START + }; var path_label = new Gtk.Label ( - @"$(should_distinguish_project ? result.project + " • " : "")$(result.relative_path)" - ); - - path_label.halign = Gtk.Align.START; - - var filename_label = new Gtk.Label (Path.get_basename (result.relative_path)); - filename_label.halign = Gtk.Align.START; + @"$(should_distinguish_project ? result.project + " → " : "")$(result.relative_path)" + ) { + ellipsize = MIDDLE, + halign = START + }; + path_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + path_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); + Icon icon; try { var fi = File.new_for_path (result.full_path); var info = fi.query_info ("standard::*", 0); @@ -42,18 +41,19 @@ public class FileItem : Gtk.ListBoxRow { } var image = new Gtk.Image.from_gicon (icon, Gtk.IconSize.DND); - image.get_style_context ().add_class ("fuzzy-file-icon"); + var path_box = new Gtk.Box (VERTICAL, 0) { + valign = CENTER + }; path_box.add (filename_label); path_box.add (path_label); - var container_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 1) { - valign = Gtk.Align.CENTER - }; - + var container_box = new Gtk.Box (HORIZONTAL, 12); container_box.add (image); container_box.add (path_box); - this.child = container_box; + get_style_context ().add_class ("fuzzy-item"); + get_style_context ().add_class ("flat"); + child = container_box; } } diff --git a/plugins/fuzzy-search/fuzzy-search-popover.vala b/plugins/fuzzy-search/fuzzy-search-popover.vala index d67782a3d9..0b4e104678 100644 --- a/plugins/fuzzy-search/fuzzy-search-popover.vala +++ b/plugins/fuzzy-search/fuzzy-search-popover.vala @@ -68,7 +68,8 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { propagate_natural_height = true, hexpand = true, vexpand = true, - child = search_result_container + child = search_result_container, + hscrollbar_policy = NEVER }; var box = new Gtk.Box (VERTICAL, 0); From 2e8b1d967e238d245a0fa9cc387fe6646b068ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 10 Aug 2026 13:42:27 -0700 Subject: [PATCH 2/2] Way too much cleanup --- data/Application.css | 5 - plugins/fuzzy-search/file-item.vala | 3 +- .../fuzzy-search/fuzzy-search-popover.vala | 122 ++++++------------ 3 files changed, 38 insertions(+), 92 deletions(-) diff --git a/data/Application.css b/data/Application.css index eae9ef22db..5cbde9eae1 100644 --- a/data/Application.css +++ b/data/Application.css @@ -34,11 +34,6 @@ textview.scrubber { background-color: @theme_unfocused_selected_bg_color; } -.fuzzy-item.preselect-fuzzy { - background-color: @selected_bg_color; - color: @selected_fg_color; -} - .symbol-outline > box.horizontal { margin: 1em; } diff --git a/plugins/fuzzy-search/file-item.vala b/plugins/fuzzy-search/file-item.vala index b1c3415578..c94e9a92ea 100644 --- a/plugins/fuzzy-search/file-item.vala +++ b/plugins/fuzzy-search/file-item.vala @@ -53,7 +53,8 @@ public class FileItem : Gtk.ListBoxRow { container_box.add (path_box); get_style_context ().add_class ("fuzzy-item"); - get_style_context ().add_class ("flat"); child = container_box; + + show_all (); } } diff --git a/plugins/fuzzy-search/fuzzy-search-popover.vala b/plugins/fuzzy-search/fuzzy-search-popover.vala index 0b4e104678..e20ac0a13e 100644 --- a/plugins/fuzzy-search/fuzzy-search-popover.vala +++ b/plugins/fuzzy-search/fuzzy-search-popover.vala @@ -14,18 +14,15 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { public Scratch.Services.FuzzySearchIndexer search_indexer { get; construct; } public bool sidebar_is_visible { get; set; } - private Gtk.SearchEntry search_term_entry; - private Services.FuzzyFinder fuzzy_finder; + private Gee.LinkedList cancellables; + private Gtk.EventControllerKey search_term_entry_key_controller; private Gtk.ListBox search_result_container; - private ListStore search_list_store; + private Gtk.SearchEntry search_term_entry; + private int max_items; private int preselected_index; - private Gtk.ScrolledWindow scrolled; + private ListStore search_list_store; private Scratch.Services.FuzzySearchIndexer indexer; - private int window_height; - private int max_items; - private Gee.LinkedList cancellables; - private Gtk.EventControllerKey search_term_entry_key_controller; - private Gtk.Label title_label; + private Services.FuzzyFinder fuzzy_finder; private string current_doc_project; public FuzzySearchPopover (Scratch.Services.FuzzySearchIndexer search_indexer, Scratch.MainWindow window) { @@ -42,21 +39,15 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { pointing_to = { 0, 32, 1, 1 }; get_style_context ().add_class ("fuzzy-popover"); - title_label = new Granite.HeaderLabel (_("Find project files")); - search_term_entry = new Gtk.SearchEntry () { + placeholder_text = _("Find project files"), hexpand = true, valign = START }; - search_list_store = new ListStore (typeof (FileItem)); - search_result_container = new Gtk.ListBox () { - selection_mode = NONE, - activate_on_single_click = true, - can_focus = false + var title_label = new Granite.HeaderLabel (_("Find project files")) { + mnemonic_widget = search_term_entry }; - search_result_container.get_style_context ().add_class ("fuzzy-list"); - search_result_container.bind_model (search_list_store, (obj) => (FileItem)obj); var entry_layout = new Gtk.Box (VERTICAL, 0) { valign = START @@ -64,10 +55,18 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { entry_layout.add (title_label); entry_layout.add (search_term_entry); - scrolled = new Gtk.ScrolledWindow (null, null) { - propagate_natural_height = true, + search_list_store = new ListStore (typeof (FileItem)); + + search_result_container = new Gtk.ListBox () { hexpand = true, vexpand = true, + selection_mode = BROWSE, + activate_on_single_click = true + }; + search_result_container.bind_model (search_list_store, (obj) => (FileItem)obj); + + var scrolled = new Gtk.ScrolledWindow (null, null) { + propagate_natural_height = true, child = search_result_container, hscrollbar_policy = NEVER }; @@ -77,9 +76,7 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { box.add (scrolled); box.show_all (); - scrolled.hide (); - - add (box); + child = box; fuzzy_finder = new Services.FuzzyFinder (search_indexer.project_paths); indexer = search_indexer; @@ -96,44 +93,16 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { search_term_entry_key_controller = new Gtk.EventControllerKey (search_term_entry); search_term_entry_key_controller.key_pressed.connect ((keyval, keycode, state) => { - // Handle key up/down to select other files found by fuzzy search switch (keyval) { - case Gdk.Key.Down: - if (search_list_store.n_items > 0) { - var old_index = preselected_index; - var item = search_list_store.get_item (preselected_index++); - if (preselected_index >= search_list_store.n_items) { - preselected_index = 0; - } - - var next_item = search_list_store.get_item (preselected_index); - preselect_new_item ((FileItem) item, (FileItem) next_item); - calculate_scroll_offset (old_index, preselected_index); - } - - return true; - case Gdk.Key.Up: - if (search_list_store.n_items > 0) { - var old_index = preselected_index; - var item = search_list_store.get_item (preselected_index--); - if (preselected_index < 0) { - preselected_index = (int) search_list_store.n_items - 1; - } - - var next_item = search_list_store.get_item (preselected_index); - preselect_new_item ((FileItem) item, (FileItem) next_item); - calculate_scroll_offset (old_index, preselected_index); - } - return true; case Gdk.Key.Escape: // Handle seperately, otherwise it takes 2 escape hits to close the modal close_search (); - return true; + return Gdk.EVENT_STOP; default: break; } - return false; + return Gdk.EVENT_PROPAGATE; }); search_term_entry.activate.connect (() => { @@ -189,7 +158,6 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { foreach (var result in results) { var file_item = new FileItem (result, indexer.project_paths.size > 1); - file_item.can_focus = false; if (first) { first = false; @@ -200,9 +168,6 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { search_list_store.insert_sorted (file_item, sort_func); } - scrolled.hide (); - scrolled.show_all (); - // Reset scrolling scrolled.vadjustment.value = 0; } @@ -212,8 +177,6 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { }); } else { search_list_store.remove_all (); - - scrolled.hide (); } }); @@ -232,6 +195,8 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { current_doc_project = get_current_project (); // This will not change while popover is showing }); + + search_result_container.move_cursor.connect (move_cursor); } private int sort_func (Object a, Object b) { @@ -252,31 +217,22 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { } } - private void calculate_scroll_offset (int old_position, int new_position) { - // Shortcut if jumping from first to last or the other way round - if (new_position == 0 && old_position > new_position) { - scrolled.vadjustment.value = 0; + private void move_cursor (Gtk.ListBox list_box, Gtk.MovementStep step, int count) { + unowned var selected = list_box.get_selected_row (); + if (step != DISPLAY_LINES || selected == null) { return; - } else if (old_position == 0 && new_position == search_list_store.n_items - 1) { - scrolled.vadjustment.value = scrolled.vadjustment.get_upper (); + } + + // Move up to the searchbar + if (selected == list_box.get_row_at_index (0) && count == -1) { + move_focus (TAB_BACKWARD); return; } - var size_box = scrolled.vadjustment.get_upper () / search_list_store.n_items; - var current_top = scrolled.vadjustment.value; - var current_bottom = current_top + size_box * (max_items - 2); - if (old_position < new_position) { - // Down movement - var new_adjust = size_box * (preselected_index); - if (new_adjust >= current_bottom) { - scrolled.vadjustment.value = size_box * (preselected_index - (max_items - 1)); - } - } else if (old_position > new_position) { - // Up movement - var new_adjust = size_box * (preselected_index); - if (new_adjust < current_top) { - scrolled.vadjustment.value = new_adjust; - } + // Wrap to the searchbar + if (list_box.get_row_at_index (selected.get_index () + count) == null) { + list_box.select_row (list_box.get_row_at_index (0)); + move_focus (TAB_FORWARD); } } @@ -284,12 +240,6 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { open_file (item.filepath.strip ()); } - private void preselect_new_item (FileItem old_item, FileItem new_item) { - var class_name = "preselect-fuzzy"; - old_item.get_style_context ().remove_class (class_name); - new_item.get_style_context ().add_class (class_name); - } - private string get_current_project () { Scratch.Services.Document current_document = current_window.document_view.current_document; if (current_document == null) {