Skip to content

Commit

Permalink
Fix missing imports due to pylance thinking open documents are under …
Browse files Browse the repository at this point in the history
…default workspace (#8033)

* wip

* package wait time

* revert analyze wait times

* update messaging

* initialize folders when sending the pylance initialize call. this way we wont be creating a default workspace if textdocument/didopen is sent before workspacefolders are updated

* return list
  • Loading branch information
bschnurr authored Oct 21, 2024
1 parent e2e4553 commit 970eec2
Showing 1 changed file with 38 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.PythonTools.Common.Core.Disposables;
using Microsoft.PythonTools.Common.Infrastructure;
using Microsoft.PythonTools.Common.Parsing;
using Microsoft.PythonTools.Infrastructure;
using Microsoft.PythonTools.Interpreter;
using Microsoft.PythonTools.LanguageServerClient.FileWatcher;
Expand Down Expand Up @@ -99,7 +96,7 @@ internal sealed class PythonLanguageClient : ILanguageClient, ILanguageClientCus
private bool _sentInitialWorkspaceFolders = false;
private List<WorkspaceFolder> _workspaceFolders = new List<WorkspaceFolder>();
private FileWatcher.Listener _fileListener;
private static TaskCompletionSource<int> _readyTcs = new System.Threading.Tasks.TaskCompletionSource<int>();
private static TaskCompletionSource<int> _readyTcs = new TaskCompletionSource<int>();
private bool _loaded = false;
private Timer _deferredSettingsChangedTimer;
private const int _defaultSettingsDelayMS = 2000;
Expand Down Expand Up @@ -138,7 +135,7 @@ public async Task<Connection> ActivateAsync(CancellationToken token) {
await JoinableTaskContext.Factory.SwitchToMainThreadAsync();
CreateClientContexts();

_deferredSettingsChangedTimer = new Timer(OnDeferredSettingsChanged, state: null, Timeout.Infinite, Timeout.Infinite);
_deferredSettingsChangedTimer = new Timer(state => TriggerWorkspaceUpdateConfig(), state: null, Timeout.Infinite, Timeout.Infinite);
_analysisOptions = Site.GetPythonToolsService().AnalysisOptions;
_advancedEditorOptions = Site.GetPythonToolsService().AdvancedEditorOptions;
_analysisOptions.Changed += OnSettingsChanged;
Expand Down Expand Up @@ -241,8 +238,16 @@ private async Task OnWorkspaceFolders(object sender, WorkspaceFolders.WorkspaceF

public async Task OnServerInitializedAsync() {
IsInitialized = true;
// Set _workspaceFoldersSupported to true and send to either workspace open or solution open
OnWorkspaceFolderWatched(this, EventArgs.Empty);
await TriggerWorkspaceUpdateConfig();
}

private Task TriggerWorkspaceUpdateConfig() {
Debug.WriteLine("Settings Changed");
return InvokeDidChangeConfigurationAsync(new LSP.DidChangeConfigurationParams() {
// Pylance will ask us for per workspace configuration settings. We can send
// default workspace settings here.
Settings = GetSettings()
});
}

public Task OnServerInitializeFailedAsync(Exception e) {
Expand Down Expand Up @@ -329,9 +334,6 @@ await _rpc.NotifyWithParameterObjectAsync("workspace/didChangeWorkspaceFolders",
removed = removed
}
});

// If we send workspace folder updates, we have to resend document opens
// await SendDocumentOpensAsync();
}

public Task<object> InvokeTextDocumentCompletionAsync(LSP.CompletionParams request, CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -456,17 +458,6 @@ private void OnSettingsChanged(object sender, EventArgs e) {
}
}

private void OnDeferredSettingsChanged(object state) {
Debug.WriteLine("deferred Settings Changed");
InvokeDidChangeConfigurationAsync(new LSP.DidChangeConfigurationParams() {
// If we pass null settings and workspace.configuration is supported, Pylance will ask
// us for per workspace configuration settings. Otherwise we can send
// global settings here.
Settings = null
}).DoNotWait();

}

private void OnAnalysisComplete(object sender, EventArgs e) {
// Used by test code to know when it's okay to try and use intellisense
_readyTcs.TrySetResult(0);
Expand Down Expand Up @@ -558,6 +549,12 @@ private Tuple<StreamData, bool> OnSendToServer(StreamData data) {
capabilities["workspace"]["workspaceFolders"] = true;
capabilities["workspace"]["didChangeWatchedFiles"]["dynamicRegistration"] = true;
capabilities["workspace"]["configuration"] = true;

var folders = GetFolders();
Debug.Assert(folders.Any(), "no workspace or projects found");
messageParams["workspaceFolders"] = JToken.FromObject(folders.ToArray());
_sentInitialWorkspaceFolders = true;
_workspaceFoldersSupported = true;

// Root path and root URI should not be sent. They're deprecated and will
// just confuse pylance with respect to what is the root folder.
Expand Down Expand Up @@ -593,24 +590,35 @@ private Tuple<StreamData, bool> OnSendToServer(StreamData data) {
return Tuple.Create(data, true);
}

private async Task OnWorkspaceOpening(object sende, EventArgs e) {
private List<WorkspaceFolder> GetFolders() {
if (WorkspaceService.CurrentWorkspace != null) {
var folder = new WorkspaceFolder { uri = new System.Uri(WorkspaceService.CurrentWorkspace.Location), name = WorkspaceService.CurrentWorkspace.GetName() };
return [folder];
} else {
var folders = from n in this.ProjectContextProvider.ProjectNodes
select new WorkspaceFolder { uri = new System.Uri(n.BaseURI.Directory), name = n.Name };
return folders.ToList();
}
}

private async Task OnWorkspaceOpening(object sender, EventArgs e) {
if (_workspaceFoldersSupported && IsInitialized && !_sentInitialWorkspaceFolders && WorkspaceService.CurrentWorkspace != null) {
_sentInitialWorkspaceFolders = true;
// Send just this workspace folder. Assumption here is that the language client will be destroyed/recreated on
// each workspace open
var folder = new WorkspaceFolder { uri = new System.Uri(WorkspaceService.CurrentWorkspace.Location), name = WorkspaceService.CurrentWorkspace.GetName() };
this._workspaceFolders.Add(folder);
await InvokeDidChangeWorkspaceFoldersAsync(new WorkspaceFolder[] { folder }, new WorkspaceFolder[0]);
var folders = GetFolders();
this._workspaceFolders= folders.ToList();
await InvokeDidChangeWorkspaceFoldersAsync(folders.ToArray(), new WorkspaceFolder[0]);
}
}


// Note this is called for both openFolder and openProject modes
private void OnSolutionClosing() {
this._clientContexts.Clear();
if (_workspaceFoldersSupported && IsInitialized && _sentInitialWorkspaceFolders) {
JoinableTaskContext.Factory.RunAsync(async () => {
// If workspace folders are supported, then send our workspace folders
var folders = from n in this.ProjectContextProvider.ProjectNodes
select new WorkspaceFolder { uri = new System.Uri(n.BaseURI.Directory), name = n.Name };
var folders = GetFolders();
if (folders.Any()) {
await InvokeDidChangeWorkspaceFoldersAsync(new WorkspaceFolder[0], folders.ToArray());
}
Expand All @@ -627,9 +635,8 @@ private void OnSolutionOpened() {
_sentInitialWorkspaceFolders = true;
JoinableTaskContext.Factory.RunAsync(async () => {
// If workspace folders are supported, then send our workspace folders
var folders = from n in this.ProjectContextProvider.ProjectNodes
select new WorkspaceFolder { uri = new System.Uri(n.BaseURI.Directory), name = n.Name };
this._workspaceFolders = new List<WorkspaceFolder>(folders);
var folders = GetFolders();
this._workspaceFolders = folders.ToList();
if (folders.Any()) {
await InvokeDidChangeWorkspaceFoldersAsync(folders.ToArray(), new WorkspaceFolder[0]);
}
Expand Down

0 comments on commit 970eec2

Please sign in to comment.