Skip to content

Commit

Permalink
Parse Markdown Non-title Lines
Browse files Browse the repository at this point in the history
Also added two alias for V and H.
  • Loading branch information
yzhong52 committed Aug 8, 2024
1 parent fc3c213 commit 739f945
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 21 deletions.
9 changes: 9 additions & 0 deletions examples/with_content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Root

## Left Child

Quota: 100

## Right Child

Quota: 200
10 changes: 8 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ struct Args {
impl Args {
fn run(self) {
match self.command {
Command::Vertical(vertical_args) => vertical_args.run(),
Command::Horizontal(horizontal_args) => horizontal_args.run(),
Command::Vertical(vertical_args) | Command::V(vertical_args) => vertical_args.run(),
Command::Horizontal(horizontal_args) | Command::H(horizontal_args) => {
horizontal_args.run()
}
}
}
}
Expand All @@ -48,8 +50,12 @@ impl Args {
pub enum Command {
/// Print the tree virtually
Vertical(VerticalArgs),
// Print the tree virtually (alias for vertical subcommand)
V(VerticalArgs),
/// Print the tree horizontally
Horizontal(HorizontalArgs),
// Print the tree horizontally (alias for horizontal subcommand)
H(HorizontalArgs),
}

#[derive(Parser, Debug)]
Expand Down
52 changes: 33 additions & 19 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ struct NodeLayer {
}

fn parse_markdown(content: String, width: Option<usize>) -> Vec<TreeNode> {
// Split the content by line, and remove empty lines
let lines: Vec<&str> = content
.split("\n")
.map(|x| x.trim())
.filter(|&x| !x.is_empty())
.filter(|&x| x.starts_with("#"))
.collect();

// Create a dummy root node at depth 0
Expand All @@ -88,22 +88,35 @@ fn parse_markdown(content: String, width: Option<usize>) -> Vec<TreeNode> {
let mut stack: Vec<NodeLayer> = vec![root_layer];

for line in &lines {
let (depth, label) = parse_line(line, width);

while depth < stack.last().unwrap().depth {
let top_layer = stack.pop().unwrap();
stack.last_mut().unwrap().nodes.last_mut().unwrap().children = top_layer.nodes;
}
if line.starts_with("#") {
let (depth, label) = parse_line(line, width);
while depth < stack.last().unwrap().depth {
// Finish parsing one layer of nodes
let top_layer = stack.pop().unwrap();
stack.last_mut().unwrap().nodes.last_mut().unwrap().children = top_layer.nodes;
}

let node = TreeNode::from_label(&label);
if depth > stack.last().unwrap().depth {
stack.push(NodeLayer {
depth: depth,
nodes: vec![node],
});
let node = TreeNode::from_label(&label);
if depth > stack.last().unwrap().depth {
stack.push(NodeLayer {
depth: depth,
nodes: vec![node],
});
} else {
assert_eq!(depth, stack.last().unwrap().depth);
stack.last_mut().unwrap().nodes.push(node);
}
} else {
assert_eq!(depth, stack.last().unwrap().depth);
stack.last_mut().unwrap().nodes.push(node);
// if this line is not a title line, then append it to the last node's
// label with a line break.
stack
.last_mut()
.unwrap()
.nodes
.last_mut()
.unwrap()
.label
.push_str(&("\\n".to_string() + line));
}
}

Expand Down Expand Up @@ -145,8 +158,10 @@ mod tests {
}

#[test]
fn test_parse_markdown_ignore_none_title_lines() {
// Both empty lines and none-title lines are ignored
fn test_parse_include_non_title_line() {
// In other examples, we only parse the title lines of the markdown format.
// Here, we parse the content as well and automatically include line breaks.
// This, we believe is slight more usessssr friendly than having to type '\n'.
let nodes = parse_markdown(
r#"
#Root
Expand All @@ -157,8 +172,7 @@ mod tests {
);

assert_eq!(nodes.len(), 1);
assert_eq!(nodes[0].label, "Root");
assert_eq!(nodes[0].children.len(), 0);
assert_eq!(nodes[0].label, "Root\\nhello world");
}

#[test]
Expand Down

0 comments on commit 739f945

Please sign in to comment.