Fix section nesting order

With this fix the sections can be nested in any way possible
pull/1/head
trivernis 5 years ago
parent 345bde509c
commit 56ab594009

@ -1,6 +1,29 @@
use std::sync::{Arc, Mutex};
#[derive(Clone, Debug)]
pub const SECTION: &str = "section";
pub const PARAGRAPH: &str = "paragraph";
pub const LIST: &str = "list";
pub const TABLE: &str = "table";
pub const CODE_BLOCK: &str = "code_block";
pub const QUOTE: &str = "quote";
pub const IMPORT: &str = "import";
macro_rules! test_block {
($block:expr, $block_type:expr) => {
match $block {
Block::Section(_) if $block_type == SECTION => true,
Block::List(_) if $block_type == LIST => true,
Block::Table(_) if $block_type == TABLE => true,
Block::Paragraph(_) if $block_type == PARAGRAPH => true,
Block::CodeBlock(_) if $block_type == CODE_BLOCK => true,
Block::Quote(_) if $block_type == QUOTE => true,
Block::Import(_) if $block_type == IMPORT => true,
_ => false,
}
};
}
#[derive(Clone, Debug, PartialEq)]
pub enum Block {
Section(Section),
Paragraph(Paragraph),
@ -11,42 +34,42 @@ pub enum Block {
Import(Import),
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub enum Inline {
Text(Text),
Ruler(Ruler),
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Document {
pub(crate) elements: Vec<Block>,
pub(crate) is_root: bool,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Section {
pub(crate) header: Header,
pub(crate) elements: Vec<Block>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Header {
pub(crate) size: u8,
pub(crate) line: Inline,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Paragraph {
pub(crate) elements: Vec<Inline>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct List {
pub(crate) ordered: bool,
pub(crate) items: Vec<ListItem>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct ListItem {
pub(crate) text: Inline,
pub(crate) level: u16,
@ -54,34 +77,34 @@ pub struct ListItem {
pub(crate) children: Vec<ListItem>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Table {
pub(crate) header: Row,
pub(crate) rows: Vec<Row>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Row {
pub(crate) cells: Vec<Cell>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Cell {
pub(crate) text: Inline,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct CodeBlock {
pub(crate) language: String,
pub(crate) code: String,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Code {
code: String,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Quote {
pub(crate) metadata: Option<InlineMetadata>,
pub(crate) text: Vec<Text>,
@ -93,25 +116,25 @@ pub struct Import {
pub(crate) anchor: Arc<Mutex<ImportAnchor>>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct ImportAnchor {
pub(crate) document: Option<Document>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct InlineMetadata {
pub(crate) data: String,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Ruler {}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Text {
pub subtext: Vec<SubText>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub enum SubText {
Plain(PlainText),
Code(Code),
@ -124,43 +147,43 @@ pub enum SubText {
Image(Image),
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct PlainText {
pub(crate) value: String,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct BoldText {
pub(crate) value: Box<SubText>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct ItalicText {
pub(crate) value: Box<SubText>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct UnderlinedText {
pub(crate) value: Box<SubText>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct StrikedText {
pub(crate) value: Box<SubText>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct MonospaceText {
pub(crate) value: PlainText,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Url {
pub description: Option<String>,
pub url: String,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Image {
pub(crate) url: Url,
pub(crate) metadata: Option<InlineMetadata>,
@ -179,6 +202,27 @@ impl Document {
pub fn add_element(&mut self, element: Block) {
self.elements.push(element)
}
pub fn find(&self, block_type: &str, nested: bool) -> Vec<&Block> {
let mut found = Vec::new();
let mut found_self = self
.elements
.iter()
.filter(|e| {
if nested {
match e {
Block::Section(sec) => found.append(&mut sec.find(block_type, nested)),
_ => {}
}
}
test_block!(e, block_type)
})
.collect();
found.append(&mut found_self);
found
}
}
impl Section {
@ -192,6 +236,26 @@ impl Section {
pub fn add_element(&mut self, element: Block) {
self.elements.push(element)
}
pub fn find(&self, block_type: &str, nested: bool) -> Vec<&Block> {
let mut found = Vec::new();
let mut found_self = self
.elements
.iter()
.filter(|e| {
if nested {
match e {
Block::Section(sec) => found.append(&mut sec.find(block_type, nested)),
_ => {}
}
}
test_block!(e, block_type)
})
.collect();
found.append(&mut found_self);
found
}
}
impl Paragraph {
@ -297,3 +361,9 @@ impl ImportAnchor {
self.document = Some(document);
}
}
impl PartialEq for Import {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
}
}

@ -13,6 +13,30 @@ body {
box-shadow: 1em 1em 1em gray;
}
h1 {
font-size: 2.2rem;
}
h2 {
font-size: 1.8rem;
}
h3 {
font-size: 1.4rem;
}
h4 {
font-size: 1rem;
}
h5 {
font-size: 0.8rem;
}
h6 {
font-size: 0.4rem;
}
img {
max-width: 100%;
max-height: 100vh;

@ -24,9 +24,20 @@ macro_rules! parse_option {
#[derive(Debug)]
pub struct ParseError {
index: usize,
message: Option<String>,
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(message) = &self.message {
write!(
f,
"{} Parse Error at index {}: {}{}",
Fg(color::Red),
self.index,
message,
style::Reset
)
} else {
write!(
f,
"{} Parse Error at index {}{}",
@ -35,11 +46,43 @@ impl Display for ParseError {
style::Reset
)
}
}
}
impl Error for ParseError {}
impl ParseError {
pub fn new(index: usize) -> Self {
Self { index }
Self {
index,
message: None,
}
}
pub fn new_with_message(index: usize, message: &str) -> Self {
Self {
index,
message: Some(message.to_string()),
}
}
pub fn set_message(&mut self, message: &str) {
self.message = Some(message.to_string());
}
pub fn get_position(&self, content: &str) -> Option<(usize, usize)> {
if content.len() <= self.index {
return None;
}
let split_content = content.split_at(self.index);
let line_number = split_content.0.matches("\n").count() as usize;
let overshoot_position = self.index as isize - split_content.0.len() as isize;
if let Some(line) = split_content.0.lines().last() {
let inline_position = (line.len() as isize + overshoot_position) as usize;
Some((line_number, inline_position))
} else {
None
}
}
}
@ -48,6 +91,7 @@ pub struct Parser {
text: Vec<char>,
current_char: char,
section_nesting: u8,
sections: Vec<u8>,
section_return: Option<u8>,
path: Option<String>,
paths: Arc<Mutex<Vec<String>>>,
@ -90,6 +134,7 @@ impl Parser {
index: 0,
text,
current_char,
sections: Vec::new(),
section_nesting: 0,
section_return: None,
path,
@ -100,6 +145,12 @@ impl Parser {
}
}
fn get_text(&self) -> String {
self.text
.iter()
.fold("".to_string(), |a, b| format!("{}{}", a, b))
}
/// Increments the current index and returns the
/// char at the indexes position
fn next_char(&mut self) -> Option<char> {
@ -117,7 +168,7 @@ impl Parser {
self.current_char = char.clone();
Ok(())
} else {
Err(ParseError::new(index))
Err(ParseError::new_with_message(index, "failed to revert"))
}
}
@ -242,18 +293,21 @@ impl Parser {
path,
style::Reset
);
return Err(ParseError::new(self.index));
return Err(ParseError::new_with_message(
self.index,
"file does not exist",
));
}
{
let mut paths = self.paths.lock().unwrap();
if paths.iter().find(|item| **item == path) != None {
println!(
"{}Import of \"{}\" failed: Cyclic reference.{}",
"{}Import of \"{}\" failed: Cyclic import.{}",
Fg(color::Yellow),
path,
style::Reset
);
return Err(ParseError::new(self.index));
return Err(ParseError::new_with_message(self.index, "cyclic import"));
}
paths.push(path.clone());
}
@ -283,7 +337,18 @@ impl Parser {
Ok(block) => document.add_element(block),
Err(err) => {
if let Some(path) = &self.path {
if let Some(position) = err.get_position(&self.get_text()) {
println!(
"{} Error in File {}:{}:{} - {}",
Fg(color::Red),
path,
position.0,
position.1,
err
);
} else {
println!("{} Error in File {}: {}", Fg(color::Red), path, err);
}
} else {
println!("{}", err);
}
@ -302,7 +367,10 @@ impl Parser {
pub fn parse_block(&mut self) -> Result<Block, ParseError> {
if let Some(section) = self.section_return {
if section <= self.section_nesting {
return Err(ParseError::new(self.index));
return Err(ParseError::new_with_message(
self.index,
"invalid section nesting",
));
} else {
self.section_return = None;
}
@ -353,6 +421,7 @@ impl Parser {
let mut header = self.parse_header()?;
header.size = size;
self.section_nesting = size;
self.sections.push(size);
let mut section = Section::new(header);
self.seek_whitespace();
@ -360,7 +429,12 @@ impl Parser {
section.add_element(block);
}
self.section_nesting -= 1;
self.sections.pop();
if let Some(sec) = self.sections.last() {
self.section_nesting = *sec
} else {
self.section_nesting = 0;
}
Ok(section)
} else {
return Err(self.revert_with_error(start_index));

Loading…
Cancel
Save