diff --git a/language-server-protocol.sha.txt b/language-server-protocol.sha.txt index d5c0e5030..353255758 100644 --- a/language-server-protocol.sha.txt +++ b/language-server-protocol.sha.txt @@ -1,4 +1,4 @@ -- This is the last commit we caught up with https://github.com/Microsoft/language-server-protocol/commits/gh-pages -lastSha: 0e116448e3b3f4ce0b983768c045dba0a41b6a72 +lastSha: ed36538a180f15d33ffb03365fba4ace47b42d68 -https://github.com/Microsoft/language-server-protocol/compare/0e116448e3b3f4ce0b983768c045dba0a41b6a72..gh-pages +https://github.com/Microsoft/language-server-protocol/compare/ed36538a180f15d33ffb03365fba4ace47b42d68..gh-pages diff --git a/src/Client/LanguageClientServiceCollectionExtensions.cs b/src/Client/LanguageClientServiceCollectionExtensions.cs index 2e52710e8..8859456e9 100644 --- a/src/Client/LanguageClientServiceCollectionExtensions.cs +++ b/src/Client/LanguageClientServiceCollectionExtensions.cs @@ -72,7 +72,7 @@ internal static IContainer AddLanguageClientInternals(this IContainer container, var providedConfiguration = options.Services.FirstOrDefault(z => z.ServiceType == typeof(IConfiguration) && z.ImplementationInstance is IConfiguration); container.RegisterDelegate( _ => { - var builder = new ConfigurationBuilder(); + var builder = options.ConfigurationBuilder; var outerConfiguration = outerServiceProvider?.GetService(); if (outerConfiguration != null) { diff --git a/src/Dap.Protocol/Serialization/DapContractResolver.cs b/src/Dap.Protocol/Serialization/DapContractResolver.cs index 116f07d56..b6bf7fc4e 100644 --- a/src/Dap.Protocol/Serialization/DapContractResolver.cs +++ b/src/Dap.Protocol/Serialization/DapContractResolver.cs @@ -17,6 +17,7 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ ) { property.NullValueHandling = NullValueHandling.Ignore; + property.DefaultValueHandling = DefaultValueHandling.Ignore; } return property; diff --git a/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs b/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs index 63d5b123d..b58432394 100644 --- a/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs +++ b/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs @@ -146,7 +146,7 @@ HashSet additionalUsings var attribute = interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute"); if (attribute.ConstructorArguments.Length < 2) { - cacheDiagnostic( static c => Diagnostic.Create(GeneratorDiagnostics.MissingDirection, c.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation())); + cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.MissingDirection, c.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation())); yield break; } @@ -344,10 +344,10 @@ public static string GetRequestMethodName(TypeDeclarationSyntax syntax, INamedTy if ( name.StartsWith("Run") || name.StartsWith("Execute") - // TODO: Change this next breaking change - // || name.StartsWith("Set") - // || name.StartsWith("Attach") - // || name.StartsWith("Read") + || name.StartsWith("Set") + || name.StartsWith("Attach") + || name.StartsWith("Launch") + || name.StartsWith("Read") || name.StartsWith("Did") || name.StartsWith("Log") || name.StartsWith("Show") diff --git a/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs b/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs index a086a2f8d..d9f2aea76 100644 --- a/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs +++ b/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs @@ -34,7 +34,6 @@ ReportCacheDiagnostic cacheDiagnostic var textDocumentRegistrationOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.ITextDocumentRegistrationOptions")!; var workDoneProgressOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions")!; - // TODO: var staticRegistrationOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IStaticRegistrationOptions")!; foreach (var registrationOptions in syntaxReceiver.RegistrationOptions) diff --git a/src/Protocol/Client/Capabilities/ClientCapabilities.cs b/src/Protocol/Client/Capabilities/ClientCapabilities.cs index b2eeb30c1..de0ac5ecc 100644 --- a/src/Protocol/Client/Capabilities/ClientCapabilities.cs +++ b/src/Protocol/Client/Capabilities/ClientCapabilities.cs @@ -48,24 +48,12 @@ public class GeneralClientCapabilities /// [Optional] public RegularExpressionsClientCapabilities? RegularExpressions { get; set; } - } - - /// - /// Client capabilities specific to regular expressions. - /// - /// @since 3.16.0 - proposed state - /// - public class RegularExpressionsClientCapabilities - { - /// - /// The engine's name. - /// - public string Engine { get; set; } = null!; /// - /// The engine's version. + /// Client capabilities specific to the client's markdown parser. + /// + /// @since 3.16.0 - proposed state /// - [Optional] - public string? Version { get; set; } + [Optional] public MarkdownClientCapabilities? Markdown { get; set; } } } diff --git a/src/Protocol/Client/Capabilities/MarkdownClientCapabilities.cs b/src/Protocol/Client/Capabilities/MarkdownClientCapabilities.cs new file mode 100644 index 000000000..409e78746 --- /dev/null +++ b/src/Protocol/Client/Capabilities/MarkdownClientCapabilities.cs @@ -0,0 +1,23 @@ +using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; + +namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities +{ + /// + /// Client capabilities specific to the used markdown parser. + /// + /// @since 3.16.0 - proposed state + /// + public record MarkdownClientCapabilities + { + /// + /// The name of the parser. + /// + public string Parser { get; set; } + + /// + /// The version of the parser. + /// + [Optional] + public string? Version { get; set; } + } +} diff --git a/src/Protocol/Client/Capabilities/RegularExpressionsClientCapabilities.cs b/src/Protocol/Client/Capabilities/RegularExpressionsClientCapabilities.cs new file mode 100644 index 000000000..19a4af8f0 --- /dev/null +++ b/src/Protocol/Client/Capabilities/RegularExpressionsClientCapabilities.cs @@ -0,0 +1,23 @@ +using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; + +namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities +{ + /// + /// Client capabilities specific to regular expressions. + /// + /// @since 3.16.0 - proposed state + /// + public class RegularExpressionsClientCapabilities + { + /// + /// The engine's name. + /// + public string Engine { get; set; } = null!; + + /// + /// The engine's version. + /// + [Optional] + public string? Version { get; set; } + } +} diff --git a/src/Protocol/Client/Capabilities/WorkspaceEditCapability.cs b/src/Protocol/Client/Capabilities/WorkspaceEditCapability.cs index ff5876474..55c0d7fa5 100644 --- a/src/Protocol/Client/Capabilities/WorkspaceEditCapability.cs +++ b/src/Protocol/Client/Capabilities/WorkspaceEditCapability.cs @@ -37,5 +37,14 @@ public class WorkspaceEditCapability : ICapability /// [Optional] public bool NormalizesLineEndings { get; set; } + + /// + /// Whether the client in general supports change annotations on text edits, + /// create file, rename file and delete file changes. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + public bool ChangeAnnotationSupport { get; set; } } } diff --git a/src/Protocol/Features/Document/CodeActionFeature.cs b/src/Protocol/Features/Document/CodeActionFeature.cs index cdd173760..584b77306 100644 --- a/src/Protocol/Features/Document/CodeActionFeature.cs +++ b/src/Protocol/Features/Document/CodeActionFeature.cs @@ -302,6 +302,7 @@ public partial class CodeActionRegistrationOptions : IWorkDoneProgressOptions, I /// /// @since 3.16.0 /// + [Optional] public bool ResolveProvider { get; set; } class CodeActionRegistrationOptionsConverter : RegistrationOptionsConverterBase @@ -324,113 +325,113 @@ public override StaticOptions Convert(CodeActionRegistrationOptions source) } } - /// - /// A set of predefined code action kinds - /// - [DebuggerDisplay("{" + nameof(_value) + "}")] - [JsonConverter(typeof(EnumLikeStringConverter))] - public readonly struct CodeActionKind : IEquatable, IEnumLikeString - { - private static readonly Lazy> _defaults = - new Lazy>( - () => { - return typeof(CodeActionKind) - .GetFields(BindingFlags.Static | BindingFlags.Public) - .Select(z => z.GetValue(null)) - .Cast() - .ToArray(); - } - ); - - public static IEnumerable Defaults => _defaults.Value; - /// - /// Base kind for quickfix actions: '' + /// A set of predefined code action kinds /// - public static readonly CodeActionKind Empty = new CodeActionKind(""); + [DebuggerDisplay("{" + nameof(_value) + "}")] + [JsonConverter(typeof(EnumLikeStringConverter))] + public readonly struct CodeActionKind : IEquatable, IEnumLikeString + { + private static readonly Lazy> _defaults = + new Lazy>( + () => { + return typeof(CodeActionKind) + .GetFields(BindingFlags.Static | BindingFlags.Public) + .Select(z => z.GetValue(null)) + .Cast() + .ToArray(); + } + ); + + public static IEnumerable Defaults => _defaults.Value; - /// - /// Base kind for quickfix actions: 'quickfix' - /// - public static readonly CodeActionKind QuickFix = new CodeActionKind("quickfix"); + /// + /// Base kind for quickfix actions: '' + /// + public static readonly CodeActionKind Empty = new CodeActionKind(""); - /// - /// Base kind for refactoring actions: 'refactor' - /// - public static readonly CodeActionKind Refactor = new CodeActionKind("refactor"); + /// + /// Base kind for quickfix actions: 'quickfix' + /// + public static readonly CodeActionKind QuickFix = new CodeActionKind("quickfix"); - /// - /// Base kind for refactoring extraction actions: 'refactor.extract' - /// - /// Example extract actions: - /// - /// - Extract method - /// - Extract function - /// - Extract variable - /// - Extract interface from class - /// - ... - /// - public static readonly CodeActionKind RefactorExtract = new CodeActionKind("refactor.extract"); + /// + /// Base kind for refactoring actions: 'refactor' + /// + public static readonly CodeActionKind Refactor = new CodeActionKind("refactor"); - /// - /// Base kind for refactoring inline actions: 'refactor.inline' - /// - /// Example inline actions: - /// - /// - Inline function - /// - Inline variable - /// - Inline constant - /// - ... - /// - public static readonly CodeActionKind RefactorInline = new CodeActionKind("refactor.inline"); + /// + /// Base kind for refactoring extraction actions: 'refactor.extract' + /// + /// Example extract actions: + /// + /// - Extract method + /// - Extract function + /// - Extract variable + /// - Extract interface from class + /// - ... + /// + public static readonly CodeActionKind RefactorExtract = new CodeActionKind("refactor.extract"); - /// - /// Base kind for refactoring rewrite actions: 'refactor.rewrite' - /// - /// Example rewrite actions: - /// - /// - Convert JavaScript function to class - /// - Add or remove parameter - /// - Encapsulate field - /// - Make method static - /// - Move method to base class - /// - ... - /// - public static readonly CodeActionKind RefactorRewrite = new CodeActionKind("refactor.rewrite"); + /// + /// Base kind for refactoring inline actions: 'refactor.inline' + /// + /// Example inline actions: + /// + /// - Inline function + /// - Inline variable + /// - Inline constant + /// - ... + /// + public static readonly CodeActionKind RefactorInline = new CodeActionKind("refactor.inline"); - /// - /// Base kind for source actions: `source` - /// - /// Source code actions apply to the entire file. - /// - public static readonly CodeActionKind Source = new CodeActionKind("source"); + /// + /// Base kind for refactoring rewrite actions: 'refactor.rewrite' + /// + /// Example rewrite actions: + /// + /// - Convert JavaScript function to class + /// - Add or remove parameter + /// - Encapsulate field + /// - Make method static + /// - Move method to base class + /// - ... + /// + public static readonly CodeActionKind RefactorRewrite = new CodeActionKind("refactor.rewrite"); - /// - /// Base kind for an organize imports source action: `source.organizeImports` - /// - public static readonly CodeActionKind SourceOrganizeImports = new CodeActionKind("source.organizeImports"); + /// + /// Base kind for source actions: `source` + /// + /// Source code actions apply to the entire file. + /// + public static readonly CodeActionKind Source = new CodeActionKind("source"); + + /// + /// Base kind for an organize imports source action: `source.organizeImports` + /// + public static readonly CodeActionKind SourceOrganizeImports = new CodeActionKind("source.organizeImports"); - private readonly string? _value; + private readonly string? _value; - public CodeActionKind(string kind) => _value = kind; + public CodeActionKind(string kind) => _value = kind; - public static implicit operator CodeActionKind(string kind) => new CodeActionKind(kind); + public static implicit operator CodeActionKind(string kind) => new CodeActionKind(kind); - public static implicit operator string(CodeActionKind kind) => kind._value ?? string.Empty; + public static implicit operator string(CodeActionKind kind) => kind._value ?? string.Empty; - /// - public override string ToString() => _value ?? string.Empty; + /// + public override string ToString() => _value ?? string.Empty; - public bool Equals(CodeActionKind other) => _value == other._value; + public bool Equals(CodeActionKind other) => _value == other._value; - public override bool Equals(object obj) => obj is CodeActionKind other && Equals(other); + public override bool Equals(object obj) => obj is CodeActionKind other && Equals(other); - public override int GetHashCode() => _value != null ? _value.GetHashCode() : 0; + public override int GetHashCode() => _value != null ? _value.GetHashCode() : 0; - public static bool operator ==(CodeActionKind left, CodeActionKind right) => left.Equals(right); + public static bool operator ==(CodeActionKind left, CodeActionKind right) => left.Equals(right); - public static bool operator !=(CodeActionKind left, CodeActionKind right) => !left.Equals(right); - } + public static bool operator !=(CodeActionKind left, CodeActionKind right) => !left.Equals(right); + } } namespace Client.Capabilities @@ -479,6 +480,18 @@ public partial class CodeActionCapability : DynamicCapability, ConnectedCapabili /// [Optional] public CodeActionCapabilityResolveSupportOptions? ResolveSupport { get; set; } + + /// + /// Whether th client honors the change annotations in + /// text edits and resource operations returned via the + /// `CodeAction#edit` property by for example presenting + /// the workspace edit in the user interface and asking + /// for confirmation. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + public bool HonorsChangeAnnotations { get; set; } } public class CodeActionLiteralSupportOptions diff --git a/src/Protocol/Features/Document/CompletionFeature.cs b/src/Protocol/Features/Document/CompletionFeature.cs index 761529f7d..aa1dd79ba 100644 --- a/src/Protocol/Features/Document/CompletionFeature.cs +++ b/src/Protocol/Features/Document/CompletionFeature.cs @@ -177,11 +177,8 @@ public partial record CompletionItem : ICanBeResolved, IRequest /// /// @since 3.16.0 additional type `InsertReplaceEdit` - proposed state /// - /// - /// TODO: Update this to union - /// [Optional] - public TextEdit? TextEdit { get; init; } + public TextEditOrInsertReplaceEdit? TextEdit { get; init; } /// /// An optional array of additional text edits that are applied when diff --git a/src/Protocol/Features/Document/FoldingRangeFeature.cs b/src/Protocol/Features/Document/FoldingRangeFeature.cs index 135aba9cd..f9135e488 100644 --- a/src/Protocol/Features/Document/FoldingRangeFeature.cs +++ b/src/Protocol/Features/Document/FoldingRangeFeature.cs @@ -45,39 +45,35 @@ public partial record FoldingRange /// The zero-based line number from where the folded range starts. /// /// - /// TODO: UPDATE THIS next version /// in the LSP spec /// - public long StartLine { get; init; } + public int StartLine { get; init; } /// /// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. /// /// - /// TODO: UPDATE THIS next version /// in the LSP spec /// [Optional] - public long? StartCharacter { get; init; } + public int? StartCharacter { get; init; } /// /// The zero-based line number where the folded range ends. /// /// - /// TODO: UPDATE THIS next version /// in the LSP spec /// - public long EndLine { get; init; } + public int EndLine { get; init; } /// /// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. /// /// - /// TODO: UPDATE THIS next version /// in the LSP spec /// [Optional] - public long? EndCharacter { get; init; } + public int? EndCharacter { get; init; } /// /// Describes the kind of the folding range such as `comment' or 'region'. The kind diff --git a/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs b/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs index 52233d92f..68b65ecc2 100644 --- a/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs +++ b/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs @@ -629,7 +629,7 @@ private void EnsureTokenModifiers() => public static readonly SemanticTokenType Enum = new SemanticTokenType("enum"); public static readonly SemanticTokenType TypeParameter = new SemanticTokenType("typeParameter"); public static readonly SemanticTokenType Function = new SemanticTokenType("function"); - public static readonly SemanticTokenType Member = new SemanticTokenType("member"); + public static readonly SemanticTokenType Method = new SemanticTokenType("method"); public static readonly SemanticTokenType Property = new SemanticTokenType("property"); public static readonly SemanticTokenType Macro = new SemanticTokenType("macro"); public static readonly SemanticTokenType Variable = new SemanticTokenType("variable"); diff --git a/src/Protocol/Features/Document/RenameFeature.cs b/src/Protocol/Features/Document/RenameFeature.cs index 98b6b8c14..dfed3f0b5 100644 --- a/src/Protocol/Features/Document/RenameFeature.cs +++ b/src/Protocol/Features/Document/RenameFeature.cs @@ -173,7 +173,29 @@ public class RenameCapability : DynamicCapability, ConnectedCapability [Optional] - public bool PrepareSupportDefaultBehavior { get; set; } + public PrepareSupportDefaultBehavior PrepareSupportDefaultBehavior { get; set; } + + /// + /// Whether th client honors the change annotations in + /// text edits and resource operations returned via the + /// `CodeAction#edit` property by for example presenting + /// the workspace edit in the user interface and asking + /// for confirmation. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + public bool HonorsChangeAnnotations { get; set; } + } + + + public enum PrepareSupportDefaultBehavior + { + /// + /// The client's default behavior is to select the identifier + /// according the to language's syntax rule. + /// + Identifier = 1 } } diff --git a/src/Protocol/Features/Document/TextDocumentSyncFeature.cs b/src/Protocol/Features/Document/TextDocumentSyncFeature.cs index 838c44617..34aaecc22 100644 --- a/src/Protocol/Features/Document/TextDocumentSyncFeature.cs +++ b/src/Protocol/Features/Document/TextDocumentSyncFeature.cs @@ -34,7 +34,7 @@ public partial record DidChangeTextDocumentParams : IRequest /// to the version after all provided content changes have /// been applied. /// - public VersionedTextDocumentIdentifier TextDocument { get; init; } + public OptionalVersionedTextDocumentIdentifier TextDocument { get; init; } /// /// The actual content changes. @@ -87,11 +87,14 @@ public record TextDocumentEdit /// /// The text document to change. /// - public VersionedTextDocumentIdentifier TextDocument { get; init; } + public OptionalVersionedTextDocumentIdentifier TextDocument { get; init; } /// /// The edits to be applied. /// + /// + /// This can contain both and + /// public TextEditContainer Edits { get; init; } } @@ -150,9 +153,6 @@ public partial class DidSaveTextDocumentParams : ITextDocumentIdentifierParams, /// /// The document that was saved. /// - /// - /// TODO: Change to RequiredVersionedTextDocumentIdentifier (or in the future will be VersionedTextDocumentIdentifier) - /// public TextDocumentIdentifier TextDocument { get; set; } = null!; /// diff --git a/src/Protocol/Features/Window/WorkDoneProgressFeature.cs b/src/Protocol/Features/Window/WorkDoneProgressFeature.cs index 586dbe2da..e5f8f86d2 100644 --- a/src/Protocol/Features/Window/WorkDoneProgressFeature.cs +++ b/src/Protocol/Features/Window/WorkDoneProgressFeature.cs @@ -146,11 +146,10 @@ public WorkDoneProgressBegin() : base(WorkDoneProgressKind.Begin) /// that are not following this rule. /// /// - /// TODO: Change this (breaking) /// in the LSP spec /// [Optional] - public double? Percentage { get; init; } + public int? Percentage { get; init; } } /// @@ -196,11 +195,10 @@ public WorkDoneProgressReport() : base(WorkDoneProgressKind.Report) /// that are not following this rule. /// /// - /// TODO: Change this (breaking) /// in the LSP spec /// [Optional] - public double? Percentage { get; set; } + public int? Percentage { get; set; } } } diff --git a/src/Protocol/LanguageProtocolRpcOptionsBase.cs b/src/Protocol/LanguageProtocolRpcOptionsBase.cs index f5ccd4732..0e51b85b5 100644 --- a/src/Protocol/LanguageProtocolRpcOptionsBase.cs +++ b/src/Protocol/LanguageProtocolRpcOptionsBase.cs @@ -34,6 +34,7 @@ public T AddTextDocumentIdentifier() where TI : ITextDocumentIdentifier } public ISerializer Serializer { get; set; } = new LspSerializer(ClientVersion.Lsp3); + public ConfigurationBuilder ConfigurationBuilder { get; set; } = new ConfigurationBuilder(); internal bool AddDefaultLoggingProvider { get; set; } internal Action? LoggingBuilderAction { get; set; } = _ => { }; internal Action? ConfigurationBuilderAction { get; set; } = _ => { }; diff --git a/src/Protocol/Models/BooleanNumberString.cs b/src/Protocol/Models/BooleanNumberString.cs index a40722caf..36a31f850 100644 --- a/src/Protocol/Models/BooleanNumberString.cs +++ b/src/Protocol/Models/BooleanNumberString.cs @@ -6,39 +6,39 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Models [JsonConverter(typeof(BooleanNumberStringConverter))] public struct BooleanNumberString { - private long? _long; + private int? _int; private string? _string; private bool? _bool; - public BooleanNumberString(long value) + public BooleanNumberString(int value) { - _long = value; + _int = value; _string = null; _bool = null; } public BooleanNumberString(string value) { - _long = null; + _int = null; _string = value; _bool = null; } public BooleanNumberString(bool value) { - _long = null; + _int = null; _string = null; _bool = value; } - public bool IsLong => _long.HasValue; + public bool IsInteger => _int.HasValue; - public long Long + public int Integer { - get => _long ?? 0; + get => _int ?? 0; set { _string = null; - _long = value; + _int = value; _bool = null; } } @@ -50,7 +50,7 @@ public string String get => _string ?? string.Empty; set { _string = value; - _long = null; + _int = null; _bool = null; } } @@ -62,12 +62,12 @@ public bool Bool get => _bool.HasValue && _bool.Value; set { _string = null; - _long = null; + _int = null; _bool = value; } } - public static implicit operator BooleanNumberString(long value) => new BooleanNumberString(value); + public static implicit operator BooleanNumberString(int value) => new BooleanNumberString(value); public static implicit operator BooleanNumberString(string value) => new BooleanNumberString(value); diff --git a/src/Protocol/Models/CreateFile.cs b/src/Protocol/Models/CreateFile.cs index 8e36f990c..f526bedd8 100644 --- a/src/Protocol/Models/CreateFile.cs +++ b/src/Protocol/Models/CreateFile.cs @@ -22,5 +22,13 @@ public record CreateFile : IFile /// [Optional] public CreateFileOptions? Options { get; init; } + + /// + /// An optional annotation describing the operation. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + public ChangeAnnotation? Annotation { get; init; } } } diff --git a/src/Protocol/Models/DeleteFile.cs b/src/Protocol/Models/DeleteFile.cs index 1e39ccb89..0b30f2094 100644 --- a/src/Protocol/Models/DeleteFile.cs +++ b/src/Protocol/Models/DeleteFile.cs @@ -22,5 +22,13 @@ public record DeleteFile : IFile /// [Optional] public DeleteFileOptions? Options { get; init; } + + /// + /// An optional annotation describing the operation. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + public ChangeAnnotation? Annotation { get; init; } } } diff --git a/src/Protocol/Models/FormattingOptions.cs b/src/Protocol/Models/FormattingOptions.cs index ef12199e6..be9246ddf 100644 --- a/src/Protocol/Models/FormattingOptions.cs +++ b/src/Protocol/Models/FormattingOptions.cs @@ -13,13 +13,12 @@ public class FormattingOptions : Dictionary /// Size of a tab in spaces. /// /// - /// TODO: UPDATE THIS next version /// in the LSP spec /// [JsonIgnore] - public long TabSize + public int TabSize { - get => TryGetValue("tabSize", out var tabSize) && tabSize.IsLong ? tabSize.Long : -1; + get => TryGetValue("tabSize", out var tabSize) && tabSize.IsInteger ? tabSize.Integer : -1; set => this["tabSize"] = value; } diff --git a/src/Protocol/Models/IFile.cs b/src/Protocol/Models/IFile.cs index 4aa1df1cb..891a083b7 100644 --- a/src/Protocol/Models/IFile.cs +++ b/src/Protocol/Models/IFile.cs @@ -1,7 +1,17 @@ +using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; + namespace OmniSharp.Extensions.LanguageServer.Protocol.Models { public interface IFile { ResourceOperationKind Kind { get; } + + /// + /// An optional annotation describing the operation. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + ChangeAnnotation? Annotation { get; init; } } } diff --git a/src/Protocol/Models/InsertReplaceEdit.cs b/src/Protocol/Models/InsertReplaceEdit.cs deleted file mode 100644 index 98a81c6b2..000000000 --- a/src/Protocol/Models/InsertReplaceEdit.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Diagnostics; - -namespace OmniSharp.Extensions.LanguageServer.Protocol.Models -{ - /// - /// A special text edit to provide an insert and a replace operation. - /// - /// @since 3.16.0 - proposed state - /// - [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - public record InsertReplaceEdit - { - /// - /// The string to be inserted. - /// - public string NewText { get; init; } - - /// - /// The range if the insert is requested - /// - public Range Insert { get; init; } - - /// - /// The range if the replace is requested. - /// - public Range Replace { get; init; } - - private string DebuggerDisplay => $"{Insert} / {Replace} {( string.IsNullOrWhiteSpace(NewText) ? string.Empty : NewText.Length > 30 ? NewText.Substring(0, 30) : NewText )}"; - - /// - public override string ToString() => DebuggerDisplay; - } -} diff --git a/src/Protocol/Models/OptionalVersionedTextDocumentIdentifier.cs b/src/Protocol/Models/OptionalVersionedTextDocumentIdentifier.cs index 7b95038b5..3c864b78f 100644 --- a/src/Protocol/Models/OptionalVersionedTextDocumentIdentifier.cs +++ b/src/Protocol/Models/OptionalVersionedTextDocumentIdentifier.cs @@ -3,9 +3,8 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Models { - // TODO: Rename to confirm with spec OptionalVersionedTextDocumentIdentifier [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - public record VersionedTextDocumentIdentifier : TextDocumentIdentifier + public record OptionalVersionedTextDocumentIdentifier : TextDocumentIdentifier { /// /// The version number of this document. diff --git a/src/Protocol/Models/RenameFile.cs b/src/Protocol/Models/RenameFile.cs index 4e2df586c..5a43c6c56 100644 --- a/src/Protocol/Models/RenameFile.cs +++ b/src/Protocol/Models/RenameFile.cs @@ -27,5 +27,13 @@ public record RenameFile : IFile /// [Optional] public RenameFileOptions? Options { get; init; } + + /// + /// An optional annotation describing the operation. + /// + /// @since 3.16.0 - proposed state + /// + [Optional] + public ChangeAnnotation? Annotation { get; init; } } } diff --git a/src/Protocol/Models/TextEdit.cs b/src/Protocol/Models/TextEdit.cs index e7e569336..5c5e2707c 100644 --- a/src/Protocol/Models/TextEdit.cs +++ b/src/Protocol/Models/TextEdit.cs @@ -1,9 +1,13 @@ using System.Diagnostics; +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Generation; +using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; +using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters; namespace OmniSharp.Extensions.LanguageServer.Protocol.Models { [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] + [JsonConverter(typeof(TextEditConverter))] [GenerateContainer] public record TextEdit { @@ -24,4 +28,144 @@ public record TextEdit /// public override string ToString() => DebuggerDisplay; } + + /// + /// A special text edit to provide an insert and a replace operation. + /// + /// @since 3.16.0 - proposed state + /// + [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] + public record InsertReplaceEdit + { + /// + /// The string to be inserted. + /// + public string NewText { get; init; } + + /// + /// The range if the insert is requested + /// + public Range Insert { get; init; } + + /// + /// The range if the replace is requested. + /// + public Range Replace { get; init; } + + private string DebuggerDisplay => $"{Insert} / {Replace} {( string.IsNullOrWhiteSpace(NewText) ? string.Empty : NewText.Length > 30 ? NewText.Substring(0, 30) : NewText )}"; + + /// + public override string ToString() => DebuggerDisplay; + } + + [JsonConverter(typeof(TextEditOrInsertReplaceEditConverter))] + [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] + [GenerateContainer] + public record TextEditOrInsertReplaceEdit + { + private TextEdit? _textEdit; + private InsertReplaceEdit? _insertReplaceEdit; + + public TextEditOrInsertReplaceEdit(TextEdit value) + { + _textEdit = value; + _insertReplaceEdit = default; + } + + public TextEditOrInsertReplaceEdit(InsertReplaceEdit value) + { + _textEdit = default; + _insertReplaceEdit = value; + } + + public bool IsInsertReplaceEdit => _insertReplaceEdit != null; + + public InsertReplaceEdit? InsertReplaceEdit + { + get => _insertReplaceEdit; + set { + _insertReplaceEdit = value; + _textEdit = null; + } + } + + public bool IsTextEdit => _textEdit != null; + + public TextEdit? TextEdit + { + get => _textEdit; + set { + _insertReplaceEdit = default; + _textEdit = value; + } + } + + public object? RawValue + { + get { + if (IsTextEdit) return TextEdit!; + if (IsInsertReplaceEdit) return InsertReplaceEdit!; + return default; + } + } + + public static TextEditOrInsertReplaceEdit From(TextEdit value) => new(value); + public static implicit operator TextEditOrInsertReplaceEdit(TextEdit value) => new(value); + + public static TextEditOrInsertReplaceEdit From(InsertReplaceEdit value) => new(value); + public static implicit operator TextEditOrInsertReplaceEdit(InsertReplaceEdit value) => new(value); + + private string DebuggerDisplay => $"{( IsInsertReplaceEdit ? $"insert: {InsertReplaceEdit}" : IsTextEdit ? $"edit: {TextEdit}" : "..." )}"; + + /// + public override string ToString() => DebuggerDisplay; + } + + /// + /// Additional information that describes document changes. + /// + /// @since 3.16.0 - proposed state + /// + public record ChangeAnnotation + { + /// + /// A human-readable string describing the actual change. The string + /// is rendered prominent in the user interface. + /// + public string Label { get; init; } + + /// + /// A flag which indicates that user confirmation is needed + /// before applying the change. + /// + [Optional] + public bool NeedsConfirmation { get; init; } + + /// + /// A human-readable string which is rendered less prominent in + /// the user interface. + /// + [Optional] + public string? Description { get; init; } + } + + /// + /// A special text edit with an additional change annotation. + /// + /// @since 3.16.0 - proposed state. + /// + [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] + [JsonConverter(typeof(TextEditConverter))] + public record AnnotatedTextEdit : TextEdit + { + /// + /// The actual annotation + /// + public ChangeAnnotation Annotation { get; init; } + + private string DebuggerDisplay => $"annotated: {Range} {( string.IsNullOrWhiteSpace(NewText) ? string.Empty : NewText.Length > 30 ? NewText.Substring(0, 30) : NewText )}"; + + /// + public override string ToString() => DebuggerDisplay; + } } diff --git a/src/Protocol/Models/VersionedTextDocumentIdentifier.cs b/src/Protocol/Models/VersionedTextDocumentIdentifier.cs index 3be0e8031..577d16c2b 100644 --- a/src/Protocol/Models/VersionedTextDocumentIdentifier.cs +++ b/src/Protocol/Models/VersionedTextDocumentIdentifier.cs @@ -3,9 +3,8 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Models { - // TODO: Rename to confirm with spec VersionedTextDocumentIdentifier [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - public record RequiredVersionedTextDocumentIdentifier : TextDocumentIdentifier + public record VersionedTextDocumentIdentifier : TextDocumentIdentifier { /// /// The version number of this document. diff --git a/src/Protocol/Protocol.csproj b/src/Protocol/Protocol.csproj index 6a21a818a..252cc622a 100644 --- a/src/Protocol/Protocol.csproj +++ b/src/Protocol/Protocol.csproj @@ -9,49 +9,12 @@ - - - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - MSBuild:GenerateCodeFromAttributes - - - - - - diff --git a/src/Protocol/Serialization/Converters/BooleanNumberStringConverter.cs b/src/Protocol/Serialization/Converters/BooleanNumberStringConverter.cs index 96a0f0452..173c7537b 100644 --- a/src/Protocol/Serialization/Converters/BooleanNumberStringConverter.cs +++ b/src/Protocol/Serialization/Converters/BooleanNumberStringConverter.cs @@ -9,7 +9,7 @@ internal class BooleanNumberStringConverter : JsonConverter public override void WriteJson(JsonWriter writer, BooleanNumberString value, JsonSerializer serializer) { if (value.IsBool) serializer.Serialize(writer, value.Bool); - else if (value.IsLong) serializer.Serialize(writer, value.Long); + else if (value.IsInteger) serializer.Serialize(writer, value.Integer); else if (value.IsString) serializer.Serialize(writer, value.String); else writer.WriteNull(); } @@ -18,7 +18,7 @@ public override BooleanNumberString ReadJson(JsonReader reader, Type objectType, { if (reader.TokenType == JsonToken.Integer) { - return new BooleanNumberString((long) reader.Value); + return new BooleanNumberString(Convert.ToInt32((long)reader.Value)); } if (reader.TokenType == JsonToken.String) diff --git a/src/Protocol/Serialization/Converters/TextEditConverter.cs b/src/Protocol/Serialization/Converters/TextEditConverter.cs new file mode 100644 index 000000000..1eb8c7db6 --- /dev/null +++ b/src/Protocol/Serialization/Converters/TextEditConverter.cs @@ -0,0 +1,58 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; + +namespace OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters +{ + public class TextEditConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, TextEdit value, JsonSerializer serializer) + { + writer.WriteStartObject(); + writer.WritePropertyName("range"); + serializer.Serialize(writer, value.Range); + writer.WritePropertyName("newText"); + serializer.Serialize(writer, value.NewText); + if (value is AnnotatedTextEdit annotatedTextEdit) + { + writer.WritePropertyName("annotation"); + serializer.Serialize(writer, annotatedTextEdit.Annotation); + } + + writer.WriteEndObject(); + } + + public override TextEdit ReadJson(JsonReader reader, Type objectType, TextEdit existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var result = JObject.Load(reader); + var isAnnotated = result.ContainsKey("annotation"); + TextEdit edit; + if (result["annotation"] is { Type: JTokenType.Object } annotation) + { + edit = new AnnotatedTextEdit() { + Annotation = annotation.ToObject() + }; + } + else + { + edit = new TextEdit(); + } + + if (result["range"] is { Type: JTokenType.Object } range) + { + edit = edit with { Range = range.ToObject()}; + } + + if (result["newText"] is { Type: JTokenType.String } newText) + { + edit = edit with { NewText = newText.Value()}; + } + + return edit; + } + + public override bool CanRead => true; + } +} diff --git a/src/Protocol/Serialization/Converters/TextEditOrInsertReplaceEditConverter.cs b/src/Protocol/Serialization/Converters/TextEditOrInsertReplaceEditConverter.cs new file mode 100644 index 000000000..eaf924c05 --- /dev/null +++ b/src/Protocol/Serialization/Converters/TextEditOrInsertReplaceEditConverter.cs @@ -0,0 +1,42 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; + +namespace OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters +{ + public class TextEditOrInsertReplaceEditConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, TextEditOrInsertReplaceEdit value, JsonSerializer serializer) + { + if (value.IsTextEdit) + { + serializer.Serialize(writer, value.TextEdit); + } + else if (value.IsInsertReplaceEdit) + { + serializer.Serialize(writer, value.InsertReplaceEdit); + } + else + { + writer.WriteNull(); + } + } + + public override TextEditOrInsertReplaceEdit ReadJson(JsonReader reader, Type objectType, TextEditOrInsertReplaceEdit existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var result = JObject.Load(reader); + + // InsertReplaceEdit have a name, TextEdits do not + var command = result["insert"]; + if (command?.Type == JTokenType.String) + { + return new TextEditOrInsertReplaceEdit(result.ToObject()); + } + + return new TextEditOrInsertReplaceEdit(result.ToObject()); + } + + public override bool CanRead => true; + } +} diff --git a/src/Protocol/Serialization/LspContractResolver.cs b/src/Protocol/Serialization/LspContractResolver.cs index e9003c193..05d91c7ae 100644 --- a/src/Protocol/Serialization/LspContractResolver.cs +++ b/src/Protocol/Serialization/LspContractResolver.cs @@ -82,6 +82,7 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ ) { property.NullValueHandling = NullValueHandling.Ignore; + property.DefaultValueHandling = DefaultValueHandling.Ignore; } if (typeof(ISupports).IsAssignableFrom(property.PropertyType)) @@ -152,20 +153,6 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ } } - // TODO: Registration needs to be switched around to pass in the capability -// if (property.DeclaringType == typeof(SemanticTokensLegend)) -// { -// if (property.PropertyName == nameof(SemanticTokensLegend.TokenModifiers) && _semanticTokenModifier is { Length: > 0 }) -// { -// property.ValueProvider = new ArrayRangeValueProvider(property.ValueProvider, _semanticTokenModifier); -// } -// -// if (property.PropertyName == nameof(SemanticTokensLegend.TokenTypes) && _semanticTokenType is { Length: > 0 }) -// { -// property.ValueProvider = new ArrayRangeValueProvider(property.ValueProvider, _semanticTokenType); -// } -// } - return property; } diff --git a/src/Protocol/Server/WorkDone/IWorkDoneObserver.cs b/src/Protocol/Server/WorkDone/IWorkDoneObserver.cs index 343f6af42..a33e09b59 100644 --- a/src/Protocol/Server/WorkDone/IWorkDoneObserver.cs +++ b/src/Protocol/Server/WorkDone/IWorkDoneObserver.cs @@ -6,6 +6,6 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Server.WorkDone public interface IWorkDoneObserver : IObserver, IDisposable { ProgressToken WorkDoneToken { get; } - void OnNext(string message, double? percentage, bool? cancellable); + void OnNext(string message, int? percentage, bool? cancellable); } } diff --git a/src/Protocol/Server/WorkDone/NoopWorkDoneObserver.cs b/src/Protocol/Server/WorkDone/NoopWorkDoneObserver.cs index 453a406bf..a42294088 100644 --- a/src/Protocol/Server/WorkDone/NoopWorkDoneObserver.cs +++ b/src/Protocol/Server/WorkDone/NoopWorkDoneObserver.cs @@ -25,7 +25,7 @@ public void OnNext(WorkDoneProgress value) public ProgressToken WorkDoneToken { get; } = new ProgressToken("Noop"); - public void OnNext(string message, double? percentage, bool? cancellable) + public void OnNext(string message, int? percentage, bool? cancellable) { } diff --git a/src/Protocol/Server/WorkDone/WorkDoneObserver.cs b/src/Protocol/Server/WorkDone/WorkDoneObserver.cs index d31301a13..92a8f4f4b 100644 --- a/src/Protocol/Server/WorkDone/WorkDoneObserver.cs +++ b/src/Protocol/Server/WorkDone/WorkDoneObserver.cs @@ -50,7 +50,7 @@ public void OnNext(WorkDoneProgress value) => _router.SendNotification( public ProgressToken WorkDoneToken { get; } - public void OnNext(string message, double? percentage, bool? cancellable) => + public void OnNext(string message, int? percentage, bool? cancellable) => OnNext( new WorkDoneProgressReport { Cancellable = cancellable ?? false, diff --git a/src/Protocol/ServiceConfigurationExtensions.cs b/src/Protocol/ServiceConfigurationExtensions.cs new file mode 100644 index 000000000..1a36a41bf --- /dev/null +++ b/src/Protocol/ServiceConfigurationExtensions.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace OmniSharp.Extensions.LanguageServer.Protocol +{ + public static class ServiceConfigurationExtensions + { + /// + /// Registers a injected configuration service which TOptions will bind against. + /// + /// The type of options being configured. + /// The to add the services to. + /// The so that additional calls can be chained. + public static IServiceCollection Configure(this IServiceCollection services) + where TOptions : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + return Configure(services, null); + } + + /// + /// Registers a injected configuration service which TOptions will bind against. + /// + /// The type of options being configured. + /// The to add the services to. + /// The name of the options instance. + /// The so that additional calls can be chained. + public static IServiceCollection Configure(this IServiceCollection services, string? sectionName) + where TOptions : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddOptions(); + services.AddSingleton>( + _ => new ConfigurationChangeTokenSource( + Options.DefaultName, + sectionName == null ? _.GetRequiredService() : _.GetRequiredService().GetSection(sectionName) + ) + ); + return services.AddSingleton>( + _ => new NamedConfigureFromConfigurationOptions( + Options.DefaultName, + sectionName == null ? _.GetRequiredService() : _.GetRequiredService().GetSection(sectionName) + ) + ); + } + } +} diff --git a/src/Server/LanguageServer.cs b/src/Server/LanguageServer.cs index dd6abe414..145a55d61 100644 --- a/src/Server/LanguageServer.cs +++ b/src/Server/LanguageServer.cs @@ -51,6 +51,7 @@ public partial class LanguageServer : JsonRpcServerBase, ILanguageServer, ILangu private readonly IEnumerable _initializedHandlers; private readonly IEnumerable _registrationOptionsConverters; private readonly InstanceHasStarted _instanceHasStarted; + private readonly LanguageServerLoggingManager _languageServerLoggingManager; private readonly IEnumerable _startedDelegates; private readonly IEnumerable _startedHandlers; private readonly ISubject _initializeComplete = new AsyncSubject(); @@ -149,7 +150,8 @@ internal LanguageServer( ILanguageServerWorkspaceFolderManager workspaceFolderManager, IEnumerable initializeHandlers, IEnumerable initializedHandlers, IEnumerable registrationOptionsConverters, - InstanceHasStarted instanceHasStarted + InstanceHasStarted instanceHasStarted, + LanguageServerLoggingManager languageServerLoggingManager ) : base(handlerCollection, responseRouter) { Configuration = configuration; @@ -181,6 +183,7 @@ InstanceHasStarted instanceHasStarted _initializedHandlers = initializedHandlers; _registrationOptionsConverters = registrationOptionsConverters; _instanceHasStarted = instanceHasStarted; + _languageServerLoggingManager = languageServerLoggingManager; _concurrency = options.Value.Concurrency; _capabilityTypes = options @@ -327,23 +330,7 @@ public Task Handle(InitializedParams @params, CancellationToken token) private void ConfigureServerLogging(InternalInitializeParams internalInitializeParams) { - if (internalInitializeParams.Trace == InitializeTrace.Verbose) - { - var loggerSettings = Services.GetService(); - - if (loggerSettings?.MinimumLogLevel <= LogLevel.Information) - { - loggerSettings.MinimumLogLevel = LogLevel.Trace; - } - - var optionsMonitor = Services.GetService>() as LanguageServerLoggerFilterOptions; - - if (optionsMonitor?.CurrentValue.MinLevel <= LogLevel.Information) - { - optionsMonitor.CurrentValue.MinLevel = LogLevel.Trace; - optionsMonitor.Set(optionsMonitor.CurrentValue); - } - } + _languageServerLoggingManager.SetTrace(internalInitializeParams.Trace); } private ClientCapabilities ReadClientCapabilities( diff --git a/src/Server/LanguageServerServiceCollectionExtensions.cs b/src/Server/LanguageServerServiceCollectionExtensions.cs index 56e669892..20c0b16ea 100644 --- a/src/Server/LanguageServerServiceCollectionExtensions.cs +++ b/src/Server/LanguageServerServiceCollectionExtensions.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -76,7 +77,7 @@ internal static IContainer AddLanguageServerInternals(this IContainer container, var providedConfiguration = options.Services.FirstOrDefault(z => z.ServiceType == typeof(IConfiguration) && z.ImplementationInstance is IConfiguration); container.RegisterDelegate( _ => { - var builder = new ConfigurationBuilder(); + var builder = options.ConfigurationBuilder; var didChangeConfigurationProvider = _.GetRequiredService(); var outerConfiguration = outerServiceProvider?.GetService(); if (outerConfiguration != null) @@ -94,7 +95,7 @@ internal static IContainer AddLanguageServerInternals(this IContainer container, Reuse.Singleton ); - container.RegisterMany(serviceTypeCondition: type => type.IsInterface, reuse: Reuse.Singleton); + container.RegisterMany(nonPublicServiceTypes: true, reuse: Reuse.Singleton); container.RegisterInstance( options.ServerInfo ?? new ServerInfo { Name = Assembly.GetEntryAssembly()?.GetName().Name ?? string.Empty, diff --git a/src/Server/Logging/LanguageServerLogger.cs b/src/Server/Logging/LanguageServerLogger.cs index 02be65d3c..4ae08fc86 100644 --- a/src/Server/Logging/LanguageServerLogger.cs +++ b/src/Server/Logging/LanguageServerLogger.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reactive.Disposables; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; @@ -14,27 +15,22 @@ internal class LanguageServerLogger : ILogger { private readonly ILanguageServerFacade _responseRouter; private readonly string _categoryName; - private readonly Func _logLevelGetter; - public LanguageServerLogger(ILanguageServerFacade responseRouter, string categoryName, Func logLevelGetter) - { - _logLevelGetter = logLevelGetter; + public LanguageServerLogger(ILanguageServerFacade responseRouter, string categoryName) + {; _responseRouter = responseRouter; _categoryName = categoryName; } public IDisposable BeginScope(TState state) => new CompositeDisposable(); - public bool IsEnabled(LogLevel logLevel) => logLevel >= _logLevelGetter(); + public bool IsEnabled(LogLevel logLevel) => true; public void Log( LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter ) { - if (logLevel < _logLevelGetter()) - return; - if (TryGetMessageType(logLevel, out var messageType)) { _responseRouter.Window.Log( diff --git a/src/Server/Logging/LanguageServerLoggerExtensions.cs b/src/Server/Logging/LanguageServerLoggerExtensions.cs index 88a51ea06..47b046cae 100644 --- a/src/Server/Logging/LanguageServerLoggerExtensions.cs +++ b/src/Server/Logging/LanguageServerLoggerExtensions.cs @@ -8,24 +8,7 @@ public static class LanguageServerLoggerExtensions { public static ILoggingBuilder AddLanguageProtocolLogging(this ILoggingBuilder builder) { - builder.Services.AddSingleton( - services => { - var filterOptions = services.GetService>(); - - return new LanguageServerLoggerSettings { MinimumLogLevel = filterOptions.Value.MinLevel }; - } - ); - builder.Services.AddSingleton(); - - return builder; - } - - public static ILoggingBuilder AddLanguageProtocolLogging(this ILoggingBuilder builder, LogLevel minLevel) - { - builder.Services.AddSingleton(_ => new LanguageServerLoggerSettings { MinimumLogLevel = minLevel }); - builder.Services.AddSingleton(); - return builder; } } diff --git a/src/Server/Logging/LanguageServerLoggerFilterOptions.cs b/src/Server/Logging/LanguageServerLoggerFilterOptions.cs deleted file mode 100644 index c00635730..000000000 --- a/src/Server/Logging/LanguageServerLoggerFilterOptions.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace OmniSharp.Extensions.LanguageServer.Server.Logging -{ - internal class LanguageServerLoggerFilterOptions : IOptionsMonitor, IDisposable - { - private event Action? _onChange; - - public LanguageServerLoggerFilterOptions(IOptions options) => CurrentValue = options.Value; - - public LoggerFilterOptions CurrentValue { get; private set; } - - public LoggerFilterOptions Get(string _) => CurrentValue; - - public IDisposable OnChange(Action listener) - { - var disposable = new ChangeTrackerDisposable(this, listener); - _onChange += disposable.OnChange; - return disposable; - } - - public void Dispose() - { - } - - internal void Set(LoggerFilterOptions options) - { - CurrentValue = options; - _onChange?.Invoke(options, Options.DefaultName); - } - - private class ChangeTrackerDisposable : IDisposable - { - private readonly Action _listener; - private readonly LanguageServerLoggerFilterOptions _monitor; - - public ChangeTrackerDisposable(LanguageServerLoggerFilterOptions monitor, Action listener) - { - _listener = listener; - _monitor = monitor; - } - - public void OnChange(LoggerFilterOptions options, string name) => _listener.Invoke(options, name); - - public void Dispose() => _monitor._onChange -= OnChange; - } - } -} diff --git a/src/Server/Logging/LanguageServerLoggerProvider.cs b/src/Server/Logging/LanguageServerLoggerProvider.cs index 5ac52d8a5..30da89563 100644 --- a/src/Server/Logging/LanguageServerLoggerProvider.cs +++ b/src/Server/Logging/LanguageServerLoggerProvider.cs @@ -1,4 +1,6 @@ +using System.Diagnostics; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace OmniSharp.Extensions.LanguageServer.Server @@ -6,15 +8,13 @@ namespace OmniSharp.Extensions.LanguageServer.Server internal class LanguageServerLoggerProvider : ILoggerProvider { private readonly ILanguageServerFacade _languageServer; - private readonly LanguageServerLoggerSettings _settings; - public LanguageServerLoggerProvider(ILanguageServerFacade languageServer, LanguageServerLoggerSettings settings) + public LanguageServerLoggerProvider(ILanguageServerFacade languageServer) { _languageServer = languageServer; - _settings = settings; } - public ILogger CreateLogger(string categoryName) => new LanguageServerLogger(_languageServer, categoryName, () => _settings.MinimumLogLevel); + public ILogger CreateLogger(string categoryName) => new LanguageServerLogger(_languageServer, categoryName); public void Dispose() { diff --git a/src/Server/Logging/LanguageServerLoggerSettings.cs b/src/Server/Logging/LanguageServerLoggerSettings.cs deleted file mode 100644 index 9aad71435..000000000 --- a/src/Server/Logging/LanguageServerLoggerSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace OmniSharp.Extensions.LanguageServer.Server -{ - internal class LanguageServerLoggerSettings - { - public LogLevel MinimumLogLevel { get; set; } - } -} diff --git a/src/Server/Logging/LanguageServerLoggingManager.cs b/src/Server/Logging/LanguageServerLoggingManager.cs new file mode 100644 index 000000000..efe76e7e3 --- /dev/null +++ b/src/Server/Logging/LanguageServerLoggingManager.cs @@ -0,0 +1,61 @@ +using System; +using System.Reactive.Disposables; +using System.Reactive.Subjects; +using System.Threading; +using System.Threading.Tasks; +using DryIoc; +using MediatR; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; + +namespace OmniSharp.Extensions.LanguageServer.Server.Logging +{ + internal class LanguageServerLoggingManager : ISetTraceHandler, IOptionsChangeTokenSource, IPostConfigureOptions + { + private ConfigurationReloadToken _changeToken; + private InitializeTrace _currentInitializeTrace = InitializeTrace.Off; + + public LanguageServerLoggingManager() + { + _changeToken = new(); + } + + Task IRequestHandler.Handle(SetTraceParams request, CancellationToken cancellationToken) + { + SetTrace(request.Value); + return Unit.Task; + } + + public void SetTrace(InitializeTrace initializeTrace) + { + _currentInitializeTrace = initializeTrace; + RaiseChanged(); + } + + public IChangeToken GetChangeToken() => _changeToken; + + public string Name { get; } = Options.DefaultName; + + public void PostConfigure(string name, LoggerFilterOptions options) + { + options.MinLevel = CalculateOptionsMinLevel(); + } + + private LogLevel CalculateOptionsMinLevel() => + _currentInitializeTrace switch { + InitializeTrace.Off => LogLevel.Warning, + InitializeTrace.Messages => LogLevel.Information, + InitializeTrace.Verbose => LogLevel.Trace, + _ => LogLevel.Trace + }; + + private void RaiseChanged() + { + Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken()).OnReload(); + } + } +} diff --git a/src/Server/Pipelines/SemanticTokensDeltaPipeline.cs b/src/Server/Pipelines/SemanticTokensDeltaPipeline.cs index d26588bd0..f94247c1b 100644 --- a/src/Server/Pipelines/SemanticTokensDeltaPipeline.cs +++ b/src/Server/Pipelines/SemanticTokensDeltaPipeline.cs @@ -11,19 +11,18 @@ namespace OmniSharp.Extensions.LanguageServer.Server.Pipelines [Obsolete(Constants.Proposal)] class SemanticTokensDeltaPipeline : IPipelineBehavior where TRequest : notnull - where TResponse : class? { - public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next) + public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next) { if (request is SemanticTokensParams semanticTokensParams) { var response = await next().ConfigureAwait(false); if (GetResponse(semanticTokensParams, response, out var result) && string.IsNullOrEmpty(result.ResultId)) { - return result with { ResultId = Guid.NewGuid().ToString() } as TResponse; + result = result with { ResultId = Guid.NewGuid().ToString() }; } - return response; + return result is TResponse r ? r : response; } if (request is SemanticTokensDeltaParams semanticTokensDeltaParams) @@ -33,16 +32,15 @@ class SemanticTokensDeltaPipeline : IPipelineBehavior(IRequest request, object? response, [NotNullWhe result = default!; return false; } + + private TR ToResponse(IRequest request, object? response) + { + if (response is TR r) + { + return r; + } + + return default!; + } } } diff --git a/test/Client.Tests/ClientTests.cs b/test/Client.Tests/ClientTests.cs index 6a4200975..bbecfe440 100644 --- a/test/Client.Tests/ClientTests.cs +++ b/test/Client.Tests/ClientTests.cs @@ -186,26 +186,27 @@ public async Task Completions_Success() Assert.Equal(expectedCompletionItem.Label, actualCompletionItem.Label); Assert.NotNull(actualCompletionItem.TextEdit); - Assert.Equal(expectedCompletionItem.TextEdit!.NewText, actualCompletionItem.TextEdit!.NewText); + Assert.True(actualCompletionItem.TextEdit!.IsTextEdit); + Assert.Equal(expectedCompletionItem.TextEdit!.TextEdit!.NewText, actualCompletionItem.TextEdit.TextEdit!.NewText); - Assert.NotNull(actualCompletionItem.TextEdit.Range); - Assert.NotNull(actualCompletionItem.TextEdit.Range.Start); - Assert.NotNull(actualCompletionItem.TextEdit.Range.End); + Assert.NotNull(actualCompletionItem.TextEdit.TextEdit.Range); + Assert.NotNull(actualCompletionItem.TextEdit.TextEdit.Range.Start); + Assert.NotNull(actualCompletionItem.TextEdit.TextEdit.Range.End); Assert.Equal( - expectedCompletionItem.TextEdit.Range.Start.Line, - actualCompletionItem.TextEdit.Range.Start.Line + expectedCompletionItem.TextEdit.TextEdit.Range.Start.Line, + actualCompletionItem.TextEdit.TextEdit.Range.Start.Line ); Assert.Equal( - expectedCompletionItem.TextEdit.Range.Start.Character, - actualCompletionItem.TextEdit.Range.Start.Character + expectedCompletionItem.TextEdit.TextEdit.Range.Start.Character, + actualCompletionItem.TextEdit.TextEdit.Range.Start.Character ); Assert.Equal( - expectedCompletionItem.TextEdit.Range.End.Line, - actualCompletionItem.TextEdit.Range.End.Line + expectedCompletionItem.TextEdit.TextEdit.Range.End.Line, + actualCompletionItem.TextEdit.TextEdit.Range.End.Line ); Assert.Equal( - expectedCompletionItem.TextEdit.Range.End.Character, - actualCompletionItem.TextEdit.Range.End.Character + expectedCompletionItem.TextEdit.TextEdit.Range.End.Character, + actualCompletionItem.TextEdit.TextEdit.Range.End.Character ); } ); diff --git a/test/Dap.Tests/DebugAdapterSpecifictionRecieverTests.cs b/test/Dap.Tests/DebugAdapterSpecifictionRecieverTests.cs index a8dd0fedc..9ea0d05f5 100644 --- a/test/Dap.Tests/DebugAdapterSpecifictionRecieverTests.cs +++ b/test/Dap.Tests/DebugAdapterSpecifictionRecieverTests.cs @@ -44,7 +44,7 @@ public void Should_Camel_Case_As_Expected() } ); - response.Should().Be("{\"supportsConfigurationDoneRequest\":false,\"supportsFunctionBreakpoints\":false,\"supportsConditionalBreakpoints\":false,\"supportsHitConditionalBreakpoints\":false,\"supportsEvaluateForHovers\":false,\"supportsStepBack\":false,\"supportsSetVariable\":false,\"supportsRestartFrame\":false,\"supportsGotoTargetsRequest\":false,\"supportsStepInTargetsRequest\":false,\"supportsCompletionsRequest\":false,\"supportsModulesRequest\":false,\"supportsRestartRequest\":false,\"supportsExceptionOptions\":false,\"supportsValueFormattingOptions\":false,\"supportsExceptionInfoRequest\":false,\"supportTerminateDebuggee\":false,\"supportsDelayedStackTraceLoading\":false,\"supportsLoadedSourcesRequest\":false,\"supportsLogPoints\":false,\"supportsTerminateThreadsRequest\":false,\"supportsSetExpression\":false,\"supportsTerminateRequest\":false,\"supportsDataBreakpoints\":false,\"supportsReadMemoryRequest\":false,\"supportsDisassembleRequest\":false,\"supportsCancelRequest\":true,\"supportsBreakpointLocationsRequest\":false,\"supportsClipboardContext\":false,\"supportsSteppingGranularity\":false,\"supportsInstructionBreakpoints\":false}"); + response.Should().Be(@"{""supportsCancelRequest"":true}"); } private class SpecificationMessages : TheoryData diff --git a/test/Dap.Tests/FoundationTests.cs b/test/Dap.Tests/FoundationTests.cs index df26df821..535440cbc 100644 --- a/test/Dap.Tests/FoundationTests.cs +++ b/test/Dap.Tests/FoundationTests.cs @@ -535,10 +535,10 @@ private static string GetSendMethodName(IHandlerTypeDescriptor descriptor) { var name = SpecialCasedHandlerName(descriptor); if (name.StartsWith("Run") - // TODO: Change this next breaking change - // || name.StartsWith("Set") - // || name.StartsWith("Attach") - // || name.StartsWith("Read") + || name.StartsWith("Set") + || name.StartsWith("Attach") + || name.StartsWith("Launch") + || name.StartsWith("Read") ) { return name; diff --git a/test/Dap.Tests/Integration/CustomRequestsTests.cs b/test/Dap.Tests/Integration/CustomRequestsTests.cs index be0a3c694..e77def44c 100644 --- a/test/Dap.Tests/Integration/CustomRequestsTests.cs +++ b/test/Dap.Tests/Integration/CustomRequestsTests.cs @@ -25,7 +25,7 @@ public async Task Should_Support_Custom_Attach_Request_Using_Base_Class() var fake = Substitute.For>(); var (client, _) = await Initialize(options => { }, options => { options.AddHandler(fake); }); - await client.RequestAttach( + await client.Attach( new CustomAttachRequestArguments { ComputerName = "computer", RunspaceId = "1234", @@ -47,7 +47,7 @@ public async Task Should_Support_Custom_Attach_Request_Receiving_Regular_Request var fake = Substitute.For(); var (client, _) = await Initialize(options => { }, options => { options.AddHandler(fake); }); - await client.RequestAttach( + await client.Attach( new CustomAttachRequestArguments { ComputerName = "computer", RunspaceId = "1234", @@ -69,7 +69,7 @@ public async Task Should_Support_Custom_Attach_Request_Using_Extension_Data_Usin var fake = Substitute.For>(); var (client, _) = await Initialize(options => { }, options => { options.AddHandler(fake); }); - await client.RequestAttach( + await client.Attach( new AttachRequestArguments { ExtensionData = new Dictionary { ["ComputerName"] = "computer", @@ -93,7 +93,7 @@ public async Task Should_Support_Custom_Launch_Request_Using_Base_Class() var fake = Substitute.For>(); var (client, _) = await Initialize(options => { }, options => { options.AddHandler(fake); }); - await client.RequestLaunch( + await client.Launch( new CustomLaunchRequestArguments { Script = "build.ps1" } @@ -111,7 +111,7 @@ public async Task Should_Support_Custom_Launch_Request_Receiving_Regular_Request var fake = Substitute.For(); var (client, _) = await Initialize(options => { }, options => { options.AddHandler(fake); }); - await client.RequestLaunch( + await client.Launch( new CustomLaunchRequestArguments { Script = "build.ps1" } @@ -129,7 +129,7 @@ public async Task Should_Support_Custom_Launch_Request_Using_Extension_Data_Base var fake = Substitute.For>(); var (client, _) = await Initialize(options => { }, options => { options.AddHandler(fake); }); - await client.RequestLaunch( + await client.Launch( new CustomLaunchRequestArguments { ExtensionData = new Dictionary { ["Script"] = "build.ps1" @@ -149,7 +149,7 @@ public async Task Should_Support_Custom_Attach_Request_Using_Delegate() var fake = Substitute.For>>(); var (client, _) = await Initialize(options => { }, options => { options.OnAttach(fake); }); - await client.RequestAttach( + await client.Attach( new CustomAttachRequestArguments { ComputerName = "computer", RunspaceId = "1234", @@ -171,7 +171,7 @@ public async Task Should_Support_Custom_Attach_Request_Receiving_Regular_Request var fake = Substitute.For>>(); var (client, _) = await Initialize(options => { }, options => { options.OnAttach(fake); }); - await client.RequestAttach( + await client.Attach( new CustomAttachRequestArguments { ComputerName = "computer", RunspaceId = "1234", @@ -193,7 +193,7 @@ public async Task Should_Support_Custom_Attach_Request_Using_Extension_Data_Usin var fake = Substitute.For>>(); var (client, _) = await Initialize(options => { }, options => { options.OnAttach(fake); }); - await client.RequestAttach( + await client.Attach( new AttachRequestArguments { ExtensionData = new Dictionary { ["ComputerName"] = "computer", @@ -217,7 +217,7 @@ public async Task Should_Support_Custom_Launch_Request_Using_Delegate() var fake = Substitute.For>>(); var (client, _) = await Initialize(options => { }, options => { options.OnLaunch(fake); }); - await client.RequestLaunch( + await client.Launch( new CustomLaunchRequestArguments { Script = "build.ps1" } @@ -235,7 +235,7 @@ public async Task Should_Support_Custom_Launch_Request_Receiving_Regular_Request var fake = Substitute.For>>(); var (client, _) = await Initialize(options => { }, options => { options.OnLaunch(fake); }); - await client.RequestLaunch( + await client.Launch( new CustomLaunchRequestArguments { Script = "build.ps1" } @@ -253,7 +253,7 @@ public async Task Should_Support_Custom_Launch_Request_Using_Extension_Data_Usin var fake = Substitute.For>>(); var (client, _) = await Initialize(options => { }, options => { options.OnLaunch(fake); }); - await client.RequestLaunch( + await client.Launch( new CustomLaunchRequestArguments { ExtensionData = new Dictionary { ["Script"] = "build.ps1" diff --git a/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs b/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs index 9b824a5c9..70c12efec 100644 --- a/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs +++ b/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs @@ -171,6 +171,7 @@ public partial class CodeActionRegistrationOptions /// /// @since 3.16.0 /// + [Optional] public bool ResolveProvider { get; set; } } } @@ -248,6 +249,7 @@ public Container? CodeActionKinds /// /// @since 3.16.0 /// + [Optional] public bool ResolveProvider { get; @@ -310,6 +312,7 @@ public partial class CodeActionRegistrationOptions : ITextDocumentRegistrationOp /// /// @since 3.16.0 /// + [Optional] public bool ResolveProvider { get; set; } class CodeActionRegistrationOptionsConverter : RegistrationOptionsConverterBase @@ -393,6 +396,7 @@ public Container? CodeActionKinds /// /// @since 3.16.0 /// + [Optional] public bool ResolveProvider { get; diff --git a/test/Generation.Tests/JsonRpcGenerationTests.cs b/test/Generation.Tests/JsonRpcGenerationTests.cs index adfb9e89e..042d4c588 100644 --- a/test/Generation.Tests/JsonRpcGenerationTests.cs +++ b/test/Generation.Tests/JsonRpcGenerationTests.cs @@ -674,7 +674,7 @@ public static IDebugAdapterServerRegistry OnAttachRequest(this IDebugAdapterS where T : AttachRequestArguments => registry.AddHandler(""attach"", RequestHandler.For(handler)); public static IDebugAdapterServerRegistry OnAttachRequest(this IDebugAdapterServerRegistry registry, Func> handler) where T : AttachRequestArguments => registry.AddHandler(""attach"", RequestHandler.For(handler)); - public static Task RequestAttachRequest(this IDebugAdapterClient mediator, AttachRequestArguments request, CancellationToken cancellationToken = default) => mediator.SendRequest(request, cancellationToken); + public static Task AttachRequest(this IDebugAdapterClient mediator, AttachRequestArguments request, CancellationToken cancellationToken = default) => mediator.SendRequest(request, cancellationToken); } #nullable restore }"; @@ -750,7 +750,7 @@ public static IDebugAdapterServerRegistry OnAttachRequest(this IDebugAdapterS where T : AttachRequestArguments => registry.AddHandler(""attach"", RequestHandler.For(handler)); public static IDebugAdapterServerRegistry OnAttachRequest(this IDebugAdapterServerRegistry registry, Func> handler) where T : AttachRequestArguments => registry.AddHandler(""attach"", RequestHandler.For(handler)); - public static Task RequestAttachRequest(this IDebugAdapterClient mediator, AttachRequestArguments request, CancellationToken cancellationToken = default) => mediator.SendRequest(request, cancellationToken); + public static Task AttachRequest(this IDebugAdapterClient mediator, AttachRequestArguments request, CancellationToken cancellationToken = default) => mediator.SendRequest(request, cancellationToken); } #nullable restore }"; @@ -826,7 +826,7 @@ public static IDebugAdapterServerRegistry OnAttachRequest(this IDebugAdapterS where T : AttachRequestArguments => registry.AddHandler(""attach"", RequestHandler.For(handler)); public static IDebugAdapterServerRegistry OnAttachRequest(this IDebugAdapterServerRegistry registry, Func> handler) where T : AttachRequestArguments => registry.AddHandler(""attach"", RequestHandler.For(handler)); - public static Task RequestAttachRequest(this IDebugAdapterClient mediator, AttachRequestArguments request, CancellationToken cancellationToken = default) => mediator.SendRequest(request, cancellationToken); + public static Task AttachRequest(this IDebugAdapterClient mediator, AttachRequestArguments request, CancellationToken cancellationToken = default) => mediator.SendRequest(request, cancellationToken); } #nullable restore }"; diff --git a/test/Lsp.Tests/Capabilities/Client/ClientCapabilitiesTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/ClientCapabilitiesTests_$SimpleTest.json index 126d5014e..ef55c2b1a 100644 --- a/test/Lsp.Tests/Capabilities/Client/ClientCapabilitiesTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/ClientCapabilitiesTests_$SimpleTest.json @@ -2,8 +2,7 @@ "workspace": { "applyEdit": true, "workspaceEdit": { - "documentChanges": true, - "normalizesLineEndings": false + "documentChanges": true }, "didChangeConfiguration": { "dynamicRegistration": true @@ -27,21 +26,14 @@ }, "completion": { "completionItem": { - "snippetSupport": true, - "commitCharactersSupport": false, - "deprecatedSupport": false, - "preselectSupport": false, - "insertReplaceSupport": false, - "resolveAdditionalTextEditsSupport": false + "snippetSupport": true }, - "contextSupport": false, "dynamicRegistration": true }, "hover": { "dynamicRegistration": true }, "signatureHelp": { - "contextSupport": false, "dynamicRegistration": true }, "references": { @@ -51,8 +43,6 @@ "dynamicRegistration": true }, "documentSymbol": { - "hierarchicalDocumentSymbolSupport": false, - "labelSupport": false, "dynamicRegistration": true }, "formatting": { @@ -73,21 +63,15 @@ "dynamicRegistration": true }, "codeAction": { - "isPreferredSupport": false, - "disabledSupport": false, - "dataSupport": false, "dynamicRegistration": true }, "codeLens": { "dynamicRegistration": true }, "documentLink": { - "tooltipSupport": false, "dynamicRegistration": true }, "rename": { - "prepareSupport": false, - "prepareSupportDefaultBehavior": false, "dynamicRegistration": true }, "typeDefinition": { diff --git a/test/Lsp.Tests/Capabilities/Client/CompletionCapabilityTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/CompletionCapabilityTests_$SimpleTest.json index 26781aec2..1862ab505 100644 --- a/test/Lsp.Tests/Capabilities/Client/CompletionCapabilityTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/CompletionCapabilityTests_$SimpleTest.json @@ -1,12 +1,3 @@ { - "completionItem": { - "snippetSupport": false, - "commitCharactersSupport": false, - "deprecatedSupport": false, - "preselectSupport": false, - "insertReplaceSupport": false, - "resolveAdditionalTextEditsSupport": false - }, - "contextSupport": false, - "dynamicRegistration": false + "completionItem": {} } diff --git a/test/Lsp.Tests/Capabilities/Client/CompletionItemCapabilityTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/CompletionItemCapabilityTests_$SimpleTest.json index 923349684..3c16fdc7c 100644 --- a/test/Lsp.Tests/Capabilities/Client/CompletionItemCapabilityTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/CompletionItemCapabilityTests_$SimpleTest.json @@ -1,8 +1,3 @@ { - "snippetSupport": true, - "commitCharactersSupport": false, - "deprecatedSupport": false, - "preselectSupport": false, - "insertReplaceSupport": false, - "resolveAdditionalTextEditsSupport": false + "snippetSupport": true } diff --git a/test/Lsp.Tests/Capabilities/Client/DynamicCapabilityTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/DynamicCapabilityTests_$SimpleTest.json index 2ab72f18b..f11778892 100644 --- a/test/Lsp.Tests/Capabilities/Client/DynamicCapabilityTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/DynamicCapabilityTests_$SimpleTest.json @@ -1,3 +1 @@ -{ - "dynamicRegistration": false -} \ No newline at end of file +{} diff --git a/test/Lsp.Tests/Capabilities/Client/SynchronizationCapabilityTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/SynchronizationCapabilityTests_$SimpleTest.json index f4e709a8f..f11778892 100644 --- a/test/Lsp.Tests/Capabilities/Client/SynchronizationCapabilityTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/SynchronizationCapabilityTests_$SimpleTest.json @@ -1,6 +1 @@ -{ - "willSave": false, - "willSaveWaitUntil": false, - "didSave": false, - "dynamicRegistration": false -} \ No newline at end of file +{} diff --git a/test/Lsp.Tests/Capabilities/Client/TextDocumentClientCapabilitiesTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/TextDocumentClientCapabilitiesTests_$SimpleTest.json index 1937d93fc..1789c208b 100644 --- a/test/Lsp.Tests/Capabilities/Client/TextDocumentClientCapabilitiesTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/TextDocumentClientCapabilitiesTests_$SimpleTest.json @@ -7,21 +7,14 @@ }, "completion": { "completionItem": { - "snippetSupport": true, - "commitCharactersSupport": false, - "deprecatedSupport": false, - "preselectSupport": false, - "insertReplaceSupport": false, - "resolveAdditionalTextEditsSupport": false + "snippetSupport": true }, - "contextSupport": false, "dynamicRegistration": true }, "hover": { "dynamicRegistration": true }, "signatureHelp": { - "contextSupport": false, "dynamicRegistration": true }, "references": { @@ -31,8 +24,6 @@ "dynamicRegistration": true }, "documentSymbol": { - "hierarchicalDocumentSymbolSupport": false, - "labelSupport": false, "dynamicRegistration": true }, "formatting": { @@ -45,25 +36,18 @@ "dynamicRegistration": true }, "definition": { - "linkSupport": false, "dynamicRegistration": true }, "codeAction": { - "isPreferredSupport": false, - "disabledSupport": false, - "dataSupport": false, "dynamicRegistration": true }, "codeLens": { "dynamicRegistration": true }, "documentLink": { - "tooltipSupport": false, "dynamicRegistration": true }, "rename": { - "prepareSupport": false, - "prepareSupportDefaultBehavior": false, "dynamicRegistration": true } } diff --git a/test/Lsp.Tests/Capabilities/Client/WorkspaceClientCapabilitiesTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Client/WorkspaceClientCapabilitiesTests_$SimpleTest.json index 7adc77fbc..30d691678 100644 --- a/test/Lsp.Tests/Capabilities/Client/WorkspaceClientCapabilitiesTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Client/WorkspaceClientCapabilitiesTests_$SimpleTest.json @@ -1,8 +1,7 @@ { "applyEdit": true, "workspaceEdit": { - "documentChanges": true, - "normalizesLineEndings": false + "documentChanges": true }, "didChangeConfiguration": { "dynamicRegistration": true diff --git a/test/Lsp.Tests/Capabilities/Server/CodeActionOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/CodeActionOptionsTests_$SimpleTest.json index 2f8f4e005..f85cf7f19 100644 --- a/test/Lsp.Tests/Capabilities/Server/CodeActionOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/CodeActionOptionsTests_$SimpleTest.json @@ -3,6 +3,5 @@ "quickfix", "refactor" ], - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true } diff --git a/test/Lsp.Tests/Capabilities/Server/CodeLensOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/CodeLensOptionsTests_$SimpleTest.json index ba2c12738..cbd502b19 100644 --- a/test/Lsp.Tests/Capabilities/Server/CodeLensOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/CodeLensOptionsTests_$SimpleTest.json @@ -1,4 +1,3 @@ { - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true } diff --git a/test/Lsp.Tests/Capabilities/Server/CompletionOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/CompletionOptionsTests_$SimpleTest.json index bd56a3326..0967ef424 100644 --- a/test/Lsp.Tests/Capabilities/Server/CompletionOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/CompletionOptionsTests_$SimpleTest.json @@ -1,4 +1 @@ -{ - "resolveProvider": false, - "workDoneProgress": false -} +{} diff --git a/test/Lsp.Tests/Capabilities/Server/DocumentLinkOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/DocumentLinkOptionsTests_$SimpleTest.json index ba2c12738..cbd502b19 100644 --- a/test/Lsp.Tests/Capabilities/Server/DocumentLinkOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/DocumentLinkOptionsTests_$SimpleTest.json @@ -1,4 +1,3 @@ { - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true } diff --git a/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$Optional.json b/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$Optional.json index d93b6c10a..ff797502f 100644 --- a/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$Optional.json +++ b/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$Optional.json @@ -1,4 +1,3 @@ { - "firstTriggerCharacter": ".", - "workDoneProgress": false + "firstTriggerCharacter": "." } diff --git a/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$SimpleTest.json index 8d8d1c6bf..9864f5c51 100644 --- a/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/DocumentOnTypeFormattingOptionsTests_$SimpleTest.json @@ -3,6 +3,5 @@ "moreTriggerCharacter": [ ";", "`" - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Capabilities/Server/ExecuteCommandOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/ExecuteCommandOptionsTests_$SimpleTest.json index 391424851..7c23cc3f6 100644 --- a/test/Lsp.Tests/Capabilities/Server/ExecuteCommandOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/ExecuteCommandOptionsTests_$SimpleTest.json @@ -2,6 +2,5 @@ "commands": [ "command1", "command2" - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Capabilities/Server/SaveOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/SaveOptionsTests_$SimpleTest.json index 1a206b45a..f11778892 100644 --- a/test/Lsp.Tests/Capabilities/Server/SaveOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/SaveOptionsTests_$SimpleTest.json @@ -1,3 +1 @@ -{ - "includeText": false -} \ No newline at end of file +{} diff --git a/test/Lsp.Tests/Capabilities/Server/ServerCapabilitiesTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/ServerCapabilitiesTests_$SimpleTest.json index b23f4abaa..d20a13f2e 100644 --- a/test/Lsp.Tests/Capabilities/Server/ServerCapabilitiesTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/ServerCapabilitiesTests_$SimpleTest.json @@ -15,15 +15,13 @@ "a", "b", "c" - ], - "workDoneProgress": false + ] }, "signatureHelpProvider": { "triggerCharacters": [ ";", " " - ], - "workDoneProgress": false + ] }, "definitionProvider": true, "referencesProvider": true, @@ -32,8 +30,7 @@ "workspaceSymbolProvider": true, "codeActionProvider": true, "codeLensProvider": { - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true }, "documentFormattingProvider": true, "documentRangeFormattingProvider": true, @@ -42,20 +39,17 @@ "moreTriggerCharacter": [ ";", " " - ], - "workDoneProgress": false + ] }, "renameProvider": true, "documentLinkProvider": { - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true }, "executeCommandProvider": { "commands": [ "command1", "command2" - ], - "workDoneProgress": false + ] }, "experimental": { "abc": "123" diff --git a/test/Lsp.Tests/Capabilities/Server/SignatureHelpOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Capabilities/Server/SignatureHelpOptionsTests_$SimpleTest.json index f51d62dd6..4499a91df 100644 --- a/test/Lsp.Tests/Capabilities/Server/SignatureHelpOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Capabilities/Server/SignatureHelpOptionsTests_$SimpleTest.json @@ -2,6 +2,5 @@ "triggerCharacters": [ "1", "2" - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/FluentAssertionsExtensions.cs b/test/Lsp.Tests/FluentAssertionsExtensions.cs index 4c7e47f0d..6c12fb871 100644 --- a/test/Lsp.Tests/FluentAssertionsExtensions.cs +++ b/test/Lsp.Tests/FluentAssertionsExtensions.cs @@ -13,54 +13,6 @@ namespace Lsp.Tests { public static class FluentAssertionsExtensions { - - /// - /// Registers a injected configuration service which TOptions will bind against. - /// - /// The type of options being configured. - /// The to add the services to. - /// The so that additional calls can be chained. - public static IServiceCollection Configure(this IServiceCollection services) - where TOptions : class - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - return Configure(services, null); - } - - /// - /// Registers a injected configuration service which TOptions will bind against. - /// - /// The type of options being configured. - /// The to add the services to. - /// The name of the options instance. - /// The so that additional calls can be chained. - public static IServiceCollection Configure(this IServiceCollection services, string? sectionName) - where TOptions : class - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - services.AddOptions(); - services.AddSingleton>( - _ => new ConfigurationChangeTokenSource( - Options.DefaultName, - sectionName == null ? _.GetRequiredService() : _.GetRequiredService().GetSection(sectionName) - ) - ); - return services.AddSingleton>( - _ => new NamedConfigureFromConfigurationOptions( - Options.DefaultName, - sectionName == null ? _.GetRequiredService() : _.GetRequiredService().GetSection(sectionName) - ) - ); - } - public static EquivalencyAssertionOptions ConfigureForSupports(this EquivalencyAssertionOptions options, ILogger? logger = null) => options .WithTracing(new TraceWriter(logger ?? NullLogger.Instance)) diff --git a/test/Lsp.Tests/FoundationTests.cs b/test/Lsp.Tests/FoundationTests.cs index 2c61dcdc7..7eebd35a1 100644 --- a/test/Lsp.Tests/FoundationTests.cs +++ b/test/Lsp.Tests/FoundationTests.cs @@ -191,13 +191,6 @@ public void HandlersShouldAbstractClass(ILspHandlerTypeDescriptor descriptor) { _logger.LogInformation("Handler: {Type}", descriptor.HandlerType); // This test requires a refactor, the delegating handlers have been removed and replaced by shared implementations - // TODO: - // * Check for extension methods - // * Check for IPartialItem(s)<> extension methods - // * Check that the extension method calls `AddHandler` using the correct eventname - // * check extension method name - // * Also update events to have a nicer fire and forget abstract class - // * Ensure all notifications have an action and task returning function var abstractHandler = descriptor.HandlerType.Assembly.ExportedTypes.FirstOrDefault(z => z.IsAbstract && z.IsClass && descriptor.HandlerType.IsAssignableFrom(z)); abstractHandler.Should().NotBeNull($"{descriptor.HandlerType.FullName} is missing abstract base class"); @@ -224,9 +217,6 @@ public void HandlersShouldExtensionMethodClassWithMethods( ) { // This test requires a refactor, the delegating handlers have been removed and replaced by shared implementations - // TODO: - // * Check for IPartialItem(s)<> extension methods - // * Also update events to have a nicer fire and forget abstract class _logger.LogInformation( "Handler: {Type} {Extension} {ExtensionName} {OnMethod} {SendMethod}", descriptor.HandlerType, @@ -764,6 +754,9 @@ private static string GetSendMethodName(ILspHandlerTypeDescriptor descriptor) var name = SpecialCasedHandlerName(descriptor); if (name.StartsWith("Did") || name.StartsWith("Log") + || name.StartsWith("Set") + || name.StartsWith("Attach") + || name.StartsWith("Launch") || name.StartsWith("Show") || name.StartsWith("Register") || name.StartsWith("Prepare") diff --git a/test/Lsp.Tests/Integration/HandlersManagerIntegrationTests.cs b/test/Lsp.Tests/Integration/HandlersManagerIntegrationTests.cs index 359de119e..906277cf2 100644 --- a/test/Lsp.Tests/Integration/HandlersManagerIntegrationTests.cs +++ b/test/Lsp.Tests/Integration/HandlersManagerIntegrationTests.cs @@ -25,8 +25,8 @@ public async Task Should_Return_Default_Handlers() var (_, server) = await Initialize(options => {}, options => {}); var handlersManager = server.GetRequiredService(); - handlersManager.Descriptors.Should().HaveCount(8); - handlersManager.GetHandlers().Should().HaveCount(5); + handlersManager.Descriptors.Should().HaveCount(9); + handlersManager.GetHandlers().Should().HaveCount(6); } [Fact] @@ -36,8 +36,8 @@ public async Task Should_Return_Additional_Handlers() server.Register(o => o.AddHandler((IJsonRpcHandler) Substitute.For(new[] { typeof (ICompletionHandler), typeof(ICompletionResolveHandler) }, Array.Empty()))); var handlersManager = server.GetRequiredService(); - handlersManager.Descriptors.Should().HaveCount(10); - handlersManager.GetHandlers().Should().HaveCount(6); + handlersManager.Descriptors.Should().HaveCount(11); + handlersManager.GetHandlers().Should().HaveCount(7); } [Fact] diff --git a/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs b/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs index ba2444ea8..f5e518350 100644 --- a/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs +++ b/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs @@ -6,13 +6,17 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Newtonsoft.Json.Linq; using NSubstitute; using NSubstitute.Extensions; using OmniSharp.Extensions.JsonRpc.Testing; using OmniSharp.Extensions.LanguageProtocol.Testing; using OmniSharp.Extensions.LanguageServer.Client; using OmniSharp.Extensions.LanguageServer.Protocol; +using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Extensions.LanguageServer.Protocol.Workspace; using OmniSharp.Extensions.LanguageServer.Server; using Serilog.Events; using TestingUtils; @@ -41,6 +45,20 @@ public async Task Should_Not_Support_Configuration_It_Not_Configured() server.Configuration.AsEnumerable().Should().BeEmpty(); } + [Fact] + public async Task Should_Allow_Null_Response() + { + var (client, server) = await Initialize( + options => { + options.WithCapability(new DidChangeConfigurationCapability()); + options.OnConfiguration(@params => Task.FromResult(new Container(@params.Items.Select(z => (JToken?)null)))); + ConfigureClient(options); + }, ConfigureServer); + + Func a = () => server.Configuration.GetConfiguration(new ConfigurationItem() { Section = "mysection" }); + a.Should().NotThrow(); + } + [Fact] public async Task Should_Update_Configuration_On_Server() { diff --git a/test/Lsp.Tests/Integration/LanguageServerLoggingTests.cs b/test/Lsp.Tests/Integration/LanguageServerLoggingTests.cs index 0090d8b6e..346bfd8f3 100644 --- a/test/Lsp.Tests/Integration/LanguageServerLoggingTests.cs +++ b/test/Lsp.Tests/Integration/LanguageServerLoggingTests.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; @@ -19,21 +21,20 @@ namespace Lsp.Tests.Integration { public class LanguageServerLoggingTests : LanguageProtocolTestBase { - public LanguageServerLoggingTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions()) + public LanguageServerLoggingTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions().WithCancellationTimeout(TimeSpan.FromMinutes(2))) { } - private readonly List _logs = new List(); - [Fact] public async Task Logs_Are_Sent_To_Client_From_Server() { + var logs = new ConcurrentBag(); var (client, server) = await Initialize( - options => { }, + options => { options.Trace = InitializeTrace.Verbose; }, options => { options.ConfigureLogging( z => z - .AddLanguageProtocolLogging(LogLevel.Trace) + .AddLanguageProtocolLogging() .SetMinimumLevel(LogLevel.Trace) ); } @@ -41,7 +42,7 @@ public async Task Logs_Are_Sent_To_Client_From_Server() await SettleNext(); - using var _ = client.Register(r => r.OnLogMessage(x => { _logs.Add(x); })); + using var _ = client.Register(r => r.OnLogMessage(x => { logs.Add(x); })); var logger = server.GetRequiredService>(); @@ -52,24 +53,26 @@ public async Task Logs_Are_Sent_To_Client_From_Server() logger.LogTrace("Just gotta let you trace!"); logger.LogDebug("Just gotta let you debug!"); - await _logs.DelayUntilCount(6, CancellationToken); + await logs.DelayUntilCount(6, CancellationToken); + var items = logs.Take(6).ToList(); - _logs.Should().HaveCount(6); - _logs.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); - _logs.Where(z => z.Type == MessageType.Info).Should().HaveCount(1); - _logs.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); - _logs.Where(z => z.Type == MessageType.Log).Should().HaveCount(2); + items.Should().HaveCount(6); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(2); } [Fact] public async Task Logs_Are_Sent_To_Client_From_Server_Respecting_SetMinimumLevel() { + var logs = new ConcurrentBag(); var (client, server) = await Initialize( options => { }, options => { options.ConfigureLogging( z => z - .AddLanguageProtocolLogging(LogLevel.Trace) + .AddLanguageProtocolLogging() .SetMinimumLevel(LogLevel.Warning) ); } @@ -77,7 +80,7 @@ public async Task Logs_Are_Sent_To_Client_From_Server_Respecting_SetMinimumLevel await SettleNext(); - using var _ = client.Register(r => r.OnLogMessage(x => { _logs.Add(x); })); + using var _ = client.Register(r => r.OnLogMessage(x => { logs.Add(x); })); var logger = server.GetRequiredService>(); @@ -88,24 +91,64 @@ public async Task Logs_Are_Sent_To_Client_From_Server_Respecting_SetMinimumLevel logger.LogTrace("Just gotta let you trace!"); logger.LogDebug("Just gotta let you debug!"); - await _logs.DelayUntilCount(3, CancellationToken); + await logs.DelayUntilCount(3, CancellationToken); + var items = logs.Take(3).ToList(); - _logs.Should().HaveCount(3); - _logs.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); - _logs.Where(z => z.Type == MessageType.Info).Should().HaveCount(0); - _logs.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); - _logs.Where(z => z.Type == MessageType.Log).Should().HaveCount(0); + items.Should().HaveCount(3); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(0); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(0); } [Fact] public async Task Logs_Are_Sent_To_Client_From_Server_Respecting_TraceLevel() { + var logs = new ConcurrentBag(); + var (client, server) = await Initialize( + options => { options.Trace = InitializeTrace.Messages; }, + options => { + options.ConfigureLogging( + z => z + .AddLanguageProtocolLogging() + .SetMinimumLevel(LogLevel.Trace) + ); + } + ); + + await SettleNext(); + + using var _ = client.Register(r => r.OnLogMessage(x => { logs.Add(x); })); + + var logger = server.GetRequiredService>(); + + logger.LogCritical("holy cow!"); + logger.LogError("Something bad happened..."); + logger.LogInformation("Here's something cool..."); + logger.LogWarning("Uh-oh..."); + logger.LogTrace("Just gotta let you trace!"); + logger.LogDebug("Just gotta let you debug!"); + + await logs.DelayUntilCount(4, CancellationToken); + var items = logs.Take(4).ToList(); + + items.Should().HaveCount(4); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(0); + } + + [Fact] + public async Task Client_Can_Dynamically_Change_Server_Trace_Level_Off_To_Verbose() + { + var logs = new ConcurrentBag(); var (client, server) = await Initialize( - options => { }, + options => { }, options => { options.ConfigureLogging( z => z - .AddLanguageProtocolLogging(LogLevel.Information) + .AddLanguageProtocolLogging() .SetMinimumLevel(LogLevel.Trace) ); } @@ -113,7 +156,7 @@ public async Task Logs_Are_Sent_To_Client_From_Server_Respecting_TraceLevel() await SettleNext(); - using var _ = client.Register(r => r.OnLogMessage(x => { _logs.Add(x); })); + using var _ = client.Register(r => r.OnLogMessage(x => { logs.Add(x); })); var logger = server.GetRequiredService>(); @@ -124,13 +167,106 @@ public async Task Logs_Are_Sent_To_Client_From_Server_Respecting_TraceLevel() logger.LogTrace("Just gotta let you trace!"); logger.LogDebug("Just gotta let you debug!"); - await _logs.DelayUntilCount(4, CancellationToken); + await logs.DelayUntilCount(3, CancellationToken); + { + var items = logs.Take(3).ToList(); + ; + + items.Should().HaveCount(3); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(0); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(0); + } + + client.SetTrace(new() { Value = InitializeTrace.Verbose }); + await SettleNext(); + + logs.Clear(); + + logger.LogCritical("holy cow!"); + logger.LogError("Something bad happened..."); + logger.LogInformation("Here's something cool..."); + logger.LogWarning("Uh-oh..."); + logger.LogTrace("Just gotta let you trace!"); + logger.LogDebug("Just gotta let you debug!"); + + await logs.DelayUntilCount(6, CancellationToken); + { + var items = logs.Take(6).ToList(); + ; + + items.Should().HaveCount(6); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(2); + } + } + + [Fact] + public async Task Client_Can_Dynamically_Change_Server_Trace_Level_Verbose_To_Off() + { + var logs = new ConcurrentBag(); + var (client, server) = await Initialize( + options => { + options.Trace = InitializeTrace.Verbose; + }, + options => { + options.ConfigureLogging( + z => z + .AddLanguageProtocolLogging() + .SetMinimumLevel(LogLevel.Trace) + ); + } + ); + + await SettleNext(); + + using var _ = client.Register(r => r.OnLogMessage(x => { logs.Add(x); })); + + var logger = server.GetRequiredService>(); + + logger.LogCritical("holy cow!"); + logger.LogError("Something bad happened..."); + logger.LogInformation("Here's something cool..."); + logger.LogWarning("Uh-oh..."); + logger.LogTrace("Just gotta let you trace!"); + logger.LogDebug("Just gotta let you debug!"); + + await logs.DelayUntilCount(6, CancellationToken); + { + var items = logs.Take(6).ToList(); + + items.Should().HaveCount(6); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(2); + } + + client.SetTrace(new() { Value = InitializeTrace.Off }); + await SettleNext(); + + logs.Clear(); + + logger.LogCritical("holy cow!"); + logger.LogError("Something bad happened..."); + logger.LogInformation("Here's something cool..."); + logger.LogWarning("Uh-oh..."); + logger.LogTrace("Just gotta let you trace!"); + logger.LogDebug("Just gotta let you debug!"); + + await logs.DelayUntilCount(3, CancellationToken); + { + var items = logs.Take(3).ToList(); - _logs.Should().HaveCount(4); - _logs.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); - _logs.Where(z => z.Type == MessageType.Info).Should().HaveCount(1); - _logs.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); - _logs.Where(z => z.Type == MessageType.Log).Should().HaveCount(0); + items.Should().HaveCount(3); + items.Where(z => z.Type == MessageType.Error).Should().HaveCount(2); + items.Where(z => z.Type == MessageType.Info).Should().HaveCount(0); + items.Where(z => z.Type == MessageType.Warning).Should().HaveCount(1); + items.Where(z => z.Type == MessageType.Log).Should().HaveCount(0); + } } } } diff --git a/test/Lsp.Tests/Integration/RenameTests.cs b/test/Lsp.Tests/Integration/RenameTests.cs index a8c609dc8..1ea72c999 100644 --- a/test/Lsp.Tests/Integration/RenameTests.cs +++ b/test/Lsp.Tests/Integration/RenameTests.cs @@ -227,7 +227,7 @@ private void ClientOptionsAction(LanguageClientOptions obj) obj.WithCapability( new RenameCapability() { PrepareSupport = true, - PrepareSupportDefaultBehavior = true + PrepareSupportDefaultBehavior = PrepareSupportDefaultBehavior.Identifier } ); } diff --git a/test/Lsp.Tests/Integration/RequestCancellationTests.cs b/test/Lsp.Tests/Integration/RequestCancellationTests.cs index f7631f1d6..4e964bbcc 100644 --- a/test/Lsp.Tests/Integration/RequestCancellationTests.cs +++ b/test/Lsp.Tests/Integration/RequestCancellationTests.cs @@ -56,7 +56,7 @@ public async Task Should_Abandon_Pending_Requests_For_Text_Changes() client.TextDocument.DidChangeTextDocument( new DidChangeTextDocumentParams { - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = "/a/file.cs", Version = 123, }, diff --git a/test/Lsp.Tests/Integration/WorkspaceFolderTests.cs b/test/Lsp.Tests/Integration/WorkspaceFolderTests.cs index 59457a8cf..d8a02ba86 100644 --- a/test/Lsp.Tests/Integration/WorkspaceFolderTests.cs +++ b/test/Lsp.Tests/Integration/WorkspaceFolderTests.cs @@ -14,6 +14,7 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Extensions.LanguageServer.Protocol.Workspace; using OmniSharp.Extensions.LanguageServer.Server; using Serilog.Events; using Xunit; @@ -69,6 +70,19 @@ public async Task Should_Add_A_Workspace_Folder() folders[0].Folder.Name.Should().Be(nameof(Should_Add_A_Workspace_Folder)); } + [Fact] + public async Task Should_Allow_Null_Response() + { + var (client, server) = await Initialize( + options => { + ConfigureClient(options); + options.OnWorkspaceFolders(@params => Task.FromResult?>(null)); + }, ConfigureServer); + + Func a = () => server.WorkspaceFolderManager.Refresh().LastOrDefaultAsync().ToTask(); + a.Should().NotThrow(); + } + [Fact] public async Task Should_Have_Workspace_Folder_At_Startup() { diff --git a/test/Lsp.Tests/Matchers/TextDocumentMatcherTests.cs b/test/Lsp.Tests/Matchers/TextDocumentMatcherTests.cs index ee8554c42..b51c3dda0 100644 --- a/test/Lsp.Tests/Matchers/TextDocumentMatcherTests.cs +++ b/test/Lsp.Tests/Matchers/TextDocumentMatcherTests.cs @@ -134,7 +134,7 @@ public void Should_Return_Did_Change_Text_Document_Descriptor() // When var result = handlerMatcher.FindHandler( new DidChangeTextDocumentParams { - TextDocument = new VersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } }, collection.Where(x => x.Method == TextDocumentNames.DidChange) ); @@ -163,7 +163,7 @@ public void Should_Return_Did_Save_Text_Document_Descriptor() // When var result = handlerMatcher.FindHandler( new DidChangeTextDocumentParams { - TextDocument = new VersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } }, collection.Where(x => x.Method == TextDocumentNames.DidSave) ); @@ -192,7 +192,7 @@ public void Should_Return_Did_Close_Text_Document_Descriptor() // When var result = handlerMatcher.FindHandler( new DidCloseTextDocumentParams { - TextDocument = new VersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } }, collection.Where(x => x.Method == TextDocumentNames.DidClose) ); @@ -239,7 +239,7 @@ public void Should_Return_Code_Lens_Descriptor() // When var result = handlerMatcher.FindHandler( new CodeLensParams { - TextDocument = new VersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123/d.cs"), Version = 1 } }, collection.Where(x => x.Method == TextDocumentNames.CodeLens) ); diff --git a/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests.cs b/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests.cs index 32e219ea9..ec62c4c1c 100644 --- a/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests.cs +++ b/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests.cs @@ -82,7 +82,7 @@ public void DocumentChangesTest(string expected) Edit = new WorkspaceEdit { DocumentChanges = new Container( new TextDocumentEdit { - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Version = 1, Uri = new Uri("file:///abc/123/d.cs"), }, @@ -98,7 +98,7 @@ public void DocumentChangesTest(string expected) } }, new TextDocumentEdit { - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Version = 1, Uri = new Uri("file:///abc/123/b.cs"), }, diff --git a/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests_$DocumentChangesTest.json b/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests_$DocumentChangesTest.json index 05fa0918e..ecaa44a5e 100644 --- a/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests_$DocumentChangesTest.json +++ b/test/Lsp.Tests/Models/ApplyWorkspaceEditParamsTests_$DocumentChangesTest.json @@ -90,7 +90,6 @@ "kind": "delete", "uri": "file:///abc/123/c.cs", "options": { - "recursive": false, "ignoreIfNotExists": true } } diff --git a/test/Lsp.Tests/Models/CodeActionRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/CodeActionRegistrationOptionsTests_$SimpleTest.json index 410ad3f2c..56c11892f 100644 --- a/test/Lsp.Tests/Models/CodeActionRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/CodeActionRegistrationOptionsTests_$SimpleTest.json @@ -8,7 +8,6 @@ "source", "source.organizeImports" ], - "resolveProvider": false, "documentSelector": [ { "language": "csharp", @@ -20,6 +19,5 @@ "scheme": "scheme", "pattern": "pattern" } - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/CodeLensRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/CodeLensRegistrationOptionsTests_$SimpleTest.json index 783fcf765..d7b41148d 100644 --- a/test/Lsp.Tests/Models/CodeLensRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/CodeLensRegistrationOptionsTests_$SimpleTest.json @@ -11,6 +11,5 @@ "scheme": "scheme", "pattern": "pattern" } - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/CompletionItemTests_$SimpleTest.json b/test/Lsp.Tests/Models/CompletionItemTests_$SimpleTest.json index 754837233..55ebb688b 100644 --- a/test/Lsp.Tests/Models/CompletionItemTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/CompletionItemTests_$SimpleTest.json @@ -1,10 +1,6 @@ { "label": null, "kind": 1, - "deprecated": false, - "preselect": false, - "insertTextFormat": 0, - "insertTextMode": 0, "additionalTextEdits": [ { "range": null, diff --git a/test/Lsp.Tests/Models/CompletionListTests_$ComplexTest.json b/test/Lsp.Tests/Models/CompletionListTests_$ComplexTest.json index ed9ffa2fe..4f2b5d005 100644 --- a/test/Lsp.Tests/Models/CompletionListTests_$ComplexTest.json +++ b/test/Lsp.Tests/Models/CompletionListTests_$ComplexTest.json @@ -4,11 +4,7 @@ { "label": null, "kind": 7, - "detail": "details", - "deprecated": false, - "preselect": false, - "insertTextFormat": 0, - "insertTextMode": 0 + "detail": "details" } ] } diff --git a/test/Lsp.Tests/Models/CompletionListTests_$SimpleTest.json b/test/Lsp.Tests/Models/CompletionListTests_$SimpleTest.json index 3bb0b7494..d11085561 100644 --- a/test/Lsp.Tests/Models/CompletionListTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/CompletionListTests_$SimpleTest.json @@ -2,10 +2,6 @@ { "label": null, "kind": 7, - "detail": "details", - "deprecated": false, - "preselect": false, - "insertTextFormat": 0, - "insertTextMode": 0 + "detail": "details" } ] diff --git a/test/Lsp.Tests/Models/CompletionRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/CompletionRegistrationOptionsTests_$SimpleTest.json index d7c3fde10..d456d5110 100644 --- a/test/Lsp.Tests/Models/CompletionRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/CompletionRegistrationOptionsTests_$SimpleTest.json @@ -7,6 +7,5 @@ { "language": "csharp" } - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/DidChangeTextDocumentParamsTests.cs b/test/Lsp.Tests/Models/DidChangeTextDocumentParamsTests.cs index 7410d3a50..04d344801 100644 --- a/test/Lsp.Tests/Models/DidChangeTextDocumentParamsTests.cs +++ b/test/Lsp.Tests/Models/DidChangeTextDocumentParamsTests.cs @@ -22,7 +22,7 @@ public void SimpleTest(string expected) Text = "abc" } }, - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = "/somepath/to/a/file.ext", } }; @@ -46,7 +46,7 @@ public void NonStandardCharactersTest(string expected) Text = "abc" } }, - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = DocumentUri.FromFileSystemPath("c:\\abc\\Mörkö.cs") } }; diff --git a/test/Lsp.Tests/Models/DocumentLinkRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/DocumentLinkRegistrationOptionsTests_$SimpleTest.json index 0a1f03e65..26f2b70b9 100644 --- a/test/Lsp.Tests/Models/DocumentLinkRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/DocumentLinkRegistrationOptionsTests_$SimpleTest.json @@ -4,6 +4,5 @@ { "language": "csharp" } - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/DocumentOnTypeFormattingRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/DocumentOnTypeFormattingRegistrationOptionsTests_$SimpleTest.json index 65761c1db..4c64bb701 100644 --- a/test/Lsp.Tests/Models/DocumentOnTypeFormattingRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/DocumentOnTypeFormattingRegistrationOptionsTests_$SimpleTest.json @@ -8,6 +8,5 @@ { "language": "csharp" } - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/DocumentSymbolInformationTests_$SimpleTest.json b/test/Lsp.Tests/Models/DocumentSymbolInformationTests_$SimpleTest.json index 8ba35e2c9..38bf25cc6 100644 --- a/test/Lsp.Tests/Models/DocumentSymbolInformationTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/DocumentSymbolInformationTests_$SimpleTest.json @@ -1,7 +1,6 @@ { "name": "name", "kind": 17, - "deprecated": false, "location": { "uri": "file:///abc/123.cs", "range": { diff --git a/test/Lsp.Tests/Models/ExecuteCommandRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/ExecuteCommandRegistrationOptionsTests_$SimpleTest.json index e257c3756..41fc1d8bb 100644 --- a/test/Lsp.Tests/Models/ExecuteCommandRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/ExecuteCommandRegistrationOptionsTests_$SimpleTest.json @@ -2,6 +2,5 @@ "commands": [ "1", "2" - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/FormattingOptionsTests.cs b/test/Lsp.Tests/Models/FormattingOptionsTests.cs index e7c9b14fd..a21ce7670 100644 --- a/test/Lsp.Tests/Models/FormattingOptionsTests.cs +++ b/test/Lsp.Tests/Models/FormattingOptionsTests.cs @@ -31,7 +31,7 @@ public void Should_Not_Require_A_Value_To_Be_Defined() { var model = new FormattingOptions(); model.InsertSpaces.Should().BeFalse(); - model.TabSize.Should().Be(-1L); + model.TabSize.Should().Be(-1); model.InsertFinalNewline.Should().BeFalse(); model.TrimFinalNewlines.Should().BeFalse(); model.TrimTrailingWhitespace.Should().BeFalse(); diff --git a/test/Lsp.Tests/Models/InitializeParamsTests_$SimpleTest.json b/test/Lsp.Tests/Models/InitializeParamsTests_$SimpleTest.json index 7fefbe767..c8fe959b6 100644 --- a/test/Lsp.Tests/Models/InitializeParamsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/InitializeParamsTests_$SimpleTest.json @@ -28,21 +28,14 @@ }, "completion": { "completionItem": { - "snippetSupport": true, - "commitCharactersSupport": false, - "deprecatedSupport": false, - "preselectSupport": false, - "insertReplaceSupport": false, - "resolveAdditionalTextEditsSupport": false + "snippetSupport": true }, - "contextSupport": false, "dynamicRegistration": true }, "hover": { "dynamicRegistration": true }, "signatureHelp": { - "contextSupport": false, "dynamicRegistration": true }, "references": { @@ -52,8 +45,6 @@ "dynamicRegistration": true }, "documentSymbol": { - "hierarchicalDocumentSymbolSupport": false, - "labelSupport": false, "dynamicRegistration": true }, "formatting": { @@ -66,25 +57,18 @@ "dynamicRegistration": true }, "definition": { - "linkSupport": false, "dynamicRegistration": true }, "codeAction": { - "isPreferredSupport": false, - "disabledSupport": false, - "dataSupport": false, "dynamicRegistration": true }, "codeLens": { "dynamicRegistration": true }, "documentLink": { - "tooltipSupport": false, "dynamicRegistration": true }, "rename": { - "prepareSupport": false, - "prepareSupportDefaultBehavior": false, "dynamicRegistration": true }, "foldingRange": { diff --git a/test/Lsp.Tests/Models/InitializeResultTests_$BooleanOrTest.json b/test/Lsp.Tests/Models/InitializeResultTests_$BooleanOrTest.json index abf2085a4..b1d879161 100644 --- a/test/Lsp.Tests/Models/InitializeResultTests_$BooleanOrTest.json +++ b/test/Lsp.Tests/Models/InitializeResultTests_$BooleanOrTest.json @@ -3,33 +3,25 @@ "codeActionProvider": { "codeActionKinds": [ "quickfix" - ], - "resolveProvider": false, - "workDoneProgress": false + ] }, "renameProvider": { - "prepareProvider": true, - "workDoneProgress": false + "prepareProvider": true }, "experimental": {}, "typeDefinitionProvider": { - "workDoneProgress": false, "id": "foo" }, "implementationProvider": { - "workDoneProgress": false, "id": "foo" }, "colorProvider": { - "workDoneProgress": false, "id": "foo" }, "foldingRangeProvider": { - "workDoneProgress": false, "id": "foo" }, "declarationProvider": { - "workDoneProgress": false, "id": "foo" } } diff --git a/test/Lsp.Tests/Models/InitializeResultTests_$SimpleTest.json b/test/Lsp.Tests/Models/InitializeResultTests_$SimpleTest.json index 3862cba1f..7f553ba93 100644 --- a/test/Lsp.Tests/Models/InitializeResultTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/InitializeResultTests_$SimpleTest.json @@ -16,15 +16,13 @@ "a", "b", "c" - ], - "workDoneProgress": false + ] }, "signatureHelpProvider": { "triggerCharacters": [ ";", " " - ], - "workDoneProgress": false + ] }, "definitionProvider": true, "referencesProvider": true, @@ -33,8 +31,7 @@ "workspaceSymbolProvider": true, "codeActionProvider": true, "codeLensProvider": { - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true }, "documentFormattingProvider": true, "documentRangeFormattingProvider": true, @@ -43,20 +40,17 @@ "moreTriggerCharacter": [ ";", " " - ], - "workDoneProgress": false + ] }, "renameProvider": true, "documentLinkProvider": { - "resolveProvider": true, - "workDoneProgress": false + "resolveProvider": true }, "executeCommandProvider": { "commands": [ "command1", "command2" - ], - "workDoneProgress": false + ] }, "experimental": { "abc": "123" diff --git a/test/Lsp.Tests/Models/SignatureHelpRegistrationOptionsTests_$SimpleTest.json b/test/Lsp.Tests/Models/SignatureHelpRegistrationOptionsTests_$SimpleTest.json index d8000d59e..2ab8c3497 100644 --- a/test/Lsp.Tests/Models/SignatureHelpRegistrationOptionsTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/SignatureHelpRegistrationOptionsTests_$SimpleTest.json @@ -7,6 +7,5 @@ { "language": "csharp" } - ], - "workDoneProgress": false + ] } diff --git a/test/Lsp.Tests/Models/TextDocumentEditTests.cs b/test/Lsp.Tests/Models/TextDocumentEditTests.cs index ca93371d8..9ee46bca0 100644 --- a/test/Lsp.Tests/Models/TextDocumentEditTests.cs +++ b/test/Lsp.Tests/Models/TextDocumentEditTests.cs @@ -16,7 +16,7 @@ public class TextDocumentEditTests public void SimpleTest(string expected) { var model = new TextDocumentEdit { - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Version = 1, Uri = new Uri("file:///abc/123/d.cs"), }, diff --git a/test/Lsp.Tests/Models/TextEditTests.cs b/test/Lsp.Tests/Models/TextEditTests.cs index 9f3612ebe..342bf6a8b 100644 --- a/test/Lsp.Tests/Models/TextEditTests.cs +++ b/test/Lsp.Tests/Models/TextEditTests.cs @@ -24,5 +24,27 @@ public void SimpleTest(string expected) var deresult = new LspSerializer(ClientVersion.Lsp3).DeserializeObject(expected); deresult.Should().BeEquivalentTo(model, x => x.UsingStructuralRecordEquality()); } + + [Theory] + [JsonFixture] + public void AnnotatedTest(string expected) + { + var model = new AnnotatedTextEdit { + NewText = "new text", + Range = new Range(new Position(1, 1), new Position(2, 2)), + Annotation = new ChangeAnnotation() { + Description = "Cool story", + Label = "Heck ya", + NeedsConfirmation = true + } + }; + var result = Fixture.SerializeObject(model); + + result.Should().Be(expected); + + var deresult = new LspSerializer(ClientVersion.Lsp3).DeserializeObject(expected); + deresult.Should().BeOfType(); + deresult.Should().BeEquivalentTo(model, x => x.UsingStructuralRecordEquality()); + } } } diff --git a/test/Lsp.Tests/Models/TextEditTests_$AnnotatedTest.json b/test/Lsp.Tests/Models/TextEditTests_$AnnotatedTest.json new file mode 100644 index 000000000..f0c48917c --- /dev/null +++ b/test/Lsp.Tests/Models/TextEditTests_$AnnotatedTest.json @@ -0,0 +1,18 @@ +{ + "range": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 2, + "character": 2 + } + }, + "newText": "new text", + "annotation": { + "label": "Heck ya", + "needsConfirmation": true, + "description": "Cool story" + } +} diff --git a/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs b/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs index ec84390ad..8f2e74f70 100644 --- a/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs +++ b/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs @@ -14,7 +14,7 @@ public class VersionedTextDocumentIdentifierTests [JsonFixture] public void SimpleTest(string expected) { - var model = new VersionedTextDocumentIdentifier { + var model = new OptionalVersionedTextDocumentIdentifier { Uri = new Uri("file:///abc/123.cs"), Version = 12 }; @@ -22,7 +22,7 @@ public void SimpleTest(string expected) result.Should().Be(expected); - var deresult = new LspSerializer(ClientVersion.Lsp3).DeserializeObject(expected); + var deresult = new LspSerializer(ClientVersion.Lsp3).DeserializeObject(expected); deresult.Should().BeEquivalentTo(model, x => x.UsingStructuralRecordEquality()); } } diff --git a/test/Lsp.Tests/Models/WorkspaceEditTests.cs b/test/Lsp.Tests/Models/WorkspaceEditTests.cs index c328bef2b..75334924d 100644 --- a/test/Lsp.Tests/Models/WorkspaceEditTests.cs +++ b/test/Lsp.Tests/Models/WorkspaceEditTests.cs @@ -48,7 +48,7 @@ public void DocumentChangesTest(string expected) var model = new WorkspaceEdit { DocumentChanges = new Container( new TextDocumentEdit { - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Version = 1, Uri = new Uri("file:///abc/123/d.cs"), }, @@ -64,7 +64,7 @@ public void DocumentChangesTest(string expected) } }, new TextDocumentEdit { - TextDocument = new VersionedTextDocumentIdentifier { + TextDocument = new OptionalVersionedTextDocumentIdentifier { Version = 1, Uri = new Uri("file:///abc/123/b.cs"), }, diff --git a/test/Lsp.Tests/Models/WorkspaceEditTests_$DocumentChangesTest.json b/test/Lsp.Tests/Models/WorkspaceEditTests_$DocumentChangesTest.json index 6961c0421..3c72f5d5f 100644 --- a/test/Lsp.Tests/Models/WorkspaceEditTests_$DocumentChangesTest.json +++ b/test/Lsp.Tests/Models/WorkspaceEditTests_$DocumentChangesTest.json @@ -89,7 +89,6 @@ "kind": "delete", "uri": "file:///abc/123/c.cs", "options": { - "recursive": false, "ignoreIfNotExists": true } } diff --git a/test/Lsp.Tests/Models/WorkspaceSymbolInformationTests_$SimpleTest.json b/test/Lsp.Tests/Models/WorkspaceSymbolInformationTests_$SimpleTest.json index 8ba35e2c9..38bf25cc6 100644 --- a/test/Lsp.Tests/Models/WorkspaceSymbolInformationTests_$SimpleTest.json +++ b/test/Lsp.Tests/Models/WorkspaceSymbolInformationTests_$SimpleTest.json @@ -1,7 +1,6 @@ { "name": "name", "kind": 17, - "deprecated": false, "location": { "uri": "file:///abc/123.cs", "range": {