From 7806533184d8d281d384230d4c1294b02c33f19c Mon Sep 17 00:00:00 2001 From: rsteube Date: Thu, 5 May 2022 15:18:24 +0200 Subject: [PATCH] added custom macros --- .github/workflows/go.yml | 4 +- .gitignore | 1 + cmd/carapace/cmd/lazyInit.go | 163 +++++++++++++++++++++++++++++++- cmd/carapace/cmd/macros.go | 146 ---------------------------- cmd/carapace/cmd/root.go | 47 +++++---- cmd/generate/gen.go | 76 +++++++++++++++ go.mod | 6 +- go.sum | 8 +- pkg/actions/bridge/cobra.go | 2 +- pkg/actions/tools/git/action.go | 5 + 10 files changed, 281 insertions(+), 177 deletions(-) delete mode 100644 cmd/carapace/cmd/macros.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 06475f8df3..23cae8d3f0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -23,7 +23,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18 - name: Generate run: go generate ./cmd/... @@ -39,7 +39,7 @@ jobs: run: '[ "$(gofmt -d -s . | tee -a /dev/stderr)" = "" ]' - name: "staticcheck" - run: go install honnef.co/go/tools/cmd/staticcheck@2021.1.1 && staticcheck ./... + run: go install honnef.co/go/tools/cmd/staticcheck@latest && staticcheck ./... - name: "caralint" run: go run ./cmd/caralint completers/*/cmd/*.go diff --git a/.gitignore b/.gitignore index ab73e380c2..78a329144a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ cmd/carapace/carapace cmd/carapace/cmd/completers.go cmd/carapace/cmd/completers_release.go +cmd/carapace/cmd/macros.go cmd/caraparse/caraparse completers/*/*_completer completers/gh_completer/cmd/action/api.github.com.json diff --git a/cmd/carapace/cmd/lazyInit.go b/cmd/carapace/cmd/lazyInit.go index 499d4647c0..fcd5bc4883 100644 --- a/cmd/carapace/cmd/lazyInit.go +++ b/cmd/carapace/cmd/lazyInit.go @@ -4,9 +4,29 @@ package cmd import ( "fmt" + "os" + "regexp" "strings" ) +func getSpecs() (specs []string, dir string) { + r := regexp.MustCompile(`^[0-9a-zA-Z_\-.]+\.yaml$`) // sanity check + specs = make([]string, 0) + if configDir, err := os.UserConfigDir(); err == nil { + dir = configDir + "/carapace/specs" + if entries, err := os.ReadDir(dir); err == nil { + for _, entry := range entries { + if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".yaml") && r.MatchString(entry.Name()) { + specs = append(specs, strings.TrimSuffix(entry.Name(), ".yaml")) + } + } + } else if os.IsNotExist(err) { + os.MkdirAll(dir, os.ModePerm) + } + } + return +} + func bash_lazy(completers []string) string { snippet := `_carapace_lazy() { source <(carapace $1 bash) @@ -14,6 +34,17 @@ func bash_lazy(completers []string) string { } complete -F _carapace_lazy %v ` + + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(` +_carapace_lazy_spec() { + source <(carapace --spec %v/$1.yaml bash) + $"_$1_completion" +} +complete -F _carapace_lazy_spec %v +`, dir, strings.Join(specs, " ")) + } + return fmt.Sprintf(snippet, strings.Join(completers, " ")) } @@ -24,6 +55,17 @@ func bash_ble_lazy(completers []string) string { } complete -F _carapace_lazy %v ` + + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(` +_carapace_lazy_spec() { + source <(carapace --spec %v/$1.yaml bash-ble) + $"_$1_completion" +} +complete -F _carapace_lazy_spec %v +`, dir, strings.Join(specs, " ")) + } + return fmt.Sprintf(snippet, strings.Join(completers, " ")) } @@ -36,6 +78,20 @@ func elvish_lazy(completers []string) string { } } ` + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(` +put %v | each {|c| + set edit:completion:arg-completer[$c] = {|@arg| + set edit:completion:arg-completer[$c] = {|@arg| } + eval (carapace --spec %v/$c.yaml elvish | slurp) + $edit:completion:arg-completer[$c] $@arg + } + +} +`, strings.Join(specs, " "), dir) + + } + return fmt.Sprintf(snippet, strings.Join(completers, " ")) } @@ -49,9 +105,24 @@ end ` complete := make([]string, len(completers)) for index, completer := range completers { - complete[index] = fmt.Sprintf(` complete --erase -c '%v' -complete -c '%v' -f -a '(_carapace_lazy %v)'`, completer, completer, completer) + complete[index] = fmt.Sprintf(`complete -c '%v' -f -a '(_carapace_lazy %v)'`, completer, completer) } + + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(` +function _carapace_lazy_spec + complete -c $argv[1] -e + carapace --spec %v/$argv[1].yaml fish | source + complete --do-complete=(commandline -cp) +end + +`, dir) + for _, spec := range specs { + snippet += fmt.Sprintf(`complete -c '%v' -f -a '(_carapace_lazy_spec %v)' +`, spec, spec) + } + } + return fmt.Sprintf(snippet, strings.Join(complete, "\n")) } @@ -62,7 +133,7 @@ func nushell_lazy(completers []string) string { ...args: string@"nu-complete carapace" ]`, completer) } - return fmt.Sprintf(`module carapace { + snippet := fmt.Sprintf(`module carapace { def "nu-complete carapace" [line: string, pos: int] { let words = ($line | str substring [0 $pos] | split row " ") if ($line | str substring [0 $pos] | str ends-with " ") { @@ -73,9 +144,32 @@ func nushell_lazy(completers []string) string { } %v +`, strings.Join(exports, "\n")) + + // if specs, dir := getSpecs(); len(specs) > 0 { + // snippet += fmt.Sprintf(` + // def "nu-complete carapace-spec" [line: string, pos: int] { + // let words = ($line | str substring [0 $pos] | split row " ") + // if ($line | str substring [0 $pos] | str ends-with " ") { + // carapace --spec '%v'/$words.0'.yaml' nushell ($words | append "") | from json + // } else { + // carapace --spec '%v'/$words.0'.yaml' nushell $words | from json + // } + // } + //`, dir, dir) + // + // for _, spec := range specs { + // snippet += fmt.Sprintf(` export extern "%v" [ + // ...args: string@"nu-complete carapace-spec" + // ]`, spec) + // } + // } + + snippet += ` } use carapace * -`, strings.Join(exports, "\n")) +` + return snippet } func oil_lazy(completers []string) string { @@ -85,6 +179,17 @@ func oil_lazy(completers []string) string { } complete -F _carapace_lazy %v ` + + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(` +_carapace_lazy_spec() { + source <(carapace --spec %v/$1.yaml oil) + $"_$1_completion" +} +complete -F _carapace_lazy_spec %v +`, dir, strings.Join(specs, " ")) + } + return fmt.Sprintf(snippet, strings.Join(completers, " ")) } @@ -101,6 +206,22 @@ func powershell_lazy(completers []string) string { for index, completer := range completers { complete[index] = fmt.Sprintf(`Register-ArgumentCompleter -Native -CommandName '%v' -ScriptBlock $_carapace_lazy`, completer) } + + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(`$_carapace_lazy_spec = { + param($wordToComplete, $commandAst, $cursorPosition) + $completer = $commandAst.CommandElements[0].Value + carapace --spec %v/$completer.yaml powershell | Out-String | Invoke-Expression + & (Get-Item "Function:_${completer}_completer") $wordToComplete $commandAst $cursorPosition +} +`, dir) + for _, spec := range specs { + snippet += fmt.Sprintf(`Register-ArgumentCompleter -Native -CommandName '%v' -ScriptBlock $_carapace_lazy_spec +`, spec) + } + + } + return fmt.Sprintf(snippet, strings.Join(complete, "\n")) } @@ -110,6 +231,12 @@ func tcsh_lazy(completers []string) string { for index, c := range completers { snippet[index] = fmt.Sprintf("complete \"%v\" 'p@*@`echo \"$COMMAND_LINE'\"''\"'\" | xargs carapace %v tcsh `@@' ;", c, c) } + + if specs, dir := getSpecs(); len(specs) > 0 { + for _, spec := range specs { + snippet = append(snippet, fmt.Sprintf("complete \"%v\" 'p@*@`echo \"$COMMAND_LINE'\"''\"'\" | xargs carapace --spec %v/%v.yaml tcsh `@@' ;", spec, dir, spec)) + } + } return strings.Join(snippet, "\n") } @@ -126,12 +253,28 @@ def _carapace_lazy(context): builtins.__xonsh__.completers = builtins.__xonsh__.completers.copy() exec(compile(subprocess.run(['carapace', context.command.args[0].value, 'xonsh'], stdout=subprocess.PIPE).stdout.decode('utf-8'), "", "exec")) return builtins.__xonsh__.completers[context.command.args[0].value](context) -_add_one_completer('carapace_lazy', _carapace_lazy, 'start') ` complete := make([]string, len(completers)) for index, completer := range completers { complete[index] = fmt.Sprintf(`'%v'`, completer) } + + if specs, dir := getSpecs(); len(specs) > 0 { + quotedSpecs := make([]string, 0) + for _, spec := range specs { + quotedSpecs = append(quotedSpecs, fmt.Sprintf(`'%v'`, spec)) + } + snippet += fmt.Sprintf(` + if (context.command and + context.command.arg_index > 0 and + context.command.args[0].value in [%v]): + builtins.__xonsh__.completers = builtins.__xonsh__.completers.copy() + exec(compile(subprocess.run(['carapace', '--spec', '%v/'+context.command.args[0].value+'.yaml', 'xonsh'], stdout=subprocess.PIPE).stdout.decode('utf-8'), "", "exec")) + return builtins.__xonsh__.completers[context.command.args[0].value](context) +`, strings.Join(quotedSpecs, ", "), dir) + + } + snippet += `_add_one_completer('carapace_lazy', _carapace_lazy, 'start')` return fmt.Sprintf(snippet, strings.Join(complete, ", ")) } @@ -141,5 +284,15 @@ func zsh_lazy(completers []string) string { } compdef _carapace_lazy %v ` + + if specs, dir := getSpecs(); len(specs) > 0 { + snippet += fmt.Sprintf(`function _carapace_lazy_spec { + source <(carapace --spec %v/$words[1].yaml zsh) +} +compdef _carapace_lazy_spec %v +`, dir, strings.Join(specs, " ")) + + } + return fmt.Sprintf(snippet, strings.Join(completers, " ")) } diff --git a/cmd/carapace/cmd/macros.go b/cmd/carapace/cmd/macros.go deleted file mode 100644 index 5bedd318ab..0000000000 --- a/cmd/carapace/cmd/macros.go +++ /dev/null @@ -1,146 +0,0 @@ -package cmd - -import ( - "github.com/rsteube/carapace" - "github.com/rsteube/carapace-bin/pkg/actions/fs" - "github.com/rsteube/carapace-bin/pkg/actions/net" - "github.com/rsteube/carapace-bin/pkg/actions/net/http" - "github.com/rsteube/carapace-bin/pkg/actions/net/ssh" - "github.com/rsteube/carapace-bin/pkg/actions/os" - "github.com/rsteube/carapace-bin/pkg/actions/os/usb" - "github.com/rsteube/carapace-bin/pkg/actions/time" - "github.com/rsteube/carapace-bin/pkg/actions/tools/adb" - "github.com/rsteube/carapace-bin/pkg/actions/tools/apt" - "github.com/rsteube/carapace-bin/pkg/actions/tools/aws" - "github.com/rsteube/carapace-bin/pkg/actions/tools/docker" - "github.com/rsteube/carapace-bin/pkg/actions/tools/gh" - "github.com/rsteube/carapace-bin/pkg/actions/tools/git" - "github.com/rsteube/carapace-bin/pkg/actions/tools/golang" - "github.com/rsteube/carapace-bin/pkg/actions/tools/jaeger" - "github.com/rsteube/carapace-bin/pkg/actions/tools/journalctl" - "github.com/rsteube/carapace-bin/pkg/actions/tools/kak" - "github.com/rsteube/carapace-bin/pkg/actions/tools/pacman" - "github.com/rsteube/carapace-bin/pkg/actions/tools/pub" - "github.com/rsteube/carapace-bin/pkg/actions/tools/tshark" - "github.com/rsteube/carapace-bin/pkg/actions/tools/virtualbox" -) - -// TODO generate with go:generate -// TODO support Actions with arguments -var macros = map[string]func(string) carapace.Action{ - "fs.BlockDevices": func(s string) carapace.Action { return fs.ActionBlockDevices() }, - "fs.FileModes": func(s string) carapace.Action { return fs.ActionFileModes() }, - "fs.FileModesNumeric": func(s string) carapace.Action { return fs.ActionFileModesNumeric() }, - "fs.FileModesSymbolic": func(s string) carapace.Action { return fs.ActionFileModesSymbolic() }, - "fs.FilenameExtensions": func(s string) carapace.Action { return fs.ActionFilenameExtensions() }, - "fs.FilesystemTypes": func(s string) carapace.Action { return fs.ActionFilesystemTypes() }, - "fs.Labels": func(s string) carapace.Action { return fs.ActionLabels() }, - "fs.Mounts": func(s string) carapace.Action { return fs.ActionMounts() }, - "fs.PartLabels": func(s string) carapace.Action { return fs.ActionPartLabels() }, - "fs.PartUuids": func(s string) carapace.Action { return fs.ActionPartUuids() }, - "fs.Uuids": func(s string) carapace.Action { return fs.ActionUuids() }, - "net.Bssids": func(s string) carapace.Action { return net.ActionBssids() }, - "net.Connections": func(s string) carapace.Action { return net.ActionConnections() }, - "net.Hosts": func(s string) carapace.Action { return net.ActionHosts() }, - "net.Ipv4Addresses": func(s string) carapace.Action { return net.ActionIpv4Addresses() }, - "net.Ports": func(s string) carapace.Action { return net.ActionPorts() }, - "net.Ssids": func(s string) carapace.Action { return net.ActionSsids() }, - "net.Subnets": func(s string) carapace.Action { return net.ActionSubnets() }, - "net.http.CacheControlRequestDirectives": func(s string) carapace.Action { return http.ActionCacheControlRequestDirectives() }, - "net.http.ContentEncodingTokens": func(s string) carapace.Action { return http.ActionContentEncodingTokens() }, - "net.http.RequestHeaderNames": func(s string) carapace.Action { return http.ActionRequestHeaderNames() }, - "net.http.RequestHeaders": func(s string) carapace.Action { return http.ActionRequestHeaders() }, - "net.http.Tags": func(s string) carapace.Action { return http.ActionTags() }, - "net.http.MediaTypes": func(s string) carapace.Action { return http.ActionMediaTypes() }, - "net.http.RequestMethods": func(s string) carapace.Action { return http.ActionRequestMethods() }, - "net.http.StatusCodes": func(s string) carapace.Action { return http.ActionStatusCodes() }, - "net.http.TransferEncodingTokens": func(s string) carapace.Action { return http.ActionTransferEncodingTokens() }, - "net.http.UserAgents": func(s string) carapace.Action { return http.ActionUserAgents() }, - "os.Cgroups": func(s string) carapace.Action { return os.ActionCgroups() }, - "os.Displays": func(s string) carapace.Action { return os.ActionDisplays() }, - "os.EnvironmentVariables": func(s string) carapace.Action { return os.ActionEnvironmentVariables() }, - "os.GpgKeyIds": func(s string) carapace.Action { return os.ActionGpgKeyIds() }, - "os.Groups": func(s string) carapace.Action { return os.ActionGroups() }, - "os.HexColors": func(s string) carapace.Action { return os.ActionHexColors() }, - "os.KernelModulesLoaded": func(s string) carapace.Action { return os.ActionKernelModulesLoaded() }, - "os.KillSignals": func(s string) carapace.Action { return os.ActionKillSignals() }, - "os.Languages": func(s string) carapace.Action { return os.ActionLanguages() }, - "os.Locales": func(s string) carapace.Action { return os.ActionLocales() }, - "os.MouseButtons": func(s string) carapace.Action { return os.ActionMouseButtons() }, - "os.PathExecutables": func(s string) carapace.Action { return os.ActionPathExecutables() }, - "os.ProcessExecutables": func(s string) carapace.Action { return os.ActionProcessExecutables() }, - "os.ProcessIds": func(s string) carapace.Action { return os.ActionProcessIds() }, - "os.ProcessStates": func(s string) carapace.Action { return os.ActionProcessStates() }, - "os.SessionIds": func(s string) carapace.Action { return os.ActionSessionIds() }, - "os.Shells": func(s string) carapace.Action { return os.ActionShells() }, - "os.SoundCards": func(s string) carapace.Action { return os.ActionSoundCards() }, - "os.Terminals": func(s string) carapace.Action { return os.ActionTerminals() }, - "os.UserGroup": func(s string) carapace.Action { return os.ActionUserGroup() }, - "os.Users": func(s string) carapace.Action { return os.ActionUsers() }, - "os.XtermColorNames": func(s string) carapace.Action { return os.ActionXtermColorNames() }, - "os.usb.DeviceNumbers": func(s string) carapace.Action { return usb.ActionDeviceNumbers() }, - "os.usb.ProductNumbers": func(s string) carapace.Action { return usb.ActionProductNumbers() }, - "ssh.Ciphers": func(s string) carapace.Action { return ssh.ActionCiphers() }, - "ssh.HostKeyAlgorithms": func(s string) carapace.Action { return ssh.ActionHostKeyAlgorithms() }, - "ssh.Options": func(s string) carapace.Action { return ssh.ActionOptions() }, - "time.Date": func(s string) carapace.Action { return time.ActionDate() }, - "time.DateTime": func(s string) carapace.Action { return time.ActionDateTime() }, - "time.Months": func(s string) carapace.Action { return time.ActionMonths() }, - "time.Time": func(s string) carapace.Action { return time.ActionTime() }, - "time.TimeS": func(s string) carapace.Action { return time.ActionTimeS() }, - "tools.adb.Packages": func(s string) carapace.Action { return adb.ActionPackages() }, - "tools.adb.Users": func(s string) carapace.Action { return adb.ActionUsers() }, - "tools.apt.PackageSearch": func(s string) carapace.Action { return apt.ActionPackageSearch() }, - "tools.apt.Packages": func(s string) carapace.Action { return apt.ActionPackages() }, - "tools.aws.Profiles": func(s string) carapace.Action { return aws.ActionProfiles() }, - "tools.aws.Regions": func(s string) carapace.Action { return aws.ActionRegions() }, - "tools.docker.Configs": func(s string) carapace.Action { return docker.ActionConfigs() }, - "tools.docker.ContainerIds": func(s string) carapace.Action { return docker.ActionContainerIds() }, - "tools.docker.ContainerPath": func(s string) carapace.Action { return docker.ActionContainerPath() }, - "tools.docker.Containers": func(s string) carapace.Action { return docker.ActionContainers() }, - "tools.docker.Contexts": func(s string) carapace.Action { return docker.ActionContexts() }, - "tools.docker.DetachKeys": func(s string) carapace.Action { return docker.ActionDetachKeys() }, - "tools.docker.LogDrivers": func(s string) carapace.Action { return docker.ActionLogDrivers() }, - "tools.docker.Networks": func(s string) carapace.Action { return docker.ActionNetworks() }, - "tools.docker.Nodes": func(s string) carapace.Action { return docker.ActionNodes() }, - "tools.docker.Plugins": func(s string) carapace.Action { return docker.ActionPlugins() }, - "tools.docker.Ports": func(s string) carapace.Action { return docker.ActionPorts() }, - "tools.docker.Repositories": func(s string) carapace.Action { return docker.ActionRepositories() }, - "tools.docker.RepositoryTags": func(s string) carapace.Action { return docker.ActionRepositoryTags() }, - "tools.docker.Secrets": func(s string) carapace.Action { return docker.ActionSecrets() }, - "tools.docker.Services": func(s string) carapace.Action { return docker.ActionServices() }, - "tools.docker.Volumes": func(s string) carapace.Action { return docker.ActionVolumes() }, - "tools.gh.ConfigHosts": func(s string) carapace.Action { return gh.ActionConfigHosts() }, - "tools.gh.OwnerRepositories": func(s string) carapace.Action { return gh.ActionOwnerRepositories() }, - "tools.git.Authors": func(s string) carapace.Action { return git.ActionAuthors() }, - "tools.git.CleanupMode": func(s string) carapace.Action { return git.ActionCleanupMode() }, - "tools.git.ColorConfigs": func(s string) carapace.Action { return git.ActionColorConfigs() }, - "tools.git.Colors": func(s string) carapace.Action { return git.ActionColors() }, - "tools.git.ConfigTypes": func(s string) carapace.Action { return git.ActionConfigTypes() }, - "tools.git.Configs": func(s string) carapace.Action { return git.ActionConfigs() }, - "tools.git.CurrentBranch": func(s string) carapace.Action { return git.ActionCurrentBranch() }, - "tools.git.FieldNames": func(s string) carapace.Action { return git.ActionFieldNames() }, - "tools.git.MergeStrategy": func(s string) carapace.Action { return git.ActionMergeStrategy() }, - "tools.git.Remotes": func(s string) carapace.Action { return git.ActionRemotes() }, - "tools.git.RepositorySearch": func(s string) carapace.Action { return git.ActionRepositorySearch() }, - "tools.git.Stashes": func(s string) carapace.Action { return git.ActionStashes() }, - "tools.git.SubmoduleNames": func(s string) carapace.Action { return git.ActionSubmoduleNames() }, - "tools.git.SubmodulePaths": func(s string) carapace.Action { return git.ActionSubmodulePaths() }, - "tools.git.TextAttributes": func(s string) carapace.Action { return git.ActionTextAttributes() }, - "tools.git.WhitespaceModes": func(s string) carapace.Action { return git.ActionWhitespaceModes() }, - "tools.golang.BuildTags": func(s string) carapace.Action { return golang.ActionBuildTags() }, - "tools.jaeger.SamplingTypes": func(s string) carapace.Action { return jaeger.ActionSamplingTypes() }, - "tools.journalctl.Outputs": func(s string) carapace.Action { return journalctl.ActionOutputs() }, - "tools.kak.Sessions": func(s string) carapace.Action { return kak.ActionSessions() }, - "tools.pacman.PackageGroups": func(s string) carapace.Action { return pacman.ActionPackageGroups() }, - "tools.pacman.Repositories": func(s string) carapace.Action { return pacman.ActionRepositories() }, - "tools.pub.Dependencies": func(s string) carapace.Action { return pub.ActionDependencies() }, - "tools.pub.PackageSearch": func(s string) carapace.Action { return pub.ActionPackageSearch() }, - "tools.tshark.FileTypes": func(s string) carapace.Action { return tshark.ActionFileTypes() }, - "tools.tshark.Interfaces": func(s string) carapace.Action { return tshark.ActionInterfaces() }, - "tools.tshark.Protocols": func(s string) carapace.Action { return tshark.ActionProtocols() }, - "tools.tshark.ReadFormats": func(s string) carapace.Action { return tshark.ActionReadFormats() }, - "tools.tshark.Selectors": func(s string) carapace.Action { return tshark.ActionSelectors() }, - "tools.tshark.Statistics": func(s string) carapace.Action { return tshark.ActionStatistics() }, - "tools.virtualbox.Machines": func(s string) carapace.Action { return virtualbox.ActionMachines() }, -} diff --git a/cmd/carapace/cmd/root.go b/cmd/carapace/cmd/root.go index a857034f87..2bd05c604b 100644 --- a/cmd/carapace/cmd/root.go +++ b/cmd/carapace/cmd/root.go @@ -21,18 +21,7 @@ import ( var rootCmd = &cobra.Command{ Use: "carapace [flags] [COMPLETER] [bash|elvish|fish|nushell|oil|powershell|tcsh|xonsh|zsh]", Long: "multi-shell multi-command argument completer", - Example: fmt.Sprintf(` Single completer: - bash: source <(carapace chmod bash) - elvish: eval (carapace chmod elvish | slurp) - fish: carapace chmod fish | source - nushell: carapace chmod | save chmod.nu ; nu -c 'source chmod.nu' - oil: source <(carapace chmod oil) - powershell: carapace chmod powershell | Out-String | Invoke-Expression - tcsh: eval `+"`"+`carapace _chmod tcsh`+"`"+` - xonsh: exec($(carapace chmod xonsh)) - zsh: source <(carapace chmod zsh) - - All completers: + Example: fmt.Sprintf(` All completers and specs: bash: source <(carapace _carapace bash) elvish: eval (carapace _carapace elvish | slurp) fish: carapace _carapace fish | source @@ -43,6 +32,17 @@ var rootCmd = &cobra.Command{ xonsh: exec($(carapace _carapace xonsh)) zsh: source <(carapace _carapace zsh) + Single completer: + bash: source <(carapace chmod bash) + elvish: eval (carapace chmod elvish | slurp) + fish: carapace chmod fish | source + nushell: carapace chmod | save chmod.nu ; nu -c 'source chmod.nu' + oil: source <(carapace chmod oil) + powershell: carapace chmod powershell | Out-String | Invoke-Expression + tcsh: eval `+"`"+`carapace _chmod tcsh`+"`"+` + xonsh: exec($(carapace chmod xonsh)) + zsh: source <(carapace chmod zsh) + Bridge completion: bash: source <(carapace --bridge vault/posener) elvish: eval (carapace --bridge vault/posener|slurp) @@ -72,7 +72,7 @@ var rootCmd = &cobra.Command{ Shell parameter is optional and if left out carapace will try to detect it by parent process name. Some completions are cached at [%v/carapace]. Config is written to [%v/carapace]. - `, func() string { dir, _ := os.UserCacheDir(); return dir }(), func() string { dir, _ := os.UserConfigDir(); return dir }()), + `, suppressErr(os.UserCacheDir), suppressErr(os.UserConfigDir)), Args: cobra.MinimumNArgs(1), ValidArgs: completers, Run: func(cmd *cobra.Command, args []string) { @@ -94,11 +94,24 @@ var rootCmd = &cobra.Command{ } case "--macros": sortedMacros := make([]string, 0, len(macros)) - for m := range macros { - sortedMacros = append(sortedMacros, m) + for name, m := range macros { + sortedMacros = append(sortedMacros, fmt.Sprintf("$_%v(%v)", name, m.Signature())) } sort.Strings(sortedMacros) - println(strings.Join(sortedMacros, "\n")) + fmt.Fprintln(cmd.OutOrStdout(), strings.Join(sortedMacros, "\n")) + + //if len(args) == 1 { + // sortedMacros := make([]string, 0, len(macros)) + // for name := range macros { + // sortedMacros = append(sortedMacros, name) + // } + // sort.Strings(sortedMacros) + // fmt.Fprintln(cmd.OutOrStdout(), strings.Join(sortedMacros, "\n")) + //} else { + // if m, ok := macros[args[1]]; ok { + // fmt.Fprintf(cmd.OutOrStdout(), "$_%v(%v)\n", args[1], m.Signature()) + // } + //} case "-h": cmd.Help() case "--help": @@ -158,6 +171,8 @@ var rootCmd = &cobra.Command{ }, } +func suppressErr(f func() (string, error)) string { s, _ := f(); return s } + func printCompleters() { maxlen := 0 for _, name := range completers { diff --git a/cmd/generate/gen.go b/cmd/generate/gen.go index e7ab98b5b2..b5d55bdb8b 100644 --- a/cmd/generate/gen.go +++ b/cmd/generate/gen.go @@ -1,10 +1,14 @@ package main import ( + "bufio" "fmt" + "io/fs" + "log" "os" "path/filepath" "regexp" + "sort" "strconv" "strings" @@ -13,6 +17,8 @@ import ( ) func main() { + macros() + names, descriptions := readCompleters() imports := make([]string, 0, len(names)) @@ -160,3 +166,73 @@ func rootDir() (string, error) { return filepath.Dir(path), nil } + +func macros() { + root, err := rootDir() + if err != nil { + panic(err.Error) + } + + imports := make(map[string]bool) + macros := make([]string, 0) + + r := regexp.MustCompile(`^func Action(?P[^(]+)\((?P[^(]*)\) carapace.Action {$`) + filepath.WalkDir(root+"/pkg/actions", func(path string, d fs.DirEntry, err error) error { + if !d.IsDir() && strings.HasSuffix(path, ".go") { + file, err := os.Open(path) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if t := scanner.Text(); strings.HasPrefix(t, "func Action") { + if r.MatchString(t) { + pkg := strings.Replace(filepath.Dir(strings.TrimPrefix(path, root+"/pkg/actions/")), "/", ".", -1) + matches := r.FindStringSubmatch(t) + + _import := fmt.Sprintf(` %v "github.com/rsteube/carapace-bin/pkg/actions/%v"`, strings.Replace(pkg, ".", "_", -1), strings.Replace(pkg, ".", "/", -1)) + _func := fmt.Sprintf("%v.Action%v", strings.Replace(pkg, ".", "_", -1), matches[1]) + + if arg := matches[2]; strings.Contains(arg, ",") { + macros = append(macros, "// TODO unsupported signature: "+t) + continue + } else if arg == "" { + macros = append(macros, fmt.Sprintf(`"%v.%v": spec.MacroN(%v),`, pkg, matches[1], _func)) + } else if strings.Contains(arg, "...") { + macros = append(macros, fmt.Sprintf(`"%v.%v": spec.MacroVarI(%v),`, pkg, matches[1], _func)) + } else { + macros = append(macros, fmt.Sprintf(`"%v.%v": spec.MacroI(%v),`, pkg, matches[1], _func)) + } + imports[_import] = true + } + } + } + + } + return nil + }) + + sortedImports := make([]string, 0) + for i := range imports { + sortedImports = append(sortedImports, i) + } + sort.Strings(sortedImports) + + content := fmt.Sprintf(`package cmd + +import ( +%v + spec "github.com/rsteube/carapace-spec" +) + +var macros = map[string]spec.Macro{ +%v +} +`, strings.Join(sortedImports, "\n"), strings.Join(macros, "\n")) + + os.WriteFile(root+"/cmd/carapace/cmd/macros.go", []byte(content), 0644) + exec.Command("go", "fmt", root+"/cmd/carapace/cmd/macros.go").Run() + +} diff --git a/go.mod b/go.mod index b8da8e2431..ccd2fcad4e 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/rsteube/carapace-bin -go 1.17 +go 1.18 require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-ps v1.0.0 github.com/pelletier/go-toml v1.9.5 - github.com/rsteube/carapace v0.20.1 - github.com/rsteube/carapace-spec v0.0.8 + github.com/rsteube/carapace v0.20.2 + github.com/rsteube/carapace-spec v0.0.11 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 golang.org/x/sys v0.0.0-20211205182925-97ca703d548d diff --git a/go.sum b/go.sum index 0bb674d76e..039d6c536d 100644 --- a/go.sum +++ b/go.sum @@ -13,10 +13,10 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rsteube/carapace v0.20.1 h1:ZnPtEZQGi4vSoco7yLexTvmx9X82jUaOcDScpl3v14M= -github.com/rsteube/carapace v0.20.1/go.mod h1:GgiwpPVhucHNOv0AmtIkxhiEFkCMP5BBRauyQLP0mFY= -github.com/rsteube/carapace-spec v0.0.8 h1:Rh4pdhJfw5VpQSgWdeapPZsP2msDRr58HKZzoKh2zWw= -github.com/rsteube/carapace-spec v0.0.8/go.mod h1:u6Qe+U4w4/yD1MWRV9k83WuCkqq4Z/rAjzj8gz7zS9M= +github.com/rsteube/carapace v0.20.2 h1:i6QSQZ5vZKmXcwupsYch8XdJ/GBbZU+H8XtfXEs8Z4E= +github.com/rsteube/carapace v0.20.2/go.mod h1:GgiwpPVhucHNOv0AmtIkxhiEFkCMP5BBRauyQLP0mFY= +github.com/rsteube/carapace-spec v0.0.11 h1:RLPwgj3GkkVm99o6uWz2SidLDMAvdLmMp5nq83obtR0= +github.com/rsteube/carapace-spec v0.0.11/go.mod h1:vyKkMfbIYHhPiUeyCemLWh96XNPwWI9B6Go0+W5nDUw= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= diff --git a/pkg/actions/bridge/cobra.go b/pkg/actions/bridge/cobra.go index f135684d1e..6120c3c9aa 100644 --- a/pkg/actions/bridge/cobra.go +++ b/pkg/actions/bridge/cobra.go @@ -39,7 +39,7 @@ func ActionCobraComplete(cmd string) carapace.Action { } // TODO experimental - directives not yet fully tested - action := carapace.ActionValues() + var action carapace.Action directive, err := readDirective(lines) if err != nil { return carapace.ActionValues() diff --git a/pkg/actions/tools/git/action.go b/pkg/actions/tools/git/action.go index bd4cca7fd7..15ed07ec09 100644 --- a/pkg/actions/tools/git/action.go +++ b/pkg/actions/tools/git/action.go @@ -1,6 +1,7 @@ package git import ( + "reflect" "strings" "github.com/rsteube/carapace" @@ -36,6 +37,10 @@ var RefOptionDefault = RefOption{ // v0.0.1 (last commit msg) func ActionRefs(refOption RefOption) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if reflect.DeepEqual(refOption, RefOption{}) { // for macros: if none is set use the default + refOption = RefOptionDefault + } + vals := make([]string, 0) if branches, err := branches(c, refOption); err != nil { return carapace.ActionMessage(err.Error())