1package vterm
2
3/*
4#cgo CFLAGS: -std=c11 -I"${SRCDIR}/libvterm/include/"
5#include <vterm.h>
6#include <stdio.h>
7
8inline static int _attr_bold(VTermScreenCell *cell) { return cell->attrs.bold; }
9inline static int _attr_underline(VTermScreenCell *cell) { return cell->attrs.underline; }
10inline static int _attr_italic(VTermScreenCell *cell) { return cell->attrs.italic; }
11inline static int _attr_blink(VTermScreenCell *cell) { return cell->attrs.blink; }
12inline static int _attr_reverse(VTermScreenCell *cell) { return cell->attrs.reverse; }
13inline static int _attr_strike(VTermScreenCell *cell) { return cell->attrs.strike; }
14inline static int _attr_font(VTermScreenCell *cell) { return cell->attrs.font; }
15inline static int _attr_dwl(VTermScreenCell *cell) { return cell->attrs.dwl; }
16inline static int _attr_dhl(VTermScreenCell *cell) { return cell->attrs.dhl; }
17
18int _go_handle_damage(VTermRect, void*);
19int _go_handle_bell(void*);
20int _go_handle_set_term_prop(VTermProp, VTermValue*, void*);
21int _go_handle_resize(int, int, void*);
22int _go_handle_moverect(VTermRect, VTermRect, void*);
23int _go_handle_movecursor(VTermPos, VTermPos, int, void*);
24
25static VTermScreenCallbacks _screen_callbacks = {
26  _go_handle_damage,
27  _go_handle_moverect,
28  _go_handle_movecursor,
29  _go_handle_set_term_prop,
30  _go_handle_bell,
31  _go_handle_resize,
32  NULL,
33  NULL
34};
35
36static void
37_vterm_screen_set_callbacks(VTermScreen *screen, void *user) {
38  vterm_screen_set_callbacks(screen, &_screen_callbacks, user);
39}
40
41static bool _vterm_value_get_boolean(VTermValue *val) {
42	return val->boolean;
43}
44
45static int _vterm_value_get_number(VTermValue *val) {
46	return val->number;
47}
48
49static char *_vterm_value_get_string(VTermValue *val) {
50	printf("get_string: %s", val->string);
51	return val->string;
52}
53
54typedef struct {
55	uint8_t color_type;
56	uint8_t red, green, blue;
57} rgb_color;
58
59*/
60import "C"
61import (
62	"errors"
63	"unsafe"
64
65	"github.com/mattn/go-pointer"
66)
67
68type Attr int
69
70const (
71	AttrNone       Attr = 0
72	AttrBold            = Attr(C.VTERM_ATTR_BOLD)
73	AttrUnderline       = Attr(C.VTERM_ATTR_UNDERLINE)
74	AttrItalic          = Attr(C.VTERM_ATTR_ITALIC)
75	AttrBlink           = Attr(C.VTERM_ATTR_BLINK)
76	AttrReverse         = Attr(C.VTERM_ATTR_REVERSE)
77	AttrStrike          = Attr(C.VTERM_ATTR_STRIKE)
78	AttrFont            = Attr(C.VTERM_ATTR_FONT)
79	AttrForeground      = Attr(C.VTERM_ATTR_FOREGROUND)
80	AttrBackground      = Attr(C.VTERM_ATTR_BACKGROUND)
81	AttrNAttrrs
82)
83
84type Modifier uint
85
86const (
87	ModNone  Modifier = 0
88	ModShift          = Modifier(C.VTERM_MOD_SHIFT)
89	ModAlt            = Modifier(C.VTERM_MOD_ALT)
90	ModCtrl           = Modifier(C.VTERM_MOD_CTRL)
91)
92
93type Key uint
94
95const (
96	KeyNone      = Key(0)
97	KeyEnter     = Key(C.VTERM_KEY_ENTER)
98	KeyTab       = Key(C.VTERM_KEY_TAB)
99	KeyBackspace = Key(C.VTERM_KEY_BACKSPACE)
100	KeyEscape    = Key(C.VTERM_KEY_ESCAPE)
101	KeyUp        = Key(C.VTERM_KEY_UP)
102	KeyDown      = Key(C.VTERM_KEY_DOWN)
103	KeyLeft      = Key(C.VTERM_KEY_LEFT)
104	KeyRight     = Key(C.VTERM_KEY_RIGHT)
105	KeyIns       = Key(C.VTERM_KEY_INS)
106	KeyDel       = Key(C.VTERM_KEY_DEL)
107	KeyHome      = Key(C.VTERM_KEY_HOME)
108	KeyEnd       = Key(C.VTERM_KEY_END)
109	KeyPageUp    = Key(C.VTERM_KEY_PAGEUP)
110	KeyPageDown  = Key(C.VTERM_KEY_PAGEDOWN)
111	KeyFunction0 = Key(C.VTERM_KEY_FUNCTION_0)
112	KeyKp0       = Key(C.VTERM_KEY_KP_0)
113	KeyKp1       = Key(C.VTERM_KEY_KP_1)
114	KeyKp2       = Key(C.VTERM_KEY_KP_2)
115	KeyKp3       = Key(C.VTERM_KEY_KP_3)
116	KeyKp4       = Key(C.VTERM_KEY_KP_4)
117	KeyKp5       = Key(C.VTERM_KEY_KP_5)
118	KeyKp6       = Key(C.VTERM_KEY_KP_6)
119	KeyKp7       = Key(C.VTERM_KEY_KP_7)
120	KeyKp8       = Key(C.VTERM_KEY_KP_8)
121	KeyKp9       = Key(C.VTERM_KEY_KP_9)
122	KeyKpMult    = Key(C.VTERM_KEY_KP_MULT)
123	KeyKpPlus    = Key(C.VTERM_KEY_KP_PLUS)
124	KeyKpComma   = Key(C.VTERM_KEY_KP_COMMA)
125	KeyKpMinus   = Key(C.VTERM_KEY_KP_MINUS)
126	KeyKpPeriod  = Key(C.VTERM_KEY_KP_PERIOD)
127	KeyKpDivide  = Key(C.VTERM_KEY_KP_DIVIDE)
128	KeyKpEnter   = Key(C.VTERM_KEY_KP_ENTER)
129	KeyKpEqual   = Key(C.VTERM_KEY_KP_EQUAL)
130)
131
132type VTerm struct {
133	term   *C.VTerm
134	screen *Screen
135}
136
137type Pos struct {
138	pos C.VTermPos
139}
140
141func NewPos(row, col int) *Pos {
142	var pos Pos
143	pos.pos.col = C.int(col)
144	pos.pos.row = C.int(row)
145	return &pos
146}
147
148func (pos *Pos) Col() int {
149	return int(pos.pos.col)
150}
151
152func (pos *Pos) Row() int {
153	return int(pos.pos.row)
154}
155
156type Rect struct {
157	rect C.VTermRect
158}
159
160func (rect *Rect) StartRow() int {
161	return int(rect.rect.start_row)
162
163}
164
165func (rect *Rect) EndRow() int {
166	return int(rect.rect.end_row)
167}
168
169func (rect *Rect) StartCol() int {
170	return int(rect.rect.start_col)
171}
172
173func (rect *Rect) EndCol() int {
174	return int(rect.rect.end_col)
175}
176
177func NewRect(start_row, end_row, start_col, end_col int) *Rect {
178	var rect Rect
179	rect.rect.start_row = C.int(start_row)
180	rect.rect.end_row = C.int(end_row)
181	rect.rect.start_col = C.int(start_col)
182	rect.rect.end_col = C.int(end_col)
183	return &rect
184}
185
186type ScreenCell struct {
187	cell C.VTermScreenCell
188}
189
190type ParserCallbacks struct {
191	Text func([]byte, interface{}) int
192	/*
193	  int (*control)(unsigned char control, void *user);
194	  int (*control)(unsigned char control, void *user);
195	  int (*escape)(const char *bytes, size_t len, void *user);
196	  int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
197	  int (*osc)(const char *command, size_t cmdlen, void *user);
198	  int (*dcs)(const char *command, size_t cmdlen, void *user);
199	  int (*resize)(int rows, int cols, void *user);
200	*/
201}
202
203type VTermColor struct {
204	color C.VTermColor
205}
206
207func _VTermColorToRGB(col *C.VTermColor) *C.rgb_color {
208	return *(**C.rgb_color)(unsafe.Pointer(&col))
209}
210
211func (c *VTermColor) _to_rgb_color() *C.rgb_color {
212	return _VTermColorToRGB(&c.color)
213}
214
215const (
216	VTERM_COLOR_RGB uint8 = 0x00
217	VTERM_COLOR_INDEXED uint8 = 0x01
218	VTERM_COLOR_TYPE_MASK uint8 = 0x01
219	VTERM_COLOR_DEFAULT_FG uint8 = 0x02
220	VTERM_COLOR_DEFAULT_BG uint8 = 0x04
221)
222
223func (c *VTermColor) IsIndexed() bool {
224	return (c.GetType()&VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_INDEXED
225}
226
227func (c *VTermColor) IsRgb() bool {
228	return (c.GetType()&VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB
229}
230
231func (c *VTermColor) IsDefaultFg() bool {
232	return c.GetType()&VTERM_COLOR_DEFAULT_FG > 0
233}
234
235func (c *VTermColor) IsDefaultBg() bool {
236	return c.GetType()&VTERM_COLOR_DEFAULT_BG > 0
237}
238
239func (c *VTermColor) GetType() uint8 {
240	colors := c._to_rgb_color()
241	return uint8(colors.color_type)
242}
243
244func (c *VTermColor) GetIndex() uint8 {
245	colors := c._to_rgb_color()
246	return uint8(colors.red)
247}
248
249func (c *VTermColor) GetRGB() (r, g, b uint8) {
250	colors := c._to_rgb_color()
251	return uint8(colors.red), uint8(colors.green), uint8(colors.blue)
252}
253
254func (sc *ScreenCell) Chars() []rune {
255	chars := make([]rune, int(sc.cell.width))
256	for i := 0; i < len(chars); i++ {
257		chars[i] = rune(sc.cell.chars[i])
258	}
259	return chars
260}
261
262func (sc *ScreenCell) Width() int {
263	return int(sc.cell.width)
264}
265
266func (sc *ScreenCell) Fg() VTermColor {
267	return VTermColor{sc.cell.fg}
268}
269
270func (sc *ScreenCell) Bg() VTermColor {
271	return VTermColor{sc.cell.bg}
272}
273
274type Attrs struct {
275	Bold      int
276	Underline int
277	Italic    int
278	Blink     int
279	Reverse   int
280	Strike    int
281	Font      int
282	Dwl       int
283	Dhl       int
284}
285
286func (sc *ScreenCell) Attrs() *Attrs {
287	return &Attrs{
288		Bold:      int(C._attr_bold(&sc.cell)),
289		Underline: int(C._attr_underline(&sc.cell)),
290		Italic:    int(C._attr_italic(&sc.cell)),
291		Blink:     int(C._attr_blink(&sc.cell)),
292		Reverse:   int(C._attr_reverse(&sc.cell)),
293		Strike:    int(C._attr_strike(&sc.cell)),
294		Font:      int(C._attr_font(&sc.cell)),
295		Dwl:       int(C._attr_dwl(&sc.cell)),
296		Dhl:       int(C._attr_dhl(&sc.cell)),
297	}
298}
299
300func New(rows, cols int) *VTerm {
301	term := C.vterm_new(C.int(rows), C.int(cols))
302	vt := &VTerm{
303		term: term,
304		screen: &Screen{
305			screen: C.vterm_obtain_screen(term),
306		},
307	}
308	C._vterm_screen_set_callbacks(C.vterm_obtain_screen(term), pointer.Save(vt))
309	return vt
310}
311
312func (vt *VTerm) Close() error {
313	C.vterm_free(vt.term)
314	return nil
315}
316
317func (vt *VTerm) Size() (int, int) {
318	var rows, cols C.int
319	C.vterm_get_size(vt.term, &rows, &cols)
320	return int(rows), int(cols)
321}
322
323func (vt *VTerm) SetSize(rows, cols int) {
324	C.vterm_set_size(vt.term, C.int(rows), C.int(cols))
325}
326
327func (vt *VTerm) KeyboardStartPaste() {
328	C.vterm_keyboard_start_paste(vt.term)
329}
330
331func (vt *VTerm) KeyboardStopPaste() {
332	C.vterm_keyboard_end_paste(vt.term)
333}
334
335func (vt *VTerm) KeyboardUnichar(c rune, mods Modifier) {
336	C.vterm_keyboard_unichar(vt.term, C.uint32_t(c), C.VTermModifier(mods))
337}
338
339func (vt *VTerm) KeyboardKey(key Key, mods Modifier) {
340	C.vterm_keyboard_key(vt.term, C.VTermKey(key), C.VTermModifier(mods))
341}
342
343func (vt *VTerm) ObtainState() *State {
344	return &State{
345		state: C.vterm_obtain_state(vt.term),
346	}
347}
348
349func (vt *VTerm) Read(b []byte) (int, error) {
350	curlen := C.vterm_output_read(vt.term, (*C.char)(unsafe.Pointer(&b[0])), C.size_t(len(b)))
351	return int(curlen), nil
352}
353
354func (vt *VTerm) Write(b []byte) (int, error) {
355	if len(b) == 0 {
356		return 0, nil
357	}
358	return int(C.vterm_input_write(vt.term, (*C.char)(unsafe.Pointer(&b[0])), C.size_t(len(b)))), nil
359}
360
361func (vt *VTerm) ObtainScreen() *Screen {
362	return vt.screen
363}
364
365func (vt *VTerm) UTF8() bool {
366	return C.vterm_get_utf8(vt.term) != C.int(0)
367}
368
369func (vt *VTerm) SetUTF8(b bool) {
370	var v C.int
371	if b {
372		v = 1
373	}
374	C.vterm_set_utf8(vt.term, v)
375}
376
377type VTermValue struct {
378	Boolean bool
379	Number  int
380	String  string
381	Color   VTermColor
382}
383
384const (
385	_ = iota
386	VTERM_PROP_CURSORVISIBLE
387	VTERM_PROP_CURSORBLINK
388	VTERM_PROP_ALTSCREEN
389	VTERM_PROP_TITLE
390	VTERM_PROP_ICONNAME
391	VTERM_PROP_REVERSE
392	VTERM_PROP_CURSORSHAPE
393	VTERM_PROP_MOUSE
394)
395
396type Screen struct {
397	screen *C.VTermScreen
398
399	UserData      interface{}
400	OnDamage      func(*Rect) int
401	OnResize      func(int, int) int
402	OnMoveRect    func(*Rect, *Rect) int
403	OnMoveCursor  func(*Pos, *Pos, bool) int
404	OnBell        func() int
405	OnSetTermProp func(int, *VTermValue) int
406	/*
407	  int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user);
408	  int (*sb_popline)(int cols, VTermScreenCell *cells, void *user);
409	*/
410}
411
412func (scr *Screen) Flush() error {
413	C.vterm_screen_flush_damage(scr.screen)
414	return nil // TODO
415}
416
417func (sc *Screen) GetCellAt(row, col int) (*ScreenCell, error) {
418	return sc.GetCell(NewPos(row, col))
419}
420
421func (sc *Screen) GetCell(pos *Pos) (*ScreenCell, error) {
422	var cell ScreenCell
423	if C.vterm_screen_get_cell(sc.screen, pos.pos, &cell.cell) == 0 {
424		return nil, errors.New("GetCell")
425	}
426	return &cell, nil
427}
428
429func (scr *Screen) GetChars(r *[]rune, rect *Rect) int {
430	l := len(*r)
431	buf := make([]C.uint32_t, l)
432	ret := int(C.vterm_screen_get_chars(scr.screen, &buf[0], C.size_t(l), rect.rect))
433	*r = make([]rune, ret)
434	for i := 0; i < ret; i++ {
435		(*r)[i] = rune(buf[i])
436	}
437	return ret
438}
439
440func (scr *Screen) Reset(hard bool) {
441	var v C.int
442	if hard {
443		v = 1
444	}
445	C.vterm_screen_reset(scr.screen, v)
446}
447
448func (scr *Screen) EnableAltScreen(e bool) {
449	var v C.int
450	if e {
451		v = 1
452	}
453	C.vterm_screen_enable_altscreen(scr.screen, v)
454}
455
456func (scr *Screen) IsEOL(pos *Pos) bool {
457	return C.vterm_screen_is_eol(scr.screen, pos.pos) != C.int(0)
458}
459
460type State struct {
461	state *C.VTermState
462}
463
464func (s *State) SetDefaultColors(fg, bg VTermColor) {
465	C.vterm_state_set_default_colors(s.state, &fg.color, &bg.color)
466}
467
468// index between 0 and 15, 0-7 are normal colors and 8-15 are bright colors.
469func (s *State) SetPaletteColor(index int, col VTermColor) {
470	if index < 0 || index >= 256 {
471		panic("Index out of range")
472	}
473	C.vterm_state_set_palette_color(s.state, C.int(index), &col.color)
474}
475
476func (s *State) GetDefaultColors() (fg, bg VTermColor) {
477	c_fg := C.VTermColor{}
478	c_bg := C.VTermColor{}
479	C.vterm_state_get_default_colors(s.state, &c_fg, &c_bg)
480	fg = VTermColor{c_fg}
481	bg = VTermColor{c_bg}
482	return
483}
484
485func (s *State) GetCursorPos() (int, int) {
486	var pos C.VTermPos
487	C.vterm_state_get_cursorpos(s.state, &pos)
488	return int(pos.row), int(pos.col)
489}
490
491// index between 0 and 15, 0-7 are normal colors and 8-15 are bright colors.
492func (s *State) GetPaletteColor(index int) VTermColor {
493	if index < 0 || index >= 256 {
494		panic("Index out of range")
495	}
496	c_color := C.VTermColor{}
497	C.vterm_state_get_palette_color(s.state, C.int(index), &c_color)
498	return VTermColor{c_color}
499}
500
501//export _go_handle_damage
502func _go_handle_damage(rect C.VTermRect, user unsafe.Pointer) C.int {
503	onDamage := pointer.Restore(user).(*VTerm).ObtainScreen().OnDamage
504	if onDamage != nil {
505		return C.int(onDamage(&Rect{rect: rect}))
506	}
507	return 0
508}
509
510//export _go_handle_bell
511func _go_handle_bell(user unsafe.Pointer) C.int {
512	onBell := pointer.Restore(user).(*VTerm).ObtainScreen().OnBell
513	if onBell != nil {
514		return C.int(onBell())
515	}
516	return 0
517}
518
519const (
520	vterm_valuetype_bool   = 1
521	vterm_valuetype_int    = 2
522	vterm_valuetype_string = 3
523	vterm_valuetype_color  = 4
524)
525
526//export _go_handle_set_term_prop
527func _go_handle_set_term_prop(prop C.VTermProp, val *C.VTermValue,
528	user unsafe.Pointer) C.int {
529
530	onSetTermProp := pointer.Restore(user).(*VTerm).ObtainScreen().OnSetTermProp
531
532	if onSetTermProp != nil {
533		value := VTermValue{}
534
535		switch int(C.vterm_get_prop_type(prop)) {
536		case vterm_valuetype_bool:
537			value.Boolean = bool(C._vterm_value_get_boolean(val))
538		case vterm_valuetype_int:
539			value.Number = int(C._vterm_value_get_number(val))
540		case vterm_valuetype_string:
541			value.String = C.GoString(C._vterm_value_get_string(val))
542		case vterm_valuetype_color:
543			return 0 // TODO
544		default:
545			return 0
546		}
547
548		return C.int(onSetTermProp(int(prop), &value))
549	}
550	return 0
551}
552
553//export _go_handle_resize
554func _go_handle_resize(row, col C.int, user unsafe.Pointer) C.int {
555	onResize := pointer.Restore(user).(*VTerm).ObtainScreen().OnResize
556	if onResize != nil {
557		return C.int(onResize(int(row), int(col)))
558	}
559	return 0
560}
561
562//export _go_handle_moverect
563func _go_handle_moverect(dest, src C.VTermRect, user unsafe.Pointer) C.int {
564	onMoveRect := pointer.Restore(user).(*VTerm).ObtainScreen().OnMoveRect
565	if onMoveRect != nil {
566		return C.int(onMoveRect(&Rect{rect: dest}, &Rect{rect: src}))
567	}
568	return 0
569}
570
571//export _go_handle_movecursor
572func _go_handle_movecursor(pos, oldpos C.VTermPos, visible C.int, user unsafe.Pointer) C.int {
573	onMoveCursor := pointer.Restore(user).(*VTerm).ObtainScreen().OnMoveCursor
574	if onMoveCursor != nil {
575		var b bool
576		if visible != C.int(0) {
577			b = true
578		}
579		return C.int(onMoveCursor(&Pos{pos: pos}, &Pos{pos: oldpos}, b))
580	}
581	return 0
582}
583