1 21 22 package org.armedbear.j; 23 24 import gnu.regexp.REMatch; 25 import java.io.IOException ; 26 import java.io.OutputStreamWriter ; 27 import java.util.List ; 28 import javax.swing.SwingUtilities ; 29 import org.armedbear.lisp.Site; 30 31 public class LispShell extends Shell 32 { 33 private static final String DEFAULT_PROMPT_PATTERN = 34 "^[^:>\\*\\]]*[:>\\*\\]] *"; 35 36 private static final String ALLEGRO_PROMPT_PATTERN = 37 "^(\\[[0-9+][ci]?\\] )?[^ ]+\\([0-9]+\\): "; 38 39 private static final String ARMEDBEAR_PROMPT_PATTERN = 40 ALLEGRO_PROMPT_PATTERN; 41 42 private static final String CLISP_PROMPT_PATTERN = 43 "^[^>\\*\\]]*\\[[0-9]+\\]> "; 44 45 private static final String CMUCL_PROMPT_PATTERN = 46 "^\\* |^[0-9]+\\] "; 47 48 private static final String SBCL_PROMPT_PATTERN = 49 CMUCL_PROMPT_PATTERN + "|" + ALLEGRO_PROMPT_PATTERN; 50 51 private final boolean slime; 52 53 private String resetCommand = null; 54 private String exitCommand = "(exit)"; 55 56 private Position posBeforeLastPrompt; 57 private Position posEndOfInput; 58 59 private File currentDirectory; 60 61 protected LispShell() 63 { 64 setPromptRE(ARMEDBEAR_PROMPT_PATTERN); 65 setResetCommand(":reset"); 66 slime = false; 67 } 68 69 private LispShell(String shellCommand, String title) 70 { 71 super(shellCommand, LispShellMode.getMode()); 72 this.title = title; 73 formatter = mode.getFormatter(this); 74 slime = title.startsWith("slime "); 75 } 76 77 public final boolean isLisp() 78 { 79 return true; 80 } 81 82 private void setResetCommand(String s) 83 { 84 resetCommand = s; 85 } 86 87 private void setExitCommand(String s) 88 { 89 exitCommand = s; 90 } 91 92 private static Shell createLispShell(String shellCommand, String title, 93 boolean startSlime) 94 { 95 if (startSlime) { 96 if (shellCommand.indexOf("sbcl") >= 0) { 97 File lispHome = File.getInstance(Site.getLispHome()); 98 if (lispHome == null) 99 return null; File swankLoader = File.getInstance(lispHome, 101 "swank-loader.lisp"); 102 if (swankLoader == null) 103 return null; shellCommand = 105 shellCommand + " --load " + swankLoader.canonicalPath(); 106 } else if (shellCommand.indexOf("abcl") >= 0 || 107 shellCommand.indexOf("org.armedbear.lisp") >= 0) { 108 shellCommand = 109 shellCommand.concat(" --load-system-file swank-loader.lisp"); 110 } 111 } 112 LispShell lisp = new LispShell(shellCommand, title); 113 lisp.startProcess(); 114 if (lisp.getProcess() == null) { 115 Editor.getBufferList().remove(lisp); 116 String message; 117 if (Utilities.haveJpty()) 118 message = "Unable to start process \"" + shellCommand + "\""; 119 else 120 message = JPTY_NOT_FOUND; 121 MessageDialog.showMessageDialog(message, "Error"); 122 return null; 123 } 124 if (shellCommand.equals("alisp") || shellCommand.equals("/usr/bin/alisp")) { 125 lisp.setPromptRE(ALLEGRO_PROMPT_PATTERN); 126 lisp.setResetCommand(":reset"); 127 } else if (shellCommand.indexOf("clisp") >= 0) { 128 lisp.setPromptRE(CLISP_PROMPT_PATTERN); 130 lisp.setResetCommand("(sys::debug-unwind)"); 131 } else if (shellCommand.equals("/usr/bin/lisp")) { 132 lisp.setPromptRE(CMUCL_PROMPT_PATTERN); 133 lisp.setResetCommand(":q"); 134 lisp.setExitCommand("(quit)"); 135 } else if (shellCommand.indexOf("sbcl") >= 0) { 136 lisp.setPromptRE(SBCL_PROMPT_PATTERN); 137 lisp.setResetCommand(":abort"); 138 lisp.setExitCommand("(quit)"); 139 } else if (shellCommand.indexOf("org.armedbear.lisp") >= 0 || 140 shellCommand.indexOf("abcl") >= 0) 141 { 142 lisp.setPromptRE(ARMEDBEAR_PROMPT_PATTERN); 143 lisp.setResetCommand(":reset"); 144 } else { 145 lisp.setPromptRE(DEFAULT_PROMPT_PATTERN); 146 if (shellCommand.equals("rep") || shellCommand.equals("/usr/bin/rep")) 147 lisp.setExitCommand(",quit"); 148 } 149 lisp.needsRenumbering(true); 150 if (Editor.isLispInitialized()) 151 LispAPI.invokeLispShellStartupHook(lisp, shellCommand); 152 return lisp; 153 } 154 155 protected void startProcess() 156 { 157 if (shellCommand == null) { 158 Debug.bug(); 159 return; 160 } 161 File initialDirectory = Editor.currentEditor().getCurrentDirectory(); 162 if (initialDirectory == null || initialDirectory.isRemote()) 163 initialDirectory = Directories.getUserHomeDirectory(); 164 List tokens = Utilities.tokenize(shellCommand); 165 final int tokenCount = tokens.size(); 166 String [] cmdArray; 167 int i = 0; 168 if (Utilities.haveJpty()) { 169 cmdArray = new String [tokenCount + 1]; 170 cmdArray[i++] = "jpty"; 171 } else 172 cmdArray = new String [tokenCount]; 173 for (int j = 0; j < tokenCount; j++) 174 cmdArray[i++] = (String ) tokens.get(j); 175 Process p = null; 176 try { 177 p = Runtime.getRuntime().exec(cmdArray, null, 178 new java.io.File (initialDirectory.canonicalPath())); 179 setProcess(p); 180 } 181 catch (Throwable t) { 182 setProcess(null); 183 return; 184 } 185 currentDirectory = initialDirectory; 186 startWatcherThread(); 187 try { 190 Thread.sleep(100); 191 } 192 catch (InterruptedException e) { 193 Log.error(e); 194 } 195 if (getProcess() == null) 198 return; try { 200 stdin = new OutputStreamWriter (p.getOutputStream()); 201 stdoutThread = new StdoutThread(p.getInputStream()); 202 stderrThread = new StderrThread(p.getErrorStream()); 203 stdoutThread.start(); 204 stderrThread.start(); 205 readOnly = false; 206 } 207 catch (Throwable t) { 208 Log.error(t); 209 } 210 } 211 212 protected void initializeHistory() 213 { 214 history = new History("lisp.history", 30); 215 } 216 217 public void enter() 218 { 219 if (!checkProcess()) 220 return; 221 final Editor editor = Editor.currentEditor(); 222 Position dot = editor.getDotCopy(); 223 if (dot == null) 224 return; 225 if (needsRenumbering) 226 renumber(); 227 final Line dotLine = dot.getLine(); 228 final Position endOfOutput = getEndOfOutput(); 229 if (endOfOutput == null) { 230 dotLine.setText(""); 232 return; 233 } 234 if (dot.isBefore(endOfOutput)) { 235 editor.newlineAndIndent(); 236 return; } 238 final Line promptLine = endOfOutput.getLine(); 239 Annotation a = new Annotation(endOfOutput.getOffset()); 240 promptLine.setAnnotation(a); 241 promptLine.setFlags(STATE_PROMPT); 242 Position end = getEnd(); 243 Position pos = LispMode.findContainingSexp(end); 244 boolean isComplete = (pos == null || pos.isBefore(endOfOutput)); 245 if (isComplete) { 246 editor.eob(); 248 editor.insertLineSeparator(); 249 editor.getDotLine().setFlags(0); 250 } else { 251 editor.newline(); 253 editor.getDotLine().setFlags(STATE_INPUT); 254 } 255 if (needsRenumbering) 256 renumber(); 257 editor.moveCaretToDotCol(); 258 editor.getDisplay().setReframe(-2); 259 resetUndo(); 260 stripEcho = true; 261 if (isComplete) { 262 Position begin = endOfOutput; 264 end = editor.getDotCopy(); 265 end.setOffset(end.getLineLength()); 266 setEndOfOutput(end); 267 Line lineBeforeLastPrompt = promptLine.previous(); 268 if (lineBeforeLastPrompt != null) { 269 posBeforeLastPrompt = 270 new Position(lineBeforeLastPrompt, 271 lineBeforeLastPrompt.length()); 272 } 273 posEndOfInput = end.copy(); 274 String s = new Region(this, begin, end).toString(); 275 sendInputToLisp(s); 276 } else 277 indentLineAtDot(editor); 278 } 279 280 public void resetLisp() 281 { 282 if (resetCommand != null) { 283 Position pos = getEnd(); 284 insertString(pos, resetCommand.concat("\n")); 285 if (needsRenumbering()) 286 renumber(); 287 enforceOutputLimit(Property.SHELL_OUTPUT_LIMIT); 288 posEndOfInput = pos.copy(); 289 send(resetCommand); 290 } 291 } 292 293 protected void stdOutUpdate(final String s) 294 { 295 String prompt; 296 int index = s.lastIndexOf('\n'); 297 if (index >= 0) 298 prompt = s.substring(index + 1); 299 else 300 prompt = s; 301 final REMatch match = promptRE.getMatch(prompt); 302 if (match != null) { 303 String m = match.toString(); 305 if (prompt.startsWith(m)) { 306 if (prompt.substring(m.length()).startsWith(m)) { 307 prompt = prompt.substring(m.length()); 309 } 310 } 311 } 312 final String output; 313 if (index >= 0) 314 output = s.substring(0, index + 1) + prompt; 315 else 316 output = prompt; 317 Runnable r = new Runnable () { 318 public void run() 319 { 320 Position pos = getEnd(); 321 if (pos != null) 322 pos.getLine().setFlags(0); if (output.length() > 0) { 324 appendString(output); 325 if (match != null) { 326 Line lineBeforeLastPrompt = 327 getEnd().getLine().previous(); 328 if (lineBeforeLastPrompt != null) { 329 posBeforeLastPrompt = 330 new Position(lineBeforeLastPrompt, 331 lineBeforeLastPrompt.length()); 332 } 333 if (isBusy()) 334 setBusy(false); 335 } 336 } 337 updateDisplayInAllFrames(); 338 resetUndo(); 339 } 340 }; 341 SwingUtilities.invokeLater(r); 342 } 343 344 protected void stdErrUpdate(final String s) 345 { 346 Runnable r = new Runnable () { 347 public void run() 348 { 349 appendString(s); 350 updateDisplayInAllFrames(); 351 resetUndo(); 352 } 353 }; 354 SwingUtilities.invokeLater(r); 355 } 356 357 protected void appendString(String s) 358 { 359 try { 360 lockWrite(); 361 } 362 catch (InterruptedException e) { 363 Log.error(e); 364 return; 365 } 366 try { 367 if (slime) { 368 if (posEndOfInput == null) 370 posEndOfInput = new Position(getFirstLine(), 0); 371 final Position pos; 372 if (posBeforeLastPrompt != null && posEndOfInput != null) { 373 Position posLastPrompt = 374 new Position(posBeforeLastPrompt.getNextLine(), 0); 375 if (posEndOfInput.isAfter(posLastPrompt)) { 376 pos = getEnd(); 378 } else { 379 pos = posBeforeLastPrompt; 380 } 381 } else 382 pos = getEnd(); 383 if (pos != null) { 384 if (pos == posBeforeLastPrompt) { 385 if (s.length() > 0) { 386 if (s.charAt(s.length() - 1) == '\n') 387 s = s.substring(0, s.length() - 1); 388 } 389 if (s.length() > 0 && s.charAt(0) != '\n') 390 insertLineSeparator(pos); 391 } 392 insertString(pos, s); 393 if (needsRenumbering()) 394 renumber(); 395 enforceOutputLimit(Property.SHELL_OUTPUT_LIMIT); 396 if (pos != posBeforeLastPrompt) 397 setEndOfOutput(pos.copy()); 398 } else { 399 setText(s); 401 setEndOfOutput(getEnd().copy()); 402 } 403 } else { 404 Position pos = getEnd(); 406 if (pos != null) { 407 insertString(pos, s); 408 if (needsRenumbering()) 409 renumber(); 410 enforceOutputLimit(Property.SHELL_OUTPUT_LIMIT); 411 setEndOfOutput(pos.copy()); 412 } else { 413 setText(s); 414 setEndOfOutput(getEnd().copy()); 415 } 416 } 417 } 418 finally { 419 unlockWrite(); 420 } 421 } 422 423 private void indentLineAtDot(Editor editor) 424 { 425 final Line dotLine = editor.getDotLine(); 426 if (dotLine.length() > 0) 427 return; 428 try { 429 lockWrite(); 430 } 431 catch (InterruptedException e) { 432 Log.error(e); 433 return; 434 } 435 try { 436 getFormatter().parseBuffer(); 437 int indent = mode.getCorrectIndentation(dotLine, this); 438 if (indent != getIndentation(dotLine)) { 439 editor.addUndo(SimpleEdit.LINE_EDIT); 440 setIndentation(dotLine, indent); 441 dotLine.setFlags(STATE_INPUT); 442 modified(); 443 } 444 if (dotLine.length() > 0) { 445 editor.moveDotToIndentation(); 446 editor.moveCaretToDotCol(); 447 } else { 448 final Display display = editor.getDisplay(); 449 display.setCaretCol(indent - display.getShift()); 450 if (getBooleanProperty(Property.RESTRICT_CARET)) 451 editor.fillToCaret(); 452 } 453 resetUndo(); } 455 finally { 456 unlockWrite(); 457 } 458 } 459 460 private void sendInputToLisp(String input) 461 { 462 String trim = input.trim(); 465 if (trim.length() > 2) { 466 history.append(trim); 467 history.save(); 468 } 469 send(input); 470 } 471 472 public void dispose() 473 { 474 if (!checkProcess()) { 475 Log.debug("checkProcess returned false"); 476 return; 477 } 478 Thread t = new Thread ("LispShell dispose") { 479 public void run() 480 { 481 try { 482 stdin.write(3); 483 stdin.flush(); 484 stdin.write(exitCommand); 485 stdin.write("\n"); 486 stdin.flush(); 487 stdin.close(); 488 final Process p = getProcess(); 489 if (p != null) { 490 p.destroy(); 491 p.waitFor(); 492 } 493 } 494 catch (IOException e) { 495 Log.error(e); 496 } 497 catch (InterruptedException e) { 498 Log.error(e); 499 } 500 } 501 }; 502 t.setPriority(Thread.MIN_PRIORITY); 503 t.setDaemon(true); 504 t.start(); 505 } 506 507 public File getCurrentDirectory() 508 { 509 return currentDirectory; 510 } 511 512 public File getCompletionDirectory() 513 { 514 return currentDirectory; 515 } 516 517 public String getFileNameForDisplay() 518 { 519 return title; 520 } 521 522 public String toString() 523 { 524 return title; 525 } 526 527 public static void slime() 528 { 529 _slime(getDefaultLispShellCommand(), "slime abcl", false); 530 } 531 532 public static void slime(String shellCommand) 533 { 534 _slime(shellCommand, "slime ".concat(shellCommand), 535 Platform.isPlatformUnix()); 537 } 538 539 private static final void _slime(String shellCommand, String title, 540 boolean requireJpty) 541 { 542 Buffer buffer = findSlime(); 543 if (buffer != null) { 544 final Editor editor = Editor.currentEditor(); 545 editor.makeNext(buffer); 546 Buffer b = editor.getBuffer(); 547 if (b != null && b.isPaired()) 548 editor.switchToBuffer(buffer); 549 else 550 editor.activate(buffer); 551 return; 552 } 553 lisp(shellCommand, title, requireJpty, true); 554 } 555 556 public static void lisp() 557 { 558 lisp(getDefaultLispShellCommand(), "abcl", false, false); 559 } 560 561 public static void lisp(String shellCommand) 562 { 563 lisp(shellCommand, shellCommand, Platform.isPlatformUnix(), false); 565 } 566 567 private static void lisp(String shellCommand, String title, 568 boolean requireJpty, boolean startSlime) 569 { 570 if (requireJpty && !Utilities.haveJpty()) { 571 MessageDialog.showMessageDialog(JPTY_NOT_FOUND, "Error"); 572 return; 573 } 574 if (Platform.isPlatformWindows()) 575 if (!Platform.isPlatformWindows5()) 576 return; 577 final Editor editor = Editor.currentEditor(); 578 Buffer buf = findLisp(title); 580 if (buf == null) { 581 editor.setWaitCursor(); 582 buf = createLispShell(shellCommand, title, startSlime); 583 if (buf != null) 584 buf.setBusy(true); 585 editor.setDefaultCursor(); 586 } else 587 startSlime = false; if (buf != null) { 589 editor.makeNext(buf); 590 Buffer b = editor.getBuffer(); 591 if (b != null && b.isPaired()) 592 editor.switchToBuffer(buf); 593 else 594 editor.activate(buf); 595 if (startSlime) 596 startSlime(buf); 597 } 598 } 599 600 private static void startSlime(final Buffer buffer) 601 { 602 Runnable r = new Runnable () { 603 public void run() 604 { 605 try { 606 JLisp.runLispCommand("(sys:load-system-file \"slime-loader.lisp\")"); 607 JLisp.runLispCommand("(setq slime::*repl-buffer-name* \"" + 608 buffer.getTitle() + "\")"); 609 JLisp.runLispCommand("(slime:slime)"); 610 } 611 catch (Throwable t) { 612 Log.debug(t); 613 } 614 } 615 }; 616 new Thread (r).start(); 617 } 618 619 private static String getDefaultLispShellCommand() 620 { 621 File java = null; 622 File javaHome = File.getInstance(System.getProperty("java.home")); 623 if (javaHome != null && javaHome.isDirectory()) { 624 java = File.getInstance(javaHome, 625 Platform.isPlatformWindows() ? "bin\\java.exe" : "bin/java"); 626 if (java != null && !java.isFile()) 627 java = null; 628 } 629 String classPath = System.getProperty("java.class.path"); 632 if (classPath.equals("j.jar:.")) classPath = "j.jar"; 634 if (classPath.indexOf(LocalFile.getPathSeparatorChar()) < 0) { 635 String path = classPath; 637 if (Platform.isPlatformWindows()) 638 path = path.toLowerCase(); 639 if (path.equals("j.jar") || path.endsWith("/j.jar") || 640 path.endsWith("\\j.jar")) 641 { 642 File dir = File.getInstance(System.getProperty("user.dir")); 643 File file = File.getInstance(dir, path); 644 if (file != null && file.isFile()) 645 classPath = file.canonicalPath(); 646 } 647 } 648 FastStringBuffer sb = new FastStringBuffer(); 649 if (java != null) { 650 sb.append('"'); 651 sb.append(java.canonicalPath()); 652 sb.append('"'); 653 String vendor = System.getProperty("java.vendor"); 654 if (vendor != null) { 655 if (vendor.indexOf("Sun") >= 0 || 656 vendor.indexOf("Blackdown") >= 0) { 657 String vm = System.getProperty("java.vm.name"); 658 if (vm != null && vm.toLowerCase().indexOf("server") >= 0) 659 sb.append(" -server"); 660 sb.append(" -Xmx128M"); 661 if (Platform.isPlatformUnix()) { 662 String lispHome = org.armedbear.lisp.Site.getLispHome(); 663 if (lispHome != null) { 664 sb.append(" -Xrs -Djava.library.path="); 665 sb.append(lispHome); 666 sb.append(":/usr/local/lib/abcl"); 667 } 668 } 669 } else if (vendor.indexOf("IBM") >= 0) { 670 sb.append(" -Xss512K"); 671 sb.append(" -Xmx128M"); 672 } 673 } 674 } else 675 sb.append("java"); 676 sb.append(" -cp "); 677 sb.append('"'); 678 sb.append(classPath); 679 sb.append('"'); 680 sb.append(" org.armedbear.lisp.Main"); 681 return sb.toString(); 682 } 683 684 public static CommandInterpreter findLisp(String title) 685 { 686 for (BufferIterator it = new BufferIterator(); it.hasNext();) { 687 Buffer b = it.nextBuffer(); 688 if (b instanceof CommandInterpreter) { 689 CommandInterpreter comint = (CommandInterpreter) b; 690 if (comint.isLisp()) { 691 if (title == null || title.equals(comint.getTitle())) 692 return comint; 693 } 694 } 695 } 696 return null; 697 } 698 699 private static final CommandInterpreter findSlime() 700 { 701 for (BufferIterator it = new BufferIterator(); it.hasNext();) { 702 Buffer b = it.nextBuffer(); 703 if (b instanceof CommandInterpreter) { 704 CommandInterpreter comint = (CommandInterpreter) b; 705 if (comint.isLisp()) { 706 String title = comint.getTitle(); 707 if (title != null && title.startsWith("slime")) 708 return comint; 709 } 710 } 711 } 712 return null; 713 } 714 } 715 | Popular Tags |