diff --git a/module/PowerShellEditorServices/Commands/Private/BuiltInCommands.ps1 b/module/PowerShellEditorServices/Commands/Private/BuiltInCommands.ps1 index e56e44af7..350bb94ca 100644 --- a/module/PowerShellEditorServices/Commands/Private/BuiltInCommands.ps1 +++ b/module/PowerShellEditorServices/Commands/Private/BuiltInCommands.ps1 @@ -3,7 +3,7 @@ Register-EditorCommand ` -DisplayName 'Open Editor Profile' ` -SuppressOutput ` -ScriptBlock { - param([Microsoft.PowerShell.EditorServices.Services.PowerShellContext.EditorContext]$context) + param([Microsoft.PowerShell.EditorServices.Extensions.EditorContext, Microsoft.PowerShell.EditorServices]$context) If (!(Test-Path -Path $Profile)) { New-Item -Path $Profile -ItemType File } $psEditor.Workspace.OpenFile($Profile) } @@ -13,7 +13,7 @@ Register-EditorCommand ` -DisplayName 'Open Profile from List (Current User)' ` -SuppressOutput ` -ScriptBlock { - param([Microsoft.PowerShell.EditorServices.Services.PowerShellContext.EditorContext]$context) + param([Microsoft.PowerShell.EditorServices.Extensions.EditorContext, Microsoft.PowerShell.EditorServices]$context) $Current = Split-Path -Path $profile -Leaf $List = @($Current,'Microsoft.VSCode_profile.ps1','Microsoft.PowerShell_profile.ps1','Microsoft.PowerShellISE_profile.ps1','Profile.ps1') | Select-Object -Unique diff --git a/module/PowerShellEditorServices/Commands/Public/CmdletInterface.ps1 b/module/PowerShellEditorServices/Commands/Public/CmdletInterface.ps1 index 285e26120..17b36165c 100644 --- a/module/PowerShellEditorServices/Commands/Public/CmdletInterface.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/CmdletInterface.ps1 @@ -36,18 +36,17 @@ function Register-EditorCommand { { $commandArgs = @($Name, $DisplayName, $SuppressOutput.IsPresent) - if ($ScriptBlock -ne $null) + $editorCommand = if ($ScriptBlock -ne $null) { Write-Verbose "Registering command '$Name' which executes a ScriptBlock" - $commandArgs += $ScriptBlock + [Microsoft.PowerShell.EditorServices.Extensions.EditorCommand, Microsoft.PowerShell.EditorServices]::new($Name, $DisplayName, $SuppressOutput, $ScriptBlock) } else { Write-Verbose "Registering command '$Name' which executes a function" - $commandArgs += $Function + [Microsoft.PowerShell.EditorServices.Extensions.EditorCommand, Microsoft.PowerShell.EditorServices]::new($Name, $DisplayName, $SuppressOutput, $Function) } - $editorCommand = New-Object Microsoft.PowerShell.EditorServices.Extensions.EditorCommand -ArgumentList $commandArgs if ($psEditor.RegisterCommand($editorCommand)) { Write-Verbose "Registered new command '$Name'" diff --git a/module/PowerShellEditorServices/Commands/Public/ConvertFrom-ScriptExtent.ps1 b/module/PowerShellEditorServices/Commands/Public/ConvertFrom-ScriptExtent.ps1 index ac5665660..3f36e91f5 100644 --- a/module/PowerShellEditorServices/Commands/Public/ConvertFrom-ScriptExtent.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/ConvertFrom-ScriptExtent.ps1 @@ -8,8 +8,8 @@ function ConvertFrom-ScriptExtent { .EXTERNALHELP ..\PowerShellEditorServices.Commands-help.xml #> [CmdletBinding()] - [OutputType([Microsoft.PowerShell.EditorServices.BufferRange], ParameterSetName='BufferRange')] - [OutputType([Microsoft.PowerShell.EditorServices.BufferPosition], ParameterSetName='BufferPosition')] + [OutputType([Microsoft.PowerShell.EditorServices.Extensions.IFileRange, Microsoft.PowerShell.EditorServices], ParameterSetName='BufferRange')] + [OutputType([Microsoft.PowerShell.EditorServices.Extensions.IFilePosition, Microsoft.PowerShell.EditorServices], ParameterSetName='BufferPosition')] param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] @@ -37,7 +37,7 @@ function ConvertFrom-ScriptExtent { switch ($PSCmdlet.ParameterSetName) { BufferRange { # yield - New-Object Microsoft.PowerShell.EditorServices.BufferRange @( + [Microsoft.PowerShell.EditorServices.Extensions.FileRange, Microsoft.PowerShell.EditorServices]::new( $aExtent.StartLineNumber, $aExtent.StartColumnNumber, $aExtent.EndLineNumber, @@ -52,7 +52,7 @@ function ConvertFrom-ScriptExtent { $column = $aExtent.StartLineNumber } # yield - New-Object Microsoft.PowerShell.EditorServices.BufferPosition @( + [Microsoft.PowerShell.EditorServices.Extensions.FileRange, Microsoft.PowerShell.EditorServices]::new( $line, $column) } diff --git a/module/PowerShellEditorServices/Commands/Public/ConvertTo-ScriptExtent.ps1 b/module/PowerShellEditorServices/Commands/Public/ConvertTo-ScriptExtent.ps1 index 3f55f1454..534db8474 100644 --- a/module/PowerShellEditorServices/Commands/Public/ConvertTo-ScriptExtent.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/ConvertTo-ScriptExtent.ps1 @@ -49,12 +49,12 @@ function ConvertTo-ScriptExtent { [Parameter(ValueFromPipelineByPropertyName, ParameterSetName='ByBuffer')] [Alias('Start')] - [Microsoft.PowerShell.EditorServices.BufferPosition] + [Microsoft.PowerShell.EditorServices.Extensions.IFilePosition, Microsoft.PowerShell.EditorServices] $StartBuffer, [Parameter(ValueFromPipelineByPropertyName, ParameterSetName='ByBuffer')] [Alias('End')] - [Microsoft.PowerShell.EditorServices.BufferPosition] + [Microsoft.PowerShell.EditorServices.Extensions.IFilePosition, Microsoft.PowerShell.EditorServices] $EndBuffer, [Parameter(Mandatory, @@ -66,13 +66,11 @@ function ConvertTo-ScriptExtent { ) begin { $fileContext = $psEditor.GetEditorContext().CurrentFile - $emptyExtent = New-Object Microsoft.PowerShell.EditorServices.FullScriptExtent @( - <# filecontext: #> $fileContext, - <# startOffset: #> 0, - <# endOffset: #> 0) + $emptyExtent = [Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]::Empty } + process { - # Already a InternalScriptExtent, FullScriptExtent or is empty. + # Already a InternalScriptExtent, FileScriptExtent or is empty. $returnAsIs = $Extent -and (0 -ne $Extent.StartOffset -or 0 -ne $Extent.EndOffset -or @@ -88,32 +86,36 @@ function ConvertTo-ScriptExtent { if (-not $EndOffsetNumber) { $endOffset = $startOffset } - return New-Object Microsoft.PowerShell.EditorServices.FullScriptExtent @( + + return [Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]::FromOffsets( $fileContext, $startOffset, $endOffset) } - if (-not $StartBuffer) { - if (-not $StartColumnNumber) { $StartColumnNumber = 1 } - if (-not $StartLineNumber) { $StartLineNumber = 1 } - $StartBuffer = New-Object Microsoft.PowerShell.EditorServices.BufferPosition @( - $StartLineNumber, - $StartColumnNumber) - - if ($EndLineNumber -and $EndColumnNumber) { - $EndBuffer = New-Object Microsoft.PowerShell.EditorServices.BufferPosition @( - $EndLineNumber, - $EndColumnNumber) + + if ($StartBuffer) { + if (-not $EndBuffer) + { + $EndBuffer = $StartBuffer } + + return [Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]::FromPositions( + $fileContext, + $StartBuffer.Line, + $StartBuffer.Column, + $EndBuffer.Line, + $EndBuffer.Column) } - if (-not $EndBuffer) { $EndBuffer = $StartBuffer } - $bufferRange = New-Object Microsoft.PowerShell.EditorServices.BufferRange @( - $StartBuffer, - $EndBuffer) + if (-not $StartColumnNumber) { $StartColumnNumber = 1 } + if (-not $StartLineNumber) { $StartLineNumber = 1 } + if (-not $EndLineNumber) { $EndLineNumber = 1 } + if (-not $EndColumnNumber) { $EndColumnNumber = 1 } - return New-Object Microsoft.PowerShell.EditorServices.FullScriptExtent @( - $fileContext, - $bufferRange) + return [Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]::FromPositions( + $StartLineNumber, + $StartColumnNumber, + $EndLineNumber, + $EndColumnNumber) } } diff --git a/module/PowerShellEditorServices/Commands/Public/Import-EditorCommand.ps1 b/module/PowerShellEditorServices/Commands/Public/Import-EditorCommand.ps1 index 0a60dddeb..7a68021ea 100644 --- a/module/PowerShellEditorServices/Commands/Public/Import-EditorCommand.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/Import-EditorCommand.ps1 @@ -7,7 +7,7 @@ function Import-EditorCommand { <# .EXTERNALHELP ..\PowerShellEditorServices.Commands-help.xml #> - [OutputType([Microsoft.PowerShell.EditorServices.Services.PowerShellContext.EditorCommand])] + [OutputType([Microsoft.PowerShell.EditorServices.Extensions.EditorCommand, Microsoft.PowerShell.EditorServices])] [CmdletBinding(DefaultParameterSetName='ByCommand')] param( [Parameter(Position=0, @@ -72,7 +72,7 @@ function Import-EditorCommand { $commands = $Command | Get-Command -ErrorAction SilentlyContinue } } - $attributeType = [Microsoft.PowerShell.EditorServices.Services.PowerShellContext.EditorCommandAttribute] + $attributeType = [Microsoft.PowerShell.EditorServices.Extensions.EditorCommandAttribute, Microsoft.PowerShell.EditorServices] foreach ($aCommand in $commands) { # Get the attribute from our command to get name info. $details = $aCommand.ScriptBlock.Attributes | Where-Object TypeId -eq $attributeType @@ -96,7 +96,7 @@ function Import-EditorCommand { } # Check for a context parameter. $contextParameter = $aCommand.Parameters.Values | - Where-Object ParameterType -eq ([Microsoft.PowerShell.EditorServices.Services.PowerShellContext.EditorContext]) + Where-Object ParameterType -eq ([Microsoft.PowerShell.EditorServices.Extensions.EditorContext, Microsoft.PowerShell.EditorServices]) # If one is found then add a named argument. Otherwise call the command directly. if ($contextParameter) { @@ -106,7 +106,7 @@ function Import-EditorCommand { $scriptBlock = [scriptblock]::Create($aCommand.Name) } - $editorCommand = New-Object Microsoft.PowerShell.EditorServices.Services.PowerShellContext.EditorCommand @( + $editorCommand = [Microsoft.PowerShell.EditorServices.Extensions.EditorCommand, Microsoft.PowerShell.EditorServices]::new( <# commandName: #> $details.Name, <# displayName: #> $details.DisplayName, <# suppressOutput: #> $details.SuppressOutput, diff --git a/module/PowerShellEditorServices/Commands/Public/Set-ScriptExtent.ps1 b/module/PowerShellEditorServices/Commands/Public/Set-ScriptExtent.ps1 index 6629bccc5..3458bb19e 100644 --- a/module/PowerShellEditorServices/Commands/Public/Set-ScriptExtent.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/Set-ScriptExtent.ps1 @@ -27,11 +27,11 @@ function Set-ScriptExtent { ) begin { $fileContext = $psEditor.GetEditorContext().CurrentFile - $extentList = New-Object System.Collections.Generic.List[Microsoft.PowerShell.EditorServices.FullScriptExtent] + $extentList = [System.Collections.Generic.List[Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]]::new() } process { - if ($Extent -isnot [Microsoft.PowerShell.EditorServices.FullScriptExtent]) { - $Extent = New-Object Microsoft.PowerShell.EditorServices.FullScriptExtent @( + if ($Extent -isnot [Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]) { + $Extent = [Microsoft.PowerShell.EditorServices.Extensions.FileScriptExtent, Microsoft.PowerShell.EditorServices]::FromOffsets( $fileContext, $Extent.StartOffset, $Extent.EndOffset) @@ -69,7 +69,7 @@ function Set-ScriptExtent { $differenceOffset = $aText.Length - $aExtent.Text.Length $scriptText = $fileContext.GetText() - $fileContext.InsertText($aText, $aExtent.BufferRange) + $fileContext.InsertText($aText, $aExtent) $newText = $scriptText.Remove($aExtent.StartOffset, $aExtent.Text.Length).Insert($aExtent.StartOffset, $aText) diff --git a/src/PowerShellEditorServices/Extensions/EditorFileRanges.cs b/src/PowerShellEditorServices/Extensions/EditorFileRanges.cs index 9db857986..d91e8bdaf 100644 --- a/src/PowerShellEditorServices/Extensions/EditorFileRanges.cs +++ b/src/PowerShellEditorServices/Extensions/EditorFileRanges.cs @@ -7,9 +7,146 @@ using Microsoft.PowerShell.EditorServices.Services.TextDocument; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using System; +using System.Management.Automation.Language; namespace Microsoft.PowerShell.EditorServices.Extensions { + public class FileScriptPosition : IScriptPosition, IFilePosition + { + public static FileScriptPosition Empty { get; } = new FileScriptPosition(null, 0, 0, 0); + + public static FileScriptPosition FromPosition(FileContext file, int lineNumber, int columnNumber) + { + int offset = 0; + int currLine = 1; + string fileText = file.Ast.Extent.Text; + while (offset < fileText.Length && currLine < lineNumber) + { + offset = fileText.IndexOf('\n', offset); + currLine++; + } + + offset += columnNumber - 1; + + return new FileScriptPosition(file, lineNumber, columnNumber, offset); + } + + public static FileScriptPosition FromOffset(FileContext file, int offset) + { + + int line = 1; + string fileText = file.Ast.Extent.Text; + + if (offset >= fileText.Length) + { + throw new ArgumentException(nameof(offset), "Offset greater than file length"); + } + + int lastLineOffset = -1; + for (int i = 0; i < offset; i++) + { + if (fileText[i] == '\n') + { + lastLineOffset = i; + line++; + } + } + + int column = offset - lastLineOffset; + + return new FileScriptPosition(file, line, column, offset); + } + + private readonly FileContext _file; + + internal FileScriptPosition(FileContext file, int lineNumber, int columnNumber, int offset) + { + _file = file; + Line = file.GetTextLines()[lineNumber - 1]; + ColumnNumber = columnNumber; + LineNumber = lineNumber; + Offset = offset; + } + + public int ColumnNumber { get; } + + public string File { get; } + + public string Line { get; } + + public int LineNumber { get; } + + public int Offset { get; } + + int IFilePosition.Column => ColumnNumber; + + int IFilePosition.Line => LineNumber; + + public string GetFullScript() => _file.GetText(); + } + + public class FileScriptExtent : IScriptExtent, IFileRange + { + public static bool IsEmpty(FileScriptExtent extent) + { + return extent == Empty + || (extent.StartOffset == 0 && extent.EndOffset == 0); + } + + public static FileScriptExtent Empty { get; } = new FileScriptExtent(null, FileScriptPosition.Empty, FileScriptPosition.Empty); + + public static FileScriptExtent FromOffsets(FileContext file, int startOffset, int endOffset) + { + return new FileScriptExtent( + file, + FileScriptPosition.FromOffset(file, startOffset), + FileScriptPosition.FromOffset(file, endOffset)); + } + + public static FileScriptExtent FromPositions(FileContext file, int startLine, int startColumn, int endLine, int endColumn) + { + return new FileScriptExtent( + file, + FileScriptPosition.FromPosition(file, startLine, startColumn), + FileScriptPosition.FromPosition(file, endLine, endColumn)); + } + + private readonly FileContext _file; + private readonly FileScriptPosition _start; + private readonly FileScriptPosition _end; + + public FileScriptExtent(FileContext file, FileScriptPosition start, FileScriptPosition end) + { + _file = file; + _start = start; + _end = end; + } + + public int EndColumnNumber => _end.ColumnNumber; + + public int EndLineNumber => _end.LineNumber; + + public int EndOffset => _end.Offset; + + public IScriptPosition EndScriptPosition => _end; + + public string File => _file.Path; + + public int StartColumnNumber => _start.ColumnNumber; + + public int StartLineNumber => _start.LineNumber; + + public int StartOffset => _start.Offset; + + public IScriptPosition StartScriptPosition => _start; + + public string Text => _file.GetText().Substring(_start.Offset, _end.Offset - _start.Offset); + + IFilePosition IFileRange.Start => _start; + + IFilePosition IFileRange.End => _end; + } + /// /// A 1-based file position, referring to a point in a file. ///