Repository: segmentio/terraform-docs
Pull request #123 (2019-09-21 02:43:23)

Code blocks support for all formats. Single line break support
### Prerequisites
- [ ] This pull request fixes a bug.
- [x] 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

Add support for embedding markdown code blocks in the heredoc of a variable description.

For the markdown table format, the code blocks are formatted as HTML on a single line.
For the markdown document format, the code blocks are kept untouched.

Support for single-line breaks: when the line ends with 2 spaces, place
a single `<br>` for the markdown table format.
For the other format, make sure to not trim the line and keep the newline in place.

This pull request supports rendering

```
variable "input-with-code-block" {
  description = <<EOD
This is a complicated one. We need a newline.  
And an example in a code block
\```
default     = [
  "machine rack01:neptune"
]
\```
EOD
  default     = [
    "name rack:location"
  ]
}
```
Into 

```
| Name | Description | Type | Default | Required |
|------|-------------|:----:|:-----:|:-----:|
| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` | no |
```

<img width="1643" alt="Screenshot 2019-09-21 at 3 47 42 PM" src="https://user-images.githubusercontent.com/55289/65370040-3cc8d080-dc87-11e9-854f-f95f7c5fd3c1.png">


### Issues Resolved

No issues were previously filed.

### Checklist

Put an `x` into all boxes that apply:

- [x] I have read the [Contributing Guidelines](https://github.com/segmentio/terraform-docs/tree/master/CONTRIBUTING.md).

#### Tests

- [x] I have added tests to cover my changes.
- [x] All tests pass when I run `make test`.

I have done rushed job at keeping the tests suite green after adding a variable to the examples folder. That final pass of sanitization for the document format has a single merit: "it works".
I would not merge it though.

Please let me know if there is sufficient interest for this new feature and I'll put in some effort in refactoring the code.

#### Documentation

- [x] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.

#### Code Style

- [x] My code follows the code style of this project.


khos2ow: Thanks @hmalphettes for your PR. I'll review it soon.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a82ed7..5eaafa3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,12 @@
 <a name="unreleased"></a>
 ## [Unreleased]
 
+- target deps was missing (required by all) ([#126](https://github.com/segmentio/terraform-docs/issues/126))
+- Enhance Makefile and add editorconfig ([#115](https://github.com/segmentio/terraform-docs/issues/115))
+- Add support for controlling the indentation of Markdown headers ([#120](https://github.com/segmentio/terraform-docs/issues/120))
+- Refactor Settings for better performance ([#119](https://github.com/segmentio/terraform-docs/issues/119))
+- Add --no-escape flag for Markdown printer ([#117](https://github.com/segmentio/terraform-docs/issues/117))
+- Update Changelog.
 - Use Cobra CLI instead of docopt ([#116](https://github.com/segmentio/terraform-docs/issues/116))
 - Update Changelog.
 - Escape pipe character when generating Markdown ([#114](https://github.com/segmentio/terraform-docs/issues/114))
@@ -122,7 +128,7 @@
 - Merge pull request [#25](https://github.com/segmentio/terraform-docs/issues/25) from fatmcgav/support_output_description
 - Prefer leading comments over description for outputs to maintain compatability.
 - *: add --no-required option
-- doc: snakecase -> camelcase
+- snakecase -> camelcase
 - Merge pull request [#27](https://github.com/segmentio/terraform-docs/issues/27) from fatmcgav/support_printing_type
 - Add support for printing the variable 'type' in Markdown. Currently only markdown supported, but trivial to add to other outputs.
 - Add support for reading `description` tag from `output` resources. Fixes [#24](https://github.com/segmentio/terraform-docs/issues/24)
@@ -138,17 +144,17 @@
 
 - Release v0.1.0
 - Merge pull request [#21](https://github.com/segmentio/terraform-docs/issues/21) from s-urbaniak/files
-- main: add support for files
+- add support for files
 - Merge pull request [#20](https://github.com/segmentio/terraform-docs/issues/20) from nwalke/update_readme_example
 - closes [#17](https://github.com/segmentio/terraform-docs/issues/17) Updated example in README
 - Merge pull request [#19](https://github.com/segmentio/terraform-docs/issues/19) from nwalke/add_sorting
 - Closes [#18](https://github.com/segmentio/terraform-docs/issues/18) Added a very basic sort to inputs and outputs
 - Merge pull request [#16](https://github.com/segmentio/terraform-docs/issues/16) from paybyphone/master
-- doc: Account for single whitespace after comment character in header
+- Account for single whitespace after comment character in header
 - print/markdown: Better markdown description normalizations
 - print/markdown: Added line break conversion for outputs
-- doc: placeholder for list types
-- doc: Allow top-level comments for variables when description missing
+- placeholder for list types
+- Allow top-level comments for variables when description missing
 - print/markdown: Replace table cell newlines with HTML line breaks
 - Merge pull request [#13](https://github.com/segmentio/terraform-docs/issues/13) from jbussdieker/jbb-fix-heredoc-description
 - Trim whitespace on markdown description too
@@ -160,9 +166,9 @@
 
 - Release v0.0.2
 - Merge pull request [#11](https://github.com/segmentio/terraform-docs/issues/11) from segmentio/fix-md
-- print: wrap default values
+- wrap default values
 - Merge pull request [#10](https://github.com/segmentio/terraform-docs/issues/10) from segmentio/fix-map-type
-- doc: fix map type
+- fix map type
 - add more install notes
 - add dist
 
@@ -172,12 +178,12 @@
 
 - Merge pull request [#5](https://github.com/segmentio/terraform-docs/issues/5) from segmentio/fix-comment
 - use /** comment for module commnet
-- print: actually print head comment
+- actually print head comment
 - img
 - Merge pull request [#4](https://github.com/segmentio/terraform-docs/issues/4) from segmentio/layout
 - fix view
 - docs
-- doc: ignore comments with /** prefix
+- ignore comments with /** prefix
 - add head comment
 - cleanup
 - cleanup
@@ -189,7 +195,7 @@
 - add usage
 - better md output
 - add markdown output
-- outputs: use comments as description
+- use comments as description
 - ocd
 - clean
 - working
diff --git a/Makefile b/Makefile
index ae4e31c..7a950c9 100644
--- a/Makefile
+++ b/Makefile
@@ -55,6 +55,9 @@ clean: ## Clean workspace
 	@ $(MAKE) --no-print-directory log-$@
 	rm -rf ./$(BUILD_DIR)
 
+.PHONY: deps
+deps: vendor ## Install dependencies
+
 .PHONY: fmt
 fmt: ## Format all go files
 	@ $(MAKE) --no-print-directory log-$@
diff --git a/examples/variables.tf b/examples/variables.tf
index dd84249..0f8d888 100644
--- a/examples/variables.tf
+++ b/examples/variables.tf
@@ -57,3 +57,18 @@ variable "input-with-pipe" {
   description = "It includes v1 | v2 | v3"
   default     = "v1"
 }
+
+variable "input-with-code-block" {
+  description = <<EOD
+This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+EOD
+  default     = [
+    "name rack:location"
+  ]
+}
\ No newline at end of file
diff --git a/internal/pkg/print/markdown/document/document.go b/internal/pkg/print/markdown/document/document.go
index 4a1681f..e96595d 100644
--- a/internal/pkg/print/markdown/document/document.go
+++ b/internal/pkg/print/markdown/document/document.go
@@ -3,6 +3,7 @@ package document
 import (
 	"bytes"
 	"fmt"
+	"strings"
 
 	"github.com/segmentio/terraform-docs/internal/pkg/doc"
 	"github.com/segmentio/terraform-docs/internal/pkg/print"
@@ -42,7 +43,31 @@ func Print(document *doc.Doc, settings *settings.Settings) (string, error) {
 		printOutputs(&buffer, document.Outputs, settings)
 	}
 
-	return markdown.Sanitize(buffer.String()), nil
+	// out := markdown.Sanitize(buffer.String())
+
+	out := strings.Replace(buffer.String(), "<br>```<br>", "\n```\n", -1)
+
+	// the left over <br> or either inside or outside a code block:
+	segments := strings.Split(out, "\n```\n")
+	buf := bytes.NewBufferString("")
+	nextIsInCodeBlock := strings.HasPrefix(out, "```\n")
+	for i, segment := range segments {
+		if !nextIsInCodeBlock {
+			if i > 0 && len(segment) > 0 {
+				buf.WriteString("\n```\n")
+			}
+			segment = markdown.Sanitize(segment)
+			segment = strings.Replace(segment, "<br><br>", "\n\n", -1)
+			segment = strings.Replace(segment, "<br>", "  \n", -1)
+			buf.WriteString(segment)
+			nextIsInCodeBlock = true
+		} else {
+			buf.WriteString("\n```\n")
+			buf.WriteString(strings.Replace(segment, "<br>", "\n", -1))
+			nextIsInCodeBlock = false
+		}
+	}
+	return strings.Replace(buf.String(), " \n\n", "\n\n", -1), nil
 }
 
 func getInputDefaultValue(input *doc.Input, settings *settings.Settings) string {
diff --git a/internal/pkg/print/markdown/markdown.go b/internal/pkg/print/markdown/markdown.go
index 0458a52..0c8b4de 100644
--- a/internal/pkg/print/markdown/markdown.go
+++ b/internal/pkg/print/markdown/markdown.go
@@ -1,6 +1,7 @@
 package markdown
 
 import (
+	"bytes"
 	"regexp"
 	"strings"
 
@@ -17,16 +18,59 @@ func SanitizeName(s string, settings *settings.Settings) string {
 	return s
 }
 
-// SanitizeDescription converts description to suitable Markdown representation. (including line-break, illegal characters, etc)
 func SanitizeDescription(s string, settings *settings.Settings) string {
-	s = ConvertMultiLineText(s)
-	s = EscapeIllegalCharacters(s, settings)
+	// s = ConvertMultiLineText(s)
+	// s = EscapeIllegalCharacters(s, settings)
+	// return s
+	// Isolate blocks of code. Dont escape anything inside them
+	nextIsInCodeBlock := strings.HasPrefix(s, "```\n")
+	segments := strings.Split(s, "\n```\n")
+	buf := bytes.NewBufferString("")
+	for i, segment := range segments {
+		if !nextIsInCodeBlock {
+			segment = ConvertMultiLineText(segment)
+			segment = EscapeIllegalCharacters(segment, settings)
+			if i > 0 && len(segment) > 0 {
+				buf.WriteString("<br>```<br>")
+			}
+			buf.WriteString(segment)
+			nextIsInCodeBlock = true
+		} else {
+			buf.WriteString("<br>```<br>")
+			buf.WriteString(segment)
+			buf.WriteString("<br>```")
+			nextIsInCodeBlock = false
+		}
+	}
+	return buf.String()
+}
 
-	return s
+// SanitizeDescription converts description to suitable Markdown representation for a table. (including line-break, illegal characters, code blocks etc)
+func SanitizeDescriptionForTable(s string, settings *settings.Settings) string {
+	// Isolate blocks of code. Dont escape anything inside them
+	nextIsInCodeBlock := strings.HasPrefix(s, "```\n")
+	segments := strings.Split(s, "```\n")
+	buf := bytes.NewBufferString("")
+	for _, segment := range segments {
+		if !nextIsInCodeBlock {
+			segment = ConvertMultiLineText(segment)
+			segment = EscapeIllegalCharacters(segment, settings)
+			buf.WriteString(segment)
+			nextIsInCodeBlock = true
+		} else {
+			buf.WriteString("<code><pre>")
+			buf.WriteString(strings.Replace(strings.Replace(segment, "\n", "<br>", -1), "\r", "", -1))
+			buf.WriteString("</pre></code>")
+			nextIsInCodeBlock = false
+		}
+	}
+
+	return buf.String()
 }
 
 // ConvertMultiLineText converts a multi-line text into a suitable Markdown representation.
 func ConvertMultiLineText(s string) string {
+
 	// Convert double newlines to <br><br>.
 	s = strings.Replace(
 		strings.TrimSpace(s),
@@ -34,6 +78,9 @@ func ConvertMultiLineText(s string) string {
 		"<br><br>",
 		-1)
 
+	// Convert space-space-newline to <br>
+	s = strings.Replace(s, "  \n", "<br>", -1)
+
 	// Convert single newline to space.
 	return strings.Replace(s, "\n", " ", -1)
 }
@@ -50,7 +97,7 @@ func EscapeIllegalCharacters(s string, settings *settings.Settings) string {
 		// Escape asterisk
 		s = strings.Replace(s, "*", "\\*", -1)
 
-		// Escape paranthesis
+		// Escape parenthesis
 		s = strings.Replace(s, "(", "\\(", -1)
 		s = strings.Replace(s, ")", "\\)", -1)
 
diff --git a/internal/pkg/print/markdown/table/table.go b/internal/pkg/print/markdown/table/table.go
index a06d0fb..953eab9 100644
--- a/internal/pkg/print/markdown/table/table.go
+++ b/internal/pkg/print/markdown/table/table.go
@@ -81,7 +81,7 @@ func printInputs(buffer *bytes.Buffer, inputs []doc.Input, settings *settings.Se
 		buffer.WriteString(
 			fmt.Sprintf("| %s | %s | %s | %s |",
 				markdown.SanitizeName(input.Name, settings),
-				markdown.SanitizeDescription(input.Description, settings),
+				markdown.SanitizeDescriptionForTable(input.Description, settings),
 				input.Type,
 				getInputDefaultValue(&input, settings)))
 
@@ -110,6 +110,6 @@ func printOutputs(buffer *bytes.Buffer, outputs []doc.Output, settings *settings
 		buffer.WriteString(
 			fmt.Sprintf("| %s | %s |\n",
 				markdown.SanitizeName(output.Name, settings),
-				markdown.SanitizeDescription(output.Description, settings)))
+				markdown.SanitizeDescriptionForTable(output.Description, settings)))
 	}
 }
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ef0e22f..cc8f8f1 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -5,12 +5,12 @@ github.com/davecgh/go-spew/spew
 # github.com/hashicorp/hcl v1.0.0
 github.com/hashicorp/hcl
 github.com/hashicorp/hcl/hcl/ast
-github.com/hashicorp/hcl/hcl/printer
 github.com/hashicorp/hcl/hcl/parser
-github.com/hashicorp/hcl/hcl/token
-github.com/hashicorp/hcl/json/parser
+github.com/hashicorp/hcl/hcl/printer
 github.com/hashicorp/hcl/hcl/scanner
 github.com/hashicorp/hcl/hcl/strconv
+github.com/hashicorp/hcl/hcl/token
+github.com/hashicorp/hcl/json/parser
 github.com/hashicorp/hcl/json/scanner
 github.com/hashicorp/hcl/json/token
 # github.com/inconshreveable/mousetrap v1.0.0


Test patch:
diff --git a/internal/pkg/doc/doc_test.go b/internal/pkg/doc/doc_test.go
index e7c21d7..4773c87 100644
--- a/internal/pkg/doc/doc_test.go
+++ b/internal/pkg/doc/doc_test.go
@@ -120,6 +120,18 @@ var inputWithPipe = doc.Input{
 	Type: "string",
 }
 
+var inputWithCodeBlock = doc.Input{
+	Name:        "input-with-code-block",
+	Description: "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n",
+	Default: &doc.Value{
+		Type: "list",
+		Value: []interface{}{
+			"name rack:location",
+		},
+	},
+	Type: "list",
+}
+
 var output1 = doc.Output{
 	Name:        "output-1",
 	Description: "It's output number one.",
@@ -215,6 +227,7 @@ func TestInputs(t *testing.T) {
 		inputList1,
 		inputWithUnderscores,
 		inputWithPipe,
+		inputWithCodeBlock,
 	}
 
 	assert.Equal(t, expected, actual)
@@ -246,6 +259,7 @@ func TestInputsFromVariablesTf(t *testing.T) {
 		inputList1,
 		inputWithUnderscores,
 		inputWithPipe,
+		inputWithCodeBlock,
 	}
 
 	assert.Equal(t, expected, actual)
@@ -257,6 +271,7 @@ func TestInputsSortedByName(t *testing.T) {
 	doc.SortInputsByName(actual)
 
 	expected := []doc.Input{
+		inputWithCodeBlock,
 		inputWithPipe,
 		inputWithUnderscores,
 		inputList1,
@@ -285,6 +300,7 @@ func TestInputsSortedByRequired(t *testing.T) {
 		inputMap2,
 		inputString2,
 		inputUnquoted,
+		inputWithCodeBlock,
 		inputWithPipe,
 		inputList1,
 		inputList3,
diff --git a/internal/pkg/print/json/testdata/json-WithSortByName.golden b/internal/pkg/print/json/testdata/json-WithSortByName.golden
index 9015d1f..eb45874 100644
--- a/internal/pkg/print/json/testdata/json-WithSortByName.golden
+++ b/internal/pkg/print/json/testdata/json-WithSortByName.golden
@@ -1,6 +1,17 @@
 {
   "Comment": "Usage:\n\nmodule \"foo\" {\n  source = \"github.com/foo/bar\"\n\n  id   = \"1234567890\"\n  name = \"baz\"\n\n  zones = [\"us-east-1\", \"us-west-1\"]\n\n  tags = {\n    Name         = \"baz\"\n    Created-By   = \"first.last@email.com\"\n    Date-Created = \"20180101\"\n  }\n}\n",
   "Inputs": [
+    {
+      "Name": "input-with-code-block",
+      "Description": "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n",
+      "Default": {
+        "Type": "list",
+        "Value": [
+          "name rack:location"
+        ]
+      },
+      "Type": "list"
+    },
     {
       "Name": "input-with-pipe",
       "Description": "It includes v1 | v2 | v3",
diff --git a/internal/pkg/print/json/testdata/json-WithSortInputsByRequired.golden b/internal/pkg/print/json/testdata/json-WithSortInputsByRequired.golden
index 018e8bc..3cce4d9 100644
--- a/internal/pkg/print/json/testdata/json-WithSortInputsByRequired.golden
+++ b/internal/pkg/print/json/testdata/json-WithSortInputsByRequired.golden
@@ -31,6 +31,17 @@
       "Default": null,
       "Type": "string"
     },
+    {
+      "Name": "input-with-code-block",
+      "Description": "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n",
+      "Default": {
+        "Type": "list",
+        "Value": [
+          "name rack:location"
+        ]
+      },
+      "Type": "list"
+    },
     {
       "Name": "input-with-pipe",
       "Description": "It includes v1 | v2 | v3",
diff --git a/internal/pkg/print/json/testdata/json.golden b/internal/pkg/print/json/testdata/json.golden
index c477e2e..bc05ba7 100644
--- a/internal/pkg/print/json/testdata/json.golden
+++ b/internal/pkg/print/json/testdata/json.golden
@@ -101,6 +101,17 @@
         "Value": "v1"
       },
       "Type": "string"
+    },
+    {
+      "Name": "input-with-code-block",
+      "Description": "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n",
+      "Default": {
+        "Type": "list",
+        "Value": [
+          "name rack:location"
+        ]
+      },
+      "Type": "list"
     }
   ],
   "Outputs": [
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithAggregateTypeDefaults.golden b/internal/pkg/print/markdown/document/testdata/document-WithAggregateTypeDefaults.golden
index 2053b61..9919798 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithAggregateTypeDefaults.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithAggregateTypeDefaults.golden
@@ -139,6 +139,26 @@ Type: `string`
 
 Default: `"v1"`
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default:
+
+```json
+[
+  "name rack:location"
+]
+```
+
 ## Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithEscapeName.golden b/internal/pkg/print/markdown/document/testdata/document-WithEscapeName.golden
index d1d4ddd..f986971 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithEscapeName.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithEscapeName.golden
@@ -115,6 +115,20 @@ Type: `string`
 
 Default: `"v1"`
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ## Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithIndentationAboveAllowed.golden b/internal/pkg/print/markdown/document/testdata/document-WithIndentationAboveAllowed.golden
index 3c992db..00d38dc 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithIndentationAboveAllowed.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithIndentationAboveAllowed.golden
@@ -115,6 +115,20 @@ Type: `string`
 
 Default: `"v1"`
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ## Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithIndentationBellowAllowed.golden b/internal/pkg/print/markdown/document/testdata/document-WithIndentationBellowAllowed.golden
index 3c992db..00d38dc 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithIndentationBellowAllowed.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithIndentationBellowAllowed.golden
@@ -115,6 +115,20 @@ Type: `string`
 
 Default: `"v1"`
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ## Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithIndentationOfFour.golden b/internal/pkg/print/markdown/document/testdata/document-WithIndentationOfFour.golden
index cb1531d..cceec76 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithIndentationOfFour.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithIndentationOfFour.golden
@@ -115,6 +115,20 @@ Type: `string`
 
 Default: `"v1"`
 
+##### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 #### Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithRequired.golden b/internal/pkg/print/markdown/document/testdata/document-WithRequired.golden
index 4cb70e1..27509d8 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithRequired.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithRequired.golden
@@ -109,6 +109,20 @@ Type: `string`
 
 Default: `"v1"`
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ## Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithSortByName.golden b/internal/pkg/print/markdown/document/testdata/document-WithSortByName.golden
index 2ba8324..b5094f2 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithSortByName.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithSortByName.golden
@@ -19,6 +19,20 @@ module "foo" {
 
 The following input variables are supported:
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ### input-with-pipe
 
 Description: It includes v1 \| v2 \| v3
diff --git a/internal/pkg/print/markdown/document/testdata/document-WithSortInputsByRequired.golden b/internal/pkg/print/markdown/document/testdata/document-WithSortInputsByRequired.golden
index 8401aaf..343df0e 100644
--- a/internal/pkg/print/markdown/document/testdata/document-WithSortInputsByRequired.golden
+++ b/internal/pkg/print/markdown/document/testdata/document-WithSortInputsByRequired.golden
@@ -59,6 +59,20 @@ Type: `string`
 
 Default: n/a
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ### input-with-pipe
 
 Description: It includes v1 \| v2 \| v3
diff --git a/internal/pkg/print/markdown/document/testdata/document.golden b/internal/pkg/print/markdown/document/testdata/document.golden
index 3c992db..00d38dc 100644
--- a/internal/pkg/print/markdown/document/testdata/document.golden
+++ b/internal/pkg/print/markdown/document/testdata/document.golden
@@ -115,6 +115,20 @@ Type: `string`
 
 Default: `"v1"`
 
+### input-with-code-block
+
+Description: This is a complicated one. We need a newline.  
+And an example in a code block
+```
+default     = [
+  "machine rack01:neptune"
+]
+```
+
+Type: `list`
+
+Default: `<list>`
+
 ## Outputs
 
 The following outputs are exported:
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithAggregateTypeDefaults.golden b/internal/pkg/print/markdown/table/testdata/table-WithAggregateTypeDefaults.golden
index c33c865..4a6978f 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithAggregateTypeDefaults.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithAggregateTypeDefaults.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `[ "a", "b", "c" ]` |
 | input_with_underscores | A variable with underscores. | string | n/a |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `[ "name rack:location" ]` |
 
 ## Outputs
 
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithEscapeName.golden b/internal/pkg/print/markdown/table/testdata/table-WithEscapeName.golden
index 9d73f09..3d75f5a 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithEscapeName.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithEscapeName.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `<list>` |
 | input\_with\_underscores | A variable with underscores. | string | n/a |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 
 ## Outputs
 
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithIndentationAboveAllowed.golden b/internal/pkg/print/markdown/table/testdata/table-WithIndentationAboveAllowed.golden
index f5b4c0b..aac5f5f 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithIndentationAboveAllowed.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithIndentationAboveAllowed.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `<list>` |
 | input_with_underscores | A variable with underscores. | string | n/a |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 
 ## Outputs
 
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithIndentationBellowAllowed.golden b/internal/pkg/print/markdown/table/testdata/table-WithIndentationBellowAllowed.golden
index f5b4c0b..aac5f5f 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithIndentationBellowAllowed.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithIndentationBellowAllowed.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `<list>` |
 | input_with_underscores | A variable with underscores. | string | n/a |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 
 ## Outputs
 
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithIndentationOfFour.golden b/internal/pkg/print/markdown/table/testdata/table-WithIndentationOfFour.golden
index 6c0c647..d74efae 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithIndentationOfFour.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithIndentationOfFour.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `<list>` |
 | input_with_underscores | A variable with underscores. | string | n/a |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 
 #### Outputs
 
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithRequired.golden b/internal/pkg/print/markdown/table/testdata/table-WithRequired.golden
index 4ea9f08..21e6e17 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithRequired.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithRequired.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `<list>` | no |
 | input_with_underscores | A variable with underscores. | string | n/a | yes |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` | no |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` | no |
 
 ## Outputs
 
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithSortByName.golden b/internal/pkg/print/markdown/table/testdata/table-WithSortByName.golden
index 88a1f85..549b299 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithSortByName.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithSortByName.golden
@@ -19,6 +19,7 @@ module "foo" {
 
 | Name | Description | Type | Default |
 |------|-------------|:----:|:-----:|
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
 | input_with_underscores | A variable with underscores. | string | n/a |
 | list-1 | It's list number one. | list | `<list>` |
diff --git a/internal/pkg/print/markdown/table/testdata/table-WithSortInputsByRequired.golden b/internal/pkg/print/markdown/table/testdata/table-WithSortInputsByRequired.golden
index 2229cc9..a794145 100644
--- a/internal/pkg/print/markdown/table/testdata/table-WithSortInputsByRequired.golden
+++ b/internal/pkg/print/markdown/table/testdata/table-WithSortInputsByRequired.golden
@@ -24,6 +24,7 @@ module "foo" {
 | map-2 | It's map number two. | map | n/a |
 | string-2 | It's string number two. | string | n/a |
 | unquoted |  | string | n/a |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
 | list-1 | It's list number one. | list | `<list>` |
 | list-3 |  | list | `<list>` |
diff --git a/internal/pkg/print/markdown/table/testdata/table.golden b/internal/pkg/print/markdown/table/testdata/table.golden
index f5b4c0b..aac5f5f 100644
--- a/internal/pkg/print/markdown/table/testdata/table.golden
+++ b/internal/pkg/print/markdown/table/testdata/table.golden
@@ -31,6 +31,7 @@ module "foo" {
 | list-1 | It's list number one. | list | `<list>` |
 | input_with_underscores | A variable with underscores. | string | n/a |
 | input-with-pipe | It includes v1 \| v2 \| v3 | string | `"v1"` |
+| input-with-code-block | This is a complicated one. We need a newline.<br>And an example in a code block<code><pre>default     = [<br>  "machine rack01:neptune"<br>]<br></pre></code> | list | `<list>` |
 
 ## Outputs
 
diff --git a/internal/pkg/print/pretty/pretty_test.go b/internal/pkg/print/pretty/pretty_test.go
index 50aa90d..8f79de6 100644
--- a/internal/pkg/print/pretty/pretty_test.go
+++ b/internal/pkg/print/pretty/pretty_test.go
@@ -78,6 +78,9 @@ func TestPretty(t *testing.T) {
 			"  " + sgr_color_1 + "var.input-with-pipe" + sgr_reset + " (\"v1\")\n" +
 			"  " + sgr_color_2 + "It includes v1 | v2 | v3" + sgr_reset + "\n" +
 			"\n" +
+			"  " + sgr_color_1 + "var.input-with-code-block" + sgr_reset + " (<list>)\n" +
+			"  " + sgr_color_2 + "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n" + sgr_reset + "\n" +
+			"\n" +
 			"\n" +
 			"\n" +
 			"  " + sgr_color_1 + "output.unquoted" + sgr_reset + "\n" +
@@ -165,6 +168,9 @@ func TestPrettyWithWithAggregateTypeDefaults(t *testing.T) {
 			"  " + sgr_color_1 + "var.input-with-pipe" + sgr_reset + " (\"v1\")\n" +
 			"  " + sgr_color_2 + "It includes v1 | v2 | v3" + sgr_reset + "\n" +
 			"\n" +
+			"  " + sgr_color_1 + "var.input-with-code-block" + sgr_reset + " ([ \"name rack:location\" ])\n" +
+			"  " + sgr_color_2 + "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n" + sgr_reset + "\n" +
+			"\n" +
 			"\n" +
 			"\n" +
 			"  " + sgr_color_1 + "output.unquoted" + sgr_reset + "\n" +
@@ -216,6 +222,9 @@ func TestPrettyWithSortByName(t *testing.T) {
 			"}\n" +
 			"\n" +
 			"\n" +
+			"  " + sgr_color_1 + "var.input-with-code-block" + sgr_reset + " (<list>)\n" +
+			"  " + sgr_color_2 + "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n" + sgr_reset + "\n" +
+			"\n" +
 			"  " + sgr_color_1 + "var.input-with-pipe" + sgr_reset + " (\"v1\")\n" +
 			"  " + sgr_color_2 + "It includes v1 | v2 | v3" + sgr_reset + "\n" +
 			"\n" +
@@ -319,6 +328,9 @@ func TestPrettyWithSortInputsByRequired(t *testing.T) {
 			"  " + sgr_color_1 + "var.unquoted" + sgr_reset + " (required)\n" +
 			"  " + sgr_color_2 + "" + sgr_reset + "\n" +
 			"\n" +
+			"  " + sgr_color_1 + "var.input-with-code-block" + sgr_reset + " (<list>)\n" +
+			"  " + sgr_color_2 + "This is a complicated one. We need a newline.  \nAnd an example in a code block\n```\ndefault     = [\n  \"machine rack01:neptune\"\n]\n```\n" + sgr_reset + "\n" +
+			"\n" +
 			"  " + sgr_color_1 + "var.input-with-pipe" + sgr_reset + " (\"v1\")\n" +
 			"  " + sgr_color_2 + "It includes v1 | v2 | v3" + sgr_reset + "\n" +
 			"\n" +