diff --git a/clidocstool_md.go b/clidocstool_md.go
index 8c9f10b..73d05c8 100644
--- a/clidocstool_md.go
+++ b/clidocstool_md.go
@@ -22,6 +22,7 @@ import (
"path/filepath"
"regexp"
"strings"
+ "text/tabwriter"
"text/template"
"github.com/docker/cli-docs-tool/annotation"
@@ -30,7 +31,8 @@ import (
)
var (
- nlRegexp = regexp.MustCompile(`\r?\n`)
+ nlRegexp = regexp.MustCompile(`\r?\n`)
+ adjustSep = regexp.MustCompile(`\|:---(\s+)`)
)
// GenMarkdownTree will generate a markdown page for this command and all
@@ -149,6 +151,42 @@ func mdMakeLink(txt, link string, f *pflag.Flag, isAnchor bool) string {
return "[" + txt + "](" + link + ")"
}
+type mdTable struct {
+ out *strings.Builder
+ tabWriter *tabwriter.Writer
+}
+
+func newMdTable(headers ...string) *mdTable {
+ w := &strings.Builder{}
+ t := &mdTable{
+ out: w,
+ // Using tabwriter.Debug, which uses "|" as separator instead of tabs,
+ // which is what we want. It's a bit of a hack, but does the job :)
+ tabWriter: tabwriter.NewWriter(w, 5, 5, 1, ' ', tabwriter.Debug),
+ }
+ t.addHeader(headers...)
+ return t
+}
+
+func (t *mdTable) addHeader(cols ...string) {
+ t.AddRow(cols...)
+ _, _ = t.tabWriter.Write([]byte("|" + strings.Repeat(":---\t", len(cols)) + "\n"))
+}
+
+func (t *mdTable) AddRow(cols ...string) {
+ for i := range cols {
+ cols[i] = mdEscapePipe(cols[i])
+ }
+ _, _ = t.tabWriter.Write([]byte("| " + strings.Join(cols, "\t ") + "\t\n"))
+}
+
+func (t *mdTable) String() string {
+ _ = t.tabWriter.Flush()
+ return adjustSep.ReplaceAllStringFunc(t.out.String()+"\n", func(in string) string {
+ return strings.ReplaceAll(in, " ", "-")
+ })
+}
+
func mdCmdOutput(cmd *cobra.Command, old string) (string, error) {
b := &strings.Builder{}
@@ -168,12 +206,11 @@ func mdCmdOutput(cmd *cobra.Command, old string) (string, error) {
if len(cmd.Commands()) != 0 {
b.WriteString("### Subcommands\n\n")
- b.WriteString("| Name | Description |\n")
- b.WriteString("| --- | --- |\n")
+ table := newMdTable("Name", "Description")
for _, c := range cmd.Commands() {
- b.WriteString(fmt.Sprintf("| [`%s`](%s) | %s |\n", c.Name(), mdFilename(c), c.Short))
+ table.AddRow(fmt.Sprintf("[`%s`](%s)", c.Name(), mdFilename(c)), c.Short)
}
- b.WriteString("\n\n")
+ b.WriteString(table.String() + "\n")
}
// add inherited flags before checking for flags availability
@@ -181,22 +218,18 @@ func mdCmdOutput(cmd *cobra.Command, old string) (string, error) {
if cmd.Flags().HasAvailableFlags() {
b.WriteString("### Options\n\n")
- b.WriteString("| Name | Type | Default | Description |\n")
- b.WriteString("| --- | --- | --- | --- |\n")
-
+ table := newMdTable("Name", "Type", "Default", "Description")
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if f.Hidden {
return
}
isLink := strings.Contains(old, "")
- b.WriteString("| ")
+ var name string
if f.Shorthand != "" {
- name := "`-" + f.Shorthand + "`"
- name = mdMakeLink(name, f.Name, f, isLink)
- b.WriteString(name + ", ")
+ name = mdMakeLink("`-"+f.Shorthand+"`", f.Name, f, isLink)
+ name += ", "
}
- name := "`--" + f.Name + "`"
- name = mdMakeLink(name, f.Name, f, isLink)
+ name += mdMakeLink("`--"+f.Name+"`", f.Name, f, isLink)
var ftype string
if f.Value.Type() != "bool" {
@@ -221,9 +254,9 @@ func mdCmdOutput(cmd *cobra.Command, old string) (string, error) {
} else if cd, ok := cmd.Annotations[annotation.CodeDelimiter]; ok {
usage = strings.ReplaceAll(usage, cd, "`")
}
- b.WriteString(fmt.Sprintf("%s | %s | %s | %s |\n", mdEscapePipe(name), mdEscapePipe(ftype), mdEscapePipe(defval), mdReplaceNewline(mdEscapePipe(usage))))
+ table.AddRow(name, ftype, defval, mdReplaceNewline(usage))
})
- b.WriteString("\n")
+ b.WriteString(table.String())
}
return b.String(), nil
diff --git a/fixtures/buildx.md b/fixtures/buildx.md
index a625820..607fec9 100644
--- a/fixtures/buildx.md
+++ b/fixtures/buildx.md
@@ -5,17 +5,17 @@ Extended build capabilities with BuildKit
### Subcommands
-| Name | Description |
-| --- | --- |
-| [`build`](buildx_build.md) | Start a build |
-| [`stop`](buildx_stop.md) | Stop builder instance |
+| Name | Description |
+|:---------------------------|:----------------------|
+| [`build`](buildx_build.md) | Start a build |
+| [`stop`](buildx_stop.md) | Stop builder instance |
### Options
-| Name | Type | Default | Description |
-| --- | --- | --- | --- |
-| `--builder` | `string` | | Override the configured builder instance |
+| Name | Type | Default | Description |
+|:------------|:---------|:--------|:-----------------------------------------|
+| `--builder` | `string` | | Override the configured builder instance |
diff --git a/fixtures/buildx_build.md b/fixtures/buildx_build.md
index f56c8e4..742f010 100644
--- a/fixtures/buildx_build.md
+++ b/fixtures/buildx_build.md
@@ -9,30 +9,30 @@ Start a build
### Options
-| Name | Type | Default | Description |
-| --- | --- | --- | --- |
-| [`--add-host`](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
-| `--allow` | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
-| [`--build-arg`](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg) | `stringArray` | | Set build-time variables |
-| `--builder` | `string` | | Override the configured builder instance |
-| `--cache-from` | `stringArray` | | External cache sources (e.g., `user/app:cache`, `type=local,src=path/to/dir`) |
-| `--cache-to` | `stringArray` | | Cache export destinations (e.g., `user/app:cache`, `type=local,dest=path/to/dir`) |
-| [`--cgroup-parent`](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) | `string` | | Optional parent cgroup for the container |
-| [`-f`](https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f), [`--file`](https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f) | `string` | | Name of the Dockerfile (default: `PATH/Dockerfile`) |
-| `--iidfile` | `string` | | Write the image ID to the file |
-| `--label` | `stringArray` | | Set metadata for an image |
-| `--load` | | | Shorthand for `--output=type=docker` |
-| `--network` | `string` | `default` | Set the networking mode for the `RUN` instructions during build |
-| `-o`, `--output` | `stringArray` | | Output destination (format: `type=local,dest=path`) |
-| `--platform` | `stringArray` | local | Set target platform for build |
-| `--push` | | | Shorthand for `--output=type=registry` |
-| `-q`, `--quiet` | | | Suppress the build output and print image ID on success |
-| `--secret` | `stringArray` | | Secret file to expose to the build (format: `id=mysecret,src=/local/secret`) |
-| `--shm-size` | `string` | | Size of `/dev/shm` |
-| `--ssh` | `stringArray` | | SSH agent socket or keys to expose to the build
format: `default\|[=\|[,]]` |
-| [`-t`](https://docs.docker.com/engine/reference/commandline/build/#tag-an-image--t), [`--tag`](https://docs.docker.com/engine/reference/commandline/build/#tag-an-image--t) | `stringArray` | | Name and optionally a tag (format: `name:tag`) |
-| [`--target`](https://docs.docker.com/engine/reference/commandline/build/#specifying-target-build-stage---target) | `string` | | Set the target build stage to build. |
-| `--ulimit` | `string` | | Ulimit options |
+| Name | Type | Default | Description |
+|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|:----------|:-----------------------------------------------------------------------------------------------------|
+| [`--add-host`](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
+| `--allow` | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
+| [`--build-arg`](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg) | `stringArray` | | Set build-time variables |
+| `--builder` | `string` | | Override the configured builder instance |
+| `--cache-from` | `stringArray` | | External cache sources (e.g., `user/app:cache`, `type=local,src=path/to/dir`) |
+| `--cache-to` | `stringArray` | | Cache export destinations (e.g., `user/app:cache`, `type=local,dest=path/to/dir`) |
+| [`--cgroup-parent`](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) | `string` | | Optional parent cgroup for the container |
+| [`-f`](https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f), [`--file`](https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f) | `string` | | Name of the Dockerfile (default: `PATH/Dockerfile`) |
+| `--iidfile` | `string` | | Write the image ID to the file |
+| `--label` | `stringArray` | | Set metadata for an image |
+| `--load` | | | Shorthand for `--output=type=docker` |
+| `--network` | `string` | `default` | Set the networking mode for the `RUN` instructions during build |
+| `-o`, `--output` | `stringArray` | | Output destination (format: `type=local,dest=path`) |
+| `--platform` | `stringArray` | local | Set target platform for build |
+| `--push` | | | Shorthand for `--output=type=registry` |
+| `-q`, `--quiet` | | | Suppress the build output and print image ID on success |
+| `--secret` | `stringArray` | | Secret file to expose to the build (format: `id=mysecret,src=/local/secret`) |
+| `--shm-size` | `string` | | Size of `/dev/shm` |
+| `--ssh` | `stringArray` | | SSH agent socket or keys to expose to the build
format: `default\|[=\|[,]]` |
+| [`-t`](https://docs.docker.com/engine/reference/commandline/build/#tag-an-image--t), [`--tag`](https://docs.docker.com/engine/reference/commandline/build/#tag-an-image--t) | `stringArray` | | Name and optionally a tag (format: `name:tag`) |
+| [`--target`](https://docs.docker.com/engine/reference/commandline/build/#specifying-target-build-stage---target) | `string` | | Set the target build stage to build. |
+| `--ulimit` | `string` | | Ulimit options |
diff --git a/fixtures/buildx_stop.md b/fixtures/buildx_stop.md
index 4eb7e67..ea23375 100644
--- a/fixtures/buildx_stop.md
+++ b/fixtures/buildx_stop.md
@@ -5,9 +5,9 @@ Stop builder instance
### Options
-| Name | Type | Default | Description |
-| --- | --- | --- | --- |
-| `--builder` | `string` | | Override the configured builder instance |
+| Name | Type | Default | Description |
+|:------------|:---------|:--------|:-----------------------------------------|
+| `--builder` | `string` | | Override the configured builder instance |