From 6ba7682391775aa9350f2d24f1cfccab4e812675 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 29 May 2025 19:01:00 +0100 Subject: [PATCH 1/2] Simplify working of highlight selection --- .../highlight-word-selection.vala | 45 ++++++--------- src/Widgets/SourceView.vala | 57 ++++++++----------- 2 files changed, 42 insertions(+), 60 deletions(-) diff --git a/plugins/highlight-word-selection/highlight-word-selection.vala b/plugins/highlight-word-selection/highlight-word-selection.vala index 91303df71..1c96c3a2a 100644 --- a/plugins/highlight-word-selection/highlight-word-selection.vala +++ b/plugins/highlight-word-selection/highlight-word-selection.vala @@ -34,13 +34,11 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Scratc plugins = (Scratch.Services.Interface) object; plugins.hook_document.connect ((doc) => { if (current_source != null) { - current_source.deselected.disconnect (on_deselection); - current_source.selection_changed.disconnect (on_selection_changed); + current_source.selection_event.disconnect (on_selection_changed); } current_source = doc.source_view; - current_source.deselected.connect (on_deselection); - current_source.selection_changed.connect (on_selection_changed); + current_source.selection_event.connect (on_selection_changed); }); plugins.hook_window.connect ((w) => { @@ -48,16 +46,15 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Scratc }); } - public void on_selection_changed (ref Gtk.TextIter start, ref Gtk.TextIter end) requires (main_window != null) { - if (!main_window.has_successful_search ()) { - // Perform plugin selection when there is no ongoing and successful search - current_search_context = new Gtk.SourceSearchContext ( - (Gtk.SourceBuffer)current_source.buffer, - null - ); - current_search_context.settings.search_text = ""; + private void on_selection_changed (ref Gtk.TextIter start, ref Gtk.TextIter end) requires (main_window != null) { + if (current_search_context != null) { + // Cancel existing search current_search_context.set_highlight (false); + current_search_context = null; + } + if (!main_window.has_successful_search ()) { + // Perform plugin selection when there is no ongoing and successful search var original_start = start.copy (); // Ignore leading space @@ -113,31 +110,25 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Scratc // Ensure no leading or trailing space var selected_text = start.get_text (end).strip (); - if (selected_text.char_count () > SELECTION_HIGHLIGHT_MAX_CHARS) { - return; + //Nevertheless select as much as permitted + selected_text = selected_text.substring (0, SELECTION_HIGHLIGHT_MAX_CHARS); } + current_search_context = new Gtk.SourceSearchContext ( + (Gtk.SourceBuffer)current_source.buffer, + null + ); + current_search_context.settings.search_text = ""; + current_search_context.set_highlight (false); current_search_context.settings.search_text = selected_text; current_search_context.set_highlight (true); - } else if (current_search_context != null) { - // Cancel existing search - current_search_context.set_highlight (false); - current_search_context = null; - } - } - - public void on_deselection () { - if (current_search_context != null) { - current_search_context.set_highlight (false); - current_search_context = null; } } public void deactivate () { if (current_source != null) { - current_source.deselected.disconnect (on_deselection); - current_source.selection_changed.disconnect (on_selection_changed); + current_source.selection_event.disconnect (on_selection_changed); } } } diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index 85d490e5b..a0196f2a2 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -35,7 +35,6 @@ namespace Scratch.Widgets { private uint size_allocate_timer = 0; private Gtk.TextIter last_select_start_iter; private Gtk.TextIter last_select_end_iter; - private string selected_text = ""; private GitGutterRenderer git_diff_gutter_renderer; private NavMarkGutterRenderer navmark_gutter_renderer; @@ -44,9 +43,9 @@ namespace Scratch.Widgets { private const double SCROLL_THRESHOLD = 1.0; public signal void style_changed (Gtk.SourceStyleScheme style); - // "selection_changed" signal now only emitted when the selected text changes (position ignored). Listened to by searchbar and highlight word selection plugin - public signal void selection_changed (Gtk.TextIter start_iter, Gtk.TextIter end_iter); - public signal void deselected (); + // "selection_event" signal emitted when selection changes. May be selection or deselection. + // Listened to by highlight word selection plugin + public signal void selection_event (Gtk.TextIter start_iter, Gtk.TextIter end_iter); //lang can be null, in the case of *No highlight style* aka Normal text public Gtk.SourceLanguage? language { @@ -663,29 +662,38 @@ namespace Scratch.Widgets { private void on_mark_set (Gtk.TextIter loc, Gtk.TextMark mar) { // Weed out user movement for text selection changes + // may not be new selection - also caused by highlighting for example Gtk.TextIter start, end; buffer.get_selection_bounds (out start, out end); + if (last_select_start_iter.equal (start) && last_select_end_iter.equal (end)) { + // Selection unchanged - update draw spaces when required + if (start.get_line () != last_select_start_iter.get_line ()) { + update_draw_spaces (); + } - if (start.equal (last_select_start_iter) && end.equal (last_select_end_iter)) { return; + } else { + last_select_start_iter.assign (start); + last_select_end_iter.assign (end); } - last_select_start_iter.assign (start); - last_select_end_iter.assign (end); - update_draw_spaces (); - if (selection_changed_timer != 0) { Source.remove (selection_changed_timer); selection_changed_timer = 0; } - // Fire deselected immediately - if (start.equal (end)) { - deselected (); - // Don't fire signal till we think select movement is done - } else { - selection_changed_timer = Timeout.add (THROTTLE_MS, selection_changed_event); - } + selection_changed_timer = Timeout.add ( + THROTTLE_MS, + () => { + selection_changed_timer = 0; + update_draw_spaces (); + + Gtk.TextIter s, e; + bool selected = buffer.get_selection_bounds (out s, out e); + selection_event (s, e); + return Source.REMOVE; + } + ); } private void on_mark_deleted (Gtk.TextMark mark) { @@ -696,23 +704,6 @@ namespace Scratch.Widgets { } } - private bool selection_changed_event () { - Gtk.TextIter start, end; - bool selected = buffer.get_selection_bounds (out start, out end); - if (selected) { - var prev_selected_text = selected_text; - selected_text = buffer.get_text (start, end, true); - if (selected_text != prev_selected_text) { - selection_changed (start, end); - } - } else { - deselected (); - } - - selection_changed_timer = 0; - return false; - } - uint refresh_timeout_id = 0; public void schedule_refresh () { if (refresh_timeout_id > 0) { From fb4bf86aa623eb05fb8b4c9581df9db20ee5ad51 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 29 May 2025 20:07:31 +0100 Subject: [PATCH 2/2] Ensure update_draw_spaces () redraws SourceView --- src/Widgets/SourceView.vala | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index a0196f2a2..0ba7a2133 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -557,20 +557,17 @@ namespace Scratch.Widgets { Gtk.TextIter start, end; var selection = buffer.get_selection_bounds (out start, out end); - var draw_spaces_state = (ScratchDrawSpacesState) Scratch.settings.get_enum ("draw-spaces"); + var draw_spaces_state = Scratch.settings.get_enum ("draw-spaces"); /* Draw spaces in selection the same way if drawn at all */ - if (selection && - draw_spaces_state in (ScratchDrawSpacesState.FOR_SELECTION | ScratchDrawSpacesState.CURRENT | ScratchDrawSpacesState.ALWAYS)) { - + if (selection && draw_spaces_state != ScratchDrawSpacesState.NEVER) { + buffer.apply_tag_by_name ("draw_spaces", start, end); + } else if (draw_spaces_state == ScratchDrawSpacesState.CURRENT) { + get_current_line (out start, out end); buffer.apply_tag_by_name ("draw_spaces", start, end); - return; } - if (draw_spaces_state == ScratchDrawSpacesState.CURRENT && - get_current_line (out start, out end)) { - - buffer.apply_tag_by_name ("draw_spaces", start, end); - } + //This is required for reliable results when this function is called from another thread (e.g. SourceFunc) + queue_draw (); } private void on_context_menu (Gtk.Menu menu) { @@ -667,10 +664,6 @@ namespace Scratch.Widgets { buffer.get_selection_bounds (out start, out end); if (last_select_start_iter.equal (start) && last_select_end_iter.equal (end)) { // Selection unchanged - update draw spaces when required - if (start.get_line () != last_select_start_iter.get_line ()) { - update_draw_spaces (); - } - return; } else { last_select_start_iter.assign (start);