package passage

  1. Overview
  2. Docs

Source file dirtree.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
open Printf
open Storage.Secrets

type t =
  | D of node list
  | F of unit outcome
and node = string * t

type top = Top of node

(* always recurse on directories and keep files with extension [ext] *)
let ext_filt ext base nm sub =
  let full = Fpath.add_seg base nm in
  let s = Fpath.to_string full in
  try
    if Sys.is_directory s then (
      let sf = sub full in
      Some (nm, D sf))
    else if FileUtil.test FileUtil.Is_file s && Fpath.has_ext ext full then (
      let name = name_of_file (Path.of_fpath full) in
      let res =
        try
          match is_recipient_of_secret (get_own_key ()) name with
          | false -> Skipped
          | true ->
          match decrypt_exn ~silence_stderr:true name with
          | exception exn -> Failed exn
          | _ -> Succeeded ()
        with _ -> Skipped
      in
      Some (Fpath.(to_string @@ rem_ext (v nm)), F res))
    else None
  with _ -> None

let of_path path =
  let rec sub p =
    let names = Sys.readdir (Fpath.to_string p) in
    Array.sort compare names;
    names |> Array.to_list |> List.filter_map (fun v -> ext_filt ext p v sub)
  in
  let sp = sub path in
  Top (Fpath.to_string path, D sp)

let bar = "│   "
let mid = "├── "
let el = "└── "
let space = "    "

let to_pref_str is_last_l =
  let rec p_aux acc d =
    match d with
    | [] -> String.concat "" acc
    | v :: rest -> p_aux ((if v then space else bar) :: acc) rest
  in
  match is_last_l with
  | v :: rest -> if v then p_aux [ el ] rest else p_aux [ mid ] rest
  | [] -> ""

let p buf d s =
  Buffer.add_string buf (to_pref_str d);
  Buffer.add_string buf s;
  Buffer.add_char buf '\n'

(* call a different function for the last item *)
let rec iter_but_one f lastf l =
  match l with
  | [] -> ()
  | [ i ] -> lastf i
  | i :: rest ->
    let () = f i in
    iter_but_one f lastf rest

let red = "31"
let blue = "34"
let green = "32"

let color c s = sprintf "\027[01;%sm%s\027[00m" c s

let rec pp_node buf d n =
  match n with
  | nm, F r ->
    (match r with
    | Succeeded _ -> p buf d (color green nm)
    | Failed _ -> p buf d (color red nm)
    | _ -> p buf d nm)
  | nm, D nl ->
    let () = p buf d (color blue nm) in
    iter_but_one (pp_node buf (false :: d)) (pp_node buf (true :: d)) nl

let pp t =
  let buf = Buffer.create 256 in
  match t with
  | Top (_, D l) ->
    Buffer.add_string buf ".\n";
    iter_but_one (pp_node buf [ false ]) (pp_node buf [ true ]) l;
    Buffer.contents buf
  | Top (_, F _) -> ""