#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

246 lines
7.1 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Parser;
using ICSharpCode.NRefactory.Parser.VB;
using ICSharpCode.SharpDevelop.Editor;
namespace VBNetBinding
{
public class VBNetBracketSearcher : IBracketSearcher
{
string openingBrackets = "([{";
string closingBrackets = ")]}";
public BracketSearchResult SearchBracket(IDocument document, int offset)
{
if (offset > 0) {
char c = document.GetCharAt(offset - 1);
int index = openingBrackets.IndexOf(c);
int otherOffset = -1;
if (index > -1)
otherOffset = SearchBracketForward(document, offset, openingBrackets[index], closingBrackets[index]);
index = closingBrackets.IndexOf(c);
if (index > -1)
otherOffset = SearchBracketBackward(document, offset - 2, openingBrackets[index], closingBrackets[index]);
if (otherOffset > -1)
return new BracketSearchResult(Math.Min(offset - 1, otherOffset), 1, Math.Max(offset - 1, otherOffset), 1);
int length;
VBStatement statement;
int startIndex = FindBeginStatementAroundOffset(document, offset, out statement, out length);
int endIndex = 0;
if (statement != null)
endIndex = FindEndStatement(document, statement);
else {
endIndex = FindEndStatementAroundOffset(document, offset, out statement);
if (statement != null)
startIndex = FindBeginStatement(document, statement, document.OffsetToPosition(endIndex), out length);
}
if (startIndex > -1 && endIndex > -1)
return new BracketSearchResult(startIndex, length, endIndex, statement.EndStatement.Length);
}
return null;
}
#region bracket search
int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
{
bool inString = false;
char ch;
int brackets = -1;
for (int i = offset; i > 0; --i) {
ch = document.GetCharAt(i);
if (ch == openBracket && !inString) {
++brackets;
if (brackets == 0) return i;
} else if (ch == closingBracket && !inString) {
--brackets;
} else if (ch == '"') {
inString = !inString;
} else if (ch == '\n') {
int lineStart = ScanLineStart(document, i);
if (lineStart >= 0) { // line could have a comment
inString = false;
for (int j = lineStart; j < i; ++j) {
ch = document.GetCharAt(j);
if (ch == '"') inString = !inString;
if (ch == '\'' && !inString) {
// comment found!
// Skip searching in the comment:
i = j;
break;
}
}
}
inString = false;
}
}
return -1;
}
static int ScanLineStart(IDocument document, int offset)
{
bool hasComment = false;
for (int i = offset - 1; i > 0; --i) {
char ch = document.GetCharAt(i);
if (ch == '\n') {
if (!hasComment) return -1;
return i + 1;
} else if (ch == '\'') {
hasComment = true;
}
}
return 0;
}
int SearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket)
{
bool inString = false;
bool inComment = false;
int brackets = 1;
for (int i = offset; i < document.TextLength; ++i) {
char ch = document.GetCharAt(i);
if (ch == '\n') {
inString = false;
inComment = false;
}
if (inComment) continue;
if (ch == '"') inString = !inString;
if (inString) continue;
if (ch == '\'') {
inComment = true;
} else if (ch == openBracket) {
++brackets;
} else if (ch == closingBracket) {
--brackets;
if (brackets == 0) return i;
}
}
return -1;
}
#endregion
#region statement search
int FindBeginStatementAroundOffset(IDocument document, int offset, out VBStatement statement, out int length)
{
length = 0;
statement = null;
return -1;
}
int FindEndStatementAroundOffset(IDocument document, int offset, out VBStatement statement)
{
IDocumentLine line = document.GetLineForOffset(offset);
string interestingText = VBNetFormattingStrategy.TrimLine(line.Text).Trim(' ', '\t');
//LoggingService.Debug("text: '" + interestingText + "'");
foreach (VBStatement s in VBNetFormattingStrategy.Statements) {
Match match = Regex.Matches(interestingText, s.EndRegex, RegexOptions.Singleline | RegexOptions.IgnoreCase).OfType<Match>().FirstOrDefault();
if (match != null) {
//LoggingService.DebugFormatted("Found end statement at offset {1}: {0}", s, offset);
statement = s;
int result = match.Index + (line.Length - line.Text.TrimStart(' ', '\t').Length) + line.Offset;
if (offset >= result && offset <= (result + match.Length))
return result;
}
}
statement = null;
return -1;
}
int FindBeginStatement(IDocument document, VBStatement statement, Location endLocation, out int length)
{
ILexer lexer = ParserFactory.CreateLexer(SupportedLanguage.VBNet, document.CreateReader());
Token currentToken = null;
Token prevToken = null;
int lookFor = statement.StatementToken;
Stack<Token> tokens = new Stack<Token>();
if (statement.EndStatement == "Next") {
lookFor = Tokens.For;
}
Token result = null;
while ((currentToken = lexer.NextToken()).Kind != Tokens.EOF) {
if (prevToken == null)
prevToken = currentToken;
if (VBNetFormattingStrategy.IsBlockStart(lexer, currentToken, prevToken))
tokens.Push(currentToken);
if (VBNetFormattingStrategy.IsBlockEnd(currentToken, prevToken)) {
while (tokens.Count > 0 && !VBNetFormattingStrategy.IsMatchingEnd(tokens.Peek(), currentToken))
tokens.Pop();
if (tokens.Count > 0) {
Token t = tokens.Pop();
if (currentToken.Location.Line == endLocation.Line) {
result = t;
break;
}
}
}
prevToken = currentToken;
}
if (result != null) {
IDocumentLine line = document.GetLine(result.Location.Line);
string interestingText = VBNetFormattingStrategy.TrimLine(line.Text).Trim(' ', '\t');
//LoggingService.Debug("text2: '" + interestingText + "'");
Match matchResult = Regex.Match(interestingText, statement.StartRegex, RegexOptions.Singleline | RegexOptions.IgnoreCase);
if (matchResult != null) {
length = matchResult.Value.TrimEnd(' ', '\t').Length;
int diff = line.Length - line.Text.TrimStart(' ', '\t').Length;
int start = diff + line.Offset;
if (IsDeclaration(result.Kind)) {
length += diff + matchResult.Index;
return start;
}
return matchResult.Index + start;
}
}
length = 0;
return -1;
}
int FindEndStatement(IDocument document, VBStatement statement)
{
return -1;
}
#endregion
bool IsDeclaration(int kind)
{
return kind == Tokens.Sub || kind == Tokens.Function || kind == Tokens.Operator || VBNetFormattingStrategy.IsDeclaration(kind);
}
}
}