From 04196d8a1ff235c235ced882198b18ca2ab229e6 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Sun, 25 Jan 2026 15:21:38 +0100 Subject: [PATCH] Implement better completion --- internal/lsp/server.go | 4 +- specification.md | 4 + .../lsp_completion_signals_robustness_test.go | 90 +++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 test/lsp_completion_signals_robustness_test.go diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 8a9178e..cd2d68a 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -646,8 +646,8 @@ func suggestGAMSignals(container *index.ProjectNode, direction string) *Completi classPath := cue.ParsePath(fmt.Sprintf("#Classes.%s.direction", cls)) val := GlobalSchema.Value.LookupPath(classPath) if val.Err() == nil { - s, err := val.String() - if err == nil { + var s string + if err := val.Decode(&s); err == nil { dir = s } } diff --git a/specification.md b/specification.md index 4c5f713..d6f1b71 100644 --- a/specification.md +++ b/specification.md @@ -34,6 +34,10 @@ The LSP server should provide the following capabilities: - **Reference Suggestions**: - `DataSource` fields suggest available DataSource objects. - `Functions` (in Threads) suggest available GAM objects. + - **Signal Completion**: Inside `InputSignals` or `OutputSignals` of a GAM: + - Suggests available signals from valid DataSources (filtering by direction: `IN`/`INOUT` for Inputs, `OUT`/`INOUT` for Outputs). + - Format: `SIGNAL_NAME:DATASOURCE_NAME`. + - Auto-inserts: `SIGNAL_NAME = { DataSource = DATASOURCE_NAME }`. - **Rename Symbol**: Rename an object, field, or reference across the entire project scope. - Supports renaming of Definitions (`+Name` or `Name`), preserving any modifiers (`+`/`$`). - Updates all references to the renamed symbol, including qualified references (e.g., `Pkg.Name`). diff --git a/test/lsp_completion_signals_robustness_test.go b/test/lsp_completion_signals_robustness_test.go new file mode 100644 index 0000000..f1dd0b5 --- /dev/null +++ b/test/lsp_completion_signals_robustness_test.go @@ -0,0 +1,90 @@ +package integration + +import ( + "testing" + + "github.com/marte-community/marte-dev-tools/internal/index" + "github.com/marte-community/marte-dev-tools/internal/lsp" + "github.com/marte-community/marte-dev-tools/internal/parser" + "github.com/marte-community/marte-dev-tools/internal/schema" +) + +func TestSuggestSignalsRobustness(t *testing.T) { + // Setup + lsp.Tree = index.NewProjectTree() + lsp.Documents = make(map[string]string) + lsp.ProjectRoot = "." + lsp.GlobalSchema = schema.NewSchema() + + // Inject schema with INOUT + custom := []byte(` +package schema +#Classes: { + InOutReader: { direction: "INOUT" } +} +`) + val := lsp.GlobalSchema.Context.CompileBytes(custom) + lsp.GlobalSchema.Value = lsp.GlobalSchema.Value.Unify(val) + + content := ` ++DS = { + Class = InOutReader + +Signals = { + Sig = { Type = uint32 } + } +} ++GAM = { + Class = IOGAM + +InputSignals = { + + } + +OutputSignals = { + + } +} +` + uri := "file://robust.marte" + lsp.Documents[uri] = content + p := parser.NewParser(content) + cfg, err := p.Parse() + if err != nil { + t.Fatal(err) + } + lsp.Tree.AddFile("robust.marte", cfg) + + // Check Input (Line 10) + paramsIn := lsp.CompletionParams{ + TextDocument: lsp.TextDocumentIdentifier{URI: uri}, + Position: lsp.Position{Line: 10, Character: 8}, + } + listIn := lsp.HandleCompletion(paramsIn) + found := false + if listIn != nil { + for _, item := range listIn.Items { + if item.Label == "Sig:DS" { + found = true + } + } + } + if !found { + t.Error("INOUT signal not found in InputSignals") + } + + // Check Output (Line 13) + paramsOut := lsp.CompletionParams{ + TextDocument: lsp.TextDocumentIdentifier{URI: uri}, + Position: lsp.Position{Line: 13, Character: 8}, + } + listOut := lsp.HandleCompletion(paramsOut) + found = false + if listOut != nil { + for _, item := range listOut.Items { + if item.Label == "Sig:DS" { + found = true + } + } + } + if !found { + t.Error("INOUT signal not found in OutputSignals") + } +}