From 418e5083e45dd404546a50f37545bef0e1b00f18 Mon Sep 17 00:00:00 2001 From: Alain Date: Wed, 23 Oct 2024 00:04:16 +0000 Subject: [PATCH] Highlight search string matches in bold (#328) --- data/settings.appdata.xml.in | 1 + src/SearchView.vala | 52 ++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/data/settings.appdata.xml.in b/data/settings.appdata.xml.in index 2505480d..40f2aabf 100644 --- a/data/settings.appdata.xml.in +++ b/data/settings.appdata.xml.in @@ -47,6 +47,7 @@ Search returns alphabetically sorted list after clicking on a search result + Highlight search string matches in bold diff --git a/src/SearchView.vala b/src/SearchView.vala index 10226df9..05297d24 100644 --- a/src/SearchView.vala +++ b/src/SearchView.vala @@ -76,7 +76,12 @@ public class Switchboard.SearchView : Gtk.Box { return true; } - return search_text.down () in ((SearchRow) listbox_row).last_item.down (); + bool valid = search_text.down () in ((SearchRow) listbox_row).last_item.down (); + if (valid) { + ((SearchRow) listbox_row).pattern = search_entry.text; + } + + return valid; } private int sort_func (Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) { @@ -146,6 +151,16 @@ public class Switchboard.SearchView : Gtk.Box { public string last_item { get; construct; } public string uri { get; construct; } + private Gtk.Label title; + private Gtk.Label description_label; + + public string pattern { + set { + title.set_markup (highlight_text (last_item, value)); + description_label.set_markup (highlight_text (description, value)); + } + } + public SearchRow (string icon_name, string description, string uri) { var path = description.split (" → "); var last_item = path[path.length - 1]; @@ -163,14 +178,18 @@ public class Switchboard.SearchView : Gtk.Box { icon_size = LARGE }; - var title = new Gtk.Label (last_item) { - halign = START + title = new Gtk.Label (null) { + halign = START, + use_markup = true }; + title.set_markup (GLib.Markup.escape_text (last_item, -1)); - var description_label = new Gtk.Label (description) { + description_label = new Gtk.Label (null) { ellipsize = MIDDLE, - halign = START + halign = START, + use_markup = true }; + description_label.set_markup (GLib.Markup.escape_text (description, -1)); description_label.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); description_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); @@ -183,5 +202,28 @@ public class Switchboard.SearchView : Gtk.Box { child = grid; } + + private string highlight_text (string _text, string search_term) { + string text = GLib.Markup.escape_text (_text, -1); + + if (search_term.length <= 0) { + return text; + } + + try { + Regex regex = new Regex (Regex.escape_string (search_term), RegexCompileFlags.CASELESS); + string highlighted_text = regex.replace (text, text.length, 0, "\\0"); + return escape_markup_but_preserve_b_tags (highlighted_text); + } catch (Error e) { + return text; + } + } + + private string escape_markup_but_preserve_b_tags (string text) { + string escaped_text = GLib.Markup.escape_text (text, -1); + escaped_text = escaped_text.replace ("<b>", "").replace ("</b>", ""); + escaped_text = escaped_text.replace ("&amp;", "&"); + return escaped_text; + } } }