Skip to content

Commit ff4b876

Browse files
authored
Create term.hcs
1 parent 5f9fc05 commit ff4b876

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

libs/std/lib/term.hcs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
get <std:env> import <env_var_present>
2+
3+
!! -- kody ANSI SGR (Select Graphic Rendition) -------------------------------
4+
!! (funkcje, NIE consts - patrz uzasadnienie na gorze pliku)
5+
6+
fun ansi_reset() -> Str [ end "\e[0m" ]
7+
fun ansi_bold() -> Str [ end "\e[1m" ]
8+
fun ansi_dim() -> Str [ end "\e[2m" ]
9+
fun ansi_red() -> Str [ end "\e[31m" ]
10+
fun ansi_green() -> Str [ end "\e[32m" ]
11+
fun ansi_yellow() -> Str [ end "\e[33m" ]
12+
fun ansi_blue() -> Str [ end "\e[34m" ]
13+
fun ansi_magenta() -> Str [ end "\e[35m" ]
14+
fun ansi_cyan() -> Str [ end "\e[36m" ]
15+
fun ansi_gray() -> Str [ end "\e[90m" ]
16+
fun ansi_bold_green() -> Str [ end "\e[1;32m" ]
17+
fun ansi_bold_red() -> Str [ end "\e[1;31m" ]
18+
fun ansi_bold_yellow() -> Str [ end "\e[1;33m" ]
19+
fun ansi_bold_cyan() -> Str [ end "\e[1;36m" ]
20+
21+
!! Kursor o JEDNA linie w gore (`\e[1A`) + czysci CALA biezaca linie
22+
!! (`\e[2K`) - podstawa "nadpisywanego w miejscu" paska postepu, patrz
23+
!! `print_progress_line`.
24+
fun ansi_cursor_up_clear() -> Str [ end "\e[1A\e[2K" ]
25+
26+
!!! `true` jesli terminal MOZE pokazywac kolory - respektuje TYLKO
27+
!!! `NO_COLOR` (https://no-color.org). Ten bootstrap nie ma dostepu do
28+
!!! `isatty()`/`termios`, wiec (w odroznieniu od np. `rustc`) NIE
29+
!!! wykrywa automatycznie przekierowania do pliku/potoku - jesli to
30+
!!! problem, ustaw `NO_COLOR=1` recznie w skryptach CI.
31+
fun term_color_enabled() -> Bool [
32+
end not env_var_present("NO_COLOR")
33+
]
34+
35+
!!! Owija `text` kodem `color` + reset, ALBO zwraca `text` bez zmian gdy
36+
!!! `term_color_enabled()` jest `false` - wszystkie `c_*` ponizej sa
37+
!!! cienkimi opakowaniami tej funkcji.
38+
fun colorize(text: Str, color: Str) -> Str [
39+
if term_color_enabled() [
40+
end color + text + ansi_reset()
41+
]
42+
end text
43+
]
44+
45+
fun c_red(text: Str) -> Str [
46+
end colorize(text, ansi_red())
47+
]
48+
49+
fun c_green(text: Str) -> Str [
50+
end colorize(text, ansi_green())
51+
]
52+
53+
fun c_yellow(text: Str) -> Str [
54+
end colorize(text, ansi_yellow())
55+
]
56+
57+
fun c_blue(text: Str) -> Str [
58+
end colorize(text, ansi_blue())
59+
]
60+
61+
fun c_magenta(text: Str) -> Str [
62+
end colorize(text, ansi_magenta())
63+
]
64+
65+
fun c_cyan(text: Str) -> Str [
66+
end colorize(text, ansi_cyan())
67+
]
68+
69+
fun c_gray(text: Str) -> Str [
70+
end colorize(text, ansi_gray())
71+
]
72+
73+
fun c_bold(text: Str) -> Str [
74+
end colorize(text, ansi_bold())
75+
]
76+
77+
fun c_dim(text: Str) -> Str [
78+
end colorize(text, ansi_dim())
79+
]
80+
81+
fun c_bold_green(text: Str) -> Str [
82+
end colorize(text, ansi_bold_green())
83+
]
84+
85+
fun c_bold_red(text: Str) -> Str [
86+
end colorize(text, ansi_bold_red())
87+
]
88+
89+
fun c_bold_yellow(text: Str) -> Str [
90+
end colorize(text, ansi_bold_yellow())
91+
]
92+
93+
fun c_bold_cyan(text: Str) -> Str [
94+
end colorize(text, ansi_bold_cyan())
95+
]
96+
97+
!! -- pasek postepu -----------------------------------------------------------
98+
99+
!!! Procent `current/total` jako `Int` w zakresie `[0, 100]` -
100+
!!! `total <= 0` daje `0` zamiast dzielenia przez zero.
101+
fun progress_percent(current: Int, total: Int) -> Int [
102+
if total <= 0 [
103+
end 0
104+
]
105+
let pct = (current * 100) / total
106+
if pct > 100 [
107+
end 100
108+
]
109+
if pct < 0 [
110+
end 0
111+
]
112+
end pct
113+
]
114+
115+
!!! Buduje SAM pasek (bez etykiety/procentu) szerokosci `width` znakow,
116+
!!! np. `"██████████░░░░░░░░░░"` dla 50% przy `width = 20` - pelne bloki
117+
!!! `█` (U+2588) dla ukonczonej czesci, puste `░` (U+2591) dla reszty.
118+
fun render_bar_fill(current: Int, total: Int, width: Int) -> Str [
119+
let pct = progress_percent(current, total)
120+
let filled = (width * pct) / 100
121+
let bar = ""
122+
let i = 0
123+
while i < width [
124+
if i < filled [
125+
bar = bar + "█"
126+
] else [
127+
bar = bar + "░"
128+
]
129+
i = i + 1
130+
]
131+
end bar
132+
]
133+
134+
!!! `render_bar_fill` + kolor zalezny od postepu (zolty < 50%, cyan
135+
!!! 50-99%, zielony przy 100%) + nawiasy kwadratowe + procent, np.
136+
!!! `"[████████████░░░░░░░░░░░░] 50%"`.
137+
fun render_bar(current: Int, total: Int, width: Int) -> Str [
138+
let pct = progress_percent(current, total)
139+
let fill = render_bar_fill(current, total, width)
140+
let colored = fill
141+
if pct >= 100 [
142+
colored = c_green(fill)
143+
] elif pct >= 50 [
144+
colored = c_cyan(fill)
145+
] else [
146+
colored = c_yellow(fill)
147+
]
148+
end "[" + colored + "] " + (pct as Str) + "%"
149+
]
150+
151+
!!! Cala linia paska postepu z etykieta krokow (`==>` na zielono),
152+
!!! samym paskiem (szerokosc 24 znakow) i licznikiem `(current/total)`,
153+
!!! np. `"==> Kompilacja [████████░░░░░░░░░░░░░░░░] 33% (1/3) lexer.hcs"`.
154+
fun render_progress_line(label: Str, current: Int, total: Int, item: Str) -> Str [
155+
let counter = "(" + (current as Str) + "/" + (total as Str) + ")"
156+
let prefix = c_bold_green("==>")
157+
if label.len() > 0 [
158+
prefix = prefix + " " + label
159+
]
160+
end prefix + " " + render_bar(current, total, 24) + " " + c_gray(counter) + " " + item
161+
]
162+
163+
!!! Wypisuje `render_progress_line` - dla `is_first = true` po prostu
164+
!!! `log()`-uje (pierwsza linia sekwencji, nic do nadpisania), dla
165+
!!! kolejnych wywolan dokleja wynik `ansi_cursor_up_clear()` PRZED
166+
!!! tresc, wiec terminal wyswietla to jako JEDNA aktualizowana w
167+
!!! miejscu linie zamiast serii nowych linii - dziala WYLACZNIE bo
168+
!!! `log()` zawsze konczy `println!` (patrz
169+
!!! hackerc/cmd/codegen.hcs::gen_log): kody ANSI wewnatrz tresci linii
170+
!!! sa interpretowane przez terminal niezaleznie od tego skad
171+
!!! pochodza w strumieniu wyjscia.
172+
fun print_progress_line(label: Str, current: Int, total: Int, item: Str, is_first: Bool) [
173+
let line = render_progress_line(label, current, total, item)
174+
if is_first [
175+
log(line)
176+
] else [
177+
log(ansi_cursor_up_clear() + line)
178+
]
179+
]

0 commit comments

Comments
 (0)