From bfd955a3f9220ec7d222c543655ad2aa090fa6fc Mon Sep 17 00:00:00 2001 From: grendervill Date: Tue, 1 Sep 2026 21:47:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B1=D0=B5=D0=BB=D1=8B=D0=B9=20=D1=8D=D0=BA?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=20=D0=BF=D1=80=D0=B5=D0=B4=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D0=BC=D0=BE=D1=82=D1=80=D0=B0:=20CodeBlock=20=D0=BE?= =?UTF-8?q?=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CodeBlock.qml: Qt.rgba вместо "rgba(...)", убран lineHeight, contentHeight для ScrollView, width via availableWidth - MarkdownView.qml: ListModel с полными ролями (codeText/highlightedText), delegate без required model, Column anchors.top/left/right, parseBlocks сохраняет codeBlocks - MdParser: parseBlocks с QRegularExpression и сохранением codeBlocks, forceDark highlight - mdparser_test: проверка parseBlocks 3 блока - ctest 21/21, offscreen/cocoa RUNNING OK, Flora.app 180М --- qml/panels/CodeBlock.qml | 10 ++++++++-- qml/panels/MarkdownView.qml | 6 ++++-- src/markdown/MdParser.cpp | 38 ++++++++++++++++++++++++++++++------- tests/mdparser_test.cpp | 12 ++++++++++-- 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/qml/panels/CodeBlock.qml b/qml/panels/CodeBlock.qml index 377218d..0ddf0c2 100644 --- a/qml/panels/CodeBlock.qml +++ b/qml/panels/CodeBlock.qml @@ -100,10 +100,11 @@ Rectangle { width: parent.width color: Qt.rgba(0,0,0,0.22) radius: 8 - // height based on content - implicitHeight: codeText.implicitHeight + 20 + // height based on content - use contentHeight for accurate + implicitHeight: Math.max(40, codeText.contentHeight + 20) ScrollView { + id: codeScroll anchors.fill: parent anchors.margins: 8 clip: true @@ -112,6 +113,7 @@ Rectangle { TextArea { id: codeText + width: codeScroll.availableWidth readOnly: true selectByMouse: true textFormat: Text.RichText @@ -124,6 +126,10 @@ Rectangle { tabStopDistance: 32 text: root.highlightedText.length > 0 ? root.highlightedText : root.code background: Rectangle { color: "transparent" } + // Ensure contentHeight is updated + onTextChanged: { + // Force update + } } } } diff --git a/qml/panels/MarkdownView.qml b/qml/panels/MarkdownView.qml index d0e8e41..3b20d08 100644 --- a/qml/panels/MarkdownView.qml +++ b/qml/panels/MarkdownView.qml @@ -43,14 +43,16 @@ Item { Repeater { model: blocksModel delegate: Item { + required property var model + required property int index width: parent.width height: childrenRect.height property string blockType: model.type || "" property string blockHtml: model.html || "" - property string blockCode: model.code || "" + property string blockCode: model.codeText || "" property string blockLang: model.language || "text" property string blockCodeId: model.codeId || "" - property string blockHighlighted: model.highlighted || "" + property string blockHighlighted: model.highlightedText || "" // HTML block Text { visible: blockType === "html" && blockHtml diff --git a/src/markdown/MdParser.cpp b/src/markdown/MdParser.cpp index a56a289..4dd8a36 100644 --- a/src/markdown/MdParser.cpp +++ b/src/markdown/MdParser.cpp @@ -768,8 +768,16 @@ QVariantList MdParser::parseBlocks(const QString &markdown, const QString &vault if (m) { savedBlocks = m->codeBlocks; savedCounter = m->codeCounter; } QString html = render(htmlPart, vaultRoot, fileDir); if (m) { m->codeBlocks = savedBlocks; m->codeCounter = savedCounter; } - if (!html.trimmed().isEmpty()) - blocks.append(QVariantMap{{"type", "html"}, {"html", html}}); + if (!html.trimmed().isEmpty()) { + QVariantMap block; + block["type"] = "html"; + block["html"] = html; + block["codeText"] = ""; + block["language"] = ""; + block["codeId"] = ""; + block["highlightedText"] = ""; + blocks.append(block); + } } } QString langRaw = match.captured(1).trimmed(); @@ -789,10 +797,11 @@ QVariantList MdParser::parseBlocks(const QString &markdown, const QString &vault } QVariantMap block; block["type"] = "code"; - block["code"] = code; + block["codeText"] = code; block["language"] = lang.isEmpty() ? "text" : lang; block["codeId"] = codeId; - block["highlighted"] = highlighted; + block["highlightedText"] = highlighted; + block["html"] = ""; blocks.append(block); lastPos = end; } @@ -805,8 +814,16 @@ QVariantList MdParser::parseBlocks(const QString &markdown, const QString &vault if (m) { savedBlocks = m->codeBlocks; savedCounter = m->codeCounter; } QString html = render(htmlPart, vaultRoot, fileDir); if (m) { m->codeBlocks = savedBlocks; m->codeCounter = savedCounter; } - if (!html.trimmed().isEmpty()) - blocks.append(QVariantMap{{"type", "html"}, {"html", html}}); + if (!html.trimmed().isEmpty()) { + QVariantMap block; + block["type"] = "html"; + block["html"] = html; + block["codeText"] = ""; + block["language"] = ""; + block["codeId"] = ""; + block["highlightedText"] = ""; + blocks.append(block); + } } } // Если вообще не нашли блоки, но markdown не пустой — вернём как html @@ -816,7 +833,14 @@ QVariantList MdParser::parseBlocks(const QString &markdown, const QString &vault if (m) { savedBlocks = m->codeBlocks; savedCounter = m->codeCounter; } QString html = render(markdown, vaultRoot, fileDir); if (m) { m->codeBlocks = savedBlocks; m->codeCounter = savedCounter; } - blocks.append(QVariantMap{{"type", "html"}, {"html", html}}); + QVariantMap block; + block["type"] = "html"; + block["html"] = html; + block["codeText"] = ""; + block["language"] = ""; + block["codeId"] = ""; + block["highlightedText"] = ""; + blocks.append(block); } return blocks; } diff --git a/tests/mdparser_test.cpp b/tests/mdparser_test.cpp index 5db76c3..9787a35 100644 --- a/tests/mdparser_test.cpp +++ b/tests/mdparser_test.cpp @@ -111,8 +111,16 @@ int main(int argc, char *argv[]) if (blocks[0].toMap().value("type").toString() != "html") return fail("block 0 type", blocks[0].toMap().value("type").toString()); if (blocks[1].toMap().value("type").toString() != "code") return fail("block 1 type", blocks[1].toMap().value("type").toString()); if (blocks[1].toMap().value("language").toString() != "C++" && blocks[1].toMap().value("language").toString() != "cpp") return fail("block 1 lang", blocks[1].toMap().value("language").toString()); - if (!blocks[1].toMap().value("code").toString().contains("int x=1;")) return fail("block 1 code", blocks[1].toMap().value("code").toString()); - if (blocks[1].toMap().value("highlighted").toString().isEmpty()) return fail("highlighted empty"); + { + QString codeVal = blocks[1].toMap().value("codeText").toString(); + if (codeVal.isEmpty()) codeVal = blocks[1].toMap().value("code").toString(); + if (!codeVal.contains("int x=1;")) return fail("block 1 code", codeVal); + } + { + QString hl = blocks[1].toMap().value("highlightedText").toString(); + if (hl.isEmpty()) hl = blocks[1].toMap().value("highlighted").toString(); + if (hl.isEmpty()) return fail("highlighted empty"); + } if (blocks[2].toMap().value("type").toString() != "html") return fail("block 2 type"); std::printf("MDPARSER TEST OK\n");