1/*
2 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: MIT
5*/
6
7#include "ksyntaxhighlighting_version.h"
8
9#include <KSyntaxHighlighting/Definition>
10#include <KSyntaxHighlighting/DefinitionDownloader>
11#include <KSyntaxHighlighting/Repository>
12#include <KSyntaxHighlighting/Theme>
13#include <ansihighlighter.h>
14#include <htmlhighlighter.h>
15
16#include <QCommandLineParser>
17#include <QCoreApplication>
18#include <QFile>
19
20#include <iostream>
21
22using namespace KSyntaxHighlighting;
23
24template<class Highlighter, class... Ts>
25static void applyHighlighter(Highlighter &highlighter,
26 QCommandLineParser &parser,
27 bool fromFileName,
28 const QString &inFileName,
29 const QCommandLineOption &outputName,
30 const Ts &...highlightParams)
31{
32 if (parser.isSet(option: outputName)) {
33 highlighter.setOutputFile(parser.value(option: outputName));
34 } else {
35 highlighter.setOutputFile(stdout);
36 }
37
38 if (fromFileName) {
39 highlighter.highlightFile(inFileName, highlightParams...);
40 } else {
41 QFile inFile;
42 inFile.open(stdin, ioFlags: QIODevice::ReadOnly);
43 highlighter.highlightData(&inFile, highlightParams...);
44 }
45}
46
47static Theme theme(const Repository &repo, const QString &themeName, Repository::DefaultTheme t)
48{
49 if (themeName.isEmpty()) {
50 return repo.defaultTheme(t);
51 }
52 return repo.theme(themeName);
53}
54
55int main(int argc, char **argv)
56{
57 QCoreApplication app(argc, argv);
58 QCoreApplication::setApplicationName(QStringLiteral("ksyntaxhighlighter"));
59 QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
60 QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
61 QCoreApplication::setApplicationVersion(QStringLiteral(KSYNTAXHIGHLIGHTING_VERSION_STRING));
62
63 QCommandLineParser parser;
64 parser.setApplicationDescription(app.translate(context: "SyntaxHighlightingCLI", key: "Command line syntax highlighter using KSyntaxHighlighting syntax definitions."));
65 parser.addHelpOption();
66 parser.addVersionOption();
67 parser.addPositionalArgument(
68 name: app.translate(context: "SyntaxHighlightingCLI", key: "source"),
69 description: app.translate(context: "SyntaxHighlightingCLI", key: "The source file to highlight. If absent, read the file from stdin and the --syntax option must be used."));
70
71 QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"),
72 app.translate(context: "SyntaxHighlightingCLI", key: "List all available syntax definitions."));
73 parser.addOption(commandLineOption: listDefs);
74 QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"), app.translate(context: "SyntaxHighlightingCLI", key: "List all available themes."));
75 parser.addOption(commandLineOption: listThemes);
76
77 QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"),
78 app.translate(context: "SyntaxHighlightingCLI", key: "Download new/updated syntax definitions."));
79 parser.addOption(commandLineOption: updateDefs);
80
81 QCommandLineOption outputName(QStringList() << QStringLiteral("o") << QStringLiteral("output"),
82 app.translate(context: "SyntaxHighlightingCLI", key: "File to write HTML output to (default: stdout)."),
83 app.translate(context: "SyntaxHighlightingCLI", key: "output"));
84 parser.addOption(commandLineOption: outputName);
85
86 QCommandLineOption syntaxName(QStringList() << QStringLiteral("s") << QStringLiteral("syntax"),
87 app.translate(context: "SyntaxHighlightingCLI", key: "Highlight using this syntax definition (default: auto-detect based on input file)."),
88 app.translate(context: "SyntaxHighlightingCLI", key: "syntax"));
89 parser.addOption(commandLineOption: syntaxName);
90
91 QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"),
92 app.translate(context: "SyntaxHighlightingCLI", key: "Color theme to use for highlighting."),
93 app.translate(context: "SyntaxHighlightingCLI", key: "theme"));
94 parser.addOption(commandLineOption: themeName);
95
96 QCommandLineOption outputFormatOption(
97 QStringList() << QStringLiteral("f") << QStringLiteral("output-format"),
98 app.translate(context: "SyntaxHighlightingCLI", key: "Use the specified format instead of html. Must be html, ansi or ansi256Colors."),
99 app.translate(context: "SyntaxHighlightingCLI", key: "format"),
100 QStringLiteral("html"));
101 parser.addOption(commandLineOption: outputFormatOption);
102
103 QCommandLineOption traceOption(QStringList() << QStringLiteral("syntax-trace"),
104 app.translate(context: "SyntaxHighlightingCLI",
105 key: "Add information to debug a syntax file. Only works with --output-format=ansi or ansi256Colors. Possible "
106 "values are format, region, context, stackSize and all."),
107 app.translate(context: "SyntaxHighlightingCLI", key: "type"));
108 parser.addOption(commandLineOption: traceOption);
109
110 QCommandLineOption noAnsiEditorBg(QStringList() << QStringLiteral("b") << QStringLiteral("no-ansi-background"),
111 app.translate(context: "SyntaxHighlightingCLI", key: "Disable ANSI background for the default color."));
112 parser.addOption(commandLineOption: noAnsiEditorBg);
113
114 QCommandLineOption unbufferedAnsi(QStringList() << QStringLiteral("U") << QStringLiteral("unbuffered"),
115 app.translate(context: "SyntaxHighlightingCLI", key: "For ansi and ansi256Colors formats, flush the output buffer on each line."));
116 parser.addOption(commandLineOption: unbufferedAnsi);
117
118 QCommandLineOption titleOption(
119 QStringList() << QStringLiteral("T") << QStringLiteral("title"),
120 app.translate(context: "SyntaxHighlightingCLI", key: "Set HTML page's title\n(default: the filename or \"KSyntaxHighlighter\" if reading from stdin)."),
121 app.translate(context: "SyntaxHighlightingCLI", key: "title"));
122 parser.addOption(commandLineOption: titleOption);
123
124 parser.process(app);
125
126 Repository repo;
127
128 if (parser.isSet(option: listDefs)) {
129 for (const auto &def : repo.definitions()) {
130 std::cout << qPrintable(def.name()) << std::endl;
131 }
132 return 0;
133 }
134
135 if (parser.isSet(option: listThemes)) {
136 for (const auto &theme : repo.themes()) {
137 std::cout << qPrintable(theme.name()) << std::endl;
138 }
139 return 0;
140 }
141
142 if (parser.isSet(option: updateDefs)) {
143 DefinitionDownloader downloader(&repo);
144 QObject::connect(sender: &downloader, signal: &DefinitionDownloader::informationMessage, slot: [](const QString &msg) {
145 std::cout << qPrintable(msg) << std::endl;
146 });
147 QObject::connect(sender: &downloader, signal: &DefinitionDownloader::done, context: &app, slot: &QCoreApplication::quit);
148 downloader.start();
149 return app.exec();
150 }
151
152 bool fromFileName = false;
153 QString inFileName;
154 if (parser.positionalArguments().size() == 1) {
155 fromFileName = true;
156 inFileName = parser.positionalArguments().at(i: 0);
157 }
158
159 Definition def;
160 if (parser.isSet(option: syntaxName)) {
161 const QString syntax = parser.value(option: syntaxName);
162 def = repo.definitionForName(defName: syntax);
163 if (!def.isValid()) {
164 /* see if it's a mimetype instead */
165 def = repo.definitionForMimeType(mimeType: syntax);
166 if (!def.isValid()) {
167 /* see if it's a extension instead */
168 def = repo.definitionForFileName(fileName: QLatin1String("f.") + syntax);
169 if (!def.isValid()) {
170 /* see if it's a filename instead */
171 def = repo.definitionForFileName(fileName: syntax);
172 }
173 }
174 }
175 } else if (fromFileName) {
176 def = repo.definitionForFileName(fileName: inFileName);
177 } else {
178 parser.showHelp(exitCode: 1);
179 }
180
181 if (!def.isValid()) {
182 std::cerr << "Unknown syntax." << std::endl;
183 return 1;
184 }
185
186 const QString outputFormat = parser.value(option: outputFormatOption);
187 if (0 == outputFormat.compare(other: QLatin1String("html"), cs: Qt::CaseInsensitive)) {
188 QString title;
189 if (parser.isSet(option: titleOption)) {
190 title = parser.value(option: titleOption);
191 }
192
193 HtmlHighlighter highlighter;
194 highlighter.setDefinition(def);
195 highlighter.setTheme(theme(repo, themeName: parser.value(option: themeName), t: Repository::LightTheme));
196 applyHighlighter(highlighter, parser, fromFileName, inFileName, outputName, highlightParams: title);
197 } else {
198 auto AnsiFormat = AnsiHighlighter::AnsiFormat::TrueColor;
199 if (0 == outputFormat.compare(other: QLatin1String("ansi256Colors"), cs: Qt::CaseInsensitive)) {
200 AnsiFormat = AnsiHighlighter::AnsiFormat::XTerm256Color;
201 } else if (0 != outputFormat.compare(other: QLatin1String("ansi"), cs: Qt::CaseInsensitive)) {
202 std::cerr << "Unknown output format." << std::endl;
203 return 2;
204 }
205
206 AnsiHighlighter::Options options{};
207 options |= parser.isSet(option: noAnsiEditorBg) ? AnsiHighlighter::Option::NoOptions : AnsiHighlighter::Option::UseEditorBackground;
208 options |= parser.isSet(option: unbufferedAnsi) ? AnsiHighlighter::Option::Unbuffered : AnsiHighlighter::Option::NoOptions;
209 if (parser.isSet(option: traceOption)) {
210 const auto traceOptions = parser.values(option: traceOption);
211 for (auto const &option : traceOptions) {
212 if (option == QStringLiteral("format")) {
213 options |= AnsiHighlighter::Option::TraceFormat;
214 } else if (option == QStringLiteral("region")) {
215 options |= AnsiHighlighter::Option::TraceRegion;
216 } else if (option == QStringLiteral("context")) {
217 options |= AnsiHighlighter::Option::TraceContext;
218 } else if (option == QStringLiteral("stackSize")) {
219 options |= AnsiHighlighter::Option::TraceStackSize;
220 } else if (option == QStringLiteral("all")) {
221 options |= AnsiHighlighter::Option::TraceAll;
222 } else {
223 std::cerr << "Unknown trace name." << std::endl;
224 return 2;
225 }
226 }
227 }
228
229 AnsiHighlighter highlighter;
230 highlighter.setDefinition(def);
231 highlighter.setTheme(theme(repo, themeName: parser.value(option: themeName), t: Repository::DarkTheme));
232 applyHighlighter(highlighter, parser, fromFileName, inFileName, outputName, highlightParams: AnsiFormat, highlightParams: options);
233 }
234
235 return 0;
236}
237

source code of syntax-highlighting/src/cli/ksyntaxhighlighter.cpp