1 21 22 package org.armedbear.j; 23 24 import gnu.regexp.RE; 25 import gnu.regexp.REException; 26 import gnu.regexp.REMatch; 27 import gnu.regexp.UncheckedRE; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.OutputStreamWriter ; 31 import javax.swing.Icon ; 32 import javax.swing.SwingUtilities ; 33 import javax.swing.undo.CompoundEdit ; 34 35 public class CommandInterpreter extends Buffer 36 { 37 protected RE promptRE = new UncheckedRE(DEFAULT_SHELL_PROMPT_PATTERN); 38 protected OutputStreamWriter stdin; 39 protected ReaderThread stdoutThread; 40 protected ReaderThread stderrThread; 41 protected History history; 42 protected String input; 43 protected boolean stripEcho; 44 protected String shellCommand; 45 46 private Position posEndOfOutput; 47 48 protected CommandInterpreter() 49 { 50 super(); 51 initializeUndo(); 52 initializeHistory(); 53 } 54 55 public final String getShellCommand() 56 { 57 return shellCommand; 58 } 59 60 public boolean isLisp() 61 { 62 return false; 63 } 64 65 public final boolean isModified() 66 { 67 return false; 68 } 69 70 protected void initializeHistory() 71 { 72 history = new History(null, 30); 73 } 74 75 public final RE getPromptRE() 76 { 77 return promptRE; 78 } 79 80 protected final void setPromptRE(String pattern) 81 { 82 try { 83 promptRE = new RE(pattern); 84 } 85 catch (REException e) { 86 Log.error(e); 87 } 88 } 89 90 protected final synchronized Position getEndOfOutput() 91 { 92 if (posEndOfOutput == null) 93 return null; 94 if (contains(posEndOfOutput.getLine())) { 95 if (posEndOfOutput.getOffset() > posEndOfOutput.getLineLength()) 96 posEndOfOutput.setOffset(posEndOfOutput.getLineLength()); 97 return posEndOfOutput; 98 } 99 RE promptRE = getPromptRE(); 101 if (promptRE != null) { 102 Position eob = getEnd(); 103 if (eob == null) 104 return null; 105 Line line = eob.getLine(); 106 while (line != null) { 107 int flags = line.flags(); 108 if (flags == 0 || flags == STATE_PROMPT || flags == STATE_INPUT) { 109 final REMatch match = promptRE.getMatch(line.getText()); 110 if (match != null && match.getStartIndex() == 0) { 111 return new Position(line, match.getEndIndex()); 112 } 113 } 114 line = line.previous(); 115 } 116 } 117 return null; 118 } 119 120 protected final synchronized void setEndOfOutput(Position pos) 121 { 122 posEndOfOutput = pos; 123 } 124 125 public Icon getIcon() 126 { 127 return Utilities.getIconFromFile("jpty.png"); 128 } 129 130 public int load() 131 { 132 try { 133 lockWrite(); 134 } 135 catch (InterruptedException e) { 136 Log.debug(e); 137 return LOAD_FAILED; } 139 try { 140 appendLine(""); 141 setLoaded(true); 142 } 143 finally { 144 unlockWrite(); 145 } 146 return LOAD_COMPLETED; 147 } 148 149 protected boolean checkProcess() 151 { 152 return true; 153 } 154 155 protected void enter() 156 { 157 if (!checkProcess()) 158 return; 159 final Editor editor = Editor.currentEditor(); 160 final Line dotLine = editor.getDotLine(); 161 Position endOfOutput = getEndOfOutput(); 162 if (endOfOutput == null) { 163 dotLine.setText(""); 165 return; 166 } 167 if (endOfOutput.getLine() == dotLine) { 168 if (endOfOutput.getOffset() < dotLine.length()) 169 input = dotLine.getText().substring(endOfOutput.getOffset()); 170 else 171 input = ""; 172 } else { 173 input = stripPrompt(dotLine.getText()); 175 } 176 if (input.length() != 0) { 177 history.append(input); 178 history.save(); 179 } 180 enter(input); 181 } 182 183 protected void enter(final String s) 184 { 185 final Editor editor = Editor.currentEditor(); 186 Line dotLine = editor.getDotLine(); 187 if (dotLine.next() != null) { 188 editor.eob(); 190 dotLine = editor.getDotLine(); 191 192 final REMatch match = promptRE.getMatch(dotLine.getText()); 194 if (match != null) 195 dotLine.setText(dotLine.substring(0, match.getEndIndex())); 196 197 dotLine.setText(dotLine.getText() + s); 199 } 200 int flags = dotLine.flags(); 201 if (flags == 0) 202 dotLine.setFlags(STATE_INPUT); 203 editor.eol(); 204 editor.insertLineSeparator(); 205 if (needsRenumbering) 206 renumber(); 207 editor.getDotLine().setFlags(0); 208 editor.moveCaretToDotCol(); 209 editor.getDisplay().setReframe(-2); 210 resetUndo(); 211 stripEcho = true; 212 send(s); 213 } 214 215 protected void send(final String s) 216 { 217 try { 218 stdin.write(s); 219 if (!s.endsWith("\n")) 220 stdin.write("\n"); 221 stdin.flush(); 222 } 223 catch (IOException e) { 224 Log.error(e); 225 } 226 } 227 228 protected String stripPrompt(String s) 229 { 230 if (promptRE != null) { 231 REMatch match = promptRE.getMatch(s); 232 if (match != null) 233 return s.substring(match.getEndIndex()); 234 } 235 RE re = new UncheckedRE(".*: ?"); 237 REMatch match = re.getMatch(s); 238 if (match != null) 239 return s.substring(match.getEndIndex()); 240 return s; 241 } 242 243 protected void escape() 244 { 245 Editor editor = Editor.currentEditor(); 246 Position endOfOutput = getEndOfOutput(); 247 if (editor.getMark() != null || endOfOutput == null || 248 editor.getDot().isBefore(endOfOutput)) 249 { 250 editor.escape(); 252 return; 253 } 254 if (editor.escapeInternal()) 255 return; 256 CompoundEdit compoundEdit = beginCompoundEdit(); 257 editor.addUndo(SimpleEdit.MOVE); 258 editor.moveDotTo(endOfOutput); 259 editor.moveCaretToDotCol(); 260 editor.setMark(getEnd()); 261 editor.deleteRegion(); 262 endCompoundEdit(compoundEdit); 263 resetUndo(); 265 } 266 267 protected void home() 268 { 269 final Editor editor = Editor.currentEditor(); 270 if (editor.getDotOffset() == 0) 271 return; 272 editor.addUndo(SimpleEdit.MOVE); 273 editor.beginningOfBlock(); 274 int offset = 0; 275 if (promptRE != null) { 276 Line dotLine = editor.getDotLine(); 277 if (dotLine.next() == null || dotLine.flags() == STATE_INPUT) { 278 REMatch match = promptRE.getMatch(dotLine.getText()); 279 if (match != null) 280 offset = match.getEndIndex(); 281 } 282 } 283 if (editor.getDotOffset() <= offset) 285 offset = 0; 286 editor.getDot().setOffset(offset); 287 editor.getDisplay().moveCaretToDotCol(); 288 } 289 290 protected void backspace() 291 { 292 Position endOfOutput = getEndOfOutput(); 293 if (endOfOutput == null) 294 return; 295 boolean ok = true; 296 final Editor editor = Editor.currentEditor(); 297 if (editor.getDotLine() == endOfOutput.getLine()) { 298 if (editor.getDotOffset() <= endOfOutput.getOffset()) 299 ok = false; 300 } else{ 301 String text = editor.getDotLine().getText(); 302 if (promptRE != null) { 303 REMatch match = promptRE.getMatch(text); 304 if (match != null) { 305 if (editor.getDotOffset() <= match.getEndIndex()) 306 ok = false; 307 } 308 } 309 } 310 if (ok) 311 editor.backspace(); 312 } 313 314 private void previousInput() 315 { 316 getInputFromHistory(-1); 317 } 318 319 private void nextInput() 320 { 321 getInputFromHistory(1); 322 } 323 324 private String currentInput; 325 326 private void getInputFromHistory(int direction) 327 { 328 if (getEndOfOutput() == null) { 329 return; 331 } 332 final Editor editor = Editor.currentEditor(); 333 final Line dotLine = editor.getDotLine(); 334 if (dotLine.next() != null) { 335 editor.status("Not at command prompt"); 336 return; 337 } 338 if (editor.getLastCommand() != COMMAND_HISTORY) { 339 history.reset(); 340 Position begin = getEndOfOutput().copy(); 341 Position end = getEnd(); 342 Region r = new Region(editor.getBuffer(), begin, end); 343 currentInput = r.toString(); 344 } 345 String s; 346 while (true) { 347 s = direction < 0 ? history.getPrevious() : history.getNext(); 348 if (s == null) 349 break; 350 s = s.trim(); 351 if (s.equals(currentInput)) 352 continue; 353 if (currentInput.length() == 0 || s.startsWith(currentInput)) 354 break; 355 } 356 if (s != null) { 357 CompoundEdit compoundEdit = beginCompoundEdit(); 358 editor.addUndo(SimpleEdit.MOVE); 359 editor.setDot(getEndOfOutput().copy()); 360 editor.setMark(getEnd()); 361 editor.deleteRegion(); 362 editor.addUndo(SimpleEdit.INSERT_STRING); 363 editor.insertStringInternal(s); 364 editor.moveCaretToDotCol(); 365 endCompoundEdit(compoundEdit); 366 resetUndo(); 368 } 369 for (Line line = getEndOfOutput().getLine(); line != null; line = line.next()) 370 line.setFlags(STATE_INPUT); 371 editor.setCurrentCommand(COMMAND_HISTORY); 372 } 373 374 protected void appendString(String s) 375 { 376 try { 377 lockWrite(); 378 } 379 catch (InterruptedException e) { 380 Log.error(e); 381 return; 382 } 383 try { 384 Position pos = getEnd(); 385 if (pos != null) { 386 insertString(pos, s); 387 if (needsRenumbering()) 388 renumber(); 389 enforceOutputLimit(Property.SHELL_OUTPUT_LIMIT); 390 setEndOfOutput(pos.copy()); 391 } else { 392 setText(s); 393 setEndOfOutput(getEnd().copy()); 394 } 395 } 396 finally { 397 unlockWrite(); 398 } 399 } 400 401 protected void updateDisplayInAllFrames() 402 { 403 for (EditorIterator it = new EditorIterator(); it.hasNext();) { 404 Editor ed = it.nextEditor(); 405 if (ed.getBuffer() == this) { 406 ed.eob(); 407 ed.getDisplay().setReframe(-2); 408 ed.setUpdateFlag(REPAINT); 409 ed.updateDisplay(); 410 } 411 } 412 } 413 414 protected void sendChar(int c) 415 { 416 final Editor editor = Editor.currentEditor(); 417 final Line dotLine = editor.getDotLine(); 418 if (dotLine.next() == null) 419 dotLine.setFlags(STATE_INPUT); 420 try { 421 stdin.write(c); 422 stdin.flush(); 423 } 424 catch (IOException e) { 425 Log.error(e); 426 } 427 } 428 429 protected String stdOutFilter(String s) 430 { 431 return removeEcho(s); 432 } 433 434 protected void stdOutUpdate(final String s) 435 { 436 Runnable r = new Runnable () { 437 public void run() 438 { 439 appendString(s); 440 updateDisplayInAllFrames(); 441 resetUndo(); 442 } 443 }; 444 SwingUtilities.invokeLater(r); 445 } 446 447 protected String stdErrFilter(String s) 448 { 449 return removeEcho(s); 450 } 451 452 protected void stdErrUpdate(final String s) 453 { 454 Runnable r = new Runnable () { 455 public void run() 456 { 457 appendString(s); 458 updateDisplayInAllFrames(); 459 resetUndo(); 460 } 461 }; 462 SwingUtilities.invokeLater(r); 463 } 464 465 private String removeEcho(String s) { 466 if (stripEcho && input != null && s.startsWith(input)) { 467 int begin = input.length(); 468 if (s.length() > begin && s.charAt(begin) == '\r') 469 ++begin; 470 if (s.length() > begin && s.charAt(begin) == '\n') 471 ++begin; 472 s = s.substring(begin); 473 stripEcho = false; 475 } 476 return s; 477 } 478 479 protected class StdoutThread extends ReaderThread 480 { 481 public StdoutThread(InputStream stdout) 482 { 483 super(stdout); 484 } 485 486 public String filter(String s) 487 { 488 return stdOutFilter(s); 489 } 490 491 public void update(String s) 492 { 493 stdOutUpdate(s); 494 } 495 } 496 497 protected class StderrThread extends ReaderThread 498 { 499 public StderrThread(InputStream stderr) 500 { 501 super(stderr); 502 } 503 504 public String filter(String s) 505 { 506 return stdErrFilter(s); 507 } 508 509 public void update(String s) 510 { 511 stdErrUpdate(s); 512 } 513 } 514 515 public static void shellEnter() 517 { 518 final Buffer buffer = Editor.currentEditor().getBuffer(); 519 if (buffer instanceof CommandInterpreter) 520 ((CommandInterpreter)buffer).enter(); 521 } 522 523 public static void shellEscape() 524 { 525 final Buffer buffer = Editor.currentEditor().getBuffer(); 526 if (buffer instanceof CommandInterpreter) 527 ((CommandInterpreter)buffer).escape(); 528 } 529 530 public static void shellHome() 531 { 532 final Buffer buffer = Editor.currentEditor().getBuffer(); 533 if (buffer instanceof CommandInterpreter) 534 ((CommandInterpreter)buffer).home(); 535 } 536 537 public static void shellBackspace() 538 { 539 final Buffer buffer = Editor.currentEditor().getBuffer(); 540 if (buffer instanceof CommandInterpreter) 541 ((CommandInterpreter)buffer).backspace(); 542 } 543 544 public static void shellPreviousInput() 545 { 546 final Buffer buffer = Editor.currentEditor().getBuffer(); 547 if (buffer instanceof CommandInterpreter) 548 ((CommandInterpreter)buffer).previousInput(); 549 } 550 551 public static void shellNextInput() 552 { 553 final Buffer buffer = Editor.currentEditor().getBuffer(); 554 if (buffer instanceof CommandInterpreter) 555 ((CommandInterpreter)buffer).nextInput(); 556 } 557 558 public static void shellPreviousPrompt() 559 { 560 findPrompt(-1); 561 } 562 563 public static void shellNextPrompt() 564 { 565 findPrompt(1); 566 } 567 568 private static final void findPrompt(int direction) 569 { 570 final Editor editor = Editor.currentEditor(); 571 final Buffer buffer = editor.getBuffer(); 572 if (buffer instanceof CommandInterpreter) { 573 Position dot = editor.getDot(); 574 if (dot != null) { 575 Line line = 576 direction > 0 ? dot.getLine().next() : dot.getLine().previous(); 577 RE promptRE = ((CommandInterpreter)buffer).getPromptRE(); 578 if (promptRE != null) { 579 while (line != null) { 580 int flags = line.flags(); 581 if (flags == STATE_PROMPT || flags == STATE_INPUT) { 582 final REMatch match = promptRE.getMatch(line.getText()); 583 if (match != null && match.getStartIndex() == 0) { 584 Position pos = new Position(line, match.getEndIndex()); 585 editor.moveDotTo(pos); 586 return; 587 } 588 } 589 line = direction > 0 ? line.next() : line.previous(); 590 } 591 } 592 } 593 } 594 } 595 } 596 | Popular Tags |