github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/readline/cursor.go (about) 1 package readline 2 3 import ( 4 "fmt" 5 "os" 6 "regexp" 7 "strconv" 8 ) 9 10 func leftMost() []byte { 11 fd := int(os.Stdout.Fd()) 12 w, _, err := GetSize(fd) 13 if err != nil { 14 return []byte{'\r', '\n'} 15 } 16 17 b := make([]byte, w+1) 18 for i := 0; i < w; i++ { 19 b[i] = ' ' 20 } 21 b[w] = '\r' 22 23 return b 24 } 25 26 var rxRcvCursorPos = regexp.MustCompile("^\x1b([0-9]+);([0-9]+)R$") 27 28 func (rl *Instance) getCursorPos() (x int, y int) { 29 if !ForceCrLf { 30 return 0, 0 31 } 32 33 if !rl.EnableGetCursorPos { 34 return -1, -1 35 } 36 37 disable := func() (int, int) { 38 printErr("\r\ngetCursorPos() not supported by terminal emulator, disabling....\r\n") 39 rl.EnableGetCursorPos = false 40 return -1, -1 41 } 42 43 print(seqGetCursorPos) 44 b := make([]byte, 64) 45 i, err := read(b) 46 if err != nil { 47 return disable() 48 } 49 50 if !rxRcvCursorPos.Match(b[:i]) { 51 return disable() 52 } 53 54 match := rxRcvCursorPos.FindAllStringSubmatch(string(b[:i]), 1) 55 y, err = strconv.Atoi(match[0][1]) 56 if err != nil { 57 return disable() 58 } 59 60 x, err = strconv.Atoi(match[0][2]) 61 if err != nil { 62 return disable() 63 } 64 65 return x, y 66 } 67 68 const ( 69 cursorUpf = "\x1b[%dA" 70 cursorDownf = "\x1b[%dB" 71 cursorForwf = "\x1b[%dC" 72 cursorBackf = "\x1b[%dD" 73 ) 74 75 func moveCursorUpStr(i int) string { 76 if i < 1 { 77 return "" 78 } 79 80 return fmt.Sprintf(cursorUpf, i) 81 } 82 83 func moveCursorDownStr(i int) string { 84 if i < 1 { 85 return "" 86 } 87 88 return fmt.Sprintf(cursorDownf, i) 89 } 90 91 func moveCursorForwardsStr(i int) string { 92 if i < 1 { 93 return "" 94 } 95 96 return fmt.Sprintf(cursorForwf, i) 97 } 98 99 func moveCursorBackwardsStr(i int) string { 100 if i < 1 { 101 return "" 102 } 103 104 return fmt.Sprintf(cursorBackf, i) 105 } 106 107 func (rl *Instance) moveCursorToStartStr() string { 108 posX, posY := rl.lineWrapCellPos() 109 return moveCursorBackwardsStr(posX-rl.promptLen) + moveCursorUpStr(posY) 110 } 111 112 func (rl *Instance) moveCursorFromStartToLinePosStr() string { 113 posX, posY := rl.lineWrapCellPos() 114 output := moveCursorForwardsStr(posX) 115 output += moveCursorDownStr(posY) 116 return output 117 } 118 119 func (rl *Instance) moveCursorFromEndToLinePosStr() string { 120 lineX, lineY := rl.lineWrapCellLen() 121 posX, posY := rl.lineWrapCellPos() 122 output := moveCursorBackwardsStr(lineX - posX) 123 output += moveCursorUpStr(lineY - posY) 124 return output 125 } 126 127 func (rl *Instance) moveCursorByRuneAdjustStr(rAdjust int) string { 128 oldX, oldY := rl.lineWrapCellPos() 129 130 rl.line.SetRunePos(rl.line.RunePos() + rAdjust) 131 132 newX, newY := rl.lineWrapCellPos() 133 134 y := newY - oldY 135 136 var output string 137 138 switch { 139 case y < 0: 140 output += moveCursorUpStr(-y) 141 case y > 0: 142 output += moveCursorDownStr(y) 143 } 144 145 x := newX - oldX 146 switch { 147 case x < 0: 148 output += moveCursorBackwardsStr(-x) 149 case x > 0: 150 output += moveCursorForwardsStr(x) 151 } 152 153 return output 154 }