diff --git a/main.go b/qline.go similarity index 80% rename from main.go rename to qline.go index 6b3437c..d3760cd 100644 --- a/main.go +++ b/qline.go @@ -1,4 +1,4 @@ -package main +package qline import ( "bufio" @@ -30,7 +30,7 @@ var ( width int ) -type Buffer struct { +type buffer struct { buf []rune cursor int maxWidth int @@ -39,11 +39,56 @@ type Buffer struct { prompt string } -func (lb Buffer) String() string { +func GetInput(prompt string, content string) string { + termios.SetCharMode() + cols, _ := termios.GetWindowSize() + b := buffer{make([]rune, 0, (len(content)+1)*2), 0, cols-len(prompt), 0, 0, prompt} + seeded := false + + fmt.Print(prompt) + fmt.Print("\033[6n") + + var ch rune + var err error + reader := bufio.NewReader(os.Stdin) + + for { + ch, err = readKey(reader) + if err != nil && err.Error() == "response" { + b.cursorStart = int(ch) + b.maxWidth = cols - b.cursorStart + } else if err != nil { + continue + } + if ch == CarriageReturn || ch == NewLine { + break + } + + if isControl(ch) { + b.controlInput(ch) + } else { + b.addChar(ch, true) + } + + // Seeding the content needs to happen + // _after_ reading in the width from the [6n + // function call. + if !seeded { + b.seedContent(content) + b.printBuf() + seeded = true + } + + } + return b.string() +} + + +func (lb buffer) string() string { return string(lb.buf) } -func (lb *Buffer) deleteChar() { +func (lb *buffer) deleteChar() { if lb.cursor == len(lb.buf) { return } else if lb.cursor == len(lb.buf)-1 { @@ -56,10 +101,7 @@ func (lb *Buffer) deleteChar() { } } -// TODO rework this so that the changes are made but all drawing to the screen comes -// from one source and always draws the whole input area. This will make dealing with -// offsets much easier. -func (lb *Buffer) addChar(c rune, echo bool) { +func (lb *buffer) addChar(c rune, echo bool) { if c < 9 || (c > 10 && c < 13) || (c > 13 && c < 32) { return } @@ -93,12 +135,12 @@ func max(a, b int) int { return b } -func (lb Buffer) printBuf() { +func (lb buffer) printBuf() { out := lb.buf[lb.offset:min(len(lb.buf), lb.offset+lb.maxWidth)] fmt.Printf("\r%s%s\033[0K\r\033[%dC", lb.prompt, string(out), lb.cursor - lb.offset + len(lb.prompt)) } -func (lb *Buffer) controlInput(c rune) { +func (lb *buffer) controlInput(c rune) { switch c { case Delete: lb.deleteChar() @@ -115,7 +157,7 @@ func (lb *Buffer) controlInput(c rune) { lb.cursor-- } case RightArrow: - // FIXME: This still isnt working quite right... + // This is still mildly funky, but works enough for ;lb.cursor - lb.offset >= lb.maxWidth && lb.cursor < len(lb.buf); { lb.offset++ } @@ -123,18 +165,16 @@ func (lb *Buffer) controlInput(c rune) { lb.cursor++ } case Home: - lb.offset = 0 - lb.cursor = 0 + lb.offset = 0 + lb.cursor = 0 case End: - if lb.cursor < len(lb.buf) { - lb.cursor = len(lb.buf) - lb.offset = max(lb.cursor - lb.maxWidth, 0) - } + lb.cursor = len(lb.buf) + lb.offset = max(lb.cursor - lb.maxWidth, 0) } lb.printBuf() } -func (lb *Buffer) seedContent(s string) { +func (lb *buffer) seedContent(s string) { for _, r := range s { lb.addChar(r, false) } @@ -147,41 +187,6 @@ func parseCursorPosition(esc string) (int, int, error) { return row, col, err } -func GetText(prompt string, content string) string { - cols, _ := termios.GetWindowSize() - b := Buffer{make([]rune, 0, (len(content)+1)*2), 0, cols-len(prompt), 0, 0, prompt} - b.seedContent(content) - - fmt.Print(prompt) - fmt.Print("\033[6n") - b.printBuf() - - var ch rune - var err error - reader := bufio.NewReader(os.Stdin) - - for { - ch, err = readKey(reader) - if err != nil && err.Error() == "response" { - b.cursorStart = int(ch) - b.maxWidth = cols - b.cursorStart - } else if err != nil { - continue - } - if ch == CarriageReturn || ch == NewLine { - break - } - - if isControl(ch) { - b.controlInput(ch) - } else { - b.addChar(ch, true) - } - - } - return b.String() -} - func readKey(reader *bufio.Reader) (rune, error) { char, _, err := reader.ReadRune() @@ -225,8 +230,6 @@ func readKey(reader *bufio.Reader) (rune, error) { err = fmt.Errorf("response") } return rune(cols), err - default: - fmt.Printf("Odd sequence: %s\n", escSeq[1:]) } } return char, nil @@ -298,16 +301,3 @@ func PrintKey(k rune) { } -func main() { - // This main func is just for testing and will - // be removed with the intention that this just - // gets used as a lib - termios.SetCharMode() - defer termios.Restore() - str := "" - - for { - fmt.Print("\n") - str = GetText("> ", str) - } -} diff --git a/qline.swim b/qline.swim deleted file mode 100644 index fb362f8..0000000 --- a/qline.swim +++ /dev/null @@ -1 +0,0 @@ -{"BoardTitle":"","Lanes":[{"LaneTitle":"Backlog","Stories":[{"StoryTitle":"Figure out a way to solve the linewidth issue","StoryBody":"Right now, line editing is working, but without knowing where the cursor starts out we cant know where the end of the line is.","StoryUsers":["sloum"],"StoryTag":-1,"StoryTasks":[{"TaskBody":"Try the escape code method.","TaskComplete":false}],"StoryComments":[],"StoryCreated":"2021-04-01T21:57:43.386761058-07:00","StoryUpdated":"2021-04-01T21:59:21.689817136-07:00","StoryPoints":3},{"StoryTitle":"Build out line offsetting for display","StoryBody":"Once widths are figured out there needs to be horizontal scrolling of input for display soas to not jump down a line.","StoryUsers":["sloum"],"StoryTag":-1,"StoryTasks":[],"StoryComments":[],"StoryCreated":"2021-04-01T21:59:09.929902095-07:00","StoryUpdated":"2021-04-01T22:00:00.004446556-07:00","StoryPoints":2}],"CurrentStory":1},{"LaneTitle":"Active","Stories":[],"CurrentStory":-1},{"LaneTitle":"Complete","Stories":[],"CurrentStory":-1}],"CurrentLane":0,"Zoom":3,"StoryOpen":true} \ No newline at end of file