Path: blob/main/vendor/github.com/chzyer/readline/utils.go
2875 views
package readline12import (3"bufio"4"bytes"5"container/list"6"fmt"7"os"8"os/signal"9"strconv"10"strings"11"sync"12"syscall"13"time"14"unicode"15)1617var (18isWindows = false19)2021const (22CharLineStart = 123CharBackward = 224CharInterrupt = 325CharDelete = 426CharLineEnd = 527CharForward = 628CharBell = 729CharCtrlH = 830CharTab = 931CharCtrlJ = 1032CharKill = 1133CharCtrlL = 1234CharEnter = 1335CharNext = 1436CharPrev = 1637CharBckSearch = 1838CharFwdSearch = 1939CharTranspose = 2040CharCtrlU = 2141CharCtrlW = 2342CharCtrlY = 2543CharCtrlZ = 2644CharEsc = 2745CharO = 7946CharEscapeEx = 9147CharBackspace = 12748)4950const (51MetaBackward rune = -iota - 152MetaForward53MetaDelete54MetaBackspace55MetaTranspose56)5758// WaitForResume need to call before current process got suspend.59// It will run a ticker until a long duration is occurs,60// which means this process is resumed.61func WaitForResume() chan struct{} {62ch := make(chan struct{})63var wg sync.WaitGroup64wg.Add(1)65go func() {66ticker := time.NewTicker(10 * time.Millisecond)67t := time.Now()68wg.Done()69for {70now := <-ticker.C71if now.Sub(t) > 100*time.Millisecond {72break73}74t = now75}76ticker.Stop()77ch <- struct{}{}78}()79wg.Wait()80return ch81}8283func Restore(fd int, state *State) error {84err := restoreTerm(fd, state)85if err != nil {86// errno 0 means everything is ok :)87if err.Error() == "errno 0" {88return nil89} else {90return err91}92}93return nil94}9596func IsPrintable(key rune) bool {97isInSurrogateArea := key >= 0xd800 && key <= 0xdbff98return key >= 32 && !isInSurrogateArea99}100101// translate Esc[X102func escapeExKey(key *escapeKeyPair) rune {103var r rune104switch key.typ {105case 'D':106r = CharBackward107case 'C':108r = CharForward109case 'A':110r = CharPrev111case 'B':112r = CharNext113case 'H':114r = CharLineStart115case 'F':116r = CharLineEnd117case '~':118if key.attr == "3" {119r = CharDelete120}121default:122}123return r124}125126// translate EscOX SS3 codes for up/down/etc.127func escapeSS3Key(key *escapeKeyPair) rune {128var r rune129switch key.typ {130case 'D':131r = CharBackward132case 'C':133r = CharForward134case 'A':135r = CharPrev136case 'B':137r = CharNext138case 'H':139r = CharLineStart140case 'F':141r = CharLineEnd142default:143}144return r145}146147type escapeKeyPair struct {148attr string149typ rune150}151152func (e *escapeKeyPair) Get2() (int, int, bool) {153sp := strings.Split(e.attr, ";")154if len(sp) < 2 {155return -1, -1, false156}157s1, err := strconv.Atoi(sp[0])158if err != nil {159return -1, -1, false160}161s2, err := strconv.Atoi(sp[1])162if err != nil {163return -1, -1, false164}165return s1, s2, true166}167168func readEscKey(r rune, reader *bufio.Reader) *escapeKeyPair {169p := escapeKeyPair{}170buf := bytes.NewBuffer(nil)171for {172if r == ';' {173} else if unicode.IsNumber(r) {174} else {175p.typ = r176break177}178buf.WriteRune(r)179r, _, _ = reader.ReadRune()180}181p.attr = buf.String()182return &p183}184185// translate EscX to Meta+X186func escapeKey(r rune, reader *bufio.Reader) rune {187switch r {188case 'b':189r = MetaBackward190case 'f':191r = MetaForward192case 'd':193r = MetaDelete194case CharTranspose:195r = MetaTranspose196case CharBackspace:197r = MetaBackspace198case 'O':199d, _, _ := reader.ReadRune()200switch d {201case 'H':202r = CharLineStart203case 'F':204r = CharLineEnd205default:206reader.UnreadRune()207}208case CharEsc:209210}211return r212}213214func SplitByLine(start, screenWidth int, rs []rune) []string {215var ret []string216buf := bytes.NewBuffer(nil)217currentWidth := start218for _, r := range rs {219w := runes.Width(r)220currentWidth += w221buf.WriteRune(r)222if currentWidth >= screenWidth {223ret = append(ret, buf.String())224buf.Reset()225currentWidth = 0226}227}228ret = append(ret, buf.String())229return ret230}231232// calculate how many lines for N character233func LineCount(screenWidth, w int) int {234r := w / screenWidth235if w%screenWidth != 0 {236r++237}238return r239}240241func IsWordBreak(i rune) bool {242switch {243case i >= 'a' && i <= 'z':244case i >= 'A' && i <= 'Z':245case i >= '0' && i <= '9':246default:247return true248}249return false250}251252func GetInt(s []string, def int) int {253if len(s) == 0 {254return def255}256c, err := strconv.Atoi(s[0])257if err != nil {258return def259}260return c261}262263type RawMode struct {264state *State265}266267func (r *RawMode) Enter() (err error) {268r.state, err = MakeRaw(GetStdin())269return err270}271272func (r *RawMode) Exit() error {273if r.state == nil {274return nil275}276return Restore(GetStdin(), r.state)277}278279// -----------------------------------------------------------------------------280281func sleep(n int) {282Debug(n)283time.Sleep(2000 * time.Millisecond)284}285286// print a linked list to Debug()287func debugList(l *list.List) {288idx := 0289for e := l.Front(); e != nil; e = e.Next() {290Debug(idx, fmt.Sprintf("%+v", e.Value))291idx++292}293}294295// append log info to another file296func Debug(o ...interface{}) {297f, _ := os.OpenFile("debug.tmp", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)298fmt.Fprintln(f, o...)299f.Close()300}301302func CaptureExitSignal(f func()) {303cSignal := make(chan os.Signal, 1)304signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM)305go func() {306for range cSignal {307f()308}309}()310}311312313