mirror of
https://github.com/Threnklyn/jira.git
synced 2026-06-07 13:33:32 +02:00
184 lines
4.2 KiB
Go
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++
|
|
}
|
|
}
|
|
}
|