mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
CtrlCore: RTF parser now imports monospace fonts as Font::MONOSPACE and imports anchored images too, ide: Markdown export tool
This commit is contained in:
parent
85c3e1af6a
commit
6770526838
7 changed files with 224 additions and 10 deletions
|
|
@ -200,7 +200,8 @@ RTFParser::Cell::Cell()
|
|||
RTFParser::RTFParser(const char *rtf)
|
||||
: rtf(rtf)
|
||||
{
|
||||
#ifdef _DEBUG0
|
||||
#ifdef _DEBUG
|
||||
_DBG_
|
||||
SaveFile(ConfigFile("rtfparser.rtf"), rtf);
|
||||
LOG(rtf);
|
||||
#endif
|
||||
|
|
@ -543,6 +544,13 @@ bool RTFParser::PassEndGroup(int level)
|
|||
{
|
||||
if(Token() == T_EOF)
|
||||
return true;
|
||||
if(PassQ("pict")) { // insert anchored images too
|
||||
Flush(false, 1);
|
||||
ReadPict();
|
||||
Flush(false, 1);
|
||||
para.part.Clear();
|
||||
output.Cat(para);
|
||||
}
|
||||
if(token != T_END_GROUP)
|
||||
return false;
|
||||
is_full = false;
|
||||
|
|
@ -671,6 +679,7 @@ void RTFParser::ReadFaceTable()
|
|||
Face n;
|
||||
n.face = Font::ARIAL;
|
||||
n.charset = default_charset;
|
||||
String facename;
|
||||
while(!PassEndGroup()) {
|
||||
if(PassCmd("f"))
|
||||
fx = command_arg;
|
||||
|
|
@ -716,13 +725,9 @@ void RTFParser::ReadFaceTable()
|
|||
case 255: n.charset = CHARSET_WIN1252; break; // OEM
|
||||
}
|
||||
}
|
||||
/* else if(PassText()) {
|
||||
String s = FromUnicode(text, charset);
|
||||
if(!s.IsEmpty() && *s.Last() == ';')
|
||||
s.Trim(s.GetLength() - 1);
|
||||
if(!s.IsEmpty())
|
||||
f = Font::FindFaceNameIndex(s);
|
||||
}
|
||||
else if(PassText())
|
||||
facename = text.ToString();
|
||||
/*
|
||||
else if(PassGroup()) {
|
||||
int level = Level();
|
||||
if(PassCmd("falt") && PassText() && f < 0)
|
||||
|
|
@ -733,7 +738,10 @@ void RTFParser::ReadFaceTable()
|
|||
Skip();
|
||||
}
|
||||
if(fx >= 0 && fx < MAX_FONTS) {
|
||||
// if(f < 0) // Cxl 2005-11-29
|
||||
facename.TrimEnd(";");
|
||||
int fi = Font::FindFaceNameIndex(facename);
|
||||
if(fi >= 0 && (Font::GetFaceInfo(fi) & Font::FIXEDPITCH))
|
||||
n.face = Font::MONOSPACE;
|
||||
if(default_font == fx) {
|
||||
plain_format.Face(n.face);
|
||||
plain_charset = n.charset;
|
||||
|
|
|
|||
|
|
@ -280,6 +280,10 @@ void TopicEditor::EditMenu(Bar& bar)
|
|||
.Check(allfonts);
|
||||
bar.Separator();
|
||||
bar.Add("Table", THISBACK(TableMenu));
|
||||
bar.Separator();
|
||||
bar.Add("Export as GitHub Markdown", [=] {
|
||||
ExportMarkdown(editor.GetQTF());
|
||||
});
|
||||
}
|
||||
|
||||
void TopicEditor::FormatMenu(Bar& bar)
|
||||
|
|
|
|||
|
|
@ -116,4 +116,6 @@ void QTFEdit(String& text);
|
|||
|
||||
void IdeHelpButton(Button& help, const String& link);
|
||||
|
||||
void ExportMarkdown(const char *qtf);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
6
uppsrc/ide/Designers/Designers.lay
Normal file
6
uppsrc/ide/Designers/Designers.lay
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
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::ArrayCtrl, list, LeftPosZ(4, 150).TopPosZ(4, 480))
|
||||
ITEM(Upp::Button, exit, SetLabel(t_("Close")).LeftPosZ(332, 64).TopPosZ(460, 24))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
@ -14,5 +14,7 @@ file
|
|||
TreeDes.cpp,
|
||||
Xml.cpp,
|
||||
Json.cpp,
|
||||
md.cpp;
|
||||
md.cpp,
|
||||
export_md.cpp,
|
||||
Designers.lay;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ void IdeQtfDes::Save()
|
|||
void IdeQtfDes::EditMenu(Bar& menu)
|
||||
{
|
||||
EditTools(menu);
|
||||
menu.Separator();
|
||||
menu.Add("Export as GitHub Markdown", [=] {
|
||||
ExportMarkdown(GetQTF());
|
||||
});
|
||||
}
|
||||
|
||||
void IdeQtfDes::Serialize(Stream& s)
|
||||
|
|
|
|||
188
uppsrc/ide/Designers/export_md.cpp
Normal file
188
uppsrc/ide/Designers/export_md.cpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
#include "Designers.h"
|
||||
|
||||
#define LAYOUTFILE <ide/Designers/Designers.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
struct ExportMD : WithExportMDLayout<TopWindow> {
|
||||
String md;
|
||||
Vector<RichObject> img;
|
||||
|
||||
void Export(const RichPara& p);
|
||||
void Export(const RichTable& table, const RichStyles& styles);
|
||||
void Export(const RichText& txt);
|
||||
|
||||
static bool IsPreformatted(const RichPara& p);
|
||||
|
||||
void Do(const char *qtf);
|
||||
|
||||
ExportMD();
|
||||
};
|
||||
|
||||
ExportMD::ExportMD()
|
||||
{
|
||||
CtrlLayoutExit(*this, "Export as GitHub Markdown");
|
||||
}
|
||||
|
||||
void ExportMD::Export(const RichPara& p)
|
||||
{
|
||||
if(p.format.ruler)
|
||||
md << "---";
|
||||
if(p.format.bullet)
|
||||
md << "- ";
|
||||
for(int i = 0; i < p.part.GetCount(); i++) {
|
||||
const RichPara::Part& part = p.part[i];
|
||||
int q;
|
||||
if(part.object) {
|
||||
md << "IMAGE:" << img.GetCount();
|
||||
img << part.object;
|
||||
}
|
||||
else {
|
||||
const wchar *s = part.text;
|
||||
|
||||
while(*s == ' ') {
|
||||
md << ' ';
|
||||
s++;
|
||||
}
|
||||
|
||||
String endtag;
|
||||
if(part.format.sscript == 1) {
|
||||
md << "<sup>";
|
||||
endtag = "</sup>" + endtag;
|
||||
}
|
||||
if(part.format.sscript == 2) {
|
||||
md << "<sub>";
|
||||
endtag = "</sub>" + endtag;
|
||||
}
|
||||
if(part.format.IsUnderline()) {
|
||||
md << "<ins>";
|
||||
endtag = "</ins>" + endtag;
|
||||
}
|
||||
if(part.format.IsBold()) {
|
||||
if(!md.TrimEnd("**"))
|
||||
md << "**";
|
||||
endtag = "**" + endtag;
|
||||
}
|
||||
if(part.format.IsItalic()) {
|
||||
md << "_";
|
||||
endtag = "_" + endtag;
|
||||
}
|
||||
if(part.format.IsStrikeout()) {
|
||||
md << "~~";
|
||||
endtag = "~~" + endtag;
|
||||
}
|
||||
|
||||
while(*s) {
|
||||
auto NeedsEscape = [](int c) { return strchr("|[]{}^*_<>~-`'\"", c); };
|
||||
if(*s == '\\' && NeedsEscape(s[1]))
|
||||
md << "\\\\" << (char)*++s;
|
||||
else
|
||||
if(NeedsEscape(*s))
|
||||
md << "\\" << (char)*s;
|
||||
else
|
||||
md << ToUtf8(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
if(endtag.GetCount()) {
|
||||
String t;
|
||||
while(md.TrimEnd(" "))
|
||||
t << ' ';
|
||||
md << endtag << t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExportMD::Export(const RichTable& table, const RichStyles& styles)
|
||||
{
|
||||
for(int i = 0; i < table.GetRows(); i++) {
|
||||
for(int j = 0; j < table.GetColumns(); j++) {
|
||||
md << "|";
|
||||
const RichTxt& txt = table.Get(i, j);
|
||||
for(int i = 0; i < txt.GetPartCount(); i++)
|
||||
if(txt.IsPara(i))
|
||||
Export(txt.Get(i, styles));
|
||||
}
|
||||
md << "|\n";
|
||||
if(i == 0) {
|
||||
for(int j = 0; j < table.GetColumns(); j++)
|
||||
md << "|-";
|
||||
md << "|\n";
|
||||
}
|
||||
}
|
||||
md << "\n\n";
|
||||
}
|
||||
|
||||
bool ExportMD::IsPreformatted(const RichPara& p)
|
||||
{
|
||||
bool b = false;
|
||||
for(int i = 0; i < p.part.GetCount(); i++) {
|
||||
const RichPara::Part& part = p.part[i];
|
||||
if(part.object || !(part.format.GetFaceInfo() & Font::FIXEDPITCH))
|
||||
return false;
|
||||
b = b || part.text.GetCount();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
void ExportMD::Export(const RichText& txt)
|
||||
{
|
||||
int i = 0;
|
||||
while(i < txt.GetPartCount())
|
||||
if(txt.IsPara(i)) {
|
||||
const RichPara& p = txt.Get(i++);
|
||||
if(IsPreformatted(p)) {
|
||||
md << "```\n";
|
||||
md << ToUtf8(p.GetText()) << '\n';
|
||||
while(i < txt.GetPartCount() && txt.IsPara(i)) {
|
||||
const RichPara& p = txt.Get(i);
|
||||
if(!IsPreformatted(p))
|
||||
break;
|
||||
i++;
|
||||
md << ToUtf8(p.GetText()) << '\n';
|
||||
}
|
||||
md << "```\n";
|
||||
}
|
||||
else {
|
||||
Export(p);
|
||||
md << "\n\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
if(txt.IsTable(i))
|
||||
Export(txt.GetTable(i++), txt.GetStyles());
|
||||
else
|
||||
i++;
|
||||
}
|
||||
|
||||
void ExportMD::Do(const char *qtf)
|
||||
{
|
||||
Export(ParseQTF(qtf));
|
||||
WriteClipboardText(md);
|
||||
if(img.GetCount()) {
|
||||
list.SetLineCy(DPI(28));
|
||||
list.AddColumn("Image").Ctrls([&](int ii, One<Ctrl>& ctrl) {
|
||||
Button& b = ctrl.Create<Button>();
|
||||
b.SetImage(CtrlImg::copy());
|
||||
b.SetLabel("Copy IMAGE:" + AsString(ii));
|
||||
b << [=] {
|
||||
if(ii >= 0 && ii < img.GetCount()) {
|
||||
RichObjectPaintInfo pi;
|
||||
pi.ink = SBlack();
|
||||
WriteClipboardImage(img[ii].ToImage(img[ii].GetPixelSize(), pi));
|
||||
}
|
||||
};
|
||||
});
|
||||
for(int i = 0; i < img.GetCount(); i++)
|
||||
list.Add();
|
||||
Run();
|
||||
}
|
||||
else
|
||||
PromptOK("Markdown copied to clipboard.");
|
||||
}
|
||||
|
||||
void ExportMarkdown(const char *qtf)
|
||||
{
|
||||
ExportMD md;
|
||||
md.Do(qtf);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue