From 7a5c487632633ab89171d0fed257e7043def401d Mon Sep 17 00:00:00 2001 From: x1unix Date: Tue, 21 Jan 2020 16:10:19 +0200 Subject: [PATCH 1/2] analyzer: parse doc comments --- pkg/analyzer/scanner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/analyzer/scanner.go b/pkg/analyzer/scanner.go index ba206eac..e2949fdf 100644 --- a/pkg/analyzer/scanner.go +++ b/pkg/analyzer/scanner.go @@ -79,7 +79,7 @@ func (p *PackageScanner) appendFunc(fn *ast.FuncDecl, dest *SymbolIndex) { func (p *PackageScanner) Scan() (PackageSummary, error) { sum := NewPackageSummary() set := token.NewFileSet() - packs, err := parser.ParseDir(set, p.path, nil, 0) + packs, err := parser.ParseDir(set, p.path, nil, parser.ParseComments) if err != nil { return sum, err } From a10c7d3bf126b5781244be334c7067ad530999b6 Mon Sep 17 00:00:00 2001 From: x1unix Date: Tue, 21 Jan 2020 17:35:17 +0200 Subject: [PATCH 2/2] analyzer: format inner source code in godoc --- pkg/analyzer/decl.go | 2 +- pkg/analyzer/docfmt.go | 79 ++++++++++++++++++++++++++++++++++++++ web/src/editor/provider.ts | 38 +++++++++--------- 3 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 pkg/analyzer/docfmt.go diff --git a/pkg/analyzer/decl.go b/pkg/analyzer/decl.go index 0b314a02..d70d1cdd 100644 --- a/pkg/analyzer/decl.go +++ b/pkg/analyzer/decl.go @@ -81,7 +81,7 @@ func funcToItem(fn *ast.FuncDecl) *CompletionItem { ci := &CompletionItem{ Label: fn.Name.String(), Kind: Function, - Documentation: fn.Doc.Text(), + Documentation: formatDoc(fn.Doc.Text()), } ci.Detail = funcToString(fn.Type) diff --git a/pkg/analyzer/docfmt.go b/pkg/analyzer/docfmt.go new file mode 100644 index 00000000..cf5c8469 --- /dev/null +++ b/pkg/analyzer/docfmt.go @@ -0,0 +1,79 @@ +package analyzer + +import "strings" + +const ( + newLineChar = '\n' + tabChar = '\t' +) + +var ( + mdCodeTag = []byte("```\n") + spaceIdent = " " + spaceIdentLen = len(spaceIdent) +) + +func isDocLine(line string) bool { + // Source code in Go usually doc starts with tab char + if line[0] == tabChar { + return true + } + + // Workaround for some packages with double space as doc indent (line "net/http") + if (len(line) > spaceIdentLen) && (line[:spaceIdentLen] == spaceIdent) { + return true + } + + return false +} + +func formatDoc(str string) MarkdownString { + if str == "" { + return MarkdownString{Value: str} + } + + w := strings.Builder{} + docStart := false + + lines := strings.Split(str, "\n") + for _, line := range lines { + if len(line) == 0 { + w.WriteRune(newLineChar) + continue + } + + // Source code in Go doc starts with tab char + if isDocLine(line) { + if !docStart { + // Put markdown code section + // if we met first source code line + docStart = true + w.Write(mdCodeTag) + } + + w.WriteString(line) + w.WriteRune(newLineChar) + continue + } + + // Else - regular text + if docStart { + // Terminate code block if previous + // was open and not terminated + docStart = false + w.Write(mdCodeTag) + } + + w.WriteString(line) + w.WriteRune(newLineChar) + } + + if docStart { + // close markdown code block if wasn't closed + w.Write(mdCodeTag) + } + + return MarkdownString{ + Value: w.String(), + } +} diff --git a/web/src/editor/provider.ts b/web/src/editor/provider.ts index b882168b..6c59e81e 100644 --- a/web/src/editor/provider.ts +++ b/web/src/editor/provider.ts @@ -15,28 +15,28 @@ const COMPL_REGEXP = /([a-zA-Z0-9_]+)(\.([A-Za-z0-9_]+))?$/; const R_GROUP_PKG = 1; const R_GROUP_METHOD = 3; -class GoCompletionItemProvider implements monaco.languages.CompletionItemProvider { - constructor(private client: IAPIClient) {} +const parseExpression = (expr: string) => { + COMPL_REGEXP.lastIndex = 0; // Reset regex state + const m = COMPL_REGEXP.exec(expr); + if (!m) { + return null; + } - private parseExpression(expr: string) { - COMPL_REGEXP.lastIndex = 0; // Reset regex state - const m = COMPL_REGEXP.exec(expr); - if (!m) { - return null; - } + const varName = m[R_GROUP_PKG]; + const propValue = m[R_GROUP_METHOD]; - const varName = m[R_GROUP_PKG]; - const propValue = m[R_GROUP_METHOD]; + if (!propValue) { + return {value: varName}; + } - if (!propValue) { - return {value: varName}; - } + return { + packageName: varName, + value: propValue + }; +}; - return { - packageName: varName, - value: propValue - }; - } +class GoCompletionItemProvider implements monaco.languages.CompletionItemProvider { + constructor(private client: IAPIClient) {} async provideCompletionItems(model: ITextModel, position: Position, context: CompletionContext, token: CancellationToken): Promise { const val = model.getValueInRange({ @@ -46,7 +46,7 @@ class GoCompletionItemProvider implements monaco.languages.CompletionItemProvide endColumn: position.column, }).trim(); - const query = this.parseExpression(val); + const query = parseExpression(val); if (!query) { return Promise.resolve({suggestions: []}); }