diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs index 51ddd7f1a..edc0ac74b 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs @@ -150,20 +150,24 @@ public string[] ReferencedFiles /// Creates a new ScriptFile instance by reading file contents from /// the given TextReader. /// - /// The path at which the script file resides. - /// The path which the client uses to identify the file. + /// The System.Uri of the file. /// The TextReader to use for reading the file's contents. /// The version of PowerShell for which the script is being parsed. public ScriptFile( - string filePath, - string clientFilePath, + Uri fileUri, TextReader textReader, Version powerShellVersion) { - this.FilePath = filePath; - this.ClientFilePath = clientFilePath; + // For non-files, use their URI representation instead + // so that other operations know it's untitled/in-memory + // and don't think that it's a relative path + // on the file system. + this.FilePath = fileUri.IsFile + ? fileUri.LocalPath + : fileUri.OriginalString; + this.ClientFilePath = fileUri.OriginalString; this.IsAnalysisEnabled = true; - this.IsInMemory = WorkspaceService.IsPathInMemory(filePath); + this.IsInMemory = !fileUri.IsFile; this.powerShellVersion = powerShellVersion; // SetFileContents() calls ParseFileContents() which initializes the rest of the properties. @@ -173,41 +177,20 @@ public ScriptFile( /// /// Creates a new ScriptFile instance with the specified file contents. /// - /// The path at which the script file resides. - /// The path which the client uses to identify the file. + /// The System.Uri of the file. /// The initial contents of the script file. /// The version of PowerShell for which the script is being parsed. public ScriptFile( - string filePath, - string clientFilePath, + Uri fileUri, string initialBuffer, Version powerShellVersion) : this( - filePath, - clientFilePath, + fileUri, new StringReader(initialBuffer), powerShellVersion) { } - /// - /// Creates a new ScriptFile instance with the specified filepath. - /// - /// The path at which the script file resides. - /// The path which the client uses to identify the file. - /// The version of PowerShell for which the script is being parsed. - public ScriptFile( - string filePath, - string clientFilePath, - Version powerShellVersion) - : this( - filePath, - clientFilePath, - File.ReadAllText(filePath), - powerShellVersion) - { - } - #endregion #region Public Methods diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs index dba1362c3..5da819232 100644 --- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs +++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs @@ -142,8 +142,7 @@ public ScriptFile GetFile(Uri fileUri) { scriptFile = new ScriptFile( - resolvedFileUri.LocalPath, - resolvedFileUri.OriginalString, + resolvedFileUri, streamReader, this.powerShellVersion); @@ -249,8 +248,7 @@ public ScriptFile GetFileBuffer(Uri fileUri, string initialBuffer) { scriptFile = new ScriptFile( - resolvedFileUri.LocalPath, - resolvedFileUri.OriginalString, + resolvedFileUri, initialBuffer, this.powerShellVersion); @@ -399,9 +397,9 @@ private void RecursivelyFindReferences( Dictionary referencedScriptFiles) { // Get the base path of the current script for use in resolving relative paths - string baseFilePath = - GetBaseFilePath( - scriptFile.FilePath); + string baseFilePath = scriptFile.IsInMemory + ? WorkspacePath + : Path.GetDirectoryName(scriptFile.FilePath); foreach (string referencedFileName in scriptFile.ReferencedFiles) { @@ -437,31 +435,6 @@ private void RecursivelyFindReferences( } } - internal string ResolveFilePath(string filePath) - { - if (!IsPathInMemory(filePath)) - { - if (filePath.StartsWith(@"file://")) - { - filePath = WorkspaceService.UnescapeDriveColon(filePath); - // Client sent the path in URI format, extract the local path - filePath = new Uri(filePath).LocalPath; - } - - // Clients could specify paths with escaped space, [ and ] characters which .NET APIs - // will not handle. These paths will get appropriately escaped just before being passed - // into the PowerShell engine. - //filePath = PowerShellContext.UnescapeWildcardEscapedPath(filePath); - - // Get the absolute file path - filePath = Path.GetFullPath(filePath); - } - - this.logger.LogDebug("Resolved path: " + filePath); - - return filePath; - } - internal Uri ResolveFileUri(Uri fileUri) { if (fileUri.IsFile) @@ -509,27 +482,6 @@ internal static bool IsPathInMemory(string filePath) return isInMemory; } - private string GetBaseFilePath(string filePath) - { - if (IsPathInMemory(filePath)) - { - // If the file is in memory, use the workspace path - return this.WorkspacePath; - } - - if (!Path.IsPathRooted(filePath)) - { - // TODO: Assert instead? - throw new InvalidOperationException( - string.Format( - "Must provide a full path for originalScriptPath: {0}", - filePath)); - } - - // Get the directory of the file path - return Path.GetDirectoryName(filePath); - } - internal string ResolveRelativeScriptPath(string baseFilePath, string relativePath) { string combinedPath = null; @@ -578,39 +530,6 @@ internal string ResolveRelativeScriptPath(string baseFilePath, string relativePa return combinedPath; } - /// - /// Takes a file-scheme URI with an escaped colon after the drive letter and unescapes only the colon. - /// VSCode sends escaped colons after drive letters, but System.Uri expects unescaped. - /// - /// The fully-escaped file-scheme URI string. - /// A file-scheme URI string with the drive colon unescaped. - private static string UnescapeDriveColon(string fileUri) - { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return fileUri; - } - - // Check here that we have something like "file:///C%3A/" as a prefix (caller must check the file:// part) - if (!(fileUri[7] == '/' && - char.IsLetter(fileUri[8]) && - fileUri[9] == '%' && - fileUri[10] == '3' && - fileUri[11] == 'A' && - fileUri[12] == '/')) - { - return fileUri; - } - - var sb = new StringBuilder(fileUri.Length - 2); // We lost "%3A" and gained ":", so length - 2 - sb.Append("file:///"); - sb.Append(fileUri[8]); // The drive letter - sb.Append(':'); - sb.Append(fileUri.Substring(12)); // The rest of the URI after the colon - - return sb.ToString(); - } - private static Uri UnescapeDriveColon(Uri fileUri) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))