From 2fb19258815e1ead757d76ef880a4cc0984c6ea2 Mon Sep 17 00:00:00 2001 From: evan Date: Sun, 20 May 2018 16:39:20 -0500 Subject: fuzzy search prototype --- README.md | 7 +-- ui/fuzzy-view.go | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui/view-main.go | 4 ++ 3 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 ui/fuzzy-view.go 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 . + +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 } -- cgit v1.2.3 From 8c869b0fd719a7cbbc15c005d899b76466956ab3 Mon Sep 17 00:00:00 2001 From: evan Date: Mon, 21 May 2018 11:08:47 -0500 Subject: make room finder transparent --- ui/fuzzy-view.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ui/fuzzy-view.go b/ui/fuzzy-view.go index 5efad04..8dd2cf2 100644 --- a/ui/fuzzy-view.go +++ b/ui/fuzzy-view.go @@ -24,12 +24,13 @@ import ( "github.com/evidlo/fuzzysearch/fuzzy" "maunium.net/go/gomuks/debug" "maunium.net/go/gomuks/matrix/rooms" + "maunium.net/go/gomuks/ui/widget" "maunium.net/go/tcell" "maunium.net/go/tview" ) type FuzzyView struct { - *tview.Grid + tview.Primitive matches fuzzy.Ranks selected int } @@ -69,12 +70,9 @@ func NewFuzzyView(view *MainView, width int, height int) *FuzzyView { 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, + Primitive: widget.TransparentCenter(width, height, fuzzyFlex), + matches: matches, + selected: selected, } // callback to update search box -- cgit v1.2.3 From b22ef132b755c6960c74aa980df2cc8e9126b26b Mon Sep 17 00:00:00 2001 From: evan Date: Mon, 21 May 2018 11:47:27 -0500 Subject: fuzzy finder cleanup --- ui/fuzzy-view.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/fuzzy-view.go b/ui/fuzzy-view.go index 8dd2cf2..d5498d0 100644 --- a/ui/fuzzy-view.go +++ b/ui/fuzzy-view.go @@ -37,12 +37,12 @@ type FuzzyView struct { func NewFuzzyView(view *MainView, width int, height int) *FuzzyView { - rooms := []*rooms.Room{} - roomtitles := []string{} + roomList := []*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()) + roomList = append(roomList, room.Room) + roomTitles = append(roomTitles, room.GetTitle()) } } // search box for fuzzy search @@ -78,7 +78,7 @@ func NewFuzzyView(view *MainView, width int, height int) *FuzzyView { // callback to update search box fuzzySearch.SetChangedFunc(func(str string) { // get matches and display in fuzzyResults - fuzz.matches = fuzzy.RankFindFold(str, roomtitles) + fuzz.matches = fuzzy.RankFindFold(str, roomTitles) if len(str) > 0 && len(fuzz.matches) > 0 { sort.Sort(fuzz.matches) fuzzyResults.Clear() @@ -99,6 +99,7 @@ func NewFuzzyView(view *MainView, width int, height int) *FuzzyView { highlights := fuzzyResults.GetHighlights() if event.Key() == tcell.KeyEsc { view.parent.views.RemovePage("fuzzy") + view.parent.app.SetFocus(view.parent.views) return nil } else if event.Key() == tcell.KeyTab { // cycle highlighted area to next fuzzy match @@ -111,8 +112,8 @@ func NewFuzzyView(view *MainView, width int, height int) *FuzzyView { } 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]) + debug.Print("Fuzzy Selected Room:", roomList[fuzz.matches[fuzz.selected].Index].GetTitle()) + view.SwitchRoom(roomList[fuzz.matches[fuzz.selected].Index].Tags()[0].Tag, roomList[fuzz.matches[fuzz.selected].Index]) } view.parent.views.RemovePage("fuzzy") fuzzyResults.Clear() -- cgit v1.2.3