From: Jochen L. <lue...@us...> - 2004-12-25 08:35:14
|
Update of /cvsroot/e-p-i-c/org.epic.ext.cbg.editor/src/cbg/editor/rules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1443/src/cbg/editor/rules Modified Files: ColoringWhitespaceDetector.java TextSequenceRule.java StarRule.java Added Files: ExtendedPatternRule.java Log Message: Changes by LeO Index: TextSequenceRule.java =================================================================== RCS file: /cvsroot/e-p-i-c/org.epic.ext.cbg.editor/src/cbg/editor/rules/TextSequenceRule.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- TextSequenceRule.java 10 Jul 2004 07:55:13 -0000 1.4 +++ TextSequenceRule.java 25 Dec 2004 08:35:03 -0000 1.5 @@ -1,138 +1,234 @@ -package cbg.editor.rules; - -import org.eclipse.jface.text.rules.ICharacterScanner; -import org.eclipse.jface.text.rules.IPredicateRule; -import org.eclipse.jface.text.rules.IToken; -import org.eclipse.jface.text.rules.IWordDetector; -import org.eclipse.jface.text.rules.Token; - -public class TextSequenceRule extends Object implements IPredicateRule {/** - * An implementation of <code>IRule</code> capable of detecting words - * Word rules also allow for the association of tokens with specific words. - * That is, not only can the rule be used to provide tokens for exact matches, - * but also for the generalized notion of a word in the context in which it is used. - * A word rules uses a word detector to determine what a word is. - * - * @see IWordDetector - */ - protected static final int UNDEFINED= -1; - - /** The word detector used by this rule */ - protected IWordDetector fDetector; - /** The token to be returned on success */ - protected IToken token; - /** The column constraint */ - protected int fColumn= UNDEFINED; - protected char[] word; - protected boolean ignoreCase; - private StringBuffer fBuffer= new StringBuffer(); - - public TextSequenceRule(String wordToMatch, IToken token, boolean ignoreCase) { - this.token = token; - word = (ignoreCase ? wordToMatch.toLowerCase().toCharArray() : wordToMatch.toCharArray()); - this.ignoreCase = ignoreCase; - } - - /** - * Sets a column constraint for this rule. If set, the rule's token - * will only be returned if the pattern is detected starting at the - * specified column. If the column is smaller then 0, the column - * constraint is considered removed. - * - * @param column the column in which the pattern starts - */ - public void setColumnConstraint(int column) { - if (column < 0) - column= UNDEFINED; - fColumn= column; - } - - /* - * @see IRule#evaluate - */ - public IToken evaluate(ICharacterScanner scanner) { - return evaluate(scanner, false); - } - - /** - * Returns the characters in the buffer to the scanner. - * - * @param scanner the scanner to be used - */ - protected void unreadBuffer(ICharacterScanner scanner) { - for (int i= fBuffer.length() - 1; i >= 0; i--) - scanner.unread(); - } - public IToken evaluate(ICharacterScanner scanner, boolean resume) { - if (fColumn == UNDEFINED) - return doEvaluate(scanner, resume); - - int c = scanner.read(); - scanner.unread(); - if (c == word[0]) - return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED); - else - return Token.UNDEFINED; - } - /** - * Evaluates this rules without considering any column constraints. - * - * @param scanner the character scanner to be used - * @return the token resulting from this evaluation - */ - protected IToken doEvaluate(ICharacterScanner scanner) { - return doEvaluate(scanner, false); - } - - /** - * Evaluates this rules without considering any column constraints. Resumes - * detection, i.e. look sonly for the end sequence required by this rule if the - * <code>resume</code> flag is set. - * - * @param scanner the character scanner to be used - * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise - * @return the token resulting from this evaluation - * @since 2.0 - */ - protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { - if (resume) { - if (sequenceDetected(scanner)) return token; - } else { - int c = scanner.read(); - if (c == word[0] || Character.toLowerCase((char)c) == word[0]) { - if (sequenceDetected(scanner)) return token; - } - } - scanner.unread(); - return Token.UNDEFINED; - } - - public IToken getSuccessToken() { - return token; - } - /** - * Returns whether the next characters to be read by the character scanner - * are an exact match with the given sequence. No escape characters are allowed - * within the sequence. If specified the sequence is considered to be found - * when reading the EOF character. - * - * @param scanner the character scanner to be used - * @param sequence the sequence to be detected - * @param eofAllowed indicated whether EOF terminates the pattern - * @return <code>true</code> if the given sequence has been detected - */ - protected boolean sequenceDetected(ICharacterScanner scanner) { - for (int i= 1; i < word.length; i++) { - int c = scanner.read(); - if (c != word[i] || c != Character.toLowerCase((char)c)) { - // Non-matching character detected, rewind the scanner back to the start. - // Do not unread the first character. - scanner.unread(); - for (int j= i-1; j > 0; j--) - scanner.unread(); - return false; - } - } - return true; - } -} +package cbg.editor.rules; + +import org.eclipse.jface.text.rules.ICharacterScanner; +import org.eclipse.jface.text.rules.IPredicateRule; +import org.eclipse.jface.text.rules.IToken; +import org.eclipse.jface.text.rules.IWhitespaceDetector; +import org.eclipse.jface.text.rules.IWordDetector; +import org.eclipse.jface.text.rules.Token; +import cbg.editor.ColoringPartitionScanner; + +public class TextSequenceRule extends Object implements IPredicateRule {/** + * An implementation of <code>IRule</code> capable of detecting words + * Word rules also allow for the association of tokens with specific words. + * That is, not only can the rule be used to provide tokens for exact matches, + * but also for the generalized notion of a word in the context in which it is used. + * A word rules uses a word detector to determine what a word is. + * + * @see IWordDetector + */ + protected static final int UNDEFINED= -1; + + /** The word detector used by this rule */ + protected IWordDetector fDetector; + /** The token to be returned on success */ + protected IToken token; + /** The column constraint */ + protected int fColumn= UNDEFINED; + protected char[] word; + protected boolean isCaseInSensitive; + private StringBuffer fBuffer= new StringBuffer(); + + private String[] groupContent; + private boolean isExistingGroup; + private char curScannerChar; + private int myStepCounter = 0; + private final char EOFChar= (char) ICharacterScanner.EOF; + private IWhitespaceDetector whiteSpace; + + + public TextSequenceRule(String wordToMatch, String[] groupContent, IToken token, + boolean ignoreCase, IWhitespaceDetector whiteSpace) { + this.token = token; + word = (ignoreCase ? wordToMatch.toLowerCase().toCharArray() : wordToMatch.toCharArray()); + this.isCaseInSensitive = ignoreCase; + + this.groupContent = groupContent; + if (groupContent == null) { + isExistingGroup = false; + } else { + isExistingGroup = true; + } + this.whiteSpace= whiteSpace; + + } + + /** + * Sets a column constraint for this rule. If set, the rule's token + * will only be returned if the pattern is detected starting at the + * specified column. If the column is smaller then 0, the column + * constraint is considered removed. + * + * @param column the column in which the pattern starts + */ + public void setColumnConstraint(int column) { + if (column < 0) + column= UNDEFINED; + fColumn= column; + } + + /* + * @see IRule#evaluate + */ + public IToken evaluate(ICharacterScanner scanner) { + return evaluate(scanner, false); + } + + /** + * Returns the characters in the buffer to the scanner. + * + * @param scanner the scanner to be used + */ + protected void unreadBuffer(ICharacterScanner scanner) { + for (int i= fBuffer.length() - 1; i >= 0; i--) + scanner.unread(); + } + public IToken evaluate(ICharacterScanner scanner, boolean resume) { + if (fColumn == UNDEFINED) + return doEvaluate(scanner, resume); + + int c = scanner.read(); + scanner.unread(); + if (c == word[0]) + return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED); + else + return Token.UNDEFINED; + } + /** + * Evaluates this rules without considering any column constraints. + * + * @param scanner the character scanner to be used + * @return the token resulting from this evaluation + */ + protected IToken doEvaluate(ICharacterScanner scanner) { + return doEvaluate(scanner, false); + } + + /** + * Same code as in ExtendePatternRule + */ + protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { + myStepCounter = 0; + boolean continueCheck=true; + + if (((ColoringPartitionScanner) scanner).getOffset() > 0) { + scanner.unread(); + curScannerChar = (char) scanner.read(); + if (!whiteSpace.isWhitespace(curScannerChar)) { + //we do not check anything, since the leading char before this is not + //whitespace or equivalent + continueCheck = false; + } + } + + if (continueCheck) { + if (isExistingGroup) { + if (forwardStartSequenceDetected(scanner)) { + return token; + } + } else { + //check from the regular startSequence + curScannerChar= (char) scanner.read(); + myStepCounter++; + if (isCaseInSensitive) { + curScannerChar = Character.toLowerCase(curScannerChar); + } + if (curScannerChar == word[0]) { + if (sequenceDetected(scanner, word, true)) { + return token; + } + } + } + } + + unwindScanner(scanner); + return Token.UNDEFINED; + } + + public IToken getSuccessToken() { + return token; + } + + private final boolean forwardStartSequenceDetected(ICharacterScanner scanner) { + StringBuffer c = new StringBuffer(); + int i=0; + int j=0; + int elementSize=0; + elementSize = groupContent.length - 1; + + String escape= groupContent[0]; + c.append(escape); + + while (i++ <= elementSize) { + curScannerChar= (char) scanner.read(); + myStepCounter++; + if (curScannerChar == EOFChar) { + return false; + } + if (isCaseInSensitive) { + curScannerChar = Character.toLowerCase(curScannerChar); + } + c.append(curScannerChar); + if (groupContent[i].indexOf(c.toString()) >= 0) { + return true; + } else if (i == elementSize) { + return false; + } else { + j= i+1; + while(j < elementSize && groupContent[j].indexOf(c.toString()) < 0) + { + j++; + } + if (j < elementSize || groupContent[j].indexOf(c.toString()) >= 0) { + for (int k = j-i-1; k> 0; k--) { + curScannerChar= (char) scanner.read(); + myStepCounter++; + if (curScannerChar == EOFChar) { + return false; + } + if (isCaseInSensitive) { + curScannerChar = Character.toLowerCase(curScannerChar); + } + c.append(curScannerChar); + i++; + } + } else { + return false; + } + } + } + return false; + } + + //copied from the superclass to provide a counter, what has read + protected boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) { + for (int i= 1; i < sequence.length; i++) { + curScannerChar= (char) scanner.read(); + myStepCounter++; + if (isCaseInSensitive) { + curScannerChar = Character.toLowerCase(curScannerChar); + } + if (curScannerChar == EOFChar && eofAllowed) { + return true; + } else if (curScannerChar != sequence[i]) { + return false; + } + } + return true; + } + + /* + * unwind the scanner to the orginal position + */ + + private final void unwindScanner(ICharacterScanner scanner) { + if (myStepCounter < 0) { + for (; myStepCounter < 0; myStepCounter++ ) + scanner.read(); + } else { + for (; myStepCounter > 0; myStepCounter--) + scanner.unread(); + } + } + +} Index: ColoringWhitespaceDetector.java =================================================================== RCS file: /cvsroot/e-p-i-c/org.epic.ext.cbg.editor/src/cbg/editor/rules/ColoringWhitespaceDetector.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- ColoringWhitespaceDetector.java 10 Jul 2004 07:55:13 -0000 1.5 +++ ColoringWhitespaceDetector.java 25 Dec 2004 08:35:03 -0000 1.6 @@ -1,22 +1,22 @@ -package cbg.editor.rules; - -import java.util.*; -import org.eclipse.jface.text.rules.IWhitespaceDetector; - -public class ColoringWhitespaceDetector implements IWhitespaceDetector { - - // TODO EPIC workaround - static private Map whitespaces = new HashMap(); - - // TODO Added by EPIC (workaround) - public static void addWhiteSpaceChar(String whitespaceChar) { - whitespaces.put(whitespaceChar, ""); - } - - public boolean isWhitespace(char c) { - // TODO Added by EPIC (workaround) - //return Character.isWhitespace(c); - return Character.isWhitespace(c) || whitespaces.get(String.valueOf(c)) != null; - } - -} +package cbg.editor.rules; + +import java.util.*; +import org.eclipse.jface.text.rules.IWhitespaceDetector; + +public class ColoringWhitespaceDetector implements IWhitespaceDetector { + + // TODO EPIC workaround + static private Map whitespaces = new HashMap(); + + // TODO Added by EPIC (workaround) + public void addWhiteSpaceChar(String whitespaceChar) { + whitespaces.put(whitespaceChar, ""); + } + + public boolean isWhitespace(char c) { + // TODO Added by EPIC (workaround) + //return Character.isWhitespace(c); + return Character.isWhitespace(c) || whitespaces.get(String.valueOf(c)) != null; + } + +} Index: StarRule.java =================================================================== RCS file: /cvsroot/e-p-i-c/org.epic.ext.cbg.editor/src/cbg/editor/rules/StarRule.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- StarRule.java 10 Jul 2004 07:55:13 -0000 1.5 +++ StarRule.java 25 Dec 2004 08:35:03 -0000 1.6 @@ -1,265 +1,264 @@ -package cbg.editor.rules; -import org.eclipse.jface.text.rules.ICharacterScanner; -import org.eclipse.jface.text.rules.IPredicateRule; -import org.eclipse.jface.text.rules.IToken; -import org.eclipse.jface.text.rules.IWhitespaceDetector; -import org.eclipse.jface.text.rules.IWordDetector; -import org.eclipse.jface.text.rules.Token; -import cbg.editor.ColoringPartitionScanner; -import cbg.editor.jedit.Mark; -public class StarRule implements IPredicateRule { - protected boolean isPrevious, excludeMatch, atLineStart; - protected char[] text; - protected static final int UNDEFINED = -1; - /** The token to be returned on success */ - protected IToken fToken; - /** The pattern's column constrain */ - protected int fColumn = UNDEFINED; - /** The pattern's escape character */ - protected char fEscapeCharacter; - /** Indicates whether end of line termines the pattern */ - protected boolean fBreaksOnEOL; - protected IWhitespaceDetector whiteDetector; - protected IWordDetector wordDetector; - private boolean atWhitepsaceEnd; - public StarRule(Mark mark, IWhitespaceDetector whitespace, IWordDetector word, IToken success) { - isPrevious = mark.isMarkPrevious(); - excludeMatch = mark.getExcludeMatch(); - atLineStart = mark.isAtLineStart(); - atWhitepsaceEnd = mark.atWhitespaceEnd(); - text = mark.getText().toCharArray(); - this.whiteDetector = whitespace; - this.wordDetector = word; - fToken = success; - } - /** - * Sets a column constraint for this rule. If set, the rule's token - * will only be returned if the pattern is detected starting at the - * specified column. If the column is smaller then 0, the column - * constraint is considered removed. - * - * @param column the column in which the pattern starts - */ - public void setColumnConstraint(int column) { - if (column < 0) - column = UNDEFINED; - fColumn = column; - } - /** - * Evaluates this rules without considering any column constraints. - * - * @param scanner the character scanner to be used - * @return the token resulting from this evaluation - */ - protected IToken doEvaluate(ICharacterScanner scanner) { - if (isPrevious) - return doEvaluatePrevious(scanner, false); - return doEvaluateFollowing(scanner, false); - } - /** - * Evaluates this rules without considering any column constraints. Resumes - * detection, i.e. looks only for the end sequence required by this rule if the - * <code>resume</code> flag is set. - * - * @param scanner the character scanner to be used - * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise - * @return the token resulting from this evaluation - * @since 2.0 - */ - protected IToken doEvaluatePrevious(ICharacterScanner scanner, boolean resume) { - if (resume) { - if (sequenceDetectedPrevious(scanner, false)) - return fToken; - } else { - char c = (char) scanner.read(); - /* Mark Previous :: c is either the end of the pattern, - * some other char, EOL, whitespace or EOF */ - if (c == ICharacterScanner.EOF) - return Token.UNDEFINED; - if (c == text[0]) { - if (sequenceDetectedPrevious(scanner, false)) - return fToken; - } - } - scanner.unread(); - return Token.UNDEFINED; - } - /** - * Evaluates this rules without considering any column constraints. Resumes - * detection, i.e. looks only for the end sequence required by this rule if the - * <code>resume</code> flag is set. - * - * @param scanner the character scanner to be used - * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise - * @return the token resulting from this evaluation - * @since 2.0 - */ - protected IToken doEvaluateFollowing(ICharacterScanner scanner, boolean resume) { - if (resume) { - if (sequenceDetectedFollowing(scanner, false)) - return fToken; - } else { - char c = (char) scanner.read(); - /* Mark Previous :: c is either the end of the pattern, - * some other char, EOL, whitespace or EOF */ - if (c == ICharacterScanner.EOF) - return Token.UNDEFINED; - if (c == text[0]) { - if (sequenceDetectedFollowing(scanner, false)) - return fToken; - } - } - scanner.unread(); - return Token.UNDEFINED; - } - /* - * @see IRule#evaluate - */ - public IToken evaluate(ICharacterScanner aScanner) { - IToken answer = evaluate(aScanner, false); - if (answer == Token.UNDEFINED) - return Token.UNDEFINED; - if (!(aScanner instanceof ColoringPartitionScanner)) - return answer; - ColoringPartitionScanner scanner = (ColoringPartitionScanner) aScanner; - if (isPrevious) { - int tokenLength = startOfToken(scanner); - scanner.moveTokenOffset(- (tokenLength - text.length)); - // scanner.markLength = excludeMatch ? tokenLength - text.length: tokenLength; - scanner.setMarkLength(tokenLength); - } - return answer; - } - private int startOfToken(ColoringPartitionScanner scanner) { - int original = scanner.getOffset(); - scanner.backup(); // this backs up to the MARK tag, for example ( - int c = scanner.backup(); - while (c != ICharacterScanner.EOF && !whiteDetector.isWhitespace((char) c) && wordDetector.isWordPart((char) c)) { - c = scanner.backup(); - } - int start = scanner.getOffset(); - // Restore the offset - scanner.setOffset(original); - return start == 0 ? original - start : original - start - 1; - } - /** - * Returns whether the next characters to be read by the character scanner - * are an exact match with the given sequence. No escape characters are allowed - * within the sequence. If specified the sequence is considered to be found - * when reading the EOF character. - * - * @param scanner the character scanner to be used - * @param sequence the sequence to be detected - * @param eofAllowed indicated whether EOF terminates the pattern - * @return <code>true</code> if the given sequence has been detected - */ - protected boolean sequenceDetectedFollowing(ICharacterScanner scanner, boolean eofAllowed) { - int c; - int read = 1; - for (; read < text.length; read++) { - c = scanner.read(); - if (c == ICharacterScanner.EOF && eofAllowed) { - return true; - } else if (c != text[read]) { - // Non-matching character detected, rewind the scanner back to the start. - // Do not unread the first character. - scanner.unread(); - for (int j = read - 1; j > 0; j--) - scanner.unread(); - return false; - } - } - - // Inserted by EPIC -- START - if (atWhitepsaceEnd) { - c = scanner.read(); - scanner.unread(); - //TODO EPIC specific SHOULD BE REMOVED if it works correct in ColorEditor - if (whiteDetector.isWhitespace((char) c) || c == ICharacterScanner.EOF) { - scanner.unread(); // <-- EPIC: Rewind scanner if whitespace character - return true; - } - for (int j = read - 1; j > 0; j--) - scanner.unread(); - return false; - } - // Inserted by EPIC -- END - - // scan until we hit whitespace or EOF - read = 1; - c = scanner.read(); - while(c != ICharacterScanner.EOF) { - if (whiteDetector.isWhitespace((char) c) || c == ICharacterScanner.EOF) { - scanner.unread(); - return true; - } - c = scanner.read(); - read++; - } - // Non-matching character detected, rewind the scanner back to the start. - // Do not unread the first character. - scanner.unread(); - for (int j = read - 1; j > 0; j--) - scanner.unread(); - return false; - } - /** - * Returns whether the next characters to be read by the character scanner - * are an exact match with the given sequence. No escape characters are allowed - * within the sequence. If specified the sequence is considered to be found - * when reading the EOF character. - * - * @param scanner the character scanner to be used - * @param sequence the sequence to be detected - * @param eofAllowed indicated whether EOF terminates the pattern - * @return <code>true</code> if the given sequence has been detected - */ - protected boolean sequenceDetectedPrevious(ICharacterScanner scanner, boolean eofAllowed) { - int c; - int read = 1; - for (; read < text.length; read++) { - c = scanner.read(); - if (c == ICharacterScanner.EOF && eofAllowed) { - return true; - } else if (c != text[read]) { - // Non-matching character detected, rewind the scanner back to the start. - // Do not unread the first character. - scanner.unread(); - for (int j = read - 1; j > 0; j--) - scanner.unread(); - return false; - } - } - if (atWhitepsaceEnd) { - c = scanner.read(); - scanner.unread(); - if (whiteDetector.isWhitespace((char) c) || c == ICharacterScanner.EOF) - return true; - for (int j = read - 1; j > 0; j--) - scanner.unread(); - return false; - } - return true; - } - /* - * @see IPredicateRule#evaluate(ICharacterScanner, boolean) - * @since 2.0 - */ - public IToken evaluate(ICharacterScanner scanner, boolean resume) { - if (fColumn == UNDEFINED) - return isPrevious ? doEvaluatePrevious(scanner, resume) : doEvaluateFollowing(scanner, resume); - int c = scanner.read(); - scanner.unread(); - if (c == text[0]) - return (fColumn == scanner.getColumn() ? (isPrevious ? doEvaluatePrevious(scanner, resume) : doEvaluateFollowing(scanner, resume)) : Token.UNDEFINED); - else - return Token.UNDEFINED; - } - /* - * @see IPredicateRule#getSuccessToken() - * @since 2.0 - */ - public IToken getSuccessToken() { - return fToken; - } -} +package cbg.editor.rules; +import org.eclipse.jface.text.rules.ICharacterScanner; +import org.eclipse.jface.text.rules.IPredicateRule; +import org.eclipse.jface.text.rules.IToken; +import org.eclipse.jface.text.rules.IWhitespaceDetector; +import org.eclipse.jface.text.rules.IWordDetector; +import org.eclipse.jface.text.rules.Token; +import cbg.editor.ColoringPartitionScanner; +import cbg.editor.jedit.Mark; +public class StarRule implements IPredicateRule { + protected boolean isPrevious, excludeMatch, atLineStart; + protected char[] text; + protected static final int UNDEFINED = -1; + /** The token to be returned on success */ + protected IToken fToken; + /** The pattern's column constrain */ + protected int fColumn = UNDEFINED; + /** The pattern's escape character */ + protected char fEscapeCharacter; + /** Indicates whether end of line termines the pattern */ + protected boolean fBreaksOnEOL; + protected IWhitespaceDetector whiteDetector; + protected IWordDetector wordDetector; + private boolean atWhitepsaceEnd; + public StarRule(Mark mark, IWhitespaceDetector whitespace, IWordDetector word, IToken success) { + isPrevious = mark.isMarkPrevious(); + excludeMatch = mark.getExcludeMatch(); + atLineStart = mark.isAtLineStart(); + atWhitepsaceEnd = mark.atWhitespaceEnd(); + text = mark.getText().toCharArray(); + this.whiteDetector = whitespace; + this.wordDetector = word; + fToken = success; + } + /** + * Sets a column constraint for this rule. If set, the rule's token + * will only be returned if the pattern is detected starting at the + * specified column. If the column is smaller then 0, the column + * constraint is considered removed. + * + * @param column the column in which the pattern starts + */ + public void setColumnConstraint(int column) { + if (column < 0) + column = UNDEFINED; + fColumn = column; + } + /** + * Evaluates this rules without considering any column constraints. + * + * @param scanner the character scanner to be used + * @return the token resulting from this evaluation + */ + protected IToken doEvaluate(ICharacterScanner scanner) { + if (isPrevious) + return doEvaluatePrevious(scanner, false); + return doEvaluateFollowing(scanner, false); + } + /** + * Evaluates this rules without considering any column constraints. Resumes + * detection, i.e. looks only for the end sequence required by this rule if the + * <code>resume</code> flag is set. + * + * @param scanner the character scanner to be used + * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise + * @return the token resulting from this evaluation + * @since 2.0 + */ + protected IToken doEvaluatePrevious(ICharacterScanner scanner, boolean resume) { + if (resume) { + if (sequenceDetectedPrevious(scanner, false)) + return fToken; + } else { + char c = (char) scanner.read(); + /* Mark Previous :: c is either the end of the pattern, + * some other char, EOL, whitespace or EOF */ + if (c == ICharacterScanner.EOF) + return Token.UNDEFINED; + if (c == text[0]) { + if (sequenceDetectedPrevious(scanner, false)) + return fToken; + } + } + scanner.unread(); + return Token.UNDEFINED; + } + /** + * Evaluates this rules without considering any column constraints. Resumes + * detection, i.e. looks only for the end sequence required by this rule if the + * <code>resume</code> flag is set. + * + * @param scanner the character scanner to be used + * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise + * @return the token resulting from this evaluation + * @since 2.0 + */ + protected IToken doEvaluateFollowing(ICharacterScanner scanner, boolean resume) { + if (resume) { + if (sequenceDetectedFollowing(scanner, false)) + return fToken; + } else { + char c = (char) scanner.read(); + /* Mark Previous :: c is either the end of the pattern, + * some other char, EOL, whitespace or EOF */ + if (c == ICharacterScanner.EOF) + return Token.UNDEFINED; + if (c == text[0]) { + if (sequenceDetectedFollowing(scanner, false)) + return fToken; + } + } + scanner.unread(); + return Token.UNDEFINED; + } + /* + * @see IRule#evaluate + */ + public IToken evaluate(ICharacterScanner aScanner) { + IToken answer = evaluate(aScanner, false); + if (answer == Token.UNDEFINED) + return Token.UNDEFINED; + if (!(aScanner instanceof ColoringPartitionScanner)) + return answer; + ColoringPartitionScanner scanner = (ColoringPartitionScanner) aScanner; + if (isPrevious) { + int tokenLength = startOfToken(scanner); + scanner.moveTokenOffset(- (tokenLength - text.length)); + // scanner.markLength = excludeMatch ? tokenLength - text.length: tokenLength; + scanner.setMarkLength(tokenLength); + } + return answer; + } + private int startOfToken(ColoringPartitionScanner scanner) { + int original = scanner.getOffset(); + scanner.backup(); // this backs up to the MARK tag, for example ( + int c = scanner.backup(); + while (c != ICharacterScanner.EOF && !whiteDetector.isWhitespace((char) c) && wordDetector.isWordPart((char) c)) { + c = scanner.backup(); + } + int start = scanner.getOffset(); + // Restore the offset + scanner.setOffset(original); + return start == 0 ? original - start : original - start - 1; + } + /** + * Returns whether the next characters to be read by the character scanner + * are an exact match with the given sequence. No escape characters are allowed + * within the sequence. If specified the sequence is considered to be found + * when reading the EOF character. + * + * @param scanner the character scanner to be used + * @param sequence the sequence to be detected + * @param eofAllowed indicated whether EOF terminates the pattern + * @return <code>true</code> if the given sequence has been detected + */ + protected boolean sequenceDetectedFollowing(ICharacterScanner scanner, boolean eofAllowed) { + int c; + int read = 1; + for (; read < text.length; read++) { + c = scanner.read(); + if (c == ICharacterScanner.EOF && eofAllowed) { + return true; + } else if (c != text[read]) { + // Non-matching character detected, rewind the scanner back to the start. + // Do not unread the first character. + scanner.unread(); + for (int j = read - 1; j > 0; j--) + scanner.unread(); + return false; + } + } + + // Inserted by EPIC -- START + if (atWhitepsaceEnd) { + c = scanner.read(); + scanner.unread(); + //TODO EPIC specific SHOULD BE REMOVED if it works correct in ColorEditor + if (whiteDetector.isWhitespace((char) c) || c == ICharacterScanner.EOF) { + scanner.unread(); // <-- EPIC: Rewind scanner if whitespace character + return true; + } + for (int j = read - 1; j > 0; j--) + scanner.unread(); + return false; + } + // Inserted by EPIC -- END + + // scan until we hit whitespace or EOF + read = 1; + c = scanner.read(); + while(c != ICharacterScanner.EOF) { + if (whiteDetector.isWhitespace((char) c) || c == ICharacterScanner.EOF) { + scanner.unread(); + return true; + } + c = scanner.read(); + read++; + } + // Non-matching character detected, rewind the scanner back to the start. + // Do not unread the first character. + for (int j = read - 1; j > 0; j--) + scanner.unread(); + return false; + } + /** + * Returns whether the next characters to be read by the character scanner + * are an exact match with the given sequence. No escape characters are allowed + * within the sequence. If specified the sequence is considered to be found + * when reading the EOF character. + * + * @param scanner the character scanner to be used + * @param sequence the sequence to be detected + * @param eofAllowed indicated whether EOF terminates the pattern + * @return <code>true</code> if the given sequence has been detected + */ + protected boolean sequenceDetectedPrevious(ICharacterScanner scanner, boolean eofAllowed) { + int c; + int read = 1; + for (; read < text.length; read++) { + c = scanner.read(); + if (c == ICharacterScanner.EOF && eofAllowed) { + return true; + } else if (c != text[read]) { + // Non-matching character detected, rewind the scanner back to the start. + // Do not unread the first character. + scanner.unread(); + for (int j = read - 1; j > 0; j--) + scanner.unread(); + return false; + } + } + if (atWhitepsaceEnd) { + c = scanner.read(); + scanner.unread(); + if (whiteDetector.isWhitespace((char) c) || c == ICharacterScanner.EOF) + return true; + for (int j = read - 1; j > 0; j--) + scanner.unread(); + return false; + } + return true; + } + /* + * @see IPredicateRule#evaluate(ICharacterScanner, boolean) + * @since 2.0 + */ + public IToken evaluate(ICharacterScanner scanner, boolean resume) { + if (fColumn == UNDEFINED) + return isPrevious ? doEvaluatePrevious(scanner, resume) : doEvaluateFollowing(scanner, resume); + int c = scanner.read(); + scanner.unread(); + if (c == text[0]) + return (fColumn == scanner.getColumn() ? (isPrevious ? doEvaluatePrevious(scanner, resume) : doEvaluateFollowing(scanner, resume)) : Token.UNDEFINED); + else + return Token.UNDEFINED; + } + /* + * @see IPredicateRule#getSuccessToken() + * @since 2.0 + */ + public IToken getSuccessToken() { + return fToken; + } +} --- NEW FILE: ExtendedPatternRule.java --- package cbg.editor.rules; /** * This class extends the given Patternrule by using either CaseSensitive, * MultipleMatch, BracketMatch or Dynamic-Tagging. The given parameters * specify the usage of this class more precesily. * * @author LeO * @version .1 * @change Dec, 12, 2004 * TODO ???? */ import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.IWhitespaceDetector; import org.eclipse.jface.text.rules.PatternRule; import org.eclipse.jface.text.rules.Token; import cbg.editor.ColoringPartitionScanner; public class ExtendedPatternRule extends PatternRule { private char openingBracket; private char closingBracket; private String[] groupContent; private boolean isExistingGroup, isBracketMatch, isMultiple, isCaseInSensitive, isDynamicTagging; private int myStepCounter = 0; private int noMultipleEndTag; private boolean requireEndTag; private char curScannerChar; private final char EOFChar= (char) ICharacterScanner.EOF; private int noDynamicDelimiterChars=0; private final String requireBeforeTag, requireAfterTag, dynamicIgnore; private boolean continueCheck = true; private IWhitespaceDetector whiteSpace; public ExtendedPatternRule(String startSequence, String endSequence, IToken token, char escapeCharacter, boolean breaksOnEOL, int noMaxChar, String[] groupContent, boolean bracketMatch, int noMultipleEndTag, boolean requireEndTag, boolean CaseInSensitive, boolean isDynamicTagging, String beforeTag, String afterTag, IWhitespaceDetector whiteSpace) { //the last parameter makes a default handling, //i.e. if the End-Tag is missing => mark till the end of File super (startSequence, endSequence, token, escapeCharacter, breaksOnEOL,true); this.isBracketMatch=bracketMatch; if (isBracketMatch) { if (endSequence.indexOf("}") >= 0) { closingBracket = '}'; openingBracket = '{'; }else if (endSequence.indexOf(")") >= 0) { closingBracket = ')'; openingBracket = '('; }else if (endSequence.indexOf("]") >= 0) { closingBracket = ']'; openingBracket = '['; }else if (endSequence.indexOf(">") >= 0) { closingBracket = '>'; openingBracket = '<'; } } this.groupContent = groupContent; if (groupContent == null) { isExistingGroup = false; } else { isExistingGroup = true; } this.requireEndTag = requireEndTag; this.noDynamicDelimiterChars = noMaxChar; isCaseInSensitive = CaseInSensitive; //TODO check if it really required, i.e. lowercase = uppercase dynamicIgnore = endSequence; this.isDynamicTagging = isDynamicTagging; if (isDynamicTagging) { isCaseInSensitive = false; //case-sensitive is nonsense with dynamic Tags } this.requireBeforeTag = beforeTag; //Programmers lazyness: we check only if content will exists!!! this.requireAfterTag = afterTag; if (isCaseInSensitive) { //rewrite the values for caseInSensitive!!! fStartSequence= startSequence.toLowerCase().toCharArray(); fEndSequence= (endSequence == null ? new char[0] : endSequence.toLowerCase().toCharArray()); } this.noMultipleEndTag = noMultipleEndTag; if (noMultipleEndTag > 1 || isDynamicTagging) { isMultiple = true; } this.whiteSpace= whiteSpace; } /* Copied from my superclass and modified to support case sensitivity. */ protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { continueCheck = true; IToken myResultToken=Token.UNDEFINED; myStepCounter = 0; if (resume) { if (isBracketMatch || isMultiple) { //we have to search back to the beginning of the partion and then start the scanning!!! unwindToStartToken(scanner); } else { if (endSequenceDetected(scanner)) { return fToken; } else { continueCheck = false; } } } else { if (isDynamicTagging) { if (((ColoringPartitionScanner) scanner).getOffset() > 0) { scanner.unread(); curScannerChar = (char) scanner.read(); if (!whiteSpace.isWhitespace(curScannerChar)) { //we do not check anything, since the leading char before this is not //whitespace or equivalent, so we could assume a single keyword for //dynamic tagging!!! continueCheck = false; } } } } if (continueCheck) { if (isExistingGroup) { if (forwardStartSequenceDetected(scanner)) { if (endCheck(scanner, resume)) { return fToken; } } } else { //check from the regular startSequence curScannerChar= (char) scanner.read(); myStepCounter++; if (isCaseInSensitive) { curScannerChar = Character.toLowerCase(curScannerChar); } if (curScannerChar == fStartSequence[0]) { if (sequenceDetected(scanner, fStartSequence, fBreaksOnEOF)) { if (endCheck(scanner, resume)) { return fToken; } } } } } unwindScanner(scanner); return myResultToken; } /* * This method is mainly for simple handling of the doEvaluate-issue */ private final boolean endCheck(ICharacterScanner scanner, boolean resume) { boolean myIsBracketMatch=isBracketMatch; if (isDynamicTagging) { myIsBracketMatch = retrieveDynamicEndTag(scanner); if (fEndSequence.length == 0) { return false; } } if (isBracketMatch || myIsBracketMatch) { if (resume) { //we have to search back to the beginning of the partion and then start the scanning!!! unwindToStartToken(scanner); } else { //rewind the scanner, so we can also take care about brackets in the fStartSequence unwindScanner(scanner); } } if (isBracketMatch) { return (endBracketSequenceDetected(scanner) && myStepCounter >= 0); } else if (isMultiple) { return (multipleEndSequenceDetected(scanner, myIsBracketMatch) && myStepCounter >= 0); } else if (myIsBracketMatch) { //from dynamic with only one return (endBracketSequenceDetected(scanner) && myStepCounter >= 0); } else { return (endSequenceDetected(scanner) && myStepCounter >= 0); } } private final boolean retrieveDynamicEndTag(ICharacterScanner scanner) { StringBuffer tmpEnd=new StringBuffer(); curScannerChar = (char) scanner.read(); myStepCounter++; int thisCounter = noDynamicDelimiterChars; while (Character.isWhitespace(curScannerChar) && curScannerChar != EOFChar) { curScannerChar = (char) scanner.read(); myStepCounter++; } while (--thisCounter >= 0 && !Character.isWhitespace(curScannerChar) && !(requireBeforeTag.length() == 0 && Character.isLetterOrDigit(curScannerChar)) && curScannerChar != EOFChar ) { if (dynamicIgnore.indexOf(curScannerChar) < 0) { tmpEnd.append(curScannerChar); } curScannerChar = (char) scanner.read(); myStepCounter++; } scanner.unread(); myStepCounter--; fEndSequence = tmpEnd.toString().toCharArray(); if (fEndSequence.length == 1) { if (fEndSequence[0] == '{') { openingBracket = '{'; closingBracket = '}'; return true; } else if (fEndSequence[0] == '(') { openingBracket = '('; closingBracket = ')'; return true; } else if (fEndSequence[0] == '[') { openingBracket = '['; closingBracket = ']'; return true; } else if (fEndSequence[0] == '<') { openingBracket = '<'; closingBracket = '>'; return true; } } return false; } private final boolean forwardStartSequenceDetected(ICharacterScanner scanner) { StringBuffer c = new StringBuffer(); int i=0; int j=0; int elementSize=0; elementSize = groupContent.length - 1; String escape= groupContent[0]; c.append(escape); while (i++ <= elementSize) { curScannerChar= (char) scanner.read(); myStepCounter++; if (curScannerChar == EOFChar) { return false; } if (isCaseInSensitive) { curScannerChar = Character.toLowerCase(curScannerChar); } c.append(curScannerChar); if (groupContent[i].indexOf(c.toString()) >= 0) { return true; } else if (i == elementSize) { return false; } else { j= i+1; while(j < elementSize && groupContent[j].indexOf(c.toString()) < 0) { j++; } if (j < elementSize || groupContent[j].indexOf(c.toString()) >= 0) { for (int k = j-i-1; k> 0; k--) { curScannerChar= (char) scanner.read(); myStepCounter++; if (curScannerChar == EOFChar) { return false; } if (isCaseInSensitive) { curScannerChar = Character.toLowerCase(curScannerChar); } c.append(curScannerChar); i++; } } else { return false; } } } return false; } private final void unwindToStartToken(ICharacterScanner scanner) { int scannerOffset = ((ColoringPartitionScanner) scanner).getOffset(); int tokenOffset = ((ColoringPartitionScanner) scanner).getTokenOffset(); for (int i= scannerOffset - tokenOffset; i> 0; i--) { scanner.unread(); myStepCounter--; } if (isMultiple) { //forward the scanner after the detected Sequence, to prevent counting the chars in StartSequence if (isExistingGroup) { forwardStartSequenceDetected(scanner); } else { for (int i=fStartSequence.length ; i >0; i--) { scanner.read(); myStepCounter++; } } } } /** * @param scanner */ public boolean multipleEndSequenceDetected(ICharacterScanner scanner, boolean dynamicBrackets) { int count= noMultipleEndTag; boolean resultEndSearch=true; while (--count >= 0 && resultEndSearch) { if (dynamicBrackets) { resultEndSearch = endBracketSequenceDetected(scanner); } else { resultEndSearch = endSequenceDetected(scanner); } } if (count < 0) { return true; } return false; } /** * Search a matching Bracket from the current scanner-postion. Ignore a Bracket with leading * Escape-Char.<p> * Note: Bracket are NOT case-senstive!!! * * @author LeO * @param scanner * @return true => found the matching Brackets * @since 11 Nov 2004 * @version 0.1 */ protected boolean endBracketSequenceDetected(ICharacterScanner scanner) { int pairs = 0; boolean previousWasEscapeCharacter=false; char[][] delimiters= scanner.getLegalLineDelimiters(); while ((curScannerChar=(char) scanner.read()) != EOFChar) { myStepCounter++; if (curScannerChar == fEscapeCharacter) { // Skip the escaped character. scanner.read(); myStepCounter++; previousWasEscapeCharacter = true; } else { if (curScannerChar == closingBracket) { if (!previousWasEscapeCharacter && --pairs == 0) { return true; } } else if (curScannerChar == openingBracket){ if (!previousWasEscapeCharacter) { pairs++; } } else if (fBreaksOnEOL) { // Check for end of line since it can be used to terminate the pattern. for (int i= 0; i < delimiters.length; i++) { if (curScannerChar == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], fBreaksOnEOF)) return !requireEndTag; } } previousWasEscapeCharacter = false; } } return false; } /* * mainly from the super-class except a counter was introduced! */ protected boolean endSequenceDetected(ICharacterScanner scanner) { curScannerChar= (char) scanner.read(); if (isCaseInSensitive) { curScannerChar = Character.toLowerCase(curScannerChar); } ++myStepCounter; char[][] delimiters= scanner.getLegalLineDelimiters(); boolean previousWasEscapeCharacter = false; while (curScannerChar != EOFChar) { if (curScannerChar == fEscapeCharacter) { // Skip the escaped character. scanner.read(); ++myStepCounter; previousWasEscapeCharacter = true; } else if (fEndSequence.length > 0 && curScannerChar == fEndSequence[0]) { // Check if the specified end sequence has been found. if (sequenceDetected(scanner, fEndSequence, fBreaksOnEOF)) { if (isDynamicTagging && requireAfterTag.length() > 0) { /* * currently we only check for one character, i.e. LineFeed * this check is mainly done for the HERE-docs which terminates by * Linefeed. IFFF there is the need to check for more chars then * only one, then a special treatement has to be applied for the * Linefeed issue, since different plattforms, differnt Linefeeds as * well with crossPlattform-editing, e.g. on Windows editing a Unix-File */ curScannerChar = (char) scanner.read(); scanner.unread(); if (requireAfterTag.indexOf(curScannerChar) >= 0) { //TODO enhance the check to more than a one-char-check! return true; } else { //continue to read } } else { return true; } } } else if (fBreaksOnEOL) { // Check for end of line since it can be used to terminate the pattern. for (int i= 0; i < delimiters.length; i++) { if (curScannerChar == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], fBreaksOnEOF)) { if (!fEscapeContinuesLine || !previousWasEscapeCharacter) return !requireEndTag; } } previousWasEscapeCharacter = false; } curScannerChar= (char) scanner.read(); if (isCaseInSensitive) { curScannerChar = Character.toLowerCase(curScannerChar); } ++myStepCounter; } return fBreaksOnEOF; } //copied from the superclass to provide a counter, what has read protected boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) { for (int i= 1; i < sequence.length; i++) { curScannerChar= (char) scanner.read(); myStepCounter++; if (isCaseInSensitive) { curScannerChar = Character.toLowerCase(curScannerChar); } if (curScannerChar == EOFChar && eofAllowed) { return true; } else if (curScannerChar != sequence[i]) { return false; } } return true; } /* * unwind the scanner to the orginal position */ private final void unwindScanner(ICharacterScanner scanner) { if (myStepCounter < 0) { for (; myStepCounter < 0; myStepCounter++ ) scanner.read(); } else { for (; myStepCounter > 0; myStepCounter--) scanner.unread(); } } } |