File indexing completed on 2024-05-12 05:26:20

0001 /*
0002  * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org>
0003  *
0004  *   This program is free software; you can redistribute it and/or modify
0005  *   it under the terms of the GNU General Public License as published by
0006  *   the Free Software Foundation; either version 2 of the License, or
0007  *   (at your option) any later version.
0008  *
0009  *   This program is distributed in the hope that it will be useful,
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *   GNU General Public License for more details.
0013  *
0014  *   You should have received a copy of the GNU General Public License
0015  *   along with this program; if not, write to the
0016  *   Free Software Foundation, Inc.,
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
0018  */
0019 
0020 #pragma once
0021 
0022 #include "state.h"
0023 
0024 #include <QStringList>
0025 #include <QTime>
0026 #include <QVector>
0027 
0028 #include <functional>
0029 
0030 class Syntax
0031 {
0032 public:
0033     typedef QVector<Syntax> List;
0034 
0035     enum Interactivity
0036     {
0037         NotInteractive = 0,
0038         EventDriven
0039     };
0040 
0041     Syntax();
0042     Syntax(const QString &keyword, const QString &helpText = QString(),
0043         std::function<bool(const QStringList &, State &)> lambda = std::function<bool(const QStringList &, State &)>(), Interactivity interactivity = NotInteractive);
0044 
0045     struct Argument {
0046         QString name;
0047         QString help;
0048         bool required = true;
0049         bool variadic = false;
0050     };
0051 
0052     struct ParameterOptions {
0053         QString name;
0054         QString help;
0055         bool required = false;
0056     };
0057 
0058     // TODO: add examples?
0059     QString keyword;
0060     QString help;
0061     QVector<Argument> arguments;
0062     QMap<QString, ParameterOptions> parameters;
0063     QMap<QString, QString> flags;
0064     Interactivity interactivity;
0065 
0066     void addPositionalArgument(const Argument &);
0067     void addParameter(const QString &name, const ParameterOptions &options);
0068     void addFlag(const QString &name, const QString &help);
0069 
0070     QString usage() const;
0071 
0072     /**
0073      * This function will be called to execute the command.
0074      *
0075      * @arguments: The command arguments
0076      * @state: The state object
0077      * @return: Return true for success and false for error. If the command is event driven, returning false will not start an event loop and abort immediately.
0078      * If the command is not event driven, returning false will set the exit code to 1.
0079      */
0080     std::function<bool(const QStringList &arguments, State &state)> lambda;
0081     std::function<QStringList(const QStringList &, const QString &, State &state)> completer;
0082 
0083     QVector<Syntax> children;
0084 };
0085 
0086 class SyntaxTree
0087 {
0088 public:
0089     typedef std::pair<const Syntax *, QStringList> Command;
0090 
0091     static SyntaxTree *self();
0092 
0093     int registerSyntax(std::function<Syntax::List()> f);
0094     Syntax::List syntax() const;
0095     Command match(const QStringList &commands) const;
0096     Syntax::List nearestSyntax(const QStringList &words, const QString &fragment) const;
0097     State &state();
0098     int run(const QStringList &commands);
0099 
0100     static QStringList tokenize(const QString &text);
0101 
0102     struct Options {
0103         QStringList positionalArguments;
0104         QMap<QString, QStringList> options;
0105     };
0106     static Options parseOptions(const QStringList &text);
0107 
0108 private:
0109     SyntaxTree();
0110 
0111     Syntax::List m_syntax;
0112     State m_state;
0113     QTime m_timeElapsed;
0114     static SyntaxTree *s_module;
0115 };
0116 
0117 #define REGISTER_SYNTAX(name) static const int theTrickFor##name = SyntaxTree::self()->registerSyntax(&name::syntax);