Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Added MarkdownString type, Deprecated MarkedString #216 #238

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
20 changes: 10 additions & 10 deletions langserver/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (h *LangHandler) handleHover(ctx context.Context, conn jsonrpc2.JSONRPC2, r
r := rangeForNode(fset, node)
if pkgName := packageStatementName(fset, pkg.Files, node); pkgName != "" {
return &lsp.Hover{
Contents: maybeAddComments(comments, []lsp.MarkedString{{Language: "go", Value: "package " + pkgName}}),
Contents: maybeAddComments(comments, []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: "package " + pkgName}}),
Range: &r,
}, nil
}
Expand Down Expand Up @@ -137,7 +137,7 @@ func (h *LangHandler) handleHover(ctx context.Context, conn jsonrpc2.JSONRPC2, r
return doc.Text()
}

contents := maybeAddComments(findComments(o), []lsp.MarkedString{{Language: "go", Value: s}})
contents := maybeAddComments(findComments(o), []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: s}})
if extra != "" {
// If we have extra info, ensure it comes after the usually
// more useful documentation
Expand All @@ -164,7 +164,7 @@ func packageStatementName(fset *token.FileSet, files []*ast.File, node *ast.Iden

// maybeAddComments appends the specified comments converted to Markdown godoc
// form to the specified contents slice, if the comments string is not empty.
func maybeAddComments(comments string, contents []lsp.MarkedString) []lsp.MarkedString {
func maybeAddComments(comments string, contents []lsp.MarkupContent) []lsp.MarkupContent {
if comments == "" {
return contents
}
Expand Down Expand Up @@ -294,7 +294,7 @@ func (h *LangHandler) handleHoverGodef(ctx context.Context, conn jsonrpc2.JSONRP
comments := packageDoc(pkgFiles, bpkg.Name)

return &lsp.Hover{
Contents: maybeAddComments(comments, []lsp.MarkedString{{Language: "go", Value: fmt.Sprintf("package %s (%q)", bpkg.Name, bpkg.ImportPath)}}),
Contents: maybeAddComments(comments, []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: fmt.Sprintf("package %s (%q)", bpkg.Name, bpkg.ImportPath)}}),

// TODO(slimsag): I think we can add Range here, but not exactly
// sure. res.Start and res.End are only present if it's a package
Expand Down Expand Up @@ -437,7 +437,7 @@ func findDocTarget(fset *token.FileSet, target token.Position, in interface{}) i
// *doc.Type
// *doc.Func
//
func fmtDocObject(fset *token.FileSet, x interface{}, target token.Position) ([]lsp.MarkedString, ast.Node) {
func fmtDocObject(fset *token.FileSet, x interface{}, target token.Position) ([]lsp.MarkupContent, ast.Node) {
switch v := x.(type) {
case *doc.Value: // Vars and Consts
// Sort the specs by distance to find the one nearest to target.
Expand All @@ -455,7 +455,7 @@ func fmtDocObject(fset *token.FileSet, x interface{}, target token.Position) ([]
cpy := *spec
cpy.Doc = nil
value := v.Decl.Tok.String() + " " + fmtNode(fset, &cpy)
return maybeAddComments(doc, []lsp.MarkedString{{Language: "go", Value: value}}), spec
return maybeAddComments(doc, []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: value}}), spec

case *doc.Type: // Type declarations
spec := v.Decl.Specs[0].(*ast.TypeSpec)
Expand All @@ -468,7 +468,7 @@ func fmtDocObject(fset *token.FileSet, x interface{}, target token.Position) ([]
if fset.Position(field.Pos()).Offset == target.Offset {
// An exact match.
value := fmt.Sprintf("func (%s).%s%s", spec.Name.Name, field.Names[0].Name, strings.TrimPrefix(fmtNode(fset, field.Type), "func"))
return maybeAddComments(field.Doc.Text(), []lsp.MarkedString{{Language: "go", Value: value}}), field
return maybeAddComments(field.Doc.Text(), []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: value}}), field
}
}

Expand All @@ -478,14 +478,14 @@ func fmtDocObject(fset *token.FileSet, x interface{}, target token.Position) ([]
if fset.Position(field.Pos()).Offset == target.Offset {
// An exact match.
value := fmt.Sprintf("struct field %s %s", field.Names[0], fmtNode(fset, field.Type))
return maybeAddComments(field.Doc.Text(), []lsp.MarkedString{{Language: "go", Value: value}}), field
return maybeAddComments(field.Doc.Text(), []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: value}}), field
}
}
}

// Formatting of all type declarations: structs, interfaces, integers, etc.
name := v.Decl.Tok.String() + " " + spec.Name.Name + " " + typeName(fset, spec.Type)
res := []lsp.MarkedString{{Language: "go", Value: name}}
res := []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: name}}

doc := spec.Doc.Text()
if doc == "" {
Expand All @@ -499,7 +499,7 @@ func fmtDocObject(fset *token.FileSet, x interface{}, target token.Position) ([]
return res, spec

case *doc.Func: // Functions
return maybeAddComments(v.Doc, []lsp.MarkedString{{Language: "go", Value: fmtNode(fset, v.Decl)}}), v.Decl
return maybeAddComments(v.Doc, []lsp.MarkupContent{lsp.MarkedString{Language: "go", Value: fmtNode(fset, v.Decl)}}), v.Decl
default:
panic("unreachable")
}
Expand Down
42 changes: 40 additions & 2 deletions pkg/lsp/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,19 @@ type CompletionParams struct {
}

type Hover struct {
Contents []MarkedString `json:"contents,omitempty"`
Range *Range `json:"range,omitempty"`
Contents []MarkupContent `json:"contents,omitempty"`
Range *Range `json:"range,omitempty"`
}

type MarkupContent interface {
MarshalJSON() ([]byte, error)
}

// Deprecated: Use MarkdownString instead.
type MarkedString markedString

type MarkdownString markdownString

type markedString struct {
Language string `json:"language"`
Value string `json:"value"`
Expand Down Expand Up @@ -338,6 +345,37 @@ func RawMarkedString(s string) MarkedString {
return MarkedString{Value: s, isRawString: true}
}

type markdownString struct {
// The markdown string.
Value string `json:"value"`
// Indicates that this markdown string is from a trusted source. Only *trusted*
// markdown supports links that execute commands, e.g. `[Run it](command:myCommandId)`
IsTrusted bool `json:"isTrusted"`
}

func (m *MarkdownString) UnmarshalJSON(data []byte) error {
if d := strings.TrimSpace(string(data)); len(d) > 0 && d[0] == '"' {
// Raw string
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
m.Value = s
m.IsTrusted = true
return nil
}
// Language string
ms := (*markdownString)(m)
return json.Unmarshal(data, ms)
}

func (m MarkdownString) MarshalJSON() ([]byte, error) {
if m.IsTrusted {
return json.Marshal(m.Value)
}
return json.Marshal((markdownString)(m))
}

type SignatureHelp struct {
Signatures []SignatureInformation `json:"signatures"`
ActiveSignature int `json:"activeSignature"`
Expand Down
27 changes: 27 additions & 0 deletions pkg/lsp/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,30 @@ func TestMarkedString_MarshalUnmarshalJSON(t *testing.T) {
}
}
}

func TestMarkdownString_MarshalUnmarshalJSON(t *testing.T) {
tests := []struct {
data []byte
want MarkdownString
}{{
data: []byte(`{"value":"## h2 heading"}`),
want: MarkdownString{Value: "## h2 heading", IsTrusted: false},
}, {
data: []byte(`"# h1 heading"`),
want: MarkdownString{Value: "# h1 heading", IsTrusted: true},
},
}

for _, test := range tests {
var m MarkdownString
if err := json.Unmarshal(test.data, &m); err != nil {
t.Errorf("json.Unmarshal error: %s", err)
continue
}
if !reflect.DeepEqual(test.want, m) {
t.Errorf("Unmarshaled %q, expected %+v, but got %+v", string(test.data), test.want, m)
continue
}

}
}