public Task <Hover> Hover(TextDocumentIdentifier textDocument, Position position, CancellationToken ct) { using (new DebugMeasureTime("textDocument/hover")) { var doc = Documents.GetDocument(textDocument.Uri); return(doc != null?doc.GetHoverAsync(position, ct) : Task.FromResult((Hover)null)); } }
public SymbolInformation[] documentSymbol(TextDocumentIdentifier textDocument, FormattingOptions options) { using (new DebugMeasureTime("textDocument/documentSymbol")) { var doc = Documents.GetDocument(textDocument.Uri); return(doc != null?doc.GetSymbols(textDocument.Uri) : new SymbolInformation[0]); } }
private async Task <int[]?> GetMatchingCSharpResponseAsync( TextDocumentIdentifier textDocumentIdentifier, long documentVersion, Range csharpRange, CancellationToken cancellationToken) { var parameter = new ProvideSemanticTokensRangeParams(textDocumentIdentifier, documentVersion, csharpRange); var request = await _languageServer.SendRequestAsync(LanguageServerConstants.RazorProvideSemanticTokensRangeEndpoint, parameter); var csharpResponse = await request.Returning <ProvideSemanticTokensResponse>(cancellationToken); if (csharpResponse is null) { // C# isn't ready yet, don't make Razor wait for it. Once C# is ready they'll send a refresh notification. return(Array.Empty <int>()); } else if (csharpResponse.HostDocumentSyncVersion != null && csharpResponse.HostDocumentSyncVersion != documentVersion) { // No C# response or C# is out of sync with us. Unrecoverable, return null to indicate no change. // Once C# syncs up they'll send a refresh notification. return(null); } var response = csharpResponse.Tokens ?? Array.Empty <int>(); return(response); }
/// <summary> /// To be called whenever a file is closed in the editor. /// Does nothing if the given file is listed as to be ignored. /// Otherwise the file content is reloaded from disk (in case changes in the editor are discarded without closing), and the diagnostics are updated. /// Invokes the given Action onError with a suitable message if the given file is not listed as being open in the editor. /// Throws an ArgumentException if the uri of the given text document identifier is null or not an absolute file uri. /// </summary> internal Task CloseFileAsync(TextDocumentIdentifier textDocument, Action <string, MessageType> onError = null) { if (!ValidFileUri(textDocument?.Uri)) { throw new ArgumentException("invalid text document identifier"); } _ = this.Projects.ManagerTaskAsync(textDocument.Uri, (manager, associatedWithProject) => // needs to be *first* (due to the modification of OpenFiles) { if (IgnoreFile(textDocument.Uri)) { return; } // Currently it is not possible to handle both the behavior of VS and VS Code for changes on disk in a manner that will never fail. // To mitigate the impact of failures we choose to ignore them silently. var removed = this.OpenFiles.TryRemove(textDocument.Uri, out FileContentManager __); #if DEBUG if (!removed) { onError?.Invoke($"Attempting to close file '{textDocument.Uri.LocalPath}' that is not currently listed as open in the editor.", MessageType.Error); } #endif if (!associatedWithProject) { _ = manager.TryRemoveSourceFileAsync(textDocument.Uri); } this.Publish(new PublishDiagnosticParams { Uri = textDocument.Uri, Diagnostics = new Diagnostic[0] }); }); // When edits are made in a file, but those are discarded by closing the file and hitting "no, don't save", // no notification is sent for the now discarded changes; // hence we reload the file content from disk upon closing. return(this.Projects.SourceFileChangedOnDiskAsync(textDocument.Uri, GetOpenFile)); // NOTE: relies on that the manager task is indeed executed first! }
public static async Task AssertHover(Server s, TextDocumentIdentifier document, SourceLocation position, string hoverText, IEnumerable <string> typeNames, SourceSpan?range = null, string expr = null) { var hover = await s.Hover(new TextDocumentPositionParams { textDocument = document, position = position, _expr = expr }); if (hoverText.EndsWith("*")) { // Check prefix first, but then show usual message for mismatched value if (!hover.contents.value.StartsWith(hoverText.Remove(hoverText.Length - 1))) { Assert.AreEqual(hoverText, hover.contents.value); } } else { Assert.AreEqual(hoverText, hover.contents.value); } if (typeNames != null) { AssertUtil.ContainsExactly(hover._typeNames, typeNames.ToArray()); } if (range.HasValue) { Assert.AreEqual(range.Value, (SourceSpan)hover.range); } }
public async Task RazorSemanticTokensRangeScrollingAsync() { var textDocumentIdentifier = new TextDocumentIdentifier(DocumentUri); var cancellationToken = CancellationToken.None; var documentVersion = 1; await UpdateDocumentAsync(documentVersion, DocumentSnapshot).ConfigureAwait(false); var documentLineCount = Range.End.Line; var lineCount = 0; while (lineCount != documentLineCount) { var newLineCount = Math.Min(lineCount + WindowSize, documentLineCount); var range = new Range(lineCount, 0, newLineCount, 0); await RazorSemanticTokenService !.GetSemanticTokensAsync( textDocumentIdentifier, range, DocumentSnapshot, documentVersion, cancellationToken); lineCount = newLineCount; } }
public void HideDiagnostics(TextDocumentIdentifier documentId) { languageServer.TextDocument.PublishDiagnostics(new PublishDiagnosticsParams { Uri = documentId.Uri, Diagnostics = new Container <Diagnostic>() }); }
public static Document?GetDocument(this Solution solution, TextDocumentIdentifier documentIdentifier, string?clientName = null) { var documents = solution.GetDocuments(documentIdentifier.Uri, clientName); if (documents.Length == 0) { return(null); } if (documents.Length > 1) { // We have more than one document; try to find the one that matches the right context if (documentIdentifier is VSTextDocumentIdentifier vsDocumentIdentifier) { if (vsDocumentIdentifier.ProjectContext != null) { var projectId = ProtocolConversions.ProjectContextToProjectId(vsDocumentIdentifier.ProjectContext); var matchingDocument = documents.FirstOrDefault(d => d.Project.Id == projectId); if (matchingDocument != null) { return(matchingDocument); } } } } // We either have only one document or have multiple, but none of them matched our context. In the // latter case, we'll just return the first one arbitrarily since this might just be some temporary mis-sync // of client and server state. return(documents[0]); }
public TSqlFormatterServiceTests() { textDocument = new TextDocumentIdentifier { Uri = "script file" }; docFormatParams = new DocumentFormattingParams() { TextDocument = textDocument, Options = new FormattingOptions() { InsertSpaces = true, TabSize = 4 } }; rangeFormatParams = new DocumentRangeFormattingParams() { TextDocument = textDocument, Options = new FormattingOptions() { InsertSpaces = true, TabSize = 4 }, Range = new ServiceLayer.Workspace.Contracts.Range() { // From first "(" to last ")" Start = new Position { Line = 0, Character = 16 }, End = new Position { Line = 0, Character = 56 } } }; }
public void DidChange(TextDocumentIdentifier textDocument, ICollection <TextDocumentContentChangeEvent> contentChanges) { Program.logWriter.WriteLine("Documento changed"); if (Session.Documents[textDocument.Uri] == null) { Program.logWriter.WriteLine("Unknown doc"); var item = new TextDocumentItem(); item.Uri = textDocument.Uri; var doc = new SessionDocument(item); var session = Session; doc.DocumentChanged += async(sender, args) => { Program.logWriter.WriteLine("Document changed"); // Lint the document when it's changed. var doc1 = ((SessionDocument)sender).Document; var diag1 = session.DiagnosticProvider.LintDocument(doc1, session.Settings.MaxNumberOfProblems); if (session.Documents.ContainsKey(doc1.Uri)) { // In case the document has been closed when we were linting… await session.Client.Document.PublishDiagnostics(doc1.Uri, diag1); } }; Session.Documents.TryAdd(textDocument.Uri, doc); } Program.logWriter.WriteLine("A"); Session.Documents[textDocument.Uri].NotifyChanges(contentChanges); Program.logWriter.WriteLine("B"); }
#pragma warning restore 0067 private async Task <VsProjectAnalyzer> FindAnalyzerAsync(TextDocumentIdentifier document) { if (document?.Uri == null) { return(null); } if (!_analyzerCache.TryGetValue(document.Uri, out var analyzer)) { var filePath = document.Uri.LocalPath; if (string.IsNullOrEmpty(filePath)) { return(null); } if (_uiThread != null) { // TODO: Use URI for more accurate lookup analyzer = await _uiThread.InvokeTask(async() => (await _serviceProvider.FindAllAnalyzersForFile(filePath)).FirstOrDefault() as VsProjectAnalyzer ); } analyzer = _analyzerCache.GetOrAdd(document.Uri, analyzer); } return(analyzer); }
/// <summary> /// Used to reload the file content when a file is saved. /// Does nothing if the given file is listed as to be ignored. /// Expects to get the entire content of the file at the time of saving as argument. /// Throws an ArgumentException if the uri of the given text document identifier is null or not an absolute file uri. /// Throws an ArgumentNullException if the given content is null. /// </summary> internal Task SaveFileAsync(TextDocumentIdentifier textDocument, string fileContent) { if (!ValidFileUri(textDocument?.Uri)) { throw new ArgumentException("invalid text document identifier"); } if (fileContent == null) { throw new ArgumentNullException(nameof(fileContent)); } return(this.Projects.ManagerTaskAsync(textDocument.Uri, (manager, __) => { if (IgnoreFile(textDocument.Uri)) { return; } // Currently it is not possible to handle both the behavior of VS and VS Code for changes on disk in a manner that will never fail. // To mitigate the impact of failures we choose to ignore them silently and do our best to recover. if (!this.OpenFiles.TryGetValue(textDocument.Uri, out var file)) { file = CompilationUnitManager.InitializeFileManager(textDocument.Uri, fileContent, this.Publish, manager.LogException); this.OpenFiles.TryAdd(textDocument.Uri, file); _ = manager.AddOrUpdateSourceFileAsync(file); } else { _ = manager.AddOrUpdateSourceFileAsync(file, fileContent); // let's reload the file content on saving } })); }
public static T FindDocumentInProjectContext <T>( this ImmutableArray <T> documents, TextDocumentIdentifier documentIdentifier ) where T : TextDocument { if (documents.Length > 1) { // We have more than one document; try to find the one that matches the right context if (documentIdentifier is VSTextDocumentIdentifier vsDocumentIdentifier) { if (vsDocumentIdentifier.ProjectContext != null) { var projectId = ProtocolConversions.ProjectContextToProjectId( vsDocumentIdentifier.ProjectContext ); var matchingDocument = documents.FirstOrDefault( d => d.Project.Id == projectId ); if (matchingDocument != null) { return(matchingDocument); } } } } // We either have only one document or have multiple, but none of them matched our context. In the // latter case, we'll just return the first one arbitrarily since this might just be some temporary mis-sync // of client and server state. return(documents[0]); }
public override async Task <SemanticTokens?> GetSemanticTokensAsync( TextDocumentIdentifier textDocumentIdentifier, Range range, CancellationToken cancellationToken) { var documentPath = textDocumentIdentifier.Uri.GetAbsoluteOrUNCPath(); if (documentPath is null) { return(null); } var documentInfo = await TryGetDocumentInfoAsync(documentPath, cancellationToken).ConfigureAwait(false); if (documentInfo is null) { return(null); } var(documentSnapshot, documentVersion) = documentInfo.Value; var tokens = await GetSemanticTokensAsync( textDocumentIdentifier, range, documentSnapshot, documentVersion, cancellationToken); return(tokens); }
public static async Task AssertReferences(Server s, TextDocumentIdentifier document, SourceLocation position, IEnumerable <string> contains, IEnumerable <string> excludes, string expr = null, bool returnDefinition = false) { var refs = (await s.FindReferences(new ReferencesParams { textDocument = document, position = position, _expr = expr, context = new ReferenceContext { includeDeclaration = true, _includeDefinitionRanges = returnDefinition, _includeValues = true } })); IEnumerable <string> set; if (returnDefinition) { set = refs.Select(r => $"{r._kind ?? ReferenceKind.Reference};{r._definitionRange}"); } else { set = refs.Select(r => $"{r._kind ?? ReferenceKind.Reference};{r.range}"); } AssertUtil.CheckCollection( set, contains, excludes ); }
private Document GetDocument(TextDocumentIdentifier documentIdentifier) { var filePath = ResolveFilePath(documentIdentifier.Uri); return(_workspace.CurrentDocuments .GetDocumentsWithFilePath(filePath) .FirstOrDefault()); }
public DafnyDocument? CloseDocument(TextDocumentIdentifier documentId) { DafnyDocument? document; if(!_documents.TryRemove(documentId.Uri, out document)) { _logger.LogTrace("the document {} was already closed", documentId); return null; } return document; }
public async Task DidClose(TextDocumentIdentifier textDocument) { Session.RemoveDocument(textDocument.Uri); if (textDocument.Uri.IsUntitled()) { await Session.Client.Document.PublishDiagnostics(textDocument.Uri, new Diagnostic[0]); } }
public CompletionList Completion(TextDocumentIdentifier textDocument, Position position, CompletionContext context) { var doc = Session.DocumentStates[textDocument.Uri]; doc.AnalyzeAsync(); return (Session.Project.GetCompletionList(doc, position, context)); //position, Session.PageInfoStore)); }
public async Task DidClose(TextDocumentIdentifier textDocument) { if (textDocument.Uri.IsUntitled()) { await Client.Document.PublishDiagnostics(textDocument.Uri, new Diagnostic[0]); } Session.Documents.TryRemove(textDocument.Uri, out _); }
public SignatureHelp SignatureHelp(TextDocumentIdentifier textDocument, Position position) { return(new SignatureHelp(new List <SignatureInformation> { new SignatureInformation("**Function1**", "Documentation1"), new SignatureInformation("**Function2** <strong>test</strong>", "Documentation2"), })); }
// Internal and virtual for testing only internal virtual async Task <SemanticRange[]?> GetCSharpSemanticRangesAsync( RazorCodeDocument codeDocument, TextDocumentIdentifier textDocumentIdentifier, Range razorRange, long documentVersion, CancellationToken cancellationToken, string?previousResultId = null) { // We'll try to call into the mapping service to map to the projected range for us. If that doesn't work, // we'll try to find the minimal range ourselves. if (!_documentMappingService.TryMapToProjectedDocumentRange(codeDocument, razorRange, out var csharpRange) && !TryGetMinimalCSharpRange(codeDocument, razorRange, out csharpRange)) { // There's no C# in the range. return(Array.Empty <SemanticRange>()); } var csharpResponse = await GetMatchingCSharpResponseAsync(textDocumentIdentifier, documentVersion, csharpRange, cancellationToken); // Indicates an issue with retrieving the C# response (e.g. no response or C# is out of sync with us). // Unrecoverable, return default to indicate no change. We've already queued up a refresh request in // `GetMatchingCSharpResponseAsync` that will cause us to retry in a bit. if (csharpResponse is null) { _logger.LogWarning($"Issue with retrieving C# response for Razor range: {razorRange}"); return(null); } var razorRanges = new List <SemanticRange>(); SemanticRange?previousSemanticRange = null; for (var i = 0; i < csharpResponse.Length; i += TokenSize) { var lineDelta = csharpResponse[i]; var charDelta = csharpResponse[i + 1]; var length = csharpResponse[i + 2]; var tokenType = csharpResponse[i + 3]; var tokenModifiers = csharpResponse[i + 4]; var semanticRange = DataToSemanticRange( lineDelta, charDelta, length, tokenType, tokenModifiers, previousSemanticRange); if (_documentMappingService.TryMapFromProjectedDocumentRange(codeDocument, semanticRange.Range, out var originalRange)) { var razorSemanticRange = new SemanticRange(semanticRange.Kind, originalRange, tokenModifiers); if (razorRange is null || razorRange.OverlapsWith(razorSemanticRange.Range)) { razorRanges.Add(razorSemanticRange); } } previousSemanticRange = semanticRange; } var result = razorRanges.ToArray(); return(result); }
public Task <SignatureHelp> SignatureHelp(TextDocumentIdentifier textDocument, Position position) { using (new DebugMeasureTime("textDocument/signatureHelp")) { return(MainThreadPriority.SendAsync(async() => { var doc = Documents.GetDocument(textDocument.Uri); return doc != null ? await doc.GetSignatureHelpAsync(position) : new SignatureHelp(); }, ThreadPostPriority.Background)); } }
public async Task <CompletionList> Completion(TextDocumentIdentifier textDocument, Position position, CancellationToken ct) { var doc = Session.DocumentStates[textDocument.Uri]; await doc.AnalyzeAsync(ct); return (Session.Project.GetCompletionList(doc, position)); //position, Session.PageInfoStore)); }
private async Task CloseDocumentAndHideDiagnosticsAsync(TextDocumentIdentifier documentId) { try { await documents.CloseDocumentAsync(documentId); } catch (Exception e) { logger.LogError(e, "error while closing the document"); } diagnosticPublisher.HideDiagnostics(documentId); }
public async Task <Hover> Hover(TextDocumentIdentifier textDocument, Position position, CancellationToken ct) { // Note that Hover is cancellable. await Task.Delay(1000, ct); return(new Hover { Contents = "Test _hover_ @" + position + "\n\n" + textDocument }); }
public async Task <CompletionList> Completion(TextDocumentIdentifier textDocument, Position position, CancellationToken ct) { var doc = Session.DocumentStates[textDocument.Uri]; await doc.AnalyzeAsync(ct); var(items, isIncomplete) = doc.LintedDocument.GetCompletionItems(position, Session.PageInfoStore); return(new CompletionList(items, isIncomplete)); }
public async Task<DafnyDocument?> SaveDocumentAsync(TextDocumentIdentifier documentId, CancellationToken cancellationToken) { if(VerifyOnSave) { return await VerifyDocumentAsync(documentId, cancellationToken); } if(_documents.TryGetValue(documentId.Uri, out var document)) { return document; } return null; }
public Task <CompletionList> completion(TextDocumentIdentifier textDocument, Position position) { using (new DebugMeasureTime("textDocument/completion")) { return(MainThreadPriority.SendAsync(() => { var doc = Documents.GetDocument(textDocument.Uri); return Task.FromResult(doc != null ? doc.GetCompletions(position) : new CompletionList()); }, ThreadPostPriority.Background)); } }
protected override VSInternalWorkspaceDiagnosticReport CreateReport(TextDocumentIdentifier identifier, VisualStudio.LanguageServer.Protocol.Diagnostic[]?diagnostics, string?resultId) => new VSInternalWorkspaceDiagnosticReport { TextDocument = identifier, Diagnostics = diagnostics, ResultId = resultId, // Mark these diagnostics as having come from us. They will be superseded by any diagnostics for the // same file produced by the DocumentPullDiagnosticHandler. Identifier = WorkspaceDiagnosticIdentifier, };