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