(FEAT): Added support for inline code blocks.

This commit is contained in:
Hayden Hargreaves 2025-10-17 13:50:29 -07:00
parent 2fdab0134a
commit 4b0900e3ae
7 changed files with 86 additions and 5 deletions

View File

@ -21,3 +21,5 @@ string BoldNode::ToHtml() const {
string BoldItalicNode::ToHtml() const {
return "<strong><em>" + this->content + "</em></strong>";
}
string CodeNode::ToHtml() const { return "<code>" + this->content + "</code>"; }

View File

@ -2,6 +2,7 @@
#define INLINENODE_H
#include "node.h"
#include <iostream>
#include <vector>
/**
@ -37,6 +38,15 @@ public:
*/
void AddChild(std::unique_ptr<Node> child);
/**
* @brief Is the node empty.
*
* This is the same as checking if the nodes content is empty.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
bool IsEmpty() const { return this->content.empty(); };
protected:
std::string content;
};
@ -94,4 +104,17 @@ public:
std::string ToHtml() const;
};
/**
* @desc An inline code block node.
*
* This node returns it's content wrapped with <code></code> tags.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class CodeNode : public InlineNode {
public:
CodeNode(std::string content) : InlineNode(content) {};
std::string ToHtml() const;
};
#endif

View File

@ -67,6 +67,15 @@ public:
virtual const std::vector<std::unique_ptr<Node>> &GetChilren() const {
return this->children;
}
/**
* @brief Is the node empty.
*
* This is done differently for inline nodes and structure nodes.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
virtual bool IsEmpty() const = 0;
};
#endif

View File

@ -89,7 +89,7 @@ std::unique_ptr<Node> Parser::ParseParagraph() {
node->AddChild(std::move(text_node));
}
if (node->GetChilren().size() < 1)
if (node->IsEmpty())
return nullptr;
return node;
@ -143,15 +143,29 @@ vector<std::unique_ptr<Node>> Parser::ParseInline() {
if (c == '*' && Peek(1) == '*' && Peek(2) == '*') {
PushTextNode(nodes, str);
nodes.push_back(std::move(ParseBoldItalic()));
auto node = ParseBoldItalic();
if (!node->IsEmpty())
nodes.push_back(std::move(node));
continue;
} else if (c == '*' && Peek(1) == '*') {
PushTextNode(nodes, str);
nodes.push_back(std::move(ParseBold()));
auto node = ParseBold();
if (!node->IsEmpty())
nodes.push_back(std::move(node));
continue;
} else if (c == '*') {
PushTextNode(nodes, str);
nodes.push_back(std::move(ParseItalic()));
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;
}
@ -231,6 +245,28 @@ std::unique_ptr<Node> Parser::ParseBoldItalic() {
return std::make_unique<BoldItalicNode>(str);
}
std::unique_ptr<Node> Parser::ParseCode() {
string str;
Consume(1);
while (!IsEOF()) {
char c = Peek();
if (c == '\n' && Peek(1) == '\n')
break;
if (c == '`') {
Consume(1);
break;
}
str += c;
Consume();
}
return std::make_unique<CodeNode>(str);
}
void Parser::PushTextNode(vector<std::unique_ptr<Node>> &nodes, string &str) {
if (!str.empty())
nodes.push_back(std::move(std::make_unique<TextNode>(str)));

View File

@ -126,6 +126,7 @@ private:
std::unique_ptr<Node> ParseItalic();
std::unique_ptr<Node> ParseBold();
std::unique_ptr<Node> ParseBoldItalic();
std::unique_ptr<Node> ParseCode();
char Peek(size_t offset = 0);
void Consume(size_t count = 1);

View File

@ -2,6 +2,7 @@
#define STRUCTURENODE_H
#include "node.h"
#include <iostream>
#include <string>
/**
@ -23,6 +24,15 @@ public:
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
virtual std::string ToHtml() const = 0;
/**
* @brief Is the node empty.
*
* This is the same as checking if the node has no children.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
bool IsEmpty() const { return this->children.size() == 0; };
};
/**

View File

@ -79,7 +79,7 @@ void test_input(int argc, char **argv) {
}
int main(int argc, char **argv) {
Parser p("syntax.md");
Parser p("input.md");
p.ParseDocument();
p.WriteOutput();