diff options
-rw-r--r-- | sinksh/syntax_modules/core_syntax.cpp | 14 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_clear.cpp | 27 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_count.cpp | 28 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_create.cpp | 62 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_drop.cpp | 24 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_inspect.cpp | 40 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_list.cpp | 37 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_livequery.cpp | 33 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_modify.cpp | 50 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_remove.cpp | 55 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_selftest.cpp | 18 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_stat.cpp | 31 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_sync.cpp | 27 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_trace.cpp | 41 | ||||
-rw-r--r-- | sinksh/syntax_modules/sink_upgrade.cpp | 16 | ||||
-rw-r--r-- | sinksh/syntaxtree.cpp | 98 | ||||
-rw-r--r-- | sinksh/syntaxtree.h | 23 |
17 files changed, 421 insertions, 203 deletions
diff --git a/sinksh/syntax_modules/core_syntax.cpp b/sinksh/syntax_modules/core_syntax.cpp index e90d894..07acc28 100644 --- a/sinksh/syntax_modules/core_syntax.cpp +++ b/sinksh/syntax_modules/core_syntax.cpp | |||
@@ -57,19 +57,7 @@ bool showHelp(const QStringList &commands, State &state) | |||
57 | if (!syntax->help.isEmpty()) { | 57 | if (!syntax->help.isEmpty()) { |
58 | state.print(": " + syntax->help); | 58 | state.print(": " + syntax->help); |
59 | } | 59 | } |
60 | state.printLine(); | 60 | state.printLine(QString("\n\n") + syntax->usage()); |
61 | |||
62 | if (!syntax->children.isEmpty()) { | ||
63 | state.printLine("Sub-commands:", 1); | ||
64 | QSet<QString> sorted; | ||
65 | for (auto childSyntax: syntax->children) { | ||
66 | sorted.insert(childSyntax.keyword); | ||
67 | } | ||
68 | |||
69 | for (auto keyword: sorted) { | ||
70 | state.printLine(keyword, 1); | ||
71 | } | ||
72 | } | ||
73 | } else { | 61 | } else { |
74 | state.printError("Unknown command: " + commands.join(" ")); | 62 | state.printError("Unknown command: " + commands.join(" ")); |
75 | } | 63 | } |
diff --git a/sinksh/syntax_modules/sink_clear.cpp b/sinksh/syntax_modules/sink_clear.cpp index e676dd6..536e9df 100644 --- a/sinksh/syntax_modules/sink_clear.cpp +++ b/sinksh/syntax_modules/sink_clear.cpp | |||
@@ -35,10 +35,25 @@ | |||
35 | namespace SinkClear | 35 | namespace SinkClear |
36 | { | 36 | { |
37 | 37 | ||
38 | bool clear(const QStringList &args, State &state); | ||
39 | |||
40 | Syntax::List syntax() | ||
41 | { | ||
42 | Syntax clear("clear", QObject::tr("Clears the local cache of one or more resources (be careful!)"), &SinkClear::clear, Syntax::NotInteractive); | ||
43 | |||
44 | clear.addPositionalArgument({.name = "resource", .help = "The resource to clear"}); | ||
45 | |||
46 | clear.completer = &SinkshUtils::resourceCompleter; | ||
47 | |||
48 | return Syntax::List() << clear; | ||
49 | } | ||
50 | |||
51 | REGISTER_SYNTAX(SinkClear) | ||
52 | |||
38 | bool clear(const QStringList &args, State &state) | 53 | bool clear(const QStringList &args, State &state) |
39 | { | 54 | { |
40 | if (args.isEmpty()) { | 55 | if (args.isEmpty()) { |
41 | state.printError(QObject::tr("Please provide at least one resource to clear.")); | 56 | state.printError(syntax()[0].usage()); |
42 | return false; | 57 | return false; |
43 | } | 58 | } |
44 | for (const auto &resource : args) { | 59 | for (const auto &resource : args) { |
@@ -50,14 +65,4 @@ bool clear(const QStringList &args, State &state) | |||
50 | return true; | 65 | return true; |
51 | } | 66 | } |
52 | 67 | ||
53 | Syntax::List syntax() | ||
54 | { | ||
55 | Syntax clear("clear", QObject::tr("Clears the local cache of one or more resources (be careful!)"), &SinkClear::clear, Syntax::NotInteractive); | ||
56 | clear.completer = &SinkshUtils::resourceCompleter; | ||
57 | |||
58 | return Syntax::List() << clear; | ||
59 | } | ||
60 | |||
61 | REGISTER_SYNTAX(SinkClear) | ||
62 | |||
63 | } | 68 | } |
diff --git a/sinksh/syntax_modules/sink_count.cpp b/sinksh/syntax_modules/sink_count.cpp index 04a9550..aaa9c33 100644 --- a/sinksh/syntax_modules/sink_count.cpp +++ b/sinksh/syntax_modules/sink_count.cpp | |||
@@ -37,12 +37,28 @@ | |||
37 | namespace SinkCount | 37 | namespace SinkCount |
38 | { | 38 | { |
39 | 39 | ||
40 | bool count(const QStringList &args, State &state); | ||
41 | |||
42 | Syntax::List syntax() | ||
43 | { | ||
44 | Syntax count("count", QObject::tr("Returns the number of items of a given type in a resource"), &SinkCount::count, Syntax::EventDriven); | ||
45 | |||
46 | count.addPositionalArgument({.name = "type", .help = "The entity type to count"}); | ||
47 | count.addPositionalArgument({.name = "resource", .help = "A resource id where to count", .required = false}); | ||
48 | |||
49 | count.completer = &SinkshUtils::typeCompleter; | ||
50 | |||
51 | return Syntax::List() << count; | ||
52 | } | ||
53 | |||
54 | REGISTER_SYNTAX(SinkCount) | ||
55 | |||
40 | bool count(const QStringList &args, State &state) | 56 | bool count(const QStringList &args, State &state) |
41 | { | 57 | { |
42 | Sink::Query query; | 58 | Sink::Query query; |
43 | query.setId("count"); | 59 | query.setId("count"); |
44 | if (!SinkshUtils::applyFilter(query, SyntaxTree::parseOptions(args))) { | 60 | if (!SinkshUtils::applyFilter(query, SyntaxTree::parseOptions(args))) { |
45 | state.printError(QObject::tr("Options: $type $filter")); | 61 | state.printError(syntax()[0].usage()); |
46 | return false; | 62 | return false; |
47 | } | 63 | } |
48 | 64 | ||
@@ -61,14 +77,4 @@ bool count(const QStringList &args, State &state) | |||
61 | return true; | 77 | return true; |
62 | } | 78 | } |
63 | 79 | ||
64 | Syntax::List syntax() | ||
65 | { | ||
66 | Syntax count("count", QObject::tr("Returns the number of items of a given type in a resource. Usage: count <type> <resource>"), &SinkCount::count, Syntax::EventDriven); | ||
67 | count.completer = &SinkshUtils::typeCompleter; | ||
68 | |||
69 | return Syntax::List() << count; | ||
70 | } | ||
71 | |||
72 | REGISTER_SYNTAX(SinkCount) | ||
73 | |||
74 | } | 80 | } |
diff --git a/sinksh/syntax_modules/sink_create.cpp b/sinksh/syntax_modules/sink_create.cpp index f18a990..b7025cc 100644 --- a/sinksh/syntax_modules/sink_create.cpp +++ b/sinksh/syntax_modules/sink_create.cpp | |||
@@ -40,15 +40,49 @@ using namespace Sink; | |||
40 | namespace SinkCreate | 40 | namespace SinkCreate |
41 | { | 41 | { |
42 | 42 | ||
43 | bool create(const QStringList &allArgs, State &state) | 43 | bool create(const QStringList &allArgs, State &state); |
44 | bool resource(const QStringList &args, State &state); | ||
45 | bool account(const QStringList &args, State &state); | ||
46 | bool identity(const QStringList &args, State &state); | ||
47 | |||
48 | Syntax::List syntax() | ||
44 | { | 49 | { |
45 | if (allArgs.isEmpty()) { | 50 | Syntax::List syntax; |
46 | state.printError(QObject::tr("A type is required"), "sinkcreate/02"); | 51 | |
47 | return false; | 52 | Syntax create("create", QObject::tr("Create items in a resource"), &SinkCreate::create); |
48 | } | 53 | create.addPositionalArgument({ .name = "type", .help = "The type of entity to create (mail, event, etc.)" }); |
54 | create.addPositionalArgument({ .name = "resourceId", .help = "The ID of the resource that will contain the new entity" }); | ||
55 | create.addPositionalArgument( | ||
56 | { .name = "key value", .help = "Content of the entity", .required = false, .variadic = true }); | ||
57 | |||
58 | Syntax resource("resource", QObject::tr("Creates a new resource"), &SinkCreate::resource); | ||
59 | resource.addPositionalArgument({ .name = "type", .help = "The type of resource to create" }); | ||
60 | resource.addPositionalArgument( | ||
61 | { .name = "key value", .help = "Content of the resource", .required = false, .variadic = true }); | ||
49 | 62 | ||
63 | Syntax account("account", QObject::tr("Creates a new account"), &SinkCreate::account); | ||
64 | account.addPositionalArgument({ .name = "type", .help = "The type of account to create" }); | ||
65 | account.addPositionalArgument( | ||
66 | { .name = "key value", .help = "Content of the account", .required = false, .variadic = true }); | ||
67 | |||
68 | Syntax identity("identity", QObject::tr("Creates a new identity"), &SinkCreate::identity); | ||
69 | identity.addPositionalArgument( | ||
70 | { .name = "key value", .help = "Content of the identity", .required = false, .variadic = true }); | ||
71 | |||
72 | create.children << resource; | ||
73 | create.children << account; | ||
74 | create.children << identity; | ||
75 | |||
76 | syntax << create; | ||
77 | return syntax; | ||
78 | } | ||
79 | |||
80 | REGISTER_SYNTAX(SinkCreate) | ||
81 | |||
82 | bool create(const QStringList &allArgs, State &state) | ||
83 | { | ||
50 | if (allArgs.count() < 2) { | 84 | if (allArgs.count() < 2) { |
51 | state.printError(QObject::tr("A resource ID is required to create items"), "sinkcreate/03"); | 85 | state.printError(syntax()[0].usage()); |
52 | return false; | 86 | return false; |
53 | } | 87 | } |
54 | 88 | ||
@@ -173,20 +207,4 @@ bool identity(const QStringList &args, State &state) | |||
173 | return true; | 207 | return true; |
174 | } | 208 | } |
175 | 209 | ||
176 | |||
177 | Syntax::List syntax() | ||
178 | { | ||
179 | Syntax::List syntax; | ||
180 | |||
181 | Syntax create("create", QObject::tr("Create items in a resource"), &SinkCreate::create); | ||
182 | create.children << Syntax("resource", QObject::tr("Creates a new resource"), &SinkCreate::resource); | ||
183 | create.children << Syntax("account", QObject::tr("Creates a new account"), &SinkCreate::account); | ||
184 | create.children << Syntax("identity", QObject::tr("Creates a new identity"), &SinkCreate::identity); | ||
185 | |||
186 | syntax << create; | ||
187 | return syntax; | ||
188 | } | ||
189 | |||
190 | REGISTER_SYNTAX(SinkCreate) | ||
191 | |||
192 | } | 210 | } |
diff --git a/sinksh/syntax_modules/sink_drop.cpp b/sinksh/syntax_modules/sink_drop.cpp index 3b9a817..2353ed1 100644 --- a/sinksh/syntax_modules/sink_drop.cpp +++ b/sinksh/syntax_modules/sink_drop.cpp | |||
@@ -35,10 +35,23 @@ | |||
35 | namespace SinkDrop | 35 | namespace SinkDrop |
36 | { | 36 | { |
37 | 37 | ||
38 | bool drop(const QStringList &args, State &state); | ||
39 | |||
40 | Syntax::List syntax() | ||
41 | { | ||
42 | Syntax drop("drop", QObject::tr("Drop all caches of a resource."), &SinkDrop::drop, Syntax::NotInteractive); | ||
43 | drop.addPositionalArgument({.name = "resource", .help = "Id(s) of the resource(s) to drop", .required = true, .variadic = true}); | ||
44 | |||
45 | drop.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
46 | return Syntax::List() << drop; | ||
47 | } | ||
48 | |||
49 | REGISTER_SYNTAX(SinkDrop) | ||
50 | |||
38 | bool drop(const QStringList &args, State &state) | 51 | bool drop(const QStringList &args, State &state) |
39 | { | 52 | { |
40 | if (args.isEmpty()) { | 53 | if (args.isEmpty()) { |
41 | state.printError(QObject::tr("Please provide at least one resource to drop.")); | 54 | state.printError(syntax()[0].usage()); |
42 | return false; | 55 | return false; |
43 | } | 56 | } |
44 | 57 | ||
@@ -57,13 +70,4 @@ bool drop(const QStringList &args, State &state) | |||
57 | return false; | 70 | return false; |
58 | } | 71 | } |
59 | 72 | ||
60 | Syntax::List syntax() | ||
61 | { | ||
62 | Syntax drop("drop", QObject::tr("Drop all caches of a resource."), &SinkDrop::drop, Syntax::NotInteractive); | ||
63 | drop.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
64 | return Syntax::List() << drop; | ||
65 | } | ||
66 | |||
67 | REGISTER_SYNTAX(SinkDrop) | ||
68 | |||
69 | } | 73 | } |
diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index f9cc50a..d952a9b 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp | |||
@@ -55,10 +55,38 @@ QString parse(const QByteArray &bytes) | |||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | bool inspect(const QStringList &args, State &state); | ||
59 | |||
60 | Syntax::List syntax() | ||
61 | { | ||
62 | Syntax state("inspect", QObject::tr("Inspect database for the resource requested"), | ||
63 | &SinkInspect::inspect, Syntax::NotInteractive); | ||
64 | |||
65 | state.addParameter("resource", | ||
66 | { .name = "resource", .help = "Which resource to inspect", .required = true }); | ||
67 | state.addParameter("db", | ||
68 | { .name = "database", .help = "Which database to inspect"}); | ||
69 | state.addParameter("filter", | ||
70 | { .name = "id", .help = "A specific id to filter the results by (currently not working)"}); | ||
71 | state.addFlag("showinternal", "Show internal fields only"); | ||
72 | state.addParameter("validaterids", | ||
73 | { .name = "type", .help = "Validate remote Ids of the given type"}); | ||
74 | state.addParameter("fulltext", | ||
75 | { .name = "id", .help = "If 'id' is not given, count the number of fulltext documents. Else, print the terms of the document with the given id"}); | ||
76 | |||
77 | state.completer = &SinkshUtils::resourceCompleter; | ||
78 | |||
79 | return Syntax::List() << state; | ||
80 | } | ||
81 | |||
82 | REGISTER_SYNTAX(SinkInspect) | ||
83 | |||
58 | bool inspect(const QStringList &args, State &state) | 84 | bool inspect(const QStringList &args, State &state) |
59 | { | 85 | { |
60 | if (args.isEmpty()) { | 86 | if (args.isEmpty()) { |
61 | state.printError(QObject::tr("Options: [--resource $resource] ([--db $db] [--filter $id] [--showinternal] | [--validaterids $type] | [--fulltext [$id]])")); | 87 | //state.printError(QObject::tr("Options: [--resource $resource] ([--db $db] [--filter $id] [--showinternal] | [--validaterids $type] | [--fulltext [$id]])")); |
88 | state.printError(syntax()[0].usage()); | ||
89 | return false; | ||
62 | } | 90 | } |
63 | auto options = SyntaxTree::parseOptions(args); | 91 | auto options = SyntaxTree::parseOptions(args); |
64 | auto resource = SinkshUtils::parseUid(options.options.value("resource").value(0).toUtf8()); | 92 | auto resource = SinkshUtils::parseUid(options.options.value("resource").value(0).toUtf8()); |
@@ -234,14 +262,4 @@ bool inspect(const QStringList &args, State &state) | |||
234 | return false; | 262 | return false; |
235 | } | 263 | } |
236 | 264 | ||
237 | Syntax::List syntax() | ||
238 | { | ||
239 | Syntax state("inspect", QObject::tr("Inspect database for the resource requested"), &SinkInspect::inspect, Syntax::NotInteractive); | ||
240 | state.completer = &SinkshUtils::resourceCompleter; | ||
241 | |||
242 | return Syntax::List() << state; | ||
243 | } | ||
244 | |||
245 | REGISTER_SYNTAX(SinkInspect) | ||
246 | |||
247 | } | 265 | } |
diff --git a/sinksh/syntax_modules/sink_list.cpp b/sinksh/syntax_modules/sink_list.cpp index 4363e6f..966548f 100644 --- a/sinksh/syntax_modules/sink_list.cpp +++ b/sinksh/syntax_modules/sink_list.cpp | |||
@@ -39,6 +39,30 @@ | |||
39 | namespace SinkList | 39 | namespace SinkList |
40 | { | 40 | { |
41 | 41 | ||
42 | bool list(const QStringList &args_, State &state); | ||
43 | |||
44 | Syntax::List syntax() | ||
45 | { | ||
46 | Syntax list("list", QObject::tr("List all resources, or the contents of one or more resources."), &SinkList::list, Syntax::NotInteractive); | ||
47 | |||
48 | list.addPositionalArgument({.name = "type", .help = "The type of content to list (resource, identity, account, mail, etc.)"}); | ||
49 | list.addParameter("resource", { .name = "resource", .help = "List only the content of the given resource" }); | ||
50 | list.addFlag("compact", "Use a compact view (reduces the size of IDs)"); | ||
51 | list.addParameter("filter", { .name = "property=$value", .help = "Filter the results" }); | ||
52 | list.addParameter("id", { .name = "id", .help = "List only the content with the given ID" }); | ||
53 | list.addFlag("showall", "Show all properties"); | ||
54 | list.addParameter("show", { .name = "property", .help = "Only show the given property" }); | ||
55 | // TODO: what is that? | ||
56 | list.addParameter("reduce", { .name = "property:$selectorProperty", .help = "Reduce the results" }); | ||
57 | list.addParameter("sort", { .name = "property", .help = "Sort the results according to the given property" }); | ||
58 | list.addParameter("limit", { .name = "count", .help = "Limit the results" }); | ||
59 | |||
60 | list.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
61 | return Syntax::List() << list; | ||
62 | } | ||
63 | |||
64 | REGISTER_SYNTAX(SinkList) | ||
65 | |||
42 | static QByteArray compressId(bool compress, const QByteArray &id) | 66 | static QByteArray compressId(bool compress, const QByteArray &id) |
43 | { | 67 | { |
44 | if (!compress) { | 68 | if (!compress) { |
@@ -115,7 +139,7 @@ QStringList printToList(const Sink::ApplicationDomain::ApplicationDomainType &o, | |||
115 | bool list(const QStringList &args_, State &state) | 139 | bool list(const QStringList &args_, State &state) |
116 | { | 140 | { |
117 | if (args_.isEmpty()) { | 141 | if (args_.isEmpty()) { |
118 | state.printError(QObject::tr("Options: $type [--resource $resource] [--compact] [--filter $property=$value] [--id $id] [--showall|--show $property] [--reduce $reduceProperty:$selectorProperty] [--sort $sortProperty] [--limit $count]")); | 142 | state.printError(syntax()[0].usage()); |
119 | return false; | 143 | return false; |
120 | } | 144 | } |
121 | 145 | ||
@@ -125,7 +149,7 @@ bool list(const QStringList &args_, State &state) | |||
125 | Sink::Query query; | 149 | Sink::Query query; |
126 | query.setId("list"); | 150 | query.setId("list"); |
127 | if (!SinkshUtils::applyFilter(query, options)) { | 151 | if (!SinkshUtils::applyFilter(query, options)) { |
128 | state.printError(QObject::tr("Options: $type [--resource $resource] [--compact] [--filter $property=$value] [--showall|--show $property]")); | 152 | state.printError(syntax()[0].usage()); |
129 | return false; | 153 | return false; |
130 | } | 154 | } |
131 | 155 | ||
@@ -193,13 +217,4 @@ bool list(const QStringList &args_, State &state) | |||
193 | return true; | 217 | return true; |
194 | } | 218 | } |
195 | 219 | ||
196 | Syntax::List syntax() | ||
197 | { | ||
198 | Syntax list("list", QObject::tr("List all resources, or the contents of one or more resources."), &SinkList::list, Syntax::NotInteractive); | ||
199 | list.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
200 | return Syntax::List() << list; | ||
201 | } | ||
202 | |||
203 | REGISTER_SYNTAX(SinkList) | ||
204 | |||
205 | } | 220 | } |
diff --git a/sinksh/syntax_modules/sink_livequery.cpp b/sinksh/syntax_modules/sink_livequery.cpp index e9e85ec..0acaaeb 100644 --- a/sinksh/syntax_modules/sink_livequery.cpp +++ b/sinksh/syntax_modules/sink_livequery.cpp | |||
@@ -38,10 +38,30 @@ | |||
38 | namespace SinkLiveQuery | 38 | namespace SinkLiveQuery |
39 | { | 39 | { |
40 | 40 | ||
41 | bool livequery(const QStringList &args_, State &state); | ||
42 | |||
43 | Syntax::List syntax() | ||
44 | { | ||
45 | Syntax list("livequery", QObject::tr("Run a livequery."), &SinkLiveQuery::livequery, Syntax::EventDriven); | ||
46 | |||
47 | list.addPositionalArgument({ .name = "type", .help = "The type to run the livequery on" }); | ||
48 | list.addParameter("resource", { .name = "resource", .help = "Filter the livequery to the given resource" }); | ||
49 | list.addFlag("compact", "Use a compact view (reduces the size of IDs)"); | ||
50 | list.addParameter("filter", { .name = "property=$value", .help = "Filter the results" }); | ||
51 | list.addParameter("id", { .name = "id", .help = "List only the content with the given ID" }); | ||
52 | list.addFlag("showall", "Show all properties"); | ||
53 | list.addParameter("show", { .name = "property", .help = "Only show the given property" }); | ||
54 | |||
55 | list.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
56 | return Syntax::List() << list; | ||
57 | } | ||
58 | |||
59 | REGISTER_SYNTAX(SinkLiveQuery) | ||
60 | |||
41 | bool livequery(const QStringList &args_, State &state) | 61 | bool livequery(const QStringList &args_, State &state) |
42 | { | 62 | { |
43 | if (args_.isEmpty()) { | 63 | if (args_.isEmpty()) { |
44 | state.printError(QObject::tr("Options: $type [--resource $resource] [--compact] [--filter $property=$value] [--id $id] [--showall|--show $property]")); | 64 | state.printError(syntax()[0].usage()); |
45 | return false; | 65 | return false; |
46 | } | 66 | } |
47 | 67 | ||
@@ -55,7 +75,7 @@ bool livequery(const QStringList &args_, State &state) | |||
55 | query.setId("livequery"); | 75 | query.setId("livequery"); |
56 | query.setFlags(Sink::Query::LiveQuery); | 76 | query.setFlags(Sink::Query::LiveQuery); |
57 | if (!SinkshUtils::applyFilter(query, options)) { | 77 | if (!SinkshUtils::applyFilter(query, options)) { |
58 | state.printError(QObject::tr("Options: $type [--resource $resource] [--compact] [--filter $property=$value] [--showall|--show $property]")); | 78 | state.printError(syntax()[0].usage()); |
59 | return false; | 79 | return false; |
60 | } | 80 | } |
61 | if (options.options.contains("resource")) { | 81 | if (options.options.contains("resource")) { |
@@ -121,13 +141,4 @@ bool livequery(const QStringList &args_, State &state) | |||
121 | return false; | 141 | return false; |
122 | } | 142 | } |
123 | 143 | ||
124 | Syntax::List syntax() | ||
125 | { | ||
126 | Syntax list("livequery", QObject::tr("Run a livequery."), &SinkLiveQuery::livequery, Syntax::EventDriven); | ||
127 | list.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
128 | return Syntax::List() << list; | ||
129 | } | ||
130 | |||
131 | REGISTER_SYNTAX(SinkLiveQuery) | ||
132 | |||
133 | } | 144 | } |
diff --git a/sinksh/syntax_modules/sink_modify.cpp b/sinksh/syntax_modules/sink_modify.cpp index 2579550..cd29d56 100644 --- a/sinksh/syntax_modules/sink_modify.cpp +++ b/sinksh/syntax_modules/sink_modify.cpp | |||
@@ -38,20 +38,36 @@ | |||
38 | namespace SinkModify | 38 | namespace SinkModify |
39 | { | 39 | { |
40 | 40 | ||
41 | bool modify(const QStringList &args, State &state) | 41 | bool modify(const QStringList &args, State &state); |
42 | bool resource(const QStringList &args, State &state); | ||
43 | |||
44 | Syntax::List syntax() | ||
42 | { | 45 | { |
43 | if (args.isEmpty()) { | 46 | Syntax modify("modify", QObject::tr("Modify items in a resource"), &SinkModify::modify); |
44 | state.printError(QObject::tr("A type is required"), "sink_modify/02"); | 47 | modify.addPositionalArgument({ .name = "type", .help = "The type of entity to modify (mail, event, etc.)" }); |
45 | return false; | 48 | modify.addPositionalArgument({ .name = "resourceId", .help = "The ID of the resource containing the entity" }); |
46 | } | 49 | modify.addPositionalArgument({ .name = "objectId", .help = "The ID of the entity" }); |
50 | modify.addPositionalArgument( | ||
51 | { .name = "key value", .help = "Attributes and values to modify", .required = false, .variadic = true }); | ||
47 | 52 | ||
48 | if (args.count() < 2) { | 53 | Syntax resource("resource", QObject::tr("Modify a resource"), &SinkModify::resource);//, Syntax::EventDriven); |
49 | state.printError(QObject::tr("A resource ID is required to remove items"), "sink_modify/03"); | 54 | |
50 | return false; | 55 | resource.addPositionalArgument({ .name = "id", .help = "The ID of the resource" }); |
51 | } | 56 | resource.addPositionalArgument( |
57 | { .name = "key value", .help = "Attributes and values to modify", .required = false, .variadic = true }); | ||
58 | |||
59 | resource.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
60 | modify.children << resource; | ||
61 | |||
62 | return Syntax::List() << modify; | ||
63 | } | ||
52 | 64 | ||
65 | REGISTER_SYNTAX(SinkModify) | ||
66 | |||
67 | bool modify(const QStringList &args, State &state) | ||
68 | { | ||
53 | if (args.count() < 3) { | 69 | if (args.count() < 3) { |
54 | state.printError(QObject::tr("An object ID is required to remove items"), "sink_modify/03"); | 70 | state.printError(syntax()[0].usage()); |
55 | return false; | 71 | return false; |
56 | } | 72 | } |
57 | 73 | ||
@@ -81,6 +97,7 @@ bool modify(const QStringList &args, State &state) | |||
81 | bool resource(const QStringList &args, State &state) | 97 | bool resource(const QStringList &args, State &state) |
82 | { | 98 | { |
83 | if (args.isEmpty()) { | 99 | if (args.isEmpty()) { |
100 | // TODO: pass the syntax as parameter | ||
84 | state.printError(QObject::tr("A resource can not be modified without an id"), "sink_modify/01"); | 101 | state.printError(QObject::tr("A resource can not be modified without an id"), "sink_modify/01"); |
85 | } | 102 | } |
86 | 103 | ||
@@ -105,17 +122,4 @@ bool resource(const QStringList &args, State &state) | |||
105 | return true; | 122 | return true; |
106 | } | 123 | } |
107 | 124 | ||
108 | |||
109 | Syntax::List syntax() | ||
110 | { | ||
111 | Syntax modify("modify", QObject::tr("Modify items in a resource"), &SinkModify::modify); | ||
112 | Syntax resource("resource", QObject::tr("Modify a resource"), &SinkModify::resource);//, Syntax::EventDriven); | ||
113 | resource.completer = &SinkshUtils::resourceOrTypeCompleter; | ||
114 | modify.children << resource; | ||
115 | |||
116 | return Syntax::List() << modify; | ||
117 | } | ||
118 | |||
119 | REGISTER_SYNTAX(SinkModify) | ||
120 | |||
121 | } | 125 | } |
diff --git a/sinksh/syntax_modules/sink_remove.cpp b/sinksh/syntax_modules/sink_remove.cpp index 6baa60f..f948290 100644 --- a/sinksh/syntax_modules/sink_remove.cpp +++ b/sinksh/syntax_modules/sink_remove.cpp | |||
@@ -37,20 +37,40 @@ | |||
37 | namespace SinkRemove | 37 | namespace SinkRemove |
38 | { | 38 | { |
39 | 39 | ||
40 | bool remove(const QStringList &args, State &state) | 40 | bool remove(const QStringList &args, State &state); |
41 | bool resource(const QStringList &args, State &state); | ||
42 | bool account(const QStringList &args, State &state); | ||
43 | bool identity(const QStringList &args, State &state); | ||
44 | |||
45 | Syntax::List syntax() | ||
41 | { | 46 | { |
42 | if (args.isEmpty()) { | 47 | Syntax remove("remove", QObject::tr("Remove items in a resource"), &SinkRemove::remove); |
43 | state.printError(QObject::tr("A type is required"), "sink_remove/02"); | ||
44 | return false; | ||
45 | } | ||
46 | 48 | ||
47 | if (args.count() < 2) { | 49 | remove.addPositionalArgument({ .name = "type", .help = "The type of entity to remove (mail, event, etc.)" }); |
48 | state.printError(QObject::tr("A resource ID is required to remove items"), "sink_remove/03"); | 50 | remove.addPositionalArgument({ .name = "resourceId", .help = "The ID of the resource containing the entity" }); |
49 | return false; | 51 | remove.addPositionalArgument({ .name = "objectId", .help = "The ID of the entity to remove" }); |
50 | } | 52 | |
53 | Syntax resource("resource", QObject::tr("Removes a resource"), &SinkRemove::resource, Syntax::NotInteractive); | ||
54 | resource.addPositionalArgument({ .name = "id", .help = "The ID of the resource to remove" }); | ||
55 | resource.completer = &SinkshUtils::resourceCompleter; | ||
56 | |||
57 | Syntax account("account", QObject::tr("Removes a account"), &SinkRemove::account, Syntax::NotInteractive); | ||
58 | account.addPositionalArgument({ .name = "id", .help = "The ID of the account to remove" }); | ||
59 | |||
60 | Syntax identity("identity", QObject::tr("Removes an identity"), &SinkRemove::identity, Syntax::NotInteractive); | ||
61 | identity.addPositionalArgument({ .name = "id", .help = "The ID of the account to remove" }); | ||
62 | |||
63 | remove.children << resource << account << identity; | ||
64 | |||
65 | return Syntax::List() << remove; | ||
66 | } | ||
67 | |||
68 | REGISTER_SYNTAX(SinkRemove) | ||
51 | 69 | ||
70 | bool remove(const QStringList &args, State &state) | ||
71 | { | ||
52 | if (args.count() < 3) { | 72 | if (args.count() < 3) { |
53 | state.printError(QObject::tr("An object ID is required to remove items"), "sink_remove/03"); | 73 | state.printError(syntax()[0].usage()); |
54 | return false; | 74 | return false; |
55 | } | 75 | } |
56 | 76 | ||
@@ -137,19 +157,4 @@ bool identity(const QStringList &args, State &state) | |||
137 | return true; | 157 | return true; |
138 | } | 158 | } |
139 | 159 | ||
140 | |||
141 | Syntax::List syntax() | ||
142 | { | ||
143 | Syntax remove("remove", QObject::tr("Remove items in a resource"), &SinkRemove::remove); | ||
144 | Syntax resource("resource", QObject::tr("Removes a resource"), &SinkRemove::resource, Syntax::NotInteractive); | ||
145 | Syntax account("account", QObject::tr("Removes a account"), &SinkRemove::account, Syntax::NotInteractive); | ||
146 | Syntax identity("identity", QObject::tr("Removes an identity"), &SinkRemove::identity, Syntax::NotInteractive); | ||
147 | resource.completer = &SinkshUtils::resourceCompleter; | ||
148 | remove.children << resource << account << identity; | ||
149 | |||
150 | return Syntax::List() << remove; | ||
151 | } | ||
152 | |||
153 | REGISTER_SYNTAX(SinkRemove) | ||
154 | |||
155 | } | 160 | } |
diff --git a/sinksh/syntax_modules/sink_selftest.cpp b/sinksh/syntax_modules/sink_selftest.cpp index a1c7dcb..132b952 100644 --- a/sinksh/syntax_modules/sink_selftest.cpp +++ b/sinksh/syntax_modules/sink_selftest.cpp | |||
@@ -41,6 +41,16 @@ | |||
41 | namespace SinkSelfTest | 41 | namespace SinkSelfTest |
42 | { | 42 | { |
43 | 43 | ||
44 | bool selfTest(const QStringList &args_, State &state); | ||
45 | |||
46 | Syntax::List syntax() | ||
47 | { | ||
48 | Syntax syntax("selftest", QObject::tr("A selftest module."), &SinkSelfTest::selfTest, Syntax::EventDriven); | ||
49 | return Syntax::List() << syntax; | ||
50 | } | ||
51 | |||
52 | REGISTER_SYNTAX(SinkSelfTest) | ||
53 | |||
44 | bool selfTest(const QStringList &args_, State &state) | 54 | bool selfTest(const QStringList &args_, State &state) |
45 | { | 55 | { |
46 | using namespace Sink::ApplicationDomain; | 56 | using namespace Sink::ApplicationDomain; |
@@ -154,12 +164,4 @@ bool selfTest(const QStringList &args_, State &state) | |||
154 | return false; | 164 | return false; |
155 | } | 165 | } |
156 | 166 | ||
157 | Syntax::List syntax() | ||
158 | { | ||
159 | Syntax syntax("selftest", QObject::tr("A selftest module."), &SinkSelfTest::selfTest, Syntax::EventDriven); | ||
160 | return Syntax::List() << syntax; | ||
161 | } | ||
162 | |||
163 | REGISTER_SYNTAX(SinkSelfTest) | ||
164 | |||
165 | } | 167 | } |
diff --git a/sinksh/syntax_modules/sink_stat.cpp b/sinksh/syntax_modules/sink_stat.cpp index 7263941..235558f 100644 --- a/sinksh/syntax_modules/sink_stat.cpp +++ b/sinksh/syntax_modules/sink_stat.cpp | |||
@@ -36,6 +36,26 @@ | |||
36 | namespace SinkStat | 36 | namespace SinkStat |
37 | { | 37 | { |
38 | 38 | ||
39 | bool stat(const QStringList &args, State &state); | ||
40 | |||
41 | Syntax::List syntax() | ||
42 | { | ||
43 | Syntax state("stat", QObject::tr("Shows database usage for the resources requested"), | ||
44 | &SinkStat::stat, Syntax::NotInteractive); | ||
45 | |||
46 | state.addPositionalArgument({ .name = "resourceId", | ||
47 | .help = "Show statistics of the given resource(s). If no resource is provided, show " | ||
48 | "statistics of all resources", | ||
49 | .required = false, | ||
50 | .variadic = true }); | ||
51 | |||
52 | state.completer = &SinkshUtils::resourceCompleter; | ||
53 | |||
54 | return Syntax::List() << state; | ||
55 | } | ||
56 | |||
57 | REGISTER_SYNTAX(SinkStat) | ||
58 | |||
39 | void statResource(const QString &resource, const State &state) | 59 | void statResource(const QString &resource, const State &state) |
40 | { | 60 | { |
41 | state.printLine("Resource " + resource + ":"); | 61 | state.printLine("Resource " + resource + ":"); |
@@ -69,7 +89,6 @@ void statResource(const QString &resource, const State &state) | |||
69 | state.printLine(QObject::tr("Actual database file sizes total: %1 [kb]").arg(size), 1); | 89 | state.printLine(QObject::tr("Actual database file sizes total: %1 [kb]").arg(size), 1); |
70 | 90 | ||
71 | QDir dataDir{Sink::resourceStorageLocation(resource.toLatin1()) + "/fulltext/"}; | 91 | QDir dataDir{Sink::resourceStorageLocation(resource.toLatin1()) + "/fulltext/"}; |
72 | Q_ASSERT(dataDir.exists()); | ||
73 | qint64 dataSize = 0; | 92 | qint64 dataSize = 0; |
74 | for (const auto &e : dataDir.entryInfoList(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot)) { | 93 | for (const auto &e : dataDir.entryInfoList(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot)) { |
75 | dataSize += e.size(); | 94 | dataSize += e.size(); |
@@ -100,14 +119,4 @@ bool stat(const QStringList &args, State &state) | |||
100 | return false; | 119 | return false; |
101 | } | 120 | } |
102 | 121 | ||
103 | Syntax::List syntax() | ||
104 | { | ||
105 | Syntax state("stat", QObject::tr("Shows database usage for the resources requested"), &SinkStat::stat, Syntax::NotInteractive); | ||
106 | state.completer = &SinkshUtils::resourceCompleter; | ||
107 | |||
108 | return Syntax::List() << state; | ||
109 | } | ||
110 | |||
111 | REGISTER_SYNTAX(SinkStat) | ||
112 | |||
113 | } | 122 | } |
diff --git a/sinksh/syntax_modules/sink_sync.cpp b/sinksh/syntax_modules/sink_sync.cpp index f165f58..ee19f0a 100644 --- a/sinksh/syntax_modules/sink_sync.cpp +++ b/sinksh/syntax_modules/sink_sync.cpp | |||
@@ -37,6 +37,23 @@ | |||
37 | namespace SinkSync | 37 | namespace SinkSync |
38 | { | 38 | { |
39 | 39 | ||
40 | bool sync(const QStringList &args, State &state); | ||
41 | |||
42 | Syntax::List syntax() | ||
43 | { | ||
44 | Syntax sync("sync", QObject::tr("Synchronizes a resource."), &SinkSync::sync, Syntax::EventDriven); | ||
45 | |||
46 | sync.addPositionalArgument({ .name = "type", .help = "The type of resource to synchronize" }); | ||
47 | sync.addPositionalArgument({ .name = "resourceId", .help = "The ID of the resource to synchronize" }); | ||
48 | sync.addParameter("password", { .name = "password", .help = "The password of the resource", .required = true }); | ||
49 | |||
50 | sync.completer = &SinkshUtils::resourceCompleter; | ||
51 | |||
52 | return Syntax::List() << sync; | ||
53 | } | ||
54 | |||
55 | REGISTER_SYNTAX(SinkSync) | ||
56 | |||
40 | bool sync(const QStringList &args, State &state) | 57 | bool sync(const QStringList &args, State &state) |
41 | { | 58 | { |
42 | auto options = SyntaxTree::parseOptions(args); | 59 | auto options = SyntaxTree::parseOptions(args); |
@@ -80,14 +97,4 @@ bool sync(const QStringList &args, State &state) | |||
80 | return true; | 97 | return true; |
81 | } | 98 | } |
82 | 99 | ||
83 | Syntax::List syntax() | ||
84 | { | ||
85 | Syntax sync("sync", QObject::tr("Synchronizes a resource."), &SinkSync::sync, Syntax::EventDriven); | ||
86 | sync.completer = &SinkshUtils::resourceCompleter; | ||
87 | |||
88 | return Syntax::List() << sync; | ||
89 | } | ||
90 | |||
91 | REGISTER_SYNTAX(SinkSync) | ||
92 | |||
93 | } | 100 | } |
diff --git a/sinksh/syntax_modules/sink_trace.cpp b/sinksh/syntax_modules/sink_trace.cpp index ed5e2d8..8636daa 100644 --- a/sinksh/syntax_modules/sink_trace.cpp +++ b/sinksh/syntax_modules/sink_trace.cpp | |||
@@ -36,6 +36,28 @@ | |||
36 | namespace SinkTrace | 36 | namespace SinkTrace |
37 | { | 37 | { |
38 | 38 | ||
39 | bool traceOff(const QStringList &args, State &state); | ||
40 | bool traceOn(const QStringList &args, State &state); | ||
41 | bool trace(const QStringList &args, State &state); | ||
42 | |||
43 | Syntax::List syntax() | ||
44 | { | ||
45 | Syntax trace("trace", QObject::tr("Control trace debug output."), &SinkTrace::trace, Syntax::NotInteractive); | ||
46 | trace.completer = &SinkshUtils::debugareaCompleter; | ||
47 | |||
48 | Syntax traceOff("off", QObject::tr("Turns off trace output."), &SinkTrace::traceOff, Syntax::NotInteractive); | ||
49 | traceOff.completer = &SinkshUtils::debugareaCompleter; | ||
50 | trace.children << traceOff; | ||
51 | |||
52 | Syntax traceOn("on", QObject::tr("Turns on trace output."), &SinkTrace::traceOn, Syntax::NotInteractive); | ||
53 | traceOn.completer = &SinkshUtils::debugareaCompleter; | ||
54 | trace.children << traceOn; | ||
55 | |||
56 | return Syntax::List() << trace; | ||
57 | } | ||
58 | |||
59 | REGISTER_SYNTAX(SinkTrace) | ||
60 | |||
39 | bool traceOff(const QStringList &args, State &state) | 61 | bool traceOff(const QStringList &args, State &state) |
40 | { | 62 | { |
41 | Sink::Log::setDebugOutputFilter(Sink::Log::Area, QByteArrayList()); | 63 | Sink::Log::setDebugOutputFilter(Sink::Log::Area, QByteArrayList()); |
@@ -66,23 +88,4 @@ bool trace(const QStringList &args, State &state) | |||
66 | return traceOn(args, state); | 88 | return traceOn(args, state); |
67 | } | 89 | } |
68 | 90 | ||
69 | |||
70 | Syntax::List syntax() | ||
71 | { | ||
72 | Syntax trace("trace", QObject::tr("Control trace debug output."), &SinkTrace::trace, Syntax::NotInteractive); | ||
73 | trace.completer = &SinkshUtils::debugareaCompleter; | ||
74 | |||
75 | Syntax traceOff("off", QObject::tr("Turns off trace output."), &SinkTrace::traceOff, Syntax::NotInteractive); | ||
76 | traceOff.completer = &SinkshUtils::debugareaCompleter; | ||
77 | trace.children << traceOff; | ||
78 | |||
79 | Syntax traceOn("on", QObject::tr("Turns on trace output."), &SinkTrace::traceOn, Syntax::NotInteractive); | ||
80 | traceOn.completer = &SinkshUtils::debugareaCompleter; | ||
81 | trace.children << traceOn; | ||
82 | |||
83 | return Syntax::List() << trace; | ||
84 | } | ||
85 | |||
86 | REGISTER_SYNTAX(SinkTrace) | ||
87 | |||
88 | } | 91 | } |
diff --git a/sinksh/syntax_modules/sink_upgrade.cpp b/sinksh/syntax_modules/sink_upgrade.cpp index c399048..03c29ae 100644 --- a/sinksh/syntax_modules/sink_upgrade.cpp +++ b/sinksh/syntax_modules/sink_upgrade.cpp | |||
@@ -29,13 +29,7 @@ | |||
29 | namespace SinkUpgrade | 29 | namespace SinkUpgrade |
30 | { | 30 | { |
31 | 31 | ||
32 | bool upgrade(const QStringList &args, State &state) | 32 | bool upgrade(const QStringList &args, State &state); |
33 | { | ||
34 | state.print(QObject::tr("Upgrading...")); | ||
35 | Sink::Store::upgrade().exec().waitForFinished(); | ||
36 | state.printLine(QObject::tr("done")); | ||
37 | return true; | ||
38 | } | ||
39 | 33 | ||
40 | Syntax::List syntax() | 34 | Syntax::List syntax() |
41 | { | 35 | { |
@@ -44,4 +38,12 @@ Syntax::List syntax() | |||
44 | 38 | ||
45 | REGISTER_SYNTAX(SinkUpgrade) | 39 | REGISTER_SYNTAX(SinkUpgrade) |
46 | 40 | ||
41 | bool upgrade(const QStringList &args, State &state) | ||
42 | { | ||
43 | state.print(QObject::tr("Upgrading...")); | ||
44 | Sink::Store::upgrade().exec().waitForFinished(); | ||
45 | state.printLine(QObject::tr("done")); | ||
46 | return true; | ||
47 | } | ||
48 | |||
47 | } | 49 | } |
diff --git a/sinksh/syntaxtree.cpp b/sinksh/syntaxtree.cpp index 0eb9782..fea99ef 100644 --- a/sinksh/syntaxtree.cpp +++ b/sinksh/syntaxtree.cpp | |||
@@ -33,6 +33,104 @@ Syntax::Syntax(const QString &k, const QString &helpText, std::function<bool(con | |||
33 | { | 33 | { |
34 | } | 34 | } |
35 | 35 | ||
36 | void Syntax::addPositionalArgument(const Argument &argument) | ||
37 | { | ||
38 | arguments.push_back(argument); | ||
39 | } | ||
40 | |||
41 | void Syntax::addParameter(const QString &name, const ParameterOptions &options) | ||
42 | { | ||
43 | parameters.insert(name, options); | ||
44 | } | ||
45 | |||
46 | void Syntax::addFlag(const QString &name, const QString &help) | ||
47 | { | ||
48 | flags.insert(name, help); | ||
49 | } | ||
50 | |||
51 | QString Syntax::usage() const | ||
52 | { | ||
53 | // TODO: refactor into meaningful functions? | ||
54 | bool hasArguments = !arguments.isEmpty(); | ||
55 | bool hasFlags = !flags.isEmpty(); | ||
56 | bool hasOptions = !parameters.isEmpty(); | ||
57 | bool hasSubcommand = !children.isEmpty(); | ||
58 | |||
59 | QString argumentsSummary; | ||
60 | |||
61 | QString argumentsUsage; | ||
62 | if (hasArguments) { | ||
63 | argumentsUsage += "\nARGUMENTS:\n"; | ||
64 | for (const auto &arg : arguments) { | ||
65 | if (arg.required) { | ||
66 | argumentsSummary += QString(" <%1>").arg(arg.name); | ||
67 | argumentsUsage += QString(" <%1>: %2\n").arg(arg.name).arg(arg.help); | ||
68 | } else { | ||
69 | argumentsSummary += QString(" [%1]").arg(arg.name); | ||
70 | argumentsUsage += QString(" [%1]: %2\n").arg(arg.name).arg(arg.help); | ||
71 | } | ||
72 | if (arg.variadic) { | ||
73 | argumentsSummary += "..."; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | if (hasFlags) { | ||
79 | argumentsSummary += " [FLAGS]"; | ||
80 | } | ||
81 | |||
82 | if (hasOptions) { | ||
83 | argumentsSummary += " [OPTIONS]"; | ||
84 | } | ||
85 | |||
86 | if (hasSubcommand) { | ||
87 | if (hasArguments || hasFlags || hasOptions) { | ||
88 | argumentsSummary = QString(" [ <SUB-COMMAND> |%1 ]").arg(argumentsSummary); | ||
89 | } else { | ||
90 | argumentsSummary = " <SUB-COMMAND>"; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | argumentsSummary += '\n'; | ||
95 | |||
96 | QString subcommandsUsage; | ||
97 | if (hasSubcommand) { | ||
98 | subcommandsUsage += "\nSUB-COMMANDS:\n" | ||
99 | " Use the 'help' command to find out more about a sub-command.\n\n"; | ||
100 | for (const auto &command : children) { | ||
101 | subcommandsUsage += QString(" %1: %2\n").arg(command.keyword).arg(command.help); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | QString flagsUsage; | ||
106 | if (hasFlags) { | ||
107 | flagsUsage += "\nFLAGS:\n"; | ||
108 | for (auto it = flags.constBegin(); it != flags.constEnd(); ++it) { | ||
109 | flagsUsage += QString(" [--%1]: %2\n").arg(it.key()).arg(it.value()); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | QString optionsUsage; | ||
114 | if (hasOptions) { | ||
115 | optionsUsage += "\nOPTIONS:\n"; | ||
116 | for (auto it = parameters.constBegin(); it != parameters.constEnd(); ++it) { | ||
117 | optionsUsage += " "; | ||
118 | if (!it.value().required) { | ||
119 | optionsUsage += QString("[--%1 $%2]").arg(it.key()).arg(it.value().name); | ||
120 | } else { | ||
121 | optionsUsage += QString("<--%1 $%2>").arg(it.key()).arg(it.value().name); | ||
122 | } | ||
123 | |||
124 | optionsUsage += ": " + it.value().help + '\n'; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // TODO: instead of just the keyword, we might want to have the whole | ||
129 | // command (e.g. if this is a sub-command) | ||
130 | return QString("USAGE:\n ") + keyword + argumentsSummary + subcommandsUsage + | ||
131 | argumentsUsage + flagsUsage + optionsUsage; | ||
132 | } | ||
133 | |||
36 | SyntaxTree::SyntaxTree() | 134 | SyntaxTree::SyntaxTree() |
37 | { | 135 | { |
38 | } | 136 | } |
diff --git a/sinksh/syntaxtree.h b/sinksh/syntaxtree.h index ce28548..3d90288 100644 --- a/sinksh/syntaxtree.h +++ b/sinksh/syntaxtree.h | |||
@@ -42,10 +42,33 @@ public: | |||
42 | Syntax(const QString &keyword, const QString &helpText = QString(), | 42 | Syntax(const QString &keyword, const QString &helpText = QString(), |
43 | std::function<bool(const QStringList &, State &)> lambda = std::function<bool(const QStringList &, State &)>(), Interactivity interactivity = NotInteractive); | 43 | std::function<bool(const QStringList &, State &)> lambda = std::function<bool(const QStringList &, State &)>(), Interactivity interactivity = NotInteractive); |
44 | 44 | ||
45 | struct Argument { | ||
46 | QString name; | ||
47 | QString help; | ||
48 | bool required = true; | ||
49 | bool variadic = false; | ||
50 | }; | ||
51 | |||
52 | struct ParameterOptions { | ||
53 | QString name; | ||
54 | QString help; | ||
55 | bool required = false; | ||
56 | }; | ||
57 | |||
58 | // TODO: add examples? | ||
45 | QString keyword; | 59 | QString keyword; |
46 | QString help; | 60 | QString help; |
61 | QVector<Argument> arguments; | ||
62 | QMap<QString, ParameterOptions> parameters; | ||
63 | QMap<QString, QString> flags; | ||
47 | Interactivity interactivity; | 64 | Interactivity interactivity; |
48 | 65 | ||
66 | void addPositionalArgument(const Argument &); | ||
67 | void addParameter(const QString &name, const ParameterOptions &options); | ||
68 | void addFlag(const QString &name, const QString &help); | ||
69 | |||
70 | QString usage() const; | ||
71 | |||
49 | /** | 72 | /** |
50 | * This function will be called to execute the command. | 73 | * This function will be called to execute the command. |
51 | * | 74 | * |