Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkg/cli/modes: Filter by tags. #1743

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
pkg/cli/modes: Filter by tags.
  • Loading branch information
rsteube committed Jan 8, 2024
commit 06b9142b6a8d5e49528fef84515f2142cc8c2505
68 changes: 65 additions & 3 deletions pkg/cli/modes/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package modes

import (
"errors"
"sort"
"strings"

"src.elv.sh/pkg/cli"
"src.elv.sh/pkg/cli/term"
"src.elv.sh/pkg/cli/tk"
"src.elv.sh/pkg/diag"
"src.elv.sh/pkg/ui"
Expand All @@ -23,6 +25,8 @@ type CompletionSpec struct {
Replace diag.Ranging
Items []CompletionItem
Filter FilterSpec
tags []string
tagIndex int
}

// CompletionItem represents a completion item, also known as a candidate.
Expand All @@ -31,6 +35,8 @@ type CompletionItem struct {
ToShow ui.Text
// Used when inserting a candidate.
ToInsert string
// TODO
Tag string
}

type completion struct {
Expand All @@ -42,16 +48,68 @@ var errNoCandidates = errors.New("no candidates")

// NewCompletion starts the completion UI.
func NewCompletion(app cli.App, cfg CompletionSpec) (Completion, error) {
itemsByTag := make(map[string][]CompletionItem)
for _, item := range cfg.Items {
itemsByTag[item.Tag] = append(itemsByTag[item.Tag], item)
}
// TODO presort items?
for tag := range itemsByTag {
if strings.TrimSpace(tag) != "" {
cfg.tags = append(cfg.tags, tag)
}
}
sort.Strings(cfg.tags)
switch len(cfg.tags) {
case 1:
if strings.TrimSpace(cfg.tags[0]) == "" {
cfg.tags = []string{cfg.Name}
}
default:
cfg.tags = append([]string{cfg.Name}, cfg.tags...)
}

codeArea, err := FocusedCodeArea(app)
if err != nil {
return nil, err
}
if len(cfg.Items) == 0 {
return nil, errNoCandidates
}
w := tk.NewComboBox(tk.ComboBoxSpec{
var w tk.ComboBox
w = tk.NewComboBox(tk.ComboBoxSpec{
CodeArea: tk.CodeAreaSpec{
Prompt: modePrompt(" COMPLETING "+cfg.Name+" ", true),
Bindings: tk.MapBindings{
term.K('n', ui.Alt): func(tk.Widget) {
if len(cfg.tags) == 1 {
return
}

cfg.tagIndex += 1
if cfg.tagIndex >= len(cfg.tags) {
cfg.tagIndex = 0
}
w.Refilter()
},
term.K('p', ui.Alt): func(t tk.Widget) {
if len(cfg.tags) == 1 {
return
}

cfg.tagIndex -= 1
if cfg.tagIndex < 0 {
cfg.tagIndex = len(cfg.tags) - 1
}
w.Refilter()
},
},
Prompt: func() ui.Text {
prompt := modePrompt(" COMPLETING "+cfg.tags[cfg.tagIndex]+" ", false)()
if cfg.tagIndex > 0 {
prompt = ui.StyleText(prompt, ui.Inverse)
}
prompt = ui.Concat(prompt, ui.T(" "))
return prompt
},
Highlighter: cfg.Filter.Highlighter,
},
ListBox: tk.ListBoxSpec{
Expand All @@ -71,7 +129,11 @@ func NewCompletion(app cli.App, cfg CompletionSpec) (Completion, error) {
ExtendStyle: true,
},
OnFilter: func(w tk.ComboBox, p string) {
w.ListBox().Reset(filterCompletionItems(cfg.Items, cfg.Filter.makePredicate(p)), 0)
filtered := cfg.Items
if cfg.tagIndex > 0 {
filtered = itemsByTag[cfg.tags[cfg.tagIndex]]
}
w.ListBox().Reset(filterCompletionItems(filtered, cfg.Filter.makePredicate(p)), 0)
},
})
return completion{w, codeArea}, nil
Expand Down
2 changes: 2 additions & 0 deletions pkg/edit/complete/raw_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type ComplexItem struct {
Stem string // Used in the code and the menu.
CodeSuffix string // Appended to the code.
Display ui.Text // How the item is displayed. If empty, defaults to ui.T(Stem).
Tag string // TODO
}

func (c ComplexItem) String() string { return c.Stem }
Expand All @@ -46,5 +47,6 @@ func (c ComplexItem) Cook(q parse.PrimaryType) modes.CompletionItem {
return modes.CompletionItem{
ToInsert: quoted + c.CodeSuffix,
ToShow: display,
Tag: c.Tag,
}
}
8 changes: 6 additions & 2 deletions pkg/edit/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
type complexCandidateOpts struct {
CodeSuffix string
Display any
Tag string
}

func (*complexCandidateOpts) SetDefaultOptions() {}
Expand All @@ -46,6 +47,7 @@ func complexCandidate(fm *eval.Frame, opts complexCandidateOpts, stem string) (c
Stem: stem,
CodeSuffix: opts.CodeSuffix,
Display: display,
Tag: opts.Tag,
}, nil
}

Expand Down Expand Up @@ -162,6 +164,8 @@ func (c complexItem) Index(k any) (any, bool) {
return c.CodeSuffix, true
case "display":
return c.Display, true
case "tag":
return c.Tag, true
}
return nil, false
}
Expand All @@ -188,8 +192,8 @@ func (c complexItem) Hash() uint32 {

func (c complexItem) Repr(indent int) string {
// TODO(xiaq): Pretty-print when indent >= 0
return fmt.Sprintf("(edit:complex-candidate %s &code-suffix=%s &display=%s)",
parse.Quote(c.Stem), parse.Quote(c.CodeSuffix), vals.Repr(c.Display, indent+1))
return fmt.Sprintf("(edit:complex-candidate %s &code-suffix=%s &display=%s &tag=%s)",
parse.Quote(c.Stem), parse.Quote(c.CodeSuffix), vals.Repr(c.Display, indent+1), parse.Quote(c.Tag))
}

type wrappedArgGenerator func(*eval.Frame, ...string) error
Expand Down
4 changes: 2 additions & 2 deletions pkg/edit/completion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ func TestComplexCandidate(t *testing.T) {
That("cc a/b").Puts(complexItem{Stem: "a/b"}),
That("cc a/b &code-suffix=' '").Puts(complexItem{Stem: "a/b", CodeSuffix: " "}),
That("cc a/b &code-suffix=' ' &display=A/B").Puts(
complexItem{"a/b", " ", ui.T("A/B")}),
complexItem{"a/b", " ", ui.T("A/B"), ""}),
That("cc a/b &code-suffix=' ' &display=(styled A/B red)").Puts(
complexItem{"a/b", " ", ui.T("A/B", ui.FgRed)}),
complexItem{"a/b", " ", ui.T("A/B", ui.FgRed), ""}),
That("cc a/b &code-suffix=' ' &display=[]").Throws(
errs.BadValue{What: "&display", Valid: "string or styled", Actual: "[]"}),

Expand Down
Loading