Repository: segmentio/terraform-docs
Pull request #266 (2020-05-20 23:40:03)

Refactor cli implemention and configuration
### Prerequisites

Put an `x` into the box(es) that apply:

- [ ] This pull request fixes a bug.
- [ ] This pull request adds a feature.
- [x] This pull request enhances existing functionality.
- [ ] This pull request introduces breaking change.

For more information, see the [Contributing Guide](https://github.com/segmentio/terraform-docs/tree/master/CONTRIBUTING.md).

### Description

Refactoring engine behind CLI configuration, this moves all the available flags into `cli.Config` which encapsulate all the normalization and validation internally and helps extensively reusing config logic for different formatters.

### Issues Resolved

List any existing issues this pull request resolves.

### Checklist

Put an `x` into all boxes that apply:

- [ ] I have read the [Contributing Guidelines](https://github.com/segmentio/terraform-docs/tree/master/CONTRIBUTING.md).

#### Tests

- [ ] I have added tests to cover my changes.
- [ ] All tests pass when I run `make test`.

#### Documentation

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.

#### Code Style

- [ ] My code follows the code style of this project.


codecov-commenter: # [Codecov](https://codecov.io/gh/segmentio/terraform-docs/pull/266?src=pr&el=h1) Report
> Merging [#266](https://codecov.io/gh/segmentio/terraform-docs/pull/266?src=pr&el=desc) into [master](https://codecov.io/gh/segmentio/terraform-docs/commit/085cac0c54c0d57fb91b0a192059e135efa491de&el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##           master     #266   +/-   ##
=======================================
  Coverage   81.68%   81.68%           
=======================================
  Files          34       34           
  Lines        1796     1796           
=======================================
  Hits         1467     1467           
  Misses        274      274           
  Partials       55       55           
```


| [Impacted Files](https://codecov.io/gh/segmentio/terraform-docs/pull/266?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [internal/format/factory.go](https://codecov.io/gh/segmentio/terraform-docs/pull/266/diff?src=pr&el=tree#diff-aW50ZXJuYWwvZm9ybWF0L2ZhY3RvcnkuZ28=) | `100.00% <100.00%> (ø)` | |


Patch:
diff --git a/cmd/asciidoc.go b/cmd/asciidoc.go
deleted file mode 100644
index 7d32f4e..0000000
--- a/cmd/asciidoc.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var asciidocCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "asciidoc [PATH]",
-	Aliases:     []string{"adoc"},
-	Short:       "Generate AsciiDoc of inputs and outputs",
-	Annotations: formatAnnotations("asciidoc"),
-	RunE:        formatRunE,
-}
-
-var asciidocTableCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "table [PATH]",
-	Aliases:     []string{"tbl"},
-	Short:       "Generate AsciiDoc tables of inputs and outputs",
-	Annotations: formatAnnotations("asciidoc table"),
-	RunE:        formatRunE,
-}
-
-var asciidocDocumentCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "document [PATH]",
-	Aliases:     []string{"doc"},
-	Short:       "Generate AsciiDoc document of inputs and outputs",
-	Annotations: formatAnnotations("asciidoc document"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	asciidocCmd.PersistentFlags().BoolVar(new(bool), "no-required", false, "do not show \"Required\" column or section")
-	asciidocCmd.PersistentFlags().BoolVar(new(bool), "no-sensitive", false, "do not show \"Sensitive\" column or section")
-	asciidocCmd.PersistentFlags().MarkDeprecated("no-required", "use '--required=false' instead")   //nolint:errcheck
-	asciidocCmd.PersistentFlags().MarkDeprecated("no-sensitive", "use '--sensitive=false' instead") //nolint:errcheck
-
-	asciidocCmd.PersistentFlags().BoolVar(&settings.ShowRequired, "required", true, "show \"Required\" column or section")
-	asciidocCmd.PersistentFlags().BoolVar(&settings.ShowSensitivity, "sensitive", true, "show \"Sensitive\" column or section")
-	asciidocCmd.PersistentFlags().IntVar(&settings.IndentLevel, "indent", 2, "indention level of AsciiDoc sections [1, 2, 3, 4, 5]")
-
-	asciidocCmd.AddCommand(asciidocTableCmd)
-	asciidocCmd.AddCommand(asciidocDocumentCmd)
-
-	rootCmd.AddCommand(asciidocCmd)
-}
diff --git a/cmd/asciidoc/asciidoc.go b/cmd/asciidoc/asciidoc.go
new file mode 100644
index 0000000..55a60bf
--- /dev/null
+++ b/cmd/asciidoc/asciidoc.go
@@ -0,0 +1,39 @@
+package asciidoc
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/cmd/asciidoc/document"
+	"github.com/segmentio/terraform-docs/cmd/asciidoc/table"
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'asciidoc' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "asciidoc [PATH]",
+		Aliases:     []string{"adoc"},
+		Short:       "Generate AsciiDoc of inputs and outputs",
+		Annotations: cli.Annotations("asciidoc"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+
+	// flags
+	cmd.PersistentFlags().BoolVar(&config.Settings.Required, "required", true, "show \"Required\" column or section")
+	cmd.PersistentFlags().BoolVar(&config.Settings.Sensitive, "sensitive", true, "show \"Sensitive\" column or section")
+	cmd.PersistentFlags().IntVar(&config.Settings.Indent, "indent", 2, "indention level of AsciiDoc sections [1, 2, 3, 4, 5]")
+
+	// deprecation
+	cmd.PersistentFlags().BoolVar(new(bool), "no-required", false, "do not show \"Required\" column or section")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-sensitive", false, "do not show \"Sensitive\" column or section")
+	cmd.PersistentFlags().MarkDeprecated("no-required", "use '--required=false' instead")   //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-sensitive", "use '--sensitive=false' instead") //nolint:errcheck
+
+	// subcommands
+	cmd.AddCommand(document.NewCommand(config))
+	cmd.AddCommand(table.NewCommand(config))
+
+	return cmd
+}
diff --git a/cmd/asciidoc/document/document.go b/cmd/asciidoc/document/document.go
new file mode 100644
index 0000000..e372ab3
--- /dev/null
+++ b/cmd/asciidoc/document/document.go
@@ -0,0 +1,21 @@
+package document
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'asciidoc document' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "document [PATH]",
+		Aliases:     []string{"doc"},
+		Short:       "Generate AsciiDoc document of inputs and outputs",
+		Annotations: cli.Annotations("asciidoc document"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/asciidoc/table/table.go b/cmd/asciidoc/table/table.go
new file mode 100644
index 0000000..71e2698
--- /dev/null
+++ b/cmd/asciidoc/table/table.go
@@ -0,0 +1,21 @@
+package table
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'asciidoc table' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "table [PATH]",
+		Aliases:     []string{"tbl"},
+		Short:       "Generate AsciiDoc tables of inputs and outputs",
+		Annotations: cli.Annotations("asciidoc table"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/completion.go b/cmd/completion.go
deleted file mode 100644
index 02ef981..0000000
--- a/cmd/completion.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package cmd
-
-import (
-	"os"
-
-	"github.com/spf13/cobra"
-)
-
-var completionCmd = &cobra.Command{
-	Args:  cobra.NoArgs,
-	Use:   "completion SHELL",
-	Short: "Generate autocomplete for terraform-docs",
-	Long:  "Generate autocomplete for terraform-docs",
-}
-
-var bashCompletionCmd = &cobra.Command{
-	Args:  cobra.NoArgs,
-	Use:   "bash",
-	Short: "Generate autocomplete for bash",
-	Long:  "Generate autocomplete for bash",
-	Run: func(cmd *cobra.Command, args []string) {
-		_ = rootCmd.GenBashCompletion(os.Stdout)
-	},
-}
-var zshCompletionCmd = &cobra.Command{
-	Args:  cobra.NoArgs,
-	Use:   "zsh",
-	Short: "Generate autocomplete for zsh",
-	Long:  "Generate autocomplete for zsh",
-	Run: func(cmd *cobra.Command, args []string) {
-		_ = rootCmd.GenZshCompletion(os.Stdout)
-	},
-}
-
-func init() {
-	completionCmd.AddCommand(bashCompletionCmd)
-	completionCmd.AddCommand(zshCompletionCmd)
-
-	rootCmd.AddCommand(completionCmd)
-}
diff --git a/cmd/completion/bash/bash.go b/cmd/completion/bash/bash.go
new file mode 100644
index 0000000..6afbaad
--- /dev/null
+++ b/cmd/completion/bash/bash.go
@@ -0,0 +1,20 @@
+package bash
+
+import (
+	"os"
+
+	"github.com/spf13/cobra"
+)
+
+// NewCommand returns a new cobra.Command for 'completion bash' command
+func NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Args:  cobra.NoArgs,
+		Use:   "bash",
+		Short: "Generate shell completion for bash",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return cmd.Parent().Parent().GenBashCompletion(os.Stdout)
+		},
+	}
+	return cmd
+}
diff --git a/cmd/completion/completion.go b/cmd/completion/completion.go
new file mode 100644
index 0000000..aad7744
--- /dev/null
+++ b/cmd/completion/completion.go
@@ -0,0 +1,40 @@
+package completion
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/cmd/completion/bash"
+	"github.com/segmentio/terraform-docs/cmd/completion/zsh"
+)
+
+// NewCommand returns a new cobra.Command for 'completion' command
+func NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Args:  cobra.NoArgs,
+		Use:   "completion SHELL",
+		Short: "Generate shell completion code for the specified shell (bash or zsh)",
+		Long:  longDescription,
+	}
+
+	// subcommands
+	cmd.AddCommand(bash.NewCommand())
+	cmd.AddCommand(zsh.NewCommand())
+
+	return cmd
+}
+
+const longDescription = `Outputs terraform-doc shell completion for the given shell (bash or zsh)
+This depends on the bash-completion binary.  Example installation instructions:
+# for bash users
+	$ terraform-doc completion bash > ~/.terraform-doc-completion
+	$ source ~/.terraform-doc-completion
+
+# for zsh users
+	% terraform-doc completion zsh > /usr/local/share/zsh/site-functions/_terraform-doc
+	% autoload -U compinit && compinit
+# or if zsh-completion is installed via homebrew
+    % terraform-doc completion zsh > "${fpath[1]}/_terraform-doc"
+
+Additionally, you may want to output the completion to a file and source in your .bashrc
+Note for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2
+`
diff --git a/cmd/completion/zsh/zsh.go b/cmd/completion/zsh/zsh.go
new file mode 100644
index 0000000..7d9b3f1
--- /dev/null
+++ b/cmd/completion/zsh/zsh.go
@@ -0,0 +1,20 @@
+package zsh
+
+import (
+	"os"
+
+	"github.com/spf13/cobra"
+)
+
+// NewCommand returns a new cobra.Command for 'completion zsh' command
+func NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Args:  cobra.NoArgs,
+		Use:   "zsh",
+		Short: "Generate shel completion for zsh",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return cmd.Parent().Parent().GenZshCompletion(os.Stdout)
+		},
+	}
+	return cmd
+}
diff --git a/cmd/json.go b/cmd/json.go
deleted file mode 100644
index 0af02f2..0000000
--- a/cmd/json.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var jsonCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "json [PATH]",
-	Short:       "Generate JSON of inputs and outputs",
-	Annotations: formatAnnotations("json"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	jsonCmd.PersistentFlags().BoolVar(new(bool), "no-escape", false, "do not escape special characters")
-	jsonCmd.PersistentFlags().MarkDeprecated("no-escape", "use '--escape=false' instead") //nolint:errcheck
-
-	jsonCmd.PersistentFlags().BoolVar(&settings.EscapeCharacters, "escape", true, "escape special characters")
-
-	rootCmd.AddCommand(jsonCmd)
-}
diff --git a/cmd/json/json.go b/cmd/json/json.go
new file mode 100644
index 0000000..72975a0
--- /dev/null
+++ b/cmd/json/json.go
@@ -0,0 +1,28 @@
+package json
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'json' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "json [PATH]",
+		Short:       "Generate JSON of inputs and outputs",
+		Annotations: cli.Annotations("json"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+
+	// flags
+	cmd.PersistentFlags().BoolVar(&config.Settings.Escape, "escape", true, "escape special characters")
+
+	// deprecation
+	cmd.PersistentFlags().BoolVar(new(bool), "no-escape", false, "do not escape special characters")
+	cmd.PersistentFlags().MarkDeprecated("no-escape", "use '--escape=false' instead") //nolint:errcheck
+
+	return cmd
+}
diff --git a/cmd/markdown.go b/cmd/markdown.go
deleted file mode 100644
index 7ab8230..0000000
--- a/cmd/markdown.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var markdownCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "markdown [PATH]",
-	Aliases:     []string{"md"},
-	Short:       "Generate Markdown of inputs and outputs",
-	Annotations: formatAnnotations("markdown"),
-	RunE:        formatRunE,
-}
-
-var markdownTableCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "table [PATH]",
-	Aliases:     []string{"tbl"},
-	Short:       "Generate Markdown tables of inputs and outputs",
-	Annotations: formatAnnotations("markdown table"),
-	RunE:        formatRunE,
-}
-
-var markdownDocumentCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "document [PATH]",
-	Aliases:     []string{"doc"},
-	Short:       "Generate Markdown document of inputs and outputs",
-	Annotations: formatAnnotations("markdown document"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	markdownCmd.PersistentFlags().BoolVar(new(bool), "no-required", false, "do not show \"Required\" column or section")
-	markdownCmd.PersistentFlags().BoolVar(new(bool), "no-sensitive", false, "do not show \"Sensitive\" column or section")
-	markdownCmd.PersistentFlags().BoolVar(new(bool), "no-escape", false, "do not escape special characters")
-	markdownCmd.PersistentFlags().MarkDeprecated("no-required", "use '--required=false' instead")   //nolint:errcheck
-	markdownCmd.PersistentFlags().MarkDeprecated("no-sensitive", "use '--sensitive=false' instead") //nolint:errcheck
-	markdownCmd.PersistentFlags().MarkDeprecated("no-escape", "use '--escape=false' instead")       //nolint:errcheck
-
-	markdownCmd.PersistentFlags().BoolVar(&settings.ShowRequired, "required", true, "show \"Required\" column or section")
-	markdownCmd.PersistentFlags().BoolVar(&settings.ShowSensitivity, "sensitive", true, "show \"Sensitive\" column or section")
-	markdownCmd.PersistentFlags().BoolVar(&settings.EscapeCharacters, "escape", true, "escape special characters")
-	markdownCmd.PersistentFlags().IntVar(&settings.IndentLevel, "indent", 2, "indention level of Markdown sections [1, 2, 3, 4, 5]")
-
-	markdownCmd.AddCommand(markdownTableCmd)
-	markdownCmd.AddCommand(markdownDocumentCmd)
-
-	rootCmd.AddCommand(markdownCmd)
-}
diff --git a/cmd/markdown/document/document.go b/cmd/markdown/document/document.go
new file mode 100644
index 0000000..dbfc6eb
--- /dev/null
+++ b/cmd/markdown/document/document.go
@@ -0,0 +1,21 @@
+package document
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'markdown document' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "document [PATH]",
+		Aliases:     []string{"doc"},
+		Short:       "Generate Markdown document of inputs and outputs",
+		Annotations: cli.Annotations("markdown document"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/markdown/markdown.go b/cmd/markdown/markdown.go
new file mode 100644
index 0000000..7d95d47
--- /dev/null
+++ b/cmd/markdown/markdown.go
@@ -0,0 +1,42 @@
+package markdown
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/cmd/markdown/document"
+	"github.com/segmentio/terraform-docs/cmd/markdown/table"
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'markdown' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "markdown [PATH]",
+		Aliases:     []string{"md"},
+		Short:       "Generate Markdown of inputs and outputs",
+		Annotations: cli.Annotations("markdown"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+
+	// flags
+	cmd.PersistentFlags().BoolVar(&config.Settings.Required, "required", true, "show \"Required\" column or section")
+	cmd.PersistentFlags().BoolVar(&config.Settings.Sensitive, "sensitive", true, "show \"Sensitive\" column or section")
+	cmd.PersistentFlags().BoolVar(&config.Settings.Escape, "escape", true, "escape special characters")
+	cmd.PersistentFlags().IntVar(&config.Settings.Indent, "indent", 2, "indention level of Markdown sections [1, 2, 3, 4, 5]")
+
+	// deprecation
+	cmd.PersistentFlags().BoolVar(new(bool), "no-required", false, "do not show \"Required\" column or section")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-sensitive", false, "do not show \"Sensitive\" column or section")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-escape", false, "do not escape special characters")
+	cmd.PersistentFlags().MarkDeprecated("no-required", "use '--required=false' instead")   //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-sensitive", "use '--sensitive=false' instead") //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-escape", "use '--escape=false' instead")       //nolint:errcheck
+
+	// subcommands
+	cmd.AddCommand(document.NewCommand(config))
+	cmd.AddCommand(table.NewCommand(config))
+
+	return cmd
+}
diff --git a/cmd/markdown/table/table.go b/cmd/markdown/table/table.go
new file mode 100644
index 0000000..ce383a5
--- /dev/null
+++ b/cmd/markdown/table/table.go
@@ -0,0 +1,21 @@
+package table
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'markdown table' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "table [PATH]",
+		Aliases:     []string{"tbl"},
+		Short:       "Generate Markdown tables of inputs and outputs",
+		Annotations: cli.Annotations("markdown table"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/pretty.go b/cmd/pretty.go
deleted file mode 100644
index d7efd04..0000000
--- a/cmd/pretty.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var prettyCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "pretty [PATH]",
-	Short:       "Generate colorized pretty of inputs and outputs",
-	Annotations: formatAnnotations("pretty"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	prettyCmd.PersistentFlags().BoolVar(new(bool), "no-color", false, "do not colorize printed result")
-	prettyCmd.PersistentFlags().MarkDeprecated("no-color", "use '--color=false' instead") //nolint:errcheck
-
-	prettyCmd.PersistentFlags().BoolVar(&settings.ShowColor, "color", true, "colorize printed result")
-
-	rootCmd.AddCommand(prettyCmd)
-}
diff --git a/cmd/pretty/pretty.go b/cmd/pretty/pretty.go
new file mode 100644
index 0000000..748111b
--- /dev/null
+++ b/cmd/pretty/pretty.go
@@ -0,0 +1,28 @@
+package pretty
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for pretty formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "pretty [PATH]",
+		Short:       "Generate colorized pretty of inputs and outputs",
+		Annotations: cli.Annotations("pretty"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+
+	// flags
+	cmd.PersistentFlags().BoolVar(&config.Settings.Color, "color", true, "colorize printed result")
+
+	// deprecation
+	cmd.PersistentFlags().BoolVar(new(bool), "no-color", false, "do not colorize printed result")
+	cmd.PersistentFlags().MarkDeprecated("no-color", "use '--color=false' instead") //nolint:errcheck
+
+	return cmd
+}
diff --git a/cmd/root.go b/cmd/root.go
index a14d77a..1289a3f 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -2,180 +2,85 @@ package cmd
 
 import (
 	"fmt"
-	"strings"
 
 	"github.com/spf13/cobra"
 
-	"github.com/segmentio/terraform-docs/internal/format"
-	"github.com/segmentio/terraform-docs/internal/module"
-	"github.com/segmentio/terraform-docs/internal/version"
-	"github.com/segmentio/terraform-docs/pkg/print"
+	"github.com/segmentio/terraform-docs/cmd/asciidoc"
+	"github.com/segmentio/terraform-docs/cmd/completion"
+	"github.com/segmentio/terraform-docs/cmd/json"
+	"github.com/segmentio/terraform-docs/cmd/markdown"
+	"github.com/segmentio/terraform-docs/cmd/pretty"
+	"github.com/segmentio/terraform-docs/cmd/tfvars"
+	"github.com/segmentio/terraform-docs/cmd/toml"
+	"github.com/segmentio/terraform-docs/cmd/version"
+	"github.com/segmentio/terraform-docs/cmd/xml"
+	"github.com/segmentio/terraform-docs/cmd/yaml"
+	"github.com/segmentio/terraform-docs/internal/cli"
 )
 
-var hides []string
-var settings = print.NewSettings()
-var options = module.NewOptions()
-
-var rootCmd = &cobra.Command{
-	Args:          cobra.NoArgs,
-	Use:           "terraform-docs",
-	Short:         "A utility to generate documentation from Terraform modules in various output formats",
-	Long:          "A utility to generate documentation from Terraform modules in various output formats",
-	Version:       version.Version(),
-	SilenceUsage:  true,
-	SilenceErrors: true,
-	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
-		oppositeBool := func(name string) bool {
-			val, _ := cmd.Flags().GetBool(name)
-			return !val
-		}
-
-		for _, h := range hides {
-			switch h {
-			case "header":
-			case "inputs":
-			case "outputs":
-			case "providers":
-			case "requirements":
-			default:
-				return fmt.Errorf("'%s' is not a valid section to hide, available options [header, inputs, outputs, providers, requirements]", h)
-			}
-		}
-
-		if len(hides) > 0 && contains("header") {
-			settings.ShowHeader = false
-		} else {
-			settings.ShowHeader = oppositeBool("no-header")
-		}
-		options.ShowHeader = settings.ShowHeader
-
-		if len(hides) > 0 && contains("inputs") {
-			settings.ShowInputs = false
-		} else {
-			settings.ShowInputs = oppositeBool("no-inputs")
-		}
-		if len(hides) > 0 && contains("outputs") {
-			settings.ShowOutputs = false
-		} else {
-			settings.ShowOutputs = oppositeBool("no-outputs")
-		}
-		if len(hides) > 0 && contains("providers") {
-			settings.ShowProviders = false
-		} else {
-			settings.ShowProviders = oppositeBool("no-providers")
-		}
-		if len(hides) > 0 && contains("requirements") {
-			settings.ShowRequirements = false
-		} else {
-			settings.ShowRequirements = oppositeBool("no-requirements")
-		}
-
-		settings.OutputValues = options.OutputValues
-
-		if !cmd.Flags().Changed("color") {
-			settings.ShowColor = oppositeBool("no-color")
-		}
-		if !cmd.Flags().Changed("sort") {
-			settings.SortByName = oppositeBool("no-sort")
-		}
-		if !cmd.Flags().Changed("required") {
-			settings.ShowRequired = oppositeBool("no-required")
-		}
-		if !cmd.Flags().Changed("escape") {
-			settings.EscapeCharacters = oppositeBool("no-escape")
-		}
-		if !cmd.Flags().Changed("sensitive") {
-			settings.ShowSensitivity = oppositeBool("no-sensitive")
-		}
-
-		return nil
-	},
-}
-
-func init() {
-	rootCmd.PersistentFlags().StringSliceVar(&hides, "hide", []string{}, "hide section [header, inputs, outputs, providers, requirements]")
-
-	rootCmd.PersistentFlags().BoolVar(new(bool), "no-header", false, "do not show module header")
-	rootCmd.PersistentFlags().BoolVar(new(bool), "no-inputs", false, "do not show inputs")
-	rootCmd.PersistentFlags().BoolVar(new(bool), "no-outputs", false, "do not show outputs")
-	rootCmd.PersistentFlags().BoolVar(new(bool), "no-providers", false, "do not show providers")
-	rootCmd.PersistentFlags().BoolVar(new(bool), "no-requirements", false, "do not show module requirements")
-
-	rootCmd.PersistentFlags().BoolVar(new(bool), "no-sort", false, "do no sort items")
-	rootCmd.PersistentFlags().BoolVar(&settings.SortByName, "sort", true, "sort items")
-	rootCmd.PersistentFlags().BoolVar(&settings.SortByRequired, "sort-by-required", false, "sort items by name and print required ones first (default false)")
-	rootCmd.PersistentFlags().BoolVar(&settings.SortByType, "sort-by-type", false, "sort items by type of them (default false)")
-
-	rootCmd.PersistentFlags().StringVar(&options.HeaderFromFile, "header-from", "main.tf", "relative path of a file to read header from")
-
-	rootCmd.PersistentFlags().BoolVar(&options.OutputValues, "output-values", false, "inject output values into outputs (default false)")
-	rootCmd.PersistentFlags().StringVar(&options.OutputValuesPath, "output-values-from", "", "inject output values from file into outputs")
-
-	rootCmd.PersistentFlags().MarkDeprecated("no-header", "use '--hide header' instead")             //nolint:errcheck
-	rootCmd.PersistentFlags().MarkDeprecated("no-inputs", "use '--hide inputs' instead")             //nolint:errcheck
-	rootCmd.PersistentFlags().MarkDeprecated("no-outputs", "use '--hide outputs' instead")           //nolint:errcheck
-	rootCmd.PersistentFlags().MarkDeprecated("no-providers", "use '--hide providers' instead")       //nolint:errcheck
-	rootCmd.PersistentFlags().MarkDeprecated("no-requirements", "use '--hide requirements' instead") //nolint:errcheck
-	rootCmd.PersistentFlags().MarkDeprecated("no-sort", "use '--sort=false' instead")                //nolint:errcheck
-}
-
 // Execute adds all child commands to the root command and sets flags appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() error {
-	if err := rootCmd.Execute(); err != nil {
+	if err := NewCommand().Execute(); err != nil {
 		fmt.Printf("Error: %s\n", err.Error())
-	}
-	return nil
-}
-
-// RootCmd represents the base command when called without any subcommands
-func RootCmd() *cobra.Command {
-	return rootCmd
-}
-
-func contains(section string) bool {
-	for _, h := range hides {
-		if h == section {
-			return true
-		}
-	}
-	return false
-}
-
-var formatRunE = func(cmd *cobra.Command, args []string) error {
-	name := strings.Replace(cmd.CommandPath(), "terraform-docs ", "", -1)
-	printer, err := format.Factory(name, settings)
-	if err != nil {
-		return err
-	}
-	_, err = options.With(&module.Options{
-		Path: args[0],
-		SortBy: &module.SortBy{
-			Name:     settings.SortByName,
-			Required: settings.SortByRequired,
-			Type:     settings.SortByType,
-		},
-	})
-	if err != nil {
-		return err
-	}
-	tfmodule, err := module.LoadWithOptions(options)
-	if err != nil {
-		return err
-	}
-	output, err := printer.Print(tfmodule, settings)
-	if err != nil {
 		return err
 	}
-	fmt.Println(output)
 	return nil
 }
 
-var formatAnnotations = func(cmd string) map[string]string {
-	annotations := make(map[string]string)
-	for _, s := range strings.Split(cmd, " ") {
-		annotations["command"] = s
+// NewCommand returns a new cobra.Command for 'root' command
+func NewCommand() *cobra.Command {
+	config := cli.DefaultConfig()
+	cmd := &cobra.Command{
+		Args:          cobra.NoArgs,
+		Use:           "terraform-docs",
+		Short:         "A utility to generate documentation from Terraform modules in various output formats",
+		Long:          "A utility to generate documentation from Terraform modules in various output formats",
+		Version:       version.Full(),
+		SilenceUsage:  true,
+		SilenceErrors: true,
 	}
-	annotations["kind"] = "formatter"
-	return annotations
+
+	// flags
+	cmd.PersistentFlags().StringSliceVar(&config.Sections.Hide, "hide", []string{}, "hide section [header, inputs, outputs, providers, requirements]")
+
+	cmd.PersistentFlags().BoolVar(&config.Sort.Enabled, "sort", true, "sort items")
+	cmd.PersistentFlags().BoolVar(&config.Sort.By.Required, "sort-by-required", false, "sort items by name and print required ones first (default false)")
+	cmd.PersistentFlags().BoolVar(&config.Sort.By.Type, "sort-by-type", false, "sort items by type of them (default false)")
+
+	cmd.PersistentFlags().StringVar(&config.HeaderFrom, "header-from", "main.tf", "relative path of a file to read header from")
+
+	cmd.PersistentFlags().BoolVar(&config.OutputValues.Enabled, "output-values", false, "inject output values into outputs (default false)")
+	cmd.PersistentFlags().StringVar(&config.OutputValues.From, "output-values-from", "", "inject output values from file into outputs (default \"\")")
+
+	// deprecation
+	cmd.PersistentFlags().BoolVar(new(bool), "no-header", false, "do not show module header")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-inputs", false, "do not show inputs")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-outputs", false, "do not show outputs")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-providers", false, "do not show providers")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-requirements", false, "do not show module requirements")
+	cmd.PersistentFlags().BoolVar(new(bool), "no-sort", false, "do no sort items")
+
+	cmd.PersistentFlags().MarkDeprecated("no-header", "use '--hide header' instead")             //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-inputs", "use '--hide inputs' instead")             //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-outputs", "use '--hide outputs' instead")           //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-providers", "use '--hide providers' instead")       //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-requirements", "use '--hide requirements' instead") //nolint:errcheck
+	cmd.PersistentFlags().MarkDeprecated("no-sort", "use '--sort=false' instead")                //nolint:errcheck
+
+	// formatter subcommands
+	cmd.AddCommand(asciidoc.NewCommand(config))
+	cmd.AddCommand(json.NewCommand(config))
+	cmd.AddCommand(markdown.NewCommand(config))
+	cmd.AddCommand(pretty.NewCommand(config))
+	cmd.AddCommand(tfvars.NewCommand(config))
+	cmd.AddCommand(toml.NewCommand(config))
+	cmd.AddCommand(xml.NewCommand(config))
+	cmd.AddCommand(yaml.NewCommand(config))
+
+	// other subcommands
+	cmd.AddCommand(completion.NewCommand())
+	cmd.AddCommand(version.NewCommand())
+
+	return cmd
 }
diff --git a/cmd/tfvars.go b/cmd/tfvars.go
deleted file mode 100644
index c988e6b..0000000
--- a/cmd/tfvars.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var tfvarsCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "tfvars [PATH]",
-	Short:       "Generate terraform.tfvars of inputs",
-	Annotations: formatAnnotations("tfvars"),
-}
-
-var tfvarsHCLCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "hcl [PATH]",
-	Short:       "Generate HCL format of terraform.tfvars of inputs",
-	Annotations: formatAnnotations("tfvars hcl"),
-	RunE:        formatRunE,
-}
-
-var tfvarsJSONCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "json [PATH]",
-	Short:       "Generate JSON format of terraform.tfvars of inputs",
-	Annotations: formatAnnotations("tfvars json"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	tfvarsCmd.AddCommand(tfvarsHCLCmd)
-	tfvarsCmd.AddCommand(tfvarsJSONCmd)
-
-	rootCmd.AddCommand(tfvarsCmd)
-}
diff --git a/cmd/tfvars/hcl/hcl.go b/cmd/tfvars/hcl/hcl.go
new file mode 100644
index 0000000..f67c9bf
--- /dev/null
+++ b/cmd/tfvars/hcl/hcl.go
@@ -0,0 +1,20 @@
+package hcl
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'tfvars hcl' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "hcl [PATH]",
+		Short:       "Generate HCL format of terraform.tfvars of inputs",
+		Annotations: cli.Annotations("tfvars hcl"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/tfvars/json/json.go b/cmd/tfvars/json/json.go
new file mode 100644
index 0000000..ce0caa4
--- /dev/null
+++ b/cmd/tfvars/json/json.go
@@ -0,0 +1,20 @@
+package json
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'tfvars json' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "json [PATH]",
+		Short:       "Generate JSON format of terraform.tfvars of inputs",
+		Annotations: cli.Annotations("tfvars json"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/tfvars/tfvars.go b/cmd/tfvars/tfvars.go
new file mode 100644
index 0000000..f878458
--- /dev/null
+++ b/cmd/tfvars/tfvars.go
@@ -0,0 +1,25 @@
+package tfvars
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/cmd/tfvars/hcl"
+	"github.com/segmentio/terraform-docs/cmd/tfvars/json"
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'tfvars' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "tfvars [PATH]",
+		Short:       "Generate terraform.tfvars of inputs",
+		Annotations: cli.Annotations("tfvars"),
+	}
+
+	// subcommands
+	cmd.AddCommand(hcl.NewCommand(config))
+	cmd.AddCommand(json.NewCommand(config))
+
+	return cmd
+}
diff --git a/cmd/toml.go b/cmd/toml.go
deleted file mode 100644
index ffda6c0..0000000
--- a/cmd/toml.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var tomlCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "toml [PATH]",
-	Short:       "Generate TOML of inputs and outputs",
-	Annotations: formatAnnotations("toml"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	rootCmd.AddCommand(tomlCmd)
-}
diff --git a/cmd/toml/toml.go b/cmd/toml/toml.go
new file mode 100644
index 0000000..bef6d73
--- /dev/null
+++ b/cmd/toml/toml.go
@@ -0,0 +1,20 @@
+package toml
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'toml' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "toml [PATH]",
+		Short:       "Generate TOML of inputs and outputs",
+		Annotations: cli.Annotations("toml"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/version.go b/cmd/version.go
deleted file mode 100644
index a2795cd..0000000
--- a/cmd/version.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package cmd
-
-import (
-	"fmt"
-
-	"github.com/spf13/cobra"
-
-	"github.com/segmentio/terraform-docs/internal/version"
-)
-
-var versionCmd = &cobra.Command{
-	Args:  cobra.NoArgs,
-	Use:   "version",
-	Short: "Print the version number of terraform-docs",
-	Run: func(cmd *cobra.Command, args []string) {
-		fmt.Print(fmt.Sprintf("terraform-docs version %s\n", version.Version()))
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(versionCmd)
-}
diff --git a/cmd/version/version.go b/cmd/version/version.go
new file mode 100644
index 0000000..806df79
--- /dev/null
+++ b/cmd/version/version.go
@@ -0,0 +1,27 @@
+package version
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/version"
+)
+
+// NewCommand returns a new cobra.Command for 'version' command
+func NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Args:  cobra.NoArgs,
+		Use:   "version",
+		Short: "Print the version number of terraform-docs",
+		Run: func(cmd *cobra.Command, args []string) {
+			fmt.Printf("terraform-docs version %s\n", Full())
+		},
+	}
+	return cmd
+}
+
+// Full returns the full version of the binary
+func Full() string {
+	return version.Full()
+}
diff --git a/cmd/xml.go b/cmd/xml.go
deleted file mode 100644
index 38f4937..0000000
--- a/cmd/xml.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var xmlCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "xml [PATH]",
-	Short:       "Generate XML of inputs and outputs",
-	Annotations: formatAnnotations("xml"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	rootCmd.AddCommand(xmlCmd)
-}
diff --git a/cmd/xml/xml.go b/cmd/xml/xml.go
new file mode 100644
index 0000000..58a4db1
--- /dev/null
+++ b/cmd/xml/xml.go
@@ -0,0 +1,20 @@
+package xml
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'xml' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "xml [PATH]",
+		Short:       "Generate XML of inputs and outputs",
+		Annotations: cli.Annotations("xml"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/cmd/yaml.go b/cmd/yaml.go
deleted file mode 100644
index 1433132..0000000
--- a/cmd/yaml.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-)
-
-var yamlCmd = &cobra.Command{
-	Args:        cobra.ExactArgs(1),
-	Use:         "yaml [PATH]",
-	Short:       "Generate YAML of inputs and outputs",
-	Annotations: formatAnnotations("yaml"),
-	RunE:        formatRunE,
-}
-
-func init() {
-	rootCmd.AddCommand(yamlCmd)
-}
diff --git a/cmd/yaml/yaml.go b/cmd/yaml/yaml.go
new file mode 100644
index 0000000..5f80c27
--- /dev/null
+++ b/cmd/yaml/yaml.go
@@ -0,0 +1,20 @@
+package yaml
+
+import (
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/cli"
+)
+
+// NewCommand returns a new cobra.Command for 'yaml' formatter
+func NewCommand(config *cli.Config) *cobra.Command {
+	cmd := &cobra.Command{
+		Args:        cobra.ExactArgs(1),
+		Use:         "yaml [PATH]",
+		Short:       "Generate YAML of inputs and outputs",
+		Annotations: cli.Annotations("yaml"),
+		PreRunE:     cli.PreRunEFunc(config),
+		RunE:        cli.RunEFunc(config),
+	}
+	return cmd
+}
diff --git a/docs/FORMATS_GUIDE.md b/docs/FORMATS_GUIDE.md
index b13d2d5..2679f2d 100644
--- a/docs/FORMATS_GUIDE.md
+++ b/docs/FORMATS_GUIDE.md
@@ -13,7 +13,7 @@ A utility to generate documentation from Terraform modules in various output for
   -h, --help                        help for terraform-docs
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -36,4 +36,4 @@ A utility to generate documentation from Terraform modules in various output for
 * [terraform-docs xml](/docs/formats/xml.md)	 - Generate XML of inputs and outputs
 * [terraform-docs yaml](/docs/formats/yaml.md)	 - Generate YAML of inputs and outputs
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/asciidoc-document.md b/docs/formats/asciidoc-document.md
index 8e4e1f8..30f8cbb 100644
--- a/docs/formats/asciidoc-document.md
+++ b/docs/formats/asciidoc-document.md
@@ -23,7 +23,7 @@ terraform-docs asciidoc document [PATH] [flags]
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --indent int                  indention level of AsciiDoc sections [1, 2, 3, 4, 5] (default 2)
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --required                    show "Required" column or section (default true)
       --sensitive                   show "Sensitive" column or section (default true)
       --sort                        sort items (default true)
@@ -416,4 +416,4 @@ generates the following output:
 
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/asciidoc-table.md b/docs/formats/asciidoc-table.md
index 1a5f661..2fba3cd 100644
--- a/docs/formats/asciidoc-table.md
+++ b/docs/formats/asciidoc-table.md
@@ -23,7 +23,7 @@ terraform-docs asciidoc table [PATH] [flags]
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --indent int                  indention level of AsciiDoc sections [1, 2, 3, 4, 5] (default 2)
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --required                    show "Required" column or section (default true)
       --sensitive                   show "Sensitive" column or section (default true)
       --sort                        sort items (default true)
@@ -372,4 +372,4 @@ generates the following output:
 
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/asciidoc.md b/docs/formats/asciidoc.md
index 6ba7f7b..88491de 100644
--- a/docs/formats/asciidoc.md
+++ b/docs/formats/asciidoc.md
@@ -25,7 +25,7 @@ terraform-docs asciidoc [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -36,4 +36,4 @@ terraform-docs asciidoc [PATH] [flags]
 * [terraform-docs asciidoc document](/docs/formats/asciidoc-document.md)	 - Generate AsciiDoc document of inputs and outputs
 * [terraform-docs asciidoc table](/docs/formats/asciidoc-table.md)	 - Generate AsciiDoc tables of inputs and outputs
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/json.md b/docs/formats/json.md
index 01b44a7..b6da476 100644
--- a/docs/formats/json.md
+++ b/docs/formats/json.md
@@ -23,7 +23,7 @@ terraform-docs json [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -335,4 +335,4 @@ generates the following output:
     }
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/markdown-document.md b/docs/formats/markdown-document.md
index e242087..e46b2be 100644
--- a/docs/formats/markdown-document.md
+++ b/docs/formats/markdown-document.md
@@ -24,7 +24,7 @@ terraform-docs markdown document [PATH] [flags]
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --indent int                  indention level of Markdown sections [1, 2, 3, 4, 5] (default 2)
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --required                    show "Required" column or section (default true)
       --sensitive                   show "Sensitive" column or section (default true)
       --sort                        sort items (default true)
@@ -417,4 +417,4 @@ generates the following output:
 
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/markdown-table.md b/docs/formats/markdown-table.md
index 6ec0d1b..1756e9d 100644
--- a/docs/formats/markdown-table.md
+++ b/docs/formats/markdown-table.md
@@ -24,7 +24,7 @@ terraform-docs markdown table [PATH] [flags]
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --indent int                  indention level of Markdown sections [1, 2, 3, 4, 5] (default 2)
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --required                    show "Required" column or section (default true)
       --sensitive                   show "Sensitive" column or section (default true)
       --sort                        sort items (default true)
@@ -143,4 +143,4 @@ generates the following output:
 
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/markdown.md b/docs/formats/markdown.md
index 2d5e909..545ba95 100644
--- a/docs/formats/markdown.md
+++ b/docs/formats/markdown.md
@@ -26,7 +26,7 @@ terraform-docs markdown [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -37,4 +37,4 @@ terraform-docs markdown [PATH] [flags]
 * [terraform-docs markdown document](/docs/formats/markdown-document.md)	 - Generate Markdown document of inputs and outputs
 * [terraform-docs markdown table](/docs/formats/markdown-table.md)	 - Generate Markdown tables of inputs and outputs
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/pretty.md b/docs/formats/pretty.md
index 05477c3..53ec56e 100644
--- a/docs/formats/pretty.md
+++ b/docs/formats/pretty.md
@@ -23,7 +23,7 @@ terraform-docs pretty [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -239,4 +239,4 @@ generates the following output:
 
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/tfvars-hcl.md b/docs/formats/tfvars-hcl.md
index ce54fa1..e5c254e 100644
--- a/docs/formats/tfvars-hcl.md
+++ b/docs/formats/tfvars-hcl.md
@@ -22,7 +22,7 @@ terraform-docs tfvars hcl [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -95,4 +95,4 @@ generates the following output:
     with-url                = ""
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/tfvars-json.md b/docs/formats/tfvars-json.md
index bf586c1..3ea12a4 100644
--- a/docs/formats/tfvars-json.md
+++ b/docs/formats/tfvars-json.md
@@ -22,7 +22,7 @@ terraform-docs tfvars json [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -97,4 +97,4 @@ generates the following output:
     }
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/tfvars.md b/docs/formats/tfvars.md
index 8e0650c..19af717 100644
--- a/docs/formats/tfvars.md
+++ b/docs/formats/tfvars.md
@@ -18,7 +18,7 @@ Generate terraform.tfvars of inputs
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -29,4 +29,4 @@ Generate terraform.tfvars of inputs
 * [terraform-docs tfvars hcl](/docs/formats/tfvars-hcl.md)	 - Generate HCL format of terraform.tfvars of inputs
 * [terraform-docs tfvars json](/docs/formats/tfvars-json.md)	 - Generate JSON format of terraform.tfvars of inputs
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/toml.md b/docs/formats/toml.md
index f549eec..b63e639 100644
--- a/docs/formats/toml.md
+++ b/docs/formats/toml.md
@@ -22,7 +22,7 @@ terraform-docs toml [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -312,4 +312,4 @@ generates the following output:
 
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/xml.md b/docs/formats/xml.md
index 2f4e618..0a9fa50 100644
--- a/docs/formats/xml.md
+++ b/docs/formats/xml.md
@@ -22,7 +22,7 @@ terraform-docs xml [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -334,4 +334,4 @@ generates the following output:
     </module>
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/docs/formats/yaml.md b/docs/formats/yaml.md
index d59dd3f..5120443 100644
--- a/docs/formats/yaml.md
+++ b/docs/formats/yaml.md
@@ -22,7 +22,7 @@ terraform-docs yaml [PATH] [flags]
       --header-from string          relative path of a file to read header from (default "main.tf")
       --hide strings                hide section [header, inputs, outputs, providers, requirements]
       --output-values               inject output values into outputs (default false)
-      --output-values-from string   inject output values from file into outputs
+      --output-values-from string   inject output values from file into outputs (default "")
       --sort                        sort items (default true)
       --sort-by-required            sort items by name and print required ones first (default false)
       --sort-by-type                sort items by type of them (default false)
@@ -286,4 +286,4 @@ generates the following output:
         version: '>= 2.2.0'
 
 
-###### Auto generated by spf13/cobra on 19-May-2020
+###### Auto generated by spf13/cobra on 20-May-2020
diff --git a/go.mod b/go.mod
index a42af30..b1b964e 100644
--- a/go.mod
+++ b/go.mod
@@ -10,6 +10,7 @@ require (
 	github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0
 	github.com/imdario/mergo v0.3.9
 	github.com/spf13/cobra v1.0.0
+	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.5.1
 	github.com/zclconf/go-cty v1.4.1
 	gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86
diff --git a/go.sum b/go.sum
index d98bfac..5a9232e 100644
--- a/go.sum
+++ b/go.sum
@@ -114,6 +114,8 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
 github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -128,8 +130,6 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
-github.com/zclconf/go-cty v1.4.0 h1:+q+tmgyUB94HIdH/uVTIi/+kt3pt4sHwEZAcTyLoGsQ=
-github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
 github.com/zclconf/go-cty v1.4.1 h1:Xzr4m4utRDhHDifag1onwwUSq32HLoLBsp+w6tD0880=
 github.com/zclconf/go-cty v1.4.1/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
diff --git a/internal/cli/annotations.go b/internal/cli/annotations.go
new file mode 100644
index 0000000..b0ad073
--- /dev/null
+++ b/internal/cli/annotations.go
@@ -0,0 +1,16 @@
+package cli
+
+import (
+	"strings"
+)
+
+// Annotations returns set of annotations for cobra.Commands,
+// specifically the 'command' namd and command 'kind'
+func Annotations(cmd string) map[string]string {
+	annotations := make(map[string]string)
+	for _, s := range strings.Split(cmd, " ") {
+		annotations["command"] = s
+	}
+	annotations["kind"] = "formatter"
+	return annotations
+}
diff --git a/internal/cli/config.go b/internal/cli/config.go
new file mode 100644
index 0000000..3642fd8
--- /dev/null
+++ b/internal/cli/config.go
@@ -0,0 +1,235 @@
+package cli
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/spf13/pflag"
+
+	"github.com/segmentio/terraform-docs/internal/module"
+	"github.com/segmentio/terraform-docs/pkg/print"
+)
+
+type sections struct {
+	Hide []string
+
+	header       bool
+	inputs       bool
+	outputs      bool
+	providers    bool
+	requirements bool
+}
+
+func (s *sections) contains(section string) bool {
+	for _, item := range s.Hide {
+		if item == section {
+			return true
+		}
+	}
+	return false
+}
+
+func (s *sections) validate(fs *pflag.FlagSet) error {
+	sections := []string{"header", "inputs", "outputs", "providers", "requirements"}
+	for _, h := range s.Hide {
+		switch h {
+		case sections[0], sections[1], sections[2], sections[3], sections[4]:
+		default:
+			return fmt.Errorf("'%s' is not a valid section", h)
+		}
+	}
+	for _, section := range sections {
+		if fs.Changed("no-"+section) && s.contains(section) {
+			return fmt.Errorf("'--no-%s' and '--hide %s' cannot be used together", section, section)
+		}
+	}
+	return nil
+}
+
+type outputvalues struct {
+	Enabled bool
+	From    string
+}
+
+func (o *outputvalues) validate() error {
+	if o.Enabled && o.From == "" {
+		return fmt.Errorf("value of '--output-values-from' cannot be empty")
+	}
+	return nil
+}
+
+type sortby struct {
+	Required bool
+	Type     bool
+}
+type sort struct {
+	Enabled bool
+	By      *sortby
+}
+
+func (s *sort) validate(fs *pflag.FlagSet) error {
+	items := []string{"sort"}
+	for _, item := range items {
+		if fs.Changed("no-"+item) && fs.Changed(item) {
+			return fmt.Errorf("'--no-%s' and '--%s' cannot be used together", item, item)
+		}
+	}
+	if fs.Changed("sort-by-required") && fs.Changed("sort-by-type") {
+		return fmt.Errorf("'--sort-by-required' and '--sort-by-type' cannot be used together")
+	}
+	return nil
+}
+
+type settings struct {
+	Color     bool
+	Escape    bool
+	Indent    int
+	Required  bool
+	Sensitive bool
+}
+
+func (s *settings) validate(fs *pflag.FlagSet) error {
+	items := []string{"escape", "color", "required", "sensitive"}
+	for _, item := range items {
+		if fs.Changed("no-"+item) && fs.Changed(item) {
+			return fmt.Errorf("'--no-%s' and '--%s' cannot be used together", item, item)
+		}
+	}
+	return nil
+}
+
+// Config represents all the available config options that can be accessed and passed through CLI
+type Config struct {
+	Formatter    string
+	HeaderFrom   string
+	Sections     *sections
+	OutputValues *outputvalues
+	Sort         *sort
+	Settings     *settings
+}
+
+// DefaultConfig returns new instance of Config with default values set
+func DefaultConfig() *Config {
+	return &Config{
+		Formatter:  "",
+		HeaderFrom: "main.tf",
+		Sections: &sections{
+			Hide: []string{},
+
+			header:       true,
+			inputs:       true,
+			outputs:      true,
+			providers:    true,
+			requirements: true,
+		},
+		OutputValues: &outputvalues{
+			Enabled: false,
+			From:    "",
+		},
+		Sort: &sort{
+			Enabled: true,
+			By: &sortby{
+				Required: false,
+				Type:     false,
+			},
+		},
+		Settings: &settings{
+			Color:     true,
+			Escape:    true,
+			Indent:    2,
+			Required:  false,
+			Sensitive: false,
+		},
+	}
+}
+
+// extract and build print.Settings and module.Options out of Config
+func (c *Config) extract() (*print.Settings, *module.Options, error) {
+	settings := print.NewSettings()
+	options := module.NewOptions()
+
+	// header-from
+	options.HeaderFromFile = c.HeaderFrom
+
+	// sections
+	settings.ShowHeader = c.Sections.header
+	settings.ShowInputs = c.Sections.inputs
+	settings.ShowOutputs = c.Sections.outputs
+	settings.ShowProviders = c.Sections.providers
+	settings.ShowRequirements = c.Sections.requirements
+	options.ShowHeader = settings.ShowHeader
+
+	// output values
+	settings.OutputValues = c.OutputValues.Enabled
+	options.OutputValues = c.OutputValues.Enabled
+	options.OutputValuesPath = c.OutputValues.From
+
+	// sort
+	settings.SortByName = c.Sort.Enabled
+	settings.SortByRequired = c.Sort.Enabled && c.Sort.By.Required
+	settings.SortByType = c.Sort.Enabled && c.Sort.By.Type
+	options.SortBy.Name = settings.SortByName
+	options.SortBy.Required = settings.SortByRequired
+	options.SortBy.Type = settings.SortByType
+
+	// settings
+	settings.EscapeCharacters = c.Settings.Escape
+	settings.IndentLevel = c.Settings.Indent
+	settings.ShowColor = c.Settings.Color
+	settings.ShowRequired = c.Settings.Required
+	settings.ShowSensitivity = c.Settings.Sensitive
+
+	return settings, options, nil
+}
+
+// normalize provided Config and check for any misuse or misconfiguration
+func normalize(command string, fs *pflag.FlagSet, config *Config) error {
+	config.Formatter = strings.Replace(command, "terraform-docs ", "", -1)
+
+	// header-from
+	if fs.Changed("header-from") && config.HeaderFrom == "" {
+		return fmt.Errorf("value of '--header-from' cannot be empty")
+	}
+
+	// sections
+	if err := config.Sections.validate(fs); err != nil {
+		return err
+	}
+	config.Sections.header = !(config.Sections.contains("header") || fs.Changed("no-header"))
+	config.Sections.inputs = !(config.Sections.contains("inputs") || fs.Changed("no-inputs"))
+	config.Sections.outputs = !(config.Sections.contains("outputs") || fs.Changed("no-outputs"))
+	config.Sections.providers = !(config.Sections.contains("providers") || fs.Changed("no-providers"))
+	config.Sections.requirements = !(config.Sections.contains("requirements") || fs.Changed("no-requirements"))
+
+	// output values
+	if err := config.OutputValues.validate(); err != nil {
+		return err
+	}
+
+	// sort
+	if err := config.Sort.validate(fs); err != nil {
+		return err
+	}
+	if !fs.Changed("sort") {
+		config.Sort.Enabled = !fs.Changed("no-sort")
+	}
+
+	// settings
+	if err := config.Settings.validate(fs); err != nil {
+		return err
+	}
+	if !fs.Changed("escape") {
+		config.Settings.Escape = !fs.Changed("no-escape")
+	}
+	if !fs.Changed("color") {
+		config.Settings.Color = !fs.Changed("no-color")
+	}
+	if !fs.Changed("required") {
+		config.Settings.Required = !fs.Changed("no-required")
+	}
+	if !fs.Changed("sensitive") {
+		config.Settings.Sensitive = !fs.Changed("no-sensitive")
+	}
+
+	return nil
+}
diff --git a/internal/cli/run.go b/internal/cli/run.go
new file mode 100644
index 0000000..8e47834
--- /dev/null
+++ b/internal/cli/run.go
@@ -0,0 +1,47 @@
+package cli
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	"github.com/segmentio/terraform-docs/internal/format"
+	"github.com/segmentio/terraform-docs/internal/module"
+)
+
+// PreRunEFunc returns actual 'cobra.Command#PreRunE' function
+// for 'formatter' commands. This functions reads and normalizes
+// flags and arguments passed through CLI execution.
+func PreRunEFunc(config *Config) func(*cobra.Command, []string) error {
+	return func(cmd *cobra.Command, args []string) error {
+		return normalize(cmd.CommandPath(), cmd.Flags(), config)
+	}
+}
+
+// RunEFunc returns actual 'cobra.Command#RunE' function for
+// 'formatter' commands. This functions extract print.Settings
+// and module.Options from generated and normalized Config and
+// initializes required print.Format instance and executes it.
+func RunEFunc(config *Config) func(*cobra.Command, []string) error {
+	return func(cmd *cobra.Command, args []string) error {
+		settings, options, err := config.extract()
+		if err != nil {
+			return err
+		}
+		printer, err := format.Factory(config.Formatter, settings)
+		if err != nil {
+			return err
+		}
+		options.Path = args[0]
+		tfmodule, err := module.LoadWithOptions(options)
+		if err != nil {
+			return err
+		}
+		output, err := printer.Print(tfmodule, settings)
+		if err != nil {
+			return err
+		}
+		fmt.Println(output)
+		return nil
+	}
+}
diff --git a/internal/format/factory.go b/internal/format/factory.go
index 1734457..b464769 100644
--- a/internal/format/factory.go
+++ b/internal/format/factory.go
@@ -12,19 +12,19 @@ import (
 // function.
 func Factory(name string, settings *print.Settings) (print.Format, error) {
 	switch name {
-	case "asciidoc":
+	case "asciidoc", "adoc":
 		return NewAsciidocTable(settings), nil
-	case "asciidoc document":
+	case "asciidoc document", "asciidoc doc", "adoc document", "adoc doc":
 		return NewAsciidocDocument(settings), nil
-	case "asciidoc table":
+	case "asciidoc table", "asciidoc tbl", "adoc table", "adoc tbl":
 		return NewAsciidocTable(settings), nil
 	case "json":
 		return NewJSON(settings), nil
-	case "markdown":
+	case "markdown", "md":
 		return NewTable(settings), nil
-	case "markdown document":
+	case "markdown document", "markdown doc", "md document", "md doc":
 		return NewDocument(settings), nil
-	case "markdown table":
+	case "markdown table", "markdown tbl", "md table", "md tbl":
 		return NewTable(settings), nil
 	case "pretty":
 		return NewPretty(settings), nil
diff --git a/internal/version/version.go b/internal/version/version.go
index a43429f..99f4b74 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -30,8 +30,8 @@ func init() {
 	}
 }
 
-// Version return the full version of the binary including commit hash and build date
-func Version() string {
+// Full return the full version of the binary including commit hash and build date
+func Full() string {
 	if !strings.HasSuffix(version, commitHash) {
 		version += " " + commitHash
 	}
diff --git a/pkg/print/settings.go b/pkg/print/settings.go
index fea6660..78daed0 100644
--- a/pkg/print/settings.go
+++ b/pkg/print/settings.go
@@ -63,7 +63,7 @@ type Settings struct {
 	SortByType bool
 }
 
-//NewSettings returns new instance of Settings
+// NewSettings returns new instance of Settings
 func NewSettings() *Settings {
 	return &Settings{
 		EscapeCharacters: true,
diff --git a/scripts/docs/generate.go b/scripts/docs/generate.go
index 54c1705..784378b 100644
--- a/scripts/docs/generate.go
+++ b/scripts/docs/generate.go
@@ -26,7 +26,7 @@ var basedir = "/docs"
 var formatdir = "/formats"
 
 func main() {
-	err := generate(cmd.RootCmd(), "", "FORMATS_GUIDE")
+	err := generate(cmd.NewCommand(), "", "FORMATS_GUIDE")
 	if err != nil {
 		log.Fatal(err)
 	}


Test patch:
diff --git a/internal/format/factory_test.go b/internal/format/factory_test.go
index cefd7c9..7d266d9 100644
--- a/internal/format/factory_test.go
+++ b/internal/format/factory_test.go
@@ -22,18 +22,60 @@ func TestFormatFactory(t *testing.T) {
 			expected: "*format.AsciidocTable",
 			wantErr:  false,
 		},
+		{
+			name:     "format factory from name",
+			format:   "adoc",
+			expected: "*format.AsciidocTable",
+			wantErr:  false,
+		},
 		{
 			name:     "format factory from name",
 			format:   "asciidoc document",
 			expected: "*format.AsciidocDocument",
 			wantErr:  false,
 		},
+		{
+			name:     "format factory from name",
+			format:   "asciidoc doc",
+			expected: "*format.AsciidocDocument",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "adoc document",
+			expected: "*format.AsciidocDocument",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "adoc doc",
+			expected: "*format.AsciidocDocument",
+			wantErr:  false,
+		},
 		{
 			name:     "format factory from name",
 			format:   "asciidoc table",
 			expected: "*format.AsciidocTable",
 			wantErr:  false,
 		},
+		{
+			name:     "format factory from name",
+			format:   "asciidoc tbl",
+			expected: "*format.AsciidocTable",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "adoc table",
+			expected: "*format.AsciidocTable",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "adoc tbl",
+			expected: "*format.AsciidocTable",
+			wantErr:  false,
+		},
 		{
 			name:     "format factory from name",
 			format:   "json",
@@ -46,18 +88,60 @@ func TestFormatFactory(t *testing.T) {
 			expected: "*format.Table",
 			wantErr:  false,
 		},
+		{
+			name:     "format factory from name",
+			format:   "md",
+			expected: "*format.Table",
+			wantErr:  false,
+		},
 		{
 			name:     "format factory from name",
 			format:   "markdown document",
 			expected: "*format.Document",
 			wantErr:  false,
 		},
+		{
+			name:     "format factory from name",
+			format:   "markdown doc",
+			expected: "*format.Document",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "md document",
+			expected: "*format.Document",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "md doc",
+			expected: "*format.Document",
+			wantErr:  false,
+		},
 		{
 			name:     "format factory from name",
 			format:   "markdown table",
 			expected: "*format.Table",
 			wantErr:  false,
 		},
+		{
+			name:     "format factory from name",
+			format:   "markdown tbl",
+			expected: "*format.Table",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "md table",
+			expected: "*format.Table",
+			wantErr:  false,
+		},
+		{
+			name:     "format factory from name",
+			format:   "md tbl",
+			expected: "*format.Table",
+			wantErr:  false,
+		},
 		{
 			name:     "format factory from name",
 			format:   "pretty",