diff options
| -rw-r--r-- | tui/text_input.go | 126 |
1 files changed, 106 insertions, 20 deletions
diff --git a/tui/text_input.go b/tui/text_input.go index 3bceb24..ba99f48 100644 --- a/tui/text_input.go +++ b/tui/text_input.go @@ -4,16 +4,15 @@ import ( "github.com/rivo/uniseg" "zgo.at/termfo/keys" "strings" + "unicode" ) type TextInput struct { id string - linesBefore []string beforeCursor string selection string selectionBefore bool afterCursor string - linesAfter []string } func (t *TextInput) Text() string { @@ -34,43 +33,119 @@ func toGraphemes(s string) []string { return result } -func splitRight(s string) (string, string) { +func splitRight(s string, word bool) (string, string) { if s == "" { return "", "" } gs := toGraphemes(s) - return strings.Join(gs[:len(gs) - 1], ""), gs[len(gs) - 1] + if !word { + return strings.Join(gs[:len(gs) - 1], ""), gs[len(gs) - 1] + } else { + i := len(gs) + for unicode.IsSpace([]rune(gs[i - 1])[0]) { + i-- + if i < 0 { + return "", s + } + } + for !unicode.IsSpace([]rune(gs[i - 1])[0]) { + i-- + if i < 1 { + break + } + } + return strings.Join(gs[:i], ""), strings.Join(gs[i:], "") + } } -func splitLeft(s string) (string, string) { +func splitLeft(s string, word bool) (string, string) { if s == "" { return "", "" } - cluster, rest, _, _ := uniseg.FirstGraphemeCluster([]byte(s), 0) - return string(cluster), string(rest) + gs := toGraphemes(s) + if !word { + return gs[0], strings.Join(gs[1:], "") + } else { + i := 0 + for unicode.IsSpace([]rune(gs[i])[0]) { + i++ + if i >= len(gs) { + return "", s + } + } + for !unicode.IsSpace([]rune(gs[i])[0]) { + i++ + if i >= len(gs) { + break + } + } + return strings.Join(gs[:i], ""), strings.Join(gs[i:], "") + } } func (t *TextInput) Left(selection bool, word bool) { - t.Deselect() + if !selection { + t.Deselect() + } + if selection && t.selection == "" { + t.selectionBefore = false + } var right string - t.beforeCursor, right = splitRight(t.beforeCursor) - t.afterCursor = right + t.afterCursor + if selection && t.selectionBefore { + t.selection, right = splitRight(t.selection, word) + } else { + t.beforeCursor, right = splitRight(t.beforeCursor, word) + } + if !selection || t.selectionBefore { + t.afterCursor = right + t.afterCursor + } else { + t.selection = right + t.selection + } } func (t *TextInput) Right(selection bool, word bool) { - t.Deselect() + if !selection { + t.Deselect() + } + if selection && t.selection == "" { + t.selectionBefore = true + } var left string - left, t.afterCursor = splitLeft(t.afterCursor) - t.beforeCursor += left + if selection && !t.selectionBefore { + left, t.selection = splitLeft(t.selection, word) + } else { + left, t.afterCursor = splitLeft(t.afterCursor, word) + } + if !selection || !t.selectionBefore { + t.beforeCursor += left + } else { + t.selection += left + } } func (t *TextInput) Start(selection bool) { - t.afterCursor = t.beforeCursor + t.afterCursor + if !selection { + t.Deselect() + } + if selection { + t.selection = t.beforeCursor + t.selection + t.selectionBefore = false + } else { + t.afterCursor = t.beforeCursor + t.afterCursor + } t.beforeCursor = "" } func (t *TextInput) End(selection bool) { - t.beforeCursor = t.beforeCursor + t.afterCursor + if !selection { + t.Deselect() + } + if selection { + t.selection = t.selection + t.afterCursor + t.selectionBefore = true + } else { + t.beforeCursor = t.beforeCursor + t.afterCursor + } t.afterCursor = "" } @@ -94,6 +169,7 @@ func (t *TextInput) Write(text string) { func (t *TextInput) Update(ev Event) (usedKeybind bool) { if Selected != t.id { + t.Deselect() return } if ev.TextInput != 0 { @@ -102,24 +178,32 @@ func (t *TextInput) Update(ev Event) (usedKeybind bool) { selection := ev.Key & keys.Shift != 0 word := ev.Key & keys.Ctrl != 0 + if ev.Key & keys.Alt != 0 { + selection = true + word = true + } switch ev.Key.WithoutMods() { case keys.Left: t.Left(selection, word) case keys.Right: t.Right(selection, word) case 'a': - if ev.Key & keys.Ctrl != 0 { + if ev.Key & (keys.Ctrl | keys.Alt) != 0 { t.Start(selection) } case 'e': - if ev.Key & keys.Ctrl != 0 { + if ev.Key & (keys.Ctrl | keys.Alt) != 0 { t.End(selection) } case keys.Backspace: if t.selection != "" { t.selection = "" } else { - t.beforeCursor, _ = splitRight(t.beforeCursor) + t.beforeCursor, _ = splitRight(t.beforeCursor, word) + } + case 'j': + if ev.Key & keys.Ctrl != 0 { + t.Write("\n") } default: return false @@ -129,12 +213,14 @@ func (t *TextInput) Update(ev Event) (usedKeybind bool) { func (t *TextInput) Show(id string) { t.id = id - Push(id, Box {Width: Fill, Height: 4})//TextSize}) + Push(id, Box {Width: Fill, Height: TextSize}) Text(t.beforeCursor, nil) if t.selectionBefore { Text(t.selection, &Style {Bg: Blue, Fg: White, selected: true}) } - Cursor() + if t.selection == "" { + Cursor() + } if !t.selectionBefore { Text(t.selection, &Style {Bg: Blue, Fg: White, selected: true}) } |
