1時間プログラミング 013 リスト形式のツリーをtreeコマンド風の出力に変更する
概要
以下のようなツリー構造をtreeコマンド風の出力に変更する
code:markdown
- dir1
- dir2
- file1
- dir3
- file2
所要時間: 2時間 + 1時間(後で機能を足したりリファクタリングなどをした)
使い方
code:console
$ cat sample/list1.md
- 1a
- 2a
- 2b
- 3a
- 2c
- 3b
1b
2d
2e
3c
2f
3d
$ cat sample/list1.md | cargo run
1a
├── 2a
├── 2b
│ └── 3a
└── 2c
└── 3b
1b
├── 2d
├── 2e
│ └── 3c
└── 2f
└── 3d
実装メモ
久しぶりにRustでCLIツールを書いた
いつの間にかclapにstructopt的な機能が入っていて驚いた リスト形式をツリー構造に変更する
ある行を基準として、その行よりもインデントが深い場合は子供として扱う
code:text
- 1a # 2a, 2b, 2c が子供
- 2a
- 2b # 3aが子供
- 3a
- 2c # 3bが子供
- 3b
再帰的にツリー構造を作っていく
code:rust
struct ListStyleTree {
content: String,
children: Vec<ListStyleTree>,
_start_line_pos: usize,
end_line_pos: usize,
}
impl ListStyleTree {
pub fn new(lines: Vec<String>) -> Self {
// ...
Self::from_lines_rec(0, &lines)
}
fn from_lines_rec(line_pos: usize, lines: &String) -> Self { let content = Self::line_content(&line);
let indent = Self::line_indent(&line);
let mut next_line_pos = line_pos + 1;
let mut children = Vec::new();
while next_line_pos < lines.len() {
if next_line_indent <= indent {
break;
}
let child = Self::from_lines_rec(next_line_pos, lines);
next_line_pos = child.end_line_pos + 1;
children.push(child);
}
Self {
content,
children,
_start_line_pos: line_pos,
end_line_pos: next_line_pos - 1,
}
}
}
ツリー構造を出力する
感想
久しぶりにRustでCLIツールを書いたので、かなり手間取った
仕事でRustを書くので普段使いの言語として練度を上げていきたい