2
* Copyright (C) 2010 Collabora Ltd.
4
* This library is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License as published by
6
* the Free Software Foundation, either version 2.1 of the License, or
7
* (at your option) any later version.
9
* This library 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 Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public License
15
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18
* Philip Withnall <philip.withnall@collabora.co.uk>
21
using Folks.Inspect.Commands;
27
/* We have to have a static global instance so that the readline callbacks can
28
* access its data, since they don't pass closures around. */
29
static Inspect.Client main_client = null;
31
public class Folks.Inspect.Client : Object
33
public HashMap<string, Command> commands;
34
private MainLoop main_loop;
35
private unowned Thread folks_thread;
36
public IndividualAggregator aggregator { get; private set; }
37
public BackendStore backend_store { get; private set; }
38
public SignalManager signal_manager { get; private set; }
40
public static int main (string[] args)
42
main_client = new Client ();
43
main_client.run_interactive ();
48
private void *folks_thread_main ()
50
this.main_loop = new MainLoop ();
52
this.signal_manager = new SignalManager ();
54
this.aggregator = new IndividualAggregator ();
55
this.aggregator.prepare ();
57
this.backend_store = BackendStore.dup ();
58
this.backend_store.backend_available.connect ((bs, b) =>
60
Backend backend = (Backend) b;
62
backend.prepare.begin ((obj, result) =>
66
backend.prepare.end (result);
70
warning ("Error preparing Backend '%s': %s", backend.name,
76
this.backend_store.load_backends ();
78
this.main_loop.run ();
87
this.commands = new HashMap<string, Command> (str_hash, str_equal);
89
/* Register the commands we support */
90
/* FIXME: This should be automatic */
91
this.commands.set ("quit", new Commands.Quit (this));
92
this.commands.set ("help", new Commands.Help (this));
93
this.commands.set ("individuals", new Commands.Individuals (this));
94
this.commands.set ("personas", new Commands.Personas (this));
95
this.commands.set ("backends", new Commands.Backends (this));
96
this.commands.set ("persona-stores", new Commands.PersonaStores (this));
97
this.commands.set ("signals", new Commands.Signals (this));
101
this.folks_thread = Thread<void*>.create<void*> (
102
this.folks_thread_main, true);
104
catch (ThreadError e)
106
stdout.printf ("Couldn't create aggregator thread: %s", e.message);
111
public void run_interactive ()
113
/* Interactive mode: have a little shell which allows the data from
114
* libfolks to be browsed and edited in real time. */
116
/* Allow things to be set for folks-inspect in ~/.inputrc, and install our
117
* own completion function. */
118
Readline.readline_name = "folks-inspect";
119
Readline.attempted_completion_function = Client.completion_cb;
121
/* Main prompt loop */
124
string command_line = Readline.readline ("> ");
126
if (command_line == null)
129
command_line = command_line.strip ();
130
if (command_line == "")
135
Command command = this.parse_command_line (command_line,
136
out command_name, out subcommand);
138
/* Run the command */
140
command.run (subcommand);
142
stdout.printf ("Unrecognised command '%s'.\n", command_name);
144
/* Store the command in the history, even if it failed */
145
Readline.History.add (command_line);
149
private static Command? parse_command_line (string command_line,
150
out string command_name,
151
out string? subcommand)
153
string[] parts = command_line.split (" ", 2);
155
if (parts.length < 1)
158
command_name = parts[0];
159
if (parts.length == 2 && parts[1] != "")
160
subcommand = parts[1];
164
/* Extract the first part of the command and see if it matches anything in
166
return main_client.commands.get (parts[0]);
169
[CCode (array_length = false, array_null_terminated = true)]
170
private static string[]? completion_cb (string word,
174
/* word is the word to complete, and start and end are its bounds inside
175
* Readline.line_buffer, which contains the entire current line. */
177
/* Command name completion */
180
return Readline.completion_matches (word,
181
Utils.command_name_completion_cb);
184
/* Command parameter completion is passed off to the Command objects */
187
Command command = Client.parse_command_line (Readline.line_buffer,
193
if (subcommand == null)
195
return command.complete_subcommand (subcommand);
202
private abstract class Folks.Inspect.Command
204
protected Client client;
206
public Command (Client client)
208
this.client = client;
211
public abstract string name { get; }
212
public abstract string description { get; }
213
public abstract string help { get; }
215
public abstract void run (string? command_string);
217
[CCode (array_length = false, array_null_terminated = true)]
218
public virtual string[]? complete_subcommand (string subcommand)
220
/* Default implementation */