Files
jira/vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader.go
T
2017-09-06 11:35:00 -07:00

184 lines
4.2 KiB
Go

package terminal
import (
"os"
"unicode"
)
type RuneReader struct {
Input *os.File
state runeReaderState
}
func NewRuneReader(input *os.File) *RuneReader {
return &RuneReader{
Input: input,
state: newRuneReaderState(input),
}
}
func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) {
line := []rune{}
// we only care about horizontal displacements from the origin so start counting at 0
index := 0
for {
// wait for some input
r, _, err := rr.ReadRune()
if err != nil {
return line, err
}
// if the user pressed enter or some other newline/termination like ctrl+d
if r == '\r' || r == '\n' || r == KeyEndTransmission {
// go to the beginning of the next line
Print("\r\n")
// we're done processing the input
return line, nil
}
// if the user interrupts (ie with ctrl+c)
if r == KeyInterrupt {
// go to the beginning of the next line
Print("\r\n")
// we're done processing the input, and treat interrupt like an error
return line, InterruptErr
}
// allow for backspace/delete editing of inputs
if r == KeyBackspace || r == KeyDelete {
// and we're not at the beginning of the line
if index > 0 && len(line) > 0 {
// if we are at the end of the word
if index == len(line) {
// just remove the last letter from the internal representation
line = line[:len(line)-1]
// go back one
CursorBack(1)
// clear the rest of the line
EraseLine(ERASE_LINE_END)
} else {
// we need to remove a character from the middle of the word
// remove the current index from the list
line = append(line[:index-1], line[index:]...)
// go back one space so we can clear the rest
CursorBack(1)
// clear the rest of the line
EraseLine(ERASE_LINE_END)
// print what comes after
Print(string(line[index-1:]))
// leave the cursor where the user left it
CursorBack(len(line) - index + 1)
}
// decrement the index
index--
} else {
// otherwise the user pressed backspace while at the beginning of the line
soundBell()
}
// we're done processing this key
continue
}
// if the left arrow is pressed
if r == KeyArrowLeft {
// and we have space to the left
if index > 0 {
// move the cursor to the left
CursorBack(1)
// decrement the index
index--
} else {
// otherwise we are at the beginning of where we started reading lines
// sound the bell
soundBell()
}
// we're done processing this key press
continue
}
// if the right arrow is pressed
if r == KeyArrowRight {
// and we have space to the right of the word
if index < len(line) {
// move the cursor to the right
CursorForward(1)
// increment the index
index++
} else {
// otherwise we are at the end of the word and can't go past
// sound the bell
soundBell()
}
// we're done processing this key press
continue
}
// if the letter is another escape sequence
if unicode.IsControl(r) {
// ignore it
continue
}
// the user pressed a regular key
// if we are at the end of the line
if index == len(line) {
// just append the character at the end of the line
line = append(line, r)
// increment the location counter
index++
// if we don't need to mask the input
if mask == 0 {
// just print the character the user pressed
Printf("%c", r)
} else {
// otherwise print the mask we were given
Printf("%c", mask)
}
} else {
// we are in the middle of the word so we need to insert the character the user pressed
line = append(line[:index], append([]rune{r}, line[index:]...)...)
// visually insert the character by deleting the rest of the line
EraseLine(ERASE_LINE_END)
// print the rest of the word after
for _, char := range line[index:] {
// if we don't need to mask the input
if mask == 0 {
// just print the character the user pressed
Printf("%c", char)
} else {
// otherwise print the mask we were given
Printf("%c", mask)
}
}
// leave the cursor where the user left it
CursorBack(len(line) - index - 1)
// accomodate the new letter in our counter
index++
}
}
}