(FEAT): List nodes seem to be working.
However, the DRY principals are being screwed around with like they don't exist. Some better architecture needs to be implemented. But that will take place after block code nodes and anchor tags are implemented. I will remain on this branch for those other implementations, for now.
This commit is contained in:
parent
0ef0500fe8
commit
2881897c23
18
input.md
18
input.md
@ -20,3 +20,21 @@ this is too far`
|
||||
# ***This is both!***
|
||||
|
||||
###### This is neither
|
||||
|
||||
- Hello world
|
||||
- This is a list
|
||||
|
||||
|
||||
* this is also a list
|
||||
* this is still a list
|
||||
|
||||
|
||||
1. This list is ordered
|
||||
2. This is **number two**
|
||||
|
||||
- hello
|
||||
world
|
||||
|
||||
- hello
|
||||
|
||||
world number two
|
||||
|
||||
118
lib/parser.cpp
118
lib/parser.cpp
@ -72,11 +72,30 @@ std::unique_ptr<Node> Parser::ParseBlock() {
|
||||
// std::unique_ptr<Node> block = std::make_unique<TextNode>(ch);
|
||||
// Consume();
|
||||
|
||||
if (Peek() == '#') {
|
||||
char c = Peek();
|
||||
char c_next = Peek(1);
|
||||
|
||||
// 1. Parse heading
|
||||
if (c == '#') {
|
||||
return ParseHeading();
|
||||
}
|
||||
|
||||
// this is the default case
|
||||
// 2. Parser unordered list
|
||||
if (c == '*' || c == '-' || c == '+') {
|
||||
// Next character must be space or tab
|
||||
if (c_next == ' ' || c_next == '\t') {
|
||||
return ParseList(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Parse ordered list
|
||||
// TODO: This only checks a single digit, should check for 'n' digits
|
||||
if (std::isdigit(c) && c_next == '.') {
|
||||
// TODO: Do we need to check for white space?
|
||||
return ParseList(true);
|
||||
}
|
||||
|
||||
// 4. Parser paragraph
|
||||
return ParseParagraph();
|
||||
}
|
||||
|
||||
@ -120,6 +139,44 @@ std::unique_ptr<Node> Parser::ParseHeading() {
|
||||
return node;
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::ParseList(bool ordered) {
|
||||
auto node = std::make_unique<ListNode>(ordered);
|
||||
|
||||
// Consume the required white space and list char ('* ' or '1.')
|
||||
while (true) {
|
||||
|
||||
Consume(ordered ? 2 : 1);
|
||||
ConsumeWhiteSpace();
|
||||
|
||||
// Parse until either '\n\n' (exit) or the next list element is found ('* '
|
||||
// or '1.') If '\n\n', then create a node and exit
|
||||
auto children = ParseInlineListContent();
|
||||
for (auto &child : children) {
|
||||
node->AddChild(std::move(child));
|
||||
}
|
||||
|
||||
char c = Peek();
|
||||
char c_next = Peek(1);
|
||||
|
||||
// 2. Parser unordered list
|
||||
if (c == '*' || c == '-' || c == '+') {
|
||||
if (c_next == ' ' || c_next == '\t') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Parse ordered list
|
||||
// TODO: This only checks a single digit, should check for 'n' digits
|
||||
if (std::isdigit(c) && c_next == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
vector<std::unique_ptr<Node>> Parser::ParseInline() {
|
||||
vector<std::unique_ptr<Node>> nodes;
|
||||
string str;
|
||||
@ -217,6 +274,63 @@ vector<std::unique_ptr<Node>> Parser::ParseInlineHeading() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
vector<std::unique_ptr<Node>> Parser::ParseInlineListContent() {
|
||||
vector<std::unique_ptr<Node>> nodes;
|
||||
string str;
|
||||
|
||||
while (!IsEOF()) {
|
||||
char c = Peek();
|
||||
char c_next = Peek(1);
|
||||
// If this char and next char are both newlines: then we have an empty line,
|
||||
// we should stop.
|
||||
if (c == '\n' && Peek(1) == '\n')
|
||||
break;
|
||||
|
||||
// Check if a list block has been found
|
||||
if ((c == '*' || c == '-' || c == '+') && (c_next == ' ' || c_next == '\t'))
|
||||
break;
|
||||
|
||||
if (std::isdigit(c) && c_next == '.')
|
||||
break;
|
||||
|
||||
if (c == '*' && Peek(1) == '*' && Peek(2) == '*') {
|
||||
PushTextNode(nodes, str);
|
||||
auto node = ParseBoldItalic();
|
||||
if (!node->IsEmpty())
|
||||
nodes.push_back(std::move(node));
|
||||
continue;
|
||||
} else if (c == '*' && Peek(1) == '*') {
|
||||
PushTextNode(nodes, str);
|
||||
auto node = ParseBold();
|
||||
if (!node->IsEmpty())
|
||||
nodes.push_back(std::move(node));
|
||||
continue;
|
||||
} else if (c == '*') {
|
||||
PushTextNode(nodes, str);
|
||||
auto node = ParseItalic();
|
||||
if (!node->IsEmpty())
|
||||
nodes.push_back(std::move(node));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '`') {
|
||||
PushTextNode(nodes, str);
|
||||
auto node = ParseCode();
|
||||
if (!node->IsEmpty())
|
||||
nodes.push_back(std::move(node));
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a newline, use a space instead
|
||||
str += (c == '\n' ? ' ' : c);
|
||||
Consume();
|
||||
}
|
||||
|
||||
// Push the last node, if the string is not empty
|
||||
PushTextNode(nodes, str);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::ParseItalic() {
|
||||
string str;
|
||||
Consume(1);
|
||||
|
||||
@ -121,10 +121,12 @@ private:
|
||||
|
||||
std::unique_ptr<Node> ParseParagraph();
|
||||
std::unique_ptr<Node> ParseHeading();
|
||||
std::unique_ptr<Node> ParseList(bool ordered);
|
||||
vector<std::unique_ptr<Node>> ParseInline();
|
||||
|
||||
// The only difference is the exit condition
|
||||
// The only differences are the exit condition
|
||||
vector<std::unique_ptr<Node>> ParseInlineHeading();
|
||||
vector<std::unique_ptr<Node>> ParseInlineListContent();
|
||||
|
||||
void PushTextNode(vector<std::unique_ptr<Node>> &nodes, string &str);
|
||||
|
||||
|
||||
@ -55,11 +55,15 @@ string ParagraphNode::ToHtml() const {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// TODO: Implement
|
||||
string ListNode::ToHtml() const {
|
||||
std::stringstream ss;
|
||||
ss << (this->ordered ? "<ol>NOT YET IMPLEMENTED</ol>"
|
||||
: "<ul>NOT YET IMPLEMENTED</ul>");
|
||||
|
||||
ss << (this->ordered ? "<ol>" : "<ul>") << "\n";
|
||||
|
||||
for (const auto &child : this->GetChilren()) {
|
||||
ss << "<li>" << child->ToHtml() << "</li>" << "\n";
|
||||
}
|
||||
|
||||
ss << (this->ordered ? "</ol>" : "</ul>") << "\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user