private bool ReloadWorkspaceAndWaitForCompletion(TextDocumentManager currentDocumentManager, out AppState appState, out LanguageServiceProviders providers) { // In case of adding/removing a document we should recompute the workspace and wait for completion, // some other code may rely that the workspace is ready when the method that calls this one is finished. ReloadWorkspace(currentDocumentManager); return(TryWaitForWorkspaceLoaded(out appState, out providers)); }
public static AppState TryCreateWorkspace( TextDocumentManager documentManager, Uri rootFolder, EventHandler <WorkspaceProgressEventArgs> progressHandler, TestContext?testContext = null, DScriptSettings settings = null) { documentManager = documentManager ?? new TextDocumentManager(new PathTable()); // Need to clear event handlers to detach old instances like IncrementalWorkspaceProvider from the new events. documentManager.ClearEventHandlers(); var pathTable = documentManager.PathTable; // Check if we need to prepopulate the document manager // with some documents (for testing) if (testContext.HasValue) { foreach (var document in testContext.Value.PrePopulatedDocuments) { documentManager.Add(AbsolutePath.Create(pathTable, document.Uri), document); } } // Bootstrap the DScript frontend to parse/type-check the workspace given a build config var loggingContext = new LoggingContext("LanguageServer"); var fileSystem = new PassThroughFileSystem(pathTable); var engineContext = EngineContext.CreateNew( cancellationToken: System.Threading.CancellationToken.None, pathTable: pathTable, fileSystem: fileSystem); var engineAbstraction = new LanguageServiceEngineAbstraction(documentManager, pathTable, engineContext.FileSystem); var frontEndContext = engineContext.ToFrontEndContext(loggingContext); var rootFolderAsAbsolutePath = rootFolder.ToAbsolutePath(pathTable); if (!WorkspaceBuilder.TryBuildWorkspaceForIde( frontEndContext: frontEndContext, engineContext: engineContext, frontEndEngineAbstraction: engineAbstraction, rootFolder: rootFolderAsAbsolutePath, progressHandler: progressHandler, workspace: out var workspace, skipNuget: settings?.SkipNuget ?? false, // Do not skip nuget by default. controller: out var controller)) { // The workspace builder fails when the workspace contains any errors // however, we bail out only if the workspace is null, which happens only // when the config could not be parsed if (workspace == null || controller == null) { return(null); } } var incrementalWorkspaceProvider = new IncrementalWorkspaceProvider(controller, pathTable, workspace, documentManager, testContext); return(new AppState(engineAbstraction, documentManager, pathTable, incrementalWorkspaceProvider, workspace)); }
/// <nodoc /> public static AppState TryCreateWorkspace( Uri rootFolder, EventHandler <WorkspaceProgressEventArgs> progressHandler, TestContext?testContext = null) { var documentManager = new TextDocumentManager(new PathTable()); return(TryCreateWorkspace(documentManager, rootFolder, progressHandler, testContext)); }
private void ReloadWorkspace(TextDocumentManager currentDocumentManager = null) { lock (m_loadWorkspaceLock) { if (m_workspaceLoadingState != WorkspaceLoadingState.InProgress) { m_workspaceLoadingState = WorkspaceLoadingState.InProgress; m_workspaceLoadingTask.Reset(); } } Analysis.IgnoreResult(LoadWorkspaceAsync(currentDocumentManager), "Fire and forget"); }
private AppState( FrontEndEngineAbstraction engineAbstraction, TextDocumentManager documentManager, PathTable pathTable, IncrementalWorkspaceProvider incrementalWorkspaceProvider, Workspace workspace) { EngineAbstraction = engineAbstraction; DocumentManager = documentManager; PathTable = pathTable; IncrementalWorkspaceProvider = incrementalWorkspaceProvider; m_workspace = workspace; }
/// <summary> /// Creates the BuildXL workspace and initializes the language service providers. /// </summary> /// <remarks> /// This must be called when a text document is actually opened. The order VSCode /// calls the plugin is "Initialize" -> "DidConfigurationChange" -> DidOpenTextDocument. /// So, if you attempt to create the workspace, and initialize the providers during the /// initialization phase, then you will not have proper access to any configuration settings /// the user may have made. /// </remarks> private Task <(WorkspaceLoadingState workspaceLoadingState, AppState appState, LanguageServiceProviders languageServiceProviders)> LoadWorkspaceAsync(TextDocumentManager documentManager = null) { var workspaceLoadingTask = m_workspaceLoadingTask.GetOrCreate(async() => { var result = await Task.Run(() => { try { m_progressReporter.ReportWorkspaceInit(); WorkspaceLoadingState workspaceLoadingState; if (m_rootUri == null) { throw new ArgumentException("Root directory was not passed from VSCode via the rootUri configuration value"); } var appState = AppState.TryCreateWorkspace(documentManager, m_rootUri, (s, ea) => { // "Casting" the EventArgs object from the BuildXL library to the "local" version // to avoid pulling in all of its dependencies during build. var rpcEventArgs = BuildXL.Ide.JsonRpc.WorkspaceProgressEventArgs.Create( (BuildXL.Ide.JsonRpc.ProgressStage)ea.ProgressStage, ea.NumberOfProcessedSpecs, ea.TotalNumberOfSpecs); m_progressReporter.ReportWorkspaceInProgress(WorkspaceLoadingParams.InProgress(rpcEventArgs)); }, m_testContext, m_settings); if (appState == null || appState.HasUnrecoverableFailures()) { workspaceLoadingState = WorkspaceLoadingState.Failure; m_progressReporter.ReportWorkspaceFailure(m_tracer.LogFilePath, OpenLogFile); } else { workspaceLoadingState = WorkspaceLoadingState.Success; m_progressReporter.ReportWorkspaceSuccess(); } LanguageServiceProviders providers = null; lock (m_loadWorkspaceLock) { if (workspaceLoadingState == WorkspaceLoadingState.Success) { // In practice you should not make callouts while holding // a lock. Initializing the providers sets members of this // class and also relies on members of the app-state. // So, we do want to block callers until initialization of // the providers is complete, however, be warned that // if a provider ever calls back into the app it could // cause a deadlock. providers = InitializeProviders(appState); } } return(workspaceLoadingState, appState, providers); } catch (Exception e) { var errorMessage = e.ToStringDemystified(); Logger.LanguageServerUnhandledInternalError(LoggingContext, errorMessage); m_progressReporter.ReportWorkspaceFailure(m_tracer.LogFilePath, OpenLogFile); m_testContext.GetValueOrDefault().ErrorReporter?.Invoke(errorMessage); return(WorkspaceLoadingState.Failure, (AppState)null, (LanguageServiceProviders)null); } }); return(result); }); // Changing the workspace loading state once the task is finished. workspaceLoadingTask.ContinueWith(t => { m_workspaceLoadingState = t.Result.Item1; }); return(workspaceLoadingTask); }
/// <nodoc /> public LanguageServiceEngineAbstraction(TextDocumentManager documentManager, PathTable pathTable, BuildXL.FrontEnd.Sdk.FileSystem.IFileSystem fileSystem) : base(pathTable, fileSystem) { m_documentManager = documentManager; }