示例#1
0
 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));
 }
示例#2
0
        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));
        }
示例#3
0
        /// <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));
        }
示例#4
0
        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");
        }
示例#5
0
 private AppState(
     FrontEndEngineAbstraction engineAbstraction,
     TextDocumentManager documentManager,
     PathTable pathTable,
     IncrementalWorkspaceProvider incrementalWorkspaceProvider,
     Workspace workspace)
 {
     EngineAbstraction            = engineAbstraction;
     DocumentManager              = documentManager;
     PathTable                    = pathTable;
     IncrementalWorkspaceProvider = incrementalWorkspaceProvider;
     m_workspace                  = workspace;
 }
示例#6
0
        /// <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);
        }
示例#7
0
 /// <nodoc />
 public LanguageServiceEngineAbstraction(TextDocumentManager documentManager, PathTable pathTable, BuildXL.FrontEnd.Sdk.FileSystem.IFileSystem fileSystem)
     : base(pathTable, fileSystem)
 {
     m_documentManager = documentManager;
 }