File indexing completed on 2024-05-12 15:49:59

0001 /*
0002     SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "ksyntaxhighlighting_version.h"
0008 
0009 #include <KSyntaxHighlighting/Definition>
0010 #include <KSyntaxHighlighting/DefinitionDownloader>
0011 #include <KSyntaxHighlighting/Repository>
0012 #include <KSyntaxHighlighting/Theme>
0013 #include <ansihighlighter.h>
0014 #include <htmlhighlighter.h>
0015 
0016 #include <QCommandLineParser>
0017 #include <QCoreApplication>
0018 #include <QFile>
0019 
0020 #include <iostream>
0021 
0022 using namespace KSyntaxHighlighting;
0023 
0024 template<class Highlighter, class... Ts>
0025 static void applyHighlighter(Highlighter &highlighter,
0026                              QCommandLineParser &parser,
0027                              bool fromFileName,
0028                              const QString &inFileName,
0029                              const QCommandLineOption &stdinOption,
0030                              const QCommandLineOption &outputName,
0031                              const Ts &...highlightParams)
0032 {
0033     if (parser.isSet(outputName)) {
0034         highlighter.setOutputFile(parser.value(outputName));
0035     } else {
0036         highlighter.setOutputFile(stdout);
0037     }
0038 
0039     if (fromFileName) {
0040         highlighter.highlightFile(inFileName, highlightParams...);
0041     } else if (parser.isSet(stdinOption)) {
0042         QFile inFile;
0043         inFile.open(stdin, QIODevice::ReadOnly);
0044         highlighter.highlightData(&inFile, highlightParams...);
0045     } else {
0046         parser.showHelp(1);
0047     }
0048 }
0049 
0050 int main(int argc, char **argv)
0051 {
0052     QCoreApplication app(argc, argv);
0053     QCoreApplication::setApplicationName(QStringLiteral("kate-syntax-highlighter"));
0054     QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
0055     QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
0056     QCoreApplication::setApplicationVersion(QStringLiteral(SyntaxHighlighting_VERSION_STRING));
0057 
0058     Repository repo;
0059 
0060     QCommandLineParser parser;
0061     parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using Kate syntax definitions."));
0062     parser.addHelpOption();
0063     parser.addVersionOption();
0064     parser.addPositionalArgument(app.translate("SyntaxHighlightingCLI", "source"), app.translate("SyntaxHighlightingCLI", "The source file to highlight."));
0065 
0066     QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"),
0067                                 app.translate("SyntaxHighlightingCLI", "List all available syntax definitions."));
0068     parser.addOption(listDefs);
0069     QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"), app.translate("SyntaxHighlightingCLI", "List all available themes."));
0070     parser.addOption(listThemes);
0071 
0072     QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"),
0073                                   app.translate("SyntaxHighlightingCLI", "Download new/updated syntax definitions."));
0074     parser.addOption(updateDefs);
0075 
0076     QCommandLineOption outputName(QStringList() << QStringLiteral("o") << QStringLiteral("output"),
0077                                   app.translate("SyntaxHighlightingCLI", "File to write HTML output to (default: stdout)."),
0078                                   app.translate("SyntaxHighlightingCLI", "output"));
0079     parser.addOption(outputName);
0080 
0081     QCommandLineOption syntaxName(QStringList() << QStringLiteral("s") << QStringLiteral("syntax"),
0082                                   app.translate("SyntaxHighlightingCLI", "Highlight using this syntax definition (default: auto-detect based on input file)."),
0083                                   app.translate("SyntaxHighlightingCLI", "syntax"));
0084     parser.addOption(syntaxName);
0085 
0086     QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"),
0087                                  app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."),
0088                                  app.translate("SyntaxHighlightingCLI", "theme"),
0089                                  repo.defaultTheme(Repository::LightTheme).name());
0090     parser.addOption(themeName);
0091 
0092     QCommandLineOption outputFormatOption(
0093         QStringList() << QStringLiteral("f") << QStringLiteral("output-format"),
0094         app.translate("SyntaxHighlightingCLI", "Use the specified format instead of html. Must be html, ansi or ansi256Colors."),
0095         app.translate("SyntaxHighlightingCLI", "format"),
0096         QStringLiteral("html"));
0097     parser.addOption(outputFormatOption);
0098 
0099     QCommandLineOption traceOption(QStringList() << QStringLiteral("syntax-trace"),
0100                                    app.translate("SyntaxHighlightingCLI",
0101                                                  "Add information to debug a syntax file. Only works with --output-format=ansi or ansi256Colors. Possible "
0102                                                  "values are format, region, context and stackSize."),
0103                                    app.translate("SyntaxHighlightingCLI", "type"));
0104     parser.addOption(traceOption);
0105 
0106     QCommandLineOption noAnsiEditorBg(QStringList() << QStringLiteral("b") << QStringLiteral("no-ansi-background"),
0107                                       app.translate("SyntaxHighlightingCLI", "Disable ANSI background for the default color."));
0108     parser.addOption(noAnsiEditorBg);
0109 
0110     QCommandLineOption titleOption(
0111         QStringList() << QStringLiteral("T") << QStringLiteral("title"),
0112         app.translate("SyntaxHighlightingCLI", "Set HTML page's title\n(default: the filename or \"Kate Syntax Highlighter\" if reading from stdin)."),
0113         app.translate("SyntaxHighlightingCLI", "title"));
0114     parser.addOption(titleOption);
0115 
0116     QCommandLineOption stdinOption(QStringList() << QStringLiteral("stdin"),
0117                                    app.translate("SyntaxHighlightingCLI", "Read file from stdin. The -s option must also be used."));
0118     parser.addOption(stdinOption);
0119 
0120     parser.process(app);
0121 
0122     if (parser.isSet(listDefs)) {
0123         for (const auto &def : repo.definitions()) {
0124             std::cout << qPrintable(def.name()) << std::endl;
0125         }
0126         return 0;
0127     }
0128 
0129     if (parser.isSet(listThemes)) {
0130         for (const auto &theme : repo.themes()) {
0131             std::cout << qPrintable(theme.name()) << std::endl;
0132         }
0133         return 0;
0134     }
0135 
0136     if (parser.isSet(updateDefs)) {
0137         DefinitionDownloader downloader(&repo);
0138         QObject::connect(&downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) {
0139             std::cout << qPrintable(msg) << std::endl;
0140         });
0141         QObject::connect(&downloader, &DefinitionDownloader::done, &app, &QCoreApplication::quit);
0142         downloader.start();
0143         return app.exec();
0144     }
0145 
0146     bool fromFileName = false;
0147     QString inFileName;
0148     if (parser.positionalArguments().size() == 1) {
0149         fromFileName = true;
0150         inFileName = parser.positionalArguments().at(0);
0151     }
0152 
0153     Definition def;
0154     if (parser.isSet(syntaxName)) {
0155         const QString syntax = parser.value(syntaxName);
0156         def = repo.definitionForName(syntax);
0157         if (!def.isValid()) {
0158             /* see if it's a mimetype instead */
0159             def = repo.definitionForMimeType(syntax);
0160             if (!def.isValid()) {
0161                 /* see if it's a extension instead */
0162                 def = repo.definitionForFileName(QLatin1String("f.") + syntax);
0163                 if (!def.isValid()) {
0164                     /* see if it's a filename instead */
0165                     def = repo.definitionForFileName(syntax);
0166                 }
0167             }
0168         }
0169     } else if (fromFileName) {
0170         def = repo.definitionForFileName(inFileName);
0171     } else {
0172         parser.showHelp(1);
0173     }
0174 
0175     if (!def.isValid()) {
0176         std::cerr << "Unknown syntax." << std::endl;
0177         return 1;
0178     }
0179 
0180     QString outputFormat = parser.value(outputFormatOption);
0181     if (0 == outputFormat.compare(QLatin1String("html"), Qt::CaseInsensitive)) {
0182         QString title;
0183         if (parser.isSet(titleOption)) {
0184             title = parser.value(titleOption);
0185         }
0186 
0187         HtmlHighlighter highlighter;
0188         highlighter.setDefinition(def);
0189         highlighter.setTheme(repo.theme(parser.value(themeName)));
0190         applyHighlighter(highlighter, parser, fromFileName, inFileName, stdinOption, outputName, title);
0191     } else {
0192         auto AnsiFormat = AnsiHighlighter::AnsiFormat::TrueColor;
0193         if (0 == outputFormat.compare(QLatin1String("ansi256Colors"), Qt::CaseInsensitive)) {
0194             AnsiFormat = AnsiHighlighter::AnsiFormat::XTerm256Color;
0195         } else if (0 != outputFormat.compare(QLatin1String("ansi"), Qt::CaseInsensitive)) {
0196             std::cerr << "Unknown output format." << std::endl;
0197             return 2;
0198         }
0199 
0200         auto debugOptions = AnsiHighlighter::TraceOptions();
0201         if (parser.isSet(traceOption)) {
0202             const auto options = parser.values(traceOption);
0203             for (auto const &option : options) {
0204                 if (option == QStringLiteral("format")) {
0205                     debugOptions |= AnsiHighlighter::TraceOption::Format;
0206                 } else if (option == QStringLiteral("region")) {
0207                     debugOptions |= AnsiHighlighter::TraceOption::Region;
0208                 } else if (option == QStringLiteral("context")) {
0209                     debugOptions |= AnsiHighlighter::TraceOption::Context;
0210                 } else if (option == QStringLiteral("stackSize")) {
0211                     debugOptions |= AnsiHighlighter::TraceOption::StackSize;
0212                 } else {
0213                     std::cerr << "Unknown trace name." << std::endl;
0214                     return 2;
0215                 }
0216             }
0217         }
0218 
0219         AnsiHighlighter highlighter;
0220         highlighter.setDefinition(def);
0221         highlighter.setTheme(repo.theme(parser.value(themeName)));
0222         applyHighlighter(highlighter, parser, fromFileName, inFileName, stdinOption, outputName, AnsiFormat, !parser.isSet(noAnsiEditorBg), debugOptions);
0223     }
0224 
0225     return 0;
0226 }