Skip to content

Commit

Permalink
indentation is now respecting ILCs
Browse files Browse the repository at this point in the history
  • Loading branch information
siegfriedpammer committed Mar 19, 2011
1 parent 045f414 commit 55de9e4
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,6 @@ bool IsEndStatementNeeded(ITextEditor editor, ref VBStatement statement, int lin
while ((currentToken = lexer.NextToken()).Kind != Tokens.EOF) {
if (prevToken == null)
prevToken = currentToken;

if (IsBlockStart(lexer, currentToken, prevToken)) {
if ((tokens.Count > 0 && tokens.Peek().Kind != Tokens.Interface) || IsDeclaration(currentToken.Kind))
tokens.Push(currentToken);
Expand Down Expand Up @@ -514,10 +513,9 @@ static int SmartIndentInternal(ITextEditor editor, int begin, int end)
ILexer lexer = ParserFactory.CreateLexer(SupportedLanguage.VBNet, new StringReader(editor.Document.Text));

Stack<string> indentation = new Stack<string>();

indentation.Push(string.Empty);

int oldLine = 1;
List<int> eols = new List<int>();

bool inInterface = false;
bool isMustOverride = false;
Expand All @@ -527,6 +525,8 @@ static int SmartIndentInternal(ITextEditor editor, int begin, int end)
Token currentToken = null;
Token prevToken = null;

int blockStart = 1;

while ((currentToken = lexer.NextToken()).Kind != Tokens.EOF) {
if (prevToken == null)
prevToken = currentToken;
Expand All @@ -540,11 +540,16 @@ static int SmartIndentInternal(ITextEditor editor, int begin, int end)
if (currentToken.Kind == Tokens.Declare)
isDeclare = true;

if (currentToken.Kind == Tokens.EOL)
if (currentToken.Kind == Tokens.EOL) {
isDelegate = isDeclare = isMustOverride = false;
eols.Add(currentToken.Location.Line);
}

if (IsBlockEnd(currentToken, prevToken)) {
ApplyToRange(editor, indentation, oldLine, currentToken.Location.Line, begin, end);
// indent the lines inside the block
// this is an End-statement
// hence we indent from blockStart to the previous line
ApplyToRange(editor, indentation, eols, blockStart, currentToken.Location.Line - 1, begin, end);

if (currentToken.Kind == Tokens.Interface)
inInterface = false;
Expand All @@ -556,12 +561,17 @@ static int SmartIndentInternal(ITextEditor editor, int begin, int end)
Unindent(indentation);
}

oldLine = currentToken.Location.Line;
// block start is this line (for the lines between two blocks)
blockStart = currentToken.Location.Line;
}

if (IsBlockStart(lexer, currentToken, prevToken)) {
int line = GetLastVisualLine(currentToken.Location.Line, editor);
ApplyToRange(editor, indentation, oldLine, line, begin, end);
// indent the lines between the last and this block
// this is a Begin-statement
// hence we indent from blockStart to the this line
int lastVisualLine = FindNextEol(lexer);
eols.Add(lastVisualLine);
ApplyToRange(editor, indentation, eols, blockStart, lastVisualLine, begin, end);

if (!inInterface && !isMustOverride && !isDeclare && !isDelegate) {
Indent(editor, indentation);
Expand All @@ -573,31 +583,78 @@ static int SmartIndentInternal(ITextEditor editor, int begin, int end)
if (currentToken.Kind == Tokens.Interface)
inInterface = true;

oldLine = line + 1;
// block start is the following line (for the lines inside a block)
blockStart = lastVisualLine + 1;
}

prevToken = currentToken;
}

// do last indent step
int newLine = prevToken.Location.Line;

if (oldLine > newLine)
newLine = oldLine;

ApplyToRange(editor, indentation, oldLine, newLine, begin, end);
ApplyToRange(editor, indentation, eols, blockStart, editor.Document.TotalNumberOfLines, begin, end);

return (indentation.PeekOrDefault() ?? string.Empty).Length;
}

static int GetLastVisualLine(int line, ITextEditor area)
static int FindNextEol(ILexer lexer)
{
string text = area.Document.GetLine(line).Text.TrimComments();
while (text.EndsWith("_", StringComparison.Ordinal)) {
line++;
text = area.Document.GetLine(line).Text.TrimComments();
lexer.StartPeek();

Token t = lexer.Peek();

while (t.Kind != Tokens.EOL)
t = lexer.Peek();

return t.Location.Line;
}

static void ApplyToRange(ITextEditor editor, Stack<string> indentation, List<int> eols, int blockStart, int blockEnd, int selectionStart, int selectionEnd) {
LoggingService.InfoFormatted("indenting line {0} to {1} with {2}", blockStart, blockEnd, (indentation.PeekOrDefault() ?? "").Length);

int nextEol = -1;
bool wasMultiLine = false;

for (int i = blockStart; i <= blockEnd; i++) {
IDocumentLine curLine = editor.Document.GetLine(i);
string lineText = curLine.Text.TrimStart();
string noComments = lineText.TrimComments().TrimEnd();

// adjust indentation if the current line is not selected
// lines between the selection will be aligned to the selected level
if (i < selectionStart || i > selectionEnd) {
indentation.PopOrDefault();
indentation.Push(DocumentUtilitites.GetWhitespaceAfter(editor.Document, curLine.Offset));
}

// look for next eol if line is not empty
// (the lexer does not produce eols for empty lines)
if (!string.IsNullOrEmpty(noComments) && i >= nextEol) {
int search = eols.BinarySearch(i);
if (search < 0)
search = ~search;
nextEol = search < eols.Count ? eols[search] : i;
}

// remove indentation in last line of multiline array(, collection, object) initializers
if (i == nextEol && wasMultiLine && noComments == "}") {
wasMultiLine = false;
Unindent(indentation);
}

// apply the indentation
editor.Document.SmartReplaceLine(curLine, (indentation.PeekOrDefault() ?? "") + lineText);

// indent line if it is ended by (implicit) line continuation
if (i < nextEol && !wasMultiLine) {
wasMultiLine = true;
Indent(editor, indentation);
}

// unindent if this is the last line of a multiline statement
if (i == nextEol && wasMultiLine) {
wasMultiLine = false;
Unindent(indentation);
}
}
return line;
}

static void Unindent(Stack<string> indentation)
Expand Down Expand Up @@ -718,41 +775,6 @@ static bool IsSpecialCase(Token current, Token prev)
return false;
}

static void ApplyToRange(ITextEditor editor, Stack<string> indentation, int begin, int end, int selBegin, int selEnd)
{
bool multiLine = false;

for (int i = begin; i <= end; i++) {
IDocumentLine curLine = editor.Document.GetLine(i);
string lineText = curLine.Text.TrimStart(' ', '\t', '\r', '\n');
string noComments = lineText.TrimComments().TrimEnd(' ', '\t', '\r', '\n');

if (i < selBegin || i > selEnd) {
indentation.PopOrDefault();
indentation.Push(DocumentUtilitites.GetWhitespaceAfter(editor.Document, curLine.Offset));
}

// change indentation before (indent this line)
if (multiLine && noComments.EndsWith("}", StringComparison.OrdinalIgnoreCase)) {
Unindent(indentation);
multiLine = false;
}

editor.Document.SmartReplaceLine(curLine, (indentation.PeekOrDefault() ?? string.Empty) + lineText);

// change indentation afterwards (indent next line)
if (!multiLine && noComments.EndsWith("_", StringComparison.OrdinalIgnoreCase)) {
Indent(editor, indentation);
multiLine = true;
}

if (multiLine && !noComments.EndsWith("_", StringComparison.OrdinalIgnoreCase)) {
multiLine = false;
Unindent(indentation);
}
}
}

/// <summary>
/// Gets the next member after the specified caret position.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace ICSharpCode.VBNetBinding.Tests
{
[TestFixture, Ignore]
[TestFixture]
public class IndentationTests
{
[Test]
Expand Down Expand Up @@ -63,34 +63,118 @@ Sub Test2()
}

[Test]
public void ArrayInitializerTest()
public void SD1775_Fix()
{
string expected = @"Public Class Test
Private Sub Tester()
test(asdf, _
asdf, _
asdf, _
asdf)
Dim test As Integer() = { _
2,2,3,34,4,5 _
}
B = New Burger With {Cheese = True, _
Lettuce = True, _
Tomato = True, _
CookLevel = MeatCookLevel.WellDone}
End Sub
End Class";

string code = @"Public Class Test
Private Sub Tester()
B = New Burger With {Cheese = True, _
Lettuce = True, _
Tomato = True, _
CookLevel = MeatCookLevel.WellDone}
End Sub
End Class";

RunFormatTest(code, expected);
}

[Test]
public void Simple()
{
string expected = @"'
' Created by SharpDevelop.
' User: Siegfried
' Date: 25.02.2011
' Time: 14:41
'
' To change this template use Tools | Options | Coding | Edit Standard Headers.
'
Imports Microsoft.VisualBasic.ApplicationServices
Namespace My
' This file controls the behaviour of the application.
Partial Class MyApplication
Public Sub New()
MyBase.New(AuthenticationMode.Windows)
Me.IsSingleInstance = False
Me.EnableVisualStyles = True
Me.SaveMySettingsOnExit = True
Me.ShutDownStyle = ShutdownMode.AfterMainFormCloses
End Sub
Protected Overrides Sub OnCreateMainForm()
Me.MainForm = My.Forms.MainForm
End Sub
End Class
End Namespace";

string code = @"'
' Created by SharpDevelop.
' User: Siegfried
' Date: 25.02.2011
' Time: 14:41
'
' To change this template use Tools | Options | Coding | Edit Standard Headers.
'
Imports Microsoft.VisualBasic.ApplicationServices
Namespace My
' This file controls the behaviour of the application.
Partial Class MyApplication
Public Sub New()
MyBase.New(AuthenticationMode.Windows)
Me.IsSingleInstance = False
Me.EnableVisualStyles = True
Me.SaveMySettingsOnExit = True
Me.ShutDownStyle = ShutdownMode.AfterMainFormCloses
End Sub
Protected Overrides Sub OnCreateMainForm()
Me.MainForm = My.Forms.MainForm
End Sub
End Class
End Namespace";

RunFormatTest(code, expected);
}

[Test]
public void ArrayInitializerTest()
{
string expected = @"Public Class Test
Private Sub Tester()
test(asdf, _
asdf, _
asdf, _
asdf)
Dim test As Integer() = { _
2,2,3,34,4,5 _
2,2,3,34,4,5 _
}
End Sub
End Class";

string code = @"Public Class Test
Private Sub Tester()
test(asdf, _
asdf, _
asdf, _
asdf)
Dim test As Integer() = { _
2,2,3,34,4,5 _
}
End Sub
End Class";

RunFormatTest(code, expected);
}

Expand Down Expand Up @@ -177,7 +261,7 @@ End Sub
[Test]
public void SelectCaseTest()
{
string expected = @"Public Class Test
string expected = @"Public Class Test
Private Sub Tester()
Select Case a
Case 0
Expand Down Expand Up @@ -215,7 +299,7 @@ End Sub
[Test]
public void SelectCaseTest2()
{
string expected = @"Public Class Test
string expected = @"Public Class Test
Private Sub Tester()
Select Case a
Case 0
Expand Down Expand Up @@ -247,7 +331,7 @@ End Sub
[Test]
public void WithTest()
{
string expected = @"Public Class Test
string expected = @"Public Class Test
Private Sub Tester()
With a
If True Then
Expand Down Expand Up @@ -281,7 +365,7 @@ End Sub
[Test]
public void WithTest2()
{
string expected = @"Public Class Test
string expected = @"Public Class Test
Private Sub Tester()
With a
If True Then
Expand Down

0 comments on commit 55de9e4

Please sign in to comment.