Merge pull request #49 from Evidlo/fuzzy

fuzzy search prototype
This commit is contained in:
Tulir Asokan 2018-05-21 19:59:45 +03:00 committed by GitHub
commit 3c23126e7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 135 additions and 3 deletions

View File

@ -26,9 +26,10 @@ or compile from source:
2. gomuks should now be in `$GOPATH/bin/gomuks` 2. gomuks should now be in `$GOPATH/bin/gomuks`
## Usage ## Usage
Switch between rooms by clicking or with ctrl + up/down arrow (alt+arrows works too). - switch rooms - `Ctrl + ↑` `Ctrl + ↓` `Alt + ↑` `Alt + ↓`
- scroll chat (line) - `↑` `↓`
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) - scroll chat (page) - `PgUp` `PgDown`
- jump to room - `Alt + Enter`, then `Tab` and `Enter` to navigate and select room
### Commands ### Commands
* `/quit` - Close gomuks * `/quit` - Close gomuks

127
ui/fuzzy-view.go Normal file
View File

@ -0,0 +1,127 @@
// 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/gomuks/ui/widget"
"maunium.net/go/tcell"
"maunium.net/go/tview"
)
type FuzzyView struct {
tview.Primitive
matches fuzzy.Ranks
selected int
}
func NewFuzzyView(view *MainView, width int, height int) *FuzzyView {
roomList := []*rooms.Room{}
roomTitles := []string{}
for _, tag := range view.roomList.tags {
for _, room := range view.roomList.items[tag].rooms {
roomList = append(roomList, 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{
Primitive: widget.TransparentCenter(width, height, fuzzyFlex),
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")
view.parent.app.SetFocus(view.parent.views)
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:", 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()
fuzzySearch.SetText("")
return nil
}
return event
})
return fuzz
}

View File

@ -201,6 +201,10 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
view.SwitchRoom(view.roomList.Next()) view.SwitchRoom(view.roomList.Next())
case tcell.KeyUp: case tcell.KeyUp:
view.SwitchRoom(view.roomList.Previous()) 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: default:
return key return key
} }