profview.bend

cswap-bend-cli@0.1.0.0 · 201 lines · 32 definitions

1import Base
2import cswap-bend-cli@0.1.0.0/json.bend as Json
3import cswap-bend-cli@0.1.0.0/act.bend as Act
4import cswap-bend-cli@0.1.0.0/cmd.bend as Cmd
5import cswap-bend-cli@0.1.0.0/fs.bend as Fs
6import cswap-bend-cli@0.1.0.0/setload.bend as Setload
7import cswap-bend-cli@0.1.0.0/setwrite.bend as Setwrite
8import cswap-bend-cli@0.1.0.0/profile.bend as P
9import cswap-bend-cli@0.1.0.0/policy/safe.bend as SF
10import cswap-bend-cli@0.1.0.0/daemon/config.bend as Cfg
11import cswap-bend-cli@0.1.0.0/daemon/events.bend as Ev
12
13# How `cswap profile` prints profiles: JSON and the table.
14# (`cswap profile list|show|use|set|remove` is src/profcmd.bend.)
15# The profiles live in settings.json (src/profile.bend);
16# a write changes only `profiles` / `active_profile` and keeps every other key.
17
18# ------------------------------------------------------------------ views
19
20def is_active.of(+a: Maybe<&2, String>, +name: String) -> Bool:
21  match a:
22    case Some{x}:
23      String.eq(x, name)
24    case None{}:
25      String.eq(name, "default")
26
27# `default` is the active profile while `active_profile` is unset.
28def is_active(+raw: Json.Json, +name: String) -> Bool:
29  is_active.of(P.active(raw), name)
30
31def opt_json(+m: Maybe<&2, Json.Json>) -> Json.Json:
32  match m:
33    case Some{j}:
34      j
35    case None{}:
36      Json.JNull{}
37
38def models_arr(+ms: List<&2, String>) -> Json.Json:
39  Json.arr(P.strs_json(ms))
40
41def eff_json(+e: Cfg.Cfg) -> Json.Json:
42  Json.of_pairs([("strategy", Json.JStr{Cfg.cfg_strategy(e)}), ("threshold", Ev.fl(Cfg.cfg_threshold(e))), ("models", models_arr(Cfg.cfg_models(e))),
43    ("cooldown_s", Json.JNum{U32.show(Cfg.cfg_cooldown(e))}), ("interval_s", Json.JNum{U32.show(Cfg.cfg_interval(e))})])
44
45def num_or_null(+m: Maybe<&2, String>) -> Json.Json:
46  opt_json(P.num_json(m))
47
48def prof_json2(+p: P.Prof, +is_builtin: Bool, +stored: Bool, +active: Bool, +e: Cfg.Cfg) -> Json.Json:
49  match p:
50    case P.Prof{n, algo, th, ms, cd, iv}:
51      Json.of_pairs([("name", Json.JStr{n}), ("builtin", Json.JBool{is_builtin}), ("stored", Json.JBool{stored}), ("active", Json.JBool{active}),
52        ("strategy", Json.JStr{SF.name(algo)}), ("threshold", num_or_null(th)), ("models", opt_json(P.models_json(ms))), ("cooldown_s", num_or_null(cd)),
53        ("interval_s", num_or_null(iv)), ("effective", eff_json(e))])
54
55# A profile as the commands print it: what it sets, and what it comes to over the settings.
56def prof_json(+raw: Json.Json, +cfg: Cfg.Cfg, +p: P.Prof) -> Json.Json:
57  prof_json2(p, P.is_builtin(P.name_of(p)), P.has_stored(raw, P.name_of(p)), is_active(raw, P.name_of(p)), P.with_prof(cfg, p))
58
59def cell(+set: Maybe<&2, String>, +eff: String) -> String:
60  match set:
61    case Some{t}:
62      t
63    case None{}:
64      "(" ++ eff ++ ")"
65
66def models_eff(+ms: List<&2, String>) -> String:
67  match ms:
68    case Nil{}:
69      "all"
70    case o:
71      String.join(ms, ",")
72
73def models_cell(+set: Maybe<&2, String>, +eff: List<&2, String>) -> String:
74  match set:
75    case Some{t}:
76      models_eff(Cfg.parse_models(t))
77    case None{}:
78      "(" ++ models_eff(eff) ++ ")"
79
80type Row is Data:
81  Row{mark: String, name: String, strategy: String, threshold: String, models: String, cooldown: String, interval: String, source: String}
82
83def source_of(+is_builtin: Bool, +stored: Bool) -> String:
84  match is_builtin stored:
85    case True{} True{}:
86      "built-in, overridden"
87    case True{} False{}:
88      "built-in"
89    case False{} _:
90      "custom"
91
92def row_of2(+p: P.Prof, +mark: String, +src: String, +e: Cfg.Cfg) -> Row:
93  match p:
94    case P.Prof{n, algo, th, ms, cd, iv}:
95      Row{mark, n, SF.name(algo), cell(th, Ev.pct_label(Cfg.cfg_threshold(e))), models_cell(ms, Cfg.cfg_models(e)), cell(cd, U32.show(Cfg.cfg_cooldown(e))), cell(iv, U32.show(Cfg.cfg_interval(e))), src}
96
97def mark(+active: Bool) -> String:
98  match active:
99    case True{}:
100      "*"
101    case False{}:
102      " "
103
104def row_of(+raw: Json.Json, +cfg: Cfg.Cfg, +p: P.Prof) -> Row:
105  row_of2(p, mark(is_active(raw, P.name_of(p))), source_of(P.is_builtin(P.name_of(p)), P.has_stored(raw, P.name_of(p))), P.with_prof(cfg, p))
106
107def rows_push(+m: Maybe<&2, P.Prof>, +raw: Json.Json, +cfg: Cfg.Cfg, +rest: List<&2, Row>) -> List<&2, Row>:
108  match m:
109    case Some{p}:
110      row_of(raw, cfg, p) <> rest
111    case None{}:
112      rest
113
114def rows_of(+raw: Json.Json, +cfg: Cfg.Cfg, +ns: List<&2, String>) -> List<&2, Row>:
115  match ns:
116    case Nil{}:
117      []
118    case Con{n, t}:
119      rows_push(P.find(raw, n), raw, cfg, rows_of(raw, cfg, t))
120
121def header() -> Row:
122  Row{" ", "NAME", "STRATEGY", "THRESHOLD", "MODELS", "COOLDOWN_S", "INTERVAL_S", "SOURCE"}
123
124def col_name(+rs: List<&2, Row>) -> List<&2, String>:
125  match rs:
126    case Nil{}:
127      []
128    case Con{Row{m, n, s, t, ms, c, i, src}, t2}:
129      n <> col_name(t2)
130
131def col_strategy(+rs: List<&2, Row>) -> List<&2, String>:
132  match rs:
133    case Nil{}:
134      []
135    case Con{Row{m, n, s, t, ms, c, i, src}, t2}:
136      s <> col_strategy(t2)
137
138def col_threshold(+rs: List<&2, Row>) -> List<&2, String>:
139  match rs:
140    case Nil{}:
141      []
142    case Con{Row{m, n, s, t, ms, c, i, src}, t2}:
143      t <> col_threshold(t2)
144
145def col_models(+rs: List<&2, Row>) -> List<&2, String>:
146  match rs:
147    case Nil{}:
148      []
149    case Con{Row{m, n, s, t, ms, c, i, src}, t2}:
150      ms <> col_models(t2)
151
152def col_cooldown(+rs: List<&2, Row>) -> List<&2, String>:
153  match rs:
154    case Nil{}:
155      []
156    case Con{Row{m, n, s, t, ms, c, i, src}, t2}:
157      c <> col_cooldown(t2)
158
159def col_interval(+rs: List<&2, Row>) -> List<&2, String>:
160  match rs:
161    case Nil{}:
162      []
163    case Con{Row{m, n, s, t, ms, c, i, src}, t2}:
164      i <> col_interval(t2)
165
166type Widths is Data:
167  Widths{n: Nat, s: Nat, t: Nat, m: Nat, c: Nat, i: Nat}
168
169def widths(+rs: List<&2, Row>) -> Widths:
170  Widths{Setwrite.width(col_name(rs), 0n), Setwrite.width(col_strategy(rs), 0n), Setwrite.width(col_threshold(rs), 0n), Setwrite.width(col_models(rs), 0n), Setwrite.width(col_cooldown(rs), 0n), Setwrite.width(col_interval(rs), 0n)}
171
172def line(+w: Widths, +r: Row) -> String:
173  match w r:
174    case Widths{wn, ws, wt, wm, wc, wi} Row{m, n, s, t, ms, c, i, src}:
175      m ++ " " ++ Setwrite.pad(n, wn) ++ "  " ++ Setwrite.pad(s, ws) ++ "  " ++ Setwrite.pad(t, wt) ++ "  " ++ Setwrite.pad(ms, wm) ++ "  " ++ Setwrite.pad(c, wc) ++ "  " ++ Setwrite.pad(i, wi) ++ "  " ++ src
176
177def lines(+w: Widths, +rs: List<&2, Row>) -> List<&2, String>:
178  match rs:
179    case Nil{}:
180      []
181    case Con{r, t}:
182      line(w, r) <> lines(w, t)
183
184# A table; a parenthesised cell is inherited from the autoswitch settings.
185def table(+rs: List<&2, Row>) -> String:
186  String.join(lines(widths(Con{header(), rs}), Con{header(), rs}), "\n")
187
188def prof_push(+m: Maybe<&2, P.Prof>, +raw: Json.Json, +cfg: Cfg.Cfg, +rest: List<&2, Json.Json>) -> List<&2, Json.Json>:
189  match m:
190    case Some{p}:
191      prof_json(raw, cfg, p) <> rest
192    case None{}:
193      rest
194
195def prof_jsons(+raw: Json.Json, +cfg: Cfg.Cfg, +ns: List<&2, String>) -> List<&2, Json.Json>:
196  match ns:
197    case Nil{}:
198      []
199    case Con{n, t}:
200      prof_push(P.find(raw, n), raw, cfg, prof_jsons(raw, cfg, t))
201