70 lines
2.1 KiB
C++
70 lines
2.1 KiB
C++
#pragma once
|
|
|
|
#include <QObject>
|
|
#include <QString>
|
|
#include <QVariantList>
|
|
#include <QtQml>
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
class QQmlEngine;
|
|
class QJSEngine;
|
|
|
|
namespace ZShell::llm {
|
|
|
|
// Syntax highlighting for LLM code blocks via tree-sitter.
|
|
//
|
|
// The tree-sitter runtime is linked. Grammar libraries
|
|
// (libtree-sitter-<lang>.so) are dlopen()'d lazily, so a missing
|
|
// grammar package degrades that language to plain text instead of
|
|
// breaking the build or the app. Highlight queries are embedded at
|
|
// build time (highlight-queries/*.scm, vendored from the grammar
|
|
// repos, MIT).
|
|
//
|
|
// The fence language the LLM wrote (```cpp, ```python, ...) is mapped
|
|
// to a grammar through an alias table.
|
|
//
|
|
// highlight() returns a list of span maps:
|
|
// { "start": int, "length": int, "kind": QString }
|
|
// where kind is a semantic role (keyword, string, comment, number,
|
|
// function, type, ...) that QML maps to theme colors. An empty list
|
|
// means "no highlighting" (unknown language or grammar not installed).
|
|
class CodeHighlighter : public QObject {
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
QML_SINGLETON
|
|
|
|
public:
|
|
Q_INVOKABLE QVariantList highlight(const QString& code, const QString& language) const;
|
|
|
|
static CodeHighlighter* create(QQmlEngine*, QJSEngine*);
|
|
|
|
struct Grammar {
|
|
QString lib; // soname to dlopen
|
|
QString symbol; // tree_sitter_<lang>() entry point
|
|
// Candidate query sources, first wins. Lets typescript reuse
|
|
// the javascript query when it compiles against the grammar.
|
|
std::vector<int> queries; // indices into querySources()
|
|
};
|
|
|
|
private:
|
|
struct State {
|
|
bool bad = false; // permanent failure, do not retry
|
|
void* lib = nullptr;
|
|
const void* lang = nullptr; // const TSLanguage*
|
|
void* query = nullptr; // TSQuery*
|
|
};
|
|
|
|
[[nodiscard]] static const QHash<QString, QString>& aliases();
|
|
[[nodiscard]] const std::vector<std::string>& querySources() const;
|
|
// Maps a tree-sitter capture name to a role index (0 = unstyled).
|
|
[[nodiscard]] static uint8_t roleFor(const char* name, uint32_t length);
|
|
[[nodiscard]] static const char* roleName(uint8_t role);
|
|
|
|
mutable QHash<QString, State> m_states;
|
|
static CodeHighlighter* s_instance;
|
|
};
|
|
|
|
} // namespace ZShell::llm
|