Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
38 changes: 38 additions & 0 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package cache

import "strings"

type Cache struct {
m map[string]interface{}
}

func New() *Cache {
return &Cache{
m: map[string]interface{}{},
}
}

func (c *Cache) Set(cmd string, resp interface{}) {
if c == nil {
return
}
c.m[cmd] = resp
}

func (c *Cache) Get(cmd string) interface{} {
if c == nil {
return nil
}
return c.m[cmd]
}

func (c *Cache) Update(namespace string) {
if c == nil {
return
}
for k := range c.m {
if strings.HasPrefix(k, namespace) {
delete(c.m, k)
}
}
}
16 changes: 13 additions & 3 deletions internal/core/autocomplete_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ package core

import (
"context"
"fmt"
"reflect"
"strings"

"github.com/scaleway/scaleway-cli/v2/internal/args"
"github.com/scaleway/scaleway-cli/v2/internal/cache"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/scaleway-sdk-go/strcase"
)

var autoCompleteCache *cache.Cache

func AutocompleteProfileName() AutoCompleteArgFunc {
return func(ctx context.Context, prefix string) AutocompleteSuggestions {
res := AutocompleteSuggestions(nil)
Expand Down Expand Up @@ -96,9 +100,15 @@ func AutocompleteGetArg(ctx context.Context, cmd *Command, argSpec *ArgSpec, com
return runner(ctx, argsI)
}
}
resp, err := listCmd.Interceptor(ctx, listCmdArgs, listCmd.Run)
if err != nil {
return nil

rawCommand := fmt.Sprintf("%s %s", listCmd.getPath(), strings.Join(listRawArgs, " "))
resp := autoCompleteCache.Get(rawCommand)
if resp == nil {
resp, err = listCmd.Interceptor(ctx, listCmdArgs, listCmd.Run)
if err != nil {
return nil
}
autoCompleteCache.Set(rawCommand, resp)
}

// As we run the "list" verb instead of using the sdk ListResource, response is already the slice
Expand Down
45 changes: 5 additions & 40 deletions internal/core/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"

"github.com/c-bata/go-prompt"
"github.com/scaleway/scaleway-cli/v2/internal/cache"
"github.com/scaleway/scaleway-cli/v2/internal/interactive"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -182,37 +183,6 @@ func sortOptions(meta *meta, args []string, toSuggest string, suggestions []stri
return suggests
}

// CompletionCache allows to keep last completion request in cache
// Useful to avoid request spamming when adding a character
type CompletionCache struct {
wordsSum string
arg string
LastResponse *AutocompleteResponse
}

// completionCacheResetCharacterList is the list of character that will trigger cache reset
var completionCacheResetCharacterList = []string{"=", "."}
var completionCache CompletionCache

func (cache *CompletionCache) HasChanged(leftWords []string, currentArg string, rightWords []string) bool {
wordsSum := strings.Join(leftWords, "-") + "_" + strings.Join(rightWords, "-")
if cache.wordsSum != wordsSum {
cache.wordsSum = wordsSum
cache.arg = currentArg
return true
}

for _, character := range completionCacheResetCharacterList {
if strings.Count(cache.arg, character) != strings.Count(currentArg, character) {
cache.arg = currentArg
return true
}
}

cache.arg = currentArg
return false
}

// Complete returns the list of suggestion based on prompt content
func (c *Completer) Complete(d prompt.Document) []prompt.Suggest {
// shell lib can request duplicate Complete request with empty strings as text
Expand All @@ -234,17 +204,9 @@ func (c *Completer) Complete(d prompt.Document) []prompt.Suggest {

leftWords := append([]string{"scw"}, leftArgs...)

var acr *AutocompleteResponse

if completionCache.HasChanged(leftWords, currentArg, rightWords) {
acr = AutoComplete(c.ctx, leftWords, currentArg, rightWords)
completionCache.LastResponse = acr
} else {
acr = completionCache.LastResponse
}
acr := AutoComplete(c.ctx, leftWords, currentArg, rightWords)

suggestions := []prompt.Suggest(nil)

rawSuggestions := []string(acr.Suggestions)

// if first suggestion is an option, all suggestions should be options
Expand Down Expand Up @@ -289,6 +251,8 @@ func shellExecutor(rootCmd *cobra.Command, printer *Printer, meta *meta) func(s
return
}

autoCompleteCache.Update(meta.command.Namespace)

printErr := printer.Print(meta.result, meta.command.getHumanMarshalerOpt())
if printErr != nil {
_, _ = fmt.Fprintln(os.Stderr, printErr)
Expand All @@ -309,6 +273,7 @@ func getShellCommand(rootCmd *cobra.Command) *cobra.Command {

// RunShell will run an interactive shell that runs cobra commands
func RunShell(ctx context.Context, printer *Printer, meta *meta, rootCmd *cobra.Command, args []string) {
autoCompleteCache = cache.New()
completer := NewShellCompleter(ctx)

shellCobraCommand := getShellCommand(rootCmd)
Expand Down