diff --git a/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go b/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go new file mode 100644 index 0000000000000..63607c844cc15 --- /dev/null +++ b/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" + "github.com/microsoft/TypeScript/tsc/internal/testutil" + "github.com/microsoft/TypeScript/tsc/internal/testutil/contentmappertest" +) + +func TestContentMapperInlayHints(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // original: (+ 1 2 "oops") + // virtual: add(1, 2, "oops"); + // [-) [) [) [----) mapped spans + f, done := newContentMapperFourslash(t, `// @Filename: /app.lisp +(+ 1 2 "oops") + +// @Filename: /main.ts +declare function add(a: number, b: number, c: string): number; +`, contentmappertest.LispMapper, ".lisp") + defer done() + + f.GoToFile(t, "/app.lisp") + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) +} diff --git a/tsc/internal/ls/inlay_hints.go b/tsc/internal/ls/inlay_hints.go index 0864f8df361e7..ab1b04646ac42 100644 --- a/tsc/internal/ls/inlay_hints.go +++ b/tsc/internal/ls/inlay_hints.go @@ -12,6 +12,7 @@ import ( "github.com/microsoft/TypeScript/tsc/internal/core" "github.com/microsoft/TypeScript/tsc/internal/debug" "github.com/microsoft/TypeScript/tsc/internal/evaluator" + "github.com/microsoft/TypeScript/tsc/internal/json" "github.com/microsoft/TypeScript/tsc/internal/ls/lsconv" "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto" @@ -37,6 +38,10 @@ func (l *LanguageService) ProvideInlayHint( mappedRanges := l.converters.FromLSPRangeIntersectingForSourceFile(file, params.Range, spanmap.FeatureInlayHints) result := make([]*lsproto.InlayHint, 0, len(mappedRanges)) + var seen map[string]struct{} + if len(mappedRanges) > 1 { + seen = make(map[string]struct{}) + } for _, mapped := range mappedRanges { projection := mapped.Script checker, done := program.GetTypeCheckerForFile(ctx, projection) @@ -51,7 +56,22 @@ func (l *LanguageService) ProvideInlayHint( converters: l.converters, } inlayHintState.visit(projection.AsNode()) - result = append(result, inlayHintState.result...) + if seen == nil { + result = append(result, inlayHintState.result...) + continue + } + for _, hint := range inlayHintState.result { + encoded, err := json.Marshal(hint) + if err != nil { + return lsproto.InlayHintsOrNull{}, err + } + key := string(encoded) + if _, ok := seen[key]; ok { + continue + } + seen[key] = struct{}{} + result = append(result, hint) + } } return lsproto.InlayHintsOrNull{InlayHints: &result}, nil } diff --git a/tsc/testdata/baselines/reference/fourslash/inlayHints/contentMapperInlayHints.baseline b/tsc/testdata/baselines/reference/fourslash/inlayHints/contentMapperInlayHints.baseline new file mode 100644 index 0000000000000..8ffd06588c5bb --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/inlayHints/contentMapperInlayHints.baseline @@ -0,0 +1,96 @@ +// === Inlay Hints === +(+ 1 2 "oops") + ^ +{ + "position": { + "line": 0, + "character": 3 + }, + "label": [ + { + "value": "a", + "location": { + "uri": "file:///main.ts", + "range": { + "start": { + "line": 0, + "character": 21 + }, + "end": { + "line": 0, + "character": 22 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +(+ 1 2 "oops") + ^ +{ + "position": { + "line": 0, + "character": 5 + }, + "label": [ + { + "value": "b", + "location": { + "uri": "file:///main.ts", + "range": { + "start": { + "line": 0, + "character": 32 + }, + "end": { + "line": 0, + "character": 33 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} + +(+ 1 2 "oops") + ^ +{ + "position": { + "line": 0, + "character": 7 + }, + "label": [ + { + "value": "c", + "location": { + "uri": "file:///main.ts", + "range": { + "start": { + "line": 0, + "character": 43 + }, + "end": { + "line": 0, + "character": 44 + } + } + } + }, + { + "value": ":" + } + ], + "kind": 2, + "paddingRight": true +} \ No newline at end of file