mirror of https://github.com/Hilbis/Hilbish
203 lines
5.1 KiB
Go
203 lines
5.1 KiB
Go
package readline
|
|
|
|
import (
|
|
"context"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// DelayedTabContext is a custom context interface for async updates to the tab completions
|
|
type DelayedTabContext struct {
|
|
rl *Instance
|
|
Context context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
func delayedSyntaxTimer(rl *Instance, i int64) {
|
|
if rl.PasswordMask != 0 || rl.DelayedSyntaxWorker == nil {
|
|
return
|
|
}
|
|
|
|
// if len(rl.line)+rl.promptLen > GetTermWidth() {
|
|
// // line wraps, which is hard to do with random ANSI escape sequences
|
|
// // so better we don't bother trying.
|
|
// return
|
|
// }
|
|
|
|
// We pass either the current line or the one with the current completion.
|
|
newLine := rl.DelayedSyntaxWorker(rl.GetLine())
|
|
var sLine string
|
|
count := atomic.LoadInt64(&rl.delayedSyntaxCount)
|
|
if count != i {
|
|
return
|
|
}
|
|
|
|
// Highlight the line again
|
|
if rl.SyntaxHighlighter != nil {
|
|
sLine = rl.SyntaxHighlighter(newLine)
|
|
} else {
|
|
sLine = string(newLine)
|
|
}
|
|
|
|
// Save the line as current, and refresh
|
|
rl.updateLine([]rune(sLine))
|
|
}
|
|
|
|
// AppendGroupSuggestions - Given a group name, append a list of completion candidates.
|
|
// Any item in the list already existing in the current group's will be ignored.
|
|
// If the group is not found with the given name, all suggestions will be dropped, no new group is created.
|
|
func (dtc DelayedTabContext) AppendGroupSuggestions(groupName string, suggestions []string) {
|
|
dtc.rl.mutex.Lock()
|
|
defer dtc.rl.mutex.Unlock()
|
|
|
|
// Get the group, and return if not found
|
|
var grp *CompletionGroup
|
|
for _, g := range dtc.rl.tcGroups {
|
|
if g.Name == groupName {
|
|
grp = g
|
|
}
|
|
}
|
|
if grp == nil {
|
|
return
|
|
}
|
|
|
|
// Add candidate items
|
|
for i := range suggestions {
|
|
select {
|
|
case <-dtc.Context.Done():
|
|
return
|
|
|
|
default:
|
|
// Drop duplicates
|
|
for _, actual := range grp.Suggestions {
|
|
if actual == suggestions[i] {
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Descriptions might be used by tabdisplay maps or grids, but not lists.
|
|
if grp.DisplayType != TabDisplayList {
|
|
grp.Descriptions[suggestions[i]] = suggestions[i]
|
|
}
|
|
|
|
// Suggestions are used by all groups no matter their display type
|
|
grp.Suggestions = append(grp.Suggestions, suggestions[i])
|
|
}
|
|
}
|
|
|
|
dtc.rl.clearHelpers()
|
|
dtc.rl.renderHelpers()
|
|
|
|
}
|
|
|
|
// AppendGroupAliases - Given a group name, append a list of completion candidates' ALIASES, that is, a second candidate item.
|
|
// If any candidate (map index) already exists, its corresponding alias will be overwritten with the new one.
|
|
// If any candidate (map index) does not exists yet, it will be added along with its alias.
|
|
// If the group is not found with the given name, all suggestions will be dropped, no new group is created.
|
|
func (dtc DelayedTabContext) AppendGroupAliases(groupName string, aliases map[string]string) {
|
|
dtc.rl.mutex.Lock()
|
|
defer dtc.rl.mutex.Unlock()
|
|
|
|
// Get the group, and return if not found
|
|
var grp *CompletionGroup
|
|
for _, g := range dtc.rl.tcGroups {
|
|
if g.Name == groupName {
|
|
grp = g
|
|
}
|
|
}
|
|
if grp == nil {
|
|
return
|
|
}
|
|
|
|
// Add candidate aliases
|
|
for sugg, alias := range aliases {
|
|
select {
|
|
case <-dtc.Context.Done():
|
|
return
|
|
|
|
default:
|
|
// Add to suggestions list if not existing yet
|
|
var found bool
|
|
for _, actual := range grp.Suggestions {
|
|
if actual == sugg {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
grp.Suggestions = append(grp.Suggestions, sugg)
|
|
}
|
|
|
|
// Map the new description anyway
|
|
grp.Aliases[sugg] = alias
|
|
}
|
|
}
|
|
|
|
// Reinit all completion groups (recomputes sizes)
|
|
for _, grp := range dtc.rl.tcGroups {
|
|
grp.init(dtc.rl)
|
|
}
|
|
|
|
// dtc.rl.clearHelpers()
|
|
// dtc.rl.renderHelpers()
|
|
}
|
|
|
|
// AppendGroupDescriptions - Given a group name, append a list of descriptions to a list of candidates.
|
|
// If any candidate (map index) already exists, its corresponding description will be overwritten with the new one.
|
|
// If any candidate (map index) does not exists yet, it will be added along with its description.
|
|
func (dtc DelayedTabContext) AppendGroupDescriptions(groupName string, descriptions map[string]string) {
|
|
dtc.rl.mutex.Lock()
|
|
defer dtc.rl.mutex.Unlock()
|
|
|
|
// Get the group, and return if not found
|
|
var grp *CompletionGroup
|
|
for _, g := range dtc.rl.tcGroups {
|
|
if g.Name == groupName {
|
|
grp = g
|
|
}
|
|
}
|
|
if grp == nil {
|
|
return
|
|
}
|
|
|
|
// Add candidate descriptions
|
|
for sugg, desc := range descriptions {
|
|
select {
|
|
case <-dtc.Context.Done():
|
|
return
|
|
|
|
default:
|
|
// Add to suggestions list if not existing yet
|
|
var found bool
|
|
for _, actual := range grp.Suggestions {
|
|
if actual == sugg {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
grp.Suggestions = append(grp.Suggestions, sugg)
|
|
}
|
|
|
|
// Map the new description anyway
|
|
grp.Descriptions[sugg] = desc
|
|
}
|
|
}
|
|
|
|
// Reinit all completion groups (recomputes sizes)
|
|
for _, grp := range dtc.rl.tcGroups {
|
|
grp.init(dtc.rl)
|
|
}
|
|
dtc.rl.clearHelpers()
|
|
dtc.rl.renderHelpers()
|
|
}
|
|
|
|
// AppendGroup - Asynchronously add an entire group of completions to the current list
|
|
func (dtc DelayedTabContext) AppendGroup(group *CompletionGroup) {
|
|
dtc.rl.mutex.Lock()
|
|
defer dtc.rl.mutex.Unlock()
|
|
|
|
// Simply append group to the list
|
|
dtc.rl.tcGroups = append(dtc.rl.tcGroups, group)
|
|
|
|
dtc.rl.clearHelpers()
|
|
dtc.rl.renderHelpers()
|
|
}
|