From 1d6d0b2bf76cd625c0f7d8518be741fa1ed3550b Mon Sep 17 00:00:00 2001 From: Mirek Fidler Date: Tue, 27 Jan 2026 15:05:53 +0100 Subject: [PATCH] ide: Markdown export improvements --- uppsrc/ide/Browser/TopicWin.cpp | 4 +- uppsrc/ide/Common/Common.h | 2 +- uppsrc/ide/Designers/Designers.lay | 7 ++- uppsrc/ide/Designers/Qtf.cpp | 4 +- uppsrc/ide/Designers/export_md.cpp | 68 ++++++++++++++++++++++++++---- 5 files changed, 71 insertions(+), 14 deletions(-) diff --git a/uppsrc/ide/Browser/TopicWin.cpp b/uppsrc/ide/Browser/TopicWin.cpp index 2de81fb7b..b5074acdd 100644 --- a/uppsrc/ide/Browser/TopicWin.cpp +++ b/uppsrc/ide/Browser/TopicWin.cpp @@ -259,8 +259,8 @@ void TopicEditor::FileBar(Bar& bar) bar.Add("Export group to PDF..", THISBACK(ExportGroupPdf)); bar.Add("Export to HTML..", THISBACK(ExportHTML)); bar.Add("Export group to HTML..", THISBACK(ExportGroupHTML)); - bar.Add("Export as GitHub Markdown", [=] { - ExportMarkdown(editor.GetQTF()); + bar.Add("Export as GitHub Markdown..", [=] { + ExportMarkdown(editor.GetQTF(), GetFileTitle(topicpath)); }); } diff --git a/uppsrc/ide/Common/Common.h b/uppsrc/ide/Common/Common.h index 051f47613..1a447b025 100644 --- a/uppsrc/ide/Common/Common.h +++ b/uppsrc/ide/Common/Common.h @@ -116,6 +116,6 @@ void QTFEdit(String& text); void IdeHelpButton(Button& help, const String& link); -void ExportMarkdown(const char *qtf); +void ExportMarkdown(const char *qtf, const char *name); #endif diff --git a/uppsrc/ide/Designers/Designers.lay b/uppsrc/ide/Designers/Designers.lay index bca2c8359..112a9a221 100644 --- a/uppsrc/ide/Designers/Designers.lay +++ b/uppsrc/ide/Designers/Designers.lay @@ -1,6 +1,11 @@ LAYOUT(ExportMDLayout, 400, 488) - ITEM(Upp::Label, dv___0, SetLabel(t_("\001[g Markdown text copied! Since Markdown doesn't natively embed images, please use the table to manually copy images for their respective placeholders (IMAGE:N).")).SetVAlign(Upp::ALIGN_TOP).LeftPosZ(160, 236).TopPosZ(4, 88)) + ITEM(Upp::Label, dv___0, SetLabel(t_("\001[g Markdown text copied! Since Markdown doesn't natively embed images, please use the table to manually copy images for their respective placeholders (IMAGE:N).")).SetVAlign(Upp::ALIGN_TOP).LeftPosZ(160, 236).TopPosZ(4, 80)) ITEM(Upp::ArrayCtrl, list, LeftPosZ(4, 150).TopPosZ(4, 480)) ITEM(Upp::Button, exit, SetLabel(t_("Close")).LeftPosZ(332, 64).TopPosZ(460, 24)) + ITEM(Upp::Button, doexport, SetLabel(t_("Export")).LeftPosZ(332, 64).TopPosZ(148, 24)) + ITEM(Upp::Label, dv___4, SetLabel(t_("\001[g Alternatively, you can export Markdown to a folder with image files:")).SetVAlign(Upp::ALIGN_TOP).LeftPosZ(160, 236).TopPosZ(88, 32)) + ITEM(Upp::EditString, dir, LeftPosZ(160, 212).TopPosZ(124, 19)) + ITEM(Upp::Button, sel, LeftPosZ(376, 20).TopPosZ(124, 20)) + ITEM(Upp::ImageCtrl, preview, LeftPosZ(156, 240).TopPosZ(212, 244)) END_LAYOUT diff --git a/uppsrc/ide/Designers/Qtf.cpp b/uppsrc/ide/Designers/Qtf.cpp index 186e1b56b..a86815fed 100644 --- a/uppsrc/ide/Designers/Qtf.cpp +++ b/uppsrc/ide/Designers/Qtf.cpp @@ -50,8 +50,8 @@ void IdeQtfDes::EditMenu(Bar& menu) { EditTools(menu); menu.Separator(); - menu.Add("Export as GitHub Markdown", [=] { - ExportMarkdown(GetQTF()); + menu.Add("Export as GitHub Markdown..", [=] { + ExportMarkdown(GetQTF(), GetFileTitle(filename)); }); } diff --git a/uppsrc/ide/Designers/export_md.cpp b/uppsrc/ide/Designers/export_md.cpp index 4e91d794f..f3fc4c2c2 100644 --- a/uppsrc/ide/Designers/export_md.cpp +++ b/uppsrc/ide/Designers/export_md.cpp @@ -4,6 +4,9 @@ #include struct ExportMD : WithExportMDLayout { + bool exporting; + String qtf; + String name; String md; Vector img; @@ -13,7 +16,7 @@ struct ExportMD : WithExportMDLayout { static bool IsPreformatted(const RichPara& p); - void Do(const char *qtf); + void Do(const char *qtf, const char *name); ExportMD(); }; @@ -21,6 +24,39 @@ struct ExportMD : WithExportMDLayout { ExportMD::ExportMD() { CtrlLayoutExit(*this, "Export as GitHub Markdown"); + sel.SetImage(Upp::CtrlImg::Dir()); + sel << [=] { + dir <<= Nvl(SelectDirectory(), ~~dir); + }; + + list.NoWantFocus(); + + doexport << [=] { + exporting = true; + Export(ParseQTF(qtf)); + String d = ~dir; + if(!DirectoryExists(d)) { + if(!PromptYesNo("Create directory [* \1 " + d)) + return; + if(!RealizeDirectory(d)) + Exclamation("Cannot create [* \1 " + d); + } + Progress pi("Exporting", 2 * img.GetCount()); + SaveFile(d + "/" + name + ".md", md); + for(int i = 0; i < img.GetCount(); i++) { + for(int half = 0; half < 2; half++) { + if(pi.StepCanceled()) + return; + RichObjectPaintInfo pi; + pi.ink = SBlack(); + Image m = img[i].ToImage(img[i].GetPixelSize(), pi); + PNGEncoder().SaveFile(d + "/" + AsString(i) + (half ? "_half.png" : ".png"), + half ? Downscale2x(m) : m); + } + } + exporting = false; + Export(ParseQTF(qtf)); + }; } void ExportMD::Export(const RichPara& p) @@ -33,7 +69,11 @@ void ExportMD::Export(const RichPara& p) const RichPara::Part& part = p.part[i]; int q; if(part.object) { - md << "IMAGE:" << img.GetCount(); + int n = img.GetCount(); + if(exporting) + md << "![IMAGE " << n << "](" << n << ".png)"; + else + md << "IMAGE:" << n; img << part.object; } else { @@ -127,6 +167,8 @@ bool ExportMD::IsPreformatted(const RichPara& p) void ExportMD::Export(const RichText& txt) { + img.Clear(); + md.Clear(); int i = 0; while(i < txt.GetPartCount()) if(txt.IsPara(i)) { @@ -155,34 +197,44 @@ void ExportMD::Export(const RichText& txt) i++; } -void ExportMD::Do(const char *qtf) +void ExportMD::Do(const char *qtf_, const char *name_) { + name = name_; + dir <<= GetHomeDirectory() + "/" + name; + qtf = qtf_; Export(ParseQTF(qtf)); WriteClipboardText(md); if(img.GetCount()) { list.SetLineCy(DPI(28)); list.AddColumn("Image").Ctrls([&](int ii, One& ctrl) { + int half = ii & 1; + ii /= 2; Button& b = ctrl.Create