Skip to content

Consistent search settings between document search and global search #1623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 37 additions & 53 deletions src/Dialogs/GlobalSearchDialog.vala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public class Scratch.Dialogs.GlobalSearchDialog : Granite.MessageDialog {
public string folder_name { get; construct; }
public bool is_repo { get; construct; }
private Granite.ValidatedEntry search_term_entry;
private Gtk.Switch case_switch;
private Gtk.Switch regex_switch;

public string search_term {
get {
Expand All @@ -36,75 +34,54 @@ public class Scratch.Dialogs.GlobalSearchDialog : Granite.MessageDialog {
}
}

public bool use_regex {
get {
return regex_switch.active;
}

set {
regex_switch.active = value;
}
}

public bool case_sensitive {
get {
return case_switch.active;
}

set {
case_switch.active = value;
}
}
public bool case_sensitive { get; construct; }
public bool wholeword { get; construct; }
public bool use_regex { get; construct; }

public GlobalSearchDialog (string folder_name, bool is_repo) {
public GlobalSearchDialog (string folder_name, bool is_repo, bool case_sensitive, bool wholeword, bool use_regex) {
Object (
transient_for: ((Gtk.Application) GLib.Application.get_default ()).active_window,
folder_name: folder_name,
is_repo: is_repo,
image_icon: new ThemedIcon ("edit-find")
case_sensitive: case_sensitive,
wholeword: wholeword,
use_regex: use_regex
);
}

construct {
primary_text = _("Search for text in “%s”").printf (folder_name);
secondary_text = _("The search term must be at least 3 characters long.");
transient_for = ((Gtk.Application) GLib.Application.get_default ()).active_window;
image_icon = new ThemedIcon ("edit-find");

search_term_entry = new Granite.ValidatedEntry () {
margin_bottom = 12,
width_chars = 30 //Most searches are less than this, can expand window if required
};

case_switch = new Gtk.Switch () {
active = false,
halign = Gtk.Align.START,
hexpand = true
};

var case_label = new Gtk.Label (_("Case sensitive:")) {
halign = Gtk.Align.END
};
string case_text = "", wholeword_text = "", regex_text = "";
if (use_regex) {
regex_text = _("The search term will be treated as a regex expression");
} else {
case_text = case_sensitive ? _("Search will be case sensitive") : _("Search will be case insensitive");
wholeword_text = wholeword ? _("Search will match only whole words") : "";
}

regex_switch = new Gtk.Switch () {
active = false,
halign = Gtk.Align.START
};
primary_text = _("Search for text in “%s”").printf (folder_name);
secondary_text = _("The search term must be at least 3 characters long.");

var regex_label = new Gtk.Label (_("Use regular expressions:")) {
halign = Gtk.Align.END
};
var box = new Gtk.Box (VERTICAL, 0);
if (!use_regex) {
box.add (new Gtk.Label (case_text) { halign = START });
if (wholeword_text != "") {
box.add (new Gtk.Label (wholeword_text) { halign = START });
}
} else {
box.add (new Gtk.Label (regex_text) { halign = START });
}

var layout = new Gtk.Grid () {
column_spacing = 12,
row_spacing = 6
};
layout.attach (search_term_entry, 0, 0, 2);
layout.attach (case_label, 0, 1);
layout.attach (case_switch, 1, 1);
layout.attach (regex_label, 0, 2);
layout.attach (regex_switch, 1, 2);
layout.show_all ();
box.add (search_term_entry);

custom_bin.add (layout);
custom_bin.add (box);
custom_bin.show_all ();

add_button (_("Cancel"), Gtk.ResponseType.CANCEL);

Expand All @@ -119,6 +96,13 @@ public class Scratch.Dialogs.GlobalSearchDialog : Granite.MessageDialog {

search_term_entry.changed.connect (() => {
search_term_entry.is_valid = search_term_entry.text.length >= 3;
if (use_regex) {
try {
var search_regex = new Regex (search_term_entry.text, 0);
} catch {
search_term_entry.is_valid = false;
}
}
});
}
}
41 changes: 31 additions & 10 deletions src/FolderManager/ProjectFolderItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,10 @@ namespace Scratch.FolderManager {
return is_git_repo ? monitored_repo.is_valid_new_local_branch_name (new_name) : false;
}

// The parameter "is_explicit" indicates whether a global search was requested
// via a context menu on an explicitly chosen folder, in which case everything in that
// folder will be searched, or whether the hot-key was used in which case the search will
// take place on the active project and will omit certain folders
public void global_search (
GLib.File start_folder = this.file.file,
string? term = null,
Expand All @@ -507,7 +511,6 @@ namespace Scratch.FolderManager {
/* For now set all options to the most inclusive (except case).
* The ability to set these in the dialog (or by parameter) may be added later. */
string? search_term = null;
bool use_regex = false;
bool search_tracked_only = false;
bool recurse_subfolders = true;
bool check_is_text = true;
Expand All @@ -516,26 +519,42 @@ namespace Scratch.FolderManager {
bool case_sensitive = false;
Regex? pattern = null;

var wholeword_search = Scratch.settings.get_boolean ("wholeword-search");
var case_mode = (CaseSensitiveMode)(Scratch.settings.get_enum ("case-sensitive-search"));
var use_regex = Scratch.settings.get_boolean ("regex-search");
switch (case_mode) {
case NEVER:
case_sensitive = false;
break;
case MIXED:
case_sensitive = (term != term.ascii_up () && term != term.ascii_down ());
break;
case ALWAYS:
case_sensitive = true;
break;
default:
assert_not_reached ();
}

var folder_name = start_folder.get_basename ();
if (this.file.file.equal (start_folder)) {
folder_name = name;
}

var dialog = new Scratch.Dialogs.GlobalSearchDialog (
folder_name,
monitored_repo != null && monitored_repo.git_repo != null
monitored_repo != null && monitored_repo.git_repo != null,
case_sensitive,
wholeword_search,
use_regex
) {
case_sensitive = case_sensitive,
use_regex = use_regex,
search_term = term
};

dialog.response.connect ((response) => {
switch (response) {
case Gtk.ResponseType.ACCEPT:
search_term = dialog.search_term;
use_regex = dialog.use_regex;
case_sensitive = dialog.case_sensitive;
break;

default:
Expand All @@ -556,8 +575,10 @@ namespace Scratch.FolderManager {
win.actions.lookup_action ("action-find").activate (search_variant);

if (!use_regex) {
search_term = Regex.escape_string (search_term);
}
if (wholeword_search) {
search_term = "\\b%s\\b".printf (search_term);
}
} // else use search_term as is - TODO do we need to escape it?

try {
var flags = RegexCompileFlags.MULTILINE;
Expand Down Expand Up @@ -643,7 +664,7 @@ namespace Scratch.FolderManager {
}

private void perform_match (GLib.File target,
Regex pattern,
Regex search_regex,
bool check_is_text = false,
FileInfo? target_info = null) {
string contents;
Expand Down Expand Up @@ -687,7 +708,7 @@ namespace Scratch.FolderManager {
MatchInfo? match_info = null;
int match_count = 0;
try {
for (pattern.match (contents, 0, out match_info);
for (search_regex.match (contents, RegexMatchFlags.NOTEMPTY, out match_info);
match_info.matches ();
match_info.next ()) {

Expand Down
19 changes: 13 additions & 6 deletions src/Widgets/SearchBar.vala
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/

public enum Scratch.CaseSensitiveMode {
NEVER,
MIXED,
ALWAYS
}

namespace Scratch.Widgets {
public class SearchBar : Gtk.Box { //TODO In Gtk4 use a BinLayout Widget
enum CaseSensitiveMode {
NEVER,
MIXED,
ALWAYS
}

public weak MainWindow window { get; construct; }


Expand Down Expand Up @@ -172,8 +174,13 @@ namespace Scratch.Widgets {

Scratch.settings.bind ("cyclic-search", cycle_search_button, "active", SettingsBindFlags.DEFAULT);
Scratch.settings.bind ("wholeword-search", whole_word_search_button, "active", SettingsBindFlags.DEFAULT);
Scratch.settings.bind ("regex-search", regex_search_button, "active", SettingsBindFlags.DEFAULT);
Scratch.settings.bind ("case-sensitive-search", case_sensitive_search_button, "active-id", SettingsBindFlags.DEFAULT);
Scratch.settings.bind ("regex-search", regex_search_button, "active", SettingsBindFlags.DEFAULT);
// These settings are ignored when regex searching
regex_search_button.bind_property ("active", cycle_search_button, "sensitive", SYNC_CREATE | INVERT_BOOLEAN);
regex_search_button.bind_property ("active", whole_word_search_button, "sensitive", SYNC_CREATE | INVERT_BOOLEAN);
regex_search_button.bind_property ("active", case_sensitive_search_label, "sensitive", SYNC_CREATE | INVERT_BOOLEAN);
regex_search_button.bind_property ("active", case_sensitive_search_button, "sensitive", SYNC_CREATE | INVERT_BOOLEAN);

var search_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) {
margin_top = 3,
Expand Down