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:
Stephan Aßmus 2013-09-07 00:09:02 +02:00
parent c6a0782a8f
commit 59b52a1163
4 changed files with 355 additions and 53 deletions

View File

@ -17,6 +17,7 @@ local textDocumentSources =
BulletData.cpp
CharacterStyle.cpp
CharacterStyleData.cpp
MarkupParser.cpp
Paragraph.cpp
ParagraphLayout.cpp
ParagraphStyle.cpp

View File

@ -0,0 +1,233 @@
/*
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
* 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;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
* 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

View File

@ -5,11 +5,13 @@
#include "TextDocumentTest.h"
#include <math.h>
#include <stdio.h>
#include <LayoutBuilder.h>
#include <Window.h>
#include "MarkupParser.h"
#include "TextDocumentView.h"
TextDocumentTest::TextDocumentTest()
@ -38,64 +40,80 @@ TextDocumentTest::ReadyToRun()
.Add(documentView)
;
ParagraphStyle paragraphStyle;
paragraphStyle.SetJustify(true);
CharacterStyle regularStyle;
CharacterStyle boldStyle(regularStyle);
boldStyle.SetBold(true);
CharacterStyle italicStyle(regularStyle);
italicStyle.SetItalic(true);
CharacterStyle italicAndBoldStyle(boldStyle);
italicAndBoldStyle.SetItalic(true);
float fontSize = regularStyle.Font().Size();
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 paragraphStyle;
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));
paragraphStyle.SetSpacingTop(ceilf(fontSize * 0.6f));
paragraphStyle.SetLineSpacing(ceilf(fontSize * 0.2f));
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);
// CharacterStyle boldStyle(regularStyle);
// boldStyle.SetBold(true);
//
// 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);
MarkupParser parser(regularStyle, paragraphStyle);
TextDocumentRef document = parser.CreateDocumentFromMarkup(
"== Text document test ==\n"
"This is a test to see if '''different''' "
"character styles already work.\n"
"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);