@@ -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
									
								
							
							
						
						
									
										127
									
								
								ui/fuzzy-view.go
									
									
									
									
									
										Normal 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user