Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UX of completion items #115

Merged
merged 2 commits into from
May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/google/go-cmp v0.4.0
github.com/hashicorp/go-version v1.2.0
github.com/hashicorp/hcl/v2 v2.3.0
github.com/hashicorp/terraform-json v0.4.0
github.com/hashicorp/terraform-json v0.5.0
github.com/mitchellh/cli v1.0.0
github.com/pmezard/go-difflib v1.0.0
github.com/sourcegraph/go-lsp v0.0.0-20200117082640-b19bb38222e2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+d
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE=
github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8=
github.com/hashicorp/terraform-json v0.4.0 h1:KNh29iNxozP5adfUFBJ4/fWd0Cu3taGgjHB38JYqOF4=
github.com/hashicorp/terraform-json v0.4.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU=
github.com/hashicorp/terraform-json v0.5.0 h1:7TV3/F3y7QVSuN4r9BEXqnWqrAyeOtON8f0wvREtyzs=
github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand Down
11 changes: 10 additions & 1 deletion internal/lsp/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,22 @@ func CompletionList(candidates lang.CompletionCandidates, pos hcl.Pos, caps lsp.
}

func CompletionItem(candidate lang.CompletionCandidate, pos hcl.Pos, snippetSupport bool) lsp.CompletionItem {
// TODO: deprecated / tags?

doc := ""
if c := candidate.Documentation(); c != nil {
// TODO: markdown handling
doc = c.Value()
}

if snippetSupport {
pos, newText := candidate.Snippet(pos)

return lsp.CompletionItem{
Label: candidate.Label(),
Kind: lsp.CIKField,
InsertTextFormat: lsp.ITFSnippet,
Detail: candidate.Detail(),
Documentation: doc,
TextEdit: &lsp.TextEdit{
Range: lsp.Range{
Start: lsp.Position{Line: pos.Line - 1, Character: pos.Column - 1},
Expand All @@ -49,5 +57,6 @@ func CompletionItem(candidate lang.CompletionCandidate, pos hcl.Pos, snippetSupp
Kind: lsp.CIKField,
InsertTextFormat: lsp.ITFPlainText,
Detail: candidate.Detail(),
Documentation: doc,
}
}
72 changes: 72 additions & 0 deletions internal/mdplain/mdplain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package mdplain

import (
"fmt"
"regexp"
)

type replacement struct {
re *regexp.Regexp
sub string
}

var replacements = []replacement{
// rules heavily inspired by: https://github.com/stiang/remove-markdown/blob/master/index.js
// back references were removed

// Header
{regexp.MustCompile(`\n={2,}`), "\n"},
// Fenced codeblocks
{regexp.MustCompile(`~{3}.*\n`), ""},
// Strikethrough
{regexp.MustCompile("~~"), ""},
// Fenced codeblocks
{regexp.MustCompile("`{3}.*\\n"), ""},
// Remove HTML tags
{regexp.MustCompile(`<[^>]*>`), ""},
// Remove setext-style headers
{regexp.MustCompile(`^[=\-]{2,}\s*$`), ""},
// Remove footnotes?
{regexp.MustCompile(`\[\^.+?\](\: .*?$)?`), ""},
{regexp.MustCompile(`\s{0,2}\[.*?\]: .*?$`), ""},
// Remove images
{regexp.MustCompile(`\!\[(.*?)\][\[\(].*?[\]\)]`), "$1"},
// Remove inline links
{regexp.MustCompile(`\[(.*?)\][\[\(].*?[\]\)]`), "$1"},
// Remove blockquotes
{regexp.MustCompile(`^\s{0,3}>\s?`), ""},
// Remove reference-style links?
{regexp.MustCompile(`^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$`), ""},
// Remove atx-style headers
{regexp.MustCompile(`^(\n)?\s{0,}#{1,6}\s+| {0,}(\n)?\s{0,}#{0,} {0,}(\n)?\s{0,}$`), "$1$2$3"},
// Remove emphasis (repeat the line to remove double emphasis)
{regexp.MustCompile(`([*_]{1,3})([^\t\n\f\r *_].*?[^\t\n\f\r *_]{0,1})([*_]{1,3})`), "$2"},
{regexp.MustCompile(`([*_]{1,3})([^\t\n\f\r *_].*?[^\t\n\f\r *_]{0,1})([*_]{1,3})`), "$2"},
// Remove code blocks
{regexp.MustCompile("(`{3,})(.*?)(`{3,})"), "$2"},
// Remove inline code
{regexp.MustCompile("`(.+?)`"), "$1"},
// Replace two or more newlines with exactly two? Not entirely sure this belongs here...
{regexp.MustCompile(`\n{2,}`), "\n\n"},
}

// Clean runs a VERY naive cleanup of markdown text to make it more palatable as plain text.
func Clean(markdown string) string {
// TODO: maybe use https://github.com/russross/blackfriday/tree/v2, write custom renderer or
// generate HTML then process that to plaintext using https://github.com/jaytaylor/html2text

fmt.Printf("cleaning %q\n", markdown)

result := markdown
before := markdown

for _, r := range replacements {
result = r.re.ReplaceAllString(result, r.sub)
if before != result {
fmt.Printf("RE: %q, %q to %q\n", r.re, before, result)
}
before = result
}

return string(result)
}
38 changes: 38 additions & 0 deletions internal/mdplain/mdplain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package mdplain_test

import (
"testing"

"github.com/hashicorp/terraform-ls/internal/mdplain"
)

func TestClean(t *testing.T) {
for _, c := range []struct {
markdown string
expected string
}{
{"", ""},

{"_foo_", "foo"},
{"__foo__", "foo"},
{"foo_bar", "foo_bar"},

{"*foo*", "foo"},
{"**foo**", "foo"},
{"Desc **2**", "Desc 2"},
{"1 * 3 = 3", "1 * 3 = 3"},

{"## Header", "Header"},
{"Header\n====\n\nSome text", "Header\n\nSome text"},

{"* item 1\n* item 2\n\n\nSome text", "* item 1\n* item 2\n\nSome text"},
} {
t.Run(c.expected, func(t *testing.T) {
actual := mdplain.Clean(c.markdown)

if c.expected != actual {
t.Fatalf("expected:\n%s\n\ngot:\n%s\n", c.expected, actual)
}
})
}
}
37 changes: 35 additions & 2 deletions internal/terraform/lang/config_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (

hcl "github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
tfjson "github.com/hashicorp/terraform-json"
)

type configBlockFactory interface {
New(*hclsyntax.Block) (ConfigBlock, error)
LabelSchema() LabelSchema
Documentation() MarkupContent
}

type labelCandidates map[string][]CompletionCandidate
Expand Down Expand Up @@ -129,8 +131,9 @@ func (l *completeList) IsComplete() bool {
}

type labelCandidate struct {
label string
detail string
label string
detail string
documentation MarkupContent
}

func (c *labelCandidate) Label() string {
Expand All @@ -141,6 +144,10 @@ func (c *labelCandidate) Detail() string {
return c.detail
}

func (c *labelCandidate) Documentation() MarkupContent {
return c.documentation
}

func (c *labelCandidate) Snippet(pos hcl.Pos) (hcl.Pos, string) {
return pos, c.label
}
Expand All @@ -156,9 +163,25 @@ func (c *attributeCandidate) Label() string {
}

func (c *attributeCandidate) Detail() string {
if c.Attr == nil {
return ""
}
return schemaAttributeDetail(c.Attr.Schema())
}

func (c *attributeCandidate) Documentation() MarkupContent {
if c.Attr == nil {
return PlainText("")
}
if schema := c.Attr.Schema(); schema != nil {
if schema.DescriptionKind == tfjson.SchemaDescriptionKindMarkdown {
return Markdown(schema.Description)
}
return PlainText(schema.Description)
}
return PlainText("")
}

func (c *attributeCandidate) Snippet(pos hcl.Pos) (hcl.Pos, string) {
return pos, fmt.Sprintf("%s = %s", c.Name, snippetForAttrType(0, c.Attr.Schema().AttributeType))
}
Expand All @@ -177,6 +200,16 @@ func (c *nestedBlockCandidate) Detail() string {
return schemaBlockDetail(c.BlockType)
}

func (c *nestedBlockCandidate) Documentation() MarkupContent {
if c.BlockType == nil || c.BlockType.Schema() == nil || c.BlockType.Schema().Block == nil {
return PlainText("")
}
if c.BlockType.Schema().Block.DescriptionKind == tfjson.SchemaDescriptionKindMarkdown {
return Markdown(c.BlockType.Schema().Block.Description)
}
return PlainText(c.BlockType.Schema().Block.Description)
}

func (c *nestedBlockCandidate) Snippet(pos hcl.Pos) (hcl.Pos, string) {
return pos, snippetForNestedBlock(c.Name)
}
Loading