Browse Source

[Formatting] Worked on C# indent engine.

newNRvisualizers
Mike Krüger 14 years ago
parent
commit
c520eaf996
  1. 316
      ICSharpCode.NRefactory.CSharp/Formatter/CSharpIndentEngine.cs
  2. 8
      ICSharpCode.NRefactory.CSharp/Formatter/Indent.cs
  3. 18
      ICSharpCode.NRefactory.Tests/IndentationTests/IndentationTests.cs

316
ICSharpCode.NRefactory.CSharp/Formatter/CSharpIndentEngine.cs

@ -1,6 +1,9 @@ @@ -1,6 +1,9 @@
using System;
using ICSharpCode.NRefactory.Editor;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace ICSharpCode.NRefactory.CSharp
{
@ -10,9 +13,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -10,9 +13,15 @@ namespace ICSharpCode.NRefactory.CSharp
readonly CSharpFormattingOptions options;
readonly TextEditorOptions textEditorOptions;
readonly StringBuilder wordBuf = new StringBuilder();
Indent thisLineindent;
Indent indent;
public IList<string> ConditionalSymbols {
get;
set;
}
public string ThisLineIndent {
get {
return thisLineindent.IndentString;
@ -34,7 +43,44 @@ namespace ICSharpCode.NRefactory.CSharp @@ -34,7 +43,44 @@ namespace ICSharpCode.NRefactory.CSharp
this.thisLineindent = new Indent(textEditorOptions);
}
CSharpIndentEngine (CSharpIndentEngine prototype)
{
this.document = prototype.document;
this.options = prototype.options;
this.textEditorOptions = prototype.textEditorOptions;
this.indent = prototype.indent.Clone();
this.thisLineindent = prototype.thisLineindent.Clone();
this.offset = prototype.offset;
this.inside = prototype.inside;
this.IsLineStart = prototype.IsLineStart;
this.pc = prototype.pc;
this.parenStack = new Stack<TextLocation>(prototype.parenStack.Reverse ());
this.currentBody = prototype.currentBody;
this.nextBody = prototype.nextBody;
this.addContinuation = prototype.addContinuation;
this.line = prototype.line;
this.col = prototype.col;
this.popNextParenBlock = prototype.popNextParenBlock;
}
public CSharpIndentEngine Clone ()
{
return new CSharpIndentEngine(this);
}
int offset;
Inside inside = Inside.Empty;
bool IsLineStart = true;
char pc;
Stack<TextLocation> parenStack = new Stack<TextLocation> ();
Body currentBody;
Body nextBody;
bool addContinuation;
int line, col;
bool popNextParenBlock;
bool readPreprocessorExpression;
void Reset()
{
@ -44,8 +90,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -44,8 +90,11 @@ namespace ICSharpCode.NRefactory.CSharp
pc = '\0';
IsLineStart = true;
addContinuation = false;
popNextParenBlock = false;
parenStack.Clear();
inside = Inside.Empty;
nextBody = currentBody = Body.None;
line = col = 1;
}
public void UpdateToOffset (int toOffset)
@ -56,8 +105,6 @@ namespace ICSharpCode.NRefactory.CSharp @@ -56,8 +105,6 @@ namespace ICSharpCode.NRefactory.CSharp
Push(document.GetCharAt(i));
}
Inside inside = Inside.Empty;
bool IsLineStart = true;
bool IsInStringOrChar {
get {
@ -71,12 +118,19 @@ namespace ICSharpCode.NRefactory.CSharp @@ -71,12 +118,19 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
bool IsInPreProcessorComment {
get {
return inside.HasFlag (Inside.PreProcessorComment);
}
}
[Flags]
public enum Inside {
Empty = 0,
PreProcessor = (1 << 0),
PreProcessorComment = (1 << 12),
MultiLineComment = (1 << 1),
LineComment = (1 << 2),
DocComment = (1 << 11),
@ -99,21 +153,198 @@ namespace ICSharpCode.NRefactory.CSharp @@ -99,21 +153,198 @@ namespace ICSharpCode.NRefactory.CSharp
FoldedBlockOrCase = (FoldedStatement | Block | Case)
}
char pc;
int parens = 0;
#region Pre processor evaluation (from cs-tokenizer.cs)
static bool is_identifier_start_character (int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || Char.IsLetter ((char)c);
}
static bool is_identifier_part_character (char c)
{
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c == '_' || (c >= '0' && c <= '9'))
return true;
if (c < 0x80)
return false;
return Char.IsLetter (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
}
bool eval_val (string s)
{
if (s == "true")
return true;
if (s == "false")
return false;
return ConditionalSymbols != null && ConditionalSymbols.Contains (s);
}
bool pp_primary (ref string s)
{
s = s.Trim ();
int len = s.Length;
if (len > 0){
char c = s [0];
if (c == '('){
s = s.Substring (1);
bool val = pp_expr (ref s, false);
if (s.Length > 0 && s [0] == ')'){
s = s.Substring (1);
return val;
}
return false;
}
if (is_identifier_start_character (c)){
int j = 1;
while (j < len){
c = s [j];
if (is_identifier_part_character (c)){
j++;
continue;
}
bool v = eval_val (s.Substring (0, j));
s = s.Substring (j);
return v;
}
bool vv = eval_val (s);
s = "";
return vv;
}
}
return false;
}
bool pp_unary (ref string s)
{
s = s.Trim ();
int len = s.Length;
if (len > 0){
if (s [0] == '!'){
if (len > 1 && s [1] == '='){
return false;
}
s = s.Substring (1);
return ! pp_primary (ref s);
} else
return pp_primary (ref s);
} else {
return false;
}
}
bool pp_eq (ref string s)
{
bool va = pp_unary (ref s);
s = s.Trim ();
int len = s.Length;
if (len > 0){
if (s [0] == '='){
if (len > 2 && s [1] == '='){
s = s.Substring (2);
return va == pp_unary (ref s);
} else {
return false;
}
} else if (s [0] == '!' && len > 1 && s [1] == '='){
s = s.Substring (2);
return va != pp_unary (ref s);
}
}
return va;
}
bool pp_and (ref string s)
{
bool va = pp_eq (ref s);
s = s.Trim ();
int len = s.Length;
if (len > 0){
if (s [0] == '&'){
if (len > 2 && s [1] == '&'){
s = s.Substring (2);
return (va & pp_and (ref s));
} else {
return false;
}
}
}
return va;
}
//
// Evaluates an expression for `#if' or `#elif'
//
bool pp_expr (ref string s, bool isTerm)
{
bool va = pp_and (ref s);
s = s.Trim ();
int len = s.Length;
if (len > 0){
char c = s [0];
if (c == '|'){
if (len > 2 && s [1] == '|'){
s = s.Substring (2);
return va | pp_expr (ref s, isTerm);
} else {
return false;
}
}
if (isTerm) {
return false;
}
}
return va;
}
bool eval (string s)
{
bool v = pp_expr (ref s, true);
s = s.Trim ();
if (s.Length != 0){
return false;
}
return v;
}
#endregion
void Push(char ch)
{
if (readPreprocessorExpression) {
wordBuf.Append(ch);
}
if (inside.HasFlag (Inside.VerbatimString) && pc == '"' && ch != '"') {
inside &= ~Inside.String;
}
Console.WriteLine(ch);
switch (ch) {
case '#':
if (IsLineStart)
inside = Inside.PreProcessor;
break;
case '/':
if (IsInStringOrChar)
if (IsInStringOrChar || IsInPreProcessorComment)
break;
if (pc == '/') {
if (inside.HasFlag (Inside.Comment)) {
@ -124,13 +355,22 @@ namespace ICSharpCode.NRefactory.CSharp @@ -124,13 +355,22 @@ namespace ICSharpCode.NRefactory.CSharp
}
break;
case '*':
if (IsInStringOrChar || IsInComment)
if (IsInStringOrChar || IsInComment || IsInPreProcessorComment)
break;
if (pc == '/')
inside |= Inside.MultiLineComment;
break;
case '\n':
case '\t':
var nextTabStop = (col - 1 + textEditorOptions.IndentSize) / textEditorOptions.IndentSize;
col = 1 + nextTabStop * textEditorOptions.IndentSize;
return;
case '\r':
if (readPreprocessorExpression) {
if (!eval (wordBuf.ToString ()))
inside |= Inside.PreProcessorComment;
}
inside &= ~(Inside.Comment | Inside.String | Inside.CharLiteral | Inside.PreProcessor);
CheckKeyword(wordBuf.ToString());
wordBuf.Length = 0;
@ -140,9 +380,16 @@ namespace ICSharpCode.NRefactory.CSharp @@ -140,9 +380,16 @@ namespace ICSharpCode.NRefactory.CSharp
thisLineindent = indent.Clone ();
addContinuation = false;
IsLineStart = true;
readPreprocessorExpression = false;
col = 1;
line++;
break;
case '\n':
if (pc == '\r')
break;
goto case '\r';
case '"':
if (IsInComment)
if (IsInComment || IsInPreProcessorComment)
break;
if (inside.HasFlag (Inside.String)) {
if (pc != '\\')
@ -159,21 +406,33 @@ namespace ICSharpCode.NRefactory.CSharp @@ -159,21 +406,33 @@ namespace ICSharpCode.NRefactory.CSharp
case '<':
case '[':
case '(':
if (IsInComment || IsInStringOrChar)
if (IsInComment || IsInStringOrChar || IsInPreProcessorComment)
break;
parens++;
parenStack.Push (new TextLocation (line, col));
popNextParenBlock = true;
indent.Push (IndentType.Block);
break;
case '>':
case ']':
case ')':
if (IsInComment || IsInStringOrChar)
if (IsInComment || IsInStringOrChar || IsInPreProcessorComment)
break;
parens--;
if (popNextParenBlock)
parenStack.Pop ();
indent.Pop ();
indent.ExtraSpaces = 0;
break;
case ',':
if (IsInComment || IsInStringOrChar || IsInPreProcessorComment)
break;
if (parenStack.Count > 0 && parenStack.Peek ().Line == line) {
indent.Pop ();
popNextParenBlock = false;
indent.ExtraSpaces = parenStack.Peek ().Column - 1 - thisLineindent.CurIndent;
}
break;
case '{':
if (IsInComment || IsInStringOrChar)
if (IsInComment || IsInStringOrChar || IsInPreProcessorComment)
break;
currentBody = nextBody;
if (indent.Count > 0 && indent.Peek() == IndentType.Continuation)
@ -182,18 +441,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -182,18 +441,20 @@ namespace ICSharpCode.NRefactory.CSharp
AddIndentation (currentBody);
break;
case '}':
if (IsInComment || IsInStringOrChar)
if (IsInComment || IsInStringOrChar || IsInPreProcessorComment)
break;
indent.Pop ();
if (indent.Count > 0 && indent.Peek() == IndentType.Continuation)
indent.Pop();
break;
case ';':
if (IsInComment || IsInStringOrChar || IsInPreProcessorComment)
break;
if (indent.Count > 0 && indent.Peek() == IndentType.Continuation)
indent.Pop();
break;
case '\'':
if (IsInComment || inside.HasFlag (Inside.String))
if (IsInComment || inside.HasFlag (Inside.String) || IsInPreProcessorComment)
break;
if (inside.HasFlag (Inside.CharLiteral)) {
if (pc != '\\')
@ -204,11 +465,22 @@ namespace ICSharpCode.NRefactory.CSharp @@ -204,11 +465,22 @@ namespace ICSharpCode.NRefactory.CSharp
break;
}
if (!IsInComment && !IsInStringOrChar) {
if (!IsInComment && !IsInStringOrChar && !readPreprocessorExpression) {
if ((wordBuf.Length == 0 ? char.IsLetter(ch) : char.IsLetterOrDigit(ch)) || ch == '_') {
wordBuf.Append(ch);
} else {
CheckKeyword(wordBuf.ToString());
if (inside.HasFlag (Inside.PreProcessor)) {
if (wordBuf.ToString () == "endif") {
inside &= ~Inside.PreProcessorComment;
} else if (wordBuf.ToString () == "if") {
readPreprocessorExpression = true;
} else if (wordBuf.ToString () == "elif") {
inside &= ~Inside.PreProcessorComment;
readPreprocessorExpression = true;
}
} else {
CheckKeyword(wordBuf.ToString());
}
wordBuf.Length = 0;
}
}
@ -218,9 +490,10 @@ namespace ICSharpCode.NRefactory.CSharp @@ -218,9 +490,10 @@ namespace ICSharpCode.NRefactory.CSharp
}
IsLineStart &= ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
pc = ch;
if (ch != '\n' && ch != '\r')
col++;
}
void AddIndentation(BraceStyle braceStyle)
{
switch (braceStyle) {
@ -277,9 +550,6 @@ namespace ICSharpCode.NRefactory.CSharp @@ -277,9 +550,6 @@ namespace ICSharpCode.NRefactory.CSharp
Switch
}
Body currentBody;
Body nextBody;
bool addContinuation;
void CheckKeyword (string keyword)
{
switch (currentBody) {

8
ICSharpCode.NRefactory.CSharp/Formatter/Indent.cs

@ -43,6 +43,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -43,6 +43,12 @@ namespace ICSharpCode.NRefactory.CSharp
int curIndent;
public int CurIndent {
get {
return curIndent;
}
}
public Indent(TextEditorOptions options)
{
this.options = options;
@ -127,6 +133,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -127,6 +133,8 @@ namespace ICSharpCode.NRefactory.CSharp
return extraSpaces;
}
set {
if (value < 0)
throw new ArgumentOutOfRangeException ("ExtraSpaces >= 0 but was " + value);
extraSpaces = value;
Update();
}

18
ICSharpCode.NRefactory.Tests/IndentationTests/IndentationTests.cs

@ -43,7 +43,6 @@ namespace ICSharpCode.NRefactory.CSharp.Indentation @@ -43,7 +43,6 @@ namespace ICSharpCode.NRefactory.CSharp.Indentation
Assert.AreEqual("\t", indent.NewLineIndent);
}
[Ignore ("TODO")]
[Test]
public void TestPreProcessorDirectives ()
{
@ -58,6 +57,20 @@ namespace Foo { @@ -58,6 +57,20 @@ namespace Foo {
Assert.AreEqual("\t\t", indent.NewLineIndent);
}
[Test]
public void TestPreProcessorDirectives2 ()
{
var indent = CreateEngine(@"
namespace Foo {
class Foo {
#if NOTTHERE || true
{
#endif
$");
Assert.AreEqual("\t\t\t", indent.ThisLineIndent);
Assert.AreEqual("\t\t\t", indent.NewLineIndent);
}
[Test]
public void TestIf ()
{
@ -144,7 +157,6 @@ class Foo { @@ -144,7 +157,6 @@ class Foo {
Assert.AreEqual("\t\t\t", indent.NewLineIndent);
}
[Ignore ("TODO")]
[Test]
public void TestParameters ()
{
@ -154,7 +166,7 @@ class Foo { @@ -154,7 +166,7 @@ class Foo {
{
Foo(true,$");
Assert.AreEqual("\t\t", indent.ThisLineIndent);
Assert.AreEqual("\t\t ", indent.NewLineIndent);
Assert.AreEqual("\t\t ", indent.NewLineIndent);
}
[Test]

Loading…
Cancel
Save