package main import ( "fmt" "os" "strconv" "strings" "time" "unicode" "github.com/fatih/color" "golang.org/x/crypto/ssh/terminal" ) var ( inputBuffer = new(ColorString) oldLineContent = new(ColorString) oldWidth int debugInfo string ) func main() { // enable raw mode doItRaw() defer cook() inputChannel := handleInput() running := true refreshInputBuffer(true) for running { select { case input := <-inputChannel: if unicode.IsControl(rune(input)) { if input == 127 && inputBuffer.Len() > 0 { // Backspace str := inputBuffer.Raw() inputBuffer = new(ColorString) inputBuffer.Append(str[:len(str)-1]) } else if input == 12 { // C-L clear() refreshInputBuffer(true) } else if input == 13 { // Enter cmd := inputBuffer.Raw() if strings.TrimSpace(cmd) == "exit" { running = false break } inputBuffer = new(ColorString) fmt.Print("\r\n") handle(cmd) refreshInputBuffer(true) } else if input == 3 { // C-C inputBuffer = new(ColorString) } else if input == 17 { // C-Q running = false break } //fmt.Print(input, "\r\n") break } inputBuffer.Append(string(input)) case <-time.After(time.Second): } refreshInputBuffer(false) } } func refreshInputBuffer(force bool) { ps := prompt() lineContent := new(ColorString).AppendColorString(ps, inputBuffer) width, _, err := terminal.GetSize(int(os.Stdin.Fd())) if err != nil { panic(err) } if oldWidth == 0 { oldWidth = width } lines := oldLineContent.Len() / width debugInfo = strconv.Itoa(lines) for i := 0; i <= lines; i++ { fmt.Print("\r") clearEOL() if i < lines { goUp() } } fmt.Print(lineContent.String()) oldLineContent = lineContent oldWidth = width } // func refreshInputBuffer(force bool) { // width, _, err := terminal.GetSize(int(os.Stdin.Fd())) // if err != nil { // panic(err) // } // clearEOL() // debugInfo = fmt.Sprint(oldLineContent.Len(), width, oldLineContent.Len()/width) // for i := 0; i < oldLineContent.Len()/width; i++ { // goUp() // } // ps := prompt() // lineContent := new(ColorString).AppendColorString(ps, inputBuffer) // if !force && lineContent.Equals(oldLineContent) { // return // } // diff := lineContent.Len() - oldLineContent.Len() // if diff < 0 { // diff = -diff // } // for i := 0; i < diff; i++ { // goLeft() // } // clearEOL() // fmt.Print("\r") // fmt.Print(lineContent.String()) // oldLineContent = lineContent // } // func getTerminalSize() (width, height int, err error) { // width, height, err = terminal.GetSize(int(os.Stdout.Fd())) // if err != nil { // return 0, 0, adverr.Wrap("Could not retrieve terminal size", err) // } // return // } func print(str string, attrs ...color.Attribute) string { return color.New(attrs...).Sprint(str) } func host() string { hostname, _ := os.Hostname() return hostname } func wd() string { wd, _ := os.Getwd() home := env("HOME") return strings.Replace(wd, home, "~", 1) } func env(key string) string { value, _ := os.LookupEnv(key) return value }