HaikuDepot: Added very simplistic markup parser.
* Follows MediaWiki or TracWiki style. * Supports only level 2 headings, bold, italic and top-level bullet paragraphs. * Line break handling would need to be changed. * Outputs a TextDocument.
This commit is contained in:
@@ -17,6 +17,7 @@ local textDocumentSources =
|
|||||||
BulletData.cpp
|
BulletData.cpp
|
||||||
CharacterStyle.cpp
|
CharacterStyle.cpp
|
||||||
CharacterStyleData.cpp
|
CharacterStyleData.cpp
|
||||||
|
MarkupParser.cpp
|
||||||
Paragraph.cpp
|
Paragraph.cpp
|
||||||
ParagraphLayout.cpp
|
ParagraphLayout.cpp
|
||||||
ParagraphStyle.cpp
|
ParagraphStyle.cpp
|
||||||
|
|||||||
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Stephan Aßmus <[email protected]>.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MarkupParser.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <utf8_functions.h>
|
||||||
|
|
||||||
|
|
||||||
|
MarkupParser::MarkupParser()
|
||||||
|
:
|
||||||
|
fNormalStyle(),
|
||||||
|
fBoldStyle(),
|
||||||
|
fItalicStyle(),
|
||||||
|
fBoldItalicStyle(),
|
||||||
|
fHeadingStyle(),
|
||||||
|
|
||||||
|
fParagraphStyle(),
|
||||||
|
fHeadingParagraphStyle(),
|
||||||
|
fBulletStyle(),
|
||||||
|
|
||||||
|
fCurrentCharacterStyle(&fNormalStyle),
|
||||||
|
fCurrentParagraphStyle(&fParagraphStyle)
|
||||||
|
{
|
||||||
|
_InitStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MarkupParser::MarkupParser(const CharacterStyle& characterStyle,
|
||||||
|
const ParagraphStyle& paragraphStyle)
|
||||||
|
:
|
||||||
|
fNormalStyle(characterStyle),
|
||||||
|
fBoldStyle(),
|
||||||
|
fItalicStyle(),
|
||||||
|
fBoldItalicStyle(),
|
||||||
|
fHeadingStyle(),
|
||||||
|
|
||||||
|
fParagraphStyle(paragraphStyle),
|
||||||
|
fHeadingParagraphStyle(),
|
||||||
|
fBulletStyle(),
|
||||||
|
|
||||||
|
fCurrentCharacterStyle(&fNormalStyle),
|
||||||
|
fCurrentParagraphStyle(&fParagraphStyle)
|
||||||
|
{
|
||||||
|
_InitStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextDocumentRef
|
||||||
|
MarkupParser::CreateDocumentFromMarkup(const BString& text)
|
||||||
|
{
|
||||||
|
fTextDocument.SetTo(new(std::nothrow) TextDocument(), true);
|
||||||
|
if (fTextDocument.Get() == NULL)
|
||||||
|
return fTextDocument;
|
||||||
|
|
||||||
|
fCurrentCharacterStyle = &fNormalStyle;
|
||||||
|
fCurrentParagraphStyle = &fParagraphStyle;
|
||||||
|
|
||||||
|
fCurrentParagraph = Paragraph(*fCurrentParagraphStyle);
|
||||||
|
fSpanStartOffset = 0;
|
||||||
|
|
||||||
|
_ParseText(text);
|
||||||
|
|
||||||
|
return fTextDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkupParser::_InitStyles()
|
||||||
|
{
|
||||||
|
fBoldStyle = fNormalStyle;
|
||||||
|
fBoldStyle.SetBold(true);
|
||||||
|
|
||||||
|
fItalicStyle = fNormalStyle;
|
||||||
|
fItalicStyle.SetItalic(true);
|
||||||
|
|
||||||
|
fBoldItalicStyle = fNormalStyle;
|
||||||
|
fBoldItalicStyle.SetBold(true);
|
||||||
|
fBoldItalicStyle.SetItalic(true);
|
||||||
|
|
||||||
|
float fontSize = fNormalStyle.Font().Size();
|
||||||
|
|
||||||
|
fHeadingStyle = fNormalStyle;
|
||||||
|
fHeadingStyle.SetFontSize(ceilf(fontSize * 1.15f));
|
||||||
|
fHeadingStyle.SetBold(true);
|
||||||
|
|
||||||
|
fHeadingParagraphStyle = fParagraphStyle;
|
||||||
|
fHeadingParagraphStyle.SetSpacingTop(ceilf(fontSize * 0.8f));
|
||||||
|
fHeadingParagraphStyle.SetSpacingBottom(ceilf(fontSize * 0.5f));
|
||||||
|
fHeadingParagraphStyle.SetJustify(false);
|
||||||
|
|
||||||
|
fBulletStyle = fParagraphStyle;
|
||||||
|
fBulletStyle.SetBullet(Bullet("•", fontSize));
|
||||||
|
fBulletStyle.SetLineInset(ceilf(fontSize * 0.8f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkupParser::_ParseText(const BString& text)
|
||||||
|
{
|
||||||
|
int32 start = 0;
|
||||||
|
int32 offset = 0;
|
||||||
|
|
||||||
|
int32 charCount = text.CountChars();
|
||||||
|
const char* c = text.String();
|
||||||
|
|
||||||
|
while (offset < charCount) {
|
||||||
|
uint32 nextChar = UTF8ToCharCode(&c);
|
||||||
|
|
||||||
|
switch (nextChar) {
|
||||||
|
case '\n':
|
||||||
|
case '\0':
|
||||||
|
_CopySpan(text, start, offset - 1);
|
||||||
|
_FinishParagraph();
|
||||||
|
start = offset + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\'':
|
||||||
|
if (offset + 2 < charCount && c[0] == '\'') {
|
||||||
|
int32 tickCount = 2;
|
||||||
|
if (c[1] == '\'')
|
||||||
|
tickCount = 3;
|
||||||
|
|
||||||
|
// Copy previous span using current style, excluding the
|
||||||
|
// ticks.
|
||||||
|
_CopySpan(text, start, offset);
|
||||||
|
|
||||||
|
if (tickCount == 2)
|
||||||
|
_ToggleStyle(fItalicStyle);
|
||||||
|
else if (tickCount == 3)
|
||||||
|
_ToggleStyle(fBoldStyle);
|
||||||
|
|
||||||
|
// Don't include the ticks in the next span.
|
||||||
|
offset += tickCount - 1;
|
||||||
|
start = offset + 1;
|
||||||
|
c += tickCount - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
// Detect headings
|
||||||
|
if (offset == start
|
||||||
|
&& fCurrentParagraph.IsEmpty()
|
||||||
|
&& offset + 2 < charCount
|
||||||
|
&& c[0] == '=' && c[1] == ' ') {
|
||||||
|
|
||||||
|
fCurrentParagraph.SetStyle(fHeadingParagraphStyle);
|
||||||
|
fCurrentCharacterStyle = &fHeadingStyle;
|
||||||
|
|
||||||
|
offset += 2;
|
||||||
|
c += 2;
|
||||||
|
|
||||||
|
start = offset + 1;
|
||||||
|
} else if (offset > start
|
||||||
|
&& offset + 2 < charCount
|
||||||
|
&& c[0] == '=' && c[1] == '\n') {
|
||||||
|
|
||||||
|
_CopySpan(text, start, offset - 1);
|
||||||
|
_FinishParagraph();
|
||||||
|
|
||||||
|
offset += 2;
|
||||||
|
c += 2;
|
||||||
|
|
||||||
|
start = offset + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
// Detect bullets at line starts
|
||||||
|
if (offset == start
|
||||||
|
&& fCurrentParagraph.IsEmpty()
|
||||||
|
&& offset + 2 < charCount
|
||||||
|
&& c[0] == '*' && c[1] == ' ') {
|
||||||
|
|
||||||
|
fCurrentParagraph.SetStyle(fBulletStyle);
|
||||||
|
|
||||||
|
offset += 2;
|
||||||
|
c += 2;
|
||||||
|
|
||||||
|
start = offset + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkupParser::_CopySpan(const BString& text, int32& start, int32 end)
|
||||||
|
{
|
||||||
|
if (start >= end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BString subString;
|
||||||
|
text.CopyCharsInto(subString, start, end - start);
|
||||||
|
fCurrentParagraph.Append(TextSpan(subString,
|
||||||
|
*fCurrentCharacterStyle));
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkupParser::_ToggleStyle(const CharacterStyle& style)
|
||||||
|
{
|
||||||
|
if (fCurrentCharacterStyle == &style)
|
||||||
|
fCurrentCharacterStyle = &fNormalStyle;
|
||||||
|
else
|
||||||
|
fCurrentCharacterStyle = &style;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MarkupParser::_FinishParagraph()
|
||||||
|
{
|
||||||
|
fTextDocument->Append(fCurrentParagraph);
|
||||||
|
fCurrentParagraph.Clear();
|
||||||
|
fCurrentParagraph.SetStyle(fParagraphStyle);
|
||||||
|
fCurrentCharacterStyle = &fNormalStyle;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Stephan Aßmus <[email protected]>.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef MARKUP_PARSER_H
|
||||||
|
#define MARKUP_PARSER_H
|
||||||
|
|
||||||
|
#include "TextDocument.h"
|
||||||
|
|
||||||
|
|
||||||
|
class MarkupParser {
|
||||||
|
public:
|
||||||
|
MarkupParser();
|
||||||
|
MarkupParser(
|
||||||
|
const CharacterStyle& characterStyle,
|
||||||
|
const ParagraphStyle& paragraphStyle);
|
||||||
|
|
||||||
|
TextDocumentRef CreateDocumentFromMarkup(const BString& text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _InitStyles();
|
||||||
|
|
||||||
|
void _ParseText(const BString& text);
|
||||||
|
void _CopySpan(const BString& text,
|
||||||
|
int32& start, int32 end);
|
||||||
|
void _ToggleStyle(const CharacterStyle& style);
|
||||||
|
void _FinishParagraph();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CharacterStyle fNormalStyle;
|
||||||
|
CharacterStyle fBoldStyle;
|
||||||
|
CharacterStyle fItalicStyle;
|
||||||
|
CharacterStyle fBoldItalicStyle;
|
||||||
|
CharacterStyle fHeadingStyle;
|
||||||
|
|
||||||
|
ParagraphStyle fParagraphStyle;
|
||||||
|
ParagraphStyle fHeadingParagraphStyle;
|
||||||
|
ParagraphStyle fBulletStyle;
|
||||||
|
|
||||||
|
const CharacterStyle* fCurrentCharacterStyle;
|
||||||
|
const ParagraphStyle* fCurrentParagraphStyle;
|
||||||
|
|
||||||
|
// while parsing:
|
||||||
|
TextDocumentRef fTextDocument;
|
||||||
|
Paragraph fCurrentParagraph;
|
||||||
|
int32 fSpanStartOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MARKUP_PARSER_H
|
||||||
@@ -5,11 +5,13 @@
|
|||||||
|
|
||||||
#include "TextDocumentTest.h"
|
#include "TextDocumentTest.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <LayoutBuilder.h>
|
#include <LayoutBuilder.h>
|
||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "MarkupParser.h"
|
||||||
#include "TextDocumentView.h"
|
#include "TextDocumentView.h"
|
||||||
|
|
||||||
TextDocumentTest::TextDocumentTest()
|
TextDocumentTest::TextDocumentTest()
|
||||||
@@ -38,64 +40,80 @@ TextDocumentTest::ReadyToRun()
|
|||||||
.Add(documentView)
|
.Add(documentView)
|
||||||
;
|
;
|
||||||
|
|
||||||
ParagraphStyle paragraphStyle;
|
|
||||||
paragraphStyle.SetJustify(true);
|
|
||||||
|
|
||||||
CharacterStyle regularStyle;
|
CharacterStyle regularStyle;
|
||||||
|
|
||||||
CharacterStyle boldStyle(regularStyle);
|
float fontSize = regularStyle.Font().Size();
|
||||||
boldStyle.SetBold(true);
|
|
||||||
|
|
||||||
CharacterStyle italicStyle(regularStyle);
|
ParagraphStyle paragraphStyle;
|
||||||
italicStyle.SetItalic(true);
|
|
||||||
|
|
||||||
CharacterStyle italicAndBoldStyle(boldStyle);
|
|
||||||
italicAndBoldStyle.SetItalic(true);
|
|
||||||
|
|
||||||
CharacterStyle bigStyle(regularStyle);
|
|
||||||
bigStyle.SetFontSize(24);
|
|
||||||
bigStyle.SetForegroundColor(255, 50, 50);
|
|
||||||
|
|
||||||
TextDocumentRef document(new TextDocument(), true);
|
|
||||||
|
|
||||||
Paragraph paragraph(paragraphStyle);
|
|
||||||
paragraph.Append(TextSpan("This is a", regularStyle));
|
|
||||||
paragraph.Append(TextSpan(" test ", bigStyle));
|
|
||||||
paragraph.Append(TextSpan("to see if ", regularStyle));
|
|
||||||
paragraph.Append(TextSpan("different", boldStyle));
|
|
||||||
paragraph.Append(TextSpan(" character styles already work.", regularStyle));
|
|
||||||
document->Append(paragraph);
|
|
||||||
|
|
||||||
paragraphStyle.SetSpacingTop(8.0f);
|
|
||||||
paragraphStyle.SetAlignment(ALIGN_CENTER);
|
|
||||||
paragraphStyle.SetJustify(false);
|
|
||||||
|
|
||||||
paragraph = Paragraph(paragraphStyle);
|
|
||||||
paragraph.Append(TextSpan("Different alignment styles ", regularStyle));
|
|
||||||
paragraph.Append(TextSpan("are", boldStyle));
|
|
||||||
paragraph.Append(TextSpan(" supported as of now!", regularStyle));
|
|
||||||
document->Append(paragraph);
|
|
||||||
|
|
||||||
// Test a bullet list
|
|
||||||
paragraphStyle.SetSpacingTop(8.0f);
|
|
||||||
paragraphStyle.SetAlignment(ALIGN_LEFT);
|
|
||||||
paragraphStyle.SetJustify(true);
|
paragraphStyle.SetJustify(true);
|
||||||
paragraphStyle.SetBullet(Bullet("•", 12.0f));
|
paragraphStyle.SetSpacingTop(ceilf(fontSize * 0.6f));
|
||||||
paragraphStyle.SetLineInset(10.0f);
|
paragraphStyle.SetLineSpacing(ceilf(fontSize * 0.2f));
|
||||||
|
|
||||||
paragraph = Paragraph(paragraphStyle);
|
// CharacterStyle boldStyle(regularStyle);
|
||||||
paragraph.Append(TextSpan("Even bullet lists are supported.", regularStyle));
|
// boldStyle.SetBold(true);
|
||||||
document->Append(paragraph);
|
//
|
||||||
|
// CharacterStyle italicStyle(regularStyle);
|
||||||
|
// italicStyle.SetItalic(true);
|
||||||
|
//
|
||||||
|
// CharacterStyle italicAndBoldStyle(boldStyle);
|
||||||
|
// italicAndBoldStyle.SetItalic(true);
|
||||||
|
//
|
||||||
|
// CharacterStyle bigStyle(regularStyle);
|
||||||
|
// bigStyle.SetFontSize(24);
|
||||||
|
// bigStyle.SetForegroundColor(255, 50, 50);
|
||||||
|
//
|
||||||
|
// TextDocumentRef document(new TextDocument(), true);
|
||||||
|
//
|
||||||
|
// Paragraph paragraph(paragraphStyle);
|
||||||
|
// paragraph.Append(TextSpan("This is a", regularStyle));
|
||||||
|
// paragraph.Append(TextSpan(" test ", bigStyle));
|
||||||
|
// paragraph.Append(TextSpan("to see if ", regularStyle));
|
||||||
|
// paragraph.Append(TextSpan("different", boldStyle));
|
||||||
|
// paragraph.Append(TextSpan(" character styles already work.", regularStyle));
|
||||||
|
// document->Append(paragraph);
|
||||||
|
//
|
||||||
|
// paragraphStyle.SetSpacingTop(8.0f);
|
||||||
|
// paragraphStyle.SetAlignment(ALIGN_CENTER);
|
||||||
|
// paragraphStyle.SetJustify(false);
|
||||||
|
//
|
||||||
|
// paragraph = Paragraph(paragraphStyle);
|
||||||
|
// paragraph.Append(TextSpan("Different alignment styles ", regularStyle));
|
||||||
|
// paragraph.Append(TextSpan("are", boldStyle));
|
||||||
|
// paragraph.Append(TextSpan(" supported as of now!", regularStyle));
|
||||||
|
// document->Append(paragraph);
|
||||||
|
//
|
||||||
|
// // Test a bullet list
|
||||||
|
// paragraphStyle.SetSpacingTop(8.0f);
|
||||||
|
// paragraphStyle.SetAlignment(ALIGN_LEFT);
|
||||||
|
// paragraphStyle.SetJustify(true);
|
||||||
|
// paragraphStyle.SetBullet(Bullet("•", 12.0f));
|
||||||
|
// paragraphStyle.SetLineInset(10.0f);
|
||||||
|
//
|
||||||
|
// paragraph = Paragraph(paragraphStyle);
|
||||||
|
// paragraph.Append(TextSpan("Even bullet lists are supported.", regularStyle));
|
||||||
|
// document->Append(paragraph);
|
||||||
|
//
|
||||||
|
// paragraph = Paragraph(paragraphStyle);
|
||||||
|
// paragraph.Append(TextSpan("The wrapping in ", regularStyle));
|
||||||
|
// paragraph.Append(TextSpan("this", italicStyle));
|
||||||
|
//
|
||||||
|
// paragraph.Append(TextSpan(" bullet item should look visually "
|
||||||
|
// "pleasing. And ", regularStyle));
|
||||||
|
// paragraph.Append(TextSpan("why", italicAndBoldStyle));
|
||||||
|
// paragraph.Append(TextSpan(" should it not?", regularStyle));
|
||||||
|
// document->Append(paragraph);
|
||||||
|
|
||||||
paragraph = Paragraph(paragraphStyle);
|
MarkupParser parser(regularStyle, paragraphStyle);
|
||||||
paragraph.Append(TextSpan("The wrapping in ", regularStyle));
|
|
||||||
paragraph.Append(TextSpan("this", italicStyle));
|
|
||||||
|
|
||||||
paragraph.Append(TextSpan(" bullet item should look visually "
|
TextDocumentRef document = parser.CreateDocumentFromMarkup(
|
||||||
"pleasing. And ", regularStyle));
|
"== Text document test ==\n"
|
||||||
paragraph.Append(TextSpan("why", italicAndBoldStyle));
|
"This is a test to see if '''different''' "
|
||||||
paragraph.Append(TextSpan(" should it not?", regularStyle));
|
"character styles already work.\n"
|
||||||
document->Append(paragraph);
|
"Different alignment styles '''are''' supported as of now!\n"
|
||||||
|
" * Even bullet lists are supported.\n"
|
||||||
|
" * The wrapping in ''this'' bullet item should look visually "
|
||||||
|
"pleasing. And ''why'' should it not?\n"
|
||||||
|
);
|
||||||
|
|
||||||
documentView->SetTextDocument(document);
|
documentView->SetTextDocument(document);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user