From 750f17d8aff7ac6e6dda883a91bcb5902689cb21 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Sun, 14 Oct 2018 08:17:57 +0700 Subject: [PATCH 1/7] New-EditorFile works on non-powershell untitled files --- .../LanguageServer/EditorCommands.cs | 2 ++ .../Server/LanguageServerEditorOperations.cs | 10 +++++++++- .../Workspace/Workspace.cs | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs index 2637ec4cb..2265de1e4 100644 --- a/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs @@ -38,6 +38,8 @@ public static readonly public class ClientEditorContext { + public string CurrentFileContent { get; set; } + public string CurrentFilePath { get; set; } public Position CursorPosition { get; set; } diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs index 84a561b0a..94b63e5cb 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,17 @@ public Task SetSelection(BufferRange selectionRange) public EditorContext ConvertClientEditorContext( ClientEditorContext clientContext) { + + ScriptFile scriptFile = null; + if (!this.editorSession.Workspace.TryGetFile(clientContext.CurrentFilePath, out scriptFile)) + { + scriptFile = this.editorSession.Workspace.GetFileBuffer(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), diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 12bfae3a4..eef8c12ba 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -101,6 +101,25 @@ public ScriptFile GetFile(string filePath) return scriptFile; } + /// + /// Tries to get an open file in the workspace. Returns true or false if it succeeds. + /// + /// 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 (FileNotFoundException) + { + scriptFile = null; + return false; + } + } + /// /// Gets a new ScriptFile instance which is identified by the given file path. /// From 5807f082da071706df4bfd74b46efcda17f40386 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Tue, 16 Oct 2018 21:31:45 +0700 Subject: [PATCH 2/7] address robs feedback --- .../Server/DebugAdapter.cs | 30 ++++++------------- .../Language/LanguageService.cs | 12 +------- .../Workspace/Workspace.cs | 21 ++++++++++++- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs index 7d1e7b550..534d0469e 100644 --- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs +++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs @@ -494,31 +494,19 @@ 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, + out Exception exception)) { Logger.WriteException( $"Failed to set breakpoint on file: {setBreakpointsParams.Source.Path}", - e); + exception); - 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 - " + exception.Message; var srcBreakpoints = setBreakpointsParams.Breakpoints .Select(srcBkpt => Protocol.DebugAdapter.Breakpoint.Create( srcBkpt, setBreakpointsParams.Source.Path, message, verified: _noDebug)); 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 eef8c12ba..70a119c4d 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -107,15 +107,34 @@ public ScriptFile GetFile(string filePath) /// 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) + { + return TryGetFile(filePath, out scriptFile, out Exception e); + } + + /// + /// Tries to get an open file in the workspace. Returns true or false if it succeeds. + /// + /// The file path at which the script resides. + /// The out parameter that will contain the ScriptFile object. + /// The out parameter that will contain the underlying exception. + public bool TryGetFile(string filePath, out ScriptFile scriptFile, out Exception exception) { try { scriptFile = GetFile(filePath); + exception = null; return true; } - catch (FileNotFoundException) + catch (Exception e) when ( + e is IOException || + e is SecurityException || + e is FileNotFoundException || + e is DirectoryNotFoundException || + e is PathTooLongException || + e is UnauthorizedAccessException) { scriptFile = null; + exception = e; return false; } } From fafcbd282977d1ca4b5b6c2bdadfd55b5d9c0a9a Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Wed, 17 Oct 2018 07:36:03 +0700 Subject: [PATCH 3/7] have TryGetFile log exception --- .../Server/DebugAdapter.cs | 9 ++------- .../Workspace/Workspace.cs | 16 +++------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs index 534d0469e..f35e9998e 100644 --- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs +++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs @@ -499,14 +499,9 @@ protected async Task HandleSetBreakpointsRequest( if (!ScriptFile.IsUntitledPath(setBreakpointsParams.Source.Path) && !_editorSession.Workspace.TryGetFile( setBreakpointsParams.Source.Path, - out scriptFile, - out Exception exception)) + out scriptFile)) { - Logger.WriteException( - $"Failed to set breakpoint on file: {setBreakpointsParams.Source.Path}", - exception); - - string message = _noDebug ? string.Empty : "Source file could not be accessed, breakpoint not set - " + exception.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/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 70a119c4d..900f977aa 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -107,22 +107,10 @@ public ScriptFile GetFile(string filePath) /// 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) - { - return TryGetFile(filePath, out scriptFile, out Exception e); - } - - /// - /// Tries to get an open file in the workspace. Returns true or false if it succeeds. - /// - /// The file path at which the script resides. - /// The out parameter that will contain the ScriptFile object. - /// The out parameter that will contain the underlying exception. - public bool TryGetFile(string filePath, out ScriptFile scriptFile, out Exception exception) { try { scriptFile = GetFile(filePath); - exception = null; return true; } catch (Exception e) when ( @@ -133,8 +121,10 @@ e is DirectoryNotFoundException || e is PathTooLongException || e is UnauthorizedAccessException) { + this.logger.WriteException( + $"Failed to set breakpoint on file: {filePath}", + e); scriptFile = null; - exception = e; return false; } } From a4d120a1ec955661fbf7ee707870052e5ffff125 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 18 Oct 2018 18:05:52 +0700 Subject: [PATCH 4/7] params on newline --- .../Server/LanguageServerEditorOperations.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs index 94b63e5cb..dd2f6bcf9 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs @@ -94,7 +94,9 @@ public EditorContext ConvertClientEditorContext( ScriptFile scriptFile = null; if (!this.editorSession.Workspace.TryGetFile(clientContext.CurrentFilePath, out scriptFile)) { - scriptFile = this.editorSession.Workspace.GetFileBuffer(clientContext.CurrentFilePath, clientContext.CurrentFileContent); + scriptFile = this.editorSession.Workspace.GetFileBuffer( + clientContext.CurrentFilePath, + clientContext.CurrentFileContent); } return From be5b707ec679529a24641d482f864ec63f41728e Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Sun, 21 Oct 2018 08:34:27 +0800 Subject: [PATCH 5/7] create a new ScriptFile and have the language be in FileContext --- .../LanguageServer/EditorCommands.cs | 2 + .../Server/LanguageServerEditorOperations.cs | 14 ++---- .../Extensions/EditorContext.cs | 5 +- .../Extensions/FileContext.cs | 50 ++++++++++++------- .../Workspace/Workspace.cs | 29 +++++++++++ 5 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs index 2265de1e4..a7c385bc6 100644 --- a/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/EditorCommands.cs @@ -40,6 +40,8 @@ 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/LanguageServerEditorOperations.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs index dd2f6bcf9..8639f5ee3 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerEditorOperations.cs @@ -90,14 +90,9 @@ public Task SetSelection(BufferRange selectionRange) public EditorContext ConvertClientEditorContext( ClientEditorContext clientContext) { - - ScriptFile scriptFile = null; - if (!this.editorSession.Workspace.TryGetFile(clientContext.CurrentFilePath, out scriptFile)) - { - scriptFile = this.editorSession.Workspace.GetFileBuffer( - clientContext.CurrentFilePath, - clientContext.CurrentFileContent); - } + ScriptFile scriptFile = this.editorSession.Workspace.CreateScriptFileFromFileBuffer( + clientContext.CurrentFilePath, + clientContext.CurrentFileContent); return new EditorContext( @@ -110,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..1a9a006cd 100644 --- a/src/PowerShellEditorServices/Extensions/EditorContext.cs +++ b/src/PowerShellEditorServices/Extensions/EditorContext.cs @@ -52,10 +52,11 @@ 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..dbd50bbf6 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 @@ -84,11 +89,18 @@ public BufferRange FileRange 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/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 900f977aa..87a6ea0b2 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. From 045ebf7d20fc01615f7abd3024d2ac51cf31ad2c Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Sun, 21 Oct 2018 08:53:29 +0800 Subject: [PATCH 6/7] xml docs --- src/PowerShellEditorServices/Extensions/EditorContext.cs | 1 + src/PowerShellEditorServices/Extensions/FileContext.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/PowerShellEditorServices/Extensions/EditorContext.cs b/src/PowerShellEditorServices/Extensions/EditorContext.cs index 1a9a006cd..c29c60fcc 100644 --- a/src/PowerShellEditorServices/Extensions/EditorContext.cs +++ b/src/PowerShellEditorServices/Extensions/EditorContext.cs @@ -48,6 +48,7 @@ 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, diff --git a/src/PowerShellEditorServices/Extensions/FileContext.cs b/src/PowerShellEditorServices/Extensions/FileContext.cs index dbd50bbf6..1b563dcb2 100644 --- a/src/PowerShellEditorServices/Extensions/FileContext.cs +++ b/src/PowerShellEditorServices/Extensions/FileContext.cs @@ -86,6 +86,7 @@ public string WorkspacePath /// 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, From 75e58da98da92138dce2bf7045e8f030722030f0 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 23 Oct 2018 22:10:09 -0700 Subject: [PATCH 7/7] address Keith's feedback --- src/PowerShellEditorServices/Workspace/Workspace.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 87a6ea0b2..25b02031d 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -131,7 +131,7 @@ public ScriptFile GetFile(string filePath) } /// - /// Tries to get an open file in the workspace. Returns true or false if it succeeds. + /// 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.