diff --git a/internal/ls/lsconv/converters.go b/internal/ls/lsconv/converters.go index 1caf5da494a..1035d38e852 100644 --- a/internal/ls/lsconv/converters.go +++ b/internal/ls/lsconv/converters.go @@ -300,9 +300,16 @@ func diagnosticToLSP(ctx context.Context, converters *Converters, diagnostic *as var tags []lsproto.DiagnosticTag if len(opts.tagValueSet) > 0 && (diagnostic.ReportsUnnecessary() || diagnostic.ReportsDeprecated()) { - tags = make([]lsproto.DiagnosticTag, 0, 2) + tags = make([]lsproto.DiagnosticTag, 0, 3) if diagnostic.ReportsUnnecessary() && slices.Contains(opts.tagValueSet, lsproto.DiagnosticTagUnnecessary) { tags = append(tags, lsproto.DiagnosticTagUnnecessary) + // Visual Studio's LSP client only renders Unnecessary diagnostics as + // faded-out text when they also carry the VS-internal HiddenInEditor + // tag; otherwise they appear as a regular squiggle. Emit it so VS + // matches the LSP-spec intent of the Unnecessary tag. + if opts.visualStudio { + tags = append(tags, lsproto.DiagnosticTagVsHiddenInEditor) + } } if diagnostic.ReportsDeprecated() && slices.Contains(opts.tagValueSet, lsproto.DiagnosticTagDeprecated) { tags = append(tags, lsproto.DiagnosticTagDeprecated) diff --git a/internal/lsp/lsproto/_generate/generate.mts b/internal/lsp/lsproto/_generate/generate.mts index 33b6c7bf3fe..61a6f2cd318 100755 --- a/internal/lsp/lsproto/_generate/generate.mts +++ b/internal/lsp/lsproto/_generate/generate.mts @@ -1112,6 +1112,22 @@ function patchAndPreprocessModel() { (reg as any).isRegistrationOnly = !allRequestMethods.has(reg.registrationMethod); } + // Add Visual Studio-specific DiagnosticTag values. + // These are VS-internal extensions not part of the LSP spec. They use sentinel + // values near int32.MaxValue to avoid collisions with future standard additions. + // Servers should only emit them when the client advertises + // _vs_supportsVisualStudioExtensions. + const diagnosticTagEnum = model.enumerations.find(e => e.name === "DiagnosticTag"); + if (diagnosticTagEnum) { + diagnosticTagEnum.values.push( + { + name: "VSHiddenInEditor", + value: 2147483641, // int32.MaxValue - 6 + documentation: "Visual Studio-specific tag: the diagnostic is not rendered with a squiggle in the editor. When combined with Unnecessary, Visual Studio renders the code as faded-out text rather than a squiggle.", + }, + ); + } + // Merge LSPErrorCodes into ErrorCodes and remove LSPErrorCodes const errorCodesEnum = model.enumerations.find(e => e.name === "ErrorCodes"); const lspErrorCodesEnum = model.enumerations.find(e => e.name === "LSPErrorCodes"); diff --git a/internal/lsp/lsproto/lsp_generated.go b/internal/lsp/lsproto/lsp_generated.go index 9acd888fa10..4f0d3013d57 100644 --- a/internal/lsp/lsproto/lsp_generated.go +++ b/internal/lsp/lsproto/lsp_generated.go @@ -30674,18 +30674,27 @@ const ( // // Clients are allowed to rendered diagnostics with this tag strike through. DiagnosticTagDeprecated DiagnosticTag = 2 + // Visual Studio-specific tag: the diagnostic is not rendered with a squiggle in the editor. When combined with Unnecessary, Visual Studio renders the code as faded-out text rather than a squiggle. + DiagnosticTagVsHiddenInEditor DiagnosticTag = 2147483641 ) -const _DiagnosticTag_name = "UnnecessaryDeprecated" +const _DiagnosticTag_name = "UnnecessaryDeprecatedVsHiddenInEditor" -var _DiagnosticTag_index = [...]uint16{0, 11, 21} +var ( + _DiagnosticTag_index_0 = [...]uint16{0, 11, 21} + _DiagnosticTag_index_1 = [...]uint16{0, 16} +) func (e DiagnosticTag) String() string { - i := int(e) - 1 - if i < 0 || i >= len(_DiagnosticTag_index)-1 { + switch { + case 1 <= e && e <= 2: + i := int(e) - 1 + return _DiagnosticTag_name[0+_DiagnosticTag_index_0[i] : 0+_DiagnosticTag_index_0[i+1]] + case e == 2147483641: + return _DiagnosticTag_name[21:37] + default: return fmt.Sprintf("DiagnosticTag(%d)", e) } - return _DiagnosticTag_name[_DiagnosticTag_index[i]:_DiagnosticTag_index[i+1]] } // How a completion was triggered