Math2mat
|
00001 00020 package m2m.frontend; 00021 00022 import java.util.Hashtable; 00023 import java.util.Vector; 00024 00025 import org.eclipse.swt.SWT; 00026 import org.eclipse.swt.custom.LineStyleEvent; 00027 import org.eclipse.swt.custom.LineStyleListener; 00028 import org.eclipse.swt.custom.StyleRange; 00029 import org.eclipse.swt.graphics.Color; 00030 import org.eclipse.swt.graphics.RGB; 00031 import org.eclipse.swt.widgets.Control; 00032 import org.eclipse.swt.widgets.Display; 00033 00034 public class MatlabLineStyler implements LineStyleListener { 00035 JavaScanner scanner = new JavaScanner(); 00036 00037 int[] tokenColors; 00038 00039 Color[] colors; 00040 00041 Vector<int[]> blockComments = new Vector<int[]>(); 00042 00043 public static final int EOF = -1; 00044 00045 public static final int EOL = 10; 00046 00047 public static final int WORD = 0; 00048 00049 public static final int WHITE = 1; 00050 00051 public static final int KEY = 2; 00052 00053 public static final int COMMENT = 3; 00054 00055 public static final int STRING = 5; 00056 00057 public static final int OTHER = 6; 00058 00059 public static final int NUMBER = 7; 00060 00061 public static final int MAXIMUM_TOKEN = 8; 00062 00063 public MatlabLineStyler() { 00064 initializeColors(); 00065 scanner = new JavaScanner(); 00066 } 00067 00068 Color getColor(int type) { 00069 if (type < 0 || type >= tokenColors.length) { 00070 return null; 00071 } 00072 return colors[tokenColors[type]]; 00073 } 00074 00075 boolean inBlockComment(int start, int end) { 00076 for (int i = 0; i < blockComments.size(); i++) { 00077 int[] offsets = (int[]) blockComments.elementAt(i); 00078 // start of comment in the line 00079 if ((offsets[0] >= start) && (offsets[0] <= end)) 00080 return true; 00081 // end of comment in the line 00082 if ((offsets[1] >= start) && (offsets[1] <= end)) 00083 return true; 00084 if ((offsets[0] <= start) && (offsets[1] >= end)) 00085 return true; 00086 } 00087 return false; 00088 } 00089 00090 void initializeColors() { 00091 Display display = Display.getDefault(); 00092 colors = new Color[] { new Color(display, new RGB(0, 0, 0)), // black 00093 new Color(display, new RGB(255, 0, 0)), // red 00094 new Color(display, new RGB(0, 255, 0)), // green 00095 new Color(display, new RGB(0, 0, 255)) // blue 00096 }; 00097 tokenColors = new int[MAXIMUM_TOKEN]; 00098 tokenColors[WORD] = 0; 00099 tokenColors[WHITE] = 0; 00100 tokenColors[KEY] = 3; 00101 tokenColors[COMMENT] = 1; 00102 tokenColors[STRING] = 2; 00103 tokenColors[OTHER] = 0; 00104 tokenColors[NUMBER] = 0; 00105 } 00106 00107 void disposeColors() { 00108 for (int i = 0; i < colors.length; i++) { 00109 colors[i].dispose(); 00110 } 00111 } 00112 00118 public void lineGetStyle(LineStyleEvent event) { 00119 Vector<StyleRange> styles = new Vector<StyleRange>(); 00120 int token; 00121 StyleRange lastStyle; 00122 // If the line is part of a block comment, create one style for the 00123 // entire line. 00124 if (inBlockComment(event.lineOffset, event.lineOffset 00125 + event.lineText.length())) { 00126 styles.addElement(new StyleRange(event.lineOffset, event.lineText.length(), getColor(COMMENT), null)); 00127 event.styles = new StyleRange[styles.size()]; 00128 styles.copyInto(event.styles); 00129 return; 00130 } 00131 Color defaultFgColor = ((Control) event.widget).getForeground(); 00132 scanner.setRange(event.lineText); 00133 token = scanner.nextToken(); 00134 while (token != EOF) { 00135 if (token == OTHER) { 00136 // do nothing for non-colored tokens 00137 } else if (token != WHITE) { 00138 Color color = getColor(token); 00139 // Only create a style if the token color is different than the 00140 // widget's default foreground color and the token's style is 00141 // not 00142 // bold. Keywords are bolded. 00143 if ((!color.equals(defaultFgColor)) || (token == KEY)) { 00144 StyleRange style = new StyleRange(scanner.getStartOffset() 00145 + event.lineOffset, scanner.getLength(), color, 00146 null); 00147 if (token == KEY) { 00148 style.fontStyle = SWT.BOLD; 00149 } 00150 if (styles.isEmpty()) { 00151 styles.addElement(style); 00152 } else { 00153 // Merge similar styles. Doing so will improve 00154 // performance. 00155 lastStyle = (StyleRange) styles.lastElement(); 00156 if (lastStyle.similarTo(style) 00157 && (lastStyle.start + lastStyle.length == style.start)) { 00158 lastStyle.length += style.length; 00159 } else { 00160 styles.addElement(style); 00161 } 00162 } 00163 } 00164 } else if ((!styles.isEmpty()) 00165 && ((lastStyle = (StyleRange) styles.lastElement()).fontStyle == SWT.BOLD)) { 00166 int start = scanner.getStartOffset() + event.lineOffset; 00167 lastStyle = (StyleRange) styles.lastElement(); 00168 // A font style of SWT.BOLD implies that the last style 00169 // represents a java keyword. 00170 if (lastStyle.start + lastStyle.length == start) { 00171 // Have the white space take on the style before it to 00172 // minimize the number of style ranges created and the 00173 // number of font style changes during rendering. 00174 lastStyle.length += scanner.getLength(); 00175 } 00176 } 00177 token = scanner.nextToken(); 00178 } 00179 event.styles = new StyleRange[styles.size()]; 00180 styles.copyInto(event.styles); 00181 } 00182 00183 00187 public class JavaScanner { 00188 00189 protected Hashtable<String,Integer> fgKeys = null; 00190 00191 protected StringBuffer fBuffer = new StringBuffer(); 00192 00193 protected String fDoc; 00194 00195 protected int fPos; 00196 00197 protected int fEnd; 00198 00199 protected int fStartToken; 00200 00201 protected boolean fEofSeen = false; 00202 00203 private String[] fgKeywords = { "int", "short", "double", "rand", "break", "case", "catch", 00204 "classdef", "continue", "else", "elseif", "end", "for", "function", 00205 "if", "global", "otherwise", "return", "switch", "try", "while", 00206 "endfunction", "endif", "endfor", "endwhile" }; 00207 00208 public JavaScanner() { 00209 initialize(); 00210 } 00211 00215 public final int getLength() { 00216 return fPos - fStartToken; 00217 } 00218 00222 void initialize() { 00223 fgKeys = new Hashtable<String,Integer>(); 00224 Integer k = new Integer(KEY); 00225 for (int i = 0; i < fgKeywords.length; i++) 00226 fgKeys.put(fgKeywords[i], k); 00227 } 00228 00232 public final int getStartOffset() { 00233 return fStartToken; 00234 } 00235 00239 public int nextToken() { 00240 int c; 00241 fStartToken = fPos; 00242 while (true) { 00243 switch (c = read()) { 00244 case EOF: 00245 return EOF; 00246 case '%': // comment 00247 case '#': 00248 while (true) { 00249 c = read(); 00250 if ((c == EOF) || (c == EOL)) { 00251 unread(c); 00252 return COMMENT; 00253 } 00254 } 00255 case '\'': // char const 00256 for (;;) { 00257 c = read(); 00258 switch (c) { 00259 case '\'': 00260 return STRING; 00261 case EOF: 00262 unread(c); 00263 return STRING; 00264 case '\\': 00265 c = read(); 00266 break; 00267 } 00268 } 00269 00270 case '"': // string 00271 for (;;) { 00272 c = read(); 00273 switch (c) { 00274 case '"': 00275 return STRING; 00276 case EOF: 00277 unread(c); 00278 return STRING; 00279 case '\\': 00280 c = read(); 00281 break; 00282 } 00283 } 00284 00285 case '0': 00286 case '1': 00287 case '2': 00288 case '3': 00289 case '4': 00290 case '5': 00291 case '6': 00292 case '7': 00293 case '8': 00294 case '9': 00295 do { 00296 c = read(); 00297 } while (Character.isDigit((char) c)); 00298 unread(c); 00299 return NUMBER; 00300 default: 00301 if (Character.isWhitespace((char) c)) { 00302 do { 00303 c = read(); 00304 } while (Character.isWhitespace((char) c)); 00305 unread(c); 00306 return WHITE; 00307 } 00308 if (Character.isJavaIdentifierStart((char) c)) { 00309 fBuffer.setLength(0); 00310 do { 00311 fBuffer.append((char) c); 00312 c = read(); 00313 } while (Character.isJavaIdentifierPart((char) c)); 00314 unread(c); 00315 Integer i = (Integer) fgKeys.get(fBuffer.toString()); 00316 if (i != null) 00317 return i.intValue(); 00318 return WORD; 00319 } 00320 return OTHER; 00321 } 00322 } 00323 } 00324 00328 protected int read() { 00329 if (fPos <= fEnd) { 00330 return fDoc.charAt(fPos++); 00331 } 00332 return EOF; 00333 } 00334 00335 public void setRange(String text) { 00336 fDoc = text; 00337 fPos = 0; 00338 fEnd = fDoc.length() - 1; 00339 } 00340 00341 protected void unread(int c) { 00342 if (c != EOF) 00343 fPos--; 00344 } 00345 } 00346 }