From 7994c289aae7662fee9b86f9424d230c7b612b3d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 21 Mar 2018 00:21:16 +0200 Subject: Refactor some things and format everything --- ui/widget/advanced-inputfield.go | 275 ++++++++++++++++++++++----------------- 1 file changed, 156 insertions(+), 119 deletions(-) (limited to 'ui/widget') diff --git a/ui/widget/advanced-inputfield.go b/ui/widget/advanced-inputfield.go index fed6444..8115b18 100644 --- a/ui/widget/advanced-inputfield.go +++ b/ui/widget/advanced-inputfield.go @@ -322,10 +322,6 @@ func (field *AdvancedInputField) setCursor(screen tcell.Screen) { y++ rightLimit -= 2 } - fieldWidth := runewidth.StringWidth(field.text) - if field.fieldWidth > 0 && fieldWidth > field.fieldWidth-1 { - fieldWidth = field.fieldWidth - 1 - } x = x + tview.StringWidth(field.label) + field.cursorOffset - field.viewOffset if x >= rightLimit { x = rightLimit - 1 @@ -344,122 +340,163 @@ func SubstringBefore(s string, w int) string { return runewidth.Truncate(s, w, "") } +func (field *AdvancedInputField) TypeRune(ch rune) { + leftPart := SubstringBefore(field.text, field.cursorOffset) + newText := leftPart + string(ch) + field.text[len(leftPart):] + if field.accept != nil { + if !field.accept(newText, ch) { + return + } + } + field.text = newText + field.cursorOffset += runewidth.RuneWidth(ch) +} + +func (field *AdvancedInputField) PasteClipboard() { + clip, _ := clipboard.ReadAll("clipboard") + leftPart := SubstringBefore(field.text, field.cursorOffset) + field.text = leftPart + clip + field.text[len(leftPart):] + field.cursorOffset += runewidth.StringWidth(clip) +} + +func (field *AdvancedInputField) MoveCursorLeft(moveWord bool) { + before := SubstringBefore(field.text, field.cursorOffset) + if moveWord { + found := lastWord.FindString(before) + field.cursorOffset -= runewidth.StringWidth(found) + } else if len(before) > 0 { + beforeRunes := []rune(before) + char := beforeRunes[len(beforeRunes)-1] + field.cursorOffset -= runewidth.RuneWidth(char) + } +} + +func (field *AdvancedInputField) MoveCursorRight(moveWord bool) { + before := SubstringBefore(field.text, field.cursorOffset) + after := field.text[len(before):] + if moveWord { + found := firstWord.FindString(after) + field.cursorOffset += runewidth.StringWidth(found) + } else if len(after) > 0 { + char := []rune(after)[0] + field.cursorOffset += runewidth.RuneWidth(char) + } +} + +func (field *AdvancedInputField) RemoveNextCharacter() { + if field.cursorOffset >= runewidth.StringWidth(field.text) { + return + } + leftPart := SubstringBefore(field.text, field.cursorOffset) + // Take everything after the left part minus the first character. + rightPart := string([]rune(field.text[len(leftPart):])[1:]) + + field.text = leftPart + rightPart +} + +func (field *AdvancedInputField) Clear() { + field.text = "" + field.cursorOffset = 0 +} + +func (field *AdvancedInputField) RemovePreviousWord() { + leftPart := SubstringBefore(field.text, field.cursorOffset) + rightPart := field.text[len(leftPart):] + replacement := lastWord.ReplaceAllString(leftPart, "") + field.text = replacement + rightPart + + field.cursorOffset -= runewidth.StringWidth(leftPart) - runewidth.StringWidth(replacement) +} + +func (field *AdvancedInputField) RemovePreviousCharacter() { + if field.cursorOffset == 0 { + return + } + leftPart := SubstringBefore(field.text, field.cursorOffset) + rightPart := field.text[len(leftPart):] + + // Take everything before the right part minus the last character. + leftPartRunes := []rune(leftPart) + leftPartRunes = leftPartRunes[0 : len(leftPartRunes)-1] + leftPart = string(leftPartRunes) + + // Figure out what character was removed to correctly decrease cursorOffset. + removedChar := field.text[len(leftPart) : len(field.text)-len(rightPart)] + + field.text = leftPart + rightPart + + field.cursorOffset -= runewidth.StringWidth(removedChar) +} + +func (field *AdvancedInputField) TriggerTabComplete() bool { + if field.tabComplete != nil { + oldWidth := runewidth.StringWidth(field.text) + field.text = field.tabComplete(field.text, field.cursorOffset) + newWidth := runewidth.StringWidth(field.text) + if oldWidth != newWidth { + field.cursorOffset += newWidth - oldWidth + } + return true + } + return false +} + +func (field *AdvancedInputField) handleInputChanges(originalText string) { + // Trigger changed events. + if field.text != originalText && field.changed != nil { + field.changed(field.text) + } + + // Make sure cursor offset is valid + if field.cursorOffset < 0 { + field.cursorOffset = 0 + } + width := runewidth.StringWidth(field.text) + if field.cursorOffset > width { + field.cursorOffset = width + } +} + // InputHandler returns the handler for this primitive. func (field *AdvancedInputField) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { - return field.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { - currentText := field.text - defer func() { - // Trigger changed events. - if field.text != currentText && field.changed != nil { - field.changed(field.text) - } - // Make sure cursor offset is valid - if field.cursorOffset < 0 { - field.cursorOffset = 0 - } - width := runewidth.StringWidth(field.text) - if field.cursorOffset > width { - field.cursorOffset = width - } - }() - - // Process key event. - switch key := event.Key(); key { - case tcell.KeyRune: // Regular character. - leftPart := SubstringBefore(field.text, field.cursorOffset) - newText := leftPart + string(event.Rune()) + field.text[len(leftPart):] - if field.accept != nil { - if !field.accept(newText, event.Rune()) { - break - } - } - field.text = newText - field.cursorOffset += runewidth.RuneWidth(event.Rune()) - case tcell.KeyCtrlV: - clip, _ := clipboard.ReadAll("clipboard") - leftPart := SubstringBefore(field.text, field.cursorOffset) - field.text = leftPart + clip + field.text[len(leftPart):] - field.cursorOffset += runewidth.StringWidth(clip) - case tcell.KeyLeft: // Move cursor left. - before := SubstringBefore(field.text, field.cursorOffset) - if event.Modifiers() == tcell.ModCtrl { - found := lastWord.FindString(before) - field.cursorOffset -= runewidth.StringWidth(found) - } else if len(before) > 0 { - beforeRunes := []rune(before) - char := beforeRunes[len(beforeRunes)-1] - field.cursorOffset -= runewidth.RuneWidth(char) - } - case tcell.KeyRight: // Move cursor right. - before := SubstringBefore(field.text, field.cursorOffset) - after := field.text[len(before):] - if event.Modifiers() == tcell.ModCtrl { - found := firstWord.FindString(after) - field.cursorOffset += runewidth.StringWidth(found) - } else if len(after) > 0 { - char := []rune(after)[0] - field.cursorOffset += runewidth.RuneWidth(char) - } - case tcell.KeyDelete: // Delete next character. - if field.cursorOffset >= runewidth.StringWidth(field.text) { - break - } - leftPart := SubstringBefore(field.text, field.cursorOffset) - // Take everything after the left part minus the first character. - rightPart := string([]rune(field.text[len(leftPart):])[1:]) - - field.text = leftPart + rightPart - case tcell.KeyCtrlU: - if !field.vimBindings { - break - } - field.text = "" - field.cursorOffset = 0 - case tcell.KeyCtrlW: - if !field.vimBindings { - break - } - fallthrough - case tcell.KeyBackspace: // Delete last word - leftPart := SubstringBefore(field.text, field.cursorOffset) - rightPart := field.text[len(leftPart):] - replacement := lastWord.ReplaceAllString(leftPart, "") - field.text = replacement + rightPart - - field.cursorOffset -= runewidth.StringWidth(leftPart) - runewidth.StringWidth(replacement) - case tcell.KeyBackspace2: // Delete last character - if field.cursorOffset == 0 { - break - } - leftPart := SubstringBefore(field.text, field.cursorOffset) - rightPart := field.text[len(leftPart):] - - // Take everything before the right part minus the last character. - leftPartRunes := []rune(leftPart) - leftPartRunes = leftPartRunes[0 : len(leftPartRunes)-1] - leftPart = string(leftPartRunes) - - // Figure out what character was removed to correctly decrease cursorOffset. - removedChar := field.text[len(leftPart) : len(field.text)-len(rightPart)] - - field.text = leftPart + rightPart - - field.cursorOffset -= runewidth.StringWidth(removedChar) - case tcell.KeyTab: // Tab-completion - if field.tabComplete != nil { - oldWidth := runewidth.StringWidth(field.text) - field.text = field.tabComplete(field.text, field.cursorOffset) - newWidth := runewidth.StringWidth(field.text) - if oldWidth != newWidth { - field.cursorOffset += newWidth - oldWidth - } - break - } - fallthrough - case tcell.KeyEnter, tcell.KeyEscape, tcell.KeyBacktab: // We're done. - if field.done != nil { - field.done(key) - } + return field.WrapInputHandler(field.inputHandler) +} + +func (field *AdvancedInputField) inputHandler(event *tcell.EventKey, setFocus func(p tview.Primitive)) { + defer field.handleInputChanges(field.text) + + // Process key event. + switch key := event.Key(); key { + case tcell.KeyRune: + field.TypeRune(event.Rune()) + case tcell.KeyCtrlV: + field.PasteClipboard() + case tcell.KeyLeft: + field.MoveCursorLeft(event.Modifiers() == tcell.ModCtrl) + case tcell.KeyRight: + field.MoveCursorRight(event.Modifiers() == tcell.ModCtrl) + case tcell.KeyDelete: + field.RemoveNextCharacter() + case tcell.KeyCtrlU: + if field.vimBindings { + field.Clear() + } + case tcell.KeyCtrlW: + if field.vimBindings { + field.RemovePreviousWord() + } + case tcell.KeyBackspace: + field.RemovePreviousWord() + case tcell.KeyBackspace2: + field.RemovePreviousCharacter() + case tcell.KeyTab: + if field.TriggerTabComplete() { + break } - }) + fallthrough + case tcell.KeyEnter, tcell.KeyEscape, tcell.KeyBacktab: + if field.done != nil { + field.done(key) + } + } } -- cgit v1.2.3