1 21 22 package org.armedbear.j; 23 24 public final class ShellScriptFormatter extends Formatter 25 { 26 private static final int STATE_BACKQUOTE = STATE_LAST + 1; 27 private static final int STATE_EXPANSION = STATE_LAST + 2; 28 private static final int STATE_HERE_DOCUMENT = STATE_LAST + 3; 29 private static final int STATE_ECHO = STATE_LAST + 4; 30 31 private static final int SHELLSCRIPT_FORMAT_TEXT = 0; 32 private static final int SHELLSCRIPT_FORMAT_COMMENT = 2; 33 34 private static final int SHELLSCRIPT_FORMAT_STRING = 4; 35 private static final int SHELLSCRIPT_FORMAT_KEYWORD = 5; 36 private static final int SHELLSCRIPT_FORMAT_FUNCTION = 6; 37 private static final int SHELLSCRIPT_FORMAT_OPERATOR = 7; 38 private static final int SHELLSCRIPT_FORMAT_BRACE = 8; 39 private static final int SHELLSCRIPT_FORMAT_NUMBER = 9; 40 41 private static StringSet keywords; 42 43 private FastStringBuffer sb = new FastStringBuffer(); 44 private int tokStart; 45 private String token; 46 47 private String endOfText; 48 49 public ShellScriptFormatter(Buffer buffer) 50 { 51 this.buffer = buffer; 52 } 53 54 private void endToken(int state) 55 { 56 if (sb.length() > 0) { 57 int format = -1; 58 switch (state) { 59 case STATE_NEUTRAL: 60 break; 61 case STATE_QUOTE: 62 case STATE_SINGLEQUOTE: 63 case STATE_BACKQUOTE: 64 case STATE_HERE_DOCUMENT: 65 case STATE_ECHO: 66 format = SHELLSCRIPT_FORMAT_STRING; 67 break; 68 case STATE_IDENTIFIER: 69 break; 70 case STATE_COMMENT: 71 format = SHELLSCRIPT_FORMAT_COMMENT; 72 break; 73 case STATE_OPERATOR: 74 format = SHELLSCRIPT_FORMAT_OPERATOR; 75 break; 76 case STATE_BRACE: 77 format = SHELLSCRIPT_FORMAT_BRACE; 78 break; 79 case STATE_NUMBER: 80 case STATE_HEXNUMBER: 81 format = SHELLSCRIPT_FORMAT_NUMBER; 82 break; 83 } 84 token = sb.toString(); 85 addSegment(token, format); 86 tokStart += token.length(); 87 sb.setLength(0); 88 } 89 } 90 91 private void parseLine(String text, int state) 92 { 93 if (Editor.tabsAreVisible()) 94 text = Utilities.makeTabsVisible(text, buffer.getTabWidth()); 95 else 96 text = Utilities.detab(text, buffer.getTabWidth()); 97 clearSegmentList(); 98 int braceCount = 0; 99 sb.setLength(0); 100 int i = 0; 101 tokStart = 0; 102 if (state == STATE_HERE_DOCUMENT) { 103 if (text.startsWith(endOfText)) 104 state = STATE_NEUTRAL; 105 else { 106 sb.append(text); 107 endToken(state); 108 return; 109 } 110 } 111 int limit = text.length(); 112 char c; 113 while (i < limit) { 115 c = text.charAt(i); 116 if (Character.isWhitespace(c)) { 117 sb.append(c); 118 ++i; 119 } else { 120 endToken(state); 121 break; 122 } 123 } 124 while (i < limit) { 125 c = text.charAt(i); 126 if (state == STATE_QUOTE) { 127 if (c == '"') { 128 sb.append(c); 129 endToken(state); 130 state = STATE_NEUTRAL; 131 } else { 132 sb.append(c); 133 if (c == '\\' && i < limit-1) { 134 sb.append(text.charAt(++i)); 136 } 137 } 138 ++i; 139 continue; 140 } 141 if (state == STATE_SINGLEQUOTE) { 142 if (c == '\'') { 143 sb.append(c); 144 endToken(state); 145 state = STATE_NEUTRAL; 146 } else { 147 sb.append(c); 148 } 149 ++i; 150 continue; 151 } 152 if (state == STATE_BACKQUOTE) { 153 if (c == '`') { 154 sb.append(c); 155 endToken(state); 156 state = STATE_NEUTRAL; 157 } else { 158 sb.append(c); 159 } 160 ++i; 161 continue; 162 } 163 if (c == '"') { 165 endToken(state); 166 sb.append(c); 167 state = STATE_QUOTE; 168 ++i; 169 continue; 170 } 171 if (c == '\'') { 172 endToken(state); 173 sb.append(c); 174 state = STATE_SINGLEQUOTE; 175 ++i; 176 continue; 177 } 178 if (c == '`') { 179 endToken(state); 180 sb.append(c); 181 state = STATE_BACKQUOTE; 182 ++i; 183 continue; 184 } 185 if (state == STATE_ECHO) { 186 if (c == '\\' && i < limit-1) { 187 sb.append(c); 189 ++i; 190 sb.append(text.charAt(i)); 191 ++i; 192 continue; 193 } 194 if (c == ';') { 196 endToken(state); 197 sb.append(c); 198 state = STATE_NEUTRAL; 199 } else 200 sb.append(c); 201 ++i; 202 continue; 203 } 204 if (state == STATE_EXPANSION) { 205 if (c == '{') { 206 ++braceCount; 207 sb.append(c); 208 ++i; 209 continue; 210 } 211 if (c == '}') { 212 --braceCount; 213 if (braceCount == 0) { 214 sb.append(c) ; 215 endToken(state); 216 state = STATE_NEUTRAL; 217 ++i; 218 continue; 219 } else { 220 sb.append(c); 221 ++i; 222 continue; 223 } 224 } 225 if (braceCount == 0) { 226 if (!buffer.mode.isIdentifierPart(c)) { 227 endToken(state); 228 sb.append(c) ; 229 state = STATE_NEUTRAL; 230 ++i; 231 continue; 232 } 233 } 234 sb.append(c); 235 ++i; 236 continue; 237 } 238 if (c == '$') { 239 endToken(state); 240 sb.append(c); 241 state = STATE_EXPANSION; 242 ++i; 243 continue; 244 } 245 if (c == '#') { 246 endToken(state); 247 state = STATE_COMMENT; 248 sb.append(text.substring(i)); 249 endToken(state); 250 return; 251 } 252 if (state == STATE_IDENTIFIER) { 253 if (buffer.mode.isIdentifierPart(c)) 254 sb.append(c); 255 else { 256 endToken(state); 257 if (token.equals("echo")) 258 state = STATE_ECHO; 259 else 260 state = STATE_NEUTRAL; 261 sb.append(c); 262 } 263 ++i; 264 continue; 265 } 266 if (state == STATE_NUMBER) { 267 if (Character.isDigit(c)) 268 sb.append(c); 269 else { 270 endToken(state); 271 sb.append(c); 272 if (buffer.mode.isIdentifierStart(c)) 273 state = STATE_IDENTIFIER; 274 else 275 state = STATE_NEUTRAL; 276 } 277 ++i; 278 continue; 279 } 280 if (state == STATE_NEUTRAL) { 281 if (buffer.mode.isIdentifierStart(c)) { 282 endToken(state); 283 sb.append(c); 284 state = STATE_IDENTIFIER; 285 } else if (Character.isDigit(c)) { 286 endToken(state); 287 sb.append(c); 288 state = STATE_NUMBER; 289 } else sb.append(c); 291 } 292 ++i; 293 } 294 endToken(state); 295 } 296 297 public LineSegmentList formatLine(Line line) 298 { 299 if (line == null) { 300 clearSegmentList(); 301 addSegment("", SHELLSCRIPT_FORMAT_TEXT); 302 return segmentList; 303 } 304 parseLine(line.getText(), line.flags()); 305 for (int i = 0; i < segmentList.size(); i++) { 306 LineSegment segment = segmentList.getSegment(i); 307 if (segment.getFormat() > 0) 308 continue; 309 String s = segment.getText(); 310 if (isKeyword(s)) 311 segment.setFormat(SHELLSCRIPT_FORMAT_KEYWORD); 312 else 313 segment.setFormat(SHELLSCRIPT_FORMAT_TEXT); 314 } 315 return segmentList; 316 } 317 318 public boolean parseBuffer() 319 { 320 int state = STATE_NEUTRAL; 321 Line line = buffer.getFirstLine(); 322 boolean changed = false; 323 char quoteChar = '\0'; 324 while (line != null) { 325 int oldflags = line.flags(); 326 if (state == STATE_HERE_DOCUMENT) { 327 if (line.getText().equals(endOfText)) 328 state = STATE_NEUTRAL; 329 } 330 if (state != oldflags) { 331 line.setFlags(state); 332 changed = true; 333 } 334 if (state == STATE_HERE_DOCUMENT) { 335 line = line.next(); 336 continue; 337 } 338 final int limit = line.length(); 339 for (int i = 0; i < limit; i++) { 340 char c = line.charAt(i); 341 if (c == '\\' && i < limit - 1) { 342 ++i; 344 continue; 345 } 346 if (state == STATE_QUOTE) { 347 if (c == '"') 348 state = STATE_NEUTRAL; 349 continue; 350 } 351 if (state == STATE_SINGLEQUOTE) { 352 if (c == '\'') 353 state = STATE_NEUTRAL; 354 continue; 355 } 356 if (c == '<' && i < limit-2) { 358 if (line.charAt(i + 1) == '<') { 359 endOfText = line.substring(i + 2).trim(); 360 if (endOfText.startsWith("-")) 361 endOfText = endOfText.substring(1); 362 int length = endOfText.length(); 363 if (length > 2) { 364 if (endOfText.charAt(0) == '"' && 365 endOfText.charAt(length - 1) == '"') { 366 endOfText = endOfText.substring(1, length-1); 368 } else if (endOfText.charAt(0) == '\'' && 369 endOfText.charAt(length - 1) == '\'') { 370 endOfText = endOfText.substring(1, length-1); 372 } 373 } 374 if (endOfText.length() > 0) { 375 if (Character.isLetter(endOfText.charAt(0))) { 377 state = STATE_HERE_DOCUMENT; 378 break; 379 } 380 } 381 } 382 continue; 383 } 384 if (c == '#') { 385 break; 389 } 390 if (c == '"') 391 state = STATE_QUOTE; 392 else if (c == '\'') 393 state = STATE_SINGLEQUOTE; 394 } 395 line = line.next(); 396 } 397 buffer.setNeedsParsing(false); 398 return changed; 399 } 400 401 public FormatTable getFormatTable() 402 { 403 if (formatTable == null) { 404 formatTable = new FormatTable("ShellScriptMode"); 405 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_TEXT, "text"); 406 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_COMMENT, "comment"); 407 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_STRING, "string"); 408 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_KEYWORD, "keyword"); 409 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_FUNCTION, "function"); 410 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_OPERATOR, "operator"); 411 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_BRACE, "brace"); 412 formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_NUMBER, "number"); 413 } 414 return formatTable; 415 } 416 } 417 | Popular Tags |