Skip to content

Commit c4d31cf

Browse files
committed
Fix #44: Enable lang features for in-memory files
This change enables language features for in-memory files such as untitled files and diff comparison files which show up in VS Code's Git diff viewer. When a file is sent in with an 'inmemory' or 'untitled' URI, it gets treated like a normal file.
1 parent dccf461 commit c4d31cf

File tree

3 files changed

+68
-15
lines changed

3 files changed

+68
-15
lines changed

src/PowerShellEditorServices.Host/LanguageServer.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ protected async Task HandleInitializeRequest(
9696
EditorSession editorSession,
9797
RequestContext<InitializeResult, InitializeError> requestContext)
9898
{
99+
// Grab the workspace path from the parameters
100+
editorSession.Workspace.WorkspacePath = initializeParams.RootPath;
101+
99102
await requestContext.SendResult(
100103
new InitializeResult
101104
{

src/PowerShellEditorServices/Workspace/ScriptFile.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ public string Id
5353
/// </summary>
5454
internal bool IsAnalysisEnabled { get; set; }
5555

56+
/// <summary>
57+
/// Gets a boolean that determines whether this file is
58+
/// in-memory or not (either unsaved or non-file content).
59+
/// </summary>
60+
public bool IsInMemory { get; private set; }
61+
5662
/// <summary>
5763
/// Gets a string containing the full contents of the file.
5864
/// </summary>
@@ -125,6 +131,7 @@ public ScriptFile(string filePath, string clientFilePath, TextReader textReader)
125131
this.FilePath = filePath;
126132
this.ClientFilePath = clientFilePath;
127133
this.IsAnalysisEnabled = true;
134+
this.IsInMemory = Workspace.IsPathInMemory(filePath);
128135

129136
this.SetFileContents(textReader.ReadToEnd());
130137
}

src/PowerShellEditorServices/Workspace/Workspace.cs

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ public class Workspace
2424

2525
#endregion
2626

27+
#region Properties
28+
29+
/// <summary>
30+
/// Gets or sets the root path of the workspace.
31+
/// </summary>
32+
public string WorkspacePath { get; set; }
33+
34+
#endregion
35+
2736
#region Public Methods
2837

2938
/// <summary>
@@ -155,15 +164,20 @@ private void RecursivelyFindReferences(
155164
ScriptFile scriptFile,
156165
Dictionary<string, ScriptFile> referencedScriptFiles)
157166
{
167+
// Get the base path of the current script for use in resolving relative paths
168+
string baseFilePath =
169+
GetBaseFilePath(
170+
scriptFile.FilePath);
171+
158172
ScriptFile referencedFile;
159173
foreach (string referencedFileName in scriptFile.ReferencedFiles)
160174
{
161175
string resolvedScriptPath =
162176
this.ResolveRelativeScriptPath(
163-
scriptFile.FilePath,
177+
baseFilePath,
164178
referencedFileName);
165179

166-
// make sure file exists before trying to get the file
180+
// Make sure file exists before trying to get the file
167181
if (File.Exists(resolvedScriptPath))
168182
{
169183
// Get the referenced file if it's not already in referencedScriptFiles
@@ -183,33 +197,62 @@ private void RecursivelyFindReferences(
183197

184198
private string ResolveFilePath(string filePath)
185199
{
186-
if (filePath.StartsWith(@"file://"))
200+
if (!IsPathInMemory(filePath))
187201
{
188-
// Client sent the path in URI format, extract the local path and trim
189-
// any extraneous slashes
190-
Uri fileUri = new Uri(filePath);
191-
filePath = fileUri.LocalPath.TrimStart('/');
192-
}
202+
if (filePath.StartsWith(@"file://"))
203+
{
204+
// Client sent the path in URI format, extract the local path and trim
205+
// any extraneous slashes
206+
Uri fileUri = new Uri(filePath);
207+
filePath = fileUri.LocalPath.TrimStart('/');
208+
}
193209

194-
// Some clients send paths with UNIX-style slashes, replace those if necessary
195-
filePath = filePath.Replace('/', '\\');
210+
// Some clients send paths with UNIX-style slashes, replace those if necessary
211+
filePath = filePath.Replace('/', '\\');
212+
213+
// Get the absolute file path
214+
filePath = Path.GetFullPath(filePath);
215+
}
196216

197217
Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);
198218

199-
return Path.GetFullPath(filePath);
219+
return filePath;
200220
}
201221

202-
private string ResolveRelativeScriptPath(string originalScriptPath, string relativePath)
222+
internal static bool IsPathInMemory(string filePath)
203223
{
204-
if (!Path.IsPathRooted(originalScriptPath))
224+
// When viewing PowerShell files in the Git diff viewer, VS Code
225+
// sends the contents of the file at HEAD with a URI that starts
226+
// with 'inmemory'. Untitled files which have been marked of
227+
// type PowerShell have a path starting with 'untitled'.
228+
return
229+
filePath.StartsWith("inmemory") ||
230+
filePath.StartsWith("untitled");
231+
}
232+
233+
private string GetBaseFilePath(string filePath)
234+
{
235+
if (IsPathInMemory(filePath))
236+
{
237+
// If the file is in memory, use the workspace path
238+
return this.WorkspacePath;
239+
}
240+
241+
if (!Path.IsPathRooted(filePath))
205242
{
206243
// TODO: Assert instead?
207244
throw new InvalidOperationException(
208245
string.Format(
209246
"Must provide a full path for originalScriptPath: {0}",
210-
originalScriptPath));
247+
filePath));
211248
}
212249

250+
// Get the directory of the file path
251+
return Path.GetDirectoryName(filePath);
252+
}
253+
254+
private string ResolveRelativeScriptPath(string baseFilePath, string relativePath)
255+
{
213256
if (Path.IsPathRooted(relativePath))
214257
{
215258
return relativePath;
@@ -220,7 +263,7 @@ private string ResolveRelativeScriptPath(string originalScriptPath, string relat
220263
string combinedPath =
221264
Path.GetFullPath(
222265
Path.Combine(
223-
Path.GetDirectoryName(originalScriptPath),
266+
baseFilePath,
224267
relativePath));
225268

226269
return combinedPath;

0 commit comments

Comments
 (0)