Add support for workspace/workspaceFolders request (#7990)

* Add support for workspace/workspaceFolders message. New requirement from pylance

* Wasn't handling the project add/remove scenario too
This commit is contained in:
Rich Chiodo 2024-08-29 17:16:39 -07:00 коммит произвёл GitHub
Родитель e19e852cac
Коммит 436d1dab4d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 54 добавлений и 3 удалений

Просмотреть файл

@ -325,6 +325,7 @@
<Compile Include="PythonTools\LanguageServerClient\WorkspaceFolderChanged\DidChangeWorkspaceFoldersParams.cs" />
<Compile Include="PythonTools\LanguageServerClient\WorkspaceFolderChanged\WorkspaceFolder.cs" />
<Compile Include="PythonTools\LanguageServerClient\WorkspaceFolderChanged\WorkspaceFoldersChangeEvent.cs" />
<Compile Include="PythonTools\LanguageServerClient\WorkspaceFolders\WorkspaceFoldersArgs.cs" />
<Compile Include="PythonTools\Logging\LogHubLogger.cs" />
<Compile Include="PythonTools\Navigation\Navigable\NavigableSymbol.cs" />
<Compile Include="PythonTools\Navigation\Navigable\NavigableSymbolSource.cs" />

Просмотреть файл

@ -97,6 +97,7 @@ namespace Microsoft.PythonTools.LanguageServerClient {
private bool _workspaceFoldersSupported = false;
private bool _isDebugging = LanguageServer.IsDebugging();
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 bool _loaded = false;
@ -200,6 +201,7 @@ namespace Microsoft.PythonTools.LanguageServerClient {
customTarget.WorkspaceFolderChangeRegistered += OnWorkspaceFolderWatched;
customTarget.AnalysisComplete += OnAnalysisComplete;
customTarget.WorkspaceConfiguration += OnWorkspaceConfiguration;
customTarget.WorkspaceFolders += OnWorkspaceFolders;
await StartAsync.InvokeAsync(this, EventArgs.Empty);
}
@ -232,6 +234,11 @@ namespace Microsoft.PythonTools.LanguageServerClient {
args.requestResult = result.ToArray();
}
private async Task OnWorkspaceFolders(object sender, WorkspaceFolders.WorkspaceFoldersArgs args) {
// Return our current list of workspace folders
args.requestResult = this._workspaceFolders;
}
public async Task OnServerInitializedAsync() {
IsInitialized = true;
// Set _workspaceFoldersSupported to true and send to either workspace open or solution open
@ -592,6 +599,7 @@ namespace Microsoft.PythonTools.LanguageServerClient {
// 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]);
}
}
@ -607,6 +615,7 @@ namespace Microsoft.PythonTools.LanguageServerClient {
await InvokeDidChangeWorkspaceFoldersAsync(new WorkspaceFolder[0], folders.ToArray());
}
});
this._workspaceFolders.Clear();
_workspaceFoldersSupported = false;
IsInitialized = false;
_sentInitialWorkspaceFolders = false;
@ -620,6 +629,7 @@ namespace Microsoft.PythonTools.LanguageServerClient {
// 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);
if (folders.Any()) {
await InvokeDidChangeWorkspaceFoldersAsync(folders.ToArray(), new WorkspaceFolder[0]);
}
@ -630,9 +640,10 @@ namespace Microsoft.PythonTools.LanguageServerClient {
private void OnProjectAdded(EnvDTE.Project project) {
if (_workspaceFoldersSupported) {
JoinableTaskContext.Factory.RunAsync(async () => {
var pythonProject = project as PythonProjectNode;
var pythonProject = project.GetPythonProject() as PythonProjectNode;
if (pythonProject != null) {
var folder = new WorkspaceFolder { uri = new System.Uri(pythonProject.BaseURI.Directory), name = project.Name };
this._workspaceFolders.Add(folder);
await InvokeDidChangeWorkspaceFoldersAsync(new WorkspaceFolder[] { folder }, new WorkspaceFolder[0]);
}
});
@ -642,9 +653,13 @@ namespace Microsoft.PythonTools.LanguageServerClient {
private void OnProjectRemoved(EnvDTE.Project project) {
if (_workspaceFoldersSupported) {
JoinableTaskContext.Factory.RunAsync(async () => {
var pythonProject = project as PythonProjectNode;
var pythonProject = project.GetPythonProject() as PythonProjectNode;
if (pythonProject != null) {
var folder = new WorkspaceFolder { uri = new System.Uri(pythonProject.BaseURI.Directory), name = project.Name };
var entry = this._workspaceFolders.Find((f) => f.uri.ToString() == folder.uri.ToString());
if (entry != null) {
this._workspaceFolders.Remove(entry);
}
await InvokeDidChangeWorkspaceFoldersAsync(new WorkspaceFolder[0], new WorkspaceFolder[] { folder });
}
});

Просмотреть файл

@ -29,6 +29,7 @@ using Task = System.Threading.Tasks.Task;
using Microsoft.PythonTools.LanguageServerClient.WorkspaceConfiguration;
using Microsoft.PythonTools.LanguageServerClient.FileWatcher;
using Microsoft.PythonTools.LanguageServerClient.WorkspaceFolders;
namespace Microsoft.PythonTools.LanguageServerClient {
internal class PythonLanguageClientCustomTarget {
@ -89,6 +90,11 @@ namespace Microsoft.PythonTools.LanguageServerClient {
/// </summary>
internal event AsyncEventHandler<ConfigurationArgs> WorkspaceConfiguration;
/// <summary>
/// Event fired when pylance sends a workspace/workspaceFolders request
/// </summary>
internal event AsyncEventHandler<WorkspaceFoldersArgs> WorkspaceFolders;
[JsonRpcMethod("telemetry/event")]
public void OnTelemetryEvent(JToken arg) {
if (!(arg is JObject telemetry)) {
@ -175,5 +181,23 @@ namespace Microsoft.PythonTools.LanguageServerClient {
return null;
}
}
[JsonRpcMethod("workspace/workspaceFolders")]
public async Task<object> OnWorkspaceFolders() {
try {
// Should be no arguments (see request here: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_workspaceFolders)
if (this.WorkspaceFolders != null) {
var eventArgs = new WorkspaceFoldersArgs { requestResult = null };
await this.WorkspaceFolders.InvokeAsync(this, eventArgs);
return eventArgs.requestResult;
}
return null;
} catch {
return null;
}
}
}
internal class EmptyEventArgs {
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PythonTools.LanguageServerClient.WorkspaceFolders {
internal class WorkspaceFoldersArgs {
public object requestResult;
}
}

Просмотреть файл

@ -2,6 +2,6 @@
"name": "ptvs",
"private": true,
"devDependencies": {
"@pylance/pylance": "2024.8.1"
"@pylance/pylance": "2024.8.2"
}
}