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 CommandPlugin: Object, Activatable, ItemProvider
26
public bool enabled { get; set; default = true; }
28
public void activate ()
33
public void deactivate ()
38
private class CommandObject: Object, Match, ApplicationMatch
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; }
48
// for ApplicationMatch
49
public AppInfo? app_info { get; set; default = null; }
50
public bool needs_terminal { get; set; default = false; }
51
public string? filename { get; construct set; default = null; }
52
public string command { get; construct set; }
54
public CommandObject (string cmd)
56
Object (title: _("Execute '%s'").printf (cmd), description: _ ("Run command"), command: cmd,
57
icon_name: "application-x-executable",
58
match_type: MatchType.APPLICATION,
59
needs_terminal: cmd.has_prefix ("sudo "));
63
app_info = AppInfo.create_from_commandline (cmd, null, 0);
67
warning ("%s", err.message);
72
static void register_plugin ()
74
DataSink.PluginRegistry.get_default ().register_plugin (
75
typeof (CommandPlugin),
77
_ ("Find and execute arbitrary commands."),
88
private Gee.Set<string> past_commands;
89
private Regex split_regex;
93
// TODO: load from configuration
94
past_commands = new Gee.HashSet<string> ();
97
split_regex = new Regex ("\\s+", RegexCompileFlags.OPTIMIZE);
99
catch (RegexError err)
101
critical ("%s", err.message);
105
private CommandObject? create_co (string exec)
107
// ignore results that will be returned by DesktopFilePlugin
108
// and at the same time look for hidden and no-display desktop files,
109
// so we can display their info (title, comment, icon)
110
var dfs = DesktopFileService.get_default ();
111
var df_list = dfs.get_desktop_files_for_exec (exec);
112
DesktopFileInfo? dfi = null;
113
foreach (var df in df_list)
115
if (!df.is_hidden) return null; // will be handled by App plugin
119
var co = new CommandObject (exec);
123
if (dfi.comment != "") co.description = dfi.comment;
124
if (dfi.icon_name != null && dfi.icon_name != "") co.icon_name = dfi.icon_name;
130
private void command_executed (Match match)
132
CommandObject? co = match as CommandObject;
133
if (co == null) return;
135
past_commands.add (co.command);
138
public async ResultSet? search (Query q) throws SearchError
140
// we only search for applications
141
if (!(QueryFlags.APPLICATIONS in q.query_type)) return null;
143
Idle.add (search.callback);
146
var result = new ResultSet ();
148
string stripped = q.query_string.strip ();
149
if (stripped == "") return null;
150
if (stripped.has_prefix ("~/"))
152
stripped = stripped.replace ("~", Environment.get_home_dir ());
155
if (!(stripped in past_commands))
157
foreach (var command in past_commands)
159
if (command.has_prefix (stripped))
161
result.add (create_co (command), Match.Score.AVERAGE);
165
string[] args = split_regex.split (stripped);
166
string? valid_cmd = Environment.find_program_in_path (args[0]);
168
if (valid_cmd != null)
170
// don't allow dangerous commands
171
if (args[0] == "rm") return null;
172
CommandObject? co = create_co (stripped);
173
if (co == null) return null;
174
result.add (co, Match.Score.POOR);
175
co.executed.connect (this.command_executed);
180
result.add (create_co (stripped), Match.Score.VERY_GOOD);
183
q.check_cancellable ();
2
* Copyright (c) 2010 Michal Hruby <michal.mhr@gmail.com>
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this program; if not, write to the
17
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301 USA
20
* Authored by: Michal Hruby <michal.mhr@gmail.com>
24
public class CommandPlugin: Object, Activatable, ItemProvider {
25
public bool enabled { get; set; default = true; }
27
public void activate () { }
29
public void deactivate () { }
31
private class CommandObject: Object, Match, ApplicationMatch {
32
// for Match interface
33
public string title { get; construct set; }
34
public string description { get; set; default = ""; }
35
public string icon_name { get; construct set; default = ""; }
36
public bool has_thumbnail { get; construct set; default = false; }
37
public string thumbnail_path { get; construct set; }
38
public MatchType match_type { get; construct set; }
40
// for ApplicationMatch
41
public AppInfo? app_info { get; set; default = null; }
42
public bool needs_terminal { get; set; default = false; }
43
public string? filename { get; construct set; default = null; }
44
public string command { get; construct set; }
46
public CommandObject (string cmd) {
47
Object (title: _("Execute '%s'").printf (cmd), description: _("Run command"), command: cmd,
48
icon_name: "application-x-executable",
49
match_type: MatchType.APPLICATION,
50
needs_terminal: cmd.has_prefix ("sudo "));
53
app_info = AppInfo.create_from_commandline (cmd, null, 0);
55
warning ("%s", err.message);
60
static void register_plugin () {
61
DataSink.PluginRegistry.get_default ().register_plugin (typeof (CommandPlugin),
63
_("Find and execute arbitrary commands."),
72
private Gee.Set<string> past_commands;
73
private Regex split_regex;
76
// TODO: load from configuration
77
past_commands = new Gee.HashSet<string> ();
80
split_regex = new Regex ("\\s+", RegexCompileFlags.OPTIMIZE);
81
} catch (RegexError err) {
82
critical ("%s", err.message);
86
private CommandObject? create_co (string exec) {
87
// ignore results that will be returned by DesktopFilePlugin
88
// and at the same time look for hidden and no-display desktop files,
89
// so we can display their info (title, comment, icon)
90
var dfs = DesktopFileService.get_default ();
91
var df_list = dfs.get_desktop_files_for_exec (exec);
92
DesktopFileInfo? dfi = null;
94
foreach (var df in df_list) {
96
return null; // will be handled by App plugin
101
var co = new CommandObject (exec);
104
if (dfi.comment != "") {
105
co.description = dfi.comment;
108
if (dfi.icon_name != null && dfi.icon_name != "") {
109
co.icon_name = dfi.icon_name;
116
private void command_executed (Match match) {
117
CommandObject? co = match as CommandObject;
122
past_commands.add (co.command);
125
public async ResultSet? search (Query q) throws SearchError {
126
// we only search for applications
127
if (!(QueryFlags.APPLICATIONS in q.query_type)) {
131
Idle.add (search.callback);
134
var result = new ResultSet ();
135
string stripped = q.query_string.strip ();
137
if (stripped == "") {
141
if (stripped.has_prefix ("~/")) {
142
stripped = stripped.replace ("~", Environment.get_home_dir ());
145
if (!(stripped in past_commands)) {
146
foreach (var command in past_commands) {
147
if (command.has_prefix (stripped)) {
148
result.add (create_co (command), Match.Score.AVERAGE);
152
string[] args = split_regex.split (stripped);
153
string? valid_cmd = Environment.find_program_in_path (args[0]);
155
if (valid_cmd != null) {
156
// don't allow dangerous commands
157
if (args[0] == "rm") {
160
CommandObject? co = create_co (stripped);
165
result.add (co, Match.Score.POOR);
166
co.executed.connect (this.command_executed);
169
result.add (create_co (stripped), Match.Score.VERY_GOOD);
171
q.check_cancellable ();