From 06342e3055aaec33f367f4f2c1fbc8be81fc06c8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 17:28:09 +0000
Subject: [PATCH 01/31] Initial plan
From 4db3d1dd074b24f6da2771746b8367d2276b6fd3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 17:32:44 +0000
Subject: [PATCH 02/31] 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>
---
.../Extensions/EditorWorkspace.cs | 47 ++++++++
.../Extensions/IEditorOperations.cs | 6 +
.../Extension/EditorOperationsService.cs | 2 +
.../Extensions/EditorWorkspaceTests.cs | 110 ++++++++++++++++++
4 files changed, 165 insertions(+)
create mode 100644 test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index e1e0824cb..47fcca378 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -3,6 +3,35 @@
namespace Microsoft.PowerShell.EditorServices.Extensions
{
+ ///
+ /// A document currently open in the editor workspace.
+ ///
+ public sealed class EditorWorkspaceDocument
+ {
+ private readonly EditorWorkspace _workspace;
+
+ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path)
+ {
+ _workspace = workspace;
+ Path = path;
+ }
+
+ ///
+ /// Gets the path of the document.
+ ///
+ public string Path { get; }
+
+ ///
+ /// Opens this document in the editor.
+ ///
+ public void Open() => _workspace.OpenFile(Path);
+
+ ///
+ /// Saves this document in the editor.
+ ///
+ public void Save() => _workspace.SaveFile(Path);
+ }
+
///
/// Provides a PowerShell-facing API which allows scripts to
/// interact with the editor's workspace.
@@ -28,6 +57,24 @@ public sealed class EditorWorkspace
///
public string[] Paths => editorOperations.GetWorkspacePaths();
+ ///
+ /// Get all currently open documents in the workspace.
+ ///
+ public EditorWorkspaceDocument[] Documents
+ {
+ get
+ {
+ string[] openDocumentPaths = editorOperations.GetWorkspaceOpenDocumentPaths();
+ EditorWorkspaceDocument[] documents = new EditorWorkspaceDocument[openDocumentPaths.Length];
+ for (int i = 0; i < openDocumentPaths.Length; i++)
+ {
+ documents[i] = new EditorWorkspaceDocument(this, openDocumentPaths[i]);
+ }
+
+ return documents;
+ }
+ }
+
#endregion
#region Constructors
diff --git a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
index 3ec33ebc6..909f11255 100644
--- a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
+++ b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
@@ -32,6 +32,12 @@ internal interface IEditorOperations
///
string[] GetWorkspacePaths();
+ ///
+ /// Get all open document paths in the current workspace session.
+ ///
+ /// All currently open document paths.
+ string[] GetWorkspaceOpenDocumentPaths();
+
///
/// Resolves the given file path relative to the current workspace path.
///
diff --git a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
index 607d38720..aef0ad033 100644
--- a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
+++ b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
@@ -198,6 +198,8 @@ public async Task SaveFileAsync(string currentPath, string newSavePath)
public string[] GetWorkspacePaths() => _workspaceService.WorkspacePaths.ToArray();
+ public string[] GetWorkspaceOpenDocumentPaths() => _workspaceService.GetOpenedFiles().Select(static scriptFile => scriptFile.FilePath).ToArray();
+
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => _workspaceService.GetRelativePath(scriptFile);
public async Task ShowInformationMessageAsync(string message)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
new file mode 100644
index 000000000..a499040f7
--- /dev/null
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -0,0 +1,110 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.PowerShell.EditorServices.Extensions;
+using Microsoft.PowerShell.EditorServices.Services.TextDocument;
+using Xunit;
+
+namespace PowerShellEditorServices.Test.Extensions
+{
+ [Trait("Category", "Extensions")]
+ public class EditorWorkspaceTests
+ {
+ [Fact]
+ public void DocumentsReturnsOpenWorkspaceDocuments()
+ {
+ TestEditorOperations editorOperations = new()
+ {
+ OpenDocumentPaths = new[] { @"C:\test\one.ps1", @"C:\test\two.ps1" }
+ };
+
+ EditorWorkspace workspace = new(editorOperations);
+
+ EditorWorkspaceDocument[] documents = workspace.Documents;
+
+ Assert.Collection(
+ documents,
+ document => Assert.Equal(@"C:\test\one.ps1", document.Path),
+ document => Assert.Equal(@"C:\test\two.ps1", document.Path));
+ }
+
+ [Fact]
+ public void DocumentOpenAndSaveUseWorkspaceOperations()
+ {
+ const string filePath = @"C:\test\file.ps1";
+ TestEditorOperations editorOperations = new()
+ {
+ OpenDocumentPaths = new[] { filePath }
+ };
+
+ EditorWorkspace workspace = new(editorOperations);
+ EditorWorkspaceDocument document = Assert.Single(workspace.Documents);
+
+ document.Open();
+ document.Save();
+
+ Assert.Collection(
+ editorOperations.Calls,
+ call => Assert.Equal("OpenFile:" + filePath, call),
+ call => Assert.Equal("SaveFile:" + filePath, call));
+ }
+
+ private sealed class TestEditorOperations : IEditorOperations
+ {
+ public string[] OpenDocumentPaths { get; set; } = Array.Empty();
+
+ public List Calls { get; } = new();
+
+ public Task GetEditorContextAsync() => Task.FromResult(default(EditorContext));
+
+ public string GetWorkspacePath() => @"C:\test";
+
+ public string[] GetWorkspacePaths() => new[] { @"C:\test" };
+
+ public string[] GetWorkspaceOpenDocumentPaths() => OpenDocumentPaths;
+
+ public string GetWorkspaceRelativePath(ScriptFile scriptFile) => scriptFile.FilePath;
+
+ public Task NewFileAsync() => Task.CompletedTask;
+
+ public Task NewFileAsync(string content) => Task.CompletedTask;
+
+ public Task OpenFileAsync(string filePath)
+ {
+ Calls.Add("OpenFile:" + filePath);
+ return Task.CompletedTask;
+ }
+
+ public Task OpenFileAsync(string filePath, bool preview) => Task.CompletedTask;
+
+ public Task CloseFileAsync(string filePath) => Task.CompletedTask;
+
+ public Task SaveFileAsync(string filePath)
+ {
+ Calls.Add("SaveFile:" + filePath);
+ return Task.CompletedTask;
+ }
+
+ public Task SaveFileAsync(string oldFilePath, string newFilePath) => Task.CompletedTask;
+
+ public Task InsertTextAsync(string filePath, string insertText, BufferRange insertRange) => Task.CompletedTask;
+
+ public Task SetSelectionAsync(BufferRange selectionRange) => Task.CompletedTask;
+
+ public Task ShowInformationMessageAsync(string message) => Task.CompletedTask;
+
+ public Task ShowErrorMessageAsync(string message) => Task.CompletedTask;
+
+ public Task ShowWarningMessageAsync(string message) => Task.CompletedTask;
+
+ public Task SetStatusBarMessageAsync(string message, int? timeout) => Task.CompletedTask;
+
+ public void ClearTerminal()
+ {
+ }
+ }
+ }
+}
From ac478395a8a148effc493f04d78f8ba495345ba1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 17:52:50 +0000
Subject: [PATCH 03/31] Add close operation to workspace documents API
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/6a4ffcb3-ffa5-431d-8a79-d5c87df48a9c
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorWorkspace.cs | 5 +++++
.../Extensions/EditorWorkspaceTests.cs | 12 +++++++++---
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 47fcca378..0a6e764fc 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -30,6 +30,11 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path)
/// Saves this document in the editor.
///
public void Save() => _workspace.SaveFile(Path);
+
+ ///
+ /// Closes this document in the editor.
+ ///
+ public void Close() => _workspace.CloseFile(Path);
}
///
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index a499040f7..c2a265347 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -32,7 +32,7 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
}
[Fact]
- public void DocumentOpenAndSaveUseWorkspaceOperations()
+ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
{
const string filePath = @"C:\test\file.ps1";
TestEditorOperations editorOperations = new()
@@ -45,11 +45,13 @@ public void DocumentOpenAndSaveUseWorkspaceOperations()
document.Open();
document.Save();
+ document.Close();
Assert.Collection(
editorOperations.Calls,
call => Assert.Equal("OpenFile:" + filePath, call),
- call => Assert.Equal("SaveFile:" + filePath, call));
+ call => Assert.Equal("SaveFile:" + filePath, call),
+ call => Assert.Equal("CloseFile:" + filePath, call));
}
private sealed class TestEditorOperations : IEditorOperations
@@ -80,7 +82,11 @@ public Task OpenFileAsync(string filePath)
public Task OpenFileAsync(string filePath, bool preview) => Task.CompletedTask;
- public Task CloseFileAsync(string filePath) => Task.CompletedTask;
+ public Task CloseFileAsync(string filePath)
+ {
+ Calls.Add("CloseFile:" + filePath);
+ return Task.CompletedTask;
+ }
public Task SaveFileAsync(string filePath)
{
From c8721bab527148f9301cd2b2e554de6ed3866db1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 18:14:07 +0000
Subject: [PATCH 04/31] Add ToString override for workspace documents
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/7e3e8a1d-f66b-4f87-8bde-eb0dd19f928c
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorWorkspace.cs | 6 ++++++
.../Extensions/EditorWorkspaceTests.cs | 15 +++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 0a6e764fc..b6b0abe0c 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -21,6 +21,12 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path)
///
public string Path { get; }
+ ///
+ /// Gets the full path of this document.
+ ///
+ /// The full document path.
+ public override string ToString() => Path;
+
///
/// Opens this document in the editor.
///
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index c2a265347..7414dce27 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -54,6 +54,21 @@ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
call => Assert.Equal("CloseFile:" + filePath, call));
}
+ [Fact]
+ public void DocumentToStringReturnsDocumentPath()
+ {
+ const string filePath = @"C:\test\file.ps1";
+ TestEditorOperations editorOperations = new()
+ {
+ OpenDocumentPaths = new[] { filePath }
+ };
+
+ EditorWorkspace workspace = new(editorOperations);
+ EditorWorkspaceDocument document = Assert.Single(workspace.Documents);
+
+ Assert.Equal(filePath, document.ToString());
+ }
+
private sealed class TestEditorOperations : IEditorOperations
{
public string[] OpenDocumentPaths { get; set; } = Array.Empty();
From 9b0f3728eb6986351634394d167a8a5b57f790ff Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 18:35:36 +0000
Subject: [PATCH 05/31] Add Saved status to workspace documents
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/3e87bc0c-ffcc-4ce4-9b08-22d248a3f5db
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorWorkspace.cs | 26 +++++---
.../Extensions/IEditorOperations.cs | 19 +++++-
.../Extension/EditorOperationsService.cs | 5 +-
.../Handlers/TextDocumentHandler.cs | 2 +
.../Services/TextDocument/ScriptFile.cs | 7 +++
.../Extensions/EditorWorkspaceTests.cs | 63 +++++++++++++++----
6 files changed, 99 insertions(+), 23 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index b6b0abe0c..19c5dac6a 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -10,10 +10,11 @@ public sealed class EditorWorkspaceDocument
{
private readonly EditorWorkspace _workspace;
- internal EditorWorkspaceDocument(EditorWorkspace workspace, string path)
+ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool saved)
{
_workspace = workspace;
Path = path;
+ Saved = saved;
}
///
@@ -22,10 +23,19 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path)
public string Path { get; }
///
- /// Gets the full path of this document.
+ /// Gets whether the document has unsaved changes.
///
- /// The full document path.
- public override string ToString() => Path;
+ public bool Saved { get; }
+
+ ///
+ /// Gets the display name of this document and unsaved status.
+ ///
+ /// The display name of this document.
+ public override string ToString()
+ {
+ string fileName = System.IO.Path.GetFileName(Path);
+ return Saved ? fileName : fileName + " [Unsaved]";
+ }
///
/// Opens this document in the editor.
@@ -75,11 +85,11 @@ public EditorWorkspaceDocument[] Documents
{
get
{
- string[] openDocumentPaths = editorOperations.GetWorkspaceOpenDocumentPaths();
- EditorWorkspaceDocument[] documents = new EditorWorkspaceDocument[openDocumentPaths.Length];
- for (int i = 0; i < openDocumentPaths.Length; i++)
+ WorkspaceOpenDocument[] openDocuments = editorOperations.GetWorkspaceOpenDocuments();
+ EditorWorkspaceDocument[] documents = new EditorWorkspaceDocument[openDocuments.Length];
+ for (int i = 0; i < openDocuments.Length; i++)
{
- documents[i] = new EditorWorkspaceDocument(this, openDocumentPaths[i]);
+ documents[i] = new EditorWorkspaceDocument(this, openDocuments[i].Path, openDocuments[i].Saved);
}
return documents;
diff --git a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
index 909f11255..b3e629a0c 100644
--- a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
+++ b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
@@ -6,6 +6,19 @@
namespace Microsoft.PowerShell.EditorServices.Extensions
{
+ internal readonly struct WorkspaceOpenDocument
+ {
+ internal WorkspaceOpenDocument(string path, bool saved)
+ {
+ Path = path;
+ Saved = saved;
+ }
+
+ public string Path { get; }
+
+ public bool Saved { get; }
+ }
+
///
/// Provides an interface that must be implemented by an editor
/// host to perform operations invoked by extensions written in
@@ -33,10 +46,10 @@ internal interface IEditorOperations
string[] GetWorkspacePaths();
///
- /// Get all open document paths in the current workspace session.
+ /// Get all open documents in the current workspace session.
///
- /// All currently open document paths.
- string[] GetWorkspaceOpenDocumentPaths();
+ /// All currently open documents.
+ WorkspaceOpenDocument[] GetWorkspaceOpenDocuments();
///
/// Resolves the given file path relative to the current workspace path.
diff --git a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
index aef0ad033..5260f3d39 100644
--- a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
+++ b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
@@ -198,7 +198,10 @@ public async Task SaveFileAsync(string currentPath, string newSavePath)
public string[] GetWorkspacePaths() => _workspaceService.WorkspacePaths.ToArray();
- public string[] GetWorkspaceOpenDocumentPaths() => _workspaceService.GetOpenedFiles().Select(static scriptFile => scriptFile.FilePath).ToArray();
+ public WorkspaceOpenDocument[] GetWorkspaceOpenDocuments()
+ => _workspaceService.GetOpenedFiles()
+ .Select(static scriptFile => new WorkspaceOpenDocument(scriptFile.FilePath, scriptFile.IsSaved))
+ .ToArray();
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => _workspaceService.GetRelativePath(scriptFile);
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
index a02e7b884..c48c73889 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
@@ -136,6 +136,8 @@ public override async Task Handle(DidSaveTextDocumentParams notification,
{
await _remoteFileManagerService.SaveRemoteFileAsync(savedFile.FilePath).ConfigureAwait(false);
}
+
+ savedFile.IsSaved = true;
}
return Unit.Value;
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
index fb6772d2b..f4986c1ed 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
@@ -55,6 +55,11 @@ internal sealed class ScriptFile
///
public bool IsInMemory { get; }
+ ///
+ /// Gets or sets whether this file has no unsaved changes.
+ ///
+ public bool IsSaved { get; internal set; }
+
///
/// Gets a string containing the full contents of the file.
///
@@ -137,6 +142,7 @@ internal ScriptFile(
// SetFileContents() calls ParseFileContents() which initializes the rest of the properties.
SetFileContents(textReader.ReadToEnd());
+ IsSaved = !IsInMemory;
References = new ReferenceTable(this);
}
@@ -364,6 +370,7 @@ public void ApplyChange(FileChange fileChange)
// Parse the script again to be up-to-date
ParseFileContents();
+ IsSaved = false;
References.TagAsChanged();
}
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index 7414dce27..1fec290f1 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -18,7 +18,11 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
{
TestEditorOperations editorOperations = new()
{
- OpenDocumentPaths = new[] { @"C:\test\one.ps1", @"C:\test\two.ps1" }
+ OpenDocuments = new[]
+ {
+ new WorkspaceOpenDocument(@"C:\test\one.ps1", saved: true),
+ new WorkspaceOpenDocument(@"C:\test\two.ps1", saved: true)
+ }
};
EditorWorkspace workspace = new(editorOperations);
@@ -27,8 +31,16 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
Assert.Collection(
documents,
- document => Assert.Equal(@"C:\test\one.ps1", document.Path),
- document => Assert.Equal(@"C:\test\two.ps1", document.Path));
+ document =>
+ {
+ Assert.Equal(@"C:\test\one.ps1", document.Path);
+ Assert.True(document.Saved);
+ },
+ document =>
+ {
+ Assert.Equal(@"C:\test\two.ps1", document.Path);
+ Assert.True(document.Saved);
+ });
}
[Fact]
@@ -37,7 +49,7 @@ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
const string filePath = @"C:\test\file.ps1";
TestEditorOperations editorOperations = new()
{
- OpenDocumentPaths = new[] { filePath }
+ OpenDocuments = new[] { new WorkspaceOpenDocument(filePath, saved: true) }
};
EditorWorkspace workspace = new(editorOperations);
@@ -55,23 +67,52 @@ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
}
[Fact]
- public void DocumentToStringReturnsDocumentPath()
+ public void DocumentToStringReturnsFileNameAndSavedStatus()
{
- const string filePath = @"C:\test\file.ps1";
+ const string savedFilePath = @"C:\test\file.ps1";
+ const string unsavedFilePath = @"C:\test\other.ps1";
TestEditorOperations editorOperations = new()
{
- OpenDocumentPaths = new[] { filePath }
+ OpenDocuments = new[]
+ {
+ new WorkspaceOpenDocument(savedFilePath, saved: true),
+ new WorkspaceOpenDocument(unsavedFilePath, saved: false)
+ }
};
EditorWorkspace workspace = new(editorOperations);
- EditorWorkspaceDocument document = Assert.Single(workspace.Documents);
+ EditorWorkspaceDocument[] documents = workspace.Documents;
+
+ Assert.Collection(
+ documents,
+ document => Assert.Equal("file.ps1", document.ToString()),
+ document => Assert.Equal("other.ps1 [Unsaved]", document.ToString()));
+ }
+
+ [Fact]
+ public void DocumentSavedReturnsWorkspaceSavedState()
+ {
+ TestEditorOperations editorOperations = new()
+ {
+ OpenDocuments = new[]
+ {
+ new WorkspaceOpenDocument(@"C:\test\saved.ps1", saved: true),
+ new WorkspaceOpenDocument(@"C:\test\unsaved.ps1", saved: false)
+ }
+ };
- Assert.Equal(filePath, document.ToString());
+ EditorWorkspace workspace = new(editorOperations);
+ EditorWorkspaceDocument[] documents = workspace.Documents;
+
+ Assert.Collection(
+ documents,
+ document => Assert.True(document.Saved),
+ document => Assert.False(document.Saved));
}
private sealed class TestEditorOperations : IEditorOperations
{
- public string[] OpenDocumentPaths { get; set; } = Array.Empty();
+ public WorkspaceOpenDocument[] OpenDocuments { get; set; } = Array.Empty();
public List Calls { get; } = new();
@@ -81,7 +122,7 @@ private sealed class TestEditorOperations : IEditorOperations
public string[] GetWorkspacePaths() => new[] { @"C:\test" };
- public string[] GetWorkspaceOpenDocumentPaths() => OpenDocumentPaths;
+ public WorkspaceOpenDocument[] GetWorkspaceOpenDocuments() => OpenDocuments;
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => scriptFile.FilePath;
From 9cbd9e631af6e416f5fcfa0ec5973c5bf1bbc313 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 18:38:52 +0000
Subject: [PATCH 06/31] Fix Saved property XML docs wording
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/3e87bc0c-ffcc-4ce4-9b08-22d248a3f5db
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
src/PowerShellEditorServices/Extensions/EditorWorkspace.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 19c5dac6a..2380019d6 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -23,7 +23,7 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool sa
public string Path { get; }
///
- /// Gets whether the document has unsaved changes.
+ /// Gets whether the document is saved (has no unsaved changes).
///
public bool Saved { get; }
From 8afd2a56c32d9f228090c0187e8d7b6f2e13b64b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 18:55:28 +0000
Subject: [PATCH 07/31] Fix ToString filename extraction for Windows paths
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/6285ab7f-3d36-4174-84cd-57dcebf32386
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
src/PowerShellEditorServices/Extensions/EditorWorkspace.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 2380019d6..7b5d75b3f 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -33,7 +33,8 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool sa
/// The display name of this document.
public override string ToString()
{
- string fileName = System.IO.Path.GetFileName(Path);
+ int fileNameStartIndex = System.Math.Max(Path.LastIndexOf('\\'), Path.LastIndexOf('/')) + 1;
+ string fileName = Path.Substring(fileNameStartIndex);
return Saved ? fileName : fileName + " [Unsaved]";
}
From 866c2aafc9500525b09a2247f0c1b368eeac4e3b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 18:58:51 +0000
Subject: [PATCH 08/31] Harden ToString path handling for null and separators
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/6285ab7f-3d36-4174-84cd-57dcebf32386
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
src/PowerShellEditorServices/Extensions/EditorWorkspace.cs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 7b5d75b3f..3f8b3639f 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -33,8 +33,10 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool sa
/// The display name of this document.
public override string ToString()
{
- int fileNameStartIndex = System.Math.Max(Path.LastIndexOf('\\'), Path.LastIndexOf('/')) + 1;
- string fileName = Path.Substring(fileNameStartIndex);
+ string documentPath = Path ?? string.Empty;
+ // Handle Windows and POSIX separators consistently across platforms.
+ int fileNameStartIndex = System.Math.Max(documentPath.LastIndexOf('\\'), documentPath.LastIndexOf('/')) + 1;
+ string fileName = documentPath.Substring(fileNameStartIndex);
return Saved ? fileName : fileName + " [Unsaved]";
}
From b781fd1420c37ebadaae7c3e62c71850ab55a706 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 12:53:15 -0700
Subject: [PATCH 09/31] Simplify methods
---
.../Extensions/EditorWorkspace.cs | 44 +++++++------------
1 file changed, 17 insertions(+), 27 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 3f8b3639f..54467594e 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -1,6 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Generic;
+using System.Linq;
+
namespace Microsoft.PowerShell.EditorServices.Extensions
{
///
@@ -27,19 +30,6 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool sa
///
public bool Saved { get; }
- ///
- /// Gets the display name of this document and unsaved status.
- ///
- /// The display name of this document.
- public override string ToString()
- {
- string documentPath = Path ?? string.Empty;
- // Handle Windows and POSIX separators consistently across platforms.
- int fileNameStartIndex = System.Math.Max(documentPath.LastIndexOf('\\'), documentPath.LastIndexOf('/')) + 1;
- string fileName = documentPath.Substring(fileNameStartIndex);
- return Saved ? fileName : fileName + " [Unsaved]";
- }
-
///
/// Opens this document in the editor.
///
@@ -54,6 +44,17 @@ public override string ToString()
/// Closes this document in the editor.
///
public void Close() => _workspace.CloseFile(Path);
+
+ ///
+ /// Gets the display name of this document and unsaved status.
+ ///
+ /// The display name of this document.
+ public override string ToString()
+ {
+ string documentPath = Path ?? string.Empty;
+ string fileName = System.IO.Path.GetFileName(documentPath);
+ return Saved ? fileName : fileName + " [Unsaved]";
+ }
}
///
@@ -84,20 +85,9 @@ public sealed class EditorWorkspace
///
/// Get all currently open documents in the workspace.
///
- public EditorWorkspaceDocument[] Documents
- {
- get
- {
- WorkspaceOpenDocument[] openDocuments = editorOperations.GetWorkspaceOpenDocuments();
- EditorWorkspaceDocument[] documents = new EditorWorkspaceDocument[openDocuments.Length];
- for (int i = 0; i < openDocuments.Length; i++)
- {
- documents[i] = new EditorWorkspaceDocument(this, openDocuments[i].Path, openDocuments[i].Saved);
- }
-
- return documents;
- }
- }
+ public IEnumerable Documents => editorOperations
+ .GetWorkspaceOpenDocuments()
+ .Select(doc => new EditorWorkspaceDocument(this, doc.Path, doc.Saved));
#endregion
From 29ae10f420df93f51591e56f9fac8b94a53f12bf Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 19:56:08 +0000
Subject: [PATCH 10/31] Use IsInMemory for workspace document saved state
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/b2f2d9b7-95c7-413b-8a23-7845a964c98a
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Services/Extension/EditorOperationsService.cs | 2 +-
.../Services/TextDocument/Handlers/TextDocumentHandler.cs | 1 -
.../Services/TextDocument/ScriptFile.cs | 7 -------
3 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
index 5260f3d39..ad812d07d 100644
--- a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
+++ b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
@@ -200,7 +200,7 @@ public async Task SaveFileAsync(string currentPath, string newSavePath)
public WorkspaceOpenDocument[] GetWorkspaceOpenDocuments()
=> _workspaceService.GetOpenedFiles()
- .Select(static scriptFile => new WorkspaceOpenDocument(scriptFile.FilePath, scriptFile.IsSaved))
+ .Select(static scriptFile => new WorkspaceOpenDocument(scriptFile.FilePath, !scriptFile.IsInMemory))
.ToArray();
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => _workspaceService.GetRelativePath(scriptFile);
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
index c48c73889..7f982df3f 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
@@ -137,7 +137,6 @@ public override async Task Handle(DidSaveTextDocumentParams notification,
await _remoteFileManagerService.SaveRemoteFileAsync(savedFile.FilePath).ConfigureAwait(false);
}
- savedFile.IsSaved = true;
}
return Unit.Value;
}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
index f4986c1ed..fb6772d2b 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
@@ -55,11 +55,6 @@ internal sealed class ScriptFile
///
public bool IsInMemory { get; }
- ///
- /// Gets or sets whether this file has no unsaved changes.
- ///
- public bool IsSaved { get; internal set; }
-
///
/// Gets a string containing the full contents of the file.
///
@@ -142,7 +137,6 @@ internal ScriptFile(
// SetFileContents() calls ParseFileContents() which initializes the rest of the properties.
SetFileContents(textReader.ReadToEnd());
- IsSaved = !IsInMemory;
References = new ReferenceTable(this);
}
@@ -370,7 +364,6 @@ public void ApplyChange(FileChange fileChange)
// Parse the script again to be up-to-date
ParseFileContents();
- IsSaved = false;
References.TagAsChanged();
}
From a568cf4e864f20e071efc3398002fd001c686199 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 20:00:00 +0000
Subject: [PATCH 11/31] Clarify Saved semantics as file-backed state
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/b2f2d9b7-95c7-413b-8a23-7845a964c98a
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
src/PowerShellEditorServices/Extensions/EditorWorkspace.cs | 2 +-
.../Extensions/IEditorOperations.cs | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 54467594e..bdd8d1db2 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -26,7 +26,7 @@ internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool sa
public string Path { get; }
///
- /// Gets whether the document is saved (has no unsaved changes).
+ /// Gets whether the document is backed by a saved file path (not in-memory).
///
public bool Saved { get; }
diff --git a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
index b3e629a0c..286478a55 100644
--- a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
+++ b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
@@ -14,8 +14,14 @@ internal WorkspaceOpenDocument(string path, bool saved)
Saved = saved;
}
+ ///
+ /// Gets the path or URI of the open document.
+ ///
public string Path { get; }
+ ///
+ /// Gets whether the document is backed by a saved file path (not in-memory).
+ ///
public bool Saved { get; }
}
From 945736e7bf617fcefac5954d1ddefc76c130aeeb Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 13:04:40 -0700
Subject: [PATCH 12/31] Remove unnecessary newline
---
.../Services/TextDocument/Handlers/TextDocumentHandler.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
index 7f982df3f..a02e7b884 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
@@ -136,7 +136,6 @@ public override async Task Handle(DidSaveTextDocumentParams notification,
{
await _remoteFileManagerService.SaveRemoteFileAsync(savedFile.FilePath).ConfigureAwait(false);
}
-
}
return Unit.Value;
}
From 9b19bc2aa52e5852848446f83b2afbeb457d95bd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 12 May 2026 20:10:14 +0000
Subject: [PATCH 13/31] Fix EditorWorkspaceTests for IEnumerable Documents
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/2e354cc4-b0b9-4177-8ac1-8826e0921553
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorWorkspaceTests.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index 1fec290f1..3c882d5bc 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -27,7 +27,7 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
EditorWorkspace workspace = new(editorOperations);
- EditorWorkspaceDocument[] documents = workspace.Documents;
+ IEnumerable documents = workspace.Documents;
Assert.Collection(
documents,
@@ -81,7 +81,7 @@ public void DocumentToStringReturnsFileNameAndSavedStatus()
};
EditorWorkspace workspace = new(editorOperations);
- EditorWorkspaceDocument[] documents = workspace.Documents;
+ IEnumerable documents = workspace.Documents;
Assert.Collection(
documents,
@@ -102,7 +102,7 @@ public void DocumentSavedReturnsWorkspaceSavedState()
};
EditorWorkspace workspace = new(editorOperations);
- EditorWorkspaceDocument[] documents = workspace.Documents;
+ IEnumerable documents = workspace.Documents;
Assert.Collection(
documents,
From b82b81ecacbdeef6f080934f1fa9f2b9d0f406e4 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 13:14:49 -0700
Subject: [PATCH 14/31] Switch to array and collection expressions
---
.../Extensions/EditorWorkspace.cs | 7 ++++---
.../Extensions/EditorWorkspaceTests.cs | 10 +++++-----
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index bdd8d1db2..d1790ae90 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System.Collections.Generic;
using System.Linq;
namespace Microsoft.PowerShell.EditorServices.Extensions
@@ -85,9 +84,11 @@ public sealed class EditorWorkspace
///
/// Get all currently open documents in the workspace.
///
- public IEnumerable Documents => editorOperations
+ public EditorWorkspaceDocument[] Documents => [..
+ editorOperations
.GetWorkspaceOpenDocuments()
- .Select(doc => new EditorWorkspaceDocument(this, doc.Path, doc.Saved));
+ .Select(doc => new EditorWorkspaceDocument(this, doc.Path, doc.Saved))
+ ];
#endregion
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index 3c882d5bc..20e811e95 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -18,16 +18,16 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
{
TestEditorOperations editorOperations = new()
{
- OpenDocuments = new[]
- {
+ OpenDocuments =
+ [
new WorkspaceOpenDocument(@"C:\test\one.ps1", saved: true),
new WorkspaceOpenDocument(@"C:\test\two.ps1", saved: true)
- }
+ ]
};
EditorWorkspace workspace = new(editorOperations);
- IEnumerable documents = workspace.Documents;
+ EditorWorkspaceDocument[] documents = workspace.Documents;
Assert.Collection(
documents,
@@ -49,7 +49,7 @@ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
const string filePath = @"C:\test\file.ps1";
TestEditorOperations editorOperations = new()
{
- OpenDocuments = new[] { new WorkspaceOpenDocument(filePath, saved: true) }
+ OpenDocuments = [new WorkspaceOpenDocument(filePath, saved: true)]
};
EditorWorkspace workspace = new(editorOperations);
From dd0f79fd3ba0d486848dccc18f07ca9dffb6c3f5 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 13:43:36 -0700
Subject: [PATCH 15/31] Make EditorWorkspaceTests OS Independent
---
.../Extensions/EditorWorkspaceTests.cs | 38 ++++++++++---------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index 20e811e95..fb721fb51 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Extensions;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
@@ -13,15 +14,20 @@ namespace PowerShellEditorServices.Test.Extensions
[Trait("Category", "Extensions")]
public class EditorWorkspaceTests
{
+ private static readonly string WorkspacePath = Path.Combine("test");
+
[Fact]
public void DocumentsReturnsOpenWorkspaceDocuments()
{
+ string firstPath = Path.Combine(WorkspacePath, "one.ps1");
+ string secondPath = Path.Combine(WorkspacePath, "two.ps1");
+
TestEditorOperations editorOperations = new()
{
OpenDocuments =
[
- new WorkspaceOpenDocument(@"C:\test\one.ps1", saved: true),
- new WorkspaceOpenDocument(@"C:\test\two.ps1", saved: true)
+ new WorkspaceOpenDocument(firstPath, saved: true),
+ new WorkspaceOpenDocument(secondPath, saved: true)
]
};
@@ -33,12 +39,12 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
documents,
document =>
{
- Assert.Equal(@"C:\test\one.ps1", document.Path);
+ Assert.Equal(firstPath, document.Path);
Assert.True(document.Saved);
},
document =>
{
- Assert.Equal(@"C:\test\two.ps1", document.Path);
+ Assert.Equal(secondPath, document.Path);
Assert.True(document.Saved);
});
}
@@ -46,7 +52,7 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
[Fact]
public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
{
- const string filePath = @"C:\test\file.ps1";
+ string filePath = Path.Combine(WorkspacePath, "file.ps1");
TestEditorOperations editorOperations = new()
{
OpenDocuments = [new WorkspaceOpenDocument(filePath, saved: true)]
@@ -69,15 +75,14 @@ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
[Fact]
public void DocumentToStringReturnsFileNameAndSavedStatus()
{
- const string savedFilePath = @"C:\test\file.ps1";
- const string unsavedFilePath = @"C:\test\other.ps1";
+ string savedFilePath = Path.Combine(WorkspacePath, "file.ps1");
+ string unsavedFilePath = Path.Combine(WorkspacePath, "other.ps1");
TestEditorOperations editorOperations = new()
{
- OpenDocuments = new[]
- {
+ OpenDocuments = [
new WorkspaceOpenDocument(savedFilePath, saved: true),
new WorkspaceOpenDocument(unsavedFilePath, saved: false)
- }
+ ]
};
EditorWorkspace workspace = new(editorOperations);
@@ -94,11 +99,10 @@ public void DocumentSavedReturnsWorkspaceSavedState()
{
TestEditorOperations editorOperations = new()
{
- OpenDocuments = new[]
- {
- new WorkspaceOpenDocument(@"C:\test\saved.ps1", saved: true),
- new WorkspaceOpenDocument(@"C:\test\unsaved.ps1", saved: false)
- }
+ OpenDocuments = [
+ new WorkspaceOpenDocument(Path.Combine(WorkspacePath, "saved.ps1"), saved: true),
+ new WorkspaceOpenDocument(Path.Combine(WorkspacePath, "unsaved.ps1"), saved: false)
+ ]
};
EditorWorkspace workspace = new(editorOperations);
@@ -118,9 +122,9 @@ private sealed class TestEditorOperations : IEditorOperations
public Task GetEditorContextAsync() => Task.FromResult(default(EditorContext));
- public string GetWorkspacePath() => @"C:\test";
+ public string GetWorkspacePath() => WorkspacePath;
- public string[] GetWorkspacePaths() => new[] { @"C:\test" };
+ public string[] GetWorkspacePaths() => [WorkspacePath];
public WorkspaceOpenDocument[] GetWorkspaceOpenDocuments() => OpenDocuments;
From 38dd80121d2f3187654e4e4ce176beafefa7ce99 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 15:41:59 -0700
Subject: [PATCH 16/31] Fixup Open/Unsaved file identification
---
.../Extension/EditorOperationsService.cs | 9 ++-
.../Handlers/TextDocumentHandler.cs | 8 ++-
.../Services/TextDocument/ScriptFile.cs | 20 +++++--
.../EditorOperationsServiceTests.cs | 55 +++++++++++++++++++
4 files changed, 83 insertions(+), 9 deletions(-)
create mode 100644 test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
diff --git a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
index ad812d07d..9c3e0c4ff 100644
--- a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
+++ b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
@@ -199,9 +199,12 @@ public async Task SaveFileAsync(string currentPath, string newSavePath)
public string[] GetWorkspacePaths() => _workspaceService.WorkspacePaths.ToArray();
public WorkspaceOpenDocument[] GetWorkspaceOpenDocuments()
- => _workspaceService.GetOpenedFiles()
- .Select(static scriptFile => new WorkspaceOpenDocument(scriptFile.FilePath, !scriptFile.IsInMemory))
- .ToArray();
+ => [..
+ _workspaceService
+ .GetOpenedFiles()
+ .Where(static scriptFile => scriptFile.IsOpen)
+ .Select(static scriptFile => new WorkspaceOpenDocument(scriptFile.FilePath, !scriptFile.IsInMemory))
+ ];
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => _workspaceService.GetRelativePath(scriptFile);
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
index a02e7b884..5ad70905c 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
@@ -111,10 +111,11 @@ public override Task Handle(DidCloseTextDocumentParams notification, Cance
{
fileToClose.IsOpen = false;
- // If the file watcher is supported, only close in-memory files when this
+ // If the file watcher is supported, only close non-file-backed documents when this
// notification is triggered. This lets us keep workspace files open so we can scan
// for references. When a file is deleted, the file watcher will close the file.
- if (!_isFileWatcherSupported || fileToClose.IsInMemory)
+ bool isBackedByFile = notification.TextDocument.Uri.ToUri().IsFile;
+ if (!_isFileWatcherSupported || !isBackedByFile)
{
_workspaceService.CloseFile(fileToClose);
}
@@ -132,6 +133,9 @@ public override async Task Handle(DidSaveTextDocumentParams notification,
if (savedFile != null)
{
+ // On a save, untitled files will remain in memory, so this won't change for those
+ savedFile.IsInMemory = savedFile.IsUntitled;
+
if (_remoteFileManagerService.IsUnderRemoteTempPath(savedFile.FilePath))
{
await _remoteFileManagerService.SaveRemoteFileAsync(savedFile.FilePath).ConfigureAwait(false);
diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
index fb6772d2b..96912d751 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
@@ -51,9 +51,14 @@ internal sealed class ScriptFile
///
/// Gets a boolean that determines whether this file is
- /// in-memory or not (either unsaved or non-file content).
+ /// in-memory or not (either unsaved or non-file content) aka "dirty"
///
- public bool IsInMemory { get; }
+ public bool IsInMemory { get; internal set; }
+
+ ///
+ /// Getter that returns if the document is not backed by a saved file path (not in-memory).
+ ///
+ public bool IsUntitled => !DocumentUri?.ToUri().IsFile ?? false;
///
/// Gets a string containing the full contents of the file.
@@ -127,11 +132,15 @@ internal ScriptFile(
// so that other operations know it's untitled/in-memory
// and don't think that it's a relative path
// on the file system.
- IsInMemory = !docUri.ToUri().IsFile;
+ DocumentUri = docUri;
+
+ // Initial state of document. Untitled files are in memory by definition, otherwise files start non-dirty on a filesystem
+ IsInMemory = IsUntitled;
+
FilePath = IsInMemory
? docUri.ToString()
: docUri.GetFileSystemPath();
- DocumentUri = docUri;
+
IsAnalysisEnabled = true;
this.powerShellVersion = powerShellVersion;
@@ -365,6 +374,9 @@ public void ApplyChange(FileChange fileChange)
// Parse the script again to be up-to-date
ParseFileContents();
References.TagAsChanged();
+
+ // Flag the script as modified
+ IsInMemory = true;
}
///
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
new file mode 100644
index 000000000..e679bdeb1
--- /dev/null
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.IO;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.PowerShell.EditorServices.Extensions;
+using Microsoft.PowerShell.EditorServices.Services;
+using Microsoft.PowerShell.EditorServices.Services.Extension;
+using Microsoft.PowerShell.EditorServices.Services.TextDocument;
+using OmniSharp.Extensions.LanguageServer.Protocol;
+using Xunit;
+
+namespace PowerShellEditorServices.Test.Extensions
+{
+ [Trait("Category", "Extensions")]
+ public class EditorOperationsServiceTests
+ {
+ [Fact]
+ public void GetWorkspaceOpenDocumentsReturnsOnlyOpenDocumentsAndCurrentInMemoryState()
+ {
+ WorkspaceService workspaceService = new(NullLoggerFactory.Instance);
+
+ ScriptFile openSaved = CreateFileBuffer(workspaceService, "open-saved.ps1");
+ openSaved.IsOpen = true;
+ openSaved.IsInMemory = false;
+
+ ScriptFile openUnsaved = CreateFileBuffer(workspaceService, "open-unsaved.ps1");
+ openUnsaved.IsOpen = true;
+ openUnsaved.IsInMemory = true;
+
+ ScriptFile closed = CreateFileBuffer(workspaceService, "closed.ps1");
+ closed.IsOpen = false;
+ closed.IsInMemory = false;
+
+ EditorOperationsService editorOperationsService = new(
+ psesHost: null,
+ workspaceService,
+ languageServer: null);
+
+ WorkspaceOpenDocument[] documents = editorOperationsService.GetWorkspaceOpenDocuments();
+
+ Assert.Equal(2, documents.Length);
+ Assert.Contains(documents, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
+ Assert.Contains(documents, static document => document.Path.EndsWith("open-unsaved.ps1") && !document.Saved);
+ Assert.DoesNotContain(documents, static document => document.Path.EndsWith("closed.ps1"));
+ }
+
+ private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, string fileName)
+ {
+ string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), fileName);
+ return workspaceService.GetFileBuffer(DocumentUri.FromFileSystemPath(filePath), initialBuffer: string.Empty);
+ }
+ }
+}
From 8220f533a366db467d44e65e470059d09f352b85 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 16:04:34 -0700
Subject: [PATCH 17/31] Try to fix flaky vim test
---
test/vim-simple-test.vim | 14 +++++++++++++-
test/vim-test.vim | 14 +++++++++++++-
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/test/vim-simple-test.vim b/test/vim-simple-test.vim
index fe0adda74..4a670b8db 100644
--- a/test/vim-simple-test.vim
+++ b/test/vim-simple-test.vim
@@ -1,6 +1,18 @@
let s:suite = themis#suite('pses')
let s:assert = themis#helper('assert')
+function s:wait_for_diagnostics(bufname, expected)
+ let l:attempts = 20
+ while l:attempts > 0
+ if getbufvar(a:bufname, 'LanguageClient_statusLineDiagnosticsCounts') == a:expected
+ return
+ endif
+
+ execute 'sleep 500m'
+ let l:attempts -= 1
+ endwhile
+endfunction
+
function s:suite.before()
let l:pses_path = g:repo_root . '/module'
let g:LanguageClient_serverCommands = {
@@ -33,7 +45,7 @@ function s:suite.analyzes_powershell_file()
call s:assert.equal(getbufvar(l:bufinfo.bufnr, '&filetype'), 'ps1')
execute 'LanguageClientStart'
- execute 'sleep' 5
+ call s:wait_for_diagnostics(l:bufinfo.name, {'E': 0, 'W': 1, 'H': 0, 'I': 0})
call s:assert.equal(getbufvar(l:bufinfo.name, 'LanguageClient_isServerRunning'), 1)
call s:assert.equal(getbufvar(l:bufinfo.name, 'LanguageClient_projectRoot'), g:repo_root)
call s:assert.equal(getbufvar(l:bufinfo.name, 'LanguageClient_statusLineDiagnosticsCounts'), {'E': 0, 'W': 1, 'H': 0, 'I': 0})
diff --git a/test/vim-test.vim b/test/vim-test.vim
index 3d94d174c..4fc5cfcd5 100644
--- a/test/vim-test.vim
+++ b/test/vim-test.vim
@@ -1,6 +1,18 @@
let s:suite = themis#suite('pses')
let s:assert = themis#helper('assert')
+function s:wait_for_diagnostics(bufname, expected)
+ let l:attempts = 20
+ while l:attempts > 0
+ if getbufvar(a:bufname, 'LanguageClient_statusLineDiagnosticsCounts') == a:expected
+ return
+ endif
+
+ execute 'sleep 500m'
+ let l:attempts -= 1
+ endwhile
+endfunction
+
function s:suite.before()
let l:pses_path = g:repo_root . '/module'
let g:LanguageClient_serverCommands = {
@@ -37,7 +49,7 @@ function s:suite.analyzes_powershell_file()
call s:assert.equal(getbufvar(l:bufinfo.bufnr, '&filetype'), 'ps1')
execute 'LanguageClientStart'
- execute 'sleep' 5
+ call s:wait_for_diagnostics(l:bufinfo.name, {'E': 0, 'W': 1, 'H': 0, 'I': 0})
call s:assert.equal(getbufvar(l:bufinfo.name, 'LanguageClient_isServerRunning'), 1)
call s:assert.equal(getbufvar(l:bufinfo.name, 'LanguageClient_projectRoot'), g:repo_root)
call s:assert.equal(getbufvar(l:bufinfo.name, 'LanguageClient_statusLineDiagnosticsCounts'), {'E': 0, 'W': 1, 'H': 0, 'I': 0})
From 2a0df442dc302b6689a254fb7bbdf9124bc40278 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 17:07:14 -0700
Subject: [PATCH 18/31] Simplify API abstraction to just the existing
WorkspaceOpenDocument
---
.../Extensions/EditorWorkspace.cs | 59 +------------------
.../Extensions/IEditorOperations.cs | 24 +++++---
.../Extensions/EditorWorkspaceTests.cs | 12 ++--
3 files changed, 23 insertions(+), 72 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index d1790ae90..a19c3d538 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -5,57 +5,6 @@
namespace Microsoft.PowerShell.EditorServices.Extensions
{
- ///
- /// A document currently open in the editor workspace.
- ///
- public sealed class EditorWorkspaceDocument
- {
- private readonly EditorWorkspace _workspace;
-
- internal EditorWorkspaceDocument(EditorWorkspace workspace, string path, bool saved)
- {
- _workspace = workspace;
- Path = path;
- Saved = saved;
- }
-
- ///
- /// Gets the path of the document.
- ///
- public string Path { get; }
-
- ///
- /// Gets whether the document is backed by a saved file path (not in-memory).
- ///
- public bool Saved { get; }
-
- ///
- /// Opens this document in the editor.
- ///
- public void Open() => _workspace.OpenFile(Path);
-
- ///
- /// Saves this document in the editor.
- ///
- public void Save() => _workspace.SaveFile(Path);
-
- ///
- /// Closes this document in the editor.
- ///
- public void Close() => _workspace.CloseFile(Path);
-
- ///
- /// Gets the display name of this document and unsaved status.
- ///
- /// The display name of this document.
- public override string ToString()
- {
- string documentPath = Path ?? string.Empty;
- string fileName = System.IO.Path.GetFileName(documentPath);
- return Saved ? fileName : fileName + " [Unsaved]";
- }
- }
-
///
/// Provides a PowerShell-facing API which allows scripts to
/// interact with the editor's workspace.
@@ -84,11 +33,7 @@ public sealed class EditorWorkspace
///
/// Get all currently open documents in the workspace.
///
- public EditorWorkspaceDocument[] Documents => [..
- editorOperations
- .GetWorkspaceOpenDocuments()
- .Select(doc => new EditorWorkspaceDocument(this, doc.Path, doc.Saved))
- ];
+ public WorkspaceOpenDocument[] Documents => [.. editorOperations.GetWorkspaceOpenDocuments()];
#endregion
@@ -138,6 +83,7 @@ public sealed class EditorWorkspace
/// The path to the file to be closed.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void CloseFile(string filePath) => editorOperations.CloseFileAsync(filePath).Wait();
+ public void CloseFile(WorkspaceOpenDocument document) => CloseFile(document.Path);
///
/// Saves an open file in the workspace.
@@ -145,6 +91,7 @@ public sealed class EditorWorkspace
/// The path to the file to be saved.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SaveFile(string filePath) => editorOperations.SaveFileAsync(filePath).Wait();
+ public void SaveFile(WorkspaceOpenDocument document) => SaveFile(document.Path);
///
/// Saves a file with a new name AKA a copy.
diff --git a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
index 286478a55..7fb39b22c 100644
--- a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
+++ b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
@@ -3,26 +3,32 @@
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
+#nullable enable
namespace Microsoft.PowerShell.EditorServices.Extensions
{
- internal readonly struct WorkspaceOpenDocument
+ public readonly struct WorkspaceOpenDocument(string path, bool saved)
{
- internal WorkspaceOpenDocument(string path, bool saved)
- {
- Path = path;
- Saved = saved;
- }
-
///
/// Gets the path or URI of the open document.
///
- public string Path { get; }
+ public string Path { get; } = path;
///
/// Gets whether the document is backed by a saved file path (not in-memory).
///
- public bool Saved { get; }
+ public bool Saved { get; } = saved;
+
+ ///
+ /// Gets the display name of this document and unsaved status.
+ ///
+ /// The display name of this document.
+ public override string ToString()
+ {
+ string documentPath = Path ?? string.Empty;
+ string fileName = System.IO.Path.GetFileName(documentPath);
+ return Saved ? fileName : fileName + " [Unsaved]";
+ }
}
///
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index fb721fb51..ab027b1e9 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -33,7 +33,7 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
EditorWorkspace workspace = new(editorOperations);
- EditorWorkspaceDocument[] documents = workspace.Documents;
+ WorkspaceOpenDocument[] documents = workspace.Documents;
Assert.Collection(
documents,
@@ -50,7 +50,7 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
}
[Fact]
- public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
+ public void DocumentSaveAndCloseUseWorkspaceOperations()
{
string filePath = Path.Combine(WorkspacePath, "file.ps1");
TestEditorOperations editorOperations = new()
@@ -59,15 +59,13 @@ public void DocumentOpenSaveAndCloseUseWorkspaceOperations()
};
EditorWorkspace workspace = new(editorOperations);
- EditorWorkspaceDocument document = Assert.Single(workspace.Documents);
+ WorkspaceOpenDocument document = Assert.Single(workspace.Documents);
- document.Open();
document.Save();
document.Close();
Assert.Collection(
editorOperations.Calls,
- call => Assert.Equal("OpenFile:" + filePath, call),
call => Assert.Equal("SaveFile:" + filePath, call),
call => Assert.Equal("CloseFile:" + filePath, call));
}
@@ -86,7 +84,7 @@ public void DocumentToStringReturnsFileNameAndSavedStatus()
};
EditorWorkspace workspace = new(editorOperations);
- IEnumerable documents = workspace.Documents;
+ IEnumerable documents = workspace.Documents;
Assert.Collection(
documents,
@@ -106,7 +104,7 @@ public void DocumentSavedReturnsWorkspaceSavedState()
};
EditorWorkspace workspace = new(editorOperations);
- IEnumerable documents = workspace.Documents;
+ IEnumerable documents = workspace.Documents;
Assert.Collection(
documents,
From 9d5106349f1c81f3a95f354bd67a1fdf1dac2e9a Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 17:09:02 -0700
Subject: [PATCH 19/31] Remove dangling using
---
src/PowerShellEditorServices/Extensions/EditorWorkspace.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index a19c3d538..209d6b091 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System.Linq;
-
namespace Microsoft.PowerShell.EditorServices.Extensions
{
///
From cfeba0e85f3336536db5852843ce0221b0415247 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Tue, 12 May 2026 17:24:55 -0700
Subject: [PATCH 20/31] Fix Tests
---
.../Extensions/EditorWorkspaceTests.cs | 21 -------------------
1 file changed, 21 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
index ab027b1e9..673d864d5 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorWorkspaceTests.cs
@@ -49,27 +49,6 @@ public void DocumentsReturnsOpenWorkspaceDocuments()
});
}
- [Fact]
- public void DocumentSaveAndCloseUseWorkspaceOperations()
- {
- string filePath = Path.Combine(WorkspacePath, "file.ps1");
- TestEditorOperations editorOperations = new()
- {
- OpenDocuments = [new WorkspaceOpenDocument(filePath, saved: true)]
- };
-
- EditorWorkspace workspace = new(editorOperations);
- WorkspaceOpenDocument document = Assert.Single(workspace.Documents);
-
- document.Save();
- document.Close();
-
- Assert.Collection(
- editorOperations.Calls,
- call => Assert.Equal("SaveFile:" + filePath, call),
- call => Assert.Equal("CloseFile:" + filePath, call));
- }
-
[Fact]
public void DocumentToStringReturnsFileNameAndSavedStatus()
{
From 9bba5bfe3cdac44a15212480d4591c547857844d Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Wed, 13 May 2026 08:52:46 -0700
Subject: [PATCH 21/31] Additional comments and logging
---
.../Services/TextDocument/ScriptFile.cs | 3 +++
.../Services/Workspace/WorkspaceService.cs | 9 ++++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
index 96912d751..b8d60ce08 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
@@ -110,6 +110,9 @@ public Token[] ScriptTokens
internal ReferenceTable References { get; }
+ ///
+ /// Indicates whether the file is currently open in the editor. PSES may open files for analysis that aren't actually visible in the editor.
+ ///
internal bool IsOpen { get; set; }
#endregion
diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
index efd7f82d7..ac6799238 100644
--- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
@@ -302,7 +302,14 @@ public void CloseFile(ScriptFile scriptFile)
Validate.IsNotNull(nameof(scriptFile), scriptFile);
string keyName = GetFileKey(scriptFile.DocumentUri);
- workspaceFiles.TryRemove(keyName, out ScriptFile _);
+ if (workspaceFiles.TryRemove(keyName, out ScriptFile _))
+ {
+ logger.LogDebug("Closed file: " + scriptFile.DocumentUri);
+ }
+ else
+ {
+ logger.LogWarning("Tried to close file that was not open: " + scriptFile.DocumentUri);
+ }
}
///
From 25e22404b203ef9ff5d91e8572dd238ffb7d4a63 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Wed, 13 May 2026 09:34:50 -0700
Subject: [PATCH 22/31] Simplify IsUntitled getter (even tho I'm pretty sure
this will break it again)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
.../Services/TextDocument/ScriptFile.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
index b8d60ce08..9cff31d41 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
@@ -56,9 +56,10 @@ internal sealed class ScriptFile
public bool IsInMemory { get; internal set; }
///
- /// Getter that returns if the document is not backed by a saved file path (not in-memory).
+ /// Gets a value indicating whether the document URI is not a file:// URI
+ /// (for example, an untitled: URI).
///
- public bool IsUntitled => !DocumentUri?.ToUri().IsFile ?? false;
+ public bool IsUntitled => !DocumentUri.ToUri().IsFile;
///
/// Gets a string containing the full contents of the file.
From 7e2f5d4056b6cb207e43cb62ae3b14da595e7fce Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Wed, 13 May 2026 09:36:02 -0700
Subject: [PATCH 23/31] Remove unnecessary collection expression
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
src/PowerShellEditorServices/Extensions/EditorWorkspace.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index 209d6b091..f3c40d74a 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -31,7 +31,7 @@ public sealed class EditorWorkspace
///
/// Get all currently open documents in the workspace.
///
- public WorkspaceOpenDocument[] Documents => [.. editorOperations.GetWorkspaceOpenDocuments()];
+ public WorkspaceOpenDocument[] Documents => editorOperations.GetWorkspaceOpenDocuments();
#endregion
From 8a167cbdf2950f9bf5ce26226035e7aa9f78e0e0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 13 May 2026 16:36:07 +0000
Subject: [PATCH 24/31] Fix file-backed checks to use IsUntitled
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/25fb4a4a-04f5-471e-93fa-82a0a9cdcd91
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Services/TextDocument/Handlers/CompletionHandler.cs | 2 +-
.../Services/Workspace/WorkspaceService.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs
index c3d7a39c5..8dbb8f798 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs
@@ -366,7 +366,7 @@ private CompletionItem CreateProviderItemCompletion(
if (textToBeReplaced.IndexOf(PSScriptRootVariable, StringComparison.OrdinalIgnoreCase) is int variableIndex and not -1
&& System.IO.Path.GetDirectoryName(scriptFile.FilePath) is string scriptFolder and not ""
&& completionText.IndexOf(scriptFolder, StringComparison.OrdinalIgnoreCase) is int pathIndex and not -1
- && !scriptFile.IsInMemory)
+ && !scriptFile.IsUntitled)
{
completionText = completionText
.Remove(pathIndex, scriptFolder.Length)
diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
index ac6799238..9b721387a 100644
--- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
@@ -319,7 +319,7 @@ public void CloseFile(ScriptFile scriptFile)
public string GetRelativePath(ScriptFile scriptFile)
{
Uri fileUri = scriptFile.DocumentUri.ToUri();
- if (!scriptFile.IsInMemory)
+ if (!scriptFile.IsUntitled)
{
// Support calculating out-of-workspace relative paths in the common case of a
// single workspace folder. Otherwise try to get the matching folder.
From f14c10df69e20c05470c8dc0c35a110443edd510 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Wed, 13 May 2026 09:37:45 -0700
Subject: [PATCH 25/31] Avoid extra recompilation for IsUntitled
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
.../Services/TextDocument/Handlers/TextDocumentHandler.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
index 5ad70905c..ba2e9242b 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
@@ -114,7 +114,7 @@ public override Task Handle(DidCloseTextDocumentParams notification, Cance
// If the file watcher is supported, only close non-file-backed documents when this
// notification is triggered. This lets us keep workspace files open so we can scan
// for references. When a file is deleted, the file watcher will close the file.
- bool isBackedByFile = notification.TextDocument.Uri.ToUri().IsFile;
+ bool isBackedByFile = !fileToClose.IsUntitled;
if (!_isFileWatcherSupported || !isBackedByFile)
{
_workspaceService.CloseFile(fileToClose);
From e105ee67f3cad386f57b71cfdadf88784d1f2db6 Mon Sep 17 00:00:00 2001
From: Justin Grote
Date: Wed, 13 May 2026 09:38:15 -0700
Subject: [PATCH 26/31] Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
.../EditorOperationsServiceTests.cs | 78 +++++++++----------
1 file changed, 39 insertions(+), 39 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
index e679bdeb1..bf702ee03 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -13,43 +13,43 @@
namespace PowerShellEditorServices.Test.Extensions
{
- [Trait("Category", "Extensions")]
- public class EditorOperationsServiceTests
- {
- [Fact]
- public void GetWorkspaceOpenDocumentsReturnsOnlyOpenDocumentsAndCurrentInMemoryState()
- {
- WorkspaceService workspaceService = new(NullLoggerFactory.Instance);
-
- ScriptFile openSaved = CreateFileBuffer(workspaceService, "open-saved.ps1");
- openSaved.IsOpen = true;
- openSaved.IsInMemory = false;
-
- ScriptFile openUnsaved = CreateFileBuffer(workspaceService, "open-unsaved.ps1");
- openUnsaved.IsOpen = true;
- openUnsaved.IsInMemory = true;
-
- ScriptFile closed = CreateFileBuffer(workspaceService, "closed.ps1");
- closed.IsOpen = false;
- closed.IsInMemory = false;
-
- EditorOperationsService editorOperationsService = new(
- psesHost: null,
- workspaceService,
- languageServer: null);
-
- WorkspaceOpenDocument[] documents = editorOperationsService.GetWorkspaceOpenDocuments();
-
- Assert.Equal(2, documents.Length);
- Assert.Contains(documents, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
- Assert.Contains(documents, static document => document.Path.EndsWith("open-unsaved.ps1") && !document.Saved);
- Assert.DoesNotContain(documents, static document => document.Path.EndsWith("closed.ps1"));
- }
-
- private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, string fileName)
- {
- string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), fileName);
- return workspaceService.GetFileBuffer(DocumentUri.FromFileSystemPath(filePath), initialBuffer: string.Empty);
- }
- }
+ [Trait("Category", "Extensions")]
+ public class EditorOperationsServiceTests
+ {
+ [Fact]
+ public void GetWorkspaceOpenDocumentsReturnsOnlyOpenDocumentsAndCurrentInMemoryState()
+ {
+ WorkspaceService workspaceService = new(NullLoggerFactory.Instance);
+
+ ScriptFile openSaved = CreateFileBuffer(workspaceService, "open-saved.ps1");
+ openSaved.IsOpen = true;
+ openSaved.IsInMemory = false;
+
+ ScriptFile openUnsaved = CreateFileBuffer(workspaceService, "open-unsaved.ps1");
+ openUnsaved.IsOpen = true;
+ openUnsaved.IsInMemory = true;
+
+ ScriptFile closed = CreateFileBuffer(workspaceService, "closed.ps1");
+ closed.IsOpen = false;
+ closed.IsInMemory = false;
+
+ EditorOperationsService editorOperationsService = new(
+ psesHost: null,
+ workspaceService,
+ languageServer: null);
+
+ WorkspaceOpenDocument[] documents = editorOperationsService.GetWorkspaceOpenDocuments();
+
+ Assert.Equal(2, documents.Length);
+ Assert.Contains(documents, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
+ Assert.Contains(documents, static document => document.Path.EndsWith("open-unsaved.ps1") && !document.Saved);
+ Assert.DoesNotContain(documents, static document => document.Path.EndsWith("closed.ps1"));
+ }
+
+ private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, string fileName)
+ {
+ string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), fileName);
+ return workspaceService.GetFileBuffer(DocumentUri.FromFileSystemPath(filePath), initialBuffer: string.Empty);
+ }
+ }
}
From cfead40b037ea950b0089b48db3debc88a1b46c8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 13 May 2026 16:43:44 +0000
Subject: [PATCH 27/31] Add transition coverage for workspace open document
saved state
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/f6b6da25-a6a1-4158-9738-3a65a7e3008e
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../EditorOperationsServiceTests.cs | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
index bf702ee03..5b5b887c7 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -46,6 +46,43 @@ public void GetWorkspaceOpenDocumentsReturnsOnlyOpenDocumentsAndCurrentInMemoryS
Assert.DoesNotContain(documents, static document => document.Path.EndsWith("closed.ps1"));
}
+ [Fact]
+ public void GetWorkspaceOpenDocumentsTracksEditedAndUntitledSaveStates()
+ {
+ WorkspaceService workspaceService = new(NullLoggerFactory.Instance);
+
+ ScriptFile openSaved = CreateFileBuffer(workspaceService, "open-saved.ps1");
+ openSaved.IsOpen = true;
+
+ ScriptFile openUntitled = workspaceService.GetFileBuffer("untitled:Untitled-1", initialBuffer: string.Empty);
+ openUntitled.IsOpen = true;
+
+ EditorOperationsService editorOperationsService = new(
+ psesHost: null,
+ workspaceService,
+ languageServer: null);
+
+ WorkspaceOpenDocument[] initialDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
+ Assert.Contains(initialDocuments, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
+ Assert.Contains(initialDocuments, static document => document.Path.StartsWith("untitled:", StringComparison.Ordinal) && !document.Saved);
+
+ openSaved.ApplyChange(new FileChange
+ {
+ IsReload = true,
+ InsertString = "Set-StrictMode -Version Latest"
+ });
+
+ WorkspaceOpenDocument[] editedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
+ Assert.Contains(editedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && !document.Saved);
+
+ openSaved.IsInMemory = openSaved.IsUntitled;
+ openUntitled.IsInMemory = openUntitled.IsUntitled;
+
+ WorkspaceOpenDocument[] savedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
+ Assert.Contains(savedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
+ Assert.Contains(savedDocuments, static document => document.Path.StartsWith("untitled:", StringComparison.Ordinal) && !document.Saved);
+ }
+
private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, string fileName)
{
string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), fileName);
From 45f719c46a37acc8939e89229c89afc95a1b467b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 13 May 2026 16:44:34 +0000
Subject: [PATCH 28/31] Refine workspace document transition test semantics
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/f6b6da25-a6a1-4158-9738-3a65a7e3008e
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorOperationsServiceTests.cs | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
index 5b5b887c7..30c2bfdd5 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -68,15 +68,18 @@ public void GetWorkspaceOpenDocumentsTracksEditedAndUntitledSaveStates()
openSaved.ApplyChange(new FileChange
{
- IsReload = true,
+ Line = 1,
+ Offset = 1,
+ EndLine = 1,
+ EndOffset = 1,
InsertString = "Set-StrictMode -Version Latest"
});
WorkspaceOpenDocument[] editedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
Assert.Contains(editedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && !document.Saved);
- openSaved.IsInMemory = openSaved.IsUntitled;
- openUntitled.IsInMemory = openUntitled.IsUntitled;
+ SimulateSaveReset(openSaved);
+ SimulateSaveReset(openUntitled);
WorkspaceOpenDocument[] savedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
Assert.Contains(savedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
@@ -88,5 +91,10 @@ private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, st
string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), fileName);
return workspaceService.GetFileBuffer(DocumentUri.FromFileSystemPath(filePath), initialBuffer: string.Empty);
}
+
+ private static void SimulateSaveReset(ScriptFile scriptFile)
+ {
+ scriptFile.IsInMemory = scriptFile.IsUntitled;
+ }
}
}
From 9c3ac22d5b7afa8e88566de23acd7239dbfdaaa6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 13 May 2026 16:45:14 +0000
Subject: [PATCH 29/31] Rename test helper to clarify saved-state intent
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/f6b6da25-a6a1-4158-9738-3a65a7e3008e
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorOperationsServiceTests.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
index 30c2bfdd5..19767a095 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -78,8 +78,8 @@ public void GetWorkspaceOpenDocumentsTracksEditedAndUntitledSaveStates()
WorkspaceOpenDocument[] editedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
Assert.Contains(editedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && !document.Saved);
- SimulateSaveReset(openSaved);
- SimulateSaveReset(openUntitled);
+ MarkAsSaved(openSaved);
+ MarkAsSaved(openUntitled);
WorkspaceOpenDocument[] savedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
Assert.Contains(savedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && document.Saved);
@@ -92,7 +92,7 @@ private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, st
return workspaceService.GetFileBuffer(DocumentUri.FromFileSystemPath(filePath), initialBuffer: string.Empty);
}
- private static void SimulateSaveReset(ScriptFile scriptFile)
+ private static void MarkAsSaved(ScriptFile scriptFile)
{
scriptFile.IsInMemory = scriptFile.IsUntitled;
}
From 605e82cdbb61c065ab86363c00ba1b6906f8b693 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 13 May 2026 16:45:55 +0000
Subject: [PATCH 30/31] Assert edited content in open-document transition test
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/f6b6da25-a6a1-4158-9738-3a65a7e3008e
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorOperationsServiceTests.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
index 19767a095..a43982b72 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -74,6 +74,7 @@ public void GetWorkspaceOpenDocumentsTracksEditedAndUntitledSaveStates()
EndOffset = 1,
InsertString = "Set-StrictMode -Version Latest"
});
+ Assert.Contains("Set-StrictMode -Version Latest", openSaved.Contents, StringComparison.Ordinal);
WorkspaceOpenDocument[] editedDocuments = editorOperationsService.GetWorkspaceOpenDocuments();
Assert.Contains(editedDocuments, static document => document.Path.EndsWith("open-saved.ps1") && !document.Saved);
From 384b313cb98b640f6b08fd72376da0a608f3ed4b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 13 May 2026 20:18:42 +0000
Subject: [PATCH 31/31] Use expression-bodied helper to satisfy IDE0022
Agent-Logs-Url: https://github.com/PowerShell/PowerShellEditorServices/sessions/c6f63c96-d7c5-4f03-9391-a32f918383a6
Co-authored-by: JustinGrote <15258962+JustinGrote@users.noreply.github.com>
---
.../Extensions/EditorOperationsServiceTests.cs | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
index a43982b72..45ef4e538 100644
--- a/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Extensions/EditorOperationsServiceTests.cs
@@ -93,9 +93,6 @@ private static ScriptFile CreateFileBuffer(WorkspaceService workspaceService, st
return workspaceService.GetFileBuffer(DocumentUri.FromFileSystemPath(filePath), initialBuffer: string.Empty);
}
- private static void MarkAsSaved(ScriptFile scriptFile)
- {
- scriptFile.IsInMemory = scriptFile.IsUntitled;
- }
+ private static void MarkAsSaved(ScriptFile scriptFile) => scriptFile.IsInMemory = scriptFile.IsUntitled;
}
}