Render org src blocks as styled code blocks

- Parse body text into segments (text vs code)
- Src blocks get: monospace font, alternate background, rounded corners
- Language label shown above code (python, bash, etc.)
- Regular text keeps left rule indicator

Handles #+BEGIN_SRC lang ... #+END_SRC blocks.
This commit is contained in:
Levi Neely 2026-10-01 10:16:27 +02:00
parent 9e6dc589bd
commit 17906c06f9
1 changed files with 119 additions and 17 deletions

View File

@ -57,6 +57,57 @@ ListView {
readonly property int sectionLevel: model.level ?? 1
readonly property int indent: (sectionLevel - 1) * outline.indentWidth
// Parse body into text and code block segments
readonly property var bodyParts: {
let parts = [];
let body = sectionBody;
if (!body) return parts;
let lines = body.split('\n');
let currentText = [];
let inCode = false;
let codeLang = "";
let codeLines = [];
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
let trimmed = line.trim();
if (!inCode && trimmed.toUpperCase().startsWith("#+BEGIN_SRC")) {
// Flush pending text
if (currentText.length > 0) {
let text = currentText.join('\n').trim();
if (text) parts.push({type: "text", content: text});
currentText = [];
}
// Start code block
inCode = true;
codeLang = trimmed.substring(11).trim().split(/\s+/)[0] || "";
codeLines = [];
} else if (inCode && trimmed.toUpperCase() === "#+END_SRC") {
// End code block
parts.push({type: "code", language: codeLang, content: codeLines.join('\n')});
inCode = false;
codeLang = "";
codeLines = [];
} else if (inCode) {
codeLines.push(line);
} else {
currentText.push(line);
}
}
// Flush remaining
if (inCode && codeLines.length > 0) {
parts.push({type: "code", language: codeLang, content: codeLines.join('\n')});
} else if (currentText.length > 0) {
let text = currentText.join('\n').trim();
if (text) parts.push({type: "text", content: text});
}
return parts;
}
MouseArea {
anchors.fill: parent
onClicked: outline.currentIndex = del.index
@ -230,27 +281,78 @@ ListView {
}
}
// Body text with left rule
RowLayout {
// Body content (text and code blocks)
ColumnLayout {
visible: del.sectionBody !== ""
Layout.fillWidth: true
spacing: 8
spacing: 4
Rectangle {
width: 2
Layout.fillHeight: true
Layout.leftMargin: 2
color: theme.midColor
}
Repeater {
model: del.bodyParts
Label {
Layout.fillWidth: true
text: del.sectionBody
color: theme.placeholderTextColor
font.pointSize: outline.baseFontSize + 1
lineHeight: 1.3
wrapMode: Text.WordWrap
textFormat: Text.PlainText
delegate: Loader {
required property var modelData
Layout.fillWidth: true
sourceComponent: modelData.type === "code" ? codeBlockComponent : textBlockComponent
Component {
id: textBlockComponent
RowLayout {
spacing: 8
Rectangle {
width: 2
Layout.fillHeight: true
Layout.leftMargin: 2
color: theme.midColor
}
Label {
Layout.fillWidth: true
text: modelData.content
color: theme.placeholderTextColor
font.pointSize: outline.baseFontSize + 1
lineHeight: 1.3
wrapMode: Text.WordWrap
textFormat: Text.PlainText
}
}
}
Component {
id: codeBlockComponent
Rectangle {
color: theme.alternateBaseColor
radius: 4
implicitHeight: codeColumn.implicitHeight + 12
ColumnLayout {
id: codeColumn
anchors.fill: parent
anchors.margins: 6
spacing: 4
// Language label
Label {
visible: (modelData.language ?? "") !== ""
text: modelData.language
color: theme.linkColor
font.pointSize: outline.baseFontSize - 2
font.bold: true
}
// Code content
Label {
Layout.fillWidth: true
text: modelData.content
color: theme.textColor
font.family: "monospace"
font.pointSize: outline.baseFontSize
wrapMode: Text.WrapAnywhere
textFormat: Text.PlainText
}
}
}
}
}
}
}
}