-% commet
-
-text \texttt{more text}
-
-\verb!verbatim text! normal text
-
diff --git a/autotests/input/highlight.tex b/autotests/input/highlight.tex
index 34c0890..fc0a365 100644
--- a/autotests/input/highlight.tex
+++ b/autotests/input/highlight.tex
@@ -1,85 +1,262 @@
% LaTeX test file for kate's syntax highlighting and code folding
\ordinaryLaTeXcommandwithoption[10pt,a4paper]{article}
% BEGIN region
%comment, this is all ok % $
\%no comments please
\\%comment
% END of region
\newcommand{\nohighlighting}
\section{normal}
\ref{blue}
\pageref{blue}
\cite{blue}
\begin{environmentshavespecialcolors}
normal
\end{environmentshavespecialcolors}
$equations are green, \commands somewhat darker$
normal
$$equations are green, \commands somewhat darker$$
normal
\(
\frac{1}{2}
\begin{test}
\end{test}
\)
normal
\[
%comment
displaymath
\]
normal
\begin{equation}
green\darkergreen
\begin{test}
\test
\end{test}
\end{equation}
\begin{equation*}
green\darkergreen
%comment
\begin{test}
\test
\end{test}
\%no comment
\end{equation*}
\{ %this should be comment
\verb%this shouldn't be%and this should be normal text
+\verb!verbatim text! normal text
+
+text \texttt{more text}
\begin{verbatim}
text inside a verbatim environment is also treated special $ %,
you can even put a \begin{verbatim} inside
\end{verbatim}
normal
\begin{Verbatim}
&@@#^%&^#$
\end{Verbatim}
\begin{Verbatim*}
@*&^#@*(^#(*@&
\end{Verbatim*}
normal
+\begin{Verbatim}
+\begin{verbatim}
+This is a verbatim block.
+\end{verbatim}
+\end{Verbatim}
+
+normal
+
% test alignat
\begin{alignat}{2}
A &= B &= C \\
A &= B &= C
\end{alignat}
normal text
\iffalse
\fill commented out text
\fi
+% Math mode
+
+Depending on the value of $x$ the equation \( f(x) = \sum_{i=0}^{n} \frac{a_i}{1+x} \) may diverge or converge.
+
+\[ f(x) = \sum_{i=0}^{n} \frac{a_i}{1+x} \]
+
+\[
+S = \{ z \in \mathbb{C}\, |\, |z| < 1 \} \quad \textrm{and} \quad S_2=\partial{S}
+\]
+
+\[
+\frac{
+ \begin{array}[b]{r}
+ \left( x_1 x_2 \right)\\
+ \times \left( x'_1 x'_2 \right)
+ \end{array}
+ }{
+ \left( y_1y_2y_3y_4 \right)
+ }
+\]
+
+\begin{eqnarray*}
+\begin{eqnarray*}
+f(x) = \sum_{i=0}^{n} \frac{a_i}{1+x} \\
+\textstyle f(x) = \textstyle \sum_{i=0}^{n} \frac{a_i}{1+x} \\
+\scriptstyle f(x) = \scriptstyle \sum_{i=0}^{n} \frac{a_i}{1+x} \\
+\scriptscriptstyle f(x) = \scriptscriptstyle \sum_{i=0}^{n} \frac{a_i}{1+x}
+\end{eqnarray*}
+\end{eqnarray*}
+
+\begin{xalignat}{3}
+i_{11} & =i_{23}\nonumber
+\end{xalignat}
+
+c
+\begin{equation}
+c
+\begin{aligned}
+a & b\\
+c & d
+\end{aligned}
+c
+\end{equation}
+c
+
+$$E=mc^2$$
+
+\begin{equation}
+E=m
+\end{equation}
+
+\begin{equation
+x=3\textrm{plop}
+\end{equation}
+
+\[ \begin{array}{llll}
+ x^3 = (-x)^3 & \text{if $x > 0$}\\
+ x^3 = (-x)^3 & \text{if {$x > 0$}}\\
+ x^3 = (-x)^3 & \text{if {\color{green} $x > 0$}}\\
+\end{array} \]
+
+\section*{Notes for My Paper}
+
+\begin{center}
+\begin{tabular}{ |c|c|c| }
+ \hline
+ cell1 & cell2 & cell3 \\
+ cell4 & cell5 & cell6 \\
+ cell7 & cell8 & cell9 \\
+ \hline
+\end{tabular}
+
+\begin{tabular*}{0.75\textwidth}{@{\extracolsep{\fill} } | c | c | c | r | }
+ \hline
+ label 1 & label 2 & label 3 & label 4 \\
+ \hline
+ item 1 & item 2 & item 3 & item 4 \\
+ \hline
+\end{tabular*}
+
+\begin{tabular*}{0.75\textwidth}{ | c | c | c | r | }
+ \hline
+ label 1 & label 2 & label 3 & label 4 \\
+ \hline
+ item 1 & item 2 & item 3 & item 4 \\
+ \hline
+\end{tabular*}
+\end{center}
+
+
+\begin{tabularx}{1\textwidth}{ |>{\setlength\hsize{1\hsize}\centering}X|>{\setlength\hsize{1\hsize}\raggedleft}X@{} >{\setlength\hsize{1\hsize}\raggedright}X|>{\setlength\hsize{1\hsize}\centering}X| }
+ \hline
+Label 1 & \multicolumn{2}{>{\centering\setlength\hsize{2\hsize} }X|}{Label 2} & Label 3\tabularnewline
+\hline
+ 123 & 123 & 456 & 123 \tabularnewline
+ \hline
+ 123 & 123 & 456 & 123 \tabularnewline
+ \hline
+\end{tabularx}
+
+\begin{lstlisting}
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}%[frame=single]
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}[frame=single]
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}[frame=single] % blah blah
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}
+[frame=single] % blah blah
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{minted}{python}
+def foo(x):
+ return x
+\end{minted}
+
+\begin{minted}
+% blah blah
+{python}
+def foo(x):
+ return x
+\end{minted}
+
+\begin{minted}[frame=lines]{python}
+def foo(x):
+ return x
+\end{minted}
+
+\begin{minted}
+% plop
+[frame=lines,
+fontsize=\footnotesize
+]
+% ok
+{python}
+def foo(x):
+ return x
+\end{minted}
+
+\begin{comment}
+This is a comment block.
+\end{comment}
+
+\documentclass{article}
+\usepackage{fancyvrb}
+
+\documentclass[12pt]{article}
+\begin{document}
+
+Text that has a footnote\footnote{This $i_s$ the \[i_s\] $$x_i$$ \(x_i\)footnote}\addtocounter{footnote}{-1}\addtocounter{footnote}{-1} looks like this. Later text referring to same footnote\footnotemark uses the other command.
+\end{document}
diff --git a/autotests/input/test.tex b/autotests/input/test.tex
deleted file mode 100644
index 8da60c9..0000000
--- a/autotests/input/test.tex
+++ /dev/null
@@ -1,5 +0,0 @@
-% commet
-
-text \texttt{more text}
-
-\verb!verbatim text! normal text
diff --git a/autotests/reference/highlight.tex.ref b/autotests/reference/highlight.tex.ref
index bcd6926..f6a02ab 100644
--- a/autotests/reference/highlight.tex.ref
+++ b/autotests/reference/highlight.tex.ref
@@ -1,85 +1,262 @@
% LaTeX test file for kate's syntax highlighting and code folding \ordinaryLaTeXcommandwithoption[10pt,a4paper]{article} % BEGIN region %comment, this is all ok % $ \%no comments please \\%comment % END of region
-\newcommand{\nohighlighting}
+\newcommand{\nohighlighting} \section{normal}
-\ref{blue}
-\pageref{blue}
-\cite{blue}
+\ref{blue}
+\pageref{blue}
+\cite{blue} \begin{environmentshavespecialcolors} normal \end{environmentshavespecialcolors} \commands normal \commands normal
\frac
-\begin
-\end
+\begin{test}
+\end{test}
normal
%comment
normal \begin{equation} \darkergreen \begin{test} \test
-\end{
+\end{test} \end{equation} \begin{equation*} \darkergreen %comment \begin{test} \test
-\end{
+\end{test} \% \end{equation*} \{%this should be comment \verb%this shouldn't be%and this should be normal text
+\verb!verbatim text! normal text
+
+text \texttt{more text} \begin{verbatim} text inside a verbatim environment is also treated special $ %, you can even put a \begin{verbatim} inside \end{verbatim} normal \begin{Verbatim} &@@#^%&^#$ \end{Verbatim}
-\begin{Verbatim*}
+\begin{Verbatim*} @*&^#@*(^#(*@& \end{Verbatim*} normal
+\begin{Verbatim}
+\begin{verbatim}
+This is a verbatim block.
+\end{verbatim}
+\end{Verbatim}
+
+normal
+ % test alignat \begin{alignat}{2} \\
\end{alignat} normal text \iffalse \fill commented out text \fi
+% Math mode
+
+Depending on the value of the equation \sum\frac may diverge or converge.
+
+\sum\frac
+
+
+\{\in\mathbb\,\,\}\quad\textrm{and}\quad\partial
+
+
+
+\frac
+\begin{array}
+\left\right\\
+\times\left\right
+\end{array}
+
+\left\right
+
+
+
+\begin{eqnarray*}
+\begin{eqnarray*}
+\sum\frac\\
+\textstyle\textstyle\sum\frac\\
+\scriptstyle\scriptstyle\sum\frac\\
+\scriptscriptstyle\scriptscriptstyle\sum\frac
+\end{eqnarray*}
+\end{eqnarray*}
+
+\begin{xalignat}{3}
+\nonumber
+\end{xalignat}
+
+c
+\begin{equation}
+
+\begin{aligned}
+\\
+
+\end{aligned}
+
+\end{equation}
+c
+
+
+
+\begin{equation}
+
+\end{equation}
+
+\begin{equation
+x=3\textrm{plop}
+\end{equation}
+
+\begin{array}
+\text{if }\\
+\text{if {}}\\
+\text{if {\color{green} }}\\
+\end{array}
+
+\section*{Notes for My Paper}
+
+\begin{center}
+\begin{tabular}{ |c|c|c| }
+\hline
+ cell1 & cell2 & cell3 \\
+ cell4 & cell5 & cell6 \\
+ cell7 & cell8 & cell9 \\
+\hline
+\end{tabular}
+
+\begin{tabular*}{0.75\textwidth}{@{\extracolsep{\fill} } | c | c | c | r | }
+\hline
+ label 1 & label 2 & label 3 & label 4 \\
+\hline
+ item 1 & item 2 & item 3 & item 4 \\
+\hline
+\end{tabular*}
+
+\begin{tabular*}{0.75\textwidth}{ | c | c | c | r | }
+\hline
+ label 1 & label 2 & label 3 & label 4 \\
+\hline
+ item 1 & item 2 & item 3 & item 4 \\
+\hline
+\end{tabular*}
+\end{center}
+
+
+\begin{tabularx}{1\textwidth}{ |>{\setlength\hsize{1\hsize}\centering}X|>{\setlength\hsize{1\hsize}\raggedleft}X@{} >{\setlength\hsize{1\hsize}\raggedright}X|>{\setlength\hsize{1\hsize}\centering}X| }
+\hline
+Label 1 &\multicolumn{2}{>{\centering\setlength\hsize{2\hsize} }X|}{Label 2} & Label 3\tabularnewline
+\hline
+ 123 & 123 & 456 & 123 \tabularnewline
+\hline
+ 123 & 123 & 456 & 123 \tabularnewline
+\hline
+\end{tabularx}
+
+\begin{lstlisting}
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}%[frame=single]
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}[frame=single]
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}[frame=single] % blah blah
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{lstlisting}
+[frame=single] % blah blah
+Write('Case insensitive ');
+Write('Pascal keywords.');
+\end{lstlisting}
+
+\begin{minted}{python}
+deffoo(x):
+return x
+\end{minted}
+
+\begin{minted}
+% blah blah
+{python}
+deffoo(x):
+return x
+\end{minted}
+
+\begin{minted}[frame=lines]{python}
+deffoo(x):
+return x
+\end{minted}
+
+\begin{minted}
+% plop
+[frame=lines,
+fontsize=\footnotesize
+]
+% ok
+{python}
+deffoo(x):
+return x
+\end{minted}
+
+\begin{comment}
+This is a comment block.
+\end{comment}
+
+\documentclass{article}
+\usepackage{fancyvrb}
+
+\documentclass[]{article}
+\begin{document}
+
+Text that has a footnote\footnote{This the footnote}\addtocounter{footnote}{-1}\addtocounter{footnote}{-1} looks like this. Later text referring to same footnote\footnotemark uses the other command.
+\end{document}
diff --git a/autotests/reference/test.tex.ref b/autotests/reference/test.tex.ref
deleted file mode 100644
index 3f24c2a..0000000
--- a/autotests/reference/test.tex.ref
+++ /dev/null
@@ -1,5 +0,0 @@
-% commet
-
-text \texttt{more text}
-
-\verb!verbatim text! normal text
diff --git a/autotests/syntaxrepository_test.cpp b/autotests/syntaxrepository_test.cpp
index 9c7cc5a..1915941 100644
--- a/autotests/syntaxrepository_test.cpp
+++ b/autotests/syntaxrepository_test.cpp
@@ -1,558 +1,558 @@
/*
Copyright (C) 2016 Volker Krause
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "test-config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace KSyntaxHighlighting {
class NullHighlighter : public AbstractHighlighter
{
public:
using AbstractHighlighter::highlightLine;
void applyFormat(int offset, int length, const Format &format) Q_DECL_OVERRIDE
{
Q_UNUSED(offset);
Q_UNUSED(length);
// only here to ensure we don't crash
format.isDefaultTextStyle(theme());
format.textColor(theme());
}
};
class RepositoryTest : public QObject
{
Q_OBJECT
private:
Repository m_repo;
private Q_SLOTS:
void initTestCase()
{
QStandardPaths::setTestModeEnabled(true);
initRepositorySearchPaths(m_repo);
}
void testDefinitionByExtension_data()
{
QTest::addColumn("fileName");
QTest::addColumn("defName");
QTest::newRow("empty") << QString() << QString();
QTest::newRow("qml") << QStringLiteral("/bla/foo.qml") << QStringLiteral("QML");
QTest::newRow("glsl") << QStringLiteral("flat.frag") << QStringLiteral("GLSL");
// the following ones are defined in multiple syntax definitions
QTest::newRow("c") << QStringLiteral("test.c") << QStringLiteral("C");
QTest::newRow("c++") << QStringLiteral("test.cpp") << QStringLiteral("C++");
QTest::newRow("markdown") << QStringLiteral("test.md") << QStringLiteral("Markdown");
QTest::newRow("Makefile 1") << QStringLiteral("Makefile") << QStringLiteral("Makefile");
QTest::newRow("Makefile 2") << QStringLiteral("/some/path/to/Makefile") << QStringLiteral("Makefile");
QTest::newRow("Makefile 3") << QStringLiteral("Makefile.am") << QStringLiteral("Makefile");
}
void testDefinitionByExtension()
{
QFETCH(QString, fileName);
QFETCH(QString, defName);
auto def = m_repo.definitionForFileName(fileName);
if (defName.isEmpty()) {
QVERIFY(!def.isValid());
} else {
QVERIFY(def.isValid());
QCOMPARE(def.name(), defName);
}
}
void testDefinitionsForFileName_data()
{
QTest::addColumn("fileName");
QTest::addColumn("expectedNames");
QTest::newRow("Matlab") << QStringLiteral("/bla/foo.m")
<< (QStringList() << QStringLiteral("Magma") << QStringLiteral("Matlab") << QStringLiteral("Octave") << QStringLiteral("Objective-C"));
}
void testDefinitionsForFileName()
{
QFETCH(QString, fileName);
QFETCH(QStringList, expectedNames);
const auto defs = m_repo.definitionsForFileName(fileName);
QStringList names;
for (auto def : defs) {
names.push_back(def.name());
}
QCOMPARE(names, expectedNames);
}
void testDefinitionsForMimeType_data()
{
QTest::addColumn("mimeType");
QTest::addColumn("expectedNames");
QTest::newRow("C Header") << QStringLiteral("text/x-chdr")
<< (QStringList() << QStringLiteral("C++")
<< QStringLiteral("ISO C++")
<< QStringLiteral("C")
<< QStringLiteral("GCCExtensions")
<< QStringLiteral("ANSI C89")
<< QStringLiteral("SystemC"));
}
void testDefinitionsForMimeType()
{
QFETCH(QString, mimeType);
QFETCH(QStringList, expectedNames);
const auto defs = m_repo.definitionsForMimeType(mimeType);
QStringList names;
for (auto def : defs) {
names.push_back(def.name());
}
QCOMPARE(names, expectedNames);
}
void testLoadAll()
{
for (const auto &def : m_repo.definitions()) {
QVERIFY(!def.name().isEmpty());
QVERIFY(!def.translatedName().isEmpty());
QVERIFY(!def.isValid() || !def.section().isEmpty());
QVERIFY(!def.isValid() || !def.translatedSection().isEmpty());
// indirectly trigger loading, as we can't reach that from public API
// if the loading fails the highlighter will produce empty states
NullHighlighter hl;
State initialState;
hl.setDefinition(def);
const auto state = hl.highlightLine(QLatin1String("This should not crash } ] ) !"), initialState);
QVERIFY(!def.isValid() || state != initialState || def.name() == QLatin1String("Broken Syntax"));
}
}
void testMetaData()
{
auto def = m_repo.definitionForName(QLatin1String("Alerts"));
QVERIFY(def.isValid());
QVERIFY(def.extensions().isEmpty());
QVERIFY(def.mimeTypes().isEmpty());
QVERIFY(def.version() >= 1.11f);
QVERIFY(def.isHidden());
QCOMPARE(def.section(), QLatin1String("Other"));
QCOMPARE(def.license(), QLatin1String("MIT"));
QVERIFY(def.author().contains(QLatin1String("Dominik")));
QFileInfo fi(def.filePath());
QVERIFY(fi.isAbsolute());
QVERIFY(def.filePath().endsWith(QLatin1String("alert.xml")));
def = m_repo.definitionForName(QLatin1String("C++"));
QVERIFY(def.isValid());
QCOMPARE(def.section(), QLatin1String("Sources"));
QCOMPARE(def.indenter(), QLatin1String("cstyle"));
QCOMPARE(def.style(), QLatin1String("C++"));
QVERIFY(def.mimeTypes().contains(QLatin1String("text/x-c++hdr")));
QVERIFY(def.extensions().contains(QLatin1String("*.h")));
QCOMPARE(def.priority(), 9);
def = m_repo.definitionForName(QLatin1String("Apache Configuration"));
QVERIFY(def.isValid());
QVERIFY(def.extensions().contains(QLatin1String("httpd.conf")));
QVERIFY(def.extensions().contains(QLatin1String(".htaccess*")));
}
void testGeneralMetaData()
{
auto def = m_repo.definitionForName(QLatin1String("C++"));
QVERIFY(def.isValid());
QVERIFY(!def.indentationBasedFoldingEnabled());
// comment markers
QCOMPARE(def.singleLineCommentMarker(), QLatin1String("//"));
QCOMPARE(def.singleLineCommentPosition(), KSyntaxHighlighting::CommentPosition::StartOfLine);
const auto cppMultiLineCommentMarker = QPair(QLatin1String("/*"), QLatin1String("*/"));
QCOMPARE(def.multiLineCommentMarker(), cppMultiLineCommentMarker);
def = m_repo.definitionForName(QLatin1String("Python"));
QVERIFY(def.isValid());
// indentation
QVERIFY(def.indentationBasedFoldingEnabled());
QCOMPARE(def.foldingIgnoreList(), QStringList() << QLatin1String("(?:\\s+|\\s*#.*)"));
// keyword lists
QVERIFY(!def.keywordLists().isEmpty());
QVERIFY(def.keywordList(QLatin1String("operators")).contains(QLatin1String("and")));
QVERIFY(!def.keywordList(QLatin1String("does not exits")).contains(QLatin1String("and")));
}
void testFormatData()
{
auto def = m_repo.definitionForName(QLatin1String("ChangeLog"));
QVERIFY(def.isValid());
auto formats = def.formats();
QVERIFY(!formats.isEmpty());
// verify that the formats are sorted, such that the order matches the order of the itemDatas in the xml files.
auto sortComparator = [](const KSyntaxHighlighting::Format & lhs, const KSyntaxHighlighting::Format & rhs) {
return lhs.id() < rhs.id();
};
QVERIFY(std::is_sorted(formats.begin(), formats.end(), sortComparator));
// check all names are listed
QStringList formatNames;
for (const auto & format : qAsConst(formats)) {
formatNames.append(format.name());
}
const QStringList expectedItemDatas = {
QStringLiteral("Normal Text"),
QStringLiteral("Name"),
QStringLiteral("E-Mail"),
QStringLiteral("Date"),
QStringLiteral("Entry")
};
QCOMPARE(formatNames, expectedItemDatas);
}
void testIncludedDefinitions()
{
auto def = m_repo.definitionForName(QLatin1String("PHP (HTML)"));
QVERIFY(def.isValid());
auto defs = def.includedDefinitions();
const QStringList expectedDefinitionNames = {
QStringLiteral("PHP/PHP"),
QStringLiteral("Alerts"),
QStringLiteral("CSS/PHP"),
QStringLiteral("JavaScript/PHP"),
QStringLiteral("Doxygen"),
QStringLiteral("JavaScript React/PHP"),
QStringLiteral("TypeScript/PHP"),
QStringLiteral("Mustache/Handlebars (HTML)/PHP"),
QStringLiteral("Modelines"),
QStringLiteral("HTML"),
QStringLiteral("CSS"),
QStringLiteral("SQL (MySQL)"),
QStringLiteral("JavaScript"),
QStringLiteral("JavaScript React"),
QStringLiteral("TypeScript"),
QStringLiteral("Mustache/Handlebars (HTML)")
};
QStringList definitionNames;
for (auto d : defs) {
QVERIFY(d.isValid());
definitionNames.push_back(d.name());
// already check here a bit to make the test fails better fixable
if (definitionNames.size() <= expectedDefinitionNames.size()) {
QCOMPARE(d.name(), expectedDefinitionNames[definitionNames.size()-1]);
} else {
QCOMPARE(d.name(), QStringLiteral("too many included defs found, first one is this one"));
}
}
QCOMPARE(definitionNames, expectedDefinitionNames);
}
void testIncludedFormats()
{
QStringList definitionNames;
for (const auto &def : m_repo.definitions()) {
definitionNames.push_back(def.name());
}
for (const QString & name : qAsConst(definitionNames)) {
Repository repo;
initRepositorySearchPaths(repo);
auto def = repo.definitionForName(name);
QCOMPARE(m_repo.definitionForName(name).isValid(), def.isValid());
auto includedDefs = def.includedDefinitions();
includedDefs.push_front(def);
// collect all formats, shall be numbered from 1..
QSet formatIds;
for (auto d : qAsConst(includedDefs)) {
const auto formats = d.formats();
for (const auto format : formats) {
// no duplicates
QVERIFY(!formatIds.contains(format.id()));
formatIds.insert(format.id());
}
}
QVERIFY(!def.isValid() || def.name() == QLatin1String("Broken Syntax") || !formatIds.isEmpty());
// ensure all ids are there from 1..size
for (int i = 1; i <= formatIds.size(); ++i) {
QVERIFY(formatIds.contains(i));
}
}
}
void testReload()
{
auto def = m_repo.definitionForName(QLatin1String("QML"));
QVERIFY(!m_repo.definitions().isEmpty());
QVERIFY(def.isValid());
NullHighlighter hl;
hl.setDefinition(def);
auto oldState = hl.highlightLine(QLatin1String("/* TODO this should not crash */"), State());
m_repo.reload();
QVERIFY(!m_repo.definitions().isEmpty());
QVERIFY(!def.isValid());
hl.highlightLine(QLatin1String("/* TODO this should not crash */"), State());
hl.highlightLine(QLatin1String("/* FIXME neither should this crash */"), oldState);
QVERIFY(hl.definition().isValid());
QCOMPARE(hl.definition().name(), QLatin1String("QML"));
}
void testLifetime()
{
// common mistake with value-type like Repo API, make sure this doesn'T crash
NullHighlighter hl;
{
Repository repo;
hl.setDefinition(repo.definitionForName(QLatin1String("C++")));
hl.setTheme(repo.defaultTheme());
}
hl.highlightLine(QLatin1String("/**! @todo this should not crash .*/"), State());
}
void testCustomPath()
{
QString testInputPath = QStringLiteral(TESTSRCDIR "/input");
Repository repo;
QVERIFY(repo.customSearchPaths().empty());
repo.addCustomSearchPath(testInputPath);
QCOMPARE(repo.customSearchPaths().size(), 1);
QCOMPARE(repo.customSearchPaths()[0], testInputPath);
auto customDefinition = repo.definitionForName(QLatin1String("Test Syntax"));
QVERIFY(customDefinition.isValid());
auto customTheme = repo.theme(QLatin1String("Test Theme"));
QVERIFY(customTheme.isValid());
}
void testInvalidDefinition()
{
Definition def;
QVERIFY(!def.isValid());
QVERIFY(def.filePath().isEmpty());
QCOMPARE(def.name(), QLatin1String("None"));
QVERIFY(def.section().isEmpty());
QVERIFY(def.translatedSection().isEmpty());
QVERIFY(def.mimeTypes().isEmpty());
QVERIFY(def.extensions().isEmpty());
QCOMPARE(def.version(), 0);
QCOMPARE(def.priority(), 0);
QVERIFY(!def.isHidden());
QVERIFY(def.style().isEmpty());
QVERIFY(def.indenter().isEmpty());
QVERIFY(def.author().isEmpty());
QVERIFY(def.license().isEmpty());
QVERIFY(!def.foldingEnabled());
QVERIFY(!def.indentationBasedFoldingEnabled());
QVERIFY(def.foldingIgnoreList().isEmpty());
QVERIFY(def.keywordLists().isEmpty());
QVERIFY(def.formats().isEmpty());
QVERIFY(def.includedDefinitions().isEmpty());
QVERIFY(def.singleLineCommentMarker().isEmpty());
QCOMPARE(def.singleLineCommentPosition(), KSyntaxHighlighting::CommentPosition::StartOfLine);
const auto emptyPair = QPair();
QCOMPARE(def.multiLineCommentMarker(), emptyPair);
QVERIFY(def.characterEncodings().isEmpty());
for (QChar c : QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~")) {
QVERIFY(def.isWordDelimiter(c));
QVERIFY(def.isWordWrapDelimiter(c));
}
}
void testDelimiters()
{
auto def = m_repo.definitionForName(QLatin1String("LaTeX"));
QVERIFY(def.isValid());
- // check that backslash '\' is removed
- for (QChar c : QStringLiteral("\t !%&()*+,-./:;<=>?[]^{|}~"))
+ // check that backslash '\' and '*' are removed
+ for (QChar c : QStringLiteral("\t !%&()+,-./:;<=>?[]^{|}~"))
QVERIFY(def.isWordDelimiter(c));
QVERIFY(!def.isWordDelimiter(QLatin1Char('\\')));
// check where breaking a line is valid
for (QChar c : QStringLiteral(",{}[]"))
QVERIFY(def.isWordWrapDelimiter(c));
}
void testFoldingEnabled()
{
// test invalid folding
Definition def;
QVERIFY(!def.isValid());
QVERIFY(!def.foldingEnabled());
QVERIFY(!def.indentationBasedFoldingEnabled());
// test no folding
def = m_repo.definitionForName(QLatin1String("ChangeLog"));
QVERIFY(def.isValid());
QVERIFY(!def.foldingEnabled());
QVERIFY(!def.indentationBasedFoldingEnabled());
// C++ itself has no regions, but it includes ISO C++
def = m_repo.definitionForName(QLatin1String("C++"));
QVERIFY(def.isValid());
QVERIFY(def.foldingEnabled());
QVERIFY(!def.indentationBasedFoldingEnabled());
// ISO C++ itself has folding regions
def = m_repo.definitionForName(QLatin1String("ISO C++"));
QVERIFY(def.isValid());
QVERIFY(def.foldingEnabled());
QVERIFY(!def.indentationBasedFoldingEnabled());
// Python has indentation based folding
def = m_repo.definitionForName(QLatin1String("Python"));
QVERIFY(def.isValid());
QVERIFY(def.foldingEnabled());
QVERIFY(def.indentationBasedFoldingEnabled());
}
void testCharacterEncodings()
{
auto def = m_repo.definitionForName(QLatin1String("LaTeX"));
QVERIFY(def.isValid());
const auto encodings = def.characterEncodings();
QVERIFY(!encodings.isEmpty());
QVERIFY(encodings.contains({ QChar(196), QLatin1String("\\\"{A}") }));
QVERIFY(encodings.contains({ QChar(227), QLatin1String("\\~{a}") }));
}
void testIncludeKeywordLists()
{
Repository repo;
QTemporaryDir dir;
// forge a syntax file
{
QVERIFY(QDir(dir.path()).mkpath(QLatin1String("syntax")));
const char syntax[] = R"xml(
cabacbde##AAAeff
)xml";
QFile file(dir.path() + QLatin1String("/syntax/a.xml"));
QVERIFY(file.open(QIODevice::WriteOnly));
QTextStream stream(&file);
stream << syntax;
}
repo.addCustomSearchPath(dir.path());
auto def = repo.definitionForName(QLatin1String("AAA"));
QCOMPARE(def.name(), QLatin1String("AAA"));
auto klist1 = def.keywordList(QLatin1String("a"));
auto klist2 = def.keywordList(QLatin1String("b"));
auto klist3 = def.keywordList(QLatin1String("c"));
// internal QHash is arbitrarily ordered and undeterministic
auto& klist = klist1.size() == 3 ? klist1
: klist2.size() == 3 ? klist2
: klist3;
QCOMPARE(klist.size(), 3);
QVERIFY(klist.contains(QLatin1String("a")));
QVERIFY(klist.contains(QLatin1String("b")));
QVERIFY(klist.contains(QLatin1String("c")));
klist = def.keywordList(QLatin1String("d"));
QCOMPARE(klist.size(), 3);
QVERIFY(klist.contains(QLatin1String("d")));
QVERIFY(klist.contains(QLatin1String("e")));
QVERIFY(klist.contains(QLatin1String("f")));
klist = def.keywordList(QLatin1String("e"));
QCOMPARE(klist.size(), 2);
QVERIFY(klist.contains(QLatin1String("e")));
QVERIFY(klist.contains(QLatin1String("f")));
klist = def.keywordList(QLatin1String("f"));
QCOMPARE(klist.size(), 1);
QVERIFY(klist.contains(QLatin1String("f")));
}
};
}
QTEST_GUILESS_MAIN(KSyntaxHighlighting::RepositoryTest)
#include "syntaxrepository_test.moc"
diff --git a/data/syntax/latex.xml b/data/syntax/latex.xml
index 9583e55..df05bf3 100644
--- a/data/syntax/latex.xml
+++ b/data/syntax/latex.xml
@@ -1,697 +1,1107 @@
-
-
+
+
+]>
+
+
+ \begin
+
+
+
+ \end
+
+
+
+ \Autocite
+ \autocite
+ \autoref
+ \Cite
+ \cite
+ \Citeauthor
+ \citeauthor
+ \citep
+ \citet
+ \citetitle
+ \citeurl
+ \citeyear
+ \cref
+ \Cref
+ \cref*
+ \Cref*
+ \eqref
+ \Footcite
+ \footcite
+ \footfullcite
+ \fullcite
+ \label
+ \nocite
+ \pagecite
+ \pageref
+ \Parencite
+ \parencite
+ \ref
+ \subref
+ \subref*
+ \supercite
+ \Textcite
+ \textcite
+ \vpageref
+ \vref
+
+
+
+ \documentclass
+ \includegraphics
+ \include
+ \usepackage
+ \bibliography
+ \bibliographystyle
+
+
+
+ \cites
+ \Cites
+ \parencites
+ \Parencites
+ \autocites
+ \Autocites
+ \supercites
+ \footcites
+ \Footcites
+
+
+
+ \part*
+ \part
+ \chapter*
+ \chapter
+ \section*
+ \section
+ \subsection*
+ \subsection
+ \subsubsection*
+ \subsubsection
+ \paragraph*
+ \paragraph
+ \subparagraph*
+ \subparagraph
+
+
+
+ \column
+ \definecolor
+ \geometry
+ \hspace*
+ \hspace
+ \input
+ \newboolean
+ \rule
+ \setboolean
+ \setcounter
+ \setlength
+ \special
+ \textcolor
+ \vspace*
+ \vspace
+
+
+
+ \footnote*
+ \footnote
+
+
+
+ \renewcommand*
+ \renewcommand
+ \providecommand*
+ \providecommand
+ \newcommand*
+ \newcommand
+
+
+
+ \edef
+ \gdef
+ \xdef
+
+
+
+ \ensuremath
+
+
+
+ \iffalse
+
+
+
+ \fi
+ \else
+
+
+
+ verb*
+ verb
+ Verb
+
+
+
+ lstinline
+
+
+
+ mint
+
+
+
+ lstlisting*
+ lstlisting
+
+
+
+ minted*
+ minted
+
+
+
+ Verbatim*
+ Verbatim
+ BVerbatim*
+ BVerbatim
+ LVerbatim*
+ LVerbatim
+ verbatim*
+ verbatim
+ boxedverbatim*
+ boxedverbatim
+
+
+
+ comment*
+ comment
+
+
+
+ alignat*
+ alignat
+ xalignat*
+ xalignat
+ xxalignat*
+ xxalignat
+
+
+
+ Bmatrix*
+ Bmatrix
+ IEEEeqnarray*
+ IEEEeqnarray
+ IEEEeqnarraybox*
+ IEEEeqnarraybox
+ Vmatrix*
+ Vmatrix
+ align*
+ align
+ bmatrix*
+ bmatrix
+ cases*
+ cases
+ displaymath*
+ displaymath
+ eqnarray*
+ eqnarray
+ equation*
+ equation
+ flalign*
+ flalign
+ gather*
+ gather
+ math*
+ math
+ multline*
+ multline
+ pmatrix*
+ pmatrix
+ smallmatrix*
+ smallmatrix
+ subeqnarray*
+ subeqnarray
+ vmatrix*
+ vmatrix
+
+
+
+ tabularx*
+ tabularx
+ tabular*
+ tabular
+ supertabular*
+ supertabular
+ mpsupertabular*
+ mpsupertabular
+ xtabular*
+ xtabular
+ mpxtabular*
+ mpxtabular
+ longtable*
+ longtable
+
+
+
+ \text
+ \textit
+ \textbf
+ \textmd
+ \textsl
+ \textsc
+ \textrm
+ \textsf
+ \texttt
+ \textup
+ \textlf
+ \textnormal
+ \shortintertext
+ \intertext
+ \mbox
+ \emph
+
+
+
+ \KileResetHL
+ \KateResetHL
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
-
-
+
+
-
+
-
+
-
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
-
+
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
-
+
-
-
+
+
+
+
-
+
-
+
+
-
-
-
+
+
+
-
+
+
-
+
-
-
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
+
-
+
+
-
+
-
-
+
+
-
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
+
-
+
+
-
+
-
-
+
+
-
-
-
+
+
-
+
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
-
+
+
-
-
+
+
+
-
-
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
+
+
+
-
+
+
+
+
-
-
-
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
-
+
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
-
-
-
+
+
+
+
+
-
-
+