Files
z-bar-qt/Plugins/ZShell/Llm/codehighlighter.hpp
T

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