Skip to content

Commit c9a9d26

Browse files
authored
Merge pull request #399 from daviwil/remote-file-save
Enable saving remote files opened with psedit
2 parents 737b8cf + a8c8a04 commit c9a9d26

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

src/PowerShellEditorServices.Protocol/LanguageServer/TextDocument.cs

+12
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ public static readonly
5252
EventType<TextDocumentIdentifier>.Create("textDocument/didClose");
5353
}
5454

55+
public class DidSaveTextDocumentNotification
56+
{
57+
public static readonly
58+
EventType<DidSaveTextDocumentParams> Type =
59+
EventType<DidSaveTextDocumentParams>.Create("textDocument/didSave");
60+
}
61+
62+
public class DidSaveTextDocumentParams
63+
{
64+
public TextDocumentIdentifier TextDocument { get; set; }
65+
}
66+
5567
public class DidChangeTextDocumentNotification
5668
{
5769
public static readonly

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

+18
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ protected override void Initialize()
110110

111111
this.SetEventHandler(DidOpenTextDocumentNotification.Type, this.HandleDidOpenTextDocumentNotification);
112112
this.SetEventHandler(DidCloseTextDocumentNotification.Type, this.HandleDidCloseTextDocumentNotification);
113+
this.SetEventHandler(DidSaveTextDocumentNotification.Type, this.HandleDidSaveTextDocumentNotification);
113114
this.SetEventHandler(DidChangeTextDocumentNotification.Type, this.HandleDidChangeTextDocumentNotification);
114115
this.SetEventHandler(DidChangeConfigurationNotification<LanguageServerSettingsWrapper>.Type, this.HandleDidChangeConfigurationNotification);
115116

@@ -516,6 +517,23 @@ protected async Task HandleDidCloseTextDocumentNotification(
516517

517518
Logger.Write(LogLevel.Verbose, "Finished closing document.");
518519
}
520+
protected async Task HandleDidSaveTextDocumentNotification(
521+
DidSaveTextDocumentParams saveParams,
522+
EventContext eventContext)
523+
{
524+
ScriptFile savedFile =
525+
this.editorSession.Workspace.GetFile(
526+
saveParams.TextDocument.Uri);
527+
528+
if (savedFile != null)
529+
{
530+
if (this.editorSession.RemoteFileManager.IsUnderRemoteTempPath(savedFile.FilePath))
531+
{
532+
await this.editorSession.RemoteFileManager.SaveRemoteFile(
533+
savedFile.FilePath);
534+
}
535+
}
536+
}
519537

520538
protected Task HandleDidChangeTextDocumentNotification(
521539
DidChangeTextDocumentParams textChangeParams,

src/PowerShellEditorServices/Session/RemoteFileManager.cs

+65
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Linq;
1313
using System.Management.Automation;
1414
using System.Management.Automation.Runspaces;
15+
using System.Text;
1516
using System.Threading.Tasks;
1617

1718
namespace Microsoft.PowerShell.EditorServices.Session
@@ -77,6 +78,15 @@ public class RemoteFileManager
7778
Get-EventSubscriber -SourceIdentifier PSESRemoteSessionOpenFile -EA Ignore | Remove-Event
7879
";
7980

81+
private const string SetRemoteContentsScript = @"
82+
param(
83+
[string] $RemoteFilePath,
84+
[byte[]] $Content
85+
)
86+
87+
Set-Content -Path $RemoteFilePath -Value $Content -Encoding Byte -Force 2>&1
88+
";
89+
8090
#endregion
8191

8292
#region Constructors
@@ -185,6 +195,61 @@ public async Task<string> FetchRemoteFile(
185195
return localFilePath;
186196
}
187197

198+
/// <summary>
199+
/// Saves the contents of the file under the temporary local
200+
/// file cache to its corresponding remote file.
201+
/// </summary>
202+
/// <param name="localFilePath">
203+
/// The local file whose contents will be saved. It is assumed
204+
/// that the editor has saved the contents of the local cache
205+
/// file to disk before this method is called.
206+
/// </param>
207+
/// <returns>A Task to be awaited for completion.</returns>
208+
public async Task SaveRemoteFile(string localFilePath)
209+
{
210+
string remoteFilePath =
211+
this.GetMappedPath(
212+
localFilePath,
213+
this.powerShellContext.CurrentRunspace);
214+
215+
Logger.Write(
216+
LogLevel.Verbose,
217+
$"Saving remote file {remoteFilePath} (local path: {localFilePath})");
218+
219+
byte[] localFileContents = null;
220+
try
221+
{
222+
localFileContents = File.ReadAllBytes(localFilePath);
223+
}
224+
catch (IOException e)
225+
{
226+
Logger.WriteException(
227+
"Failed to read contents of local copy of remote file",
228+
e);
229+
230+
return;
231+
}
232+
233+
PSCommand saveCommand = new PSCommand();
234+
saveCommand
235+
.AddScript(SetRemoteContentsScript)
236+
.AddParameter("RemoteFilePath", remoteFilePath)
237+
.AddParameter("Content", localFileContents);
238+
239+
StringBuilder errorMessages = new StringBuilder();
240+
241+
await this.powerShellContext.ExecuteCommand<object>(
242+
saveCommand,
243+
errorMessages,
244+
false,
245+
false);
246+
247+
if (errorMessages.Length > 0)
248+
{
249+
Logger.Write(LogLevel.Error, $"Remote file save failed due to an error:\r\n\r\n{errorMessages}");
250+
}
251+
}
252+
188253
/// <summary>
189254
/// Creates a temporary file with the given name and contents
190255
/// corresponding to the specified runspace.

0 commit comments

Comments
 (0)