better scrollbar in codeblocks + enter anim for delegates

This commit is contained in:
2026-08-27 01:47:17 +02:00
parent c33dbc147f
commit 293bf67e09
16 changed files with 458 additions and 229 deletions
@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Shapes
import QtQuick.Layouts
import Quickshell
@@ -7,7 +8,7 @@ import ZShell.Llm
import qs.Components
import qs.Services
CustomClippingRect {
CustomRect {
id: root
required property string language
@@ -15,16 +16,11 @@ CustomClippingRect {
property bool copied: false
property color codeBackgroundColor: Colors.palette.m3surfaceContainerHigh
property color codeHeaderColor: Colors.palette.m3outline
// Highlighter spans for the current code; refreshed when the code or
// its language changes. Highlighting runs off the GUI thread; the
// token drops results that arrive after the code already changed.
property var codeSpans: []
property int highlightToken: 0
function refresh() {
const token = ++root.highlightToken;
codeSpans = [];
CodeHighlighter.highlight(root.code, root.language, root, token);
}
@@ -84,10 +80,14 @@ CustomClippingRect {
let pos = 0;
for (let i = 0; i < spans.length; i++) {
const span = spans[i];
if (span.start > pos)
out += escapeHtml(code.slice(pos, span.start));
out += `<font color="${roleColor(span.kind)}">` + escapeHtml(code.slice(span.start, span.start + span.length)) + "</font>";
pos = span.start + span.length;
const start = Math.min(span.start, code.length);
const end = Math.min(span.start + span.length, code.length);
if (end <= pos)
continue;
if (start > pos)
out += escapeHtml(code.slice(pos, start));
out += `<font color="${roleColor(span.kind)}">` + escapeHtml(code.slice(start, end)) + "</font>";
pos = end;
}
if (pos < code.length)
out += escapeHtml(code.slice(pos));
@@ -100,7 +100,10 @@ CustomClippingRect {
color: root.codeBackgroundColor
radius: Tokens.rounding.medium
onLanguageChanged: refresh()
onLanguageChanged: {
codeSpans = [];
refresh();
}
onCodeChanged: refresh()
RowLayout {
@@ -212,7 +215,7 @@ CustomClippingRect {
}
}
CustomRect {
CustomClippingRect {
id: codeRect
anchors.left: parent.left
@@ -226,6 +229,21 @@ CustomClippingRect {
implicitHeight: codeText.implicitHeight + codeFlick.anchors.margins * 2
color: CodeColors.active.bg
CustomText {
id: code
anchors.top: parent.top
anchors.bottom: parent.bottom
x: implicitWidth * (0 - codeFlick.visibleArea.xPosition) + Tokens.padding.small
anchors.margins: Tokens.padding.small
text: root.highlightedHtml(root.code, root.codeSpans)
textFormat: Text.RichText
color: CodeColors.active.normal
layer.enabled: true
clip: false
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
}
Flickable {
id: codeFlick
@@ -234,15 +252,23 @@ CustomClippingRect {
CustomScrollBar.horizontal: CustomScrollBar {
flickable: codeFlick
parent: codeFlick.parent
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
TextAreaBase.flickable: TextAreaBase {
id: codeText
color: CodeColors.active.normal
layer.enabled: true
leftInset: Tokens.padding.small
clip: false
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
textFormat: Text.RichText
text: root.highlightedHtml(root.code, root.codeSpans)
text: code.text
readOnly: true
}
}