raiguard/tcom

git clone https://git.raiguard.me/raiguard/tcom

Caleb HeuerNo idea what I was working on...7992681

trunk
3.9 KiB172 linesraw
1package tcom
2
3import rt "base:runtime"
4import hm "core:container/handle_map"
5import "core:log"
6import "core:testing"
7
8Cell :: struct {
9	r: rune,
10	attribs: Cell_Attribs,
11	// TODO: Colors
12}
13
14Cell_Attrib :: enum {
15	Bold,
16	Dim,
17	Italic,
18	Underline,
19}
20
21Cell_Attribs :: bit_set[Cell_Attrib]
22
23Pane :: struct {
24	cells: []Cell, // owned
25	dims: TTY_Pos,
26	cursor: Pane_Cursor,
27	handle: Pane_Handle,
28	allocator: rt.Allocator,
29	child: Sys_Child_Info,
30}
31
32Pane_Cursor :: struct {
33	using pos: [2]u16,
34	attribs: Cell_Attribs,
35}
36
37pane_init :: proc(cmd: []string, dims: TTY_Pos, allocator: rt.Allocator) -> (h: Pane_Handle, err: rt.Allocator_Error) {
38	return hm.add(&g_panes, Pane{
39		cells = make_slice([]Cell, dims.x * dims.y, allocator) or_return,
40		dims = dims,
41		allocator = allocator,
42		child = sys_child_start(cmd, dims, allocator) or_return,
43	})
44}
45
46pane_init_headless :: proc(dims: TTY_Pos, allocator: rt.Allocator) -> (h: Pane_Handle, err: rt.Allocator_Error) {
47	return hm.add(&g_panes, Pane{
48		cells = make_slice([]Cell, dims.x * dims.y, allocator) or_return,
49		dims = dims,
50		allocator = allocator,
51	})
52}
53
54pane_fini :: proc(pane_handle: Pane_Handle) {
55	pane, ok := hm.get(&g_panes, pane_handle)
56	if !ok {
57		log.errorf("pane_fini called when pane does not exist.")
58		return
59	}
60	delete(pane.cells, pane.allocator)
61	hm.remove(&g_panes, pane_handle)
62}
63
64pane_set_dims :: proc(h: Pane_Handle, dims: TTY_Pos) -> (ok: bool) {
65	pane := hm.get(&g_panes, h) or_return
66	sys_term_set_dims(dims, pane.child)
67	return true
68}
69
70pane_handle_event :: proc(h: Pane_Handle, event: TTY_Event) -> (ok: bool) {
71	p := hm.get(&g_panes, h) or_return
72
73	switch e in event {
74	case TTY_Ctrl:
75		return _pane_handle_ctrl(p, e)
76	case TTY_Resized:
77		log.error("TTY_Resize is unimplemented.")
78		// TODO:
79	case TTY_Text:
80		return _pane_handle_text(p, e)
81	}
82
83	return true
84}
85
86pane_draw :: proc(h: Pane_Handle) -> (ok: bool) {
87	pane := hm.get(&g_panes, h) or_return
88	log.debug("DRAW:", pane)
89	// TODO:
90	return true
91}
92
93// ---------------------------------------------------------------------------------------------------------------------
94// INTERNALS
95
96_pane_advance_cursor :: proc(p: ^Pane) {
97	p.cursor.x = (p.cursor.x + 1) % p.dims.x
98	if p.cursor.x == 0 {
99		p.cursor.y += 1
100	}
101}
102
103_pane_get_cursor_cell :: proc(p: ^Pane) -> ^Cell {
104	i := (p.cursor.y * p.dims.x) + p.cursor.x
105	// log.debug("cursor offset calc:", p.cursor.pos, i)
106	return &p.cells[i]
107}
108
109_pane_handle_ctrl :: proc(p: ^Pane, ctrl: TTY_Ctrl) -> (ok: bool) {
110	switch ctrl {
111	// C0 control codes
112	case .Bell:
113	case .Backspace:
114	case .Tab:
115	case .Line_Feed:
116	case .Form_Feed:
117	case .Carriage_Return:
118	// CSI commands
119    case .Reset_All:
120	    p.cursor.attribs = {}
121    case .Bold:
122		p.cursor.attribs += {.Bold}
123    case .Dim:
124		p.cursor.attribs += {.Dim}
125    case .Italic:
126		p.cursor.attribs += {.Italic}
127    case .Underline:
128		p.cursor.attribs += {.Underline}
129	}
130	return true
131}
132
133_pane_handle_text :: proc(p: ^Pane, r: rune) -> (ok: bool) {
134	cell := _pane_get_cursor_cell(p)
135	cell.r = r
136	cell.attribs = p.cursor.attribs
137	_pane_advance_cursor(p)
138
139	return true
140}
141
142// ---------------------------------------------------------------------------------------------------------------------
143// TESTS
144
145@test
146pane_test_cursor_attribs :: proc(t: ^testing.T) {
147	panes_init(context.allocator)
148	defer panes_fini()
149
150	h, err := pane_init_headless({600, 400}, context.allocator)
151	testing.expect(t, err == nil)
152	defer pane_fini(h)
153
154	// The pane pointer will be stable throughout this test.
155	pane, ok := hm.get(&g_panes, h)
156	testing.expect(t, ok)
157
158	pane_handle_event(h, .Bold)
159	testing.expect(t, .Bold in pane.cursor.attribs)
160
161	pane_handle_event(h, .Dim)
162	testing.expect(t, .Dim in pane.cursor.attribs)
163
164	pane_handle_event(h, .Italic)
165	testing.expect(t, .Italic in pane.cursor.attribs)
166
167	pane_handle_event(h, .Underline)
168	testing.expect(t, .Underline in pane.cursor.attribs)
169
170	pane_handle_event(h, .Reset_All)
171	testing.expect(t, pane.cursor.attribs == {})
172}