Skip to content

Commit d85a019

Browse files
TylerLeonhardtrjmholt
authored andcommitted
New-EditorFile works on non-powershell untitled files (#774)
* New-EditorFile works on non-powershell untitled files * Have TryGetFile log exception * Create a new ScriptFile and have the language be in FileContext
1 parent 954e4db commit d85a019

File tree

7 files changed

+113
-58
lines changed

7 files changed

+113
-58
lines changed

src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public static readonly
3838

3939
public class ClientEditorContext
4040
{
41+
public string CurrentFileContent { get; set; }
42+
43+
public string CurrentFileLanguage { get; set; }
44+
4145
public string CurrentFilePath { get; set; }
4246

4347
public Position CursorPosition { get; set; }

src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

+7-24
Original file line numberDiff line numberDiff line change
@@ -494,31 +494,14 @@ protected async Task HandleSetBreakpointsRequest(
494494
{
495495
ScriptFile scriptFile = null;
496496

497-
// Fix for issue #195 - user can change name of file outside of VSCode in which case
498-
// VSCode sends breakpoint requests with the original filename that doesn't exist anymore.
499-
try
500-
{
501-
// When you set a breakpoint in the right pane of a Git diff window on a PS1 file,
502-
// the Source.Path comes through as Untitled-X.
503-
if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path))
504-
{
505-
scriptFile = _editorSession.Workspace.GetFile(setBreakpointsParams.Source.Path);
506-
}
507-
}
508-
catch (Exception e) when (
509-
e is FileNotFoundException ||
510-
e is DirectoryNotFoundException ||
511-
e is IOException ||
512-
e is NotSupportedException ||
513-
e is PathTooLongException ||
514-
e is SecurityException ||
515-
e is UnauthorizedAccessException)
497+
// When you set a breakpoint in the right pane of a Git diff window on a PS1 file,
498+
// the Source.Path comes through as Untitled-X. That's why we check for IsUntitledPath.
499+
if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path) &&
500+
!_editorSession.Workspace.TryGetFile(
501+
setBreakpointsParams.Source.Path,
502+
out scriptFile))
516503
{
517-
Logger.WriteException(
518-
$"Failed to set breakpoint on file: {setBreakpointsParams.Source.Path}",
519-
e);
520-
521-
string message = _noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set - " + e.Message;
504+
string message = _noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set.";
522505
var srcBreakpoints = setBreakpointsParams.Breakpoints
523506
.Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create(
524507
srcBkpt, setBreakpointsParams.Source.Path, message, verified: _noDebug));

src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs

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

6+
using Microsoft.PowerShell.EditorServices;
67
using Microsoft.PowerShell.EditorServices.Extensions;
78
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
89
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
@@ -89,18 +90,23 @@ public Task SetSelection(BufferRange selectionRange)
8990
public EditorContext ConvertClientEditorContext(
9091
ClientEditorContext clientContext)
9192
{
93+
ScriptFile scriptFile = this.editorSession.Workspace.CreateScriptFileFromFileBuffer(
94+
clientContext.CurrentFilePath,
95+
clientContext.CurrentFileContent);
96+
9297
return
9398
new EditorContext(
9499
this,
95-
this.editorSession.Workspace.GetFile(clientContext.CurrentFilePath),
100+
scriptFile,
96101
new BufferPosition(
97102
clientContext.CursorPosition.Line + 1,
98103
clientContext.CursorPosition.Character + 1),
99104
new BufferRange(
100105
clientContext.SelectionRange.Start.Line + 1,
101106
clientContext.SelectionRange.Start.Character + 1,
102107
clientContext.SelectionRange.End.Line + 1,
103-
clientContext.SelectionRange.End.Character + 1));
108+
clientContext.SelectionRange.End.Character + 1),
109+
clientContext.CurrentFileLanguage);
104110
}
105111

106112
public Task NewFile()

src/PowerShellEditorServices/Extensions/EditorContext.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,16 @@ public class EditorContext
4848
/// <param name="currentFile">The ScriptFile that is in the active editor buffer.</param>
4949
/// <param name="cursorPosition">The position of the user's cursor in the active editor buffer.</param>
5050
/// <param name="selectedRange">The range of the user's selection in the active editor buffer.</param>
51+
/// <param name="language">Determines the language of the file.false If it is not specified, then it defaults to "Unknown"</param>
5152
public EditorContext(
5253
IEditorOperations editorOperations,
5354
ScriptFile currentFile,
5455
BufferPosition cursorPosition,
55-
BufferRange selectedRange)
56+
BufferRange selectedRange,
57+
string language = "Unknown")
5658
{
5759
this.editorOperations = editorOperations;
58-
this.CurrentFile = new FileContext(currentFile, this, editorOperations);
60+
this.CurrentFile = new FileContext(currentFile, this, editorOperations, language);
5961
this.SelectedRange = selectedRange;
6062
this.CursorPosition = new FilePosition(currentFile, cursorPosition);
6163
}

src/PowerShellEditorServices/Extensions/FileContext.cs

+32-19
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,33 @@ public class FileContext
2626
#region Properties
2727

2828
/// <summary>
29-
/// Gets the filesystem path of the file.
29+
/// Gets the parsed abstract syntax tree for the file.
3030
/// </summary>
31-
public string Path
31+
public Ast Ast
3232
{
33-
get { return this.scriptFile.FilePath; }
33+
get { return this.scriptFile.ScriptAst; }
3434
}
3535

3636
/// <summary>
37-
/// Gets the workspace-relative path of the file.
37+
/// Gets a BufferRange which represents the entire content
38+
/// range of the file.
3839
/// </summary>
39-
public string WorkspacePath
40+
public BufferRange FileRange
4041
{
41-
get
42-
{
43-
return
44-
this.editorOperations.GetWorkspaceRelativePath(
45-
this.scriptFile.FilePath);
46-
}
42+
get { return this.scriptFile.FileRange; }
4743
}
4844

4945
/// <summary>
50-
/// Gets the parsed abstract syntax tree for the file.
46+
/// Gets the language of the file.
5147
/// </summary>
52-
public Ast Ast
48+
public string Language { get; private set; }
49+
50+
/// <summary>
51+
/// Gets the filesystem path of the file.
52+
/// </summary>
53+
public string Path
5354
{
54-
get { return this.scriptFile.ScriptAst; }
55+
get { return this.scriptFile.FilePath; }
5556
}
5657

5758
/// <summary>
@@ -63,12 +64,16 @@ public Token[] Tokens
6364
}
6465

6566
/// <summary>
66-
/// Gets a BufferRange which represents the entire content
67-
/// range of the file.
67+
/// Gets the workspace-relative path of the file.
6868
/// </summary>
69-
public BufferRange FileRange
69+
public string WorkspacePath
7070
{
71-
get { return this.scriptFile.FileRange; }
71+
get
72+
{
73+
return
74+
this.editorOperations.GetWorkspaceRelativePath(
75+
this.scriptFile.FilePath);
76+
}
7277
}
7378

7479
#endregion
@@ -81,14 +86,22 @@ public BufferRange FileRange
8186
/// <param name="scriptFile">The ScriptFile to which this file refers.</param>
8287
/// <param name="editorContext">The EditorContext to which this file relates.</param>
8388
/// <param name="editorOperations">An IEditorOperations implementation which performs operations in the editor.</param>
89+
/// <param name="language">Determines the language of the file.false If it is not specified, then it defaults to "Unknown"</param>
8490
public FileContext(
8591
ScriptFile scriptFile,
8692
EditorContext editorContext,
87-
IEditorOperations editorOperations)
93+
IEditorOperations editorOperations,
94+
string language = "Unknown")
8895
{
96+
if (string.IsNullOrWhiteSpace(language))
97+
{
98+
language = "Unknown";
99+
}
100+
89101
this.scriptFile = scriptFile;
90102
this.editorContext = editorContext;
91103
this.editorOperations = editorOperations;
104+
this.Language = language;
92105
}
93106

94107
#endregion

src/PowerShellEditorServices/Language/LanguageService.cs

+1-11
Original file line numberDiff line numberDiff line change
@@ -338,17 +338,7 @@ public async Task<FindReferencesResult> FindReferencesOfSymbol(
338338
{
339339
if (!fileMap.Contains(file))
340340
{
341-
ScriptFile scriptFile;
342-
try
343-
{
344-
scriptFile = workspace.GetFile(file);
345-
}
346-
catch (Exception e) when (e is IOException
347-
|| e is SecurityException
348-
|| e is FileNotFoundException
349-
|| e is DirectoryNotFoundException
350-
|| e is PathTooLongException
351-
|| e is UnauthorizedAccessException)
341+
if (!workspace.TryGetFile(file, out ScriptFile scriptFile))
352342
{
353343
// If we can't access the file for some reason, just ignore it
354344
continue;

src/PowerShellEditorServices/Workspace/Workspace.cs

+57
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,35 @@ public Workspace(Version powerShellVersion, ILogger logger)
5454

5555
#region Public Methods
5656

57+
/// <summary>
58+
/// Creates a new ScriptFile instance which is identified by the given file
59+
/// path and initially contains the given buffer contents.
60+
/// </summary>
61+
/// <param name="filePath">The file path for which a buffer will be retrieved.</param>
62+
/// <param name="initialBuffer">The initial buffer contents if there is not an existing ScriptFile for this path.</param>
63+
/// <returns>A ScriptFile instance for the specified path.</returns>
64+
public ScriptFile CreateScriptFileFromFileBuffer(string filePath, string initialBuffer)
65+
{
66+
Validate.IsNotNullOrEmptyString("filePath", filePath);
67+
68+
// Resolve the full file path
69+
string resolvedFilePath = this.ResolveFilePath(filePath);
70+
string keyName = resolvedFilePath.ToLower();
71+
72+
ScriptFile scriptFile =
73+
new ScriptFile(
74+
resolvedFilePath,
75+
filePath,
76+
initialBuffer,
77+
this.powerShellVersion);
78+
79+
this.workspaceFiles[keyName] = scriptFile;
80+
81+
this.logger.Write(LogLevel.Verbose, "Opened file as in-memory buffer: " + resolvedFilePath);
82+
83+
return scriptFile;
84+
}
85+
5786
/// <summary>
5887
/// Gets an open file in the workspace. If the file isn't open but
5988
/// exists on the filesystem, load and return it.
@@ -98,6 +127,34 @@ public ScriptFile GetFile(string filePath)
98127
return scriptFile;
99128
}
100129

130+
/// <summary>
131+
/// Tries to get an open file in the workspace. Returns true if it succeeds, false otherwise.
132+
/// </summary>
133+
/// <param name="filePath">The file path at which the script resides.</param>
134+
/// <param name="scriptFile">The out parameter that will contain the ScriptFile object.</param>
135+
public bool TryGetFile(string filePath, out ScriptFile scriptFile)
136+
{
137+
try
138+
{
139+
scriptFile = GetFile(filePath);
140+
return true;
141+
}
142+
catch (Exception e) when (
143+
e is IOException ||
144+
e is SecurityException ||
145+
e is FileNotFoundException ||
146+
e is DirectoryNotFoundException ||
147+
e is PathTooLongException ||
148+
e is UnauthorizedAccessException)
149+
{
150+
this.logger.WriteException(
151+
$"Failed to set breakpoint on file: {filePath}",
152+
e);
153+
scriptFile = null;
154+
return false;
155+
}
156+
}
157+
101158
/// <summary>
102159
/// Gets a new ScriptFile instance which is identified by the given file path.
103160
/// </summary>

0 commit comments

Comments
 (0)