示例#1
0
 private static async Task <SignatureHelp?> RequestSignatureHelp(ILanguageClient client, Position position, DocumentUri uri, SignatureHelpContext?context = null) =>
 await client.RequestSignatureHelp(new SignatureHelpParams
 {
     Position     = position,
     TextDocument = new TextDocumentIdentifier(uri),
     Context      = context ?? new SignatureHelpContext
     {
         TriggerKind = SignatureHelpTriggerKind.Invoked,
         IsRetrigger = false
     }
 });
 public CompilationContext?GetCompilation(DocumentUri uri)
 {
     this.activeContexts.TryGetValue(uri, out var context);
     return(context);
 }
示例#3
0
        public async Task Should_Fallback_To_Original_Configuration()
        {
            var(_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, ConfigureServer);

            var scopedConfiguration = await server.Configuration.GetScopedConfiguration(DocumentUri.From("/my/file.cs"), CancellationToken);

            configuration.Update("mysection", new Dictionary <string, string> {
                ["key"] = "value"
            });
            configuration.Update("othersection", new Dictionary <string, string> {
                ["value"] = "key"
            });
            await server.Configuration.WaitForChange(CancellationToken);

            await SettleNext();

            configuration.Update("mysection", DocumentUri.From("/my/file.cs"), new Dictionary <string, string> {
                ["key"] = "scopedvalue"
            });
            configuration.Update("othersection", DocumentUri.From("/my/file.cs"), new Dictionary <string, string> {
                ["value"] = "scopedkey"
            });
            await server.Configuration.WaitForChange(CancellationToken);

            await SettleNext();

            server.Configuration["mysection:key"].Should().Be("value");
            scopedConfiguration["mysection:key"].Should().Be("scopedvalue");
            server.Configuration["othersection:value"].Should().Be("key");
            scopedConfiguration["othersection:value"].Should().Be("scopedkey");

            configuration.Update("mysection", DocumentUri.From("/my/file.cs"), new Dictionary <string, string>());
            configuration.Update("othersection", DocumentUri.From("/my/file.cs"), new Dictionary <string, string>());
            await scopedConfiguration.WaitForChange(CancellationToken);

            await SettleNext();

            await TestHelper.DelayUntil(() => scopedConfiguration["mysection:key"] == "value", CancellationToken);

            scopedConfiguration["mysection:key"].Should().Be("value");
            scopedConfiguration["othersection:value"].Should().Be("key");
        }
示例#4
0
        public async Task Diagnostics_Success()
        {
            await Connect();

            var documentPath        = AbsoluteDocumentPath;
            var expectedDocumentUri = DocumentUri.FromFileSystemPath(documentPath);
            var expectedDiagnostics = new List <Diagnostic>
            {
                new Diagnostic
                {
                    Source  = "Test",
                    Code    = new DiagnosticCode(1234),
                    Message = "This is a diagnostic message.",
                    Range   = new Range
                    {
                        Start = new Position
                        {
                            Line      = 2,
                            Character = 5
                        },
                        End = new Position
                        {
                            Line      = 3,
                            Character = 7
                        }
                    },
                    Severity = DiagnosticSeverity.Warning
                }
            };

            var receivedDiagnosticsNotification = new TaskCompletionSource <object>();

            Uri actualDocumentUri = null;
            List <Diagnostic> actualDiagnostics = null;

            LanguageClient.TextDocument.OnPublishDiagnostics((documentUri, diagnostics) => {
                actualDocumentUri = documentUri;
                actualDiagnostics = diagnostics;

                receivedDiagnosticsNotification.SetResult(null);
            });

            ServerConnection.SendNotification(DocumentNames.PublishDiagnostics, new PublishDiagnosticsParams {
                Uri         = DocumentUri.FromFileSystemPath(documentPath),
                Diagnostics = expectedDiagnostics
            });

            // Timeout.
            var winner = await Task.WhenAny(
                receivedDiagnosticsNotification.Task,
                Task.Delay(
                    TimeSpan.FromSeconds(2)
                    )
                );

            Assert.Same(receivedDiagnosticsNotification.Task, winner);

            Assert.NotNull(actualDocumentUri);
            Assert.Equal(expectedDocumentUri, actualDocumentUri);

            Assert.NotNull(actualDiagnostics);
            Assert.Equal(1, actualDiagnostics.Count);

            var expectedDiagnostic = expectedDiagnostics[0];
            var actualDiagnostic   = actualDiagnostics[0];

            Assert.Equal(expectedDiagnostic.Code, actualDiagnostic.Code);
            Assert.Equal(expectedDiagnostic.Message, actualDiagnostic.Message);
            Assert.Equal(expectedDiagnostic.Range.Start.Line, actualDiagnostic.Range.Start.Line);
            Assert.Equal(expectedDiagnostic.Range.Start.Character, actualDiagnostic.Range.Start.Character);
            Assert.Equal(expectedDiagnostic.Range.End.Line, actualDiagnostic.Range.End.Line);
            Assert.Equal(expectedDiagnostic.Range.End.Character, actualDiagnostic.Range.End.Character);
            Assert.Equal(expectedDiagnostic.Severity, actualDiagnostic.Severity);
            Assert.Equal(expectedDiagnostic.Source, actualDiagnostic.Source);
        }
        private (ImmutableArray <SyntaxTree> added, ImmutableArray <SyntaxTree> removed) UpdateCompilationInternal(DocumentUri documentUri, int?version)
        {
            try
            {
                var context = this.provider.Create(workspace, documentUri);

                var output = workspace.UpsertSyntaxTrees(context.Compilation.SyntaxTreeGrouping.SyntaxTrees);

                // there shouldn't be concurrent upsert requests (famous last words...), so a simple overwrite should be sufficient
                this.activeContexts[documentUri] = context;

                // convert all the diagnostics to LSP diagnostics
                var diagnostics = GetDiagnosticsFromContext(context).ToDiagnostics(context.LineStarts);

                // publish all the diagnostics
                this.PublishDocumentDiagnostics(documentUri, version, diagnostics);

                return(output);
            }
            catch (Exception exception)
            {
                // this is a fatal error likely due to a code defect

                // publish a single fatal error diagnostic to tell the user something horrible has occurred
                // TODO: Tell user how to create an issue on GitHub.
                var fatalError = new OmniSharp.Extensions.LanguageServer.Protocol.Models.Diagnostic
                {
                    Range = new Range
                    {
                        Start = new Position(0, 0),
                        End   = new Position(1, 0),
                    },
                    Severity = DiagnosticSeverity.Error,
                    Message  = exception.Message,
                    Code     = new DiagnosticCode("Fatal")
                };

                // the file is no longer in a state that can be parsed
                // clear all info to prevent cascading failures elsewhere
                var closedTrees = CloseCompilationInternal(documentUri, version, fatalError.AsEnumerable());

                return(ImmutableArray <SyntaxTree> .Empty, closedTrees);
            }
        }
示例#6
0
 private record CompletionNotification(ICompilationManager CompilationManager, DocumentUri Uri);
示例#7
0
        public async Task Completions_Success()
        {
            await Connect();

            const int line   = 5;
            const int column = 5;
            var       expectedDocumentPath = AbsoluteDocumentPath;
            var       expectedDocumentUri  = DocumentUri.FromFileSystemPath(expectedDocumentPath);

            var expectedCompletionItems = new CompletionItem[]
            {
                new CompletionItem
                {
                    Kind     = CompletionItemKind.Class,
                    Label    = "Class1",
                    TextEdit = new TextEdit
                    {
                        Range = new Range
                        {
                            Start = new Position
                            {
                                Line      = line,
                                Character = column
                            },
                            End = new Position
                            {
                                Line      = line,
                                Character = column
                            }
                        },
                        NewText = "Class1",
                    }
                }
            };

            ServerDispatcher.HandleRequest <TextDocumentPositionParams, CompletionList>(DocumentNames.Completion, (request, cancellationToken) => {
                Assert.NotNull(request.TextDocument);

                Assert.Equal(expectedDocumentUri, request.TextDocument.Uri);

                Assert.Equal(line, request.Position.Line);
                Assert.Equal(column, request.Position.Character);

                return(Task.FromResult(new CompletionList(
                                           expectedCompletionItems,
                                           isIncomplete: true
                                           )));
            });

            var actualCompletions = await LanguageClient.TextDocument.Completions(AbsoluteDocumentPath, line, column);

            Assert.True(actualCompletions.IsIncomplete, "completions.IsIncomplete");
            Assert.NotNull(actualCompletions.Items);

            var actualCompletionItems = actualCompletions.Items.ToArray();

            Assert.Collection(actualCompletionItems, actualCompletionItem => {
                var expectedCompletionItem = expectedCompletionItems[0];

                Assert.Equal(expectedCompletionItem.Kind, actualCompletionItem.Kind);
                Assert.Equal(expectedCompletionItem.Label, actualCompletionItem.Label);

                Assert.NotNull(actualCompletionItem.TextEdit);
                Assert.Equal(expectedCompletionItem.TextEdit.NewText, actualCompletionItem.TextEdit.NewText);

                Assert.NotNull(actualCompletionItem.TextEdit.Range);
                Assert.NotNull(actualCompletionItem.TextEdit.Range.Start);
                Assert.NotNull(actualCompletionItem.TextEdit.Range.End);
                Assert.Equal(expectedCompletionItem.TextEdit.Range.Start.Line, actualCompletionItem.TextEdit.Range.Start.Line);
                Assert.Equal(expectedCompletionItem.TextEdit.Range.Start.Character, actualCompletionItem.TextEdit.Range.Start.Character);
                Assert.Equal(expectedCompletionItem.TextEdit.Range.End.Line, actualCompletionItem.TextEdit.Range.End.Line);
                Assert.Equal(expectedCompletionItem.TextEdit.Range.End.Character, actualCompletionItem.TextEdit.Range.End.Character);
            });
        }
 public void Should_Normalize_Unix_Uris(Uri uri, string expected)
 {
     _testOutputHelper.WriteLine($"Given: {uri}");
     _testOutputHelper.WriteLine($"Expected: {expected}");
     DocumentUri.GetFileSystemPath(uri).Should().Be(expected);
 }
 public void Should_Handle_Unix_File_System_Paths(string uri, DocumentUri expected)
 {
     _testOutputHelper.WriteLine($"Given: {uri}");
     _testOutputHelper.WriteLine($"Expected: {expected}");
     new DocumentUri(uri).Should().Be(expected);
 }
 public void Should_Handle_Unix_Uris(Uri uri, DocumentUri expected)
 {
     _testOutputHelper.WriteLine($"Given: {uri}");
     _testOutputHelper.WriteLine($"Expected: {expected}");
     DocumentUri.From(uri).Should().Be(expected);
 }
 public void Should_Normalize_Unix_FileSystem_Paths(string uri, DocumentUri expected)
 {
     _testOutputHelper.WriteLine($"Given: {uri}");
     _testOutputHelper.WriteLine($"Expected: {expected}");
     DocumentUri.FromFileSystemPath(uri).Should().Be(expected);
 }
 public void Should_Handle_Windows_Alt_String_Uris(string uri, DocumentUri expected)
 {
     _testOutputHelper.WriteLine($"Given: {uri}");
     _testOutputHelper.WriteLine($"Expected: {expected}");
     new DocumentUri(uri).Should().Be(expected);
 }
示例#13
0
 public SymbolLocation(DocumentUri uri, Range name, Range declaration)
 {
     Uri         = uri;
     Name        = name;
     Declaration = declaration;
 }
示例#14
0
        public async Task NonExistentUriShouldProvideNoSignatureHelp()
        {
            using var client = await IntegrationTestHelper.StartServerWithTextAsync(this.TestContext, string.Empty, DocumentUri.From("/fake.bicep"));

            var signatureHelp = await RequestSignatureHelp(client, new Position(0, 0), DocumentUri.From("/fake2.bicep"));

            signatureHelp.Should().BeNull();
        }
 public void HandleBicepConfigCloseEvent(DocumentUri documentUri)
 {
     activeBicepConfigCache.TryRemove(documentUri, out _);
 }
        public async Task DidOpenTextDocument_should_trigger_PublishDiagnostics()
        {
            var documentUri   = DocumentUri.From("/template.bicep");
            var diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>();

            using var helper = await LanguageServerHelper.StartServerWithClientConnectionAsync(this.TestContext, options =>
            {
                options.OnPublishDiagnostics(diags =>
                {
                    diagsReceived.SetResult(diags);
                });
            });

            var client = helper.Client;

            // open document
            client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, @"
param myParam string = 2
resource myRes 'invalidFormat' = {

}
randomToken
", 1));

            var response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task);

            response.Diagnostics.Should().SatisfyRespectively(
                d =>
            {
                d.Range.Should().HaveRange((1, 6), (1, 13));
                // note documentation pretty printing moves Uri to code for output
                d.Should().HaveCodeAndSeverity(new NoUnusedParametersRule().Uri !.AbsoluteUri, DiagnosticSeverity.Warning);
            },
                d =>
            {
                d.Range.Should().HaveRange((1, 23), (1, 24));
                d.Should().HaveCodeAndSeverity("BCP027", DiagnosticSeverity.Error);
            },
                d =>
            {
                d.Range.Should().HaveRange((2, 15), (2, 30));
                d.Should().HaveCodeAndSeverity("BCP029", DiagnosticSeverity.Error);
            },
                d =>
            {
                d.Range.Should().HaveRange((5, 0), (5, 11));
                d.Should().HaveCodeAndSeverity("BCP007", DiagnosticSeverity.Error);
            }
                );

            // change document
            diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>();
            client.TextDocument.DidChangeTextDocument(TextDocumentParamHelper.CreateDidChangeTextDocumentParams(documentUri, @"
param myParam string = 'fixed!'
resource myRes 'invalidFormat' = {

}
randomToken
", 2));

            response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task);

            response.Diagnostics.Should().SatisfyRespectively(
                d =>
            {
                d.Range.Should().HaveRange((1, 6), (1, 13));
                // documentation provided with linter sets code to uri for pretty link print outs
                d.Should().HaveCodeAndSeverity(new NoUnusedParametersRule().Uri !.AbsoluteUri, DiagnosticSeverity.Warning);
            },
                d =>
            {
                d.Range.Should().HaveRange((2, 15), (2, 30));
                d.Should().HaveCodeAndSeverity("BCP029", DiagnosticSeverity.Error);
            },
                d =>
            {
                d.Range.Should().HaveRange((5, 0), (5, 11));
                d.Should().HaveCodeAndSeverity("BCP007", DiagnosticSeverity.Error);
            }
                );

            // close document
            diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>();
            client.TextDocument.DidCloseTextDocument(TextDocumentParamHelper.CreateDidCloseTextDocumentParams(documentUri, 3));

            response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task);

            response.Diagnostics.Should().BeEmpty();
        }
示例#17
0
 private record QueueItem(ICompilationManager CompilationManager, DocumentUri Uri, ImmutableArray <ModuleReference> ModuleReferences, RootConfiguration Configuration);
示例#18
0
 private List <TextDocumentAttributes> GetTextDocumentAttributes(DocumentUri uri) =>
 _textDocumentIdentifiers
 .Select(x => x.GetTextDocumentAttributes(uri))
 .Where(x => x != null)
 .ToList();
示例#19
0
        /// <summary>
        /// Starts a language client/server pair that will load the specified Bicep text and wait for the diagnostics to be published.
        /// No further file opening is possible.
        /// </summary>
        /// <param name="testContext">The test context</param>
        /// <param name="text">The bicep text</param>
        /// <param name="documentUri">The document URI of the Bicep text</param>
        /// <param name="onClientOptions">The additional client options</param>
        /// <param name="creationOptions">The server creation options</param>
        public static async Task <LanguageServerHelper> StartServerWithTextAsync(TestContext testContext, string text, DocumentUri documentUri, Action <LanguageClientOptions>?onClientOptions = null, Server.CreationOptions?creationOptions = null)
        {
            var diagnosticsPublished = new TaskCompletionSource <PublishDiagnosticsParams>();

            creationOptions ??= new Server.CreationOptions();
            creationOptions = creationOptions with
            {
                FileResolver = creationOptions.FileResolver ?? new InMemoryFileResolver(new Dictionary <Uri, string> {
                    [documentUri.ToUri()] = text,
                }),
                ModuleRestoreScheduler = creationOptions.ModuleRestoreScheduler ?? BicepTestConstants.ModuleRestoreScheduler
            };
            var helper = await LanguageServerHelper.StartServerWithClientConnectionAsync(
                testContext,
                options =>
            {
                onClientOptions?.Invoke(options);
                options.OnPublishDiagnostics(p =>
                {
                    testContext.WriteLine($"Received {p.Diagnostics.Count()} diagnostic(s).");
                    diagnosticsPublished.SetResult(p);
                });
            },
                creationOptions);

            // send open document notification
            helper.Client.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, text, 0));

            testContext.WriteLine($"Opened file {documentUri}.");

            // notifications don't produce responses,
            // but our server should send us diagnostics when it receives the notification
            await IntegrationTestHelper.WithTimeoutAsync(diagnosticsPublished.Task);

            return(helper);
        }
示例#20
0
 public static LanguageClientOptions WithRootUri(this LanguageClientOptions options, DocumentUri rootUri)
 {
     options.RootUri = rootUri;
     return(options);
 }
示例#21
0
        public async Task SignatureHelp_Success()
        {
            await Connect();

            const int line   = 5;
            const int column = 5;
            var       expectedDocumentPath = AbsoluteDocumentPath;
            var       expectedDocumentUri  = DocumentUri.FromFileSystemPath(expectedDocumentPath);

            var expectedSignatureHelp = new SignatureHelp {
                ActiveParameter = 0,
                ActiveSignature = 0,
                Signatures      = new[] {
                    new SignatureInformation {
                        Documentation = new StringOrMarkupContent("test documentation"),
                        Label         = "TestSignature",
                        Parameters    = new[] {
                            new ParameterInformation {
                                Documentation = "test parameter documentation",
                                Label         = "parameter label"
                            }
                        }
                    }
                }
            };

            ServerDispatcher.HandleRequest <TextDocumentPositionParams, SignatureHelp>(DocumentNames.SignatureHelp, (request, cancellationToken) => {
                Assert.NotNull(request.TextDocument);

                Assert.Equal(expectedDocumentUri, request.TextDocument.Uri);

                Assert.Equal(line, request.Position.Line);
                Assert.Equal(column, request.Position.Character);

                return(Task.FromResult(expectedSignatureHelp));
            });

            var actualSignatureHelp = await LanguageClient.TextDocument.SignatureHelp(AbsoluteDocumentPath, line, column);

            Assert.Equal(expectedSignatureHelp.ActiveParameter, actualSignatureHelp.ActiveParameter);
            Assert.Equal(expectedSignatureHelp.ActiveSignature, actualSignatureHelp.ActiveSignature);

            var actualSignatures = actualSignatureHelp.Signatures.ToArray();

            Assert.Collection(actualSignatures, actualSignature => {
                var expectedSignature = expectedSignatureHelp.Signatures.ToArray()[0];

                Assert.True(actualSignature.Documentation.HasString);
                Assert.Equal(expectedSignature.Documentation.String, actualSignature.Documentation.String);

                Assert.Equal(expectedSignature.Label, actualSignature.Label);

                var expectedParameters = expectedSignature.Parameters.ToArray();
                var actualParameters   = actualSignature.Parameters.ToArray();

                Assert.Collection(actualParameters, actualParameter => {
                    var expectedParameter = expectedParameters[0];
                    Assert.True(actualParameter.Documentation.HasString);
                    Assert.Equal(expectedParameter.Documentation.String, actualParameter.Documentation.String);
                    Assert.Equal(expectedParameter.Label, actualParameter.Label);
                });
            });
        }
示例#22
0
 public static LanguageClientOptions WithWorkspaceFolder(this LanguageClientOptions options, DocumentUri documentUri, string name)
 {
     options.Services.AddSingleton(new WorkspaceFolder {
         Name = name, Uri = documentUri
     });
     return(options);
 }
示例#23
0
 public TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri)
 {
     return(new TextDocumentAttributes(uri, "ostw"));
 }
示例#24
0
 public TextDocumentIdentifier(DocumentUri uri)
 {
     Uri = uri;
 }
 public void CloseCompilation(DocumentUri documentUri)
 {
     // close and clear diagnostics for the file
     // if upsert failed to create a compilation due to a fatal error, we still need to clean up the diagnostics
     CloseCompilationInternal(documentUri, 0, Enumerable.Empty <OmniSharp.Extensions.LanguageServer.Protocol.Models.Diagnostic>());
 }
        private string GenerateCompiledFileAndReturnBuildOutputMessage(string bicepFilePath, DocumentUri documentUri)
        {
            string compiledFilePath = PathHelper.GetDefaultBuildOutputPath(bicepFilePath);
            string compiledFile     = Path.GetFileName(compiledFilePath);

            // If the template exists and contains bicep generator metadata, we can go ahead and replace the file.
            // If not, we'll fail the build.
            if (File.Exists(compiledFilePath) && !TemplateContainsBicepGeneratorMetadata(File.ReadAllText(compiledFilePath)))
            {
                return("Build failed. The file \"" + compiledFile + "\" already exists and was not generated by Bicep. If overwriting the file is intended, delete it manually and retry the Build command.");
            }

            var fileUri = documentUri.ToUri();
            RootConfiguration?configuration = null;

            try
            {
                configuration = this.configurationManager.GetConfiguration(fileUri);
            }
            catch (ConfigurationException exception)
            {
                // Fail the build if there's configuration errors.
                return(exception.Message);
            }

            CompilationContext?context = compilationManager.GetCompilation(fileUri);
            Compilation        compilation;

            if (context is null)
            {
                SourceFileGrouping sourceFileGrouping = SourceFileGroupingBuilder.Build(this.fileResolver, this.moduleDispatcher, new Workspace(), fileUri, configuration);
                compilation = new Compilation(namespaceProvider, sourceFileGrouping, configuration, new LinterAnalyzer(configuration));
            }
            else
            {
                compilation = context.Compilation;
            }

            KeyValuePair <BicepFile, IEnumerable <IDiagnostic> > diagnosticsByFile = compilation.GetAllDiagnosticsByBicepFile()
                                                                                     .FirstOrDefault(x => x.Key.FileUri == fileUri);

            if (diagnosticsByFile.Value.Any(x => x.Level == DiagnosticLevel.Error))
            {
                return(GetDiagnosticsMessage(diagnosticsByFile));
            }

            using var fileStream = new FileStream(compiledFilePath, FileMode.Create, FileAccess.ReadWrite);
            var        emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), emitterSettings);
            EmitResult result  = emitter.Emit(fileStream);

            return("Build succeeded. Created file " + compiledFile);
        }
 public override TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri)
 {
     return(new TextDocumentAttributes(uri, LanguageConstants.LanguageId));
 }
 public void HandleBicepConfigChangeEvent(DocumentUri documentUri)
 {
     HandleBicepConfigOpenOrChangeEvent(documentUri);
 }
        internal static RazorCodeAction CreateAddUsingCodeAction(string fullyQualifiedName, DocumentUri uri)
        {
            var @namespace = GetNamespaceFromFQN(fullyQualifiedName);

            if (string.IsNullOrEmpty(@namespace))
            {
                return(null);
            }

            var actionParams = new AddUsingsCodeActionParams
            {
                Uri       = uri,
                Namespace = @namespace
            };

            var resolutionParams = new RazorCodeActionResolutionParams
            {
                Action   = LanguageServerConstants.CodeActions.AddUsing,
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = actionParams,
            };

            return(new RazorCodeAction()
            {
                Title = $"@using {@namespace}",
                Data = JToken.FromObject(resolutionParams)
            });
        }
示例#30
0
 /// <summary>
 ///     Request completions at the specified document position.
 /// </summary>
 /// <param name="documentUri">
 ///     The document URI.
 /// </param>
 /// <param name="line">
 ///     The target line (0-based).
 /// </param>
 /// <param name="column">
 ///     The target column (0-based).
 /// </param>
 /// <param name="cancellationToken">
 ///     An optional <see cref="CancellationToken"/> that can be used to cancel the request.
 /// </param>
 /// <returns>
 ///     A <see cref="Task{TResult}"/> that resolves to the completions or <c>null</c> if no completions are available at the specified position.
 /// </returns>
 public Task <CompletionList> Completions(DocumentUri documentUri, int line, int column, CancellationToken cancellationToken = default(CancellationToken))
 {
     return(PositionalRequest <CompletionList>(DocumentNames.Completion, documentUri, line, column, cancellationToken));
 }