Skip to content

Commit 5c77603

Browse files
author
Kapil Borle
authored
Merge pull request #780 from PowerShell/kapilmb/update-formatter
Add a Range parameter to Invoke-Formatter cmdlet
2 parents e212bc7 + 1ed33fa commit 5c77603

File tree

5 files changed

+84
-28
lines changed

5 files changed

+84
-28
lines changed

Engine/Commands/InvokeFormatterCommand.cs

+17-23
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
using System;
1414
using System.Globalization;
15+
using System.Linq;
1516
using System.Management.Automation;
1617

1718
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands
@@ -26,6 +27,7 @@ public class InvokeFormatterCommand : PSCmdlet, IOutputWriter
2627
{
2728
private const string defaultSettingsPreset = "CodeFormatting";
2829
private Settings inputSettings;
30+
private Range range;
2931

3032
/// <summary>
3133
/// The script text to be formated.
@@ -43,19 +45,20 @@ public class InvokeFormatterCommand : PSCmdlet, IOutputWriter
4345
[ValidateNotNull]
4446
public object Settings { get; set; } = defaultSettingsPreset;
4547

46-
#if DEBUG
47-
[Parameter(Mandatory = false)]
48-
public Range Range { get; set; }
49-
50-
[Parameter(Mandatory = false, ParameterSetName = "NoRange")]
51-
public int StartLineNumber { get; set; } = -1;
52-
[Parameter(Mandatory = false, ParameterSetName = "NoRange")]
53-
public int StartColumnNumber { get; set; } = -1;
54-
[Parameter(Mandatory = false, ParameterSetName = "NoRange")]
55-
public int EndLineNumber { get; set; } = -1;
56-
[Parameter(Mandatory = false, ParameterSetName = "NoRange")]
57-
public int EndColumnNumber { get; set; } = -1;
48+
/// <summary>
49+
/// The range within which formatting should take place.
50+
///
51+
/// The parameter is an array of integers of length 4 such that the first, second, third and last
52+
/// elements correspond to the start line number, start column number, end line number and
53+
/// end column number. These numbers must be greater than 0.
54+
/// </summary>
55+
/// <returns></returns>
56+
[Parameter(Mandatory = false, Position = 3)]
57+
[ValidateNotNull]
58+
[ValidateCount(4, 4)]
59+
public int[] Range { get; set; }
5860

61+
#if DEBUG
5962
/// <summary>
6063
/// Attaches to an instance of a .Net debugger
6164
/// </summary>
@@ -85,6 +88,7 @@ protected override void BeginProcessing()
8588
}
8689
#endif
8790

91+
this.range = Range == null ? null : new Range(Range[0], Range[1], Range[2], Range[3]);
8892
try
8993
{
9094
inputSettings = PSSASettings.Create(Settings, this.MyInvocation.PSScriptRoot, this);
@@ -93,7 +97,7 @@ protected override void BeginProcessing()
9397
{
9498
this.ThrowTerminatingError(new ErrorRecord(
9599
e,
96-
"SETTNGS_ERROR",
100+
"SETTINGS_ERROR",
97101
ErrorCategory.InvalidData,
98102
Settings));
99103
}
@@ -114,17 +118,7 @@ protected override void ProcessRecord()
114118
{
115119
// todo add tests to check range formatting
116120
string formattedScriptDefinition;
117-
#if DEBUG
118-
var range = Range;
119-
if (this.ParameterSetName.Equals("NoRange"))
120-
{
121-
range = new Range(StartLineNumber, StartColumnNumber, EndLineNumber, EndColumnNumber);
122-
}
123-
124121
formattedScriptDefinition = Formatter.Format(ScriptDefinition, inputSettings, range, this);
125-
#endif // DEBUG
126-
127-
formattedScriptDefinition = Formatter.Format(ScriptDefinition, inputSettings, null, this);
128122
this.WriteObject(formattedScriptDefinition);
129123
}
130124

Engine/EditableText.cs

+22-4
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,27 @@ public EditableText ApplyEdit(TextEdit textEdit)
106106

107107
// TODO Add a method that takes multiple edits, checks if they are unique and applies them.
108108

109+
/// <summary>
110+
/// Checks if the range falls within the bounds of the text.
111+
/// </summary>
112+
/// <param name="range"></param>
113+
/// <returns></returns>
114+
public bool IsValidRange(Range range)
115+
{
116+
if (range == null)
117+
{
118+
throw new ArgumentNullException(nameof(range));
119+
}
120+
121+
return range.Start.Line <= Lines.Length
122+
&& range.End.Line <= Lines.Length
123+
&& range.Start.Column <= Lines[range.Start.Line - 1].Length
124+
&& range.End.Column <= Lines[range.End.Line - 1].Length + 1;
125+
}
126+
127+
/// <summary>
128+
/// Returns the text representation of the object.
129+
/// </summary>
109130
public override string ToString()
110131
{
111132
return Text;
@@ -123,10 +144,7 @@ private void ValidateTextEdit(TextEdit textEdit)
123144

124145
private void ValidateTextEditExtent(TextEdit textEdit)
125146
{
126-
if (textEdit.StartLineNumber > Lines.Length
127-
|| textEdit.EndLineNumber > Lines.Length
128-
|| textEdit.StartColumnNumber > Lines[textEdit.StartLineNumber - 1].Length
129-
|| textEdit.EndColumnNumber > Lines[textEdit.EndLineNumber - 1].Length + 1)
147+
if (!IsValidRange(textEdit))
130148
{
131149
throw new ArgumentException(String.Format(
132150
CultureInfo.CurrentCulture,

Engine/ScriptAnalyzer.cs

+9
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,15 @@ public EditableText Fix(EditableText text, Range range, out Range updatedRange)
15591559

15601560
// todo validate range
15611561
var isRangeNull = range == null;
1562+
if (!isRangeNull && !text.IsValidRange(range))
1563+
{
1564+
this.outputWriter.ThrowTerminatingError(new ErrorRecord(
1565+
new ArgumentException("Invalid Range", nameof(range)),
1566+
"FIX_ERROR",
1567+
ErrorCategory.InvalidArgument,
1568+
range));
1569+
}
1570+
15621571
range = isRangeNull ? null : SnapToEdges(text, range);
15631572
var previousLineCount = text.Lines.Length;
15641573
var previousUnusedCorrections = 0;

Tests/Engine/InvokeFormatter.tests.ps1

+21
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,27 @@ function foo {
3131
Invoke-Formatter $def $settings | Should Be $expected
3232
}
3333
}
34+
35+
Context "When a range is given" {
36+
It "Should format only within the range when a range list is given" {
37+
$def = @"
38+
function foo {
39+
"xyz"
40+
"abc"
41+
}
42+
"@
43+
44+
$expected = @"
45+
function foo {
46+
"xyz"
47+
"abc"
48+
}
49+
"@
50+
51+
Invoke-Formatter -ScriptDefinition $def -Range @(3, 1, 4, 1) | Should Be $expected
52+
}
53+
}
54+
3455
Context "When no settings are given" {
3556
It "Should format using default settings" {
3657
$def = @'

docs/markdown/Invoke-Formatter.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Formats a script text based on the input settings or default settings.
1010
## SYNTAX
1111

1212
```
13-
Invoke-Formatter [-ScriptDefinition] <String> [-Settings <object>]
13+
Invoke-Formatter [-ScriptDefinition] <String> [-Settings <object>] [-Range <int[]>]
1414
```
1515

1616
## DESCRIPTION
@@ -97,3 +97,17 @@ Default value: CodeFormatting
9797
Accept pipeline input: False
9898
Accept wildcard characters: False
9999
```
100+
101+
### -Range
102+
The range within which formatting should take place. The parameter is an array of integers of length 4 such that the first, second, third and last elements correspond to the start line number, start column number, end line number and end column number. These numbers must be greater than 0.
103+
104+
```yaml
105+
Type: Int32[]
106+
Parameter Sets: (All)
107+
108+
Required: False
109+
Position: 3
110+
Default value:
111+
Accept pipeline input: False
112+
Accept wildcard characters: False
113+
```

0 commit comments

Comments
 (0)