Skip to content

Fix unable to open files in problems/peek windows issue #872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 11, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private async Task HandleCodeLensRequestAsync(
codeLensResponse[i] = codeLensResults[i].ToProtocolCodeLens(
new CodeLensData
{
Uri = codeLensResults[i].File.ClientFilePath,
Uri = codeLensResults[i].File.DocumentUri,
ProviderId = codeLensResults[i].Provider.ProviderId
},
_jsonSerializer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using Microsoft.PowerShell.EditorServices.Commands;
using Microsoft.PowerShell.EditorServices.Symbols;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Commands;
using Microsoft.PowerShell.EditorServices.Symbols;

namespace Microsoft.PowerShell.EditorServices.CodeLenses
{
Expand Down Expand Up @@ -53,7 +51,7 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile
"PowerShell.RunPesterTests",
"Run tests",
new object[] {
scriptFile.ClientFilePath,
scriptFile.DocumentUri,
false /* No debug */,
pesterSymbol.TestName,
pesterSymbol.ScriptRegion?.StartLineNumber })),
Expand All @@ -66,7 +64,7 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile
"PowerShell.RunPesterTests",
"Debug tests",
new object[] {
scriptFile.ClientFilePath,
scriptFile.DocumentUri,
true /* Run in the debugger */,
pesterSymbol.TestName,
pesterSymbol.ScriptRegion?.StartLineNumber })),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public async Task<CodeLens> ResolveCodeLensAsync(
GetReferenceCountHeader(referenceLocations.Length),
new object[]
{
codeLens.File.ClientFilePath,
codeLens.File.DocumentUri,
codeLens.ScriptExtent.ToRange().Start,
referenceLocations,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1757,15 +1757,15 @@ private static async Task PublishScriptDiagnosticsAsync(
diagnostics.Add(markerDiagnostic);
}

correctionIndex[scriptFile.ClientFilePath] = fileCorrections;
correctionIndex[scriptFile.DocumentUri] = fileCorrections;

// Always send syntax and semantic errors. We want to
// make sure no out-of-date markers are being displayed.
await eventSender(
PublishDiagnosticsNotification.Type,
new PublishDiagnosticsNotification
{
Uri = scriptFile.ClientFilePath,
Uri = scriptFile.DocumentUri,
Diagnostics = diagnostics.ToArray()
});
}
Expand Down
16 changes: 15 additions & 1 deletion src/PowerShellEditorServices/Workspace/ScriptFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using Microsoft.PowerShell.EditorServices.Utility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Runtime.InteropServices;
using Microsoft.PowerShell.EditorServices.Utility;

namespace Microsoft.PowerShell.EditorServices
{
Expand Down Expand Up @@ -52,6 +53,19 @@ public string Id
/// </summary>
public string ClientFilePath { get; private set; }

/// <summary>
/// Gets the file path in LSP DocumentUri form. The ClientPath property must not be null.
/// </summary>
public string DocumentUri
{
get
{
return (this.ClientFilePath == null )
? string.Empty
: Workspace.ConvertPathToDocumentUri(this.ClientFilePath);
}
}

/// <summary>
/// Gets or sets a boolean that determines whether
/// semantic analysis should be enabled for this file.
Expand Down
57 changes: 55 additions & 2 deletions src/PowerShellEditorServices/Workspace/Workspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ private void RecursivelyEnumerateFiles(string folderPath, ref List<string> found
this.logger.WriteHandledException(
$"Could not enumerate files in the path '{folderPath}' due to an exception",
e);

continue;
}

Expand Down Expand Up @@ -400,7 +400,7 @@ private void RecursivelyEnumerateFiles(string folderPath, ref List<string> found
this.logger.WriteHandledException(
$"Could not enumerate directories in the path '{folderPath}' due to an exception",
e);

return;
}

Expand Down Expand Up @@ -625,6 +625,59 @@ private static string UnescapeDriveColon(string fileUri)
return sb.ToString();
}

/// <summary>
/// Converts a file system path into a DocumentUri required by Language Server Protocol.
/// </summary>
/// <remarks>
/// When sending a document path to a LSP client, the path must be provided as a
/// DocumentUri in order to features like the Problems window or peek definition
/// to be able to open the specified file.
/// </remarks>
/// <param name="path">
/// A file system path. Note: if the path is already a DocumentUri, it will be returned unmodified.
/// </param>
/// <returns>The file system path encoded as a DocumentUri.</returns>
internal static string ConvertPathToDocumentUri(string path)
{
const string fileUriPrefix = "file:///";

if (path.StartsWith("untitled:", StringComparison.Ordinal))
{
return path;
}

if (path.StartsWith(fileUriPrefix, StringComparison.Ordinal))
{
return path;
}

if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return new Uri(path).AbsoluteUri;
}

// VSCode file URIs on Windows need the drive letter lowercase, and the colon
// URI encoded. System.Uri won't do that, so we manually create the URI.
var newUri = System.Web.HttpUtility.UrlPathEncode(path);
int colonIndex = path.IndexOf(':');
for (var i = colonIndex - 1; i >= 0; i--)
{
newUri.Remove(i, 1);
newUri.Insert(i, char.ToLowerInvariant(path[i]).ToString());
}

// On a Linux filesystem, you can have multiple colons in a filename e.g. foo:bar:baz.txt
if (colonIndex >= 0)
{
newUri = newUri.Replace(":", "%3A");
}

return newUri
.Replace('\\', '/')
.Insert(0, fileUriPrefix)
.ToString();
}

#endregion
}
}