readline/utils.go

247 lines
4.0 KiB
Go
Raw Normal View History

2015-09-20 18:14:29 +03:00
package readline
import (
"strconv"
2015-09-28 04:46:33 +03:00
"syscall"
"unicode"
2015-09-20 18:14:29 +03:00
"golang.org/x/crypto/ssh/terminal"
)
2015-09-28 04:46:33 +03:00
var (
StdinFd = int(uintptr(syscall.Stdin))
isWindows = false
2015-09-28 04:46:33 +03:00
)
2015-09-20 18:14:29 +03:00
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
return terminal.IsTerminal(fd)
}
func MakeRaw(fd int) (*terminal.State, error) {
return terminal.MakeRaw(fd)
}
func Restore(fd int, state *terminal.State) error {
2015-09-24 19:16:49 +03:00
err := terminal.Restore(fd, state)
if err != nil {
2015-09-27 05:50:14 +03:00
// errno 0 means everything is ok :)
2015-09-24 19:16:49 +03:00
if err.Error() == "errno 0" {
err = nil
}
}
return nil
2015-09-20 18:14:29 +03:00
}
func IsPrintable(key rune) bool {
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
return key >= 32 && !isInSurrogateArea
}
2015-09-27 05:50:14 +03:00
// translate Esc[X
func escapeExKey(r rune) rune {
switch r {
case 'D':
r = CharBackward
case 'C':
r = CharForward
case 'A':
r = CharPrev
case 'B':
r = CharNext
}
return r
}
2015-09-27 05:50:14 +03:00
// translate EscX to Meta+X
func escapeKey(r rune) rune {
2015-09-20 18:14:29 +03:00
switch r {
case 'b':
2015-10-01 17:44:43 +03:00
r = MetaBackward
2015-09-20 18:14:29 +03:00
case 'f':
2015-10-01 17:44:43 +03:00
r = MetaForward
2015-09-20 18:14:29 +03:00
case 'd':
r = MetaDelete
2015-09-23 08:03:13 +03:00
case CharTranspose:
r = MetaTranspose
2015-09-21 16:00:48 +03:00
case CharBackspace:
r = MetaBackspace
2015-09-23 06:46:56 +03:00
case CharEsc:
2015-09-21 08:13:30 +03:00
2015-09-20 18:14:29 +03:00
}
return r
}
2015-09-27 05:50:14 +03:00
func RunesEqual(a, b []rune) bool {
2015-09-21 16:00:48 +03:00
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false
}
}
return true
}
2015-09-21 17:27:40 +03:00
2015-09-27 05:50:14 +03:00
// calculate how many lines for N character
2015-09-22 18:01:15 +03:00
func LineCount(w int) int {
screenWidth := getWidth()
r := w / screenWidth
if w%screenWidth != 0 {
r++
}
return r
}
2015-09-27 05:50:14 +03:00
// Search in runes from end to front
2015-09-23 06:10:36 +03:00
func RunesIndexBck(r, sub []rune) int {
for i := len(r) - len(sub); i >= 0; i-- {
found := true
for j := 0; j < len(sub); j++ {
if r[i+j] != sub[j] {
found = false
break
}
}
if found {
return i
}
}
return -1
}
2015-09-27 05:50:14 +03:00
// Search in runes from front to end
2015-09-22 18:01:15 +03:00
func RunesIndex(r, sub []rune) int {
for i := 0; i < len(r); i++ {
found := true
if len(r[i:]) < len(sub) {
return -1
}
for j := 0; j < len(sub); j++ {
if r[i+j] != sub[j] {
found = false
break
}
}
if found {
return i
}
}
return -1
}
2015-09-23 06:59:39 +03:00
func IsWordBreak(i rune) bool {
if i >= 'a' && i <= 'z' {
return false
}
if i >= 'A' && i <= 'Z' {
return false
}
return true
}
var zeroWidth = []*unicode.RangeTable{
unicode.Mn,
unicode.Me,
unicode.Cc,
unicode.Cf,
}
var doubleWidth = []*unicode.RangeTable{
unicode.Han,
unicode.Hangul,
unicode.Hiragana,
unicode.Katakana,
}
func RuneIndex(r rune, rs []rune) int {
for i := 0; i < len(rs); i++ {
if rs[i] == r {
return i
}
}
return -1
}
func RunesColorFilter(r []rune) []rune {
newr := make([]rune, 0, len(r))
for pos := 0; pos < len(r); pos++ {
if r[pos] == '\033' && r[pos+1] == '[' {
idx := RuneIndex('m', r[pos+2:])
if idx == -1 {
continue
}
pos += idx + 2
continue
}
newr = append(newr, r[pos])
}
return newr
}
func RuneWidth(r rune) int {
if unicode.IsOneOf(zeroWidth, r) {
return 0
}
if unicode.IsOneOf(doubleWidth, r) {
return 2
}
return 1
}
func RunesWidth(r []rune) (length int) {
for i := 0; i < len(r); i++ {
length += RuneWidth(r[i])
}
return
}
2015-09-25 17:56:00 +03:00
2015-09-27 05:50:14 +03:00
func RunesAggregate(candicate [][]rune) (same []rune, size int) {
2015-09-25 17:56:00 +03:00
for i := 0; i < len(candicate[0]); i++ {
for j := 0; j < len(candicate)-1; j++ {
if i >= len(candicate[j]) || i >= len(candicate[j+1]) {
goto aggregate
}
if candicate[j][i] != candicate[j+1][i] {
goto aggregate
}
}
size = i + 1
}
aggregate:
if size > 0 {
2015-09-27 05:50:14 +03:00
same = RunesCopy(candicate[0][:size])
2015-09-25 17:56:00 +03:00
for i := 0; i < len(candicate); i++ {
2015-09-27 05:50:14 +03:00
n := RunesCopy(candicate[i])
2015-09-25 17:56:00 +03:00
copy(n, n[size:])
candicate[i] = n[:len(n)-size]
}
}
return
}
2015-09-27 05:50:14 +03:00
func RunesCopy(r []rune) []rune {
2015-09-25 17:56:00 +03:00
n := make([]rune, len(r))
copy(n, r)
return n
}
2015-09-25 19:31:09 +03:00
func RunesHasPrefix(r, prefix []rune) bool {
if len(r) < len(prefix) {
return false
}
2015-09-27 05:50:14 +03:00
return RunesEqual(r[:len(prefix)], prefix)
2015-09-25 19:31:09 +03:00
}
func GetInt(s []string, def int) int {
if len(s) == 0 {
return def
}
c, err := strconv.Atoi(s[0])
if err != nil {
return def
}
return c
}