Skip to content

Commit 4db3d1d

Browse files
CopilotJustinGrote
andauthored
Expose open workspace documents on PSEditor workspace API
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/76ae345c-b025-4fa0-8a0c-f6f8fa243d80 Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
1 parent 06342e3 commit 4db3d1d

4 files changed

Lines changed: 165 additions & 0 deletions

File tree

src/PowerShellEditorServices/Extensions/EditorWorkspace.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,35 @@
33

44
namespace Microsoft.PowerShell.EditorServices.Extensions
55
{
6+
/// <summary>
7+
/// A document currently open in the editor workspace.
8+
/// </summary>
9+
public sealed class EditorWorkspaceDocument
10+
{
11+
private readonly EditorWorkspace _workspace;
12+
13+
internal EditorWorkspaceDocument(EditorWorkspace workspace, string path)
14+
{
15+
_workspace = workspace;
16+
Path = path;
17+
}
18+
19+
/// <summary>
20+
/// Gets the path of the document.
21+
/// </summary>
22+
public string Path { get; }
23+
24+
/// <summary>
25+
/// Opens this document in the editor.
26+
/// </summary>
27+
public void Open() => _workspace.OpenFile(Path);
28+
29+
/// <summary>
30+
/// Saves this document in the editor.
31+
/// </summary>
32+
public void Save() => _workspace.SaveFile(Path);
33+
}
34+
635
/// <summary>
736
/// Provides a PowerShell-facing API which allows scripts to
837
/// interact with the editor's workspace.
@@ -28,6 +57,24 @@ public sealed class EditorWorkspace
2857
/// </summary>
2958
public string[] Paths => editorOperations.GetWorkspacePaths();
3059

60+
/// <summary>
61+
/// Get all currently open documents in the workspace.
62+
/// </summary>
63+
public EditorWorkspaceDocument[] Documents
64+
{
65+
get
66+
{
67+
string[] openDocumentPaths = editorOperations.GetWorkspaceOpenDocumentPaths();
68+
EditorWorkspaceDocument[] documents = new EditorWorkspaceDocument[openDocumentPaths.Length];
69+
for (int i = 0; i < openDocumentPaths.Length; i++)
70+
{
71+
documents[i] = new EditorWorkspaceDocument(this, openDocumentPaths[i]);
72+
}
73+
74+
return documents;
75+
}
76+
}
77+
3178
#endregion
3279

3380
#region Constructors

src/PowerShellEditorServices/Extensions/IEditorOperations.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ internal interface IEditorOperations
3232
/// <returns></returns>
3333
string[] GetWorkspacePaths();
3434

35+
/// <summary>
36+
/// Get all open document paths in the current workspace session.
37+
/// </summary>
38+
/// <returns>All currently open document paths.</returns>
39+
string[] GetWorkspaceOpenDocumentPaths();
40+
3541
/// <summary>
3642
/// Resolves the given file path relative to the current workspace path.
3743
/// </summary>

src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ public async Task SaveFileAsync(string currentPath, string newSavePath)
198198

199199
public string[] GetWorkspacePaths() => _workspaceService.WorkspacePaths.ToArray();
200200

201+
public string[] GetWorkspaceOpenDocumentPaths() => _workspaceService.GetOpenedFiles().Select(static scriptFile => scriptFile.FilePath).ToArray();
202+
201203
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => _workspaceService.GetRelativePath(scriptFile);
202204

203205
public async Task ShowInformationMessageAsync(string message)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Threading.Tasks;
7+
using Microsoft.PowerShell.EditorServices.Extensions;
8+
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
9+
using Xunit;
10+
11+
namespace PowerShellEditorServices.Test.Extensions
12+
{
13+
[Trait("Category", "Extensions")]
14+
public class EditorWorkspaceTests
15+
{
16+
[Fact]
17+
public void DocumentsReturnsOpenWorkspaceDocuments()
18+
{
19+
TestEditorOperations editorOperations = new()
20+
{
21+
OpenDocumentPaths = new[] { @"C:\test\one.ps1", @"C:\test\two.ps1" }
22+
};
23+
24+
EditorWorkspace workspace = new(editorOperations);
25+
26+
EditorWorkspaceDocument[] documents = workspace.Documents;
27+
28+
Assert.Collection(
29+
documents,
30+
document => Assert.Equal(@"C:\test\one.ps1", document.Path),
31+
document => Assert.Equal(@"C:\test\two.ps1", document.Path));
32+
}
33+
34+
[Fact]
35+
public void DocumentOpenAndSaveUseWorkspaceOperations()
36+
{
37+
const string filePath = @"C:\test\file.ps1";
38+
TestEditorOperations editorOperations = new()
39+
{
40+
OpenDocumentPaths = new[] { filePath }
41+
};
42+
43+
EditorWorkspace workspace = new(editorOperations);
44+
EditorWorkspaceDocument document = Assert.Single(workspace.Documents);
45+
46+
document.Open();
47+
document.Save();
48+
49+
Assert.Collection(
50+
editorOperations.Calls,
51+
call => Assert.Equal("OpenFile:" + filePath, call),
52+
call => Assert.Equal("SaveFile:" + filePath, call));
53+
}
54+
55+
private sealed class TestEditorOperations : IEditorOperations
56+
{
57+
public string[] OpenDocumentPaths { get; set; } = Array.Empty<string>();
58+
59+
public List<string> Calls { get; } = new();
60+
61+
public Task<EditorContext> GetEditorContextAsync() => Task.FromResult(default(EditorContext));
62+
63+
public string GetWorkspacePath() => @"C:\test";
64+
65+
public string[] GetWorkspacePaths() => new[] { @"C:\test" };
66+
67+
public string[] GetWorkspaceOpenDocumentPaths() => OpenDocumentPaths;
68+
69+
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => scriptFile.FilePath;
70+
71+
public Task NewFileAsync() => Task.CompletedTask;
72+
73+
public Task NewFileAsync(string content) => Task.CompletedTask;
74+
75+
public Task OpenFileAsync(string filePath)
76+
{
77+
Calls.Add("OpenFile:" + filePath);
78+
return Task.CompletedTask;
79+
}
80+
81+
public Task OpenFileAsync(string filePath, bool preview) => Task.CompletedTask;
82+
83+
public Task CloseFileAsync(string filePath) => Task.CompletedTask;
84+
85+
public Task SaveFileAsync(string filePath)
86+
{
87+
Calls.Add("SaveFile:" + filePath);
88+
return Task.CompletedTask;
89+
}
90+
91+
public Task SaveFileAsync(string oldFilePath, string newFilePath) => Task.CompletedTask;
92+
93+
public Task InsertTextAsync(string filePath, string insertText, BufferRange insertRange) => Task.CompletedTask;
94+
95+
public Task SetSelectionAsync(BufferRange selectionRange) => Task.CompletedTask;
96+
97+
public Task ShowInformationMessageAsync(string message) => Task.CompletedTask;
98+
99+
public Task ShowErrorMessageAsync(string message) => Task.CompletedTask;
100+
101+
public Task ShowWarningMessageAsync(string message) => Task.CompletedTask;
102+
103+
public Task SetStatusBarMessageAsync(string message, int? timeout) => Task.CompletedTask;
104+
105+
public void ClearTerminal()
106+
{
107+
}
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)