src

Go monorepo.
Log | Files | Refs

commit fda86a519e22051317e398ef8b2de048acb7973a
parent 005551137577929740796b239f33928b61245bd4
Author: dwrz <dwrz@dwrz.net>
Date:   Fri,  2 Dec 2022 16:20:54 +0000

Add terminal pkg

Diffstat:
Apkg/terminal/key.go | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apkg/terminal/terminal.go | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 247 insertions(+), 0 deletions(-)

diff --git a/pkg/terminal/key.go b/pkg/terminal/key.go @@ -0,0 +1,137 @@ +package terminal + +const ( + // Control Characters + Null rune = 0 + StartOfHeading rune = 1 + StartOfText rune = 2 + EndOfText rune = 3 + EndOfTransmission rune = 4 + Enquiry rune = 5 + Acknowledgment rune = 6 + Bell rune = 7 + Backspace rune = 8 + HorizontalTab rune = 9 + LineFeed rune = 10 + VerticalTab rune = 11 + FormFeed rune = 12 + CarriageReturn rune = 13 + ShiftOut rune = 14 + ShiftIn rune = 15 + DataLineEscape rune = 16 + DeviceControl1 rune = 17 + DeviceControl2 rune = 18 + DeviceControl3 rune = 19 + DeviceControl4 rune = 20 + NegativeAcknowledgment rune = 21 + SynchronousIdle rune = 22 + EndOfTransmitBlock rune = 23 + Cancel rune = 24 + EndOfMedium rune = 25 + Substitute rune = 26 + Escape rune = 27 + FileSeparator rune = 28 + GroupSeparator rune = 29 + RecordSeparator rune = 30 + UnitSeparator rune = 31 + + // Printable Characters + Space rune = 32 + ExclamationMark rune = 33 + DoubleQuote rune = 34 + Number rune = 35 + Dollar rune = 36 + Percentage rune = 37 + Ampersand rune = 38 + SingleQuote rune = 39 + LeftParenthesis rune = 40 + RightParenthesis rune = 41 + Asterisk rune = 42 + Plus rune = 43 + Comma rune = 44 + Hyphen rune = 45 + Period rune = 46 + ForwardSlash rune = 47 + Zero rune = 48 + One rune = 49 + Two rune = 50 + Three rune = 51 + Four rune = 52 + Five rune = 53 + Six rune = 54 + Seven rune = 55 + Eight rune = 56 + Nine rune = 57 + Colon rune = 58 + Semicolon rune = 59 + LessThan rune = 60 + Equals rune = 61 + GreaterThan rune = 62 + QuestionMark rune = 63 + At rune = 64 + UpperA rune = 65 + UpperB rune = 66 + UpperC rune = 67 + UpperD rune = 68 + UpperE rune = 69 + UpperF rune = 70 + UpperG rune = 71 + UpperH rune = 72 + UpperI rune = 73 + UpperJ rune = 74 + UpperK rune = 75 + UpperL rune = 76 + UpperM rune = 77 + UpperN rune = 78 + UpperO rune = 79 + UpperP rune = 80 + UpperQ rune = 81 + UpperR rune = 82 + UpperS rune = 83 + UpperT rune = 84 + UpperU rune = 85 + UpperV rune = 86 + UpperW rune = 87 + UpperX rune = 88 + UpperY rune = 89 + UpperZ rune = 90 + LeftBracket rune = 91 + Backslash rune = 92 + RightBracket rune = 93 + Caret rune = 94 + Underscore rune = 95 + Grave rune = 96 + LowerA rune = 97 + LowerB rune = 98 + LowerC rune = 99 + LowerD rune = 100 + LowerE rune = 101 + LowerF rune = 102 + LowerG rune = 103 + LowerH rune = 104 + LowerI rune = 105 + LowerJ rune = 106 + LowerK rune = 107 + LowerL rune = 108 + LowerM rune = 109 + LowerN rune = 110 + LowerO rune = 111 + LowerP rune = 112 + LowerQ rune = 113 + LowerR rune = 114 + LowerS rune = 115 + LowerT rune = 116 + LowerU rune = 117 + LowerV rune = 118 + LowerW rune = 119 + LowerX rune = 120 + LowerY rune = 121 + LowerZ rune = 122 + LeftBrace rune = 123 + VerticalBar rune = 124 + RightBrace rune = 125 + Tilde rune = 126 + Delete rune = 127 +) + +const Control = 0x1f diff --git a/pkg/terminal/terminal.go b/pkg/terminal/terminal.go @@ -0,0 +1,110 @@ +package terminal + +import ( + "fmt" + "syscall" + "unsafe" +) + +const ( + ClearScreen = "\u001Bc" + CursorHide = "\u001B[?25l" + CursorShow = "\u001B[?25h" + CursorTopLeft = "\u001B[H" + EraseLine = "\u001B[K" + + SetCursorFmt = "\u001B[%d;%dH" +) + +type Terminal struct { + fd uintptr + termios *syscall.Termios +} + +type Size struct { + Rows uint16 + Columns uint16 + XPixels uint16 + YPixels uint16 +} + +func New(fd uintptr) (*Terminal, error) { + var t = &Terminal{ + termios: &syscall.Termios{}, + } + + if _, _, err := syscall.Syscall( + syscall.SYS_IOCTL, + fd, + syscall.TCGETS, + uintptr(unsafe.Pointer(t.termios)), + ); err != 0 { + return nil, fmt.Errorf("ioctl syscall: %w", err) + } + + return t, nil +} + +// Reset the terminal into the original termios. +func (t *Terminal) Reset() error { + if _, _, err := syscall.Syscall( + syscall.SYS_IOCTL, + t.fd, + uintptr(syscall.TCSETS), + uintptr(unsafe.Pointer(t.termios)), + ); err != 0 { + return fmt.Errorf("ioctl syscall: %w", err) + } + + return nil +} + +// SetRaw enables raw mode. +func (t *Terminal) SetRaw() error { + var termios = *t.termios + termios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON + termios.Oflag &^= syscall.OPOST + termios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN + termios.Cflag &^= syscall.CSIZE | syscall.PARENB + termios.Cflag |= syscall.CS8 + termios.Cc[syscall.VMIN] = 1 + termios.Cc[syscall.VTIME] = 0 + + if _, _, err := syscall.Syscall( + syscall.SYS_IOCTL, + t.fd, + uintptr(syscall.TCSETS), + uintptr(unsafe.Pointer(&termios)), + ); err != 0 { + return fmt.Errorf("ioctl syscall: %w", err) + } + + return nil +} + +func (t *Terminal) size() (*Size, error) { + var s = &Size{} + if _, _, err := syscall.Syscall( + syscall.SYS_IOCTL, + t.fd, + syscall.TIOCGWINSZ, + uintptr(unsafe.Pointer(s)), + ); err != 0 { + return nil, fmt.Errorf("ioctl syscall: %w", err) + } + + return s, nil +} + +// Size returns the zero-indexed size of the terminal. +func (t *Terminal) Size() (*Size, error) { + size, err := t.size() + if err != nil { + return nil, err + } + + size.Columns-- + size.Rows-- + + return size, nil +}