Here 'tis. On 3/20/07, Mirko Stocker <[EMAIL PROTECTED]> wrote:
On Monday 19 March 2007 19:27:43 rover rhubarb wrote: > So this is all local at the moment, how can I best get it to you to > contribute it? Files? Diffs? Patches? Check in?I think the easiest way for us to take a look at your code would be to send patches / diffs, so we can review and apply it. You can also open a ticket[1] and append the patch there if you want. Thank you! Mirko [1] http://rubyeclipse.gr-ruby.org/newticket
Index: C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyPairMatcher.java =================================================================== --- C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyPairMatcher.java (revision 1938) +++ C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyPairMatcher.java (working copy) @@ -73,71 +73,59 @@ */ public void clear() { } - + + + /** + * Checks the current offset to see if it is a bracketing character or keyword, then returns + * true if it can find a matching pair for it. Importantly, it also sets the fields fStartPos and + * fEndPos to the first character of the opening bracket or keyword and the last character of the + * closing bracket or keyword, respectively. + * @return true if we can find a matching pair for the character or keyword at the current position. + */ protected boolean matchPairsAt() { - - int i; - int pairIndex1= fPairs.length; - int pairIndex2= fPairs.length; - fStartPos= -1; fEndPos= -1; - // get the char preceding the start position - try { - - char prevChar= fDocument.getChar(Math.max(fOffset - 1, 0)); - // search for opening peer character next to the activation point - for (i= 0; i < fPairs.length; i= i + 2) { - if (prevChar == fPairs[i]) { - fStartPos= fOffset - 1; - pairIndex1= i; - } - } - - // search for closing peer character next to the activation point - for (i= 1; i < fPairs.length; i= i + 2) { - if (prevChar == fPairs[i]) { - fEndPos= fOffset - 1; - pairIndex2= i; - } - } - - if (fEndPos > -1) { - fAnchor= RIGHT; - fStartPos= searchForOpeningPeer(fEndPos, fPairs[pairIndex2 - 1], fPairs[pairIndex2], fDocument); - if (fStartPos > -1) - return true; - else - fEndPos= -1; - } else if (fStartPos > -1) { - fAnchor= LEFT; - fEndPos= searchForClosingPeer(fStartPos, fPairs[pairIndex1], fPairs[pairIndex1 + 1], fDocument); - if (fEndPos > -1) - return true; - else - fStartPos= -1; - } - - } catch (BadLocationException x) { - } - + RubyHeuristicScanner scanner; + try { + scanner = new RubyHeuristicScanner(fDocument, IRubyPartitions.RUBY_PARTITIONING, + TextUtilities.getContentType(fDocument, IRubyPartitions.RUBY_PARTITIONING, fOffset, false)); + + String contentType = TextUtilities.getContentType(fDocument, IRubyPartitions.RUBY_PARTITIONING, fOffset, false); + if (contentType.equals(IRubyPartitions.RUBY_SINGLE_LINE_COMMENT) || + contentType.equals(IRubyPartitions.RUBY_MULTI_LINE_COMMENT)) { + return false; // don't try to match within comments + } + + int token = scanner.tokenAt(fOffset); // only returns a token if there really is one at the position + + if (RubyHeuristicScanner.isOpeningToken(token)) { + fStartPos = scanner.getPosition(); // scanner put the pos at the start in the tokenAt call + fAnchor= LEFT; + fEndPos = scanner.findClosingPeerToken(fStartPos, token); + if (fEndPos == RubyHeuristicScanner.NOT_FOUND) { + fStartPos = -1; + fEndPos = -1; + return false; + } + return true; + } + else if (RubyHeuristicScanner.isClosingToken(token)) { + fEndPos = scanner.getPosition(); + fAnchor = RIGHT; + fStartPos = scanner.findOpeningPeerToken(fEndPos, token); + if (fStartPos == RubyHeuristicScanner.NOT_FOUND) { + fStartPos = -1; + fEndPos = -1; + return false; + } + return true; + } + } catch (BadLocationException e) { + return false; + } + + // not on a token with a pair return false; } - - protected int searchForClosingPeer(int offset, char openingPeer, char closingPeer, IDocument document) throws BadLocationException { - RubyHeuristicScanner scanner= new RubyHeuristicScanner(document, IRubyPartitions.RUBY_PARTITIONING, TextUtilities.getContentType(document, IRubyPartitions.RUBY_PARTITIONING, offset, false)); - return scanner.findClosingPeer(offset + 1, openingPeer, closingPeer); - } - - - protected int searchForOpeningPeer(int offset, char openingPeer, char closingPeer, IDocument document) throws BadLocationException { - RubyHeuristicScanner scanner= new RubyHeuristicScanner(document, IRubyPartitions.RUBY_PARTITIONING, TextUtilities.getContentType(document, IRubyPartitions.RUBY_PARTITIONING, offset, false)); - int peer= scanner.findOpeningPeer(offset - 1, openingPeer, closingPeer); - if (peer == RubyHeuristicScanner.NOT_FOUND) - return -1; - return peer; - } - - } Index: C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyHeuristicScanner.java =================================================================== --- C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyHeuristicScanner.java (revision 1938) +++ C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyHeuristicScanner.java (working copy) @@ -10,7 +10,10 @@ *******************************************************************************/ package org.rubypeople.rdt.internal.ui.text; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; @@ -40,7 +43,137 @@ */ public static final int UNBOUND= -2; + + /** + * Pairs of tokens to be matched. + * This array is defined such that every second entry is a closing pair token for the entry bofore it, + * so only add entries in pairs. + */ + public static final int[] BRACKET_TOKENS = new int[] { TokenLBRACE, TokenRBRACE, + TokenLBRACKET, TokenRBRACKET, + TokenLPAREN, TokenRPAREN, + TokenDEF, TokenEND, + TokenDO, TokenEND, + TokenBEGIN, TokenEND, + TokenIF, TokenEND, + TokenUNLESS, TokenEND, + TokenCLASS, TokenEND, + TokenMODULE, TokenEND + }; + + /** A hashmap that associates tokens with their matching closing or opening tokens */ + private static HashMap fMatchingPeers; + + static { + fMatchingPeers = new HashMap(); + buildMatchMap(fMatchingPeers, true); + buildMatchMap(fMatchingPeers, false); + } + + /** + * Convenience method for stepping through the bracket tokens array, looking + * for a token either among the opening or the closing tokens. + */ + private static boolean _findBracketToken(int token, int startIndex, int step) { + for (int i = startIndex; i < BRACKET_TOKENS.length; i += step) { + if (token == BRACKET_TOKENS[i]) return true; + } + return false; + } + + /** + * Returns true if the token represents the opening or closing of a bracket or scope. + * E.g. {, }, [, ], (, def, class, begin, if, end, ... + * + * @param token the token to test + * @return true if it is a character or keyword that brackets a scope + */ + public static boolean isBracketToken(int token) { + return _findBracketToken(token, 0, 1); + } + + /** + * Returns true if the token represents the opening of a bracket or scope. + * E.g. {, [, (, def, class, begin, if, ... + * + * @param token the token to test + * @return true if it is a character or keyword that opens a scope + */ + public static boolean isOpeningToken(int token) { + return _findBracketToken(token, 0, 2); + } + + /** + * Returns true if the token represents the closing of a bracket or scope. + * E.g. }, ], ), end, ... + * + * @param token the token to test + * @return true if it is a character or keyword that closes a scope + */ + public static boolean isClosingToken(int token) { + return _findBracketToken(token, 1, 2); + } + + /** + * Builds up a map of tokens that close the scope opened by each token. + * If forward is false it builds a list of tokens that open each token. + * @param matchMap the hashmap to be filled + * @param forward true to build a map of closing tokens + */ + private static void buildMatchMap(HashMap matchMap, boolean forward) { + int startIndex, matchOffset; + if (forward) { + startIndex = 0; + matchOffset = 1; + } + else { + startIndex = 1; + matchOffset = -1; + } + + List matchList; + + for (int i= startIndex; i < BRACKET_TOKENS.length; i+= 2) { + int token = BRACKET_TOKENS[i]; + int matchingToken = BRACKET_TOKENS[i + matchOffset]; + + matchList = (ArrayList)matchMap.get(Integer.valueOf(token)); + if (matchList == null) { + matchList = new ArrayList(); + matchMap.put(Integer.valueOf(token), matchList); + } + matchList.add(Integer.valueOf(matchingToken)); + } + } + + /** + * Returns an arry of tokens that are either the opening or closing pairs for the specified token. + * For example: passing in TokenLBRACE (token for '{') will return an array of one element containing + * TokenRBRACE (token for '}'). + * Passing in TokenBEGIN (token for 'begin') will return an array of one element containing + * TokenEND (token for 'end'). + * Passing in TokenEND (token for 'begin') will return an array containing all of the tokens + * that open a scope that can end with 'end', such as: TokenBEGIN, TokenIF, TokenDO, etc. + * + * Note that in reality, passing in an opening token will only ever return a single element array, and so + * will passing in a closing token that is not TokenEND, but this method is designed to work generically + * anyway, so that any addition to the BRACKET_TOKENS arry will be handled properly. + * + * @param token the token whose pair is sought + * @return the set of tokens that can pair with the given token + */ + public static int[] getMatchingTokens(int token) { + List list = (List)fMatchingPeers.get(Integer.valueOf(token)); + int count = list.size(); + int[] intArray = new int[count]; + for (int i = 0; i < count; i++) { + intArray[i] = ((Integer)list.get(i)).intValue(); + } + Arrays.sort(intArray); + return intArray; + } + /* character constants */ private static final char LBRACE= '{'; private static final char RBRACE= '}'; @@ -53,7 +186,7 @@ private static final char RBRACKET= ']'; private static final char QUESTIONMARK= '?'; private static final char EQUAL= '='; - + /** * Specifies the stop condition, upon which the <code>scanXXX</code> methods will decide whether * to keep scanning or not. This interface may implemented by clients. @@ -97,6 +230,21 @@ } /** + * Stops upon a non-whitespace character but ignores end-of-line backslashes + * + * @see NonWhitespace + */ + private class NonWhitespaceSkipLineContinuationsDefaultPartition extends NonWhitespaceDefaultPartition { + /* + * @see org.eclipse.jdt.internal.ui.text.RubyHeuristicScanner.StopCondition#stop(char) + */ + public boolean stop(char ch, int position, boolean forward) { + return super.stop(ch, position, true) && + !(ch == '\\' && position == getLineEndOfOffset(position)); + } + } + + /** * Stops upon a non-java identifier (as defined by [EMAIL PROTECTED] Character#isRubyIdentifierPart(char)}) character. */ private static class NonRubyIdentifierPart implements StopCondition { @@ -121,6 +269,7 @@ return super.stop(ch, position, true) || !isDefaultPartition(position); } } + /** * Stops upon a character in the default partition that matches the given character list. @@ -238,6 +387,124 @@ } + /** + * Finds the token that closes the block starting at the given openingToken. + * E.g., given a '{', it will return the next '}'; given an 'if' it will return + * the next 'end' (unless the 'if' is a conditional modifier, having no 'end') + * + * The method is careful to track scope so that an 'end' which closes any other + * blocks along the way won't be returned. + * + * (This is actually tricky in Ruby because there are so many different ways to + * start a block that finishes with 'end') + * + * @param start the offset to start searching at + * @param openingToken the token that opens the block + * @return the offset of the last char of the closing token or NOT_FOUND + * @throws BadLocationException + */ + public int findClosingPeerToken(int start, final int openingToken) throws BadLocationException { + // there's only one closing token for this opening token, but there may be many + // other opening tokens for that closing token. + // E.g. DEF is closed by END, but the next END may be closing a BEGIN that was started in the meantime + + int closingToken = getMatchingTokens(openingToken)[0]; + int[] openers = getMatchingTokens(closingToken); + + int depth= 1; + + int token = tokenAt(start); + token = nextToken(getPosition(), UNBOUND); + start = getPosition(); + + while (true) { + token = nextToken(start, UNBOUND); + start = getPosition(); // updated by nextToken + if (token == TokenEOF) { + return NOT_FOUND; + } + else if (token == closingToken) { + // close off this scope + depth--; + if (depth == 0) { + // we're back at the outermost scope, so we're done + return start - 1; + } + } + else if (Arrays.binarySearch(openers, token) >= 0) { + // found another opener with the same end, open another scope + if (!isConditionalModifier(token, start, true)) { + // ignore it if it's a modifier like "puts x if (y);". + // So a standalone if or unless without an end doesnt open a new scope + depth++; + } + } + // else token is neither a an opener or closer, loop to the next one + } + } + + /** + * Finds the token, searching backward, that openss the block ending at the given closingToken. + * E.g., given a '}', it will return the next '{'; given an 'end' it will return + * the previous 'if' (skipping any 'if's that are conditional modifiers, having no 'end') + * + * The method is careful to track scope so that an 'end' which closes any other + * blocks along the way won't be returned. + * + * (This is actually tricky in Ruby because there are so many different ways to + * start a block that finishes with 'end') + * + * @param start the offset to start searching at + * @param closingToken the token that closes the block + * @return the offset of the last char of the opening token or NOT_FOUND + * @throws BadLocationException + */ + public int findOpeningPeerToken(int start, final int closingToken) throws BadLocationException { + // there could be a number of tokens that would open this closing token, particularly + // if it's a ruby "end" keyword, so we have look out other scopes being opened on the way + // to one of them. + // But for all those other potential openers, this is the only closer. + // If we have an END we might find a BEGIN to open it, butif we find another END before that BEGIN + // we open another scope with the END, close it with the BEGIN and keep searching. + + int[] openers = getMatchingTokens(closingToken); + + int depth= 1; + int token = tokenAt(start); + token = previousToken(getPosition(), UNBOUND); // skip back to before the closing token + start = getPosition(); + + while (true) { + + token = previousToken(start - 1, UNBOUND); + start = getPosition(); // updated by nextToken to the RHS of the found token + + if (token == TokenEOF) { + return NOT_FOUND; + } + else if (token == closingToken) { + // found another opener with the same end, open another scope + depth++; + + } + else if (Arrays.binarySearch(openers, token) >= 0) { + // Found an opener that matches our closer, close off this scope + // + if (!isConditionalModifier(token, start, false)) { + // ignore it if it's a modifier like "puts x if (y);". + // So a standalone if or unless without an end doesnt close a scope + depth--; + if (depth == 0) { + // we're back at the outermost scope, so we're done + return start; + } + } + + } + // else token is neither a an opener or closer, loop to the next one + } + } + /** The document being scanned. */ private IDocument fDocument; /** The partitioning being used for scanning. */ @@ -254,6 +521,7 @@ /* preset stop conditions */ private final StopCondition fNonWSDefaultPart= new NonWhitespaceDefaultPartition(); + private final StopCondition fNonWSContinuationDefaultPart= new NonWhitespaceSkipLineContinuationsDefaultPartition(); private final static StopCondition fNonWS= new NonWhitespace(); private final StopCondition fNonIdent= new NonRubyIdentifierPartDefaultPartition(); @@ -336,10 +604,12 @@ // assume an ident or keyword int from= pos, to; pos= scanForward(pos + 1, bound, fNonIdent); - if (pos == NOT_FOUND) + if (pos == NOT_FOUND) { to= bound == UNBOUND ? fDocument.getLength() : bound; - else + } + else { to= pos; + } String identOrKeyword; try { @@ -357,6 +627,86 @@ } /** + * Returns the token at the current position, starting just at the left of it. + * The return value is one of the constants defined in [EMAIL PROTECTED] Symbols}. + * After a call, [EMAIL PROTECTED] #getPosition()} will return the position just before the scanned token + * starts (i.e. the next position that will be scanned). + * + * @param start the first character position in the document to consider + * @param bound the first position not to consider any more + * @return a constant from [EMAIL PROTECTED] Symbols} describing the previous token + * @throws BadLocationException + */ + public int tokenAt(int start) throws BadLocationException { + if (start < 0 || start >= fDocument.getLength()) throw new BadLocationException(); + + // find the char under or to the left and only if it's nonWS, then we scan back the start of the token + // the trick here is to use the very close bound: start - 1 + int pos= scanBackward(start, start - 1, fNonWSDefaultPart); + + int token; + if (pos == NOT_FOUND) // whitespace so no token + return TokenEOF; // NO TOKEN here + + // we're right over a token, so the prevToken will be the current one +// fPos--; + + switch (fChar) { + case LBRACE: + return TokenLBRACE; + case RBRACE: + return TokenRBRACE; + case LBRACKET: + return TokenLBRACKET; + case RBRACKET: + return TokenRBRACKET; + case LPAREN: + return TokenLPAREN; + case RPAREN: + return TokenRPAREN; + case SEMICOLON: + return TokenSEMICOLON; + case COLON: + return TokenCOLON; + case COMMA: + return TokenCOMMA; + case QUESTIONMARK: + return TokenQUESTIONMARK; + case EQUAL: + return TokenEQUAL; + } + + // else + // FIXME Change calls to isJavaIdentifierPart to a custom method that does isRubyidentifierPart + if (Character.isJavaIdentifierPart(fChar)) { + // assume an ident or keyword + int from, to= pos + 1; + pos= scanBackward(pos - 1, UNBOUND, fNonIdent); + if (pos == NOT_FOUND) { + from= 0; + } else { + from= pos + 1; + // get the whole ident or keyword, just in case we started in the middle + to = pos= scanForward(from, UNBOUND, fNonIdent); + if (to == NOT_FOUND) + to= pos + 1; + } + + String identOrKeyword; + try { + identOrKeyword= fDocument.get(from, to - from); + } catch (BadLocationException e) { + return TokenEOF; + } + + return getToken(identOrKeyword); + + } + // operators, number literals etc + return TokenOTHER; + } + + /** * Returns the next token in backward direction, starting at <code>start</code>, and not extending * further than <code>bound</code>. The return value is one of the constants defined in [EMAIL PROTECTED] Symbols}. * After a call, [EMAIL PROTECTED] #getPosition()} will return the position just before the scanned token @@ -370,8 +720,6 @@ int pos= scanBackward(start, bound, fNonWSDefaultPart); if (pos == NOT_FOUND) return TokenEOF; - - fPos--; switch (fChar) { case LBRACE: @@ -404,11 +752,14 @@ // assume an ident or keyword int from, to= pos + 1; pos= scanBackward(pos - 1, bound, fNonIdent); - if (pos == NOT_FOUND) + if (pos == NOT_FOUND) { from= bound == UNBOUND ? 0 : bound + 1; - else + } else { from= pos + 1; + fPos = from; + } + String identOrKeyword; try { identOrKeyword= fDocument.get(from, to - from); @@ -416,6 +767,7 @@ return TokenEOF; } + return getToken(identOrKeyword); } @@ -442,6 +794,10 @@ case 3: if ("for".equals(s)) //$NON-NLS-1$ return TokenFOR; + if ("def".equals(s)) //$NON-NLS-1$ + return TokenDEF; + if ("end".equals(s)) //$NON-NLS-1$ + return TokenEND; break; case 4: if ("case".equals(s)) //$NON-NLS-1$ @@ -456,6 +812,8 @@ return TokenCLASS; if ("while".equals(s)) //$NON-NLS-1$ return TokenWHILE; + if ("begin".equals(s)) + return TokenBEGIN; //$NON-NLS-1$ break; case 6: if ("return".equals(s)) //$NON-NLS-1$ @@ -466,6 +824,8 @@ return TokenMODULE; if ("unless".equals(s)) //$NON-NLS-1$ return TokenUNLESS; + if ("rescue".equals(s)) //$NON-NLS-1$ + return TokenRESCUE; break; } return TokenIDENT; @@ -743,42 +1103,216 @@ return false; } + /** - * Checks if the line seems to be an open condition not followed by a block (i.e. an if, while, - * or for statement with just one following statement, see example below). - * + * Checks if the given token is a conditional modifier IF or UNLESS as opposed to the start of a block. + * In ruby, normal IFs and UNLESSes always need an END to close the block, even if their on one line, + * but modifiers are a special case where the conditional is at the end of the line. + * E.g. * <pre> - * if (condition) - * doStuff(); + * puts "foo" if (x > 1); * </pre> + * In this code there is no END for the IF. In all other cases there must be an END. * - * <p>Algorithm: if the last non-WS, non-Comment code on the line is an if (condition), while (condition), - * for( expression), do, else, and there is no statement after that </p> + * This method scans backward from the offset, which should be just before + * the IF or UNLESS, until it finds the first non-whitespace or the start of the line. + * If the first non-whitespace is a semicolon or the actual line start, it will return true. * - * @param position the insert position of the new character - * @param bound the lowest position to consider - * @return <code>true</code> if the code is a conditional statement or loop without a block, <code>false</code> otherwise + * It also handles line continuations where a line ends with a backslash: imagine these cases + * + * <pre> + * begin + * puts "dog" + * if (false); end + * </pre> + * and + * <pre> + * begin + * puts "dog" \ + * if (false); end + * </pre> + * + * The only difference is the backslash after dog (must be at the end of the line with no ws after it) + * In the first case the END is a match for the IF, but in the second case the IF is a conditional + * modifier on the "puts 'dog'" statement, because the previous line is continued, so the END matches + * the BEGIN higher up. + * + * If the token is not an IF or UNLESS, then false is returned. + * + * @param token the token that is to be tested as a conditional modifier (if or unless) + * @param offset the position anticipated to be the first text in the line - we scan back from there + * @param forward true if we were searching forward implying the the offset is at the end of the token + * + * @return <code>true</code> if there is no text between the offset and the start of the line or a semicolon */ - public boolean isBracelessBlockStart(int position, int bound) { - if (position < 1) - return false; - - switch (previousToken(position, bound)) { - case TokenDO: - case TokenELSE: - return true; - case TokenRPAREN: - position= findOpeningPeer(fPos, LPAREN, RPAREN); - if (position > 0) { - switch (previousToken(position - 1, bound)) { - case TokenIF: - case TokenFOR: - case TokenWHILE: - return true; - } - } + public boolean isConditionalModifier(int token, int offset, boolean forward) + { + if (token != TokenIF && token != TokenUNLESS) return false; // not a conditional + int safeOffset = offset; + if (forward) { + // scanning forward when the token was found, so the offset was at the end of the token + // we need to find the start of it. + previousToken(offset, UNBOUND); + offset = getPosition(); } - return false; + try { + int line = fDocument.getLineOfOffset(offset); + // lines can be continued with backslashes, so loop back to the real line + // number of the start of this logical line + while (line > 0 && isContinuedLine(line - 1)) { + line--; + } + + int startOfLine = fDocument.getLineInformation(line).getOffset(); + + int firstTextInLine = scanBackward(offset - 1, startOfLine, fNonWSContinuationDefaultPart); + if (firstTextInLine == NOT_FOUND) { + return false; // nothing on the line before the if/else + } + + // if the first non-ws char is a semicolon then we're at the start of the logical line and + // we haven't found anything else, so it's not a oconditional modifier + return fDocument.getChar(firstTextInLine) != ';'; + } catch (BadLocationException e) { + return false; // default to nothing special + } + finally { + // we don't actually want to change the position, we're just peeking here + fPos = safeOffset; + } } -} + + /** + * Returns the position of the end of the line containing the specified offset. + * @param offset some position in a line + * @return the end position of that line or zero if the offset is not valid + */ + private int getLineEndOfOffset(int offset) { + IRegion lineInfo; + try { + lineInfo = fDocument.getLineInformationOfOffset(offset); + } catch (BadLocationException e) { + return 0; + } + return lineInfo.getOffset() + lineInfo.getLength() - 1; + } + + /** + * Determines whether the specified line ends with a backslash indicating + * that it is continued beyond the line break. + * Note that ruby permits no whitespace after the \, it must be the last char on the line. + * + * @param line number of the line to test + * @return true if the line ends with a backslash (\) + */ + private boolean isContinuedLine(int line) + { + IRegion lineInfo; + try { + lineInfo = fDocument.getLineInformation(line); + int lineEnd = lineInfo.getOffset() + lineInfo.getLength() - 1; + char ch = fDocument.getChar(lineEnd); + return fDocument.getChar(lineEnd) == '\\' && isDefaultPartition(lineEnd); + } catch (BadLocationException e) { + return false; + } + } + + + // debug methods commented out +// +// // debug method returns a description of the location +// private String _locationToString(int pos) +// { +// StringBuffer buf = new StringBuffer(100); +// buf.append(pos + ": "); +// try { +// buf.append(fDocument.get(pos - 10, 10)); +// buf.append("^"); +// buf.append(fDocument.get(pos, 10)); +// } catch (BadLocationException e) { +// buf.append("BAD LOCATION"); +// } +// return buf.toString(); +// } +// +// // debug method returns the name of a token and its id +// static String _tokenToString(int token) +// { +// return _getTokenText(token) + " ("+token+")"; +// } +// +// // debug method returns the name of a token +// static String _getTokenText(int token) +// { +// switch (token) { +// case TokenEOF: +// return "eof"; +// case TokenLBRACE: +// return "{"; +// case TokenRBRACE: +// return "}"; +// case TokenLBRACKET: +// return "["; +// case TokenRBRACKET: +// return "]"; +// case TokenLPAREN: +// return "("; +// case TokenRPAREN: +// return ")"; +// case TokenSEMICOLON: +// return ";"; +// case TokenOTHER: +// return "OTHER"; +// case TokenCOLON: +// return ":"; +// case TokenQUESTIONMARK: +// return "?"; +// case TokenCOMMA: +// return ","; +// case TokenEQUAL: +// return "="; +// case TokenLESSTHAN: +// return "<"; +// case TokenGREATERTHAN: +// return ">"; +// case TokenIF: +// return "if"; +// case TokenDO: +// return "do"; +// case TokenFOR: +// return "for"; +// case TokenBEGIN: +// return "begin"; +// case TokenEND: +// return "end"; +// case TokenCASE: +// return "case"; +// case TokenELSE: +// return "else"; +// case TokenBREAK: +// return "break"; +// case TokenRESCUE: +// return "rescue"; +// case TokenWHILE: +// return "while"; +// case TokenRETURN: +// return "return"; +// case TokenSWITCH: +// return "switch"; +// case TokenUNLESS: +// return "unless"; +// case TokenCLASS: +// return "class"; +// case TokenMODULE: +// return "module"; +// case TokenIDENT: +// return "ident"; +// case TokenDEF: +// return "def"; +// default: +// return "UNKNOWN"; +// } +// } +} \ No newline at end of file Index: C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/Symbols.java =================================================================== --- C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/Symbols.java (revision 1938) +++ C:/ruby/rdtworkspace/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/Symbols.java (working copy) @@ -16,7 +16,7 @@ * @since 3.0 */ public interface Symbols { - // FIXME Add More Ruby keywords! + // FIXME Add More Ruby keywords! (Hint look in DefaultRubyParser) int TokenEOF= -1; int TokenLBRACE= 1; int TokenRBRACE= 2; @@ -48,4 +48,5 @@ int TokenCLASS= 1026; int TokenMODULE= 1027; int TokenIDENT= 2000; + int TokenDEF=2001; // TODO what number should this be? }
------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________ Rubyeclipse-development mailing list Rubyeclipse-development@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rubyeclipse-development