/* * 08/26/2004 * * TokenMakerBase.java - A base class for token makers. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.rsyntaxtextarea; import javax.swing.Action; import javax.swing.text.Segment; /** * Base class for token makers. * * @author Robert Futrell * @version 1.0 */ public abstract class TokenMakerBase implements TokenMaker { /** * The first token in the returned linked list. */ protected TokenImpl firstToken; /** * Used in the creation of the linked list. */ protected TokenImpl currentToken; /** * Used in the creation of the linked list. */ protected TokenImpl previousToken; /** * The factory that gives us our tokens to use. */ private TokenFactory tokenFactory; /** * Highlights occurrences of the current token in the editor, if it is * relevant. */ private OccurrenceMarker occurrenceMarker; /** * "0" implies this is the "main" language being highlighted. Positive * values imply various "secondary" or "embedded" languages, such as CSS * or JavaScript in HTML. While this value is non-zero, tokens will be * generated with this language index so they can (possibly) be painted * differently, so "embedded" languages can be rendered with a special * background. */ private int languageIndex; /** * Constructor. */ public TokenMakerBase() { firstToken = currentToken = previousToken = null; tokenFactory = new DefaultTokenFactory(); } /** * {@inheritDoc} */ public void addNullToken() { if (firstToken==null) { firstToken = tokenFactory.createToken(); currentToken = firstToken; } else { TokenImpl next = tokenFactory.createToken(); currentToken.setNextToken(next); previousToken = currentToken; currentToken = next; } currentToken.setLanguageIndex(languageIndex); } /** * Adds the token specified to the current linked list of tokens. * * @param segment <code>Segment</code> to get text from. * @param start Start offset in <code>segment</code> of token. * @param end End offset in <code>segment</code> of token. * @param tokenType The token's type. * @param startOffset The offset in the document at which this token * occurs. */ public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) { addToken(segment.array, start,end, tokenType, startOffset); } /** * {@inheritDoc} */ public void addToken(char[] array, int start, int end, int tokenType, int startOffset) { addToken(array, start, end, tokenType, startOffset, false); } /** * Adds the token specified to the current linked list of tokens. * * @param array The character array. * @param start The starting offset in the array. * @param end The ending offset in the array. * @param tokenType The token's type. * @param startOffset The offset in the document at which this token * occurs. * @param hyperlink Whether this token is a hyperlink. */ public void addToken(char[] array, int start, int end, int tokenType, int startOffset, boolean hyperlink) { if (firstToken==null) { firstToken = tokenFactory.createToken(array, start, end, startOffset, tokenType); currentToken = firstToken; // previous token is still null. } else { TokenImpl next = tokenFactory.createToken(array, start,end, startOffset, tokenType); currentToken.setNextToken(next); previousToken = currentToken; currentToken = next; } currentToken.setLanguageIndex(languageIndex); currentToken.setHyperlink(hyperlink); } /** * Returns the occurrence marker to use for this token maker. Subclasses * can override to use different implementations. * * @return The occurrence marker to use. */ protected OccurrenceMarker createOccurrenceMarker() { return new DefaultOccurrenceMarker(); } /** * Returns the closest {@link TokenTypes "standard" token type} for a given * "internal" token type (e.g. one whose value is <code>< 0</code>).<p> * * The default implementation returns <code>type</code> always, which * denotes that a mapping from internal token types to standard token types * is not defined; subclasses can override. * * @param type The token type. * @return The closest "standard" token type. */ public int getClosestStandardTokenTypeForInternalType(int type) { return type; } /** * Returns whether this programming language uses curly braces * ('<code>{</code>' and '<code>}</code>') to denote code blocks. * * The default implementation returns <code>false</code>; subclasses can * override this method if necessary. * * @param languageIndex The language index at the offset in question. * Since some <code>TokenMaker</code>s effectively have nested * languages (such as JavaScript in HTML), this parameter tells the * <code>TokenMaker</code> what sub-language to look at. * @return Whether curly braces denote code blocks. */ public boolean getCurlyBracesDenoteCodeBlocks(int languageIndex) { return false; } /** * Returns an action to handle "insert break" key presses (i.e. Enter). * The default implementation returns <code>null</code>. Subclasses * can override. * * @return The default implementation always returns <code>null</code>. */ public Action getInsertBreakAction() { return null; } /** * Returns the current language index. * * @return The current language index. * @see #setLanguageIndex(int) */ protected int getLanguageIndex() { return languageIndex; } /** * {@inheritDoc} */ public int getLastTokenTypeOnLine(Segment text, int initialTokenType) { // Last parameter doesn't matter if we're not painting. Token t = getTokenList(text, initialTokenType, 0); while (t.getNextToken()!=null) t = t.getNextToken(); return t.getType(); } /** * {@inheritDoc} */ public String[] getLineCommentStartAndEnd(int languageIndex) { return null; } /** * Returns whether tokens of the specified type should have "mark * occurrences" enabled for the current programming language. The default * implementation returns true if <tt>type</tt> is {@link Token#IDENTIFIER}. * Subclasses can override this method to support other token types, such * as {@link Token#VARIABLE}. * * @param type The token type. * @return Whether tokens of this type should have "mark occurrences" * enabled. */ public boolean getMarkOccurrencesOfTokenType(int type) { return type==Token.IDENTIFIER; } /** * {@inheritDoc} */ public OccurrenceMarker getOccurrenceMarker() { if (occurrenceMarker==null) { occurrenceMarker = createOccurrenceMarker(); } return occurrenceMarker; } /** * The default implementation returns <code>false</code> always. Languages * that wish to better support auto-indentation can override this method. * * @param token The token the previous line ends with. * @return Whether the next line should be indented. */ public boolean getShouldIndentNextLineAfter(Token token) { return false; } /** * Returns whether a character could be part of an "identifier" token * in a specific language. The default implementation returns * <code>true</code> for letters, numbers, and certain symbols. */ public boolean isIdentifierChar(int languageIndex, char ch) { return Character.isLetterOrDigit(ch) || ch=='_' || ch=='$'; } /** * The default implementation returns <code>false</code> always. * Subclasses that are highlighting a markup language should override this * method to return <code>true</code>. * * @return <code>false</code> always. */ public boolean isMarkupLanguage() { return false; } /** * Deletes the linked list of tokens so we can begin anew. This should * never have to be called by the programmer, as it is automatically * called whenever the user calls * {@link #getLastTokenTypeOnLine(Segment, int)} or * {@link #getTokenList(Segment, int, int)}. */ protected void resetTokenList() { firstToken = currentToken = previousToken = null; tokenFactory.resetAllTokens(); } /** * Sets the language index to assign to tokens moving forward. This * property is used to designate tokens as being in "secondary" languages * (such as CSS or JavaScript in HTML). * * @param languageIndex The new language index. A value of * <code>0</code> denotes the "main" language, any positive value * denotes a specific secondary language. Negative values will * be treated as <code>0</code>. * @see #getLanguageIndex() */ protected void setLanguageIndex(int languageIndex) { this.languageIndex = Math.max(0, languageIndex); } }