1package terminal 2 3import ( 4 "bytes" 5 "syscall" 6 "unsafe" 7) 8 9var COORDINATE_SYSTEM_BEGIN Short = 0 10 11// shared variable to save the cursor location from CursorSave() 12var cursorLoc Coord 13 14type Cursor struct { 15 In FileReader 16 Out FileWriter 17} 18 19func (c *Cursor) Up(n int) { 20 c.cursorMove(0, n) 21} 22 23func (c *Cursor) Down(n int) { 24 c.cursorMove(0, -1*n) 25} 26 27func (c *Cursor) Forward(n int) { 28 c.cursorMove(n, 0) 29} 30 31func (c *Cursor) Back(n int) { 32 c.cursorMove(-1*n, 0) 33} 34 35// save the cursor location 36func (c *Cursor) Save() { 37 cursorLoc, _ = c.Location(nil) 38} 39 40func (c *Cursor) Restore() { 41 handle := syscall.Handle(c.Out.Fd()) 42 // restore it to the original position 43 procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursorLoc)))) 44} 45 46func (cur Coord) CursorIsAtLineEnd(size *Coord) bool { 47 return cur.X == size.X 48} 49 50func (cur Coord) CursorIsAtLineBegin() bool { 51 return cur.X == 0 52} 53 54func (c *Cursor) cursorMove(x int, y int) { 55 handle := syscall.Handle(c.Out.Fd()) 56 57 var csbi consoleScreenBufferInfo 58 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 59 60 var cursor Coord 61 cursor.X = csbi.cursorPosition.X + Short(x) 62 cursor.Y = csbi.cursorPosition.Y + Short(y) 63 64 procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) 65} 66 67func (c *Cursor) NextLine(n int) { 68 c.Up(n) 69 c.HorizontalAbsolute(0) 70} 71 72func (c *Cursor) PreviousLine(n int) { 73 c.Down(n) 74 c.HorizontalAbsolute(0) 75} 76 77// for comparability purposes between windows 78// in windows we don't have to print out a new line 79func (c *Cursor) MoveNextLine(cur Coord, terminalSize *Coord) { 80 c.NextLine(1) 81} 82 83func (c *Cursor) HorizontalAbsolute(x int) { 84 handle := syscall.Handle(c.Out.Fd()) 85 86 var csbi consoleScreenBufferInfo 87 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 88 89 var cursor Coord 90 cursor.X = Short(x) 91 cursor.Y = csbi.cursorPosition.Y 92 93 if csbi.size.X < cursor.X { 94 cursor.X = csbi.size.X 95 } 96 97 procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) 98} 99 100func (c *Cursor) Show() { 101 handle := syscall.Handle(c.Out.Fd()) 102 103 var cci consoleCursorInfo 104 procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 105 cci.visible = 1 106 107 procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 108} 109 110func (c *Cursor) Hide() { 111 handle := syscall.Handle(c.Out.Fd()) 112 113 var cci consoleCursorInfo 114 procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 115 cci.visible = 0 116 117 procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 118} 119 120func (c *Cursor) Location(buf *bytes.Buffer) (Coord, error) { 121 handle := syscall.Handle(c.Out.Fd()) 122 123 var csbi consoleScreenBufferInfo 124 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 125 126 return csbi.cursorPosition, nil 127} 128 129func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { 130 handle := syscall.Handle(c.Out.Fd()) 131 132 var csbi consoleScreenBufferInfo 133 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 134 // windows' coordinate system begins at (0, 0) 135 csbi.size.X-- 136 csbi.size.Y-- 137 return &csbi.size, nil 138} 139