mirror of
https://github.com/shazow/ssh-chat.git
synced 2025-04-26 13:22:18 +03:00
Add NameTrie for predictable, correct name autocomplete
This commit is contained in:
parent
55c1def24d
commit
56cd155e4f
@ -232,3 +232,8 @@ func (r *Room) NamesPrefix(prefix string) []string {
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func (r *Room) CompleteName(prefix string) string {
|
||||
name, _ := r.Members.CompleteName(prefix)
|
||||
return name
|
||||
}
|
||||
|
8
host.go
8
host.go
@ -192,13 +192,7 @@ func (h *Host) Serve() {
|
||||
}
|
||||
|
||||
func (h *Host) completeName(partial string) string {
|
||||
names := h.NamesPrefix(partial)
|
||||
if len(names) == 0 {
|
||||
// Didn't find anything
|
||||
return ""
|
||||
}
|
||||
|
||||
return names[len(names)-1]
|
||||
return h.CompleteName(partial)
|
||||
}
|
||||
|
||||
func (h *Host) completeCommand(partial string) string {
|
||||
|
83
set/name_trie.go
Normal file
83
set/name_trie.go
Normal file
@ -0,0 +1,83 @@
|
||||
package set
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type NameTrie struct {
|
||||
children map[rune]*NameTrie
|
||||
terminates bool
|
||||
}
|
||||
|
||||
func createNameTrie() *NameTrie {
|
||||
return &NameTrie{make(map[rune]*NameTrie), false}
|
||||
}
|
||||
|
||||
func (tree *NameTrie) Exists(name string) bool {
|
||||
nameSlice := []rune(name)
|
||||
node, ok := tree.traverse(nameSlice, false)
|
||||
return ok && node.terminates
|
||||
}
|
||||
|
||||
func (tree *NameTrie) Insert(name string) {
|
||||
nameSlice := []rune(name)
|
||||
node, ok := tree.traverse(nameSlice, true)
|
||||
if ok {
|
||||
node.terminates = true
|
||||
}
|
||||
}
|
||||
|
||||
func (tree *NameTrie) Delete(name string) {
|
||||
nameSlice := []rune(name)
|
||||
node, ok := tree.traverse(nameSlice, false)
|
||||
if ok {
|
||||
node.terminates = false
|
||||
}
|
||||
}
|
||||
|
||||
func (tree *NameTrie) ClosestName(prefix string) (name string, ok bool) {
|
||||
fmt.Println(tree, prefix)
|
||||
nameslice := []rune(prefix)
|
||||
node, ok := tree.traverse(nameslice, false)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return node.closestName(prefix)
|
||||
}
|
||||
|
||||
func (node *NameTrie) closestName(prefix string) (name string, ok bool) {
|
||||
if node.terminates {
|
||||
return prefix, true
|
||||
}
|
||||
keys := []string{}
|
||||
for suffix := range(node.children){keys = append(keys, string(suffix))}
|
||||
sort.Strings(keys)
|
||||
fmt.Println(keys)
|
||||
for i := range keys {
|
||||
child := node.children[[]rune(keys[i])[0]]
|
||||
name, ok := child.closestName(prefix + keys[i])
|
||||
if ok{
|
||||
return name, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (tree *NameTrie) traverse(remainder []rune, create bool) (nextTree *NameTrie, ok bool) {
|
||||
nextRune := remainder[0]
|
||||
nextTree, ok = tree.children[nextRune]
|
||||
if !ok {
|
||||
if create {
|
||||
tree.children[nextRune] = createNameTrie()
|
||||
nextTree = tree.children[nextRune]
|
||||
} else {
|
||||
return createNameTrie(), false
|
||||
}
|
||||
}
|
||||
if len(remainder) < 2 {
|
||||
return nextTree, true
|
||||
} else {
|
||||
return nextTree.traverse(remainder[1:], create)
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ type Set struct {
|
||||
sync.RWMutex
|
||||
lookup map[string]Item
|
||||
normalize func(string) string
|
||||
names *NameTrie
|
||||
}
|
||||
|
||||
// New creates a new set with case-insensitive keys
|
||||
@ -28,6 +29,7 @@ func New() *Set {
|
||||
return &Set{
|
||||
lookup: map[string]Item{},
|
||||
normalize: normalize,
|
||||
names: createNameTrie(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,6 +38,7 @@ func (s *Set) Clear() int {
|
||||
s.Lock()
|
||||
n := len(s.lookup)
|
||||
s.lookup = map[string]Item{}
|
||||
s.names = createNameTrie()
|
||||
s.Unlock()
|
||||
return n
|
||||
}
|
||||
@ -102,6 +105,7 @@ func (s *Set) Add(item Item) error {
|
||||
}
|
||||
|
||||
s.lookup[key] = item
|
||||
s.names.Insert(key)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -117,6 +121,7 @@ func (s *Set) Remove(key string) error {
|
||||
return ErrMissing
|
||||
}
|
||||
delete(s.lookup, key)
|
||||
s.names.Delete(key)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -187,6 +192,10 @@ func (s *Set) ListPrefix(prefix string) []Item {
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *Set) CompleteName(name string) (string, bool) {
|
||||
return s.names.ClosestName(name)
|
||||
}
|
||||
|
||||
func normalize(key string) string {
|
||||
return strings.ToLower(key)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user