diff options
-rw-r--r-- | config/session.go | 2 | ||||
-rw-r--r-- | matrix/room/room.go | 4 | ||||
-rw-r--r-- | notification/notify_darwin.go | 9 | ||||
-rw-r--r-- | notification/notify_linux.go | 6 | ||||
-rw-r--r-- | notification/notify_windows.go | 10 | ||||
-rw-r--r-- | ui/ui.go | 12 | ||||
-rw-r--r-- | ui/widget/advanced-inputfield.go | 275 |
7 files changed, 177 insertions, 141 deletions
diff --git a/config/session.go b/config/session.go index 128cbe5..de10757 100644 --- a/config/session.go +++ b/config/session.go @@ -33,7 +33,7 @@ type Session struct { NextBatch string FilterID string Rooms map[string]*rooms.Room - PushRules *gomatrix.PushRuleset + PushRules *gomatrix.PushRuleset } func (config *Config) LoadSession(mxid string) error { diff --git a/matrix/room/room.go b/matrix/room/room.go index a67d363..6bafbfa 100644 --- a/matrix/room/room.go +++ b/matrix/room/room.go @@ -27,7 +27,7 @@ type Room struct { *gomatrix.Room PrevBatch string - Owner string + Owner string memberCache map[string]*Member firstMemberCache string nameCache string @@ -204,7 +204,7 @@ func (room *Room) GetMember(userID string) *Member { // NewRoom creates a new Room with the given ID func NewRoom(roomID, owner string) *Room { return &Room{ - Room: gomatrix.NewRoom(roomID), + Room: gomatrix.NewRoom(roomID), Owner: owner, } } diff --git a/notification/notify_darwin.go b/notification/notify_darwin.go index 3a4a8c2..f7a2d89 100644 --- a/notification/notify_darwin.go +++ b/notification/notify_darwin.go @@ -17,8 +17,8 @@ package notification import ( - "os/exec" "fmt" + "os/exec" "strings" ) @@ -37,9 +37,9 @@ func Send(title, text string, critical bool) error { if critical { args = append(args, "-timeout", "30") } -// if len(iconPath) > 0 { -// args = append(args, "-appIcon", iconPath) -// } +// if len(iconPath) > 0 { +// args = append(args, "-appIcon", iconPath) +// } return exec.Command("terminal-notifier", args...).Run() } title = strings.Replace(title, `"`, `\"`, -1) @@ -47,4 +47,3 @@ func Send(title, text string, critical bool) error { notification := fmt.Sprintf("display notification \"%s\" with title \"gomuks\" subtitle \"%s\"", text, title) return exec.Command("osascript", "-e", notification).Run() } - diff --git a/notification/notify_linux.go b/notification/notify_linux.go index f48e208..25ab405 100644 --- a/notification/notify_linux.go +++ b/notification/notify_linux.go @@ -23,9 +23,9 @@ func Send(title, text string, critical bool) error { if critical { args = append(args, "-p", "critical") } -// if iconPath { -// args = append(args, "-i", iconPath) -// } +// if iconPath { +// args = append(args, "-i", iconPath) +// } args = append(args, title, text) return exec.Command("notify-send", args...).Run() } diff --git a/notification/notify_windows.go b/notification/notify_windows.go index 74ef7a6..71c547d 100644 --- a/notification/notify_windows.go +++ b/notification/notify_windows.go @@ -20,12 +20,12 @@ import "gopkg.in/toast.v1" func Send(title, text string, critical bool) error { notification := toast.Notification{ - AppID: "gomuks", - Title: title, - Message: message, - Audio: toast.IM, + AppID: "gomuks", + Title: title, + Message: message, + Audio: toast.IM, Duration: toast.Short, -// Icon: ..., +// Icon: ..., } if critical { notification.Duration = toast.Long @@ -23,9 +23,9 @@ import ( ) type GomuksUI struct { - gmx ifc.Gomuks - app *tview.Application - views *tview.Pages + gmx ifc.Gomuks + app *tview.Application + views *tview.Pages mainView *MainView loginView *tview.Form @@ -38,9 +38,9 @@ func init() { func NewGomuksUI(gmx ifc.Gomuks) (ui *GomuksUI) { ui = &GomuksUI{ - gmx: gmx, - app: gmx.App(), - views: tview.NewPages(), + gmx: gmx, + app: gmx.App(), + views: tview.NewPages(), } ui.views.SetChangedFunc(ui.Render) return 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) + } + } } |