diff --git a/cmd/carapace/cmd/root.go b/cmd/carapace/cmd/root.go index d91953d375..cb8c4a2126 100644 --- a/cmd/carapace/cmd/root.go +++ b/cmd/carapace/cmd/root.go @@ -12,6 +12,7 @@ import ( "sort" "strconv" "strings" + "time" "github.com/rsteube/carapace-bin/cmd/carapace/cmd/completers" spec "github.com/rsteube/carapace-spec" @@ -79,6 +80,10 @@ var rootCmd = &cobra.Command{ Args: cobra.MinimumNArgs(1), ValidArgs: completers.Names(), Run: func(cmd *cobra.Command, args []string) { + if err := updateSchema(); err != nil { + fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) + } + // since flag parsing is disabled do this manually switch args[0] { case "--bridge": @@ -275,6 +280,45 @@ func setStyle(s string) error { return fmt.Errorf("invalid format: '%v'", s) } +func updateSchema() error { + confDir, err := os.UserConfigDir() + if err != nil { + return err + } + path := fmt.Sprintf("%v/carapace/schema.json", confDir) + + infoSchema, err := os.Stat(path) + if err != nil && !os.IsNotExist(err) { + return err + } + + executable, err := os.Executable() + if err != nil && !os.IsNotExist(err) { + return err + } + + infoCarapace, err := os.Stat(executable) + if err != nil && !os.IsNotExist(err) { + return err + } + + if infoSchema == nil || !infoSchema.ModTime().Equal(infoCarapace.ModTime()) { + schema, err := spec.Schema() + if err != nil && !os.IsNotExist(err) { + return err + } + + if err := os.WriteFile(path, []byte(schema), os.ModePerm); err != nil { + return err + } + + if err := os.Chtimes(path, time.Now(), infoCarapace.ModTime()); err != nil { + return err + } + } + return nil +} + func Execute(version string) error { rootCmd.Version = version return rootCmd.Execute() diff --git a/docs/src/spec/user.md b/docs/src/spec/user.md index 26d5c01f72..909c23eda3 100644 --- a/docs/src/spec/user.md +++ b/docs/src/spec/user.md @@ -18,4 +18,13 @@ completion: positionalany: ["$_bridge.Cobra(kubectl)"] ``` +## JSON Schema + +A [JSON Schema](http://json-schema.org/) is automatically written to [`${UserConfigDir}/.config/carapace/schema.json`](https://pkg.go.dev/os#UserConfigDir). +It can be used by adding the following header to the [Specs]: + +```yaml +# yaml-language-server: $schema=../schema.json +``` + [Specs]:../spec.md diff --git a/go.mod b/go.mod index a2e15e3f3e..0ff891141f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/pelletier/go-toml v1.9.5 github.com/rsteube/carapace v0.25.1 - github.com/rsteube/carapace-spec v0.1.2 + github.com/rsteube/carapace-spec v0.1.3 github.com/spf13/cobra v1.6.0 github.com/spf13/pflag v1.0.5 gopkg.in/ini.v1 v1.67.0 diff --git a/go.sum b/go.sum index d1dbdaeaf1..a3335071f9 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/rsteube/carapace v0.25.1 h1:zF6gJqrQ82fPv15A8APh2giAjj/IXX1ENri/svNm7 github.com/rsteube/carapace v0.25.1/go.mod h1:3N1bLcmfoBOn0WwCniEhVF52AqvN//zyV1JrtT52ECw= github.com/rsteube/carapace-pflag v0.0.4 h1:Onb0cLNLxg1xJr2EsMlBldAI5KkybrvZ89b5cRElZXI= github.com/rsteube/carapace-pflag v0.0.4/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/rsteube/carapace-spec v0.1.2 h1:3jzihlqG/hIyULzIQvBgjftLHdMqkZ8ucI8v5A1Xc4A= -github.com/rsteube/carapace-spec v0.1.2/go.mod h1:vhyWE0ml+1RhJNWgVBDBOaSQtTDIX9uaOqBZeASRfPk= +github.com/rsteube/carapace-spec v0.1.3 h1:rTsETXp0XyQ6LqUTzkQgOBZ3I/NrtKEcc3mapfWkYBc= +github.com/rsteube/carapace-spec v0.1.3/go.mod h1:vhyWE0ml+1RhJNWgVBDBOaSQtTDIX9uaOqBZeASRfPk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=