aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--ui/fuzzy-view.go128
-rw-r--r--ui/view-main.go4
3 files changed, 136 insertions, 3 deletions
diff --git a/README.md b/README.md
index ab88f9f..8ea6e6b 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,10 @@ or compile from source:
2. gomuks should now be in `$GOPATH/bin/gomuks`
## Usage
-Switch between rooms by clicking or with ctrl + up/down arrow (alt+arrows works too).
-
-Scroll chat with the scroll wheel (3 rows per tick), page up/down (half of height per click) or up/down arrow (1 row per click)
+- switch rooms - `Ctrl + ↑` `Ctrl + ↓` `Alt + ↑` `Alt + ↓`
+- scroll chat (line) - `↑` `↓`
+- scroll chat (page) - `PgUp` `PgDown`
+- jump to room - `Alt + Enter`, then `Tab` and `Enter` to navigate and select room
### Commands
* `/quit` - Close gomuks
diff --git a/ui/fuzzy-view.go b/ui/fuzzy-view.go
new file mode 100644
index 0000000..5efad04
--- /dev/null
+++ b/ui/fuzzy-view.go
@@ -0,0 +1,128 @@
+// gomuks - A terminal Matrix client written in Go.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package ui
+
+import (
+ "fmt"
+ "sort"
+ "strconv"
+
+ "github.com/evidlo/fuzzysearch/fuzzy"
+ "maunium.net/go/gomuks/debug"
+ "maunium.net/go/gomuks/matrix/rooms"
+ "maunium.net/go/tcell"
+ "maunium.net/go/tview"
+)
+
+type FuzzyView struct {
+ *tview.Grid
+ matches fuzzy.Ranks
+ selected int
+}
+
+func NewFuzzyView(view *MainView, width int, height int) *FuzzyView {
+
+ rooms := []*rooms.Room{}
+ roomtitles := []string{}
+ for _, tag := range view.roomList.tags {
+ for _, room := range view.roomList.items[tag].rooms {
+ rooms = append(rooms, room.Room)
+ roomtitles = append(roomtitles, room.GetTitle())
+ }
+ }
+ // search box for fuzzy search
+ fuzzySearch := tview.NewInputField().
+ SetLabel("Room: ")
+
+ // list of rooms matching fuzzy search
+ fuzzyResults := tview.NewTextView().
+ SetDynamicColors(true).
+ SetRegions(true)
+
+ fuzzyResults.
+ SetBorderPadding(1, 0, 0, 0)
+
+ // flexbox containing input box and results
+ fuzzyFlex := tview.NewFlex().
+ SetDirection(tview.FlexRow).
+ AddItem(fuzzySearch, 1, 0, true).
+ AddItem(fuzzyResults, 0, 1, false)
+
+ fuzzyFlex.SetBorder(true).
+ SetBorderPadding(1, 1, 1, 1).
+ SetTitle("Fuzzy Room Finder")
+
+ var matches fuzzy.Ranks
+ var selected int
+ fuzz := &FuzzyView{
+ Grid: tview.NewGrid().
+ SetColumns(0, width, 0).
+ SetRows(0, height, 0).
+ AddItem(fuzzyFlex, 1, 1, 1, 1, 0, 0, true),
+ matches: matches,
+ selected: selected,
+ }
+
+ // callback to update search box
+ fuzzySearch.SetChangedFunc(func(str string) {
+ // get matches and display in fuzzyResults
+ fuzz.matches = fuzzy.RankFindFold(str, roomtitles)
+ if len(str) > 0 && len(fuzz.matches) > 0 {
+ sort.Sort(fuzz.matches)
+ fuzzyResults.Clear()
+ for _, match := range fuzz.matches {
+ fmt.Fprintf(fuzzyResults, "[\"%d\"]%s[\"\"]\n", match.Index, match.Target)
+ }
+ view.parent.app.Draw()
+ fuzzyResults.Highlight(strconv.Itoa(fuzz.matches[0].Index))
+ fuzzyResults.ScrollToBeginning()
+ } else {
+ fuzzyResults.Clear()
+ fuzzyResults.Highlight()
+ }
+ })
+
+ // callback to handle key events on fuzzy search
+ fuzzySearch.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ highlights := fuzzyResults.GetHighlights()
+ if event.Key() == tcell.KeyEsc {
+ view.parent.views.RemovePage("fuzzy")
+ return nil
+ } else if event.Key() == tcell.KeyTab {
+ // cycle highlighted area to next fuzzy match
+ if len(highlights) > 0 {
+ fuzz.selected = (fuzz.selected + 1) % len(fuzz.matches)
+ fuzzyResults.Highlight(strconv.Itoa(fuzz.matches[fuzz.selected].Index))
+ fuzzyResults.ScrollToHighlight()
+ }
+ return nil
+ } else if event.Key() == tcell.KeyEnter {
+ // switch room to currently selected room
+ if len(highlights) > 0 {
+ debug.Print("Fuzzy Selected Room:", rooms[fuzz.matches[fuzz.selected].Index].GetTitle())
+ view.SwitchRoom(rooms[fuzz.matches[fuzz.selected].Index].Tags()[0].Tag, rooms[fuzz.matches[fuzz.selected].Index])
+ }
+ view.parent.views.RemovePage("fuzzy")
+ fuzzyResults.Clear()
+ fuzzySearch.SetText("")
+ return nil
+ }
+ return event
+ })
+
+ return fuzz
+}
diff --git a/ui/view-main.go b/ui/view-main.go
index 314221a..e576a24 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -201,6 +201,10 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
view.SwitchRoom(view.roomList.Next())
case tcell.KeyUp:
view.SwitchRoom(view.roomList.Previous())
+ case tcell.KeyEnter:
+ fuzz := NewFuzzyView(view, 42, 12)
+ view.parent.views.AddPage("fuzzy", fuzz, true, true)
+ view.parent.app.SetFocus(fuzz)
default:
return key
}