2
* Copyright (C) 2010 Michal Hruby <michal.mhr@gmail.com>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
* Authored by Michal Hruby <michal.mhr@gmail.com>
24
public class LocatePlugin: Object, Activatable, ActionProvider
26
public bool enabled { get; set; default = true; }
28
public void activate ()
33
public void deactivate ()
38
private class MatchObject: Object, Match, UriMatch
40
// for Match interface
41
public string title { get; construct set; }
42
public string description { get; set; default = ""; }
43
public string icon_name { get; construct set; default = ""; }
44
public bool has_thumbnail { get; construct set; default = false; }
45
public string thumbnail_path { get; construct set; }
46
public MatchType match_type { get; construct set; }
49
public string uri { get; set; }
50
public QueryFlags file_type { get; set; }
51
public string mime_type { get; set; }
53
public MatchObject (string? thumbnail_path, string? icon)
55
Object (match_type: MatchType.GENERIC_URI,
56
has_thumbnail: thumbnail_path != null,
57
icon_name: icon ?? "",
58
thumbnail_path: thumbnail_path ?? "");
62
private class LocateItem: Object, SearchProvider, Match, SearchMatch
64
// for Match interface
65
public string title { get; construct set; }
66
public string description { get; set; default = ""; }
67
public string icon_name { get; construct set; default = ""; }
68
public bool has_thumbnail { get; construct set; default = false; }
69
public string thumbnail_path { get; construct set; }
70
public MatchType match_type { get; construct set; }
72
public int default_relevancy { get; set; default = Match.Score.INCREMENT_SMALL; }
73
// for SearchMatch interface
74
public Match search_source { get; set; }
75
public async Gee.List<Match> search (string query,
77
ResultSet? dest_result_set,
78
Cancellable? cancellable = null) throws SearchError
80
var q = Query (0, query, flags);
81
q.cancellable = cancellable;
82
ResultSet? results = yield plugin.locate (q);
83
dest_result_set.add_all (results);
85
return dest_result_set.get_sorted_list ();
88
private unowned LocatePlugin plugin;
90
public LocateItem (LocatePlugin plugin)
92
Object (match_type: MatchType.SEARCH,
96
description: _ ("Locate files with this name on the filesystem"));
101
static void register_plugin ()
103
DataSink.PluginRegistry.get_default ().register_plugin (
104
typeof (LocatePlugin),
106
_ ("Runs locate command to find files on the filesystem."),
109
Environment.find_program_in_path ("locate") != null,
110
_ ("Unable to find \"locate\" binary")
123
action = new LocateItem (this);
126
public bool handles_unknown ()
131
public async ResultSet? locate (Query q) throws SearchError
133
var our_results = QueryFlags.AUDIO | QueryFlags.DOCUMENTS
134
| QueryFlags.IMAGES | QueryFlags.UNCATEGORIZED | QueryFlags.VIDEO;
136
var common_flags = q.query_type & our_results;
138
q.query_string = q.query_string.strip ();
139
// ignore short searches
140
if (common_flags == 0 || q.query_string.length <= 1) return null;
142
q.check_cancellable ();
145
string regex = Regex.escape_string (q.query_string);
146
// FIXME: split pattern into words and search using --regexp?
147
string[] argv = {"locate", "-i", "-l", "%u".printf (q.max_results),
148
"*%s*".printf (regex.replace (" ", "*"))};
150
Gee.Set<string> uris = new Gee.HashSet<string> ();
157
// FIXME: fork on every letter... yey!
158
Process.spawn_async_with_pipes (null, argv, null,
159
SpawnFlags.SEARCH_PATH,
160
null, out pid, null, out read_fd);
162
UnixInputStream read_stream = new UnixInputStream (read_fd, true);
163
DataInputStream locate_output = new DataInputStream (read_stream);
166
Regex filter_re = new Regex ("/\\."); // hidden file/directory
169
line = yield locate_output.read_line_async (Priority.DEFAULT_IDLE, q.cancellable);
172
if (filter_re.match (line)) continue;
173
var file = File.new_for_path (line);
174
uris.add (file.get_uri ());
176
} while (line != null);
180
if (!q.is_cancelled ()) warning ("%s", err.message);
183
q.check_cancellable ();
185
var result = new ResultSet ();
187
foreach (string s in uris)
189
var fi = new Utils.FileInfo (s, typeof (MatchObject));
190
yield fi.initialize ();
191
if (fi.match_obj != null && fi.file_type in q.query_type)
193
int relevancy = Match.Score.INCREMENT_SMALL; // FIXME: relevancy
194
if (fi.uri.has_prefix ("file:///home/")) relevancy += Match.Score.INCREMENT_MINOR;
195
result.add (fi.match_obj, relevancy);
197
q.check_cancellable ();
203
public ResultSet? find_for_match (ref Query q, Match match)
205
var our_results = QueryFlags.AUDIO | QueryFlags.DOCUMENTS
206
| QueryFlags.IMAGES | QueryFlags.UNCATEGORIZED | QueryFlags.VIDEO;
208
var common_flags = q.query_type & our_results;
209
// ignore short searches
210
if (common_flags == 0 || match.match_type != MatchType.UNKNOWN) return null;
213
q.query_string = q.query_string.strip ();
214
bool query_empty = q.query_string == "";
215
var results = new ResultSet ();
219
results.add (action, action.default_relevancy);
223
var matchers = Query.get_matchers_for_query (q.query_string, 0,
224
RegexCompileFlags.CASELESS);
225
foreach (var matcher in matchers)
227
if (matcher.key.match (action.title))
229
results.add (action, matcher.value);