Coverage for src/markdown_exec/formatters/tree.py: 69.64%

42 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-16 20:19 +0200

1"""Formatter for file-system trees.""" 

2 

3from __future__ import annotations 

4 

5from textwrap import dedent 

6from typing import TYPE_CHECKING, Any 

7 

8from markdown_exec.rendering import MarkdownConverter, code_block 

9 

10if TYPE_CHECKING: 

11 from markdown import Markdown 

12 

13 

14def _rec_build_tree(lines: list[str], parent: list, offset: int, base_indent: int) -> int: 

15 while offset < len(lines): 

16 line = lines[offset] 

17 lstripped = line.lstrip() 

18 indent = len(line) - len(lstripped) 

19 if indent == base_indent: 19 ↛ 22line 19 didn't jump to line 22, because the condition on line 19 was never false

20 parent.append((lstripped, [])) 

21 offset += 1 

22 elif indent > base_indent: 

23 offset = _rec_build_tree(lines, parent[-1][1], offset, indent) 

24 else: 

25 return offset 

26 return offset 

27 

28 

29def _build_tree(code: str) -> list[tuple[str, list]]: 

30 lines = dedent(code.strip()).split("\n") 

31 root_layer: list[tuple[str, list]] = [] 

32 _rec_build_tree(lines, root_layer, 0, 0) 

33 return root_layer 

34 

35 

36def _rec_format_tree(tree: list[tuple[str, list]], *, root: bool = True) -> list[str]: 

37 lines = [] 

38 n_items = len(tree) 

39 for index, node in enumerate(tree): 

40 last = index == n_items - 1 

41 prefix = "" if root else f"{'└' if last else '├'}── " 

42 if node[1]: 42 ↛ 43line 42 didn't jump to line 43, because the condition on line 42 was never true

43 lines.append(f"{prefix}📁 {node[0]}") 

44 sublines = _rec_format_tree(node[1], root=False) 

45 if root: 

46 lines.extend(sublines) 

47 else: 

48 indent_char = " " if last else "│" 

49 lines.extend([f"{indent_char} {line}" for line in sublines]) 

50 else: 

51 name = node[0].split()[0] 

52 icon = "📁" if name.endswith("/") else "📄" 

53 lines.append(f"{prefix}{icon} {node[0]}") 

54 return lines 

55 

56 

57def _format_tree(code: str, md: Markdown, result: str, **options: Any) -> str: 

58 markdown = MarkdownConverter(md) 

59 output = "\n".join(_rec_format_tree(_build_tree(code))) 

60 return markdown.convert(code_block(result or "bash", output, **options.get("extra", {})))