Commit dc6b3b6a authored by Ilia Kats's avatar Ilia Kats Committed by Christoph Cullmann
Browse files

compile-time initialization of the completion table

come at the cost of run-time creation of QStrings in the data() function
parent 9ab56618
......@@ -8,6 +8,8 @@
#include "completiontable.h"
#include <cstring>
#include <QObject>
#include <QTest>
......@@ -17,8 +19,8 @@ class LatexCompletionTableTest : public QObject
private Q_SLOTS:
void testSorting()
{
for (int i = 0; i < completiontable.size() - 1; ++i) {
QVERIFY(completiontable[i].completion < completiontable[i + 1].completion);
for (int i = 0; i < n_completions - 1; ++i) {
QVERIFY(strcmp(completiontable[i].completion, completiontable[i + 1].completion) < 0);
}
}
};
......
......@@ -8,7 +8,7 @@
#include "completiontable.h"
#include <algorithm>
#include <iterator>
#include <cstring>
#include <QIcon>
#include <QRegularExpression>
......@@ -17,6 +17,13 @@
#include <KTextEditor/Document>
#include <KTextEditor/View>
bool startsWith(const Completion &comp, const std::string &prefix)
{
if (prefix.size() <= comp.completion_strlen)
return std::strncmp(prefix.data(), comp.completion, prefix.size()) == 0;
return false;
}
LatexCompletionModel::LatexCompletionModel(QObject *parent)
: KTextEditor::CodeCompletionModel(parent)
{
......@@ -29,19 +36,19 @@ void LatexCompletionModel::completionInvoked(KTextEditor::View *view,
Q_UNUSED(invocationType);
beginResetModel();
m_matches.first = m_matches.second = -1;
auto word = view->document()->text(range);
if (!word.isEmpty() && word[0] == QLatin1Char('\\')) {
auto beginit = completiontable.constBegin();
auto endit = completiontable.constEnd();
auto prefixrangestart = std::lower_bound(beginit, endit, word, [](const Completion &a, const QString &b) -> bool {
return a.completion.startsWith(b) ? false : a.completion < b;
auto word = view->document()->text(range).toStdString();
const Completion *beginit = (Completion *)&completiontable;
const Completion *endit = beginit + n_completions;
if (!word.empty() && word[0] == QLatin1Char('\\')) {
auto prefixrangestart = std::lower_bound(beginit, endit, word, [](const Completion &a, const std::string &b) -> bool {
return startsWith(a, b) ? false : a.completion < b;
});
auto prefixrangeend = std::upper_bound(beginit, endit, word, [](const QString &a, const Completion &b) -> bool {
return b.completion.startsWith(a) ? false : a < b.completion;
auto prefixrangeend = std::upper_bound(beginit, endit, word, [](const std::string &a, const Completion &b) -> bool {
return startsWith(b, a) ? false : a < b.completion;
});
if (prefixrangestart != endit) {
m_matches.first = std::distance(beginit, prefixrangestart);
m_matches.second = std::distance(beginit, prefixrangeend);
m_matches.first = prefixrangestart - beginit;
m_matches.second = prefixrangeend - beginit;
}
}
setRowCount(m_matches.second - m_matches.first);
......@@ -92,12 +99,13 @@ QVariant LatexCompletionModel::data(const QModelIndex &index, int role) const
// when determining the completion widget width. So expanding is
// the only way to make sure that the complete description is available.
else if (role == ItemSelected || role == ExpandingWidget)
return QStringLiteral("<table><tr><td>%1</td><td>%2</td></tr></table>").arg(completion.codepoint, completion.name);
return QStringLiteral("<table><tr><td>%1</td><td>%2</td></tr></table>")
.arg(QString::fromUtf8(completion.codepoint), QString::fromUtf8(completion.name));
else if (role == Qt::DisplayRole) {
if (index.column() == Name)
return completion.completion;
return QString::fromUtf8(completion.completion);
else if (index.column() == Postfix)
return completion.chars;
return QString::fromUtf8(completion.chars);
} else if (index.column() == Icon && role == Qt::DecorationRole) {
static const QIcon icon(QIcon::fromTheme(QStringLiteral("texcompiler")));
return icon;
......
......@@ -72,33 +72,38 @@ parser.table.sort(key=lambda x: x[2])
completionchars = set()
wordchars = set(list(ascii_letters) + list(digits) + ["_"])
with open(OUTFNAME, "w") as out:
out.write("""\
with open(OUTFNAME, "w", encoding="utf-8") as out:
out.write(f"""\
#include <QString>
#include <QRegularExpression>
struct Completion {
QString completion;
QString codepoint;
QString chars;
QString name;
};
struct Completion {{
const char *completion;
const char *codepoint;
const char *chars;
const char *name;
const uint16_t completion_strlen;
}};
static const QVector<Completion> completiontable({
static constexpr uint16_t n_completions = {len(parser.table)};
static constexpr Completion completiontable[] = {{
""")
for i, completion in enumerate(parser.table):
for letter in completion[2][1:]:
if letter not in wordchars:
completionchars.add(letter)
latexsymlength = len(completion[2].encode("utf-8"))
latexsym = completion[2].replace("\\", "\\\\")
if i > 0:
out.write(",")
out.write(f"{{\n QStringLiteral(\"{latexsym}\"),\n"
f" QStringLiteral(\"{completion[0]}\"),\n"
f" QStringLiteral(u\"{completion[1]}\"),\n"
f" QStringLiteral(\"{completion[3]}\")\n}}\n")
out.write(f"{{\n u8\"{latexsym}\",\n"
f" u8\"{completion[0]}\",\n"
f" u8\"{completion[1]}\",\n"
f" u8\"{completion[3]}\",\n"
f" {latexsymlength}\n}}\n")
out.write("""\
});
};
""")
have_dash = False
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment