Repository: rsteube/carapace
Pull request #132 (2020-12-06 00:01:00)

added docs (inital version)
- updated ci (added gh-pages)
- updated project layout


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 353be67..73834b2 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,9 +1,5 @@
 version: 2.1
 
-references:
-  workspace: &workspace
-    /go/src/github.com/rsteube/carapace
-
 commands:
   run_tests:
     steps:
@@ -19,11 +15,13 @@ commands:
       - run:
           name: "install shellcheck"
           command: |
-            curl -Lso shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.6/shellcheck
+            scversion="stable" # or "v0.4.7", or "latest"
+            wget -qO- "https://github.com/koalaman/shellcheck/releases/download/${scversion?}/shellcheck-${scversion?}.linux.x86_64.tar.xz" | tar -xJv shellcheck-stable/shellcheck
+            mv shellcheck-stable/shellcheck .
             chmod +x shellcheck
       - run:
           name: "shellcheck bash"
-          command: ./shellcheck -e SC2046,SC2207 <(./example/example _carapace bash)
+          command: ./shellcheck -e SC2046,SC2206,SC2207 <(./example/example _carapace bash)
       - run:
           name: "shellcheck fish"
           command: ./shellcheck -e SC1064,SC1072,SC1073 <(./example/example _carapace fish)
@@ -34,10 +32,9 @@ commands:
 jobs:
   go-current:
     docker:
-      - image: circleci/golang:1.15
+      - image: cimg/go:1.15
         environment:
           GO111MODULE: "on"
-    working_directory: *workspace
     steps:
       - checkout
       - run_tests
@@ -46,23 +43,36 @@ jobs:
           command: diff -u <(echo -n) <(gofmt -d -s .)
   go-previous:
     docker:
-      - image: circleci/golang:1.14
+      - image: cimg/go:1.14
         environment:
           GO111MODULE: "on"
-    working_directory: *workspace
     steps:
       - checkout
       - run_tests
-  go-latest:
+  doc:
     docker:
-      - image: circleci/golang:latest
-    working_directory: *workspace
+      - image: cimg/go:1.15
     steps:
       - checkout
-      - run_tests
+      - run:
+          name: "install mdbook"
+          command: curl -L "https://github.com/rust-lang/mdBook/releases/download/v0.4.4/mdbook-v0.4.4-x86_64-unknown-linux-gnu.tar.gz" | tar -xvz mdbook
+      - run:
+          name: "build docs"
+          command: ./mdbook build docs
+      - run:
+          name: "push gh-pages"
+          command: |
+            cd docs/book/
+            git init
+            git config user.name rsteube
+            git config user.email rsteube@users.noreply.github.com
+            git add .
+            git commit -m "Initial commit [ci skip]"
+            git push --force https://rsteube:${GITHUB_TOKEN}@github.com/rsteube/carapace.git master:gh-pages
   release:
     docker:
-      - image: circleci/golang:1.15
+      - image: cimg/go:1.15
     steps:
       - checkout
       - run: cd example && curl -sL https://git.io/goreleaser | bash
@@ -73,7 +83,12 @@ workflows:
     jobs:
       - go-current
       - go-previous
-      - go-latest
+      - doc:
+          filters:
+            branches:
+              only: /master/
+            tags:
+              ignore: /.*/
   tags:
     jobs:
       - release:
diff --git a/.gitignore b/.gitignore
index 87e43df..39959f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .vscode
 example/example
 caraparse/caraparse
+docs/book
diff --git a/action.go b/action.go
index 7f782e2..1ba73af 100644
--- a/action.go
+++ b/action.go
@@ -3,13 +3,13 @@ package carapace
 import (
 	"strings"
 
-	"github.com/rsteube/carapace/bash"
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/elvish"
-	"github.com/rsteube/carapace/fish"
-	"github.com/rsteube/carapace/powershell"
-	"github.com/rsteube/carapace/xonsh"
-	"github.com/rsteube/carapace/zsh"
+	"github.com/rsteube/carapace/internal/bash"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/elvish"
+	"github.com/rsteube/carapace/internal/fish"
+	"github.com/rsteube/carapace/internal/powershell"
+	"github.com/rsteube/carapace/internal/xonsh"
+	"github.com/rsteube/carapace/internal/zsh"
 	"github.com/spf13/cobra"
 )
 
diff --git a/carapace.go b/carapace.go
index 75c5884..89eabe0 100644
--- a/carapace.go
+++ b/carapace.go
@@ -11,13 +11,13 @@ import (
 	"strings"
 
 	ps "github.com/mitchellh/go-ps"
-	"github.com/rsteube/carapace/bash"
-	"github.com/rsteube/carapace/elvish"
-	"github.com/rsteube/carapace/fish"
-	"github.com/rsteube/carapace/powershell"
-	"github.com/rsteube/carapace/uid"
-	"github.com/rsteube/carapace/xonsh"
-	"github.com/rsteube/carapace/zsh"
+	"github.com/rsteube/carapace/internal/bash"
+	"github.com/rsteube/carapace/internal/elvish"
+	"github.com/rsteube/carapace/internal/fish"
+	"github.com/rsteube/carapace/internal/powershell"
+	"github.com/rsteube/carapace/internal/uid"
+	"github.com/rsteube/carapace/internal/xonsh"
+	"github.com/rsteube/carapace/internal/zsh"
 	"github.com/spf13/cobra"
 )
 
diff --git a/docker-compose.yml b/docker-compose.yml
index 7756586..70ceab1 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,7 +3,7 @@ version: '3'
 services:
   build:
     image: golang
-    command: sh -c 'cd /carapace/example && go build .'
+    command: sh -c 'cd /carapace/examples && go build .'
     volumes:
       - '.:/carapace/'
       - 'go:/go/'
diff --git a/docs/book.toml b/docs/book.toml
new file mode 100644
index 0000000..985ff7f
--- /dev/null
+++ b/docs/book.toml
@@ -0,0 +1,9 @@
+[book]
+authors = ["rsteube"]
+language = "en"
+multilingual = false
+src = "src"
+title = "carapace"
+
+[output.html]
+default-theme = "Coal"
diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
new file mode 100644
index 0000000..083c596
--- /dev/null
+++ b/docs/src/SUMMARY.md
@@ -0,0 +1,12 @@
+# Summary
+
+- [carapace](./carapace.md)
+  - [Action](./carapace/action.md)
+  - [InvokedAction](./carapace/invokedAction.md)
+  - [Uid](./carapace/uid.md) 
+  - [Hidden Subcommand](./carapace/hiddenSubcommand.md)
+  - [Flags](./carapace/flags.md) 
+  - [Positional Arguments](./carapace/positionalArguments.md)
+- [caraparse](./caraparse.md)
+- [carapace-bin](./carapace-bin.md)
+- [lazycomplete](./lazycomplete.md)
diff --git a/docs/src/carapace-bin.md b/docs/src/carapace-bin.md
new file mode 100644
index 0000000..4e9aa41
--- /dev/null
+++ b/docs/src/carapace-bin.md
@@ -0,0 +1,1 @@
+# carapace-bin
diff --git a/docs/src/carapace.md b/docs/src/carapace.md
new file mode 100644
index 0000000..2d808af
--- /dev/null
+++ b/docs/src/carapace.md
@@ -0,0 +1,14 @@
+# carapace
+
+[carapace] is a shell completion script generator for [spf13/cobra] with support for:
+
+- [Bash](https://www.gnu.org/software/bash/)
+- [Elvish](https://elv.sh/)
+- [Fish](https://fishshell.com/)
+- [Oil](http://www.oilshell.org/)
+- [Powershell](https://microsoft.com/powershell)
+- [Xonsh](https://xon.sh/)
+- [Zsh](https://www.zsh.org/)
+
+[carapace]:https://github.com/rsteube/carapace
+[spf13/cobra]:https://github.com/spf13/cobra
diff --git a/docs/src/carapace/action.md b/docs/src/carapace/action.md
new file mode 100644
index 0000000..bf3d497
--- /dev/null
+++ b/docs/src/carapace/action.md
@@ -0,0 +1,71 @@
+# Action
+
+An [Action](https://pkg.go.dev/github.com/rsteube/carapace#Action) indicates how to complete a flag or a positional argument.
+
+## ActionMessage
+
+```go
+carapace.ActionMessage("message example")
+```
+
+## ActionValues
+
+## ActionValuesDescribed
+
+## ActionCallback
+ActionCallback is a special action where the program itself provides the completion dynamically. For this the hidden command is called with a uid and the current command line content which then lets cobra parse existing flags and invokes the callback function after that.
+
+```go
+carapace.ActionCallback(func(args []string) carapace.Action {
+  if conditionCmd.Flag("required").Value.String() == "valid" {
+    return carapace.ActionValues("condition fulfilled")
+  } else {
+    return carapace.ActionMessage("flag --required must be set to valid: " + conditionCmd.Flag("required").Value.String())
+  }
+})
+```
+
+Since callbacks are simply invocations of the program they can be tested directly.
+```sh
+./example _carapace bash '_example__condition#1' example condition --required invalid
+#compgen -W $'_\nERR (flag --required must be set to valid: invalid)' -- "${cur//\\ / }" | sed "s!^${curprefix//\\ / }!!"
+
+./example _carapace elvish '_example__condition#1' example condition --required invalid
+#edit:complex-candidate ERR &display-suffix=' (flag --required must be set to valid: invalid)'
+#edit:complex-candidate _ &display-suffix=' ()'
+
+./example _carapace fish '_example__condition#1' example condition --required invalid
+#echo -e ERR\tflag --required must be set to valid: invalid\n_\t\n\n
+
+./example _carapace powershell '_example__condition#1' example condition --required invalid
+#[CompletionResult]::new('ERR', 'ERR', [CompletionResultType]::ParameterValue, ' ')
+#[CompletionResult]::new('flag --required must be set to valid: invalid', 'flag --required must be set to valid: invalid', [CompletionResultType]::ParameterValue, ' ')
+
+./example _carapace xonsh '_example__condition#1' example condition --required invalid
+#{
+#  RichCompletion('_', display='_', description='flag --required must be set to valid: invalid', prefix_len=0),
+#  RichCompletion('ERR', display='ERR', description='flag --required must be set to valid: invalid', prefix_len=0),
+#}
+
+./example _carapace zsh '_example__condition#1' example condition --required invalid
+#{local _comp_desc=('_' 'ERR (flag --required must be set to valid: invalid)');compadd -S '' -d _comp_desc '_' 'ERR'}
+```
+
+## ActionMultiParts
+
+ActionMultiParts is a callback action where parts of an argument can be completed separately (e.g. user:group from chown). Divider can be empty as well, but note that bash and fish will add the space suffix for anything other than `/=@:.,` (it still works, but after each selection backspace is needed to continue the completion).
+
+```go
+func ActionUserGroup() carapace.Action {
+	return carapace.ActionMultiParts(":", func(args []string, parts []string) carapace.Action {
+		switch len(parts) {
+		case 0:
+			return ActionUsers().Invoke(args).Suffix(":").ToA()
+		case 1:
+			return ActionGroups()
+		default:
+			return carapace.ActionValues()
+		}
+	})
+}
+```
diff --git a/docs/src/carapace/commands.md b/docs/src/carapace/commands.md
new file mode 100644
index 0000000..61c515e
--- /dev/null
+++ b/docs/src/carapace/commands.md
@@ -0,0 +1,1 @@
+# Commands
diff --git a/docs/src/carapace/flags.md b/docs/src/carapace/flags.md
new file mode 100644
index 0000000..643b2b2
--- /dev/null
+++ b/docs/src/carapace/flags.md
@@ -0,0 +1,29 @@
+# Flags
+
+| type | example |
+| --- | --- |
+| shorthand | `ls -l` |
+| longhand | `ls --all` |
+| optional argument | `tail --follow=descriptor` |
+
+> - `shorthand-only` flags are supported using the [cornfeedhobo/pflag](https://github.com/cornfeedhobo/pflag) fork
+
+
+## Completion
+
+Completion for flags can be configured with [`FlagCompletion`](https://pkg.go.dev/github.com/rsteube/carapace#Carapace.FlagCompletion) and a map consisting of name and [Action](./action.md).
+
+```go
+carapace.Gen(myCmd).FlagCompletion(carapace.ActionMap{
+    "flagName": carapace.ActionValues("a", "b", "c"),
+    // ...
+})
+```
+
+To mark a flag argument as optional the `NoOptDefVal` needs to be set to anything other than empty string.
+
+```go
+rootCmd.Flag("optarg").NoOptDefVal = " "
+```
+
+
diff --git a/docs/src/carapace/hiddenSubcommand.md b/docs/src/carapace/hiddenSubcommand.md
new file mode 100644
index 0000000..1e15618
--- /dev/null
+++ b/docs/src/carapace/hiddenSubcommand.md
@@ -0,0 +1,3 @@
+# Hidden Subcommand
+
+When `carapace.Gen()` is invoked a hidden command (`_carapace`) is added to the root command unless it already exists. This handles completion script generation and callbacks.
diff --git a/docs/src/carapace/invokedAction.md b/docs/src/carapace/invokedAction.md
new file mode 100644
index 0000000..f840552
--- /dev/null
+++ b/docs/src/carapace/invokedAction.md
@@ -0,0 +1,1 @@
+# InvokedAction
diff --git a/docs/src/carapace/positionalArguments.md b/docs/src/carapace/positionalArguments.md
new file mode 100644
index 0000000..1095ab9
--- /dev/null
+++ b/docs/src/carapace/positionalArguments.md
@@ -0,0 +1,27 @@
+# Positional Arguments
+
+```sh
+command subcommand [arg1] [arg2] ...
+```
+
+> A command can have only either arguments or subcommands. A mix of these is **not** supported.
+
+## Completion
+
+Completion for positional arguments can be configured with [`PositionalCompletion`](https://pkg.go.dev/github.com/rsteube/carapace#Carapace.PositionalCompletion) and a list of [Actions](./action.md).
+
+```go
+carapace.Gen(callbackCmd).PositionalCompletion(
+    carapace.ActionValues("a", "b", "c"),
+    // ...
+)
+```
+
+It is also possible to define completion for any positional argument not already explicitly defined using [`PositionalAnyCompletion`](https://pkg.go.dev/github.com/rsteube/carapace#Carapace.PositionalAnyCompletion).
+
+```go
+carapace.Gen(callbackCmd).PositionalCompletion(
+    carapace.ActionValues("a", "b", "c"),
+    // ...
+)
+```
diff --git a/docs/src/carapace/uid.md b/docs/src/carapace/uid.md
new file mode 100644
index 0000000..10feab2
--- /dev/null
+++ b/docs/src/carapace/uid.md
@@ -0,0 +1,15 @@
+# Uid
+
+Uids are generated to identify corresponding completions:
+
+- positional arguments
+```handlebars
+_{{rootCmd}}__{{subCommand1}}__{{subCommand2}}#{{position}}
+```
+
+- flags
+```handlebars
+_{{rootCmd}}__{{subCommand1}}__{{subCommand2}}##{{flagName}}
+```
+
+
diff --git a/docs/src/caraparse.md b/docs/src/caraparse.md
new file mode 100644
index 0000000..edaaa46
--- /dev/null
+++ b/docs/src/caraparse.md
@@ -0,0 +1,10 @@
+# caraparse
+
+[caraparse] is a helper tool that uses regex to parse gnu help pages. Due to strong inconsistencies between these the results may differ but generally give a good head start.
+
+```sh
+docker node update --help | caraparse -n update -p node -s "Update a node"
+```
+
+
+[caraparse]:https://github.com/rsteube/carapace-bin/tree/master/cmd/caraparse
diff --git a/docs/src/lazycomplete.md b/docs/src/lazycomplete.md
new file mode 100644
index 0000000..c1cb955
--- /dev/null
+++ b/docs/src/lazycomplete.md
@@ -0,0 +1,1 @@
+# lazycomplete
diff --git a/assert/assert.go b/internal/assert/assert.go
similarity index 100%
rename from assert/assert.go
rename to internal/assert/assert.go
diff --git a/bash/action.go b/internal/bash/action.go
similarity index 96%
rename from bash/action.go
rename to internal/bash/action.go
index 17a68c1..8d8386d 100644
--- a/bash/action.go
+++ b/internal/bash/action.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
+	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer(
diff --git a/bash/snippet.go b/internal/bash/snippet.go
similarity index 98%
rename from bash/snippet.go
rename to internal/bash/snippet.go
index 4d74d3b..37fdd99 100644
--- a/bash/snippet.go
+++ b/internal/bash/snippet.go
@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/uid"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )
diff --git a/common/pflag.go b/internal/common/pflag.go
similarity index 100%
rename from common/pflag.go
rename to internal/common/pflag.go
diff --git a/common/value.go b/internal/common/value.go
similarity index 100%
rename from common/value.go
rename to internal/common/value.go
diff --git a/elvish/action.go b/internal/elvish/action.go
similarity index 96%
rename from elvish/action.go
rename to internal/elvish/action.go
index 642f27e..c7b3fb8 100644
--- a/elvish/action.go
+++ b/internal/elvish/action.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
+	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer(
diff --git a/elvish/snippet.go b/internal/elvish/snippet.go
similarity index 97%
rename from elvish/snippet.go
rename to internal/elvish/snippet.go
index 9d5ee86..162b9f2 100644
--- a/elvish/snippet.go
+++ b/internal/elvish/snippet.go
@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/uid"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )
diff --git a/fish/action.go b/internal/fish/action.go
similarity index 95%
rename from fish/action.go
rename to internal/fish/action.go
index 7e3b588..a3fa46e 100644
--- a/fish/action.go
+++ b/internal/fish/action.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
+	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer(
diff --git a/fish/snippet.go b/internal/fish/snippet.go
similarity index 98%
rename from fish/snippet.go
rename to internal/fish/snippet.go
index a8941aa..ecfb5bf 100644
--- a/fish/snippet.go
+++ b/internal/fish/snippet.go
@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/uid"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )
diff --git a/powershell/action.go b/internal/powershell/action.go
similarity index 96%
rename from powershell/action.go
rename to internal/powershell/action.go
index 8cbe555..cb893cc 100644
--- a/powershell/action.go
+++ b/internal/powershell/action.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
+	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer( // TODO
diff --git a/powershell/snippet.go b/internal/powershell/snippet.go
similarity index 98%
rename from powershell/snippet.go
rename to internal/powershell/snippet.go
index 55aa64d..ecc552d 100644
--- a/powershell/snippet.go
+++ b/internal/powershell/snippet.go
@@ -6,8 +6,8 @@ import (
 	"io"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/uid"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )
diff --git a/xonsh/action.go b/internal/xonsh/action.go
similarity index 96%
rename from xonsh/action.go
rename to internal/xonsh/action.go
index 04ee7da..38aaeef 100644
--- a/xonsh/action.go
+++ b/internal/xonsh/action.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
+	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer( // TODO
diff --git a/xonsh/snippet.go b/internal/xonsh/snippet.go
similarity index 98%
rename from xonsh/snippet.go
rename to internal/xonsh/snippet.go
index 681f757..929f576 100644
--- a/xonsh/snippet.go
+++ b/internal/xonsh/snippet.go
@@ -6,8 +6,8 @@ import (
 	"io"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/uid"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )
diff --git a/zsh/action.go b/internal/zsh/action.go
similarity index 97%
rename from zsh/action.go
rename to internal/zsh/action.go
index b782a5a..b56b2f2 100644
--- a/zsh/action.go
+++ b/internal/zsh/action.go
@@ -2,7 +2,7 @@ package zsh
 
 import (
 	"fmt"
-	"github.com/rsteube/carapace/common"
+	"github.com/rsteube/carapace/internal/common"
 	"strings"
 )
 
diff --git a/zsh/snippet.go b/internal/zsh/snippet.go
similarity index 98%
rename from zsh/snippet.go
rename to internal/zsh/snippet.go
index 10cb648..a1e1a2a 100644
--- a/zsh/snippet.go
+++ b/internal/zsh/snippet.go
@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/common"
-	"github.com/rsteube/carapace/uid"
+	"github.com/rsteube/carapace/internal/common"
+	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )


Test patch:
diff --git a/example/cmd/root_test.go b/example/cmd/root_test.go
index d41a3b2..4f684f0 100644
--- a/example/cmd/root_test.go
+++ b/example/cmd/root_test.go
@@ -4,7 +4,7 @@ import (
 	"testing"
 
 	"github.com/rsteube/carapace"
-	"github.com/rsteube/carapace/assert"
+	"github.com/rsteube/carapace/internal/assert"
 )
 
 func TestBash(t *testing.T) {
diff --git a/uid/uid.go b/internal/uid/uid.go
similarity index 100%
rename from uid/uid.go
rename to internal/uid/uid.go
diff --git a/uid/uid_test.go b/internal/uid/uid_test.go
similarity index 97%
rename from uid/uid_test.go
rename to internal/uid/uid_test.go
index 67eab73..0c569e2 100644
--- a/uid/uid_test.go
+++ b/internal/uid/uid_test.go
@@ -3,7 +3,7 @@ package uid
 import (
 	"testing"
 
-	"github.com/rsteube/carapace/assert"
+	"github.com/rsteube/carapace/internal/assert"
 	"github.com/spf13/cobra"
 )