private void ValidateTextDocument(TextDocumentItem document) { if (!ValaDocumentValidator.IsHandled(document)) { return; } List <Diagnostic> diagnostics = new List <Diagnostic>(); try { List <Diagnostic> messages = _validator.Validate(document.GetDocumentPath()); diagnostics.AddRange(messages); } catch (ParseException ex) { if (ex.error_type != ParseError.SYNTAX) { throw ex; } diagnostics.Add(new Diagnostic { severity = DiagnosticSeverity.Error, message = ex.Message, source = "syntax" }); } finally { Proxy.TextDocument.PublishDiagnostics(new PublishDiagnosticsParams { uri = document.uri, diagnostics = diagnostics.ToArray() }); } }
private Task CloseDocumentAndWaitAsync(TextDocumentItem documentItem) { _client.DidCloseTextDocument(new DidCloseTextDocumentParams { TextDocument = documentItem }); return(_client.WaitForNotificationCompletionAsync(documentItem.Uri, CancellationToken)); }
// routines related to tracking the editor state /// <summary> /// To be called whenever a file is opened in the editor. /// Does nothing if the given file is listed as to be ignored. /// Otherwise publishes suitable diagnostics for it. /// Invokes the given Action showError with a suitable message if the given file cannot be loaded. /// Invokes the given Action logError with a suitable message if the given file cannot be associated with a compilation unit, /// or if the given file is already 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. /// Throws an ArgumentNullException if the given content is null. /// </summary> internal Task OpenFileAsync(TextDocumentItem textDocument, Action <string, MessageType> showError = null, Action <string, MessageType> logError = null) { if (!ValidFileUri(textDocument?.Uri)) { throw new ArgumentException("invalid text document identifier"); } if (textDocument.Text == null) { throw new ArgumentNullException(nameof(textDocument.Text)); } _ = this.Projects.ManagerTaskAsync(textDocument.Uri, (manager, associatedWithProject) => { if (IgnoreFile(textDocument.Uri)) { return; } var newManager = CompilationUnitManager.InitializeFileManager(textDocument.Uri, textDocument.Text, this.Publish, ex => { showError?.Invoke($"Failed to load file '{textDocument.Uri.LocalPath}'", MessageType.Error); manager.LogException(ex); }); // 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 just log them as info. var file = this.OpenFiles.GetOrAdd(textDocument.Uri, newManager); if (file != newManager) // this may be the case (depending on the editor) e.g. when opening a version control diff ... { showError?.Invoke($"Version control and opening multiple versions of the same file in the editor are currently not supported. \n" + $"Intellisense has been disable for the file '{textDocument.Uri.LocalPath}'. An editor restart is required to enable intellisense again.", MessageType.Error); #if DEBUG if (showError == null) { logError?.Invoke("Attempting to open a file that is already open in the editor.", MessageType.Error); } #endif this.IgnoreEditorUpdatesFor(textDocument.Uri); this.OpenFiles.TryRemove(textDocument.Uri, out FileContentManager _); if (!associatedWithProject) { _ = manager.TryRemoveSourceFileAsync(textDocument.Uri); } this.Publish(new PublishDiagnosticParams { Uri = textDocument.Uri, Diagnostics = new Diagnostic[0] }); return; } if (!associatedWithProject) { logError?.Invoke( $"The file {textDocument.Uri.LocalPath} is not associated with a compilation unit. Only syntactic diagnostics are generated." , MessageType.Info); } _ = manager.AddOrUpdateSourceFileAsync(file); }); // reloading from disk in case we encountered a file already open error above return(this.Projects.SourceFileChangedOnDiskAsync(textDocument.Uri, GetOpenFile)); // NOTE: relies on that the manager task is indeed executed first! }
Task <Unit> Parse(TextDocumentItem document) { return(Task.Run(() => { Update(document); return Unit.Value; })); }
private void RecomputeWorkspace(TextDocumentItem document) { var path = document.Uri.ToAbsolutePath(m_pathTable); // Need to check if parsedModule is prelude or configuration module. // If the parsed module is the configuration module, then full reanalysis is required. ParsedModule parsedModule = m_workspace.TryGetModuleBySpecFileName(path); ModuleDefinition moduleDefinition; if (parsedModule != null) { moduleDefinition = parsedModule.Definition; } else { // This should never happen: all the new files trigger full workspace reconstruction. return; } try { var updatedWorkspace = GetUpdatedWorkspace(parsedModule, moduleDefinition, path); m_workspace = updatedWorkspace; } catch (Exception e) { // TODO: saqadri - log exception, but for now just swallow Debug.Fail($"Workspace recomputation threw an exception: {e}"); } }
public Task OpenFileAsync(TextDocumentItem textDocument, Action <string, MessageType> showError, Action <string, MessageType> logError) { if (!ValidFileUri(textDocument.Uri)) { throw new ArgumentException("invalid text document identifier"); } _ = this.ManagerTaskAsync(textDocument.Uri, (associatedWithProject) => { if (this.IgnoreFile(textDocument.Uri)) { return; } var file = this.openFiles.GetOrAdd(textDocument.Uri, textDocument.Uri); if (!associatedWithProject) { logError?.Invoke( $"The file {textDocument.Uri.LocalPath} is not associated with a compilation unit. Only syntactic diagnostics are generated.", MessageType.Info); } // _ = manager.AddOrUpdateSourceFileAsync(file); }); return(Task.CompletedTask);//this.projects.SourceFileChangedOnDiskAsync(textDocument.Uri, this.GetOpenFile); // NOTE: relies on that the manager task is indeed executed first! }
private bool TryGetOrAddDocument(AbsolutePath path, VersionedTextDocumentIdentifier documentIdentifier, TextDocumentContentChangeEvent[] changeEvents, out TextDocumentItem document) { if (!m_documents.TryGetValue(path, out document)) { // The document is missing from the internal storage and the changeset is empty. // Can't do anything here. if (changeEvents.Length == 0) { return(false); } lock (m_documents) { if (!m_documents.TryGetValue(path, out document)) { document = new TextDocumentItem() { Version = documentIdentifier.Version, Uri = documentIdentifier.Uri, Text = changeEvents.Last().Text, }; document = m_documents.GetOrAdd(path, document); return(true); } } } return(true); }
public void Started(TextDocumentItem textDocument) { _languageServer.SendNotification(new VerificationStartedParams { Uri = textDocument.Uri, Version = textDocument.Version, }); }
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"); }
public async Task <Dafny.Program> ParseAsync(TextDocumentItem document, ErrorReporter errorReporter, CancellationToken cancellationToken) { await _mutex.WaitAsync(cancellationToken); try { // Ensure that the statically kept scopes are empty when parsing a new document. Type.ResetScopes(); var module = new LiteralModuleDecl(new DefaultModuleDecl(), null); var builtIns = new BuiltIns(); var parseErrors = Parser.Parse( document.Text, document.Uri.GetFileSystemPath(), // We use the full path as filename so we can better re-construct the DocumentUri for the definition lookup. document.Uri.GetFileSystemPath(), module, builtIns, errorReporter ); if (parseErrors != 0) { _logger.LogDebug("encountered {} errors while parsing {}", parseErrors, document.Uri); } if (!TryParseIncludesOfModule(module, builtIns, errorReporter)) { _logger.LogDebug("encountered error while parsing the includes of {}", document.Uri); } // TODO Remove PoC workaround: the file system path is used as a program name to return(new Dafny.Program(document.Uri.GetFileSystemPath(), module, builtIns, errorReporter)); } finally { _mutex.Release(); } }
private static void DoReportDiagnostics(Workspace workspace, TextDocumentItem document, PathTable pathTable, ProviderContext providerContext) { // We report diagnostics for the document var documentUri = document.Uri; var semanticModel = workspace.GetSemanticModel(); Contract.Assert(semanticModel != null, "We should always get a semantic model since we don't cancel on first failure"); // These are all the syntactic diagnostics that come from the workspace, across all files var allDiagnostics = workspace.GetAllParsingAndBindingErrors(); // If the file is part of the workspace, we add the type checking errors for that file only var path = documentUri.ToAbsolutePath(pathTable); if (workspace.TryGetSourceFile(path, out var spec)) { allDiagnostics = allDiagnostics.Union(semanticModel.GetTypeCheckingDiagnosticsForFile(spec)); } var publishDiagnostics = FilterDiagnosticsForSpec(documentUri, allDiagnostics, pathTable); // Need to report even if publishedDiagnostics is empty to clear the diagnostics list in IDE. Analysis.IgnoreResult(providerContext.PublishDiagnosticsAsync(publishDiagnostics), "Fire and forget"); }
public TextDocumentItem ApplyChange(TextDocumentItem originalTextDocument, DidChangeTextDocumentParams documentChange, CancellationToken cancellationToken) { return(originalTextDocument with { Version = documentChange.TextDocument.Version, Text = ApplyTextChanges(originalTextDocument.Text, documentChange.ContentChanges, cancellationToken) }); }
public async Task <CompilationUnit> ResolveSymbolsAsync(TextDocumentItem textDocument, Dafny.Program program, CancellationToken cancellationToken) { int parserErrors = GetErrorCount(program); if (parserErrors > 0) { _logger.LogTrace("document {} had {} parser errors, skipping symbol resolution", textDocument.Uri, parserErrors); return(new CompilationUnit(program)); } // TODO The resolution requires mutual exclusion since it sets static variables of classes like Microsoft.Dafny.Type. // Although, the variables are marked "ThreadStatic" - thus it might not be necessary. But there might be // other classes as well. await _resolverMutex.WaitAsync(cancellationToken); try { if (!RunDafnyResolver(textDocument, program)) { // We cannot proceeed without a successful resolution. Due to the contracts in dafny-lang, we cannot // access a property without potential contract violations. For example, a variable may have an // unresolved type represented by null. However, the contract prohibits the use of the type property // because it must not be null. return(new CompilationUnit(program)); } } finally { _resolverMutex.Release(); } return(new SymbolDeclarationResolver(_logger, cancellationToken).ProcessProgram(program)); }
public void OnTextDocumentOpened(DidOpenTextDocumentParams messageParams) { this.textDocument = messageParams.TextDocument; SendDiagnostics(); }
public async Task DidOpen(TextDocumentItem textDocument) { try { var doc = new SessionDocument(textDocument); 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); var colors = session.ColorProvider.ColorDocument(doc1); 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); await session.Client.Document.ColorProvider(doc1.Uri, colors); } }; if (Session == null) { Program.logWriter.WriteLine("Session is null"); } if (Session.Documents == null) { Program.logWriter.WriteLine("Session.Documents is null"); } Session.Documents.TryAdd(textDocument.Uri, doc); if (Session.DiagnosticProvider == null) { Program.logWriter.WriteLine("Session.DiagnosticProvider is null"); } if (Session.Settings == null) { Program.logWriter.WriteLine("Session.Settings is null"); } if (doc.Document == null) { Program.logWriter.WriteLine("doc.Document is null"); } var diag = Session.DiagnosticProvider.LintDocument(doc.Document, Session.Settings.MaxNumberOfProblems); await Client.Document.PublishDiagnostics(textDocument.Uri, diag); var color = Session.ColorProvider.ColorDocument(doc.Document); await Client.Document.ColorProvider(textDocument.Uri, color); } catch (Exception exc) { Program.logWriter.WriteLine(exc.Message + "\r\n" + exc.StackTrace); } }
public async Task<DafnyDocument> LoadDocumentAsync(TextDocumentItem textDocument, CancellationToken cancellationToken) { var dafnyDocument = await _documentLoader.LoadAsync(textDocument, VerifyOnLoad, cancellationToken); var databaseDocument = _documents.AddOrUpdate(textDocument.Uri, dafnyDocument, (uri, old) => dafnyDocument.Version > old.Version ? dafnyDocument : old); if (databaseDocument != dafnyDocument) { _logger.LogDebug("a newer version of {} was already loaded", textDocument.Uri); } return databaseDocument; }
public void Completed(TextDocumentItem textDocument, bool verified) { _languageServer.SendNotification(new VerificationCompletedParams { Uri = textDocument.Uri, Version = textDocument.Version, Verified = verified }); }
public DocumentState AddOrUpdateDocument(TextDocumentItem doc) { var ds = new DocumentState(TextDocument.Load <FullTextDocument>(doc), WiktextParser, loggerFactory); DocumentStates[doc.Uri] = ds; Attach(ds); return(ds); }
public void SendStatusNotification(TextDocumentItem textDocument, CompilationStatus status) { languageServer.SendNotification(new CompilationStatusParams { Uri = textDocument.Uri, Version = textDocument.Version, Status = status }); }
public override async Task <WorkspaceEdit> Handle(RenameParams request, CancellationToken cancellationToken) { return(await Task.Run(() => { var link = RenameInfo.GetLink(_languageServer, request.TextDocument.Uri.ToUri(), request.Position); if (link == null) { return new WorkspaceEdit(); } var grouped = link.Group(); var documentChanges = new List <WorkspaceEditDocumentChange>(); foreach (var group in grouped) { List <TextEdit> edits = new List <TextEdit>(); foreach (var renameRange in group.Links) { edits.Add(new TextEdit() { NewText = request.NewName, Range = renameRange }); } var document = _languageServer.DocumentHandler.TextDocumentFromUri(group.Uri)?.AsItem(); // document will be null if the editor doesn't have the document of the group opened. if (document == null) { ImportedScript importedScript = _languageServer.FileGetter.GetImportedFile(group.Uri); document = new TextDocumentItem() { Uri = group.Uri, Text = importedScript.Content, LanguageId = "ostw" }; } WorkspaceEditDocumentChange edit = new WorkspaceEditDocumentChange(new TextDocumentEdit() { Edits = edits.ToArray(), TextDocument = new VersionedTextDocumentIdentifier() { Version = document.Version, Uri = document.Uri } }); documentChanges.Add(edit); } return new WorkspaceEdit() { DocumentChanges = documentChanges }; })); }
public void Add(TextDocumentItem document) { if (_all.Any(x => x.uri == document.uri)) { return; } _all.Add(document); OnChanged(document); }
/// <nodoc /> protected IdeProviderBase(ProviderContext providerContext) { ProviderContext = providerContext; JsonRpc = providerContext.JsonRpc; PathTable = providerContext.PathTable; m_incrementalWorkspaceProvider = providerContext.IncrementalWorkspaceProvider; m_incrementalWorkspaceProvider.WorkspaceRecomputed += OnWorkspaceRecomputed; ChangedTextDocumentItems = new TextDocumentItem[0]; }
public void Add(TextDocumentItem document) { if (_documents.ContainsKey(document.uri)) { return; } _documents.Add(document.uri, document); OnChanged(document); }
private void ApplyChanges(TextDocumentItem documentItem, params TextDocumentContentChangeEvent[] changes) { client.DidChangeTextDocument(new DidChangeTextDocumentParams { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = documentItem.Uri, Version = documentItem.Version + 1 }, ContentChanges = changes }); }
private Task <Hover> RequestHover(TextDocumentItem documentItem, Position position) { return(_client.RequestHover( new HoverParams { TextDocument = documentItem.Uri, Position = position }, CancellationToken )); }
/// <inheritdoc /> protected override void OnLoad(TextDocumentItem doc) { base.OnLoad(doc); if (string.IsNullOrEmpty(Content)) { _LineStarts = emptyLineStarts; return; } _LineStarts = GetLineStarts(Content).ToArray(); }
public void OnTextDocumentOpened(DidOpenTextDocumentParams messageParams) { this.textDocument = messageParams.TextDocument; lock (textDocuments) { textDocuments.Add(messageParams.TextDocument); } SendDiagnostics(); }
protected Task ApplyChangeAndWaitCompletionAsync(TextDocumentItem documentItem, Range range, string newText) { return(ApplyChangesAndWaitCompletionAsync( documentItem, new TextDocumentContentChangeEvent { Text = newText, Range = range } )); }
private Task <SignatureHelp> RequestSignatureHelpAsync(TextDocumentItem documentItem, Position position) { // TODO at this time we do not set the context since it appears that's also the case when used within VSCode. return(client.RequestSignatureHelp( new SignatureHelpParams { TextDocument = documentItem.Uri, Position = position }, CancellationToken )); }
protected Task ApplyChangesAndWaitCompletionAsync(TextDocumentItem documentItem, params TextDocumentContentChangeEvent[] changes) { Client.DidChangeTextDocument(new DidChangeTextDocumentParams { TextDocument = new VersionedTextDocumentIdentifier { Uri = documentItem.Uri, Version = documentItem.Version + 1 }, ContentChanges = changes }); return(Client.WaitForNotificationCompletionAsync(documentItem.Uri, CancellationToken)); }