// +build windows linux darwin openbsd freebsd netbsd
package liner
import (
"container/ring"
"errors"
"fmt"
"io"
"strings"
"unicode"
"unicode/utf8"
)
type action int
const (
left action = iota
right
up
down
home
end
insert
del
pageUp
pageDown
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
f11
f12
altB
altF
altY
shiftTab
wordLeft
wordRight
winch
unknown
)
const (
ctrlA = 1
ctrlB = 2
ctrlC = 3
ctrlD = 4
ctrlE = 5
ctrlF = 6
ctrlG = 7
ctrlH = 8
tab = 9
lf = 10
ctrlK = 11
ctrlL = 12
cr = 13
ctrlN = 14
ctrlO = 15
ctrlP = 16
ctrlQ = 17
ctrlR = 18
ctrlS = 19
ctrlT = 20
ctrlU = 21
ctrlV = 22
ctrlW = 23
ctrlX = 24
ctrlY = 25
ctrlZ = 26
esc = 27
bs = 127
)
const (
beep = "\a"
)
type tabDirection int
const (
tabForward tabDirection = iota
tabReverse
)
func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
s.needRefresh = false
if s.multiLineMode {
return s.refreshMultiLine(prompt, buf, pos)
}
return s.refreshSingleLine(prompt, buf, pos)
}
func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error {
s.cursorPos(0)
_, err := fmt.Print(string(prompt))
if err != nil {
return err
}
pLen := countGlyphs(prompt)
bLen := countGlyphs(buf)
pos = countGlyphs(buf[:pos])
if pLen+bLen < s.columns {
_, err = fmt.Print(string(buf))
s.eraseLine()
s.cursorPos(pLen + pos)
} else {
// Find space available
space := s.columns - pLen
space-- // space for cursor
start := pos - space/2
end := start + space
if end > bLen {
end = bLen
start = end - space
}
if start < 0 {
start = 0
end = space
}
pos -= start
// Leave space for markers
if start > 0 {
start++
}
if end < bLen {
end--
}
startRune := len(getPrefixGlyphs(buf, start))
line := getPrefixGlyphs(buf[startRune:], end-start)
// Output
if start > 0 {
fmt.Print("{")
}
fmt.Print(string(line))
if end < bLen {
fmt.Print("}")
}
// Set cursor position
s.eraseLine()
s.cursorPos(pLen + pos)
}
return err
}
func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error {
promptColumns := countMultiLineGlyphs(prompt, s.columns, 0)
totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns)
totalRows := (totalColumns + s.columns - 1) / s.columns
maxRows := s.maxRows
if totalRows > s.maxRows {
s.maxRows = totalRows
}
cursorRows := s.cursorRows
if cursorRows == 0 {
cursorRows = 1
}
/* First step: clear all the lines used before. To do so start by
* going to the last row. */
if maxRows-cursorRows > 0 {
s.moveDown(maxRows - cursorRows)
}
/* Now for every row clear it, go up. */
for i := 0; i < maxRows-1; i++ {
s.cursorPos(0)
s.eraseLine()
s.moveUp(1)
}
/* Clean the top line. */
s.cursorPos(0)
s.eraseLine()
/* Write the prompt and the current buffer content */
if _, err := fmt.Print(string(prompt)); err != nil {
return err
}
if _, err := fmt.Print(string(buf)); err != nil {
return err
}
/* If we are at the very end of the screen with our prompt, we need to
* emit a newline and move the prompt to the first column. */
|