fix syntax highlighting: use AbstractHighlighter directly
QSyntaxHighlighter applies colors to the layout only (not accessible via QTextBlock iteration). Replace with a custom AbstractHighlighter subclass (HtmlBuilder) that builds HTML directly in applyFormat(). This actually produces colored output.
This commit is contained in:
parent
9f365f49b0
commit
5c093a3bb2
|
|
@ -4,8 +4,9 @@
|
|||
#include <KSyntaxHighlighting/Repository>
|
||||
#include <KSyntaxHighlighting/Definition>
|
||||
#include <KSyntaxHighlighting/Theme>
|
||||
#include <KSyntaxHighlighting/SyntaxHighlighter>
|
||||
#include <QTextDocument>
|
||||
#include <KSyntaxHighlighting/AbstractHighlighter>
|
||||
#include <KSyntaxHighlighting/State>
|
||||
#include <KSyntaxHighlighting/Format>
|
||||
#include <QGuiApplication>
|
||||
#include <QClipboard>
|
||||
#include <QJsonDocument>
|
||||
|
|
@ -329,6 +330,37 @@ QVariantList ChatBlockModel::parseSubBlocks(const QString &content) const
|
|||
return result;
|
||||
}
|
||||
|
||||
// Custom highlighter that builds HTML string directly
|
||||
class HtmlBuilder : public KSyntaxHighlighting::AbstractHighlighter
|
||||
{
|
||||
public:
|
||||
QString html;
|
||||
|
||||
using AbstractHighlighter::AbstractHighlighter;
|
||||
|
||||
KSyntaxHighlighting::State processLine(const QString &line, const KSyntaxHighlighting::State &state)
|
||||
{
|
||||
m_currentLine = line;
|
||||
return highlightLine(line, state);
|
||||
}
|
||||
|
||||
protected:
|
||||
void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override
|
||||
{
|
||||
QString text = m_currentLine.mid(offset, length).toHtmlEscaped();
|
||||
if (format.hasTextColor(theme())) {
|
||||
QColor fg = format.textColor(theme());
|
||||
html += QStringLiteral("<span style=\"color:") + fg.name() + QStringLiteral(";\">")
|
||||
+ text + QStringLiteral("</span>");
|
||||
} else {
|
||||
html += text;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_currentLine;
|
||||
};
|
||||
|
||||
QString ChatBlockModel::highlightedHtml(const QString &code, const QString &language) const
|
||||
{
|
||||
// Check cache first
|
||||
|
|
@ -339,55 +371,33 @@ QString ChatBlockModel::highlightedHtml(const QString &code, const QString &lang
|
|||
|
||||
auto def = repo().definitionForName(language);
|
||||
if (!def.isValid()) {
|
||||
// Try by file extension
|
||||
def = repo().definitionForFileName("file." + language);
|
||||
}
|
||||
if (!def.isValid()) {
|
||||
// Return escaped plain text
|
||||
QString plain = code.toHtmlEscaped().replace('\n', "<br>");
|
||||
QString plain = code.toHtmlEscaped().replace('\n', QStringLiteral("<br>"));
|
||||
m_highlightCache.insert(cacheKey, plain);
|
||||
return plain;
|
||||
}
|
||||
|
||||
// Determine theme based on current palette
|
||||
bool dark = QGuiApplication::palette().color(QPalette::Window).lightnessF() < 0.5;
|
||||
auto theme = dark
|
||||
? repo().defaultTheme(KSyntaxHighlighting::Repository::DarkTheme)
|
||||
: repo().defaultTheme(KSyntaxHighlighting::Repository::LightTheme);
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setPlainText(code);
|
||||
HtmlBuilder builder;
|
||||
builder.setDefinition(def);
|
||||
builder.setTheme(theme);
|
||||
|
||||
auto *highlighter = new KSyntaxHighlighting::SyntaxHighlighter(&doc);
|
||||
highlighter->setDefinition(def);
|
||||
highlighter->setTheme(theme);
|
||||
highlighter->rehighlight();
|
||||
|
||||
// Extract HTML from the highlighted document
|
||||
QString html;
|
||||
QTextBlock block = doc.begin();
|
||||
while (block.isValid()) {
|
||||
for (auto it = block.begin(); !it.atEnd(); ++it) {
|
||||
QTextFragment fragment = it.fragment();
|
||||
if (!fragment.isValid()) continue;
|
||||
|
||||
QTextCharFormat fmt = fragment.charFormat();
|
||||
QString text = fragment.text().toHtmlEscaped();
|
||||
|
||||
if (fmt.foreground().style() != Qt::NoBrush) {
|
||||
QColor fg = fmt.foreground().color();
|
||||
html += QString("<span style=\"color:%1;\">%2</span>").arg(fg.name(), text);
|
||||
} else {
|
||||
html += text;
|
||||
}
|
||||
}
|
||||
block = block.next();
|
||||
if (block.isValid())
|
||||
html += "<br>";
|
||||
KSyntaxHighlighting::State state;
|
||||
const QStringList lines = code.split('\n');
|
||||
for (int i = 0; i < lines.size(); ++i) {
|
||||
state = builder.processLine(lines[i], state);
|
||||
if (i < lines.size() - 1)
|
||||
builder.html += QStringLiteral("<br>");
|
||||
}
|
||||
|
||||
m_highlightCache.insert(cacheKey, html);
|
||||
return html;
|
||||
m_highlightCache.insert(cacheKey, builder.html);
|
||||
return builder.html;
|
||||
}
|
||||
|
||||
QString ChatBlockModel::prettyJson(const QString &text) const
|
||||
|
|
|
|||
Reference in New Issue