/** * RepDev - RepGen IDE for Symitar * Copyright (C) 2007 Jake Poznanski, Ryan Schultz, Sean Delaney * http://repdev.org/ <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.repdev; import java.io.File; import java.util.ArrayList; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ExtendedModifyEvent; import org.eclipse.swt.custom.ExtendedModifyListener; import org.eclipse.swt.custom.LineBackgroundEvent; import org.eclipse.swt.custom.LineBackgroundListener; import org.eclipse.swt.custom.LineStyleEvent; import org.eclipse.swt.custom.LineStyleListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Display; import com.repdev.parser.FunctionLayout; import com.repdev.parser.RepgenParser; import com.repdev.parser.Token; import com.repdev.parser.Variable; import com.repdev.parser.Token.SpecialBackgroundReason; /** * Adds the right listeners to a StyledText object to colorize repgens. Uses RepgenParser for the tokenization * @author Jake Poznanski * */ public class SyntaxHighlighter implements ExtendedModifyListener, LineStyleListener, LineBackgroundListener { //TODO: Style set here private static String styleName = "default"; private static String FONT_NAME = ""; // "Courier New"; //Fix Font Behavior private static int FONT_SIZE = 0;// = 11; private static RGB BACKGROUND = new RGB(255, 255, 255), FOREGROUND = new RGB(0, 0, 0); private static EStyle MAIN = new EStyle(null,null), NORMAL = new EStyle(null, null), COMMENTS = new EStyle(new RGB(127, 127, 127), null), VARIABLES = new EStyle(new RGB(0, 0, 0), null, SWT.BOLD), FUNCTIONS = new EStyle(new RGB(0, 0, 255), null, SWT.BOLD), KEYWORDS = new EStyle(new RGB(0, 0, 255), null), TYPE_CHAR = new EStyle(new RGB(255, 0, 0), null), TYPE_DATE = new EStyle(new RGB(255, 0, 0), null, SWT.BOLD), STRUCT1 = new EStyle(new RGB(255, 0, 255), null), STRUCT2 = new EStyle(new RGB(255, 128, 255), null), STRUCT1_INVALID = new EStyle(new RGB(255, 0, 255), new RGB(128, 0, 0), SWT.NONE), STRUCT2_INVALID = new EStyle(new RGB(255, 128, 255), new RGB(128, 0, 0), SWT.NONE), TASK = new EStyle(new RGB(64,64,64), null, SWT.BOLD); private static Color FORECOLOR = new Color(Display.getCurrent(), FOREGROUND), BACKCOLOR = new Color(Display.getCurrent(), BACKGROUND), BULLETS = new Color(Display.getCurrent(),new RGB(105,105,105)); private static Font FONT; private RepgenParser parser; private StyledText txt; private SymitarFile file; private int sym; //Custom line background, used by the compare composite interface private int[] customLines = null; private static Color customColor, tokenColor; static { loadStyle(Config.getStyle()); Font cur = null; try { cur = new Font(Display.getCurrent(), FONT_NAME, FONT_SIZE, SWT.NORMAL); } catch (Exception e) { } FONT = cur; } public SyntaxHighlighter(RepgenParser parser) { this.parser = parser; this.txt = parser.getTxt(); this.file = parser.getFile(); this.sym = parser.getSym(); txt.setForeground(FORECOLOR); txt.setBackground(BACKCOLOR); if(parser.getSym()==Config.getLiveSym() && !this.file.isLocal()) txt.setBackground(new Color(Display.getCurrent(), getRGB(Config.getLiveSymColor()))); txt.addExtendedModifyListener(this); txt.addLineStyleListener(this); if (FONT != null) txt.setFont(FONT); } /** * This is used by compare composite to set custom background for sections with diffs * @param parser * @param customLineColor * @param customLines */ public SyntaxHighlighter(RepgenParser parser, Color customLineColor, int[] customLines){ this.parser = parser; this.txt = parser.getTxt(); this.file = parser.getFile(); this.sym = parser.getSym(); this.customColor = customLineColor; this.customLines = customLines; txt.setForeground(FORECOLOR); txt.setBackground(BACKCOLOR); txt.addExtendedModifyListener(this); txt.addLineBackgroundListener(this); txt.addLineStyleListener(this); if (FONT != null) txt.setFont(FONT); } public void highlight(){ txt.removeExtendedModifyListener(this); txt.removeLineBackgroundListener(this); txt.removeLineStyleListener(this); } public static Color getLineColor(){ return customColor; } public static Color getBlockMatchColor(){ return tokenColor; } public Color getBulletColor(){ return BULLETS; } public static void loadStyle(String styleName){ System.out.println("Loading theme " + styleName + ".xml"); try{ Style style = new Style( new File("styles\\" + styleName + ".xml" )); FONT_NAME = style.getFontValue("editor", "font"); // "Courier New"; FONT_SIZE = style.getFontSize("editor", "fontSize"); // 11; BACKGROUND = style.getColor("editor", "bgColor"); // just... don't... FOREGROUND = style.getColor("editor", "fgColor"); // ask, it's not worth it. FORECOLOR = new Color(Display.getCurrent(), FOREGROUND); BACKCOLOR = new Color(Display.getCurrent(), BACKGROUND); NORMAL = new EStyle(null, null); customColor = new Color(Display.getCurrent(), style.getColor("editor", "line")); tokenColor = new Color(Display.getCurrent(), style.getColor("editor", "token")); COMMENTS = new EStyle(style.getColor("comments", "fgColor"), style.getColor("comments", "bgColor"), style.getStyle("comments")); VARIABLES = new EStyle(style.getColor("variables", "fgColor"), style.getColor("variables", "bgColor"), style.getStyle("variables")); FUNCTIONS = new EStyle(style.getColor("functions", "fgColor"), style.getColor("functions", "bgColor"), style.getStyle("functions")); KEYWORDS = new EStyle(style.getColor("keywords", "fgColor"), style.getColor("keywords", "bgColor"), style.getStyle("keywords")); TYPE_CHAR = new EStyle(style.getColor("typeChar", "fgColor"), style.getColor("typeChar", "bgColor"), style.getStyle("typeChar")); TYPE_DATE = new EStyle(style.getColor("typeDate", "fgColor"), style.getColor("typeDate", "bgColor"), style.getStyle("typeDate")); STRUCT1 = new EStyle(style.getColor("struct1", "fgColor"), style.getColor("struct1", "bgColor"), style.getStyle("struct1")); STRUCT2 = new EStyle(style.getColor("struct2", "fgColor"), style.getColor("struct2", "bgColor"), style.getStyle("struct2")); STRUCT1_INVALID = new EStyle(style.getColor("struct1Inv", "fgColor"), style.getColor("struct1Inv", "bgColor"), style.getStyle("struct1Inv")); STRUCT2_INVALID = new EStyle(style.getColor("struct2Inv", "fgColor"), style.getColor("struct2Inv", "bgColor"), style.getStyle("struct2Inv")); TASK = new EStyle(style.getColor("task", "fgColor"), style.getColor("task", "bgColor"), style.getStyle("task")); try{ BULLETS = new Color(Display.getCurrent(),style.getColor("linenumber","fgColor")); }catch(Exception e){ BULLETS = new Color(Display.getCurrent(),new RGB(127, 127, 127)); } }catch(Exception e){ //System.out.println(e.getMessage()); System.out.println("Invalid theme using default"); FONT_NAME = "Courier New"; FONT_SIZE = 11; BACKGROUND = new RGB(255, 255, 255); FOREGROUND = new RGB(0, 0, 0); NORMAL = new EStyle(null, null); COMMENTS = new EStyle(new RGB(127, 127, 127), null); VARIABLES = new EStyle(new RGB(0, 0, 0), null, SWT.BOLD); FUNCTIONS = new EStyle(new RGB(0, 0, 255), null, SWT.BOLD); KEYWORDS = new EStyle(new RGB(0, 0, 255), null); TYPE_CHAR = new EStyle(new RGB(255, 0, 0), null); TYPE_DATE = new EStyle(new RGB(255, 0, 0), null, SWT.BOLD); STRUCT1 = new EStyle(new RGB(255, 0, 255), null); STRUCT2 = new EStyle(new RGB(255, 128, 255), null); STRUCT1_INVALID = new EStyle(new RGB(255, 0, 255), new RGB(128, 0, 0), SWT.NONE); STRUCT2_INVALID = new EStyle(new RGB(255, 128, 255), new RGB(128, 0, 0), SWT.NONE); TASK = new EStyle(new RGB(64,64,64), null, SWT.BOLD); FORECOLOR = new Color(Display.getCurrent(), FOREGROUND); BACKCOLOR = new Color(Display.getCurrent(), BACKGROUND); customColor = new Color(Display.getCurrent(), new RGB(232,242,254)); tokenColor = new Color(Display.getCurrent(), new RGB(192,192,192)); BULLETS = new Color(Display.getCurrent(),new RGB(127, 127, 127)); } } private static class EStyle { private Color fcolor = null, bgcolor = null; private int style; public EStyle(RGB frgb, RGB bgrgb, int style) { if (frgb != null) fcolor = new Color(Display.getCurrent(), frgb); if (bgrgb != null) bgcolor = new Color(Display.getCurrent(), bgrgb); this.style = style; } public EStyle(RGB frgb, RGB bgrgb) { this(frgb, bgrgb, SWT.NORMAL); } public StyleRange getRange(int start, int len) { return new StyleRange(start, len, fcolor, bgcolor, style); } } public void modifyText(ExtendedModifyEvent e) { parser.textModified(e.start, e.length, e.replacedText); } public StyleRange getStyle(Token tok) { boolean isVar = false; StyleRange range = null; if (tok.getCDepth() != 0) { range = COMMENTS.getRange(tok.getStart(), tok.length()); for( String taskType: RepgenParser.taskTokens ) if( tok.getStr().equals(taskType) && (tok.getAfter() != null && tok.getAfter().getStr().equals(":")) ) range = TASK.getRange(tok.getStart(), tok.length()); } else if (tok.inString()) range = TYPE_CHAR.getRange(tok.getStart(), tok.length()); else if (tok.inDate()) range = TYPE_DATE.getRange(tok.getStart(), tok.length()); else if (tok.getAfter() != null && tok.getAfter().getStr().equals(":")) { if (tok.dbRecordValid()) range = STRUCT1.getRange(tok.getStart(), tok.length()); else range = STRUCT1_INVALID.getRange(tok.getStart(), tok.length()); } else if (tok.getBefore() != null && tok.getBefore().getStr().equals(":")) { if (tok.dbFieldValid(RepgenParser.getDb().getTreeRecords())) range = STRUCT2.getRange(tok.getStart(), tok.length()); else range = STRUCT2_INVALID.getRange(tok.getStart(), tok.length()); } else if (FunctionLayout.getInstance().containsName(tok.getStr()) && tok.getAfter() != null && tok.getAfter().getStr().equals("(")) range = FUNCTIONS.getRange(tok.getStart(), tok.length()); else if (RepgenParser.getKeywords().contains(tok.getStr())) range = KEYWORDS.getRange(tok.getStart(), tok.length()); else if (RepgenParser.getSpecialvars().contains(tok.getStr())) range = VARIABLES.getRange(tok.getStart(), tok.length()); for (int i = 0; i < parser.getLvars().size(); i++){ Variable var = parser.getLvars().get(i); if (var.getName().equals(tok.getStr())) isVar = true; } if (range == null && isVar) range = VARIABLES.getRange(tok.getStart(), tok.length()); else if( range == null ){ range = NORMAL.getRange(tok.getStart(), tok.length()); } if( tok.getSpecialBackground() != null) range.background = tok.getSpecialBackground(); return range; } public void lineGetStyle(LineStyleEvent event) { ArrayList<Token> ltokens = parser.getLtokens(); ArrayList<StyleRange> ranges = new ArrayList<StyleRange>(); int line = txt.getLineAtOffset(event.lineOffset); int ftoken; for (ftoken = 0; ftoken < ltokens.size(); ftoken++) if (ltokens.get(ftoken).getEnd() >= event.lineOffset) break; int ltoken = ltokens.size(); if (line + 1 < txt.getLineCount()) { int pos = txt.getOffsetAtLine(line + 1); for (ltoken = ftoken; ltoken < ltokens.size(); ltoken++) if (ltokens.get(ltoken).getStart() > pos) break; } for (int i = ftoken; i < ltoken; i++){ StyleRange range = getStyle(ltokens.get(i)); ranges.add(range); //If we are a backgroudn highlighted token, and a CODE SNIPPET one, then connect the highlighting over whitespace between tokens if( ltokens.get(i).getBackgroundReason() == SpecialBackgroundReason.CODE_SNIPPET ) if( i + 1 < ltoken && ltokens.get(i+1).getBackgroundReason() == SpecialBackgroundReason.CODE_SNIPPET && ltokens.get(i+1).getSnippetVar() == ltokens.get(i).getSnippetVar()) ranges.add(new StyleRange(ltokens.get(i).getEnd(),ltokens.get(i+1).getStart()-ltokens.get(i).getEnd(),null,ltokens.get(i).getSpecialBackground())); } StyleRange[] rangesArray = new StyleRange[ranges.size()]; event.styles = ranges.toArray(rangesArray); } public void setCustomLines(int[] lines) { customLines = lines; } public void lineGetBackground(LineBackgroundEvent event) { boolean go = false; for( int i : customLines) if( i == txt.getLineAtOffset(event.lineOffset) ) { go = true; break; } if( go ){ event.lineBackground = customColor; } } private RGB getRGB(String rgbHex) { int[] rgb = {0,0,0}; rgb[0] = Integer.parseInt(rgbHex.substring(0,2), 16); rgb[1] = Integer.parseInt(rgbHex.substring(2,4), 16); rgb[2] = Integer.parseInt(rgbHex.substring(4), 16); return new RGB(rgb[0],rgb[1],rgb[2]); } }