diff --git a/.goreleaser.yml b/.goreleaser.yml index e43d36e..5e5efe5 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,6 +11,12 @@ builds: main: ./app/lithia env: - CGO_ENABLED=1 + ldflags: &build-ldflags + - -s -w -X github.com/vknabel/lithia/info.Version={{.Version}} + - -X github.com/vknabel/lithia/info.Commit={{.Commit}} + - -X github.com/vknabel/lithia/info.Date={{.Date}} + - -X github.com/vknabel/lithia/info.BuiltBy=goreleaser + goos: # - linux # - windows @@ -21,6 +27,7 @@ builds: # brew install mingw-w64 - id: lithia-x-linux-amd64 main: ./app/lithia + ldflags: *build-ldflags env: - CGO_ENABLED=1 - CC=x86_64-linux-musl-gcc @@ -33,6 +40,7 @@ builds: env: - CGO_ENABLED=1 - CC=aarch64-linux-musl-gcc + ldflags: *build-ldflags goos: - linux goarch: @@ -42,6 +50,7 @@ builds: env: - CGO_ENABLED=1 - CC=x86_64-w64-mingw32-gcc + ldflags: *build-ldflags goos: - windows goarch: diff --git a/app/lithia/cmd/root.go b/app/lithia/cmd/root.go index 077a3a3..0059764 100644 --- a/app/lithia/cmd/root.go +++ b/app/lithia/cmd/root.go @@ -1,6 +1,8 @@ package cmd import ( + "fmt" + "github.com/spf13/cobra" "github.com/vknabel/lithia/info" ) @@ -18,7 +20,7 @@ var rootCmd = &cobra.Command{ "all language features contribute to.\n" + "\n" + "Lean more at https://github.com/vknabel/lithia", - Version: info.Version, + Version: fmt.Sprintf("%s\ncommit: %s\nbuilt by: %s\nbuilt at: %s", info.Version, info.Commit, info.Date, info.BuiltBy), Args: cobra.RangeArgs(0, 1), Run: func(cmd *cobra.Command, args []string) { if len(args) == 1 { diff --git a/info/globals.go b/info/globals.go index 5b51669..a7eede0 100644 --- a/info/globals.go +++ b/info/globals.go @@ -1,4 +1,13 @@ package info -var Version = "0.0.18-next" -var Debug = true +var Version = "dev" +var Commit string +var Date string +var BuiltBy = "dev" +var Debug bool + +func init() { + if BuiltBy == "dev" { + Debug = true + } +} diff --git a/langsrv/handler-completion.go b/langsrv/handler-completion.go index 95bd58d..677764c 100644 --- a/langsrv/handler-completion.go +++ b/langsrv/handler-completion.go @@ -25,7 +25,8 @@ func textDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa } switch contextReferenceType { case parser.TYPE_NODE_FUNCTION_DECLARATION, "function_body", parser.TYPE_NODE_FUNCTION_LITERAL, - parser.TYPE_NODE_SOURCE_FILE: + parser.TYPE_NODE_SOURCE_FILE, + parser.TYPE_NODE_MEMBER_ACCESS, ".": insertAsStatement = true case parser.TYPE_NODE_ARRAY_LITERAL, parser.TYPE_NODE_BINARY_EXPRESSION, @@ -36,16 +37,21 @@ func textDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa completionItems := []protocol.CompletionItem{} switch targetNode.Type() { - case parser.TYPE_NODE_IMPORT_DECLARATION: + case parser.TYPE_NODE_IMPORT_DECLARATION, "import": kind := protocol.CompletionItemKindModule mods, err := ls.resolver.ImportableModules(rc.module.Package()) if err != nil { return nil, err } for _, mod := range mods { + insertText := string(mod.RelativeName) + if targetNode.Type() == "import" { + insertText = fmt.Sprintf("import %s", insertText) + } completionItems = append(completionItems, protocol.CompletionItem{ - Label: string(mod.RelativeName), - Kind: &kind, + Label: "import " + string(mod.RelativeName), + InsertText: &insertText, + Kind: &kind, Documentation: &protocol.MarkupContent{ Kind: protocol.MarkupKindMarkdown, Value: fmt.Sprintf("`import %s`", mod.RelativeName), @@ -123,6 +129,21 @@ func (rc *ReqContext) keywordCompletionItems(asStatement bool) []protocol.Comple Detail: &detail, } completionItems = append(completionItems, item) + + kind := protocol.CompletionItemKindModule + mods, _ := ls.resolver.ImportableModules(rc.module.Package()) + for _, mod := range mods { + insertText := fmt.Sprintf("import %s", string(mod.RelativeName)) + completionItems = append(completionItems, protocol.CompletionItem{ + Label: "import " + string(mod.RelativeName), + InsertText: &insertText, + Kind: &kind, + Documentation: &protocol.MarkupContent{ + Kind: protocol.MarkupKindMarkdown, + Value: fmt.Sprintf("`import %s`", mod.RelativeName), + }, + }) + } } { insertFormat := protocol.InsertTextFormatSnippet @@ -208,11 +229,36 @@ func (rc *ReqContext) textDocumentMemberAccessCompletionItems(context *glsp.Cont accessedExpr := accessedNode.Content([]byte(rc.textDocumentEntry.item.Text)) for _, imported := range defaultScope { switch decl := imported.decl.(type) { + case ast.DeclImport: + if string(decl.DeclName()) != accessedExpr { + continue + } + // TODO: support imported module + moduleDecls, err := rc.moduleDeclarationsForImportDecl(decl) + if err != nil { + return nil, err + } + scope := make([]importedDecl, 0) + for _, moduleDecl := range moduleDecls { + if !moduleDecl.IsExportedDecl() { + continue + } + scope = append(scope, importedDecl{decl: moduleDecl, module: rc.textDocumentEntry.module, importDecl: nil}) + } + + var completionItems []protocol.CompletionItem + for _, imported := range scope { + completionItems = append( + completionItems, + rc.generalCompletionItemsForDecl(imported, asStatement)..., + ) + } + return completionItems, nil case ast.DeclModule: if string(decl.DeclName()) != accessedExpr { continue } - moduleDecls := rc.moduleDeclarations() + moduleDecls := rc.currentModuleDeclarations() scope := make([]importedDecl, 0) for _, moduleDecl := range moduleDecls { if !moduleDecl.IsExportedDecl() { @@ -293,7 +339,7 @@ func (rc *ReqContext) generalCompletionItemsForDecl(imported importedDecl, asSta func (rc *ReqContext) memberAccessCompletionItemsForDecl(imported importedDecl, accessedExpr string, asStatement bool) []protocol.CompletionItem { switch decl := imported.decl.(type) { case ast.DeclModule: - moduleDecls := rc.moduleDeclarations() + moduleDecls := rc.currentModuleDeclarations() importedDecls := make([]importedDecl, 0, len(moduleDecls)) for _, moduleDecl := range moduleDecls { if !moduleDecl.IsExportedDecl() { diff --git a/langsrv/req-context.go b/langsrv/req-context.go index 97f021e..3401b28 100644 --- a/langsrv/req-context.go +++ b/langsrv/req-context.go @@ -86,7 +86,7 @@ func (rc *ReqContext) globalAndModuleDeclarations(context *glsp.Context) []impor } globals := make([]importedDecl, 0) - for _, moduleDecl := range rc.moduleDeclarations() { + for _, moduleDecl := range rc.currentModuleDeclarations() { globals = append(globals, importedDecl{decl: moduleDecl, module: rc.textDocumentEntry.module, importDecl: nil}) } globals = append(globals, rc.importedDeclarations(context)...) @@ -101,7 +101,7 @@ func (rc *ReqContext) sourceFileDeclarations() []ast.Decl { return rc.sourceFile.Declarations } -func (rc *ReqContext) moduleDeclarations() []ast.Decl { +func (rc *ReqContext) currentModuleDeclarations() []ast.Decl { if rc.sourceFile == nil { return nil } @@ -121,6 +121,30 @@ func (rc *ReqContext) moduleDeclarations() []ast.Decl { return globalDeclarations } +func (rc *ReqContext) moduleDeclarationsForImportDecl(importDecl ast.DeclImport) ([]ast.Decl, error) { + if rc.sourceFile == nil { + return nil, nil + } + resolvedModule, err := ls.resolver.ResolveModuleFromPackage(rc.module.Package(), importDecl.ModuleName) + if err != nil { + return nil, err + } + globalDeclarations := make([]ast.Decl, 0) + for _, sameModuleFile := range resolvedModule.Files { + fileUrl := "file://" + sameModuleFile + if rc.item.URI == fileUrl { + continue + } + docEntry := ls.documentCache.documents[fileUrl] + if docEntry == nil || docEntry.sourceFile == nil { + continue + } + + globalDeclarations = append(globalDeclarations, docEntry.sourceFile.ExportedDeclarations()...) + } + return globalDeclarations, nil +} + type importedDecl struct { decl ast.Decl module resolution.ResolvedModule