diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs
index 2637ec4cb..a7c385bc6 100644
--- a/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs
+++ b/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs
@@ -38,6 +38,10 @@ public static readonly
public class ClientEditorContext
{
+ public string CurrentFileContent { get; set; }
+
+ public string CurrentFileLanguage { get; set; }
+
public string CurrentFilePath { get; set; }
public Position CursorPosition { get; set; }
diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
index 7d1e7b550..f35e9998e 100644
--- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
+++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs
@@ -494,31 +494,14 @@ protected async Task HandleSetBreakpointsRequest(
{
ScriptFile scriptFile = null;
- // Fix for issue #195 - user can change name of file outside of VSCode in which case
- // VSCode sends breakpoint requests with the original filename that doesn't exist anymore.
- try
- {
- // When you set a breakpoint in the right pane of a Git diff window on a PS1 file,
- // the Source.Path comes through as Untitled-X.
- if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path))
- {
- scriptFile = _editorSession.Workspace.GetFile(setBreakpointsParams.Source.Path);
- }
- }
- catch (Exception e) when (
- e is FileNotFoundException ||
- e is DirectoryNotFoundException ||
- e is IOException ||
- e is NotSupportedException ||
- e is PathTooLongException ||
- e is SecurityException ||
- e is UnauthorizedAccessException)
+ // When you set a breakpoint in the right pane of a Git diff window on a PS1 file,
+ // the Source.Path comes through as Untitled-X. That's why we check for IsUntitledPath.
+ if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path) &&
+ !_editorSession.Workspace.TryGetFile(
+ setBreakpointsParams.Source.Path,
+ out scriptFile))
{
- Logger.WriteException(
- $"Failed to set breakpoint on file: {setBreakpointsParams.Source.Path}",
- e);
-
- string message = _noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set - " + e.Message;
+ string message = _noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set.";
var srcBreakpoints = setBreakpointsParams.Breakpoints
.Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create(
srcBkpt, setBreakpointsParams.Source.Path, message, verified: _noDebug));
diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs
index 84a561b0a..8639f5ee3 100644
--- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs
+++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs
@@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+using Microsoft.PowerShell.EditorServices;
using Microsoft.PowerShell.EditorServices.Extensions;
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
@@ -89,10 +90,14 @@ public Task SetSelection(BufferRange selectionRange)
public EditorContext ConvertClientEditorContext(
ClientEditorContext clientContext)
{
+ ScriptFile scriptFile = this.editorSession.Workspace.CreateScriptFileFromFileBuffer(
+ clientContext.CurrentFilePath,
+ clientContext.CurrentFileContent);
+
return
new EditorContext(
this,
- this.editorSession.Workspace.GetFile(clientContext.CurrentFilePath),
+ scriptFile,
new BufferPosition(
clientContext.CursorPosition.Line + 1,
clientContext.CursorPosition.Character + 1),
@@ -100,7 +105,8 @@ public EditorContext ConvertClientEditorContext(
clientContext.SelectionRange.Start.Line + 1,
clientContext.SelectionRange.Start.Character + 1,
clientContext.SelectionRange.End.Line + 1,
- clientContext.SelectionRange.End.Character + 1));
+ clientContext.SelectionRange.End.Character + 1),
+ clientContext.CurrentFileLanguage);
}
public Task NewFile()
diff --git a/src/PowerShellEditorServices/Extensions/EditorContext.cs b/src/PowerShellEditorServices/Extensions/EditorContext.cs
index cfccc516e..c29c60fcc 100644
--- a/src/PowerShellEditorServices/Extensions/EditorContext.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorContext.cs
@@ -48,14 +48,16 @@ public class EditorContext
/// The ScriptFile that is in the active editor buffer.
/// The position of the user's cursor in the active editor buffer.
/// The range of the user's selection in the active editor buffer.
+ /// Determines the language of the file.false If it is not specified, then it defaults to "Unknown"
public EditorContext(
IEditorOperations editorOperations,
ScriptFile currentFile,
BufferPosition cursorPosition,
- BufferRange selectedRange)
+ BufferRange selectedRange,
+ string language = "Unknown")
{
this.editorOperations = editorOperations;
- this.CurrentFile = new FileContext(currentFile, this, editorOperations);
+ this.CurrentFile = new FileContext(currentFile, this, editorOperations, language);
this.SelectedRange = selectedRange;
this.CursorPosition = new FilePosition(currentFile, cursorPosition);
}
diff --git a/src/PowerShellEditorServices/Extensions/FileContext.cs b/src/PowerShellEditorServices/Extensions/FileContext.cs
index 35b7e18fd..1b563dcb2 100644
--- a/src/PowerShellEditorServices/Extensions/FileContext.cs
+++ b/src/PowerShellEditorServices/Extensions/FileContext.cs
@@ -26,32 +26,33 @@ public class FileContext
#region Properties
///
- /// Gets the filesystem path of the file.
+ /// Gets the parsed abstract syntax tree for the file.
///
- public string Path
+ public Ast Ast
{
- get { return this.scriptFile.FilePath; }
+ get { return this.scriptFile.ScriptAst; }
}
///
- /// Gets the workspace-relative path of the file.
+ /// Gets a BufferRange which represents the entire content
+ /// range of the file.
///
- public string WorkspacePath
+ public BufferRange FileRange
{
- get
- {
- return
- this.editorOperations.GetWorkspaceRelativePath(
- this.scriptFile.FilePath);
- }
+ get { return this.scriptFile.FileRange; }
}
///
- /// Gets the parsed abstract syntax tree for the file.
+ /// Gets the language of the file.
///
- public Ast Ast
+ public string Language { get; private set; }
+
+ ///
+ /// Gets the filesystem path of the file.
+ ///
+ public string Path
{
- get { return this.scriptFile.ScriptAst; }
+ get { return this.scriptFile.FilePath; }
}
///
@@ -63,12 +64,16 @@ public Token[] Tokens
}
///
- /// Gets a BufferRange which represents the entire content
- /// range of the file.
+ /// Gets the workspace-relative path of the file.
///
- public BufferRange FileRange
+ public string WorkspacePath
{
- get { return this.scriptFile.FileRange; }
+ get
+ {
+ return
+ this.editorOperations.GetWorkspaceRelativePath(
+ this.scriptFile.FilePath);
+ }
}
#endregion
@@ -81,14 +86,22 @@ public BufferRange FileRange
/// The ScriptFile to which this file refers.
/// The EditorContext to which this file relates.
/// An IEditorOperations implementation which performs operations in the editor.
+ /// Determines the language of the file.false If it is not specified, then it defaults to "Unknown"
public FileContext(
ScriptFile scriptFile,
EditorContext editorContext,
- IEditorOperations editorOperations)
+ IEditorOperations editorOperations,
+ string language = "Unknown")
{
+ if (string.IsNullOrWhiteSpace(language))
+ {
+ language = "Unknown";
+ }
+
this.scriptFile = scriptFile;
this.editorContext = editorContext;
this.editorOperations = editorOperations;
+ this.Language = language;
}
#endregion
diff --git a/src/PowerShellEditorServices/Language/LanguageService.cs b/src/PowerShellEditorServices/Language/LanguageService.cs
index e30c00b8a..383c5f1da 100644
--- a/src/PowerShellEditorServices/Language/LanguageService.cs
+++ b/src/PowerShellEditorServices/Language/LanguageService.cs
@@ -342,17 +342,7 @@ public async Task FindReferencesOfSymbol(
{
if (!fileMap.Contains(file))
{
- ScriptFile scriptFile;
- try
- {
- scriptFile = workspace.GetFile(file);
- }
- catch (Exception e) when (e is IOException
- || e is SecurityException
- || e is FileNotFoundException
- || e is DirectoryNotFoundException
- || e is PathTooLongException
- || e is UnauthorizedAccessException)
+ if (!workspace.TryGetFile(file, out ScriptFile scriptFile))
{
// If we can't access the file for some reason, just ignore it
continue;
diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs
index 12bfae3a4..25b02031d 100644
--- a/src/PowerShellEditorServices/Workspace/Workspace.cs
+++ b/src/PowerShellEditorServices/Workspace/Workspace.cs
@@ -57,6 +57,35 @@ public Workspace(Version powerShellVersion, ILogger logger)
#region Public Methods
+ ///
+ /// Creates a new ScriptFile instance which is identified by the given file
+ /// path and initially contains the given buffer contents.
+ ///
+ /// The file path for which a buffer will be retrieved.
+ /// The initial buffer contents if there is not an existing ScriptFile for this path.
+ /// A ScriptFile instance for the specified path.
+ public ScriptFile CreateScriptFileFromFileBuffer(string filePath, string initialBuffer)
+ {
+ Validate.IsNotNullOrEmptyString("filePath", filePath);
+
+ // Resolve the full file path
+ string resolvedFilePath = this.ResolveFilePath(filePath);
+ string keyName = resolvedFilePath.ToLower();
+
+ ScriptFile scriptFile =
+ new ScriptFile(
+ resolvedFilePath,
+ filePath,
+ initialBuffer,
+ this.powerShellVersion);
+
+ this.workspaceFiles[keyName] = scriptFile;
+
+ this.logger.Write(LogLevel.Verbose, "Opened file as in-memory buffer: " + resolvedFilePath);
+
+ return scriptFile;
+ }
+
///
/// Gets an open file in the workspace. If the file isn't open but
/// exists on the filesystem, load and return it.
@@ -101,6 +130,34 @@ public ScriptFile GetFile(string filePath)
return scriptFile;
}
+ ///
+ /// Tries to get an open file in the workspace. Returns true if it succeeds, false otherwise.
+ ///
+ /// The file path at which the script resides.
+ /// The out parameter that will contain the ScriptFile object.
+ public bool TryGetFile(string filePath, out ScriptFile scriptFile)
+ {
+ try
+ {
+ scriptFile = GetFile(filePath);
+ return true;
+ }
+ catch (Exception e) when (
+ e is IOException ||
+ e is SecurityException ||
+ e is FileNotFoundException ||
+ e is DirectoryNotFoundException ||
+ e is PathTooLongException ||
+ e is UnauthorizedAccessException)
+ {
+ this.logger.WriteException(
+ $"Failed to set breakpoint on file: {filePath}",
+ e);
+ scriptFile = null;
+ return false;
+ }
+ }
+
///
/// Gets a new ScriptFile instance which is identified by the given file path.
///