Skip to content

Commit 9e3fbcf

Browse files
Depend on DocumentUri for handing vscode Uri's (#1291)
* Depend on DocumentUri for handing vscode Uri's * unescape colon * authorities are lowercase
1 parent f81c92a commit 9e3fbcf

15 files changed

+38
-243
lines changed

src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs

+11-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6-
using System;
76
using System.Collections.Generic;
87
using Microsoft.PowerShell.EditorServices.Services;
98
using Microsoft.PowerShell.EditorServices.Services.Symbols;
109
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
1110
using Microsoft.PowerShell.EditorServices.Utility;
1211
using Newtonsoft.Json.Linq;
1312
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
13+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
1414

1515
namespace Microsoft.PowerShell.EditorServices.CodeLenses
1616
{
@@ -60,11 +60,14 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile
6060
{
6161
Name = "PowerShell.RunPesterTests",
6262
Title = $"Run {word}",
63-
Arguments = JArray.FromObject(new object[] {
63+
Arguments = JArray.FromObject(new object[]
64+
{
6465
scriptFile.DocumentUri,
6566
false /* No debug */,
6667
pesterSymbol.TestName,
67-
pesterSymbol.ScriptRegion?.StartLineNumber })
68+
pesterSymbol.ScriptRegion?.StartLineNumber
69+
},
70+
Serializer.Instance.JsonSerializer)
6871
}
6972
},
7073

@@ -79,11 +82,14 @@ private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile
7982
{
8083
Name = "PowerShell.RunPesterTests",
8184
Title = $"Debug {word}",
82-
Arguments = JArray.FromObject(new object[] {
85+
Arguments = JArray.FromObject(new object[]
86+
{
8387
scriptFile.DocumentUri,
8488
true /* No debug */,
8589
pesterSymbol.TestName,
86-
pesterSymbol.ScriptRegion?.StartLineNumber })
90+
pesterSymbol.ScriptRegion?.StartLineNumber
91+
},
92+
Serializer.Instance.JsonSerializer)
8793
}
8894
}
8995
};

src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
1212
using Microsoft.PowerShell.EditorServices.Utility;
1313
using Newtonsoft.Json.Linq;
14+
using OmniSharp.Extensions.LanguageServer.Protocol;
1415
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
16+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
1517

1618
namespace Microsoft.PowerShell.EditorServices.CodeLenses
1719
{
@@ -113,7 +115,7 @@ public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile)
113115

114116
acc.Add(new Location
115117
{
116-
Uri = PathUtils.ToUri(foundReference.FilePath),
118+
Uri = DocumentUri.FromFileSystemPath(foundReference.FilePath),
117119
Range = foundReference.ScriptRegion.ToRange()
118120
});
119121
}
@@ -133,7 +135,8 @@ public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile)
133135
scriptFile.DocumentUri,
134136
codeLens.Range.Start,
135137
referenceLocations
136-
})
138+
},
139+
Serializer.Instance.JsonSerializer)
137140
}
138141
};
139142
}

src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,8 @@ public SymbolReference(
107107
/// </summary>
108108
/// <param name="symbolType">The higher level type of the symbol</param>
109109
/// <param name="scriptExtent">The script extent of the symbol</param>
110-
/// <param name="filePath">The file path of the symbol</param>
111-
/// <param name="sourceLine">The line contents of the given symbol (defaults to empty string)</param>
112-
public SymbolReference(SymbolType symbolType, IScriptExtent scriptExtent, string filePath = "", string sourceLine = "")
113-
: this(symbolType, scriptExtent.Text, scriptExtent, filePath, sourceLine)
110+
public SymbolReference(SymbolType symbolType, IScriptExtent scriptExtent)
111+
: this(symbolType, scriptExtent.Text, scriptExtent, scriptExtent.File, "")
114112
{
115113
}
116114
}

src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun
133133
StartLineNumber = startLineNumber,
134134
EndLineNumber = startLineNumber,
135135
StartColumnNumber = startColumnNumber,
136-
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length
136+
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length,
137+
File = functionDefinitionAst.Extent.File
137138
};
138139

139140
if (symbolRef.SymbolType.Equals(SymbolType.Function) &&

src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolVisitor.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun
7474
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber,
7575
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber,
7676
StartColumnNumber = startColumnNumber,
77-
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length
77+
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length,
78+
File = functionDefinitionAst.Extent.File
7879
};
7980

8081
if (this.IsPositionInExtent(nameExtent))

src/PowerShellEditorServices/Services/Symbols/Vistors/FindSymbolsVisitor.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun
3636
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber,
3737
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber,
3838
StartColumnNumber = functionDefinitionAst.Extent.StartColumnNumber,
39-
EndColumnNumber = functionDefinitionAst.Extent.EndColumnNumber
39+
EndColumnNumber = functionDefinitionAst.Extent.EndColumnNumber,
40+
File = functionDefinitionAst.Extent.File
4041
};
4142

4243
SymbolType symbolType =

src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.PowerShell.EditorServices.Services.Symbols;
1212
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
1313
using Microsoft.PowerShell.EditorServices.Utility;
14+
using OmniSharp.Extensions.LanguageServer.Protocol;
1415
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
1516
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
1617
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
@@ -66,7 +67,7 @@ public async Task<LocationOrLocationLinks> Handle(DefinitionParams request, Canc
6667
new LocationOrLocationLink(
6768
new Location
6869
{
69-
Uri = PathUtils.ToUri(foundDefinition.FilePath),
70+
Uri = DocumentUri.FromFileSystemPath(foundDefinition.FilePath),
7071
Range = GetRangeFromScriptRegion(foundDefinition.ScriptRegion)
7172
}));
7273
}

src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Microsoft.PowerShell.EditorServices.Services.Symbols;
1717
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
1818
using Microsoft.PowerShell.EditorServices.Utility;
19+
using OmniSharp.Extensions.LanguageServer.Protocol;
1920
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
2021
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
2122
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
@@ -74,7 +75,7 @@ public Task<SymbolInformationOrDocumentSymbolContainer> Handle(DocumentSymbolPar
7475
Kind = GetSymbolKind(r.SymbolType),
7576
Location = new Location
7677
{
77-
Uri = PathUtils.ToUri(r.FilePath),
78+
Uri = DocumentUri.FromFileSystemPath(r.FilePath),
7879
Range = GetRangeFromScriptRegion(r.ScriptRegion)
7980
},
8081
Name = GetDecoratedSymbolName(r)

src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.PowerShell.EditorServices.Services.Symbols;
1212
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
1313
using Microsoft.PowerShell.EditorServices.Utility;
14+
using OmniSharp.Extensions.LanguageServer.Protocol;
1415
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
1516
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
1617
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
@@ -63,7 +64,7 @@ public Task<LocationContainer> Handle(ReferenceParams request, CancellationToken
6364
{
6465
locations.Add(new Location
6566
{
66-
Uri = PathUtils.ToUri(foundReference.FilePath),
67+
Uri = DocumentUri.FromFileSystemPath(foundReference.FilePath),
6768
Range = GetRangeFromScriptRegion(foundReference.ScriptRegion)
6869
});
6970
}

src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ public string DocumentUri
6060
{
6161
get
6262
{
63+
// TODO: Have this be a DocumentUri type and stop having it be computed every time.
6364
return this.ClientFilePath == null
6465
? string.Empty
65-
: WorkspaceService.ConvertPathToDocumentUri(this.ClientFilePath);
66+
: OmniSharp.Extensions.LanguageServer.Protocol.DocumentUri.FromFileSystemPath(ClientFilePath)?.ToString();
6667
}
6768
}
6869

src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
using Microsoft.PowerShell.EditorServices.Services;
1313
using Microsoft.PowerShell.EditorServices.Services.Symbols;
1414
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
15-
using Microsoft.PowerShell.EditorServices.Utility;
15+
using OmniSharp.Extensions.LanguageServer.Protocol;
1616
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
1717
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
1818
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
@@ -59,7 +59,7 @@ public Task<Container<SymbolInformation>> Handle(WorkspaceSymbolParams request,
5959

6060
var location = new Location
6161
{
62-
Uri = PathUtils.ToUri(foundOccurrence.FilePath),
62+
Uri = DocumentUri.FromFileSystemPath(foundOccurrence.FilePath),
6363
Range = GetRangeFromScriptRegion(foundOccurrence.ScriptRegion)
6464
};
6565

src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs

-147
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using System.IO;
1010
using System.Security;
1111
using System.Text;
12-
using System.Runtime.InteropServices;
1312
using Microsoft.Extensions.FileSystemGlobbing;
1413
using Microsoft.Extensions.Logging;
1514
using Microsoft.PowerShell.EditorServices.Utility;
@@ -462,17 +461,6 @@ private void RecursivelyFindReferences(
462461
}
463462
}
464463

465-
internal Uri ResolveFileUri(Uri fileUri)
466-
{
467-
if (fileUri.IsFile)
468-
{
469-
fileUri = WorkspaceService.UnescapeDriveColon(fileUri);
470-
}
471-
472-
this.logger.LogDebug("Resolved path: " + fileUri.OriginalString);
473-
return fileUri;
474-
}
475-
476464
internal static bool IsPathInMemory(string filePath)
477465
{
478466
bool isInMemory = false;
@@ -562,141 +550,6 @@ internal string ResolveRelativeScriptPath(string baseFilePath, string relativePa
562550
return combinedPath;
563551
}
564552

565-
private static Uri UnescapeDriveColon(Uri fileUri)
566-
{
567-
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
568-
{
569-
return fileUri;
570-
}
571-
572-
string driveSegment = fileUri.Segments[1];
573-
// Check here that we have something like "file:///C%3A/" as a prefix (caller must check the file:// part)
574-
if (!(char.IsLetter(driveSegment[0]) &&
575-
driveSegment[1] == '%' &&
576-
driveSegment[2] == '3' &&
577-
driveSegment[3] == 'A' &&
578-
driveSegment[4] == '/'))
579-
{
580-
return fileUri;
581-
}
582-
583-
// We lost "%3A" and gained ":", so length - 2
584-
var sb = new StringBuilder(fileUri.OriginalString.Length - 2);
585-
sb.Append("file:///");
586-
587-
// The drive letter.
588-
sb.Append(driveSegment[0]);
589-
sb.Append(":/");
590-
591-
// The rest of the URI after the colon.
592-
// Skip the first two segments which are / and the drive.
593-
for (int i = 2; i < fileUri.Segments.Length; i++)
594-
{
595-
sb.Append(fileUri.Segments[i]);
596-
}
597-
598-
return new Uri(sb.ToString());
599-
}
600-
601-
/// <summary>
602-
/// Converts a file system path into a DocumentUri required by Language Server Protocol.
603-
/// </summary>
604-
/// <remarks>
605-
/// When sending a document path to a LSP client, the path must be provided as a
606-
/// DocumentUri in order to features like the Problems window or peek definition
607-
/// to be able to open the specified file.
608-
/// </remarks>
609-
/// <param name="path">
610-
/// A file system path. Note: if the path is already a DocumentUri, it will be returned unmodified.
611-
/// </param>
612-
/// <returns>The file system path encoded as a DocumentUri.</returns>
613-
public static string ConvertPathToDocumentUri(string path)
614-
{
615-
const string fileUriPrefix = "file:";
616-
const string untitledUriPrefix = "untitled:";
617-
618-
// If path is already in document uri form, there is nothing to convert.
619-
if (path.StartsWith(untitledUriPrefix, StringComparison.Ordinal) ||
620-
path.StartsWith(fileUriPrefix, StringComparison.Ordinal))
621-
{
622-
return path;
623-
}
624-
625-
string escapedPath = Uri.EscapeDataString(path);
626-
627-
// Max capacity of the StringBuilder will be the current escapedPath length
628-
// plus extra chars for file:///.
629-
var docUriStrBld = new StringBuilder(escapedPath.Length + fileUriPrefix.Length + 3);
630-
docUriStrBld.Append(fileUriPrefix).Append("//");
631-
632-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
633-
{
634-
// VSCode file URIs on Windows need the drive letter to be lowercase. Search the
635-
// original path for colon since a char search (no string culture involved) is
636-
// faster than a string search. If found, then lowercase the associated drive letter.
637-
if (path.Contains(':'))
638-
{
639-
// A valid, drive-letter based path converted to URI form needs to be prefixed
640-
// with a / to indicate the path is an absolute path.
641-
docUriStrBld.Append("/");
642-
int prefixLen = docUriStrBld.Length;
643-
644-
docUriStrBld.Append(escapedPath);
645-
646-
// Uri.EscapeDataString goes a bit far, encoding \ chars. Also, VSCode wants / instead of \.
647-
docUriStrBld.Replace("%5C", "/");
648-
649-
// Find the first colon after the "file:///" prefix, skipping the first char after
650-
// the prefix since a Windows path cannot start with a colon. End the check at
651-
// less than docUriStrBld.Length - 2 since we need to look-ahead two characters.
652-
for (int i = prefixLen + 1; i < docUriStrBld.Length - 2; i++)
653-
{
654-
if ((docUriStrBld[i] == '%') && (docUriStrBld[i + 1] == '3') && (docUriStrBld[i + 2] == 'A'))
655-
{
656-
int driveLetterIndex = i - 1;
657-
char driveLetter = char.ToLowerInvariant(docUriStrBld[driveLetterIndex]);
658-
docUriStrBld.Replace(docUriStrBld[driveLetterIndex], driveLetter, driveLetterIndex, 1);
659-
break;
660-
}
661-
}
662-
}
663-
else
664-
{
665-
// This is a Windows path without a drive specifier, must be either a relative or UNC path.
666-
int prefixLen = docUriStrBld.Length;
667-
668-
docUriStrBld.Append(escapedPath);
669-
670-
// Uri.EscapeDataString goes a bit far, encoding \ chars. Also, VSCode wants / instead of \.
671-
docUriStrBld.Replace("%5C", "/");
672-
673-
// The proper URI form for a UNC path is file://server/share. In the case of a UNC
674-
// path, remove the path's leading // because the file:// prefix already provides it.
675-
if ((docUriStrBld.Length > prefixLen + 1) &&
676-
(docUriStrBld[prefixLen] == '/') &&
677-
(docUriStrBld[prefixLen + 1] == '/'))
678-
{
679-
docUriStrBld.Remove(prefixLen, 2);
680-
}
681-
}
682-
}
683-
else
684-
{
685-
// On non-Windows systems, append the escapedPath and undo the over-aggressive
686-
// escaping of / done by Uri.EscapeDataString.
687-
docUriStrBld.Append(escapedPath).Replace("%2F", "/");
688-
}
689-
690-
if (!VersionUtils.IsNetCore)
691-
{
692-
// ' is not encoded by Uri.EscapeDataString in Windows PowerShell 5.x.
693-
// This is apparently a difference between .NET Framework and .NET Core.
694-
docUriStrBld.Replace("'", "%27");
695-
}
696-
697-
return docUriStrBld.ToString();
698-
}
699-
700553
#endregion
701554
}
702555
}

0 commit comments

Comments
 (0)