Skip to content

Commit

Permalink
Parse Markdown Non-title Lines (#26)
Browse files Browse the repository at this point in the history
* Parse Markdown Non-title Lines

Also added two alias for V and H.

* Update readme

* Update version number
  • Loading branch information
yzhong52 authored Aug 8, 2024
1 parent fc3c213 commit eef3f57
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 56 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "astree"
version = "0.2.7"
version = "0.2.8"
license = "MIT OR Apache-2.0"
description = " A command line tool for drawing tree structures with ascii characters"
readme = "README.md"
Expand Down
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
83 changes: 50 additions & 33 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ A command line tool for drawing tree structures with ascii characters.
- [Virtual Tree Styles](#virtual-tree-styles)
- [Virtual Tree Maximum Label Width](#virtual-tree-maximum-label-width)
- [Virtual Tree Horizontal Spacing](#virtual-tree-horizontal-spacing)
- [Virtual Tree Multi Lines](#virtual-tree-multi-lines)
- [Development](#development)

## Usage
Expand All @@ -23,14 +24,14 @@ cargo install astree
Check out the help message:

```
$ astree -h
$ astree -h
A command line tool for drawing tree structures with ascii characters
Usage: astree <COMMAND>
Commands:
vertical Print the tree virtually
horizontal Print the tree horizontally
vertical Print the tree virtually. Use 'v' for shorthand
horizontal Print the tree horizontally. Use 'h' for shorthand
help Print this message or the help of the given subcommand(s)
Options:
Expand All @@ -50,7 +51,7 @@ EOF
)"
```

Here, each additional `#` indicates a nested child.
Here, each additional `#` indicates a nested child.

Output:

Expand Down Expand Up @@ -104,7 +105,7 @@ Root

Example of drawing a tree with multiple root nodes:
```
$ astree horizontal -i examples/multi_tree.md
$ astree horizontal -i examples/multi_tree.md
.
├─ Root 1
│ ├─ Child 1.1
Expand Down Expand Up @@ -135,21 +136,21 @@ astree vertical --input examples/with_grandchildren_1.md
Example of drawing a forest with multiple root nodes:

```
$ astree vertical -i examples/multi_tree.md
┌────────┐
│ Root 1 │
└───┬────┘
┌──────────────┴──────────────┐
$ astree vertical -i examples/multi_tree.md
┌────────┐
│ Root 1 │
└───┬────┘
┌──────────────┴──────────────┐
┌─────┴─────┐ ┌─────┴─────┐
│ Child 1.1 │ │ Child 1.2 │
└─────┬─────┘ └───────────┘
┌──────────┴──────────┐
┌────────┴─────────┐ ┌────────┴─────────┐
│ Grandchild 1.1.1 │ │ Grandchild 1.1.2 │
└──────────────────┘ └──────────────────┘
┌────────┐
│ Root 2 │
└───┬────┘
┌──────────┴──────────┐
┌────────┴─────────┐ ┌────────┴─────────┐
│ Grandchild 1.1.1 │ │ Grandchild 1.1.2 │
└──────────────────┘ └──────────────────┘
┌────────┐
│ Root 2 │
└───┬────┘
┌─────┴─────┐
│ Child 2.1 │
└───────────┘
Expand Down Expand Up @@ -228,11 +229,11 @@ To specify the maximum width of the label with `--width <WIDTH>`. For example:

```
astree vertical --input examples/with_long_label.md --width 10
┌──────────┐
│ A Simple │
│ Root │
└────┬─────┘
┌─────┴──────┐
┌──────────┐
│ A Simple │
│ Root │
└────┬─────┘
┌─────┴──────┐
┌───┴────┐ ┌────┴────┐
│ A long │ │ Another │
│ child │ │ long │
Expand All @@ -246,30 +247,46 @@ By default, there is a two-spaces gap between boxes. This can be set with `--spa

```
astree vertical --input examples/with_many_children.md --width 10 --spacing 0
┌──────────┐
│ A Simple │
│ Root │
└────┬─────┘
┌──────────┬────┴─────┬──────────┐
┌──────────┐
│ A Simple │
│ Root │
└────┬─────┘
┌──────────┬────┴─────┬──────────┐
┌───┴────┐┌────┴────┐┌────┴────┐┌────┴─────┐
│ A long ││ Another ││ A third ││ One more │
│ child ││ long ││ child ││ child │
└────────┘│ child │└─────────┘└──────────┘
└─────────┘
└─────────┘
astree vertical --input examples/with_many_children.md --width 10 --spacing 10
┌──────────┐
│ A Simple │
│ Root │
└────┬─────┘
┌─────────┴──────────┐
┌──────────┐
│ A Simple │
│ Root │
└────┬─────┘
┌─────────┴──────────┐
┌───┴────┐ ┌────┴────┐
│ A long │ │ Another │
│ child │ │ long │
└────────┘ │ child │
└─────────┘
```

#### Virtual Tree Multi Lines

Title lines in your Markdown file define the tree structure. Any content under a title is automatically included as separate lines within the same structural level.

```
astree vertical --input examples/with_content.md
┌──────┐
│ Root │
└──┬───┘
┌───────┴────────┐
┌─────┴──────┐ ┌──────┴──────┐
│ Left Child │ │ Right Child │
│ Quota: 100 │ │ Quota: 200 │
└────────────┘ └─────────────┘
```

## Development

See [development.md](./development.md).
6 changes: 4 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ impl Args {

#[derive(Subcommand, Debug)]
pub enum Command {
/// Print the tree virtually
/// Print the tree virtually. Use 'v' for shorthand.
#[clap(alias = "v")]
Vertical(VerticalArgs),
/// Print the tree horizontally
/// Print the tree horizontally. Use 'h' for shorthand.
#[clap(alias = "h")]
Horizontal(HorizontalArgs),
}

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 eef3f57

Please sign in to comment.