File indexing completed on 2024-06-16 05:01:12

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 #include <QDebug>
0021 #include <QObject> // tr()
0022 #include <QSet>
0023 #include <QTextStream>
0024 
0025 #include "state.h"
0026 #include "syntaxtree.h"
0027 #include "utils.h"
0028 #include "common/log.h"
0029 
0030 namespace CoreSyntax
0031 {
0032 
0033 bool exit(const QStringList &, State &)
0034 {
0035     ::exit(0);
0036 }
0037 
0038 bool showHelp(const QStringList &commands, State &state)
0039 {
0040     SyntaxTree::Command command = SyntaxTree::self()->match(commands);
0041     if (commands.isEmpty()) {
0042         state.printLine(QObject::tr("Welcome to the Sink command line tool!"));
0043         state.printLine(QObject::tr("Top-level commands:"));
0044 
0045         QSet<QString> sorted;
0046         for (auto syntax: SyntaxTree::self()->syntax()) {
0047             sorted.insert(syntax.keyword);
0048         }
0049 
0050         for (auto keyword: sorted) {
0051             state.printLine(keyword, 1);
0052         }
0053     } else if (const Syntax *syntax = command.first) {
0054         //TODO: get parent!
0055         state.print(QObject::tr("Command `%1`").arg(syntax->keyword));
0056 
0057         if (!syntax->help.isEmpty()) {
0058             state.print(": " + syntax->help);
0059         }
0060         state.printLine(QString("\n\n") + syntax->usage());
0061     } else {
0062         state.printError("Unknown command: " + commands.join(" "));
0063     }
0064 
0065     return true;
0066 }
0067 
0068 QStringList showHelpCompleter(const QStringList &commands, const QString &fragment, State &)
0069 {
0070     QStringList items;
0071 
0072     for (auto syntax: SyntaxTree::self()->syntax()) {
0073         if (syntax.keyword != QObject::tr("help") &&
0074             (fragment.isEmpty() || syntax.keyword.startsWith(fragment))) {
0075             items << syntax.keyword;
0076         }
0077     }
0078 
0079     qSort(items);
0080     return items;
0081 }
0082 
0083 bool setDebugLevel(const QStringList &commands, State &state)
0084 {
0085     if (commands.count() != 1) {
0086         state.printError(QObject::tr("Wrong number of arguments; expected 1 got %1").arg(commands.count()));
0087         return false;
0088     }
0089 
0090     bool ok = false;
0091     int level = commands[0].toUInt(&ok);
0092 
0093     if (!ok) {
0094         state.printError(QObject::tr("Expected a number between 0 and 6, got %1").arg(commands[0]));
0095         return false;
0096     }
0097 
0098     state.setDebugLevel(level);
0099     return true;
0100 }
0101 
0102 bool printDebugLevel(const QStringList &, State &state)
0103 {
0104     state.printLine(QString::number(state.debugLevel()));
0105     return true;
0106 }
0107 
0108 bool printCommandTiming(const QStringList &, State &state)
0109 {
0110     state.printLine(state.commandTiming() ? QObject::tr("on") : QObject::tr("off"));
0111     return true;
0112 }
0113 
0114 void printSyntaxBranch(State &state, const Syntax::List &list, int depth)
0115 {
0116     if (list.isEmpty()) {
0117         return;
0118     }
0119 
0120     if (depth > 0) {
0121         state.printLine("\\", depth);
0122     }
0123 
0124     for (auto syntax: list) {
0125         state.print("|-", depth);
0126         state.printLine(syntax.keyword);
0127         printSyntaxBranch(state, syntax.children, depth + 1);
0128     }
0129 }
0130 
0131 bool printSyntaxTree(const QStringList &, State &state)
0132 {
0133     printSyntaxBranch(state, SyntaxTree::self()->syntax(), 0);
0134     return true;
0135 }
0136 
0137 bool setLoggingLevel(const QStringList &commands, State &state)
0138 {
0139     if (commands.count() != 1) {
0140         state.printError(QObject::tr("Wrong number of arguments; expected 1 got %1").arg(commands.count()));
0141         return false;
0142     }
0143 
0144     state.setLoggingLevel(commands.at(0));
0145     return true;
0146 }
0147 
0148 bool printLoggingLevel(const QStringList &commands, State &state)
0149 {
0150     const QString level = state.loggingLevel();
0151     state.printLine(level);
0152     return true;
0153 }
0154 
0155 bool setLoggingAreas(const QStringList &commands, State &state)
0156 {
0157     if (commands.isEmpty()) {
0158         state.printError(QObject::tr("Wrong number of arguments; expected logging areas."));
0159         return false;
0160     }
0161 
0162     QByteArrayList areas;
0163     for (const auto &c : commands) {
0164         areas << c.toLatin1();
0165     }
0166 
0167     Sink::Log::setDebugOutputFilter(Sink::Log::Area, areas);
0168     return true;
0169 }
0170 
0171 bool setLoggingFilter(const QStringList &commands, State &state)
0172 {
0173     if (commands.isEmpty()) {
0174         state.printError(QObject::tr("Wrong number of arguments; expected resource identifier or application names."));
0175         return false;
0176     }
0177 
0178     QByteArrayList filter;
0179     for (const auto &c : commands) {
0180         filter << c.toLatin1();
0181     }
0182 
0183     Sink::Log::setDebugOutputFilter(Sink::Log::ApplicationName, filter);
0184     return true;
0185 }
0186 
0187 bool setLoggingFields(const QStringList &commands, State &state)
0188 {
0189     QByteArrayList output;
0190     for (const auto &c : commands) {
0191         output << c.toLatin1();
0192     }
0193 
0194     Sink::Log::setDebugOutputFields(output);
0195     return true;
0196 }
0197 
0198 Syntax::List syntax()
0199 {
0200     Syntax::List syntax;
0201     syntax << Syntax("exit", QObject::tr("Exits the application. Ctrl-d also works!"), &CoreSyntax::exit);
0202 
0203     Syntax help("help", QObject::tr("Print command information: help [command]"), &CoreSyntax::showHelp);
0204     help.completer = &CoreSyntax::showHelpCompleter;
0205     syntax << help;
0206 
0207     syntax << Syntax("syntaxtree", QString(), &printSyntaxTree);
0208 
0209     Syntax set("set", QObject::tr("Sets settings for the session"));
0210     set.children << Syntax("debug", QObject::tr("Set the debug level from 0 to 6"), &CoreSyntax::setDebugLevel);
0211 
0212     Syntax setTiming = Syntax("timing", QObject::tr("Whether or not to print the time commands take to complete"));
0213     setTiming.children << Syntax("on", QString(), [](const QStringList &, State &state) -> bool { state.setCommandTiming(true); return true; });
0214     setTiming.children << Syntax("off", QString(), [](const QStringList &, State &state) -> bool { state.setCommandTiming(false); return true; });
0215     set.children << setTiming;
0216 
0217     Syntax logging("logging", QObject::tr("Set the logging level to one of Trace, Log, Warning or Error"), &CoreSyntax::setLoggingLevel);
0218     logging.completer = [](const QStringList &, const QString &fragment, State &state) -> QStringList { return Utils::filteredCompletions(QStringList() << "trace" << "log" << "warning" << "error", fragment, Qt::CaseInsensitive); };
0219     set.children << logging;
0220 
0221     Syntax loggingAreas("loggingAreas", QObject::tr("Set logging areas."), &CoreSyntax::setLoggingAreas);
0222     set.children << loggingAreas;
0223 
0224     Syntax loggingFilter("loggingFilter", QObject::tr("Set logging filter."), &CoreSyntax::setLoggingFilter);
0225     set.children << loggingFilter;
0226 
0227     Syntax loggingFields("loggingFields", QObject::tr("Set logging fields."), &CoreSyntax::setLoggingFields);
0228     loggingFields.completer = [](const QStringList &, const QString &fragment, State &state) -> QStringList { return Utils::filteredCompletions(QStringList() << "time" << "name" << "function" << "location" << "", fragment, Qt::CaseInsensitive); };
0229     set.children << loggingFields;
0230 
0231     syntax << set;
0232 
0233     Syntax get("get", QObject::tr("Gets settings for the session"));
0234     get.children << Syntax("debug", QObject::tr("The current debug level from 0 to 6"), &CoreSyntax::printDebugLevel);
0235     get.children << Syntax("timing", QObject::tr("Whether or not to print the time commands take to complete"), &CoreSyntax::printCommandTiming);
0236     get.children << Syntax("logging", QObject::tr("The current logging level"), &CoreSyntax::printLoggingLevel);
0237     syntax << get;
0238 
0239     return syntax;
0240 }
0241 
0242 REGISTER_SYNTAX(CoreSyntax)
0243 
0244 } // namespace CoreSyntax
0245