/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.editors.unified.colorizer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.TextAttribute; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; import com.aptana.ide.editors.UnifiedEditorsPlugin; import com.aptana.ide.editors.unified.UnifiedColorManager; import com.aptana.ide.editors.unified.UnifiedColorizerBase; import com.aptana.ide.lexer.IToken; import com.aptana.ide.lexer.Lexeme; import com.aptana.ide.parsing.IParseState; /** * Language colorizer * * @author Kevin Sawicki (ksawicki@aptana.com) */ public class LanguageColorizer extends UnifiedColorizerBase { /** * Hashes the token to store it internally * * @param token * @return - hash value, language + category + type */ public static String hashToken(IToken token) { return token.getLanguage() + "::" + token.getCategory() + "::" + token.getType(); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Fires an event noting that colorization settings have changed */ public static void fireColorizationEvent() { UnifiedEditorsPlugin.getDefault().getPreferenceStore().firePropertyChangeEvent("Colorization saved", //$NON-NLS-1$ "Colorization saved", "Colorization saved"); //$NON-NLS-1$ //$NON-NLS-2$ } private List<IColorizerHandler> handlers; private Map<String, TokenColorizer> tokenColorizers; private Map<String, CategoryColorizer> categoryColorizers; private TextAttribute DEFAULT; private String mimeType; private Color background; private Color selectionBg; private Color selectionFg; private Color caretColor; private Color lineHighlightColor; private Color foldingBg; private Color foldingFg; /** * Creates a new language colorizer for a mime type * * @param mimeType - * mime type of language */ public LanguageColorizer(String mimeType) { super(mimeType); this.mimeType = mimeType; tokenColorizers = new HashMap<String, TokenColorizer>(); categoryColorizers = new HashMap<String, CategoryColorizer>(); handlers = new ArrayList<IColorizerHandler>(); RGB fgRGB = new RGB(0, 0, 0); Color fgColor = UnifiedColorManager.getInstance().getColor(fgRGB); DEFAULT = new TextAttribute(fgColor, null, 0); background = null; selectionBg = null; selectionFg = null; caretColor = null; lineHighlightColor = null; } /** * Adds a handler to this language colorizer * * @param handler */ public void addHandler(IColorizerHandler handler) { this.handlers.add(handler); } /** * Gets the handlers for this language colorizer * * @return - list of colorizer handlers */ public List<IColorizerHandler> getHandlers() { return this.handlers; } /** * @see com.aptana.ide.editors.unified.UnifiedColorizerBase#getPluginPreferenceStore() */ protected IPreferenceStore getPluginPreferenceStore() { return UnifiedEditorsPlugin.getDefault().getPreferenceStore(); } /** * @see com.aptana.ide.editors.unified.UnifiedColorizerBase#initializeColorTables() */ protected void initializeColorTables() { } /** * @see com.aptana.ide.editors.unified.ILexemeColorMapper#createStyle(com.aptana.ide.parsing.IParseState, * com.aptana.ide.lexer.Lexeme, java.util.Vector) */ public void createStyle(IParseState parseState, Lexeme lx, Vector<StyleRange> styles) { IToken token = lx.getToken(); TokenColorizer tc = getTokenColorizer(token); IColorizerHandler handler = null; StyleRange handlerStyleRange = null; for (int i = 0; i < handlers.size(); i++) { handler = handlers.get(i); handlerStyleRange = handler.getStyleRange(parseState, lx); if (handlerStyleRange != null) { break; } } if (handlerStyleRange != null) { styles.add(handlerStyleRange); } else if (tc != null) { tc.colorize(styles, lx.offset, lx.length); } else if (categoryColorizers.containsKey(token.getCategory())) { CategoryColorizer colorizer = (CategoryColorizer) categoryColorizers.get(token.getCategory()); ColorizationStyle style = colorizer.getStyle(); int bold = style.isBold() ? SWT.BOLD : 0; int italic = style.isItalic() ? SWT.ITALIC : 0; StyleRange sr = new StyleRange(lx.offset, lx.length, style.getForegroundColor(), style.getBackgroundColor(), bold | italic); sr.underline = style.isUnderline(); styles.add(sr); } else { StyleRange sr = new StyleRange(lx.offset, lx.length, DEFAULT.getForeground(), DEFAULT.getBackground(), DEFAULT.getStyle()); styles.add(sr); } for (int i = 0; i < handlers.size(); i++) { handler = handlers.get(i); if (handler instanceof IExtendedColorizerHandler) { IExtendedColorizerHandler cm = (IExtendedColorizerHandler) handler; StyleRange[] styleRanges = cm.getStyleRanges(parseState, lx); if (styleRanges != null) { styles.addAll(Arrays.asList(styleRanges)); } } } } /** * Adds a token colorizer to this language * * @param colorizer - * token colorizer */ public void addTokenColorizer(TokenColorizer colorizer) { IToken token = colorizer.getToken(); tokenColorizers.put(hashToken(token), colorizer); } /** * Removes a token colorizer * * @param token * @return - removed colorizer */ public TokenColorizer removeTokenColorizer(IToken token) { TokenColorizer retVal = null; String key = hashToken(token); if (tokenColorizers.containsKey(key)) { retVal = (TokenColorizer) tokenColorizers.remove(key); } return retVal; } /** * Gets the token colorizer for a token * * @param token - * token to get colorization for * @return - token colorizer */ public TokenColorizer getTokenColorizer(IToken token) { if (tokenColorizers.containsKey(hashToken(token))) { return (TokenColorizer) tokenColorizers.get(hashToken(token)); } return null; } /** * getTokenColorizers * * @return Collection */ public Collection getTokenColorizers() { return tokenColorizers.values(); } /** * addTokenColorizers * * @param colorizers */ public void addTokenColorizers(Collection colorizers) { Iterator iter = colorizers.iterator(); while (iter.hasNext()) { addTokenColorizer((TokenColorizer) iter.next()); } } /** * Retains only the IToken instances found in the iterator parameter * * @param tokens */ public void retainTokens(Iterator tokens) { List<String> keys = new ArrayList<String>(); while (tokens.hasNext()) { IToken token = (IToken) tokens.next(); keys.add(hashToken(token)); } tokenColorizers.keySet().retainAll(keys); } /** * Adds a category level colorization * * @param colorizer - * colorizer for category */ public void addCategoryColorizer(CategoryColorizer colorizer) { categoryColorizers.put(colorizer.getName(), colorizer); } /** * Gets a category colorizer or null if one doesn't exist * * @param category - * name of category * @return - ColorizationStyle for this category */ public CategoryColorizer getCategoryColorizer(String category) { if (categoryColorizers.containsKey(category)) { return (CategoryColorizer) categoryColorizers.get(category); } return null; } /** * Gets the categories that have colorization * * @return - Collection of String category names */ public Collection getCategories() { return categoryColorizers.keySet(); } /** * Gets the category level colorizers * * @return - collection of CategoryColorizer objects */ public Collection getCategoryColorizers() { return categoryColorizers.values(); } /** * Sets the token colorizers * * @param colorizer */ public void setTokenColorizers(LanguageColorizer colorizer) { this.tokenColorizers = colorizer.tokenColorizers; } /** * Sets the category colorizers * * @param colorizer */ public void setCategoryColorizers(LanguageColorizer colorizer) { this.categoryColorizers = colorizer.categoryColorizers; } /** * Gets the language this colorizer is used for * * @return - mime type of language */ public String getLanguage() { return mimeType; } /** * Gets the background color * * @return - bg color */ public Color getBackground() { return background; } /** * Gets the background color taking into consideration an colorizer handlers registered that want to customize the * background based on the lexeme * * @param state * @param lexeme * @return - bg color */ public Color getBackground(IParseState state, Lexeme lexeme) { Color bg = null; IColorizerHandler handler = null; for (int i = 0; i < handlers.size(); i++) { handler = handlers.get(i); bg = handler.getBackground(state, lexeme); if (bg != null) { break; } } if (bg == null) { bg = this.background; } return bg; } /** * Gets the empty line background color * * @param state * @param offset * @return - bg color */ public Color getEmptyLineBackground(IParseState state, int offset) { Color bg = null; IColorizerHandler handler = null; for (int i = 0; i < handlers.size(); i++) { handler = handlers.get(i); bg = handler.getEmptyLineColor(state, offset); if (bg != null) { break; } } if (bg == null) { bg = this.background; } return bg; } /** * Sets the background color * * @param background - * new background color */ public void setBackground(Color background) { this.background = background; } /** * Gets the caret color * * @return - caret color */ public Color getCaretColor() { return caretColor; } /** * Sets the caret color * * @param caretColor - * new caret color */ public void setCaretColor(Color caretColor) { this.caretColor = caretColor; } /** * Gets the selection background color * * @return - selection background color */ public Color getSelectionBackground() { return selectionBg; } /** * Sets the selection background color * * @param selectionBg - * new selection background color */ public void setSelectionBackground(Color selectionBg) { this.selectionBg = selectionBg; } /** * Gets the selection foreground color * * @return - selection foreground color */ public Color getSelectionForeground() { return selectionFg; } /** * Sets the selection foreground color * * @param selectionFg - * new selection foreground color */ public void setSelectionForeground(Color selectionFg) { this.selectionFg = selectionFg; } /** * Gets the line highlight color * * @return - line highlight color */ public Color getLineHighlightColor() { return lineHighlightColor; } /** * Sets the line highlight color * * @param lineHighlightColor - * new line highlight color */ public void setLineHighlightColor(Color lineHighlightColor) { this.lineHighlightColor = lineHighlightColor; } /** * @return the foldingBg */ public Color getFoldingBg() { return foldingBg; } /** * @param foldingBg * the foldingBg to set */ public void setFoldingBg(Color foldingBg) { this.foldingBg = foldingBg; } /** * @return the foldingFg */ public Color getFoldingFg() { return foldingFg; } /** * @param foldingFg * the foldingFg to set */ public void setFoldingFg(Color foldingFg) { this.foldingFg = foldingFg; } }