Skip to content

Commit fadcfa6

Browse files
author
Kapil Borle
authored
Merge pull request #790 from PowerShell/kapilmb/tab-indentation
Add tabbed indentation capability to UseConsistentIndentation rule
2 parents b9f9b68 + 7cff264 commit fadcfa6

7 files changed

+112
-24
lines changed

Engine/Settings/CodeFormatting.psd1

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
PSUseConsistentIndentation = @{
2626
Enable = $true
27+
Kind = 'space'
2728
IndentationSize = 4
2829
}
2930

Engine/Settings/CodeFormattingAllman.psd1

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
PSUseConsistentIndentation = @{
2626
Enable = $true
27+
Kind = 'space'
2728
IndentationSize = 4
2829
}
2930

Engine/Settings/CodeFormattingOTBS.psd1

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
PSUseConsistentIndentation = @{
2626
Enable = $true
27+
Kind = 'space'
2728
IndentationSize = 4
2829
}
2930

Engine/Settings/CodeFormattingStroustrup.psd1

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
PSUseConsistentIndentation = @{
2727
Enable = $true
28+
Kind = 'space'
2829
IndentationSize = 4
2930
}
3031

RuleDocumentation/UseConsistentIndentation.md

+7
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ Enable or disable the rule during ScriptAnalyzer invocation.
2828
#### IndentationSize: bool (Default value is `4`)
2929

3030
Indentation size in the number of space characters.
31+
32+
#### Kind: string (Default value is `space`)
33+
34+
Represents the kind of indentation to be used. Possible values are: `space`, `tab`. If any invalid value is given, the property defaults to `space`.
35+
36+
`space` means `IndentationSize` number of `space` characters are used to provide one level of indentation.
37+
`tab` means a tab character, `\t`.

Rules/UseConsistentIndentation.cs

+51-9
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,48 @@ public class UseConsistentIndentation : ConfigurableRule
3636
[ConfigurableRuleProperty(defaultValue: 4)]
3737
public int IndentationSize { get; protected set; }
3838

39-
private enum IndentationKind { Space, Tab };
39+
40+
// Cannot name to IndentationKind due to the enum type of the same name.
41+
/// <summary>
42+
/// Represents the kind of indentation to be used.
43+
///
44+
/// Possible values are: `space`, `tab`. If any invalid value is given, the
45+
/// property defaults to `space`.
46+
///
47+
/// `space` means `IndentationSize` number of `space` characters are used to provide one level of indentation.
48+
/// `tab` means a tab character, `\t`.
49+
///</summary>
50+
[ConfigurableRuleProperty(defaultValue: "space")]
51+
public string Kind
52+
{
53+
get
54+
{
55+
return indentationKind.ToString();
56+
}
57+
set
58+
{
59+
if (String.IsNullOrWhiteSpace(value) ||
60+
!Enum.TryParse<IndentationKind>(value, true, out indentationKind))
61+
{
62+
indentationKind = IndentationKind.Space;
63+
}
64+
}
65+
}
66+
67+
private bool insertSpaces;
68+
private char indentationChar;
69+
private int indentationLevelMultiplier;
70+
71+
// TODO Enable auto when the rule is able to detect indentation
72+
private enum IndentationKind {
73+
Space,
74+
Tab,
75+
// Auto
76+
};
4077

4178
// TODO make this configurable
42-
private readonly IndentationKind indentationKind = IndentationKind.Space;
79+
private IndentationKind indentationKind = IndentationKind.Space;
80+
4381

4482
/// <summary>
4583
/// Analyzes the given ast to find violations.
@@ -61,6 +99,14 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
6199
return Enumerable.Empty<DiagnosticRecord>();
62100
}
63101

102+
// It is more efficient to initialize these fields in ConfigurRule method
103+
// but when the rule will enable `Auto` IndentationKind, we will anyways need to move
104+
// the setting of these variables back here after the rule detects the indentation kind for
105+
// each invocation.
106+
insertSpaces = indentationKind == IndentationKind.Space;
107+
indentationChar = insertSpaces ? ' ' : '\t';
108+
indentationLevelMultiplier = insertSpaces ? IndentationSize : 1;
109+
64110
var tokens = Helper.Instance.Tokens;
65111
var diagnosticRecords = new List<DiagnosticRecord>();
66112
var indentationLevel = 0;
@@ -262,17 +308,13 @@ private int GetIndentationColumnNumber(int indentationLevel)
262308

263309
private int GetIndentation(int indentationLevel)
264310
{
265-
return indentationLevel * this.IndentationSize;
266-
}
267-
268-
private char GetIndentationChar()
269-
{
270-
return indentationKind == IndentationKind.Space ? ' ' : '\t';
311+
// todo if condition can be evaluated during rule configuration
312+
return indentationLevel * indentationLevelMultiplier;
271313
}
272314

273315
private string GetIndentationString(int indentationLevel)
274316
{
275-
return new string(GetIndentationChar(), GetIndentation(indentationLevel));
317+
return new string(indentationChar, GetIndentation(indentationLevel));
276318
}
277319
}
278320
}

Tests/Rules/UseConsistentIndentation.tests.ps1

+50-15
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
66

77
$indentationUnit = ' '
88
$indentationSize = 4
9+
$ruleConfiguration = @{
10+
Enable = $true
11+
IndentationSize = 4
12+
Kind = 'space'
13+
}
14+
915
$settings = @{
1016
IncludeRules = @("PSUseConsistentIndentation")
11-
Rules = @{
12-
PSUseConsistentIndentation = @{
13-
Enable = $true
14-
IndentationSize = 4
15-
}
17+
Rules = @{
18+
PSUseConsistentIndentation = $ruleConfiguration
1619
}
1720
}
1821

19-
2022
Describe "UseConsistentIndentation" {
2123
Context "When top level indentation is not consistent" {
2224
BeforeAll {
@@ -127,17 +129,17 @@ function foo {
127129
get-process |
128130
where-object {$_.Name -match 'powershell'}
129131
'@
130-
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
131-
$violations.Count | Should Be 1
132+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
133+
$violations.Count | Should Be 1
132134
}
133135

134136
It "Should not find a violation if a pipleline element is indented correctly" {
135137
$def = @'
136138
get-process |
137139
where-object {$_.Name -match 'powershell'}
138140
'@
139-
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
140-
$violations.Count | Should Be 0
141+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
142+
$violations.Count | Should Be 0
141143
}
142144

143145
It "Should ignore comment in the pipleline" {
@@ -147,8 +149,8 @@ get-process |
147149
select Name,Id |
148150
format-list
149151
'@
150-
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
151-
$violations.Count | Should Be 3
152+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
153+
$violations.Count | Should Be 3
152154
}
153155

154156
It "Should indent properly after line continuation (backtick) character" {
@@ -159,13 +161,46 @@ $x = "this " + `
159161
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
160162
$violations.Count | Should Be 1
161163
$params = @{
162-
RawContent = $def
164+
RawContent = $def
163165
DiagnosticRecord = $violations[0]
164166
CorrectionsCount = 1
165-
ViolationText = "`"Should be indented properly`""
166-
CorrectionText = (New-Object -TypeName String -ArgumentList $indentationUnit,$indentationSize) + "`"Should be indented properly`""
167+
ViolationText = "`"Should be indented properly`""
168+
CorrectionText = (New-Object -TypeName String -ArgumentList $indentationUnit, $indentationSize) + "`"Should be indented properly`""
167169
}
168170
Test-CorrectionExtentFromContent @params
169171
}
170172
}
173+
174+
Context "When tabs instead of spaces are used for indentation" {
175+
BeforeAll {
176+
$ruleConfiguration.'Kind' = 'tab'
177+
}
178+
179+
It "Should indent using tabs" {
180+
$def = @'
181+
function foo
182+
{
183+
get-childitem
184+
$x=1+2
185+
$hashtable = @{
186+
property1 = "value"
187+
anotherProperty = "another value"
188+
}
189+
}
190+
'@
191+
${t} = "`t"
192+
$expected = @"
193+
function foo
194+
{
195+
${t}get-childitem
196+
${t}`$x=1+2
197+
${t}`$hashtable = @{
198+
${t}${t}property1 = "value"
199+
${t}${t}anotherProperty = "another value"
200+
${t}}
201+
}
202+
"@
203+
Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should Be $expected
204+
}
205+
}
171206
}

0 commit comments

Comments
 (0)