From c7e18c5c7bfb91fbd3473f0e362e76a54601b81c Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 9 Dec 2016 10:22:27 -0800 Subject: [PATCH 1/5] Fix #312: File preview Uris crash the language server --- src/PowerShellEditorServices/Workspace/Workspace.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 24ca0932e..125921d3d 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -264,10 +264,13 @@ internal static bool IsPathInMemory(string filePath) // When viewing PowerShell files in the Git diff viewer, VS Code // sends the contents of the file at HEAD with a URI that starts // with 'inmemory'. Untitled files which have been marked of - // type PowerShell have a path starting with 'untitled'. + // type PowerShell have a path starting with 'untitled'. Files + // opened from the find/replace view will be prefixed with + // 'private'. return filePath.StartsWith("inmemory") || - filePath.StartsWith("untitled"); + filePath.StartsWith("untitled") || + filePath.StartsWith("private"); } private string GetBaseFilePath(string filePath) From 56a0ebda1ebcf2d1640c1ae2e945a6089afe9621 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 9 Dec 2016 10:23:12 -0800 Subject: [PATCH 2/5] Fix #242: Remove timeout for PSHostUserInterface prompts --- .../Session/SessionPSHostUserInterface.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/PowerShellEditorServices/Session/SessionPSHostUserInterface.cs b/src/PowerShellEditorServices/Session/SessionPSHostUserInterface.cs index 921120c85..18eba2735 100644 --- a/src/PowerShellEditorServices/Session/SessionPSHostUserInterface.cs +++ b/src/PowerShellEditorServices/Session/SessionPSHostUserInterface.cs @@ -320,10 +320,8 @@ private void WaitForPromptCompletion( try { // This will synchronously block on the prompt task - // method which gets run on another thread. Use a - // 30 second timeout so that everything doesn't get - // backed up if the user doesn't respond. - promptTask.Wait(15000); + // method which gets run on another thread. + promptTask.Wait(); if (promptTask.Status == TaskStatus.WaitingForActivation) { From 29617f8f3d6fbdf65367c5c7ca1c69de9e2e74a1 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 9 Dec 2016 10:25:18 -0800 Subject: [PATCH 3/5] Add workspace path information to psEditor.Workspace API This change adds a new Path property to the EditorWorkspace class which gets exposed through to the psEditor API. This is useful for extension authors who want to perform operations based on the workspace path. Resolves #236. --- .../Server/LanguageServerEditorOperations.cs | 11 +++++- .../Extensions/EditorWorkspace.cs | 12 ++++++ .../Extensions/FileContext.cs | 13 +++++++ .../Extensions/IEditorOperations.cs | 13 +++++++ .../Workspace/Workspace.cs | 26 +++++++++++++ .../Extensions/ExtensionServiceTests.cs | 10 +++++ .../PowerShellEditorServices.Test.csproj | 1 + .../Session/WorkspaceTests.cs | 38 +++++++++++++++++++ 8 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs index f60772527..b8c1da92c 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs @@ -7,7 +7,6 @@ using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; using System.Threading.Tasks; -using System; namespace Microsoft.PowerShell.EditorServices.Protocol.Server { @@ -111,6 +110,16 @@ public Task OpenFile(string filePath) true); } + public string GetWorkspacePath() + { + return this.editorSession.Workspace.WorkspacePath; + } + + public string GetWorkspaceRelativePath(string filePath) + { + return this.editorSession.Workspace.GetRelativePath(filePath); + } + public Task ShowInformationMessage(string message) { return diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs index a9598f09c..68d113523 100644 --- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs +++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs @@ -17,6 +17,18 @@ public class EditorWorkspace #endregion + #region Properties + + /// + /// Gets the current workspace path if there is one or null otherwise. + /// + public string Path + { + get { return this.editorOperations.GetWorkspacePath(); } + } + + #endregion + #region Constructors internal EditorWorkspace(IEditorOperations editorOperations) diff --git a/src/PowerShellEditorServices/Extensions/FileContext.cs b/src/PowerShellEditorServices/Extensions/FileContext.cs index 9b7f7f8d7..8eb8d2812 100644 --- a/src/PowerShellEditorServices/Extensions/FileContext.cs +++ b/src/PowerShellEditorServices/Extensions/FileContext.cs @@ -32,6 +32,19 @@ public string Path get { return this.scriptFile.FilePath; } } + /// + /// Gets the workspace-relative path of the file. + /// + public string WorkspacePath + { + get + { + return + this.editorOperations.GetWorkspaceRelativePath( + this.scriptFile.FilePath); + } + } + /// /// Gets the parsed abstract syntax tree for the file. /// diff --git a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs index 7f6845d6e..8e9358e1b 100644 --- a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs +++ b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs @@ -20,6 +20,19 @@ public interface IEditorOperations /// A new EditorContext object. Task GetEditorContext(); + /// + /// Gets the path to the editor's active workspace. + /// + /// The workspace path or null if there isn't one. + string GetWorkspacePath(); + + /// + /// Resolves the given file path relative to the current workspace path. + /// + /// The file path to be resolved. + /// The resolved file path. + string GetWorkspaceRelativePath(string filePath); + /// /// Causes a file to be opened in the editor. If the file is /// already open, the editor must switch to the file. diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 125921d3d..8e66f4599 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -176,6 +176,32 @@ public ScriptFile[] ExpandScriptReferences(ScriptFile scriptFile) return expandedReferences.ToArray(); } + /// + /// Gets the workspace-relative path of the given file path. + /// + /// The original full file path. + /// A relative file path + public string GetRelativePath(string filePath) + { + string resolvedPath = filePath; + + if (!IsPathInMemory(filePath) && !string.IsNullOrEmpty(this.WorkspacePath)) + { + Uri workspaceUri = new Uri(this.WorkspacePath); + Uri fileUri = new Uri(filePath); + + resolvedPath = workspaceUri.MakeRelativeUri(fileUri).ToString(); + + // Convert the directory separators if necessary + if (System.IO.Path.DirectorySeparatorChar == '\\') + { + resolvedPath = resolvedPath.Replace('/', '\\'); + } + } + + return resolvedPath; + } + #endregion #region Private Methods diff --git a/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs index 84475829a..3ac6a22f3 100644 --- a/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs @@ -168,6 +168,16 @@ await this.extensionEventQueue.EnqueueAsync( public class TestEditorOperations : IEditorOperations { + public string GetWorkspacePath() + { + throw new NotImplementedException(); + } + + public string GetWorkspaceRelativePath(string filePath) + { + throw new NotImplementedException(); + } + public Task OpenFile(string filePath) { throw new NotImplementedException(); diff --git a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj index 5a9a43cd9..3d5531cda 100644 --- a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj +++ b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj @@ -73,6 +73,7 @@ + diff --git a/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs b/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs new file mode 100644 index 000000000..16b58987f --- /dev/null +++ b/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices; +using System; +using System.IO; +using System.Linq; +using Xunit; + +namespace Microsoft.PowerShell.EditorServices.Test.Session +{ + public class WorkspaceTests + { + private static readonly Version PowerShellVersion = new Version("5.0"); + + [Fact] + public void CanResolveWorkspaceRelativePath() + { + string workspacePath = @"c:\Test\Workspace\"; + string testPathInside = @"c:\Test\Workspace\SubFolder\FilePath.ps1"; + string testPathOutside = @"c:\Test\PeerPath\FilePath.ps1"; + string testPathAnotherDrive = @"z:\TryAndFindMe\FilePath.ps1"; + + Workspace workspace = new Workspace(PowerShellVersion); + + // Test without a workspace path + Assert.Equal(testPathOutside, workspace.GetRelativePath(testPathOutside)); + + // Test with a workspace path + workspace.WorkspacePath = workspacePath; + Assert.Equal(@"SubFolder\FilePath.ps1", workspace.GetRelativePath(testPathInside)); + Assert.Equal(@"..\PeerPath\FilePath.ps1", workspace.GetRelativePath(testPathOutside)); + Assert.Equal(testPathAnotherDrive, workspace.GetRelativePath(testPathAnotherDrive)); + } + } +} From 1d1d3eefcb4175d02b3cccd07cd4aa8c8bddb3ff Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 9 Dec 2016 10:41:55 -0800 Subject: [PATCH 4/5] Fix #237: Set session's current directory to the workspace path --- .../Server/LanguageServer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 60261d492..86aefa5ee 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -141,6 +141,13 @@ protected async Task HandleInitializeRequest( // Grab the workspace path from the parameters editorSession.Workspace.WorkspacePath = initializeParams.RootPath; + // Set the working directory of the PowerShell session to the workspace path + if (editorSession.Workspace.WorkspacePath != null) + { + editorSession.PowerShellContext.SetWorkingDirectory( + editorSession.Workspace.WorkspacePath); + } + await requestContext.SendResult( new InitializeResult { From 5c0ac2c8181861c19a7cd4c1b2d3d11039231564 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 9 Dec 2016 11:00:36 -0800 Subject: [PATCH 5/5] Fix #291: Dot-source reference detection should ignore ScriptBlocks --- src/PowerShellEditorServices/Language/FindDotSourcedVisitor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Language/FindDotSourcedVisitor.cs b/src/PowerShellEditorServices/Language/FindDotSourcedVisitor.cs index 7ffda9c2a..ea35dd4a1 100644 --- a/src/PowerShellEditorServices/Language/FindDotSourcedVisitor.cs +++ b/src/PowerShellEditorServices/Language/FindDotSourcedVisitor.cs @@ -32,7 +32,8 @@ public FindDotSourcedVisitor() /// or a decision to continue if it wasn't found public override AstVisitAction VisitCommand(CommandAst commandAst) { - if (commandAst.InvocationOperator.Equals(TokenKind.Dot)) + if (commandAst.InvocationOperator.Equals(TokenKind.Dot) && + commandAst.CommandElements[0] is StringConstantExpressionAst) { // Strip any quote characters off of the string string fileName = commandAst.CommandElements[0].Extent.Text.Trim('\'', '"');