cchat-discord/internal/discord/channel/message/send/complete/completer.go

78 lines
1.9 KiB
Go
Raw Normal View History

2020-10-07 01:53:15 +00:00
package complete
import (
2020-12-19 05:46:12 +00:00
"sort"
"github.com/diamondburned/cchat"
2020-10-07 01:53:15 +00:00
"github.com/diamondburned/cchat-discord/internal/discord/channel/shared"
2020-12-19 05:46:12 +00:00
"github.com/lithammer/fuzzysearch/fuzzy"
)
2020-12-19 05:46:12 +00:00
type CompleterFunc func(word string) []cchat.CompletionEntry
type ChannelCompleter struct {
shared.Channel
2020-10-07 01:53:15 +00:00
}
2020-09-08 04:44:09 +00:00
2020-12-19 05:46:12 +00:00
type Completer map[byte]CompleterFunc
2020-10-07 01:53:15 +00:00
const MaxCompletion = 15
2020-09-08 04:44:09 +00:00
func New(ch shared.Channel) cchat.Completer {
2020-12-19 05:46:12 +00:00
completer := ChannelCompleter{ch}
return Completer{
'@': completer.CompleteMentions,
'#': completer.CompleteChannels,
':': completer.CompleteEmojis,
}
2020-09-08 04:44:09 +00:00
}
// CompleteMessage implements message input completion capability for Discord.
// This method supports user mentions, channel mentions and emojis.
//
// For the individual implementations, refer to channel_completion.go.
func (ch Completer) Complete(words []string, i int64) []cchat.CompletionEntry {
2020-09-08 04:44:09 +00:00
var word = words[i]
// Word should have at least a character for the char check.
if len(word) < 1 {
return nil
2020-09-08 04:44:09 +00:00
}
2020-12-19 05:46:12 +00:00
fn, ok := ch[word[0]]
if !ok {
return nil
2020-09-08 04:44:09 +00:00
}
2020-12-19 05:46:12 +00:00
fn(word[1:])
return nil
}
2020-12-19 05:46:12 +00:00
// rankFunc is the default rank function to use.
func rankFunc(source, target string) int {
return fuzzy.RankMatchNormalizedFold(source, target)
}
func ensureEntriesMade(entries *[]cchat.CompletionEntry) {
if *entries == nil {
*entries = make([]cchat.CompletionEntry, 0, MaxCompletion)
}
2020-12-19 05:46:12 +00:00
}
2020-12-19 05:46:12 +00:00
func ensureDistancesMade(distances *map[string]int) {
if *distances == nil {
*distances = make(map[string]int, MaxCompletion)
}
}
// sortDistances sorts according to the given Levenshtein distances from the Raw
// string of the entries from most accurate to least accurate.
func sortDistances(entries []cchat.CompletionEntry, distances map[string]int) {
if len(entries) == 0 {
return
}
// The lower the distance, the more accurate.
sort.SliceStable(entries, func(i, j int) bool {
return distances[entries[i].Raw] < distances[entries[j].Raw]
})
}