aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore3
-rw-r--r--.gitmodules3
-rw-r--r--Makefile46
-rw-r--r--README.md87
-rw-r--r--demo/colors16/color16.ha65
-rw-r--r--demo/fullcolor/fullcolor.ha59
-rw-r--r--demo/hjkl/hjkl.ha190
-rw-r--r--demo/size/size.ha35
-rw-r--r--termbox2/README41
-rw-r--r--termbox2/attrw+attrw16.ha35
-rw-r--r--termbox2/attrw+attrw32.ha35
-rw-r--r--termbox2/attrw.ha39
-rw-r--r--termbox2/egc+noegc.ha30
-rw-r--r--termbox2/egc.ha31
-rw-r--r--termbox2/termbox2.ha605
m---------vendor/termbox20
16 files changed, 1304 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..65c3d19
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
1TODO
2build
3**/*.o
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..6714657
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
1[submodule "vendor/termbox2"]
2 path = vendor/termbox2
3 url = https://github.com/termbox/termbox2
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ef76fbd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,46 @@
1HARE=hare
2DESTDIR=
3PREFIX=/usr/local
4SRCDIR=$(PREFIX)/src
5HARESRCDIR=$(SRCDIR)/hare
6THIRDPARTYDIR=$(HARESRCDIR)/third-party
7
8TB_DIR=vendor/termbox2
9TB_OBJ=termbox2.o
10BUILD_DIR=build
11DEMO_DIR=demo
12
13all: demos
14
15install:
16 install -Dm644 termbox2/* $(DESTDIR)$(THIRDPARTYDIR)/termbox2/
17
18uninstall:
19 rm -rf $(DESTDIR)$(THIRDPARTYDIR)/termbox2
20
21demos: $(BUILD_DIR)
22 mkdir -p $(BUILD_DIR)/$(DEMO_DIR)
23 for d in $(DEMO_DIR)/*; \
24 do $(HARE) build -ltermbox2 -o $(BUILD_DIR)/$$d $$d; \
25 done
26
27local: $(BUILD_DIR) termbox2/$(TB_OBJ)
28 mkdir -p $(BUILD_DIR)/$(DEMO_DIR)
29 for d in $(DEMO_DIR)/*; \
30 do $(HARE) build -lc -o $(BUILD_DIR)/$$d $$d; \
31 done
32
33$(BUILD_DIR):
34 mkdir -p $(BUILD_DIR)
35
36termbox2/$(TB_OBJ): $(TB_DIR)/termbox2.o
37 cp $(TB_DIR)/termbox2.o termbox2/
38
39$(TB_DIR)/termbox2.o:
40 cd $(TB_DIR) && make termbox2.o
41
42clean:
43 rm -rf $(BUILD_DIR) termbox2/$(TB_OBJ)
44 [ -d $(TB_DIR) ] && cd $(TB_DIR) && make clean
45
46.PHONY: all clean demos install local-demos uninstall
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7620429
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
1# Hare bindings for termbox2
2
3This repository contains [hare](https://harelang.org) bindings for the
4terminal I/O library [termbox2](https://github.com/termbox/termbox2).
5
6There are some differences between the Hare bindings and the original
7C code, for example the fact that the prefixes `tb_` and `TB_` have been
8replaced by the namespace `termbox2::`. See the haredoc documentation
9in `termbox2/README` for more information.
10
11## Using this library
12
13There are two ways to build termbox2 for this library. Both involve
14building termbox2 as a standalone library or object file, rather than
15including it as a header-only library as one could do in a C program.
16
17### Using the system's termbox2 (default)
18
19This method assumes that termbox2 is already installed as a library
20system-wide, for example by using your OS's package manager or by
21installing it from source using `make install_lib`.
22
23Once termbox2 is installed, you can run `make install`. This will
24copy the hare bindings to `/usr/local/src/hare/third-party/` so that
25you can include them in your Hare project as any other module. Do
26not forget to add the `-ltermbox2` option to build any program that
27uses this library.
28
29To uninstall the bindings, run `make uninstall`.
30
31You can also run `make demos` (or simply `make`) to build the demo
32programs contained in `demo/`, and then you can run them from the
33`build/` folder. For example, to run the `hjkl` demo you can run
34`make && ./build/demo/hjkl`.
35
36### Using a local termbox2
37
38This method is useful if you just want to experiment with termbox2
39programming in Hare, for example by running and modifying the demos
40in `demo/`, without installing anything system-wide.
41
42To do this, the original library is provided as a
43[git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
44in this repository. You can download it with:
45
46```
47git submodule init
48```
49
50(Alternative, you can place the source code for termbox2 in
51`vendor/termbox2`). Then you can build termbox2 locally with
52
53```
54make local
55```
56
57This will directly build all the demo programs from `demo/`, placing
58the resulting binaries in `build/demo`.
59
60Technical note: this will include the compiled termbox object file
61`termbox.o` directly in the compiled binaries.
62
63To build the demo programs using this method, run `make local-demos`.
64
65## Notes on build options
66
67The original termbox2 library offers several build options via `TB_OPT_*`
68constants. Two of them, `TB_OPT_ATTR_W` and `TB_OPT_EGC`, are relevant for
69the API.
70
71* `TB_OPT_ATTR_W` (in the Hare bindings: `termbox2::OPT_ATTR_W`) can be
72either `16`, `32` or `64`, and is used to enable more output attributer
73(e.g. truecolor). The termbox2 sources claim that the default value is
74`16`, but this is only true when including termbox2 as a header-only
75library. When building it as an external library, the default is `64`.
76Since these bindings are meant to be used with termbox2 compiled as an
77external library, we use `64` as default. The hare build tags `attrw16`
78and `attrw32` are offered if one wants to use a different value.
79
80* `TB_OPT_EGC` (in the Hare bindings: `termbox2::OPT_EGC`) can be set or
81not set (in the bindings: it is a boolean value, `true` for set, `false`
82for not set). Similarly to `TB_OPT_ATTR_W`, it is by default set when
83building termbox2 as an external library, unlike when including it as a
84header-only library. An `noegc` tag is available to disable this option.
85
86Note: the consistency of these two build options between the C library
87and the Hare bindings is checked and enforced in `termbox2::init()`.
diff --git a/demo/colors16/color16.ha b/demo/colors16/color16.ha
new file mode 100644
index 0000000..3121b93
--- /dev/null
+++ b/demo/colors16/color16.ha
@@ -0,0 +1,65 @@
1use fmt;
2use tb = termbox2;
3
4fn paint_cell(x: size, y: size, c: tb::uattr) void =
5 tb::set_cell(x: int, y: int, ' ', tb::COLOR.DEFAULT, c)!;
6
7fn show_colors() size = {
8 let colors = [
9 tb::COLOR.BLACK,
10 tb::COLOR.RED,
11 tb::COLOR.GREEN,
12 tb::COLOR.YELLOW,
13 tb::COLOR.BLUE,
14 tb::COLOR.MAGENTA,
15 tb::COLOR.CYAN,
16 tb::COLOR.WHITE,
17 ];
18
19 tb::print(0, 0, tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
20 "8 regular colors:")!;
21 tb::print(0, 2, tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
22 "8 bright colors:")!;
23 for (let i: size = 0; i < len(colors); i += 1) {
24 // 8 regular colors.
25 paint_cell(i, 1, colors[i]);
26
27 // 8 bright colors.
28 paint_cell(i, 3, colors[i] | tb::ATTRIBUTE.BRIGHT);
29 };
30
31 return 4;
32};
33
34export fn main() int = {
35 let e = tb::init();
36 if (e is tb::err)
37 fmt::fatalf(tb::strerror(e as tb::err));
38 defer tb::shutdown()!;
39
40 let w = tb::width()!;
41 let h = tb::height()!;
42 tb::print(0, (h - 1): int, tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
43 "Press any key to exit")!;
44
45 show_colors();
46
47 for (true) {
48 let e = tb::present();
49 if (e is tb::err)
50 fmt::fatalf(tb::strerror(e as tb::err));
51 match (tb::poll_event()) {
52 case let e: tb::err => {
53 if (e == tb::ERR.NO_EVENT)
54 continue
55 else
56 tb::print(0, h:int -1,
57 tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
58 "Unexpected error {}!", tb::strerror(e))!;
59 };
60 case tb::key_event => break;
61 case (tb::mouse_event | tb::resize_event) => continue;
62 };
63 };
64 return 0;
65};
diff --git a/demo/fullcolor/fullcolor.ha b/demo/fullcolor/fullcolor.ha
new file mode 100644
index 0000000..5d46c7c
--- /dev/null
+++ b/demo/fullcolor/fullcolor.ha
@@ -0,0 +1,59 @@
1use fmt;
2use tb = termbox2;
3
4fn paint_cell(x: size, y: size, c: tb::uattr) void =
5 tb::set_cell(x: int, y: int, ' ', tb::COLOR.DEFAULT, c)!;
6
7fn show_colors(wmin: size, hmin: size, wmax: size, hmax: size) void = {
8 tb::set_output_mode(tb::OUTPUT.TRUECOLOR)!;
9 tb::print(wmin: int, hmin: int, tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
10 "Color palette sample:")!;
11 hmin = hmin + 1;
12
13 let nsamples = (wmax - wmin +1) * (hmax - hmin + 1);
14 let step = 0xffffff / nsamples;
15 for (let y = hmin; y < hmax; y += 1) {
16 for (let x = wmin; x < wmax; x += 1) {
17 let c: tb::uattr = ((y - hmin) * wmax + (x - wmin)) * step;
18 paint_cell(x, y, c);
19 };
20 };
21};
22
23export fn main() int = {
24 let e = tb::init();
25 if (e is tb::err)
26 fmt::fatalf(tb::strerror(e as tb::err));
27 defer tb::shutdown()!;
28
29 let w = tb::width()!;
30 let h = tb::height()!;
31 tb::print(0, (h - 1): int, tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
32 "Press any key to exit")!;
33
34 switch (tb::OPT_ATTR_W) {
35 case 64 => show_colors(0, 0, w, h-1);
36 case => tb::print(0, ((h+1)/2): int, tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
37 "This demo is only available with truecolor support, here "
38 "tb::OPT_ATTR_W is {}", tb::OPT_ATTR_W)!;
39 };
40
41 for (true) {
42 let e = tb::present();
43 if (e is tb::err)
44 fmt::fatalf(tb::strerror(e as tb::err));
45 match (tb::poll_event()) {
46 case let e: tb::err => {
47 if (e == tb::ERR.NO_EVENT)
48 continue
49 else
50 tb::print(0, h:int -1,
51 tb::COLOR.DEFAULT, tb::COLOR.DEFAULT,
52 "Unexpected error {}!", tb::strerror(e))!;
53 };
54 case tb::key_event => break;
55 case (tb::mouse_event | tb::resize_event) => continue;
56 };
57 };
58 return 0;
59};
diff --git a/demo/hjkl/hjkl.ha b/demo/hjkl/hjkl.ha
new file mode 100644
index 0000000..487ebd3
--- /dev/null
+++ b/demo/hjkl/hjkl.ha
@@ -0,0 +1,190 @@
1use fmt;
2use tb = termbox2;
3
4def bg = tb::COLOR.DEFAULT;
5def fg = tb::COLOR.DEFAULT | tb::ATTRIBUTE.BOLD;
6def exit_help: str = "Use :q to exit (colon, q, enter). Sad to see you go :(";
7
8let wpos: (int, int) = (-1, -1);
9let msg: str = "Use HJKL to move the widget around";
10let colon_mode: bool = false;
11let exit_attempts: size = 0;
12
13type cmd = enum {
14 UP,
15 DOWN,
16 LEFT,
17 RIGHT,
18 COLON,
19 ARROW,
20 Q,
21 ENTER,
22 EXIT_ATTEMPT,
23 NONE,
24};
25
26fn draw_small_widget_thing(w: size, h: size) void = {
27 if (wpos.0 < 4) wpos.0 += 1
28 else if (wpos.0 > w: int - 5) wpos.0 -= 1
29 else if (wpos.1 < 2) wpos.1 += 1
30 else if (wpos.1 > h: int - 3) wpos.1 -= 1;
31
32 tb::print(wpos.0, wpos.1 - 1, fg, bg, "K")!;
33 tb::print(wpos.0, wpos.1 + 1, fg, bg, "J")!;
34 tb::print(wpos.0 - 2, wpos.1, fg, bg, "H + L")!;
35};
36
37fn paint(x: int, y: int, c: tb::uattr) void =
38 tb::set_cell(x, y, ' ', tb::COLOR.DEFAULT, c)!;
39
40fn paint_col3(x: int, y: int, c: tb::uattr) void = {
41 paint(x, y-1, c);
42 paint(x, y, c);
43 paint(x, y+1, c);
44};
45
46fn paint_row5(x: int, y: int, c: tb::uattr) void = {
47 paint(x-2, y, c);
48 paint(x-1, y, c);
49 paint(x, y, c);
50 paint(x+1, y, c);
51 paint(x+2, y, c);
52};
53
54fn paint_cell(x: int, y: int, c: tb::uattr, s: str) void = {
55 paint_col3(x-2, y, c);
56 paint_row5(x, y-1, c);
57 tb::print(x, y, fg, bg, s)!;
58 paint_row5(x, y+1, c);
59 paint_col3(x+2, y, c);
60};
61
62fn draw_large_widget_thing(w: size, h: size) void = {
63 if (wpos.0 < 10) wpos.0 += 1
64 else if (wpos.0 > w: int - 11) wpos.0 -= 1
65 else if (wpos.1 < 7) wpos.1 += 1
66 else if (wpos.1 > h: int - 8) wpos.1 -= 1;
67
68 let c = tb::COLOR.BLUE;
69 paint_cell(wpos.0-6, wpos.1, c, "H");
70 paint_cell(wpos.0+6, wpos.1, c, "L");
71 paint_cell(wpos.0, wpos.1-4, c, "K");
72 paint_cell(wpos.0, wpos.1+4, c, "J");
73 paint_col3(wpos.0, wpos.1, c);
74 paint_row5(wpos.0, wpos.1, c);
75};
76
77fn draw_widget_thing(w: size, h: size) void = {
78 if (w < 30 || h < 15)
79 draw_small_widget_thing(w, h)
80 else
81 draw_large_widget_thing(w, h);
82};
83
84fn draw_bottom_bar(w: size, h: size) void = {
85 tb::print(0, h: int - 1, fg, bg, msg)!;
86};
87
88fn handle_events_and_exit() bool = {
89 let e = tb::poll_event();
90 if (e is tb::err)
91 return false;
92
93 return match (e as tb::event) {
94 case tb::resize_event => yield false;
95 case tb::mouse_event => yield {
96 msg = "A mouse? Are you serious?";
97 yield false;
98 };
99 case let ke: tb::key_event => yield handle_key_event_and_exit(ke);
100 };
101};
102
103fn is_arrow(k: tb::key) bool =
104 k == tb::KEY.ARROW_UP || k == tb::KEY.ARROW_DOWN ||
105 k == tb::KEY.ARROW_LEFT || k == tb::KEY.ARROW_RIGHT;
106
107fn is_exit_attempt(k: tb::key) bool =
108 k == tb::KEY.CTRL_Q || k == tb::KEY.CTRL_C || k == tb::KEY.CTRL_X ||
109 k == tb::KEY.CTRL_Z || k == tb::KEY.CTRL_D ||
110 k == tb::KEY.DELETE || k == tb::KEY.BACKSPACE || k == tb::KEY.ESC;
111
112fn get_cmd(ke: tb::key_event) cmd = match (ke.key_or_ch) {
113 case let r: rune => yield
114 if (r == 'h') cmd::LEFT
115 else if (r == 'j') cmd::DOWN
116 else if (r == 'k') cmd::UP
117 else if (r == 'l') cmd::RIGHT
118 else if (r == ':') cmd::COLON
119 else if (r == 'q') cmd::Q
120 else if (r == 'Q') cmd::EXIT_ATTEMPT
121 else cmd::NONE;
122 case let k: tb::key => yield
123 if (k == tb::KEY.ENTER) cmd::ENTER
124 else if (is_arrow(k)) cmd::ARROW
125 else if (is_exit_attempt(k)) cmd::EXIT_ATTEMPT
126 else cmd::NONE;
127 };
128
129fn exit_attempt() void = {
130 exit_attempts += 1;
131 msg = if (exit_attempts < 3) "Trying to get out? :3"
132 else if (exit_attempts < 6) "It's just like Vim!"
133 else if (exit_attempts < 8) "Uhm no, that won't work"
134 else if (exit_attempts < 10) "Ok, I'll tell you..."
135 else exit_help;
136};
137
138fn handle_key_event_and_exit(ke: tb::key_event) bool = {
139 let c = get_cmd(ke);
140
141 if (c == cmd::COLON)
142 colon_mode = true;
143
144 if (colon_mode) {
145 if (msg == ":q" && c == cmd::ENTER)
146 return true;
147
148 msg = if (msg == ":") {
149 yield if (c == cmd::Q) ":q" else exit_help;
150 } else if (c == cmd::COLON) ":" else exit_help;
151
152 return false;
153 };
154
155 switch (c) {
156 case cmd::UP => wpos.1 -= 1;
157 case cmd::DOWN => wpos.1 += 1;
158 case cmd::LEFT => wpos.0 -= 1;
159 case cmd::RIGHT => wpos.0 += 1;
160 case cmd::ARROW => msg = "No arrows allowed!";
161 case cmd::COLON => colon_mode = true;
162 case cmd::EXIT_ATTEMPT => exit_attempt();
163 case cmd::Q => exit_attempt();
164 case => yield;
165 };
166
167 return false;
168};
169
170export fn main() void = {
171 let e = tb::init();
172 if (e is tb::err)
173 fmt::fatalf(tb::strerror(e as tb::err));
174 defer tb::shutdown()!;
175
176 wpos = (tb::width()!: int / 2, tb::height()!: int / 2);
177 for (true) {
178 tb::clear()!;
179
180 let w = tb::width()!;
181 let h = tb::height()!;
182
183 draw_widget_thing(w, h);
184 draw_bottom_bar(w, h);
185 tb::present()!;
186
187 if (handle_events_and_exit()) break;
188 };
189 return;
190};
diff --git a/demo/size/size.ha b/demo/size/size.ha
new file mode 100644
index 0000000..55b6a3c
--- /dev/null
+++ b/demo/size/size.ha
@@ -0,0 +1,35 @@
1use fmt;
2use tb = termbox2;
3
4export fn main() void = {
5 let e = tb::init();
6 if (e is tb::err)
7 fmt::fatalf(tb::strerror(e as tb::err));
8 defer tb::shutdown()!;
9
10 let w = tb::width()!;
11 let h = tb::height()!;
12 tb::print(0, 0, tb::COLOR.GREEN, tb::COLOR.BLACK,
13 "Terminal width: {}", w)!;
14 tb::print(0, 1, tb::COLOR.GREEN, tb::COLOR.BLACK,
15 "Terminal height: {}", h)!;
16 tb::print(0, 2, tb::COLOR.WHITE, tb::COLOR.BLACK,
17 "Press any key to exit")!;
18 for (true) {
19 let e = tb::present();
20 if (e is tb::err)
21 fmt::fatalf(tb::strerror(e as tb::err));
22 match (tb::poll_event()) {
23 case let e: tb::err => {
24 if (e == tb::ERR.NO_EVENT)
25 continue
26 else
27 tb::print(0, 4, tb::COLOR.WHITE, tb::COLOR.BLACK,
28 "Unexpected error {}!", tb::strerror(e))!;
29 };
30 case tb::key_event => break;
31 case (tb::mouse_event | tb::resize_event) => continue;
32 };
33 };
34 return;
35};
diff --git a/termbox2/README b/termbox2/README
new file mode 100644
index 0000000..e28c58c
--- /dev/null
+++ b/termbox2/README
@@ -0,0 +1,41 @@
1This module provides bindings for termbox2.
2
3Some changes to the API have been made to enable using this library in a
4more Hare-idiomatic style. In particular:
5- The tb_ and TB_ prefixes have been removed, as the namespace termbox2::
6is used instead. We recommend importing this library as tb, so that one
7can write e.g. tb::init(), keeping it similar to the original tb_init().
8- Functions return a value that can be either a valid result (e.g. int,
9void, str...) or an int-backed error [[termbox2::err]]. The error codes
10are consistent with the original library and can be interpreted with
11[[termbox2::strerror]]. Some additional codes for binding-related errors
12are provided.
13- Similarly to the previous point, some functions that use to return
14multiple values by taking pointer parameters now simply return a tuple,
15see for example [[termbox2::get_fds]].
16- The tb_event type has changed into a tagged union of 3 types,
17see [[termbox2::event]].
18- The four tb_print* functions have been replaced by a single
19[[termbox2::print]] function that uses Hare-style string formatting.
20Similarly, tb_send and tb_sendf have replaced by only one function
21[[termbox2::send]].
22- The constants provided by ther termbox2 API, such as those for key codes,
23colors and attributes, have been split into various structures, such as
24[[termbox2::KEY]], [[termbox2::COLOR]] and [[termbox2::ATTRIBUTE]].
25
26Some functionality has been outright removed. If you are interested in
27having any of the following available in these bindings, don't hesitate
28to send a patch or a feature request to sebastiano@tronto.net:
29- The tb_get_cell function is not available. This function makes it
30possible to navigate through cells via pointer arithmetic, but since
31the Hare [[termbox2::cell]] type does not have the same size as the
32original tb_cell, this would not translate cleanly.
33- The tb_iswprint, tb_wcwidth and tb_utf8_* have functions have been
34removed. Use the Hare standard libary functions [[encoding::utf8::]]
35and [[strings::]] instead.
36- The tb_last_errno function has been removed.
37- The TB_CAP_* code constants have been removed.
38
39Links:
40- Main repository: https://git.tronto.net/hare-termbox2
41- termbox2: https://github.com/termbox/termbox2
diff --git a/termbox2/attrw+attrw16.ha b/termbox2/attrw+attrw16.ha
new file mode 100644
index 0000000..69f457d
--- /dev/null
+++ b/termbox2/attrw+attrw16.ha
@@ -0,0 +1,35 @@
1// Integer width of fg and bg attributes. Valid values (assuming system
2// support) are 16, 32, and 64; see [[termbox2::uattr]]. 32 or 64 enables
3// OUTPUT.TRUECOLOR, see [[termbox2::OUTPUT]] and
4// [[termbox2::set_output_mode]]. 64 enables additional style attributes.
5// Larger values consume more memory in exchange for more features.
6// Defaults to 64.
7export def OPT_ATTR_W: size = 16;
8
9// Unsigned integer type for cell attributes, see [[termbox2::ATTRIBUTE]].
10export type uattr = u16;
11
12// Colors (bitwise), see [[termbox2::cell]].
13export def COLOR = struct {
14 DEFAULT: uattr = 0x0000,
15 BLACK: uattr = 0x0001,
16 RED: uattr = 0x0002,
17 GREEN: uattr = 0x0003,
18 YELLOW: uattr = 0x0004,
19 BLUE: uattr = 0x0005,
20 MAGENTA: uattr = 0x0006,
21 CYAN: uattr = 0x0007,
22 WHITE: uattr = 0x0008,
23};
24
25// Style attributes (bitwise), see termbox2::cell.
26export def ATTRIBUTE = struct {
27 BOLD: uattr = 0x0100,
28 UNDERLINE: uattr = 0x0200,
29 REVERSE: uattr = 0x0400,
30 ITALIC: uattr = 0x0800,
31 BLINK: uattr = 0x1000,
32 HI_BLACK: uattr = 0x2000,
33 BRIGHT: uattr = 0x4000,
34 DIM: uattr = 0x8000,
35};
diff --git a/termbox2/attrw+attrw32.ha b/termbox2/attrw+attrw32.ha
new file mode 100644
index 0000000..9f5f885
--- /dev/null
+++ b/termbox2/attrw+attrw32.ha
@@ -0,0 +1,35 @@
1// Integer width of fg and bg attributes. Valid values (assuming system
2// support) are 16, 32, and 64; see [[termbox2::uattr]]. 32 or 64 enables
3// OUTPUT.TRUECOLOR, see [[termbox2::OUTPUT]] and
4// [[termbox2::set_output_mode]]. 64 enables additional style attributes.
5// Larger values consume more memory in exchange for more features.
6// Defaults to 64.
7export def OPT_ATTR_W: size = 32;
8
9// Unsigned integer type for cell attributes, see [[termbox2::ATTRIBUTE]].
10export type uattr = u32;
11
12// Colors (bitwise), see [[termbox2::cell]].
13export def COLORS = struct {
14 DEFAULT: uattr = 0x0000,
15 BLACK: uattr = 0x0001,
16 RED: uattr = 0x0002,
17 GREEN: uattr = 0x0003,
18 YELLOW: uattr = 0x0004,
19 BLUE: uattr = 0x0005,
20 MAGENTA: uattr = 0x0006,
21 CYAN: uattr = 0x0007,
22 WHITE: uattr = 0x0008,
23};
24
25// Style attributes (bitwise), see [[termbox2::cell]].
26export def ATTRIBUTE = struct {
27 BOLD: uattr = 0x01000000,
28 UNDERLINE: uattr = 0x02000000,
29 REVERSE: uattr = 0x04000000,
30 ITALIC: uattr = 0x08000000,
31 BLINK: uattr = 0x10000000,
32 HI_BLACK: uattr = 0x20000000,
33 BRIGHT: uattr = 0x40000000,
34 DIM: uattr = 0x80000000,
35};
diff --git a/termbox2/attrw.ha b/termbox2/attrw.ha
new file mode 100644
index 0000000..d337b8f
--- /dev/null
+++ b/termbox2/attrw.ha
@@ -0,0 +1,39 @@
1// Integer width of fg and bg attributes. Valid values (assuming system
2// support) are 16, 32, and 64; see [[termbox2::uattr]]. 32 or 64 enables
3// OUTPUT.TRUECOLOR, see [[termbox2::OUTPUT]] and
4// [[termbox2::set_output_mode]]. 64 enables additional style attributes.
5// Larger values consume more memory in exchange for more features.
6// Defaults to 64.
7export def OPT_ATTR_W: size = 64;
8
9// Unsigned integer type for cell attributes, see [[termbox2::ATTRIBUTE]].
10export type uattr = u64;
11
12// Colors (bitwise), see [[termbox2::cell]].
13export def COLOR = struct {
14 DEFAULT: uattr = 0x0000,
15 BLACK: uattr = 0x0001,
16 RED: uattr = 0x0002,
17 GREEN: uattr = 0x0003,
18 YELLOW: uattr = 0x0004,
19 BLUE: uattr = 0x0005,
20 MAGENTA: uattr = 0x0006,
21 CYAN: uattr = 0x0007,
22 WHITE: uattr = 0x0008,
23};
24
25// Style attributes (bitwise), see [[termbox2::cell]].
26export def ATTRIBUTE = struct {
27 BOLD: uattr = 0x01000000,
28 UNDERLINE: uattr = 0x02000000,
29 REVERSE: uattr = 0x04000000,
30 ITALIC: uattr = 0x08000000,
31 BLINK: uattr = 0x10000000,
32 HI_BLACK: uattr = 0x20000000,
33 BRIGHT: uattr = 0x40000000,
34 DIM: uattr = 0x80000000,
35 STRIKEOUT: uattr = 0x0000000100000000,
36 UNDERLINE_2: uattr = 0x0000000200000000,
37 OVERLINE: uattr = 0x0000000400000000,
38 INVISIBLE: uattr = 0x0000000800000000,
39};
diff --git a/termbox2/egc+noegc.ha b/termbox2/egc+noegc.ha
new file mode 100644
index 0000000..40d1b33
--- /dev/null
+++ b/termbox2/egc+noegc.ha
@@ -0,0 +1,30 @@
1// If set, enable extended grapheme cluster support (see
2// [[termbox2::extend_cell]] and [[termbox2::set_cell_ex]]). Consumes more
3// memory. Defaults on.
4export def OPT_EGC: bool = false;
5
6// A cell in a 2d grid representing the terminal screen.
7//
8// The terminal screen is represented as a 2d array of cells. The structure is
9// optimized for dealing with single-width (wcwidth==1) Unicode codepoints,
10// however some support for grapheme clusters (e.g., combining diacritical
11// marks) and wide codepoints (e.g., Hiragana) is provided through ech via
12// [[termbox2::set_cell_ex]]. ech is only valid if it is non-empty, otherwise
13// ch is used.
14//
15// For non-single-width codepoints, given W=wcwidth(ch || ech):
16//
17// - when W<=0: termbox forces a single-width cell. Callers should avoid this
18// if aiming to render text accurately. Callers may use
19// [[termbox2::set_cell_ex]] or [[termbox2::print]] or similar to render
20// W==0 combining characters.
21// - when W>=2: termbox zeroes out the following W-1 cells and skips
22// sending them to the tty. So, e.g., if the caller sets x=0,y=0 to a
23// W==2 codepoint, the caller's next set should be at x=2,y=0. Anything
24// set at x=1,y=0 will be ignored. If there are not enough columns
25// remaining on th eline to render W cells, spaces are sent instead.
26export type cell = struct {
27 ch: u32, // a Unicode codepoint
28 fg: uattr, // bitwise foreground attributes
29 bg: uattr, // bitwise background attributes
30};
diff --git a/termbox2/egc.ha b/termbox2/egc.ha
new file mode 100644
index 0000000..a14e7ef
--- /dev/null
+++ b/termbox2/egc.ha
@@ -0,0 +1,31 @@
1// If set, enable extended grapheme cluster support (see
2// [[termbox2::extend_cell]] and [[termbox2::set_cell_ex]]). Consumes more
3// memory. Defaults on.
4export def OPT_EGC: bool = true;
5
6// A cell in a 2d grid representing the terminal screen.
7//
8// The terminal screen is represented as a 2d array of cells. The structure is
9// optimized for dealing with single-width (wcwidth==1) Unicode codepoints,
10// however some support for grapheme clusters (e.g., combining diacritical
11// marks) and wide codepoints (e.g., Hiragana) is provided through ech via
12// [[termbox2::set_cell_ex]]. ech is only valid if it is non-empty, otherwise
13// ch is used.
14//
15// For non-single-width codepoints, given W=wcwidth(ch || ech):
16//
17// - when W<=0: termbox forces a single-width cell. Callers should avoid this
18// if aiming to render text accurately. Callers may use
19// [[termbox2::set_cell_ex]] or [[termbox2::print]] or similar to render
20// W==0 combining characters.
21// - when W>=2: termbox zeroes out the following W-1 cells and skips
22// sending them to the tty. So, e.g., if the caller sets x=0,y=0 to a
23// W==2 codepoint, the caller's next set should be at x=2,y=0. Anything
24// set at x=1,y=0 will be ignored. If there are not enough columns
25// remaining on th eline to render W cells, spaces are sent instead.
26export type cell = struct {
27 ch: u32, // a Unicode codepoint
28 fg: uattr, // bitwise foreground attributes
29 bg: uattr, // bitwise background attributes
30 ech: []rune, // a grapheme cluster of Unicode codepoints
31};
diff --git a/termbox2/termbox2.ha b/termbox2/termbox2.ha
new file mode 100644
index 0000000..f8476ee
--- /dev/null
+++ b/termbox2/termbox2.ha
@@ -0,0 +1,605 @@
1use encoding::utf8;
2use fmt;
3use types::c;
4
5// Type for key values, see [[termbox2::KEY]].
6export type key = u16;
7
8// ASCII constants, see [[termbox2::key_event]].key.
9export def KEY = struct {
10 CTRL_TILDE: key = 0x00,
11 CTRL_2: key = 0x00, // clash with CTRL_TILDE
12 CTRL_A: key = 0x01,
13 CTRL_B: key = 0x02,
14 CTRL_C: key = 0x03,
15 CTRL_D: key = 0x04,
16 CTRL_E: key = 0x05,
17 CTRL_F: key = 0x06,
18 CTRL_G: key = 0x07,
19 BACKSPACE: key = 0x08,
20 CTRL_H: key = 0x08, // clash with CTRL_BACKSPACE
21 TAB: key = 0x09,
22 CTRL_I: key = 0x09, // clash with TAB
23 CTRL_J: key = 0x0a,
24 CTRL_K: key = 0x0b,
25 CTRL_L: key = 0x0c,
26 ENTER: key = 0x0d,
27 CTRL_M: key = 0x0d, // clash with ENTER
28 CTRL_N: key = 0x0e,
29 CTRL_O: key = 0x0f,
30 CTRL_P: key = 0x10,
31 CTRL_Q: key = 0x11,
32 CTRL_R: key = 0x12,
33 CTRL_S: key = 0x13,
34 CTRL_T: key = 0x14,
35 CTRL_U: key = 0x15,
36 CTRL_V: key = 0x16,
37 CTRL_W: key = 0x17,
38 CTRL_X: key = 0x18,
39 CTRL_Y: key = 0x19,
40 CTRL_Z: key = 0x1a,
41 ESC: key = 0x1b,
42 CTRL_LSQ_BRACKET: key = 0x1b, // clash with 'ESC'
43 CTRL_3: key = 0x1b, // clash with 'ESC'
44 CTRL_4: key = 0x1c,
45 CTRL_BACKSLASH: key = 0x1c, // clash with 'CTRL_4'
46 CTRL_5: key = 0x1d,
47 CTRL_RSQ_BRACKET: key = 0x1d, // clash with 'CTRL_5'
48 CTRL_6: key = 0x1e,
49 CTRL_7: key = 0x1f,
50 CTRL_SLASH: key = 0x1f, // clash with 'CTRL_7'
51 CTRL_UNDERSCORE: key = 0x1f, // clash with 'CTRL_7'
52 SPACE: key = 0x20,
53 BACKSPACE2: key = 0x7f,
54 CTRL_8: key = 0x7f, // clash with 'BACKSPACE2'
55 F1: key = (0xffff - 0),
56 F2: key = (0xffff - 1),
57 F3: key = (0xffff - 2),
58 F4: key = (0xffff - 3),
59 F5: key = (0xffff - 4),
60 F6: key = (0xffff - 5),
61 F7: key = (0xffff - 6),
62 F8: key = (0xffff - 7),
63 F9: key = (0xffff - 8),
64 F10: key = (0xffff - 9),
65 F11: key = (0xffff - 10),
66 F12: key = (0xffff - 11),
67 INSERT: key = (0xffff - 12),
68 DELETE: key = (0xffff - 13),
69 HOME: key = (0xffff - 14),
70 END: key = (0xffff - 15),
71 PGUP: key = (0xffff - 16),
72 PGDN: key = (0xffff - 17),
73 ARROW_UP: key = (0xffff - 18),
74 ARROW_DOWN: key = (0xffff - 19),
75 ARROW_LEFT: key = (0xffff - 20),
76 ARROW_RIGHT: key = (0xffff - 21),
77 BACK_TAB: key = (0xffff - 22),
78 MOUSE_LEFT: key = (0xffff - 23),
79 MOUSE_RIGHT: key = (0xffff - 24),
80 MOUSE_MIDDLE: key = (0xffff - 25),
81 MOUSE_RELEASE: key = (0xffff - 26),
82 MOUSE_WHEEL_UP: key = (0xffff - 27),
83 MOUSE_WHEEL_DOWN: key = (0xffff - 28),
84};
85
86// Type for key modifiers, see [[termbox2::MOD]].
87export type mod = u8;
88
89// Key modifiers (bitwise), see [[termbox2::event]].mod.
90export def MOD = struct {
91 ALT: mod = 1,
92 CTRL: mod = 2,
93 SHIFT: mod = 4,
94 MOTION: mod = 8,
95};
96
97// Type for input modes, see [[termbox2::INPUT]].
98export type input_mode = int;
99
100// Input modes (bitwise), see [[termbox2::set_input_mode]].
101export def INPUT = struct {
102 CURRENT: input_mode = 0,
103 ESC: input_mode = 1,
104 ALT: input_mode = 2,
105 MOUSE: input_mode = 4,
106};
107
108// Type for output modes, see [[termbox2::OUTPUT]].
109export type output_mode = int;
110
111// Output modes, see [[termbox2::set_output_mode]].
112export def OUTPUT = struct {
113 CURRENT: output_mode = 0,
114 NORMAL: output_mode = 1,
115 _256: output_mode = 2,
116 _216: output_mode = 3,
117 GRAYSCALE: output_mode = 4,
118 TRUECOLOR: output_mode = 5, // only available if OPT_ATTR_W >= 32
119};
120
121// Type for error return values, see [[termbox2::ERR]].
122export type err = !int;
123
124// Common error return values.
125//
126// Library behavior is undefined after receiving ERR.MEM.
127// Callers may attempt reinitializing by freeing memory, invoking
128// [[termbox2::shutdown]], then [[termbox2::init]].
129export def ERR = struct {
130 ERR: err = -1,
131 NEED_MORE: err = -2,
132 INIT_ALREADY: err = -3,
133 INIT_OPEN: err = -4,
134 MEM: err = -5,
135 NO_EVENT: err = -6,
136 NO_TERM: err = -7,
137 NOT_INIT: err = -8,
138 OUT_OF_BOUNDS: err = -9,
139 READ: err = -10,
140 RESIZE_IOCTL: err = -11,
141 RESIZE_PIPE: err = -12,
142 RESIZE_SIGACTION: err = -13,
143 POLL: err = -14,
144 SELECT: err = -14,
145 TCGETATTR: err = -15,
146 TCSETATTR: err = -16,
147 UNSUPPORTED_TERM: err = -17,
148 RESIZE_WRITE: err = -18,
149 RESIZE_POLL: err = -19,
150 RESIZE_SELECT: err = -19,
151 RESIZE_READ: err = -20,
152 RESIZE_SSCANF: err = -21,
153 CAP_COLLISION: err = -22,
154 HARE_BUILD: err = -9990, // Additional error type
155 HARE_INVALID_UTF8: err = -9991, // Additional error type
156 HARE_OTHER: err = -9992, // Additional error type
157};
158
159// An incoming key press event. Note that there is overlap between
160// MOD.CTRL and KEY.CTRL_* keys. MOD.CTRL and MOD.SHIFT are only set
161// as modifiers to KEY.ARROW_*.
162export type key_event = struct {
163 mod: mod, // Modifier
164 key_or_ch: (key | rune), // A [[termbox2::KEY]] or a Unicode code point
165};
166
167// An incoming resize event.
168export type resize_event = struct {
169 w: i32, // resize width
170 h: i32, // resize height
171};
172
173// An incoming mouse event.
174export type mouse_event = struct {
175 key: key, // Mouse button, e.g. termbox2::KEY.MOUSE_LEFT
176 x: i32,
177 y: i32,
178};
179
180// The C data structure for an event, for compatibility.
181type tb_event = struct {
182 t: u8,
183 mod: u8,
184 key: u16,
185 ch: u32,
186 w: i32,
187 h: i32,
188 x: i32,
189 y: i32,
190};
191
192def TB_EVENT_KEY: u8 = 1;
193def TB_EVENT_RESIZE: u8 = 2;
194def TB_EVENT_MOUSE: u8 = 3;
195fn tb_event_to_event(e: tb_event) (event | err) = switch (e.t) {
196 case TB_EVENT_KEY => yield key_event {
197 mod = e.mod,
198 key_or_ch = if (e.key != 0) e.key: key else e.ch: rune,
199 };
200 case TB_EVENT_RESIZE => yield resize_event {
201 w = e.w,
202 h = e.h,
203 };
204 case TB_EVENT_MOUSE => yield mouse_event {
205 key = e.key,
206 x = e.x,
207 y = e.y,
208 };
209 case => yield ERR.HARE_OTHER;
210 };
211
212// Any incoming event from the tty.
213export type event = (key_event | resize_event | mouse_event);
214
215fn build_opts_match() bool =
216 (has_egc() == OPT_EGC) &&
217 (attr_width() == OPT_ATTR_W) &&
218 (has_truecolor() == (OPT_ATTR_W == 32 || OPT_ATTR_W == 64));
219
220fn void_or_err(r: int) (void | err) = if (r < 0) r: err;
221fn int_or_err(r: int) (int | err) = if (r < 0) r: err else r;
222fn size_or_err(r: int) (size | err) = if (r < 0) r: err else r: size;
223fn str_or_err(cstr: *c::char) (str | err) = match(c::tostr(cstr)) {
224 case utf8::invalid => yield ERR.HARE_INVALID_UTF8;
225 case let s: str => yield s;
226};
227
228// Initialize the termbox library. This function should be called before
229// any other functions. After successful initialization, the library must
230// be finalized using [[termbox2::shutdown]].
231export fn init() (void | err) =
232 if (!build_opts_match())
233 ERR.HARE_BUILD
234 else
235 void_or_err(tb_init());
236@symbol("tb_init") fn tb_init() int;
237
238// Same as [[termbox2::init]], but allows to specify a file path in place
239// of the default /dev/tty.
240export fn init_file(path: str) (void | err) = {
241 let c_path = c::fromstr(path)!;
242 defer free(c_path);
243 return if (!build_opts_match())
244 ERR.HARE_BUILD
245 else
246 void_or_err(tb_init_file(c_path));
247};
248@symbol("tb_init_file") fn tb_init_file(cstr: *c::char) int;
249
250// Same as [[termbox2::init]], but allows to specify an output
251// file descriptor.
252export fn init_fd(ttyfd: int) (void | err) =
253 if (!build_opts_match())
254 ERR.HARE_BUILD
255 else
256 void_or_err(tb_init_fd(ttyfd));
257@symbol("tb_init_fd") fn tb_init_fd(fd: int) int;
258
259// Same as [[termbox2::init]], but allows to specify input and output
260// file descriptors.
261export fn init_rwfd(rfd: int, wfd: int) (void | err) =
262 if (!build_opts_match())
263 ERR.HARE_BUILD
264 else
265 void_or_err(tb_init_rwfd(rfd, wfd));
266@symbol("tb_init_rwfd") fn tb_init_rwfd(rfd: int, wfd: int) int;
267
268// Finalizes the library.
269export fn shutdown() (void | err) = void_or_err(tb_shutdown());
270@symbol("tb_shutdown") fn tb_shutdown() int;
271
272// Return the width of the internal back buffer (which is the same as the
273// terminal's window width in columns). The internal buffer can be resized
274// after [[termbox2::clear]] or [[termbox2::present]] calls. Returns ERR.ERR
275// when called before [[termbox2::init]] or after [[termbox2::shutdown]].
276export fn width() (size | err) = size_or_err(tb_width());
277@symbol("tb_width") fn tb_width() int;
278
279// Return the height of the internal back buffer (which is the same as the
280// terminal's window width in rows). The internal buffer can be resized
281// after [[termbox2::clear]] or [[termbox2::present]] calls. Returns ERR.ERR
282// when called before [[termbox2::init]] or after [[termbox2::shutdown]].
283export fn height() (size | err) = size_or_err(tb_height());
284@symbol("tb_height") fn tb_height() int;
285
286// Clear the internal back buffer using [[termbox2::ATTRIBUTE]].DEFAULT.
287export fn clear() (void | err) = void_or_err(tb_clear());
288@symbol("tb_clear") fn tb_clear() int;
289
290// Clear the internal back buffer using the specified attributes.
291export fn set_clear_attrs(fg: uattr, bg: uattr) (void | err) =
292 void_or_err(tb_set_clear_attrs(fg, bg));
293@symbol("tb_set_clear_attrs") fn tb_set_clear_attrs(fg: uattr, bg: uattr) int;
294
295// Synchronize the internal back buffer with the terminal by
296// writing to tty.
297export fn present() (void | err) = void_or_err(tb_present());
298@symbol("tb_present") fn tb_present() int;
299
300// Clear the internal front buffer effectively forcing a complete re-render
301// of the back buffer to the tty. It is not necessary to call this under
302// normal circumstances.
303export fn invalidate() (void | err) = void_or_err(tb_invalidate());
304@symbol("tb_invalidate") fn tb_invalidate() int;
305
306// Set the position of the cursor. Upper-left cell is (0, 0).
307export fn set_cursor(cx: int, cy: int) (void | err) =
308 void_or_err(tb_set_cursor(cx, cy));
309@symbol("tb_set_cursor") fn tb_set_cursor(x: int, y: int) int;
310
311// Hide the cursor.
312export fn hide_cursor() (void | err) = void_or_err(tb_hide_cursor());
313@symbol("tb_hide_cursor") fn tb_hide_cursor() int;
314
315// Set cell contents in the internal back buffer at the specified position.
316// Non-printable runes are replaced with U+FFFD at render time.
317export fn set_cell(
318 x: int,
319 y: int,
320 ch: rune,
321 fg: uattr,
322 bg: uattr,
323) (void | err) = void_or_err(tb_set_cell(x, y, ch: u32, fg, bg));
324@symbol("tb_set_cell") fn tb_set_cell(
325 x: int,
326 y: int,
327 ch: u32,
328 fg: uattr,
329 bg: uattr,
330) int;
331
332// Set extended cell contents. Only available when OPT_ATTR_W >= 32.
333// See also [[termbox2::set_cell]] and [[termbox2::cell]].
334export fn set_cell_ex(
335 x: int,
336 y: int,
337 ch: []rune,
338 fg: uattr,
339 bg: uattr,
340) (void | err) =
341 void_or_err(tb_set_cell_ex(x, y, &ch[0]: *u32, len(ch), fg, bg));
342@symbol("tb_set_cell_ex") fn tb_set_cell_ex(
343 x: int,
344 y: int,
345 ch: *u32,
346 n: size,
347 fg: uattr,
348 bg: uattr,
349) int;
350
351// Add one character to the cell's ech. Only available when OPT_ATTR_W >= 32.
352// See also [[termbox2::set_cell_ex]] and [[termbox2::cell]].
353export fn extend_cell(x: int, y: int, ch: rune) (void | err) =
354 void_or_err(tb_extend_cell(x, y, ch: u32));
355@symbol("tb_extend_cell") fn tb_extend_cell(x: int, y: int, ch: u32) int;
356
357// Set the input mode, see [[termbox2::INPUT]].
358//
359// Termbox has two input modes:
360// - INPUT.ESC When escape (\x1b) is in the buffer and there's no match
361// for an escape sequence, a key event for [[termbox2::KEY]].ESC is returned.
362// - INPUT.ALT When escape (\x1b) is in the buffer and there's no match
363// for an an escape sequence, the next keyboard event is returned with a
364// [[termbox2::MOD]].ALT modifier.
365//
366// You can also apply termbox2::INPUT.MOUSE via bitwise OR operation to either
367// of the modes (e.g., INPUT.ALT | INPUT.MOUSE) to receive
368// [[termbox2::mouse_event]] events. If none of the main two modes were
369// set, but the mouse mode was, INPUT.ESC is used. If for some reason you've
370// decided to use INPUT.ESC | INPUT.ALT, it will behave as if only INPUT.ESC
371// was selected.
372//
373// If mode is INPUT.CURRENT, return the current input mode.
374//
375// The default input mode is INPUT.ESC.
376export fn set_input_mode(mode: input_mode) (int | err) =
377 int_or_err(tb_set_input_mode(mode: int));
378@symbol("tb_set_input_mode") fn tb_set_input_mode(mode: int) int;
379
380// Set the output mode, see [[termbox2::OUTPUT]].
381//
382// Termbox has multiple output modes:
383//
384// 1. OUTPUT.NORMAL => [0..8]
385//
386// This mode provides 8 different colors (see [[termbox2::COLOR]]), plus
387// COLOR.DEFAULT which skips sending a color code (i.e., uses the terminal's
388// default color). Colors may be bitwise OR'd with style attributes, see
389// [[termbox2::ATTRIBUTE]]. Extra attributes are available if OPT_ATTR_W == 64.
390//
391// Some notes: ATTRIBUTE.REVERSE and ATTRIBUTE.BRIGHT can be applied as either
392// fg or bg attributes for the same effect. The rest of the attributes apply to
393// fg only and are ignored as bg attributes.
394//
395// Example usage:
396//
397// let fg = termbox2::COLOR.BLACK | termbox2::ATTRIBUTE.BOLD;
398// let bg = termbox2::COLOR.RED;
399// termbox2::set_cell(x, y, '@', fg, bg);
400//
401// 2. OUTPUT._256 => [0..255] + ATTRIBUTE.HI_BLACK
402//
403// In this mode you get 256 distinct colors (plus default):
404// - 0x00 (1): ATTRIBUTE.DEFAULT
405// - ATTRIBUTE.HI_BLACK (1): COLOR.BLACK in OUTPUT.NORMAL
406// - 0x01..0x07 (7): the next 7 colors as in OUTPUT.NORMAL
407// - 0x08..0x0f (8): bright versions of the above
408// - 0x10..0xe7 (216): 216 different colors
409// - 0xe8..0xff (24): 24 different shades of gray
410//
411// All style attributes except ATTRIBUTE.BRIGHT may be bitwise OR'd as in
412// OUTPUT.NORMAL.
413//
414// Note COLOR.BLACK must be used for black, as 0x00 represents default.
415//
416// 3. OUTPUT._216 => [0..216]
417//
418// This mode supports the 216-color range of OUTPUT._256 only, but you
419// don't need to provide an offset:
420// - 0x00 (1): COLOR.DEFAULT
421// - 0x01..0xd8 (216): 216 different colors
422//
423// 4. OUTPUT.GRAYSCALE => [0..24]
424//
425// This mode supports the 24-color range of OUTPUT._256 only, but you
426// don't need to provide an offset:
427// - 0x00 (1): COLOR.DEFAULT
428// - 0x01..0x18 (24): 24 different shades of gray
429//
430// 5. OUTPUT.TRUECOLOR => [0x000000..0xffffff] + ATTRIBUTE.HI_BLACK
431//
432// This mode provides 24-bit color on supported terminals.
433// The format is 0xRRGGBB.
434//
435// All style attributes except ATTRIBUTE.BRIGHT may be bitwise OR'd as in
436// OUTPUT.NORMAL.
437//
438// Note ATTRIBUTE.HI_BLACK must be used for black, as 0x000000 represents
439// default.
440//
441// To use the terminal default color (i.e., to not send an escape code), pass
442// COLOR.DEFAULT. For convenience, the value 0 is interpreted as COLOR.DEFAULT
443// in all modes.
444//
445// Note, cell attributes persist after switching output modes. Any translation
446// between, for example, OUTPUT.NORMAL's COLOR.RED and OUTPUT.TRUECOLOR's
447// 0xff0000 must be performed by the caller. Also note that cells previously
448// rendered in one mode may persist unchanged until the front buffer is cleared
449// (such as after a resize event) at which point it will be re-interpreted and
450// flushed according to the current mode. Callers may invoke
451// [[termbox2::invalidate]] if it is desirable to immediately re-interpret
452// and flush the entire screen according to the current mode.
453//
454// Note, not all terminals support all output modes, especially beyond
455// OUTPUT.NORMAL. There is also no very reliable way to determine color
456// support dynamically. If portability is desired, callers are recommended to
457// use OUTPUT.NORMAL or make output mode end-user configurable. The same
458// advice applies to style attributes.
459//
460// If mode is OUTPUT.CURRENT, return the current output mode.
461//
462// The default output mode is OUTPUT.NORMAL.
463export fn set_output_mode(mode: output_mode) (int | err) =
464 int_or_err(tb_set_output_mode(mode: int));
465@symbol("tb_set_output_mode") fn tb_set_output_mode(mode: int) int;
466
467// Wait for an event up to timeout_ms milliseconds and return it. If no event
468// is available within the timeout period, ERR.NO_EVENT is returned. On a resize
469// event, the underlying select(2) call may be interrupted, yielding a return
470// code of ERR.POLL.
471export fn peek_event(timeout_ms: size) (event | err) = {
472 let e = tb_event {
473 t = 0,
474 mod = 0,
475 key = 0,
476 ch = 0,
477 w = 0,
478 h = 0,
479 x = 0,
480 y = 0,
481 };
482 let r = tb_peek_event(&e, timeout_ms: int);
483 return if (r < 0) r: err else tb_event_to_event(e);
484};
485@symbol("tb_peek_event") fn tb_peek_event(ev: *tb_event, t: int) int;
486
487// Same as [[termbox2::peek_event]] except no timeout.
488export fn poll_event() (event | err) = {
489 let e = tb_event {
490 t = 0,
491 mod = 0,
492 key = 0,
493 ch = 0,
494 w = 0,
495 h = 0,
496 x = 0,
497 y = 0,
498 };
499 let r = tb_poll_event(&e);
500 return if (r < 0) r: err else tb_event_to_event(e);
501};
502@symbol("tb_poll_event") fn tb_poll_event(ev: *tb_event) int;
503
504// Internal termbox fds that can be used with poll(2), select(2), etc.
505// externally. Callers must invoke [[termbox2::poll_event]] or
506// [[termbox2::peek_event]] if fds become readable.
507export fn get_fds() ((int, int) | err) = {
508 let ttyfd: int = 0;
509 let resizefd: int = 0;
510 let r = tb_get_fds(&ttyfd, &resizefd);
511 return if (r < 0) r: err else (ttyfd, resizefd);
512};
513@symbol("tb_get_fds") fn tb_get_fds(ttyfd: *int, resizefd: *int) int;
514
515// Print function. On success, it returns the width of the printed string.
516// Strings are interpreted as UTF-8.
517//
518// No attempt is made to do proper grapheme cluster parsing. With
519// [[termbox2::OPT_EGC]] enabled, as a very coarse approximation, codepoints
520// of width 0 are tacked on to the previous codepoint via
521// [[termbox2::extend_cell]].
522//
523// Non-printable characters (iswprint(3)) and truncated UTF-8 byte sequences
524// are replaced with U+FFFD.
525//
526// Newlines (\n) are supported with the caveat that the return value will be
527// the width of the string as if it were on a single line.
528//
529// If the starting coordinate is out of bounds, ERR.OUT_OF_BOUNDS is returned.
530// If the starting coordinates is in bounds, but goes out of bounds, then the
531// out-of-bounds portions of the string are ignored.
532//
533// For finer control, use [[termbox2::set_cell]].
534export fn print(
535 x: int,
536 y: int,
537 fg: uattr,
538 bg: uattr,
539 fmt_str: str,
540 args: fmt::field...
541) (size | err) = {
542 let s = fmt::asprintf(fmt_str, args...)!;
543 defer free(s);
544 let cstr = c::fromstr(s)!;
545 defer free(cstr);
546 let outw: size = 0;
547 let e = tb_print_ex(x, y, fg, bg, &outw, cstr);
548 return if (e < 0) e: err else outw;
549};
550@symbol("tb_print_ex") fn tb_print_ex(
551 x: int,
552 y: int,
553 fg: uattr,
554 bg: uattr,
555 out_w: *size,
556 cstr: const *c::char,
557) int;
558
559// Send raw bytes to the terminal.
560export fn send(buf: []u8) (void | err) =
561 void_or_err(tb_send(&buf[0]: *c::char, len(buf)));
562@symbol("tb_send") fn tb_send(buf: const *c::char, nbuf: size) int;
563
564// Returns a string explaining the given error code. The caller must free
565// the return value.
566export fn strerror(e: err) str = switch (e) {
567 case ERR.HARE_BUILD =>
568 yield fmt::asprintf(
569 "Cannot initialize Termbox because of a mismatch "
570 "between the C and Hare build options.\n"
571 "Hare OPT_EGC is {} and C TB_OPT_EGC is {}\n"
572 "Hare OPT_ATTR_W {} and C TB_OPT_ATTR_W is {}",
573 OPT_EGC, has_egc(), OPT_ATTR_W, attr_width()
574 )!;
575 case ERR.HARE_INVALID_UTF8 =>
576 yield fmt::asprintf("Invalid UTF8 sequence recieved from tb")!;
577 case ERR.HARE_OTHER =>
578 yield fmt::asprintf("Unknown error in the Hare bindings")!;
579 case => yield match (str_or_err(tb_strerror(e: int))) {
580 case err => yield fmt::asprintf(
581 "Unexpected error while interpreting previous error"
582 )!;
583 case let estr: str => yield estr;
584 };
585};
586@symbol("tb_strerror") fn tb_strerror(e: int) const *c::char;
587
588// Returns true if the the C termbox2 library was compiled with truecolor
589// support (i.e., if [[termbox2::OPT_ATTR_W]] is 32 or 64).
590export fn has_truecolor() bool = tb_has_truecolor() != 0;
591@symbol("tb_has_truecolor") fn tb_has_truecolor() int;
592
593// Returns true if the the C termbox2 library was compiled with EGC
594// support (i.e., if [[termbox2::OPT_EGC]] is true).
595export fn has_egc() bool = tb_has_egc() != 0;
596@symbol("tb_has_egc") fn tb_has_egc() int;
597
598// Returns the value of the TB_OPT_ATTR_W compile time option of the
599// C termbox2 library.
600export fn attr_width() size = tb_attr_width(): size;
601@symbol("tb_attr_width") fn tb_attr_width() int;
602
603// Returns the string version of the C termbox2 library.
604export fn version() (str | err) = str_or_err(tb_version());
605@symbol("tb_version") fn tb_version() const *c::char;
diff --git a/vendor/termbox2 b/vendor/termbox2
new file mode 160000
Subproject cdf62e9990d8b200768780080fb10a4e2f68005

Generated with cgit - Back to sebastiano.tronto.net