1 21 22 package org.armedbear.j; 23 24 public final class CSSFormatter extends Formatter implements Constants 25 { 26 private static final int CSS_STATE_QUOTE = 0x0001; 28 private static final int CSS_STATE_SINGLEQUOTE = 0x0002; 29 private static final int CSS_STATE_COMMENT = 0x0004; 30 private static final int CSS_STATE_BRACE = 0x0008; 31 private static final int CSS_STATE_IN_BLOCK = 0x0010; 32 private static final int CSS_STATE_NUMBER = 0x0020; 33 private static final int CSS_STATE_PROPERTY = 0x0040; 34 private static final int CSS_STATE_VALUE = 0x0080; 35 private static final int CSS_STATE_SELECTOR = 0x0100; 36 37 private static final int CSS_FORMAT_TEXT = 0; 39 private static final int CSS_FORMAT_COMMENT = 1; 40 private static final int CSS_FORMAT_STRING = 2; 41 private static final int CSS_FORMAT_PROPERTY = 3; 42 private static final int CSS_FORMAT_BRACE = 4; 43 private static final int CSS_FORMAT_NUMBER = 5; 44 private static final int CSS_FORMAT_SELECTOR = 6; 45 46 private static final CSSMode mode = CSSMode.getMode(); 47 48 public CSSFormatter(Buffer buffer) 49 { 50 this.buffer = buffer; 51 } 52 53 private int tokenBegin = 0; 54 55 private void endToken(String text, int tokenEnd, int state) 56 { 57 if (tokenEnd - tokenBegin > 0) { 58 int format = CSS_FORMAT_TEXT; 59 if ((state & (CSS_STATE_QUOTE | CSS_STATE_SINGLEQUOTE)) != 0) 60 format = CSS_FORMAT_STRING; 61 else if ((state & CSS_STATE_COMMENT) != 0) 62 format = CSS_FORMAT_COMMENT; 63 else if ((state & CSS_STATE_BRACE) != 0) 64 format = CSS_FORMAT_BRACE; 65 else if ((state & CSS_STATE_NUMBER) != 0) 66 format = CSS_FORMAT_NUMBER; 67 else if ((state & CSS_STATE_PROPERTY) != 0) 68 format = CSS_FORMAT_PROPERTY; 69 else if ((state & CSS_STATE_VALUE) != 0) 70 format = CSS_FORMAT_TEXT; 71 else if ((state & CSS_STATE_SELECTOR) != 0) 72 format = CSS_FORMAT_SELECTOR; 73 addSegment(text, tokenBegin, tokenEnd, format); 74 tokenBegin = tokenEnd; 75 } 76 } 77 78 private void parseLine(Line line) 79 { 80 final String text; 81 if (Editor.tabsAreVisible()) 82 text = Utilities.makeTabsVisible(line.getText(), buffer.getTabWidth()); 83 else 84 text = Utilities.detab(line.getText(), buffer.getTabWidth()); 85 tokenBegin = 0; 86 int state = line.flags(); 87 int i = 0; 88 final int limit = text.length(); 89 while (i < limit) { 91 if (Character.isWhitespace(text.charAt(i))) 92 ++i; 93 else { 94 endToken(text, i, state); 95 break; 96 } 97 } 98 while (i < limit) { 99 final char c = text.charAt(i); 100 if (c == '\\' && i < limit-1) { 101 i += 2; 103 continue; 104 } 105 if ((state & CSS_STATE_COMMENT) != 0) { 106 if (i < limit-1 && c == '*' && text.charAt(i+1) == '/') { 107 endToken(text, i+2, state); 108 state &= ~CSS_STATE_COMMENT; 109 i += 2; 110 } else 111 ++i; 112 continue; 113 } 114 if ((state & CSS_STATE_QUOTE) != 0) { 115 if (c == '"') { 116 endToken(text, i+1, state); 117 state &= ~CSS_STATE_QUOTE; 118 } 119 ++i; 120 continue; 121 } 122 if ((state & CSS_STATE_SINGLEQUOTE) != 0) { 123 if (c == '"') { 124 endToken(text, i+1, state); 125 state &= ~CSS_STATE_SINGLEQUOTE; 126 } 127 ++i; 128 continue; 129 } 130 if (c == '"') { 132 endToken(text, i, state); 133 state |= CSS_STATE_QUOTE; 134 ++i; 135 continue; 136 } 137 if (c == '\'') { 138 endToken(text, i, state); 139 state |= CSS_STATE_SINGLEQUOTE; 140 ++i; 141 continue; 142 } 143 if (c == '/') { 144 if (i < limit-1) { 145 if (text.charAt(i+1) == '*') { 146 endToken(text, i, state); 147 state |= CSS_STATE_COMMENT; 148 i += 2; 149 } else 150 ++i; 151 } else 152 ++i; 153 continue; 154 } 155 if (c == '{') { 156 endToken(text, i, state); 157 endToken(text, ++i, CSS_STATE_BRACE); 158 state |= CSS_STATE_IN_BLOCK; 159 continue; 160 } 161 if (c == '}') { 162 endToken(text, i, state); 163 endToken(text, ++i, CSS_STATE_BRACE); 164 state &= ~CSS_STATE_IN_BLOCK; 165 continue; 166 } 167 if ((state & CSS_STATE_IN_BLOCK) != 0) { 168 if ((state & CSS_STATE_NUMBER) != 0) { 169 boolean isNumeric; 170 if ("0123456789".indexOf(c) >= 0) { 171 isNumeric = true; 173 } else if ("abcdefABCDEF".indexOf(c) >= 0) { 174 if (c == 'e' && i < limit-1 && text.charAt(i+1) == 'm') { 175 isNumeric = false; 177 } else { 178 isNumeric = true; 180 } 181 } else 182 isNumeric = false; 183 if (!isNumeric) { 184 endToken(text, i, state); 186 state &= ~CSS_STATE_NUMBER; 187 } 188 ++i; 189 continue; 190 } 191 if ((state & CSS_STATE_VALUE) != 0) { 192 if (c == '#' || Character.isDigit(c)) { 193 endToken(text, i, state); 194 state |= CSS_STATE_NUMBER; 195 ++i; 196 continue; 197 } 198 if (c == '-' && i < limit-1 && Character.isDigit(text.charAt(i+1))) { 199 endToken(text, i, state); 200 state |= CSS_STATE_NUMBER; 201 i += 2; 202 continue; 203 } 204 if (c == ';') { 205 endToken(text, i, state); 207 state &= ~CSS_STATE_VALUE; 208 ++i; 209 continue; 210 } 211 ++i; 212 continue; 213 } 214 if (c == ':') { 215 endToken(text, i, CSS_STATE_PROPERTY); 216 state |= CSS_STATE_VALUE; 217 ++i; 218 continue; 219 } 220 } 221 if ((state & CSS_STATE_SELECTOR) != 0) { 222 if (!mode.isIdentifierPart(c)) { 223 endToken(text, i, state); 224 state &= ~CSS_STATE_SELECTOR; 225 } 226 ++i; 227 continue; 228 } 229 if (state == 0) { 230 if (mode.isIdentifierStart(c)) { 231 endToken(text, i, state); 232 state |= CSS_STATE_SELECTOR; 233 } 234 } 235 ++i; 236 } 237 endToken(text, i, state); 239 } 240 241 public LineSegmentList formatLine(Line line) 242 { 243 clearSegmentList(); 244 if (line == null) { 245 addSegment("", CSS_FORMAT_TEXT); 246 return segmentList; 247 } 248 parseLine(line); 249 return segmentList; 250 } 251 252 public boolean parseBuffer() 253 { 254 int state = 0; 255 Line line = buffer.getFirstLine(); 256 boolean changed = false; 257 while (line != null) { 258 int oldflags = line.flags(); 259 state &= ~(CSS_STATE_QUOTE | CSS_STATE_SINGLEQUOTE); 261 if (state != oldflags) { 262 line.setFlags(state); 263 changed = true; 264 } 265 final int limit = line.length(); 266 for (int i = 0; i < limit; i++) { 267 char c = line.charAt(i); 268 if (c == '\\' && i < limit-1) { 269 ++i; 271 continue; 272 } 273 if ((state & CSS_STATE_COMMENT) != 0) { 274 if (c == '*' && i < limit-1) { 275 c = line.charAt(i+1); 276 if (c == '/') { 277 ++i; 278 state &= ~CSS_STATE_COMMENT; 279 } 280 } 281 continue; 282 } 283 if ((state & CSS_STATE_QUOTE) != 0) { 284 if (c == '"') 285 state &= ~CSS_STATE_QUOTE; 286 continue; 287 } 288 if ((state & CSS_STATE_SINGLEQUOTE) != 0) { 289 if (c == '"') 290 state &= ~CSS_STATE_SINGLEQUOTE; 291 continue; 292 } 293 if (c == '{') { 295 state |= CSS_STATE_IN_BLOCK; 296 continue; 297 } 298 if (c == '}') { 299 state &= ~CSS_STATE_IN_BLOCK; 300 continue; 301 } 302 if (c == '/' && i < limit-1) { 303 c = line.charAt(++i); 304 if (c == '*') 305 state |= CSS_STATE_COMMENT; 306 } else if (c == '"') { 307 state |= CSS_STATE_QUOTE; 308 } else if (c == '\'') { 309 state |= CSS_STATE_SINGLEQUOTE; 310 } 311 } 312 line = line.next(); 313 } 314 buffer.setNeedsParsing(false); 315 return changed; 316 } 317 318 public FormatTable getFormatTable() 319 { 320 if (formatTable == null) { 321 formatTable = new FormatTable("CSSMode"); 322 formatTable.addEntryFromPrefs(CSS_FORMAT_TEXT, "text"); 323 formatTable.addEntryFromPrefs(CSS_FORMAT_COMMENT, "comment"); 324 formatTable.addEntryFromPrefs(CSS_FORMAT_STRING, "string"); 325 formatTable.addEntryFromPrefs(CSS_FORMAT_PROPERTY, "property", "keyword"); 326 formatTable.addEntryFromPrefs(CSS_FORMAT_BRACE, "brace"); 327 formatTable.addEntryFromPrefs(CSS_FORMAT_NUMBER, "number"); 328 formatTable.addEntryFromPrefs(CSS_FORMAT_SELECTOR, "selector", "function"); 329 } 330 return formatTable; 331 } 332 } 333 | Popular Tags |