Skip to content

Commit

Permalink
export macros
Browse files Browse the repository at this point in the history
  • Loading branch information
rsteube committed Dec 18, 2023
1 parent 12713b8 commit 9bddb2d
Show file tree
Hide file tree
Showing 15 changed files with 546 additions and 467 deletions.
38 changes: 38 additions & 0 deletions cmd/carapace/cmd/action/completer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package action

import (
"encoding/json"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/pkg/style"
)

func ActionCompleters() carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return carapace.ActionExecCommand("carapace", "--list")(func(output []byte) carapace.Action {
var completers []struct {
Name string
Description string
Spec string
Overlay string
}
if err := json.Unmarshal(output, &completers); err != nil {
return carapace.ActionMessage(err.Error())
}

vals := make([]string, 0, len(completers))
for _, completer := range completers {
s := style.Default
if completer.Spec != "" {
s = style.Blue
}
if completer.Overlay != "" {
s = style.Of(s, style.Underlined)
}

vals = append(vals, completer.Name, completer.Description, s)
}
return carapace.ActionStyledValuesDescribed(vals...)
})
})
}
2 changes: 2 additions & 0 deletions cmd/carapace/cmd/completers/completers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ var (
)

func Names() []string {
names = append(names, "carapace") // TODO add here or in generate?

unique := make(map[string]string)
for _, name := range names {
unique[name] = name
Expand Down
114 changes: 114 additions & 0 deletions cmd/carapace/cmd/invoke.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package cmd

import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/cmd/carapace/cmd/completers"
"github.com/spf13/cobra"
)

var invokeCmd = &cobra.Command{
Use: "invoke",
Short: "",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
if overlayPath, err := overlayPath(args[0]); err == nil && len(args) > 2 { // and arg[1] is a known shell
cmd := &cobra.Command{
DisableFlagParsing: true,
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: true,
},
}

// TODO yuck
command := args[0]
shell := args[1]
args[0] = "_carapace"
args[1] = "export"
os.Args[1] = "_carapace"
os.Args[2] = "export"
os.Setenv("CARAPACE_LENIENT", "1")

carapace.Gen(cmd).PositionalAnyCompletion(
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
batch := carapace.Batch()
specPath, err := completers.SpecPath(command)
if err != nil {
batch = append(batch, carapace.ActionImport([]byte(invokeCompleter(command))))
} else {
out, err := specCompletion(specPath, args[1:]...)
if err != nil {
return carapace.ActionMessage(err.Error())
}

batch = append(batch, carapace.ActionImport([]byte(out)))
}

batch = append(batch, overlayCompletion(overlayPath, args[1:]...))
return batch.ToA()
}),
)

cmd.SetArgs(append([]string{"_carapace", shell}, args[2:]...))
cmd.Execute()
} else {
if specPath, err := completers.SpecPath(args[0]); err == nil {
out, err := specCompletion(specPath, args[1:]...)
if err != nil {
fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
return
}

// TODO revert the patching from specCompletion to use the integrated version for overlay to work (should move this somewhere else - best in specCompletion)
// TODO only patch completion script
out = strings.Replace(out, fmt.Sprintf("--spec '%v'", specPath), args[0], -1)
out = strings.Replace(out, fmt.Sprintf("'--spec', '%v'", specPath), fmt.Sprintf("'%v'", args[0]), -1) // xonsh callback
fmt.Fprint(cmd.OutOrStdout(), out)
} else {
fmt.Print(invokeCompleter(args[0]))
}
}
},
}

func init() {
carapace.Gen(invokeCmd).Standalone()

}

func invokeCompleter(completer string) string {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

outC := make(chan string)
// copy the output in a separate goroutine so printing can't block indefinitely
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()

os.Args[1] = "_carapace"
executeCompleter(completer)

w.Close()
out := <-outC
os.Stdout = old

executable, err := os.Executable()
if err != nil {
panic(err.Error()) // TODO exit with error message
}
executableName := filepath.Base(executable)
patched := strings.Replace(string(out), fmt.Sprintf("%v _carapace", executableName), fmt.Sprintf("%v %v", executableName, completer), -1) // general callback
patched = strings.Replace(patched, fmt.Sprintf("'%v', '_carapace'", executableName), fmt.Sprintf("'%v', '%v'", executableName, completer), -1) // xonsh callback
return patched

}
74 changes: 74 additions & 0 deletions cmd/carapace/cmd/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package cmd

import (
"encoding/json"
"fmt"
"strconv"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/cmd/carapace/cmd/completers"
"github.com/rsteube/carapace/pkg/style"
"github.com/spf13/cobra"
)

var listCmd = &cobra.Command{
Use: "list",
Short: "",
Run: func(cmd *cobra.Command, args []string) {
// case "json":
printCompletersJson()
// default:
// printCompleters()
// }
},
}

func init() {
carapace.Gen(listCmd).Standalone()

listCmd.Flags().String("format", "plain", "output format")

carapace.Gen(listCmd).FlagCompletion(carapace.ActionMap{
"format": carapace.ActionValues("plain", "json").StyleF(func(s string, sc style.Context) string {
return style.ForPathExt("."+s, sc)
}),
})

}
func printCompleters() {

Check failure on line 38 in cmd/carapace/cmd/list.go

View workflow job for this annotation

GitHub Actions / build

func printCompleters is unused (U1000)

Check failure on line 38 in cmd/carapace/cmd/list.go

View workflow job for this annotation

GitHub Actions / build

func printCompleters is unused (U1000)
maxlen := 0
for _, name := range completers.Names() {
if len := len(name); len > maxlen {
maxlen = len
}
}

for _, name := range completers.Names() {
fmt.Printf("%-"+strconv.Itoa(maxlen)+"v %v\n", name, completers.Description(name))
}
}

func printCompletersJson() {
// TODO move to completers package
type _completer struct {
Name string
Description string
Spec string `json:",omitempty"`
Overlay string `json:",omitempty"`
}

_completers := make([]_completer, 0)
for _, name := range completers.Names() {
specPath, _ := completers.SpecPath(name) // TODO handle error (log?)
overlayPath, _ := completers.OverlayPath(name) // TODO handle error (log?)
_completers = append(_completers, _completer{
Name: name,
Description: completers.Description(name),
Spec: specPath,
Overlay: overlayPath,
})
}
if m, err := json.Marshal(_completers); err == nil { // TODO handle error (log?)
fmt.Println(string(m))
}
}
79 changes: 79 additions & 0 deletions cmd/carapace/cmd/macros.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cmd

import (
"fmt"
"path/filepath"
"sort"
"strconv"
"strings"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/pkg/actions"
"github.com/spf13/cobra"
)

var macrosCmd = &cobra.Command{
Use: "macros",
Short: "",
Run: func(cmd *cobra.Command, args []string) {
switch len(args) {
case 0:
printMacros()
case 1:
printMacro(args[0])
default:
// TODO macro args
}
},
}

func init() {
carapace.Gen(macrosCmd).Standalone()

carapace.Gen(macrosCmd).PositionalCompletion(
carapace.ActionExecCommand("carapace", "--macros")(func(output []byte) carapace.Action {
lines := strings.Split(string(output), "\n")

vals := make([]string, 0)
for _, line := range lines[:len(lines)-1] {
if fields := strings.Fields(line); len(fields) > 1 {
vals = append(vals, fields[0], strings.Join(fields[1:], " "))
} else {
vals = append(vals, fields[0], "")
}
}
return carapace.ActionValuesDescribed(vals...).Invoke(carapace.Context{}).ToMultiPartsA(".")
}),
)
}

func printMacros() {
maxlen := 0
names := make([]string, 0)
for name := range actions.MacroMap {
names = append(names, name)
if len := len(name); len > maxlen {
maxlen = len
}
}

sort.Strings(names)
for _, name := range names {
fmt.Printf("%-"+strconv.Itoa(maxlen)+"v %v\n", name, actions.MacroDescriptions[name])
}
}

func printMacro(name string) {
if m, ok := actions.MacroMap[name]; ok {
path := strings.Replace(name, ".", "/", -1)
signature := ""
if s := m.Signature(); s != "" {
signature = fmt.Sprintf("(%v)", s)
}

fmt.Printf(`signature: $_%v%v
description: %v
reference: https://pkg.go.dev/github.com/rsteube/carapace-bin/pkg/actions/%v#Action%v
`, name, signature, actions.MacroDescriptions[name], filepath.Dir(path), filepath.Base(path))
}
}
Loading

0 comments on commit 9bddb2d

Please sign in to comment.