PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/plugins-trunk/Console/console/Console.java

#
Java | 1165 lines | 802 code | 146 blank | 217 comment | 118 complexity | 5e824303e355d75124f9af44a6e8b12e MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * Console.java - The console window
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2005 Slava Pestov
  7. * parts Copyright (C) 2006 Alan Ezust
  8. * parts Copyright (C) 2010 Eric Le Lay
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24. package console;
  25. //{{{ Imports
  26. import java.awt.BorderLayout;
  27. import java.awt.Color;
  28. import java.awt.Component;
  29. import java.awt.Dimension;
  30. import java.awt.Image;
  31. import java.awt.image.BufferedImage;
  32. import java.awt.Graphics2D;
  33. import java.awt.Insets;
  34. import java.awt.Toolkit;
  35. import java.awt.event.ActionEvent;
  36. import java.awt.event.ActionListener;
  37. import java.awt.event.InputEvent;
  38. import java.awt.event.KeyEvent;
  39. import java.io.File;
  40. import java.util.Arrays;
  41. import java.util.ArrayList;
  42. import java.util.HashMap;
  43. import java.util.Iterator;
  44. import java.util.Map;
  45. import javax.swing.*;
  46. import javax.swing.border.EmptyBorder;
  47. import javax.swing.text.*;
  48. import org.gjt.sp.jedit.*;
  49. import org.gjt.sp.jedit.View;
  50. import org.gjt.sp.jedit.gui.*;
  51. import org.gjt.sp.jedit.msg.DockableWindowUpdate;
  52. import org.gjt.sp.jedit.msg.VFSPathSelected;
  53. import org.gjt.sp.jedit.msg.PluginUpdate;
  54. import org.gjt.sp.jedit.msg.PropertiesChanged;
  55. import org.gjt.sp.jedit.msg.ViewUpdate;
  56. import org.gjt.sp.util.Log;
  57. import console.SystemShell.ConsoleState;
  58. import errorlist.DefaultErrorSource;
  59. import errorlist.ErrorSource;
  60. import org.gjt.sp.util.StandardUtilities;
  61. //}}}
  62. // {{{ class Console
  63. /**
  64. * Console - an instance of a panel inside a dockablewindow.
  65. * May contain multiple Shells, each with its own shell state.
  66. *
  67. *
  68. * @version $Id: Console.java 21235 2012-03-01 02:59:00Z ezust $
  69. */
  70. public class Console extends JPanel
  71. implements EBComponent, DefaultFocusComponent
  72. {
  73. //{{{ Private members
  74. //{{{ Icons
  75. private static final Icon RUN_AGAIN = GUIUtilities.loadIcon("RunAgain.png");
  76. private static final Icon RUN = GUIUtilities.loadIcon("Run.png");
  77. private static final Icon TO_BUFFER = GUIUtilities.loadIcon("RunToBuffer.png");
  78. private static final Icon STOP = GUIUtilities.loadIcon("Cancel.png");
  79. private static final Icon CLEAR = GUIUtilities.loadIcon("Clear.png");
  80. //}}}
  81. //{{{ Instance variables
  82. private View view;
  83. private Map<String, ShellState> shellStateMap;
  84. // A pointer to the currently selected Shell instance
  85. private Shell currentShell;
  86. // The Output instance corresponding to the current shell.
  87. private ShellState shellState;
  88. // The selector of shells
  89. private JComboBox shellCombo;
  90. private RolloverButton runAgain, run, toBuffer, stop, clear;
  91. private JLabel animationLabel;
  92. private AnimatedIcon animation;
  93. private ConsolePane text;
  94. private Color infoColor, warningColor, errorColor, plainColor;
  95. private DefaultErrorSource errorSource;
  96. private ProjectTreeListener listener;
  97. // }}}
  98. // }}}
  99. //{{{ Console constructor
  100. public Console(View view)
  101. {
  102. super(new BorderLayout());
  103. this.view = view;
  104. shellStateMap = new HashMap<String, ShellState>();
  105. initGUI();
  106. propertiesChanged();
  107. String defShell = jEdit.getProperty("console.shell.default", "System");
  108. if (defShell.equals(jEdit.getProperty("options.last-selected"))) {
  109. defShell = jEdit.getProperty("console.shell", "System");
  110. }
  111. Shell s = Shell.getShell(defShell);
  112. if (s == null) s = Shell.getShell("System");
  113. setShell(s);
  114. load();
  115. propertiesChanged();
  116. } //}}}
  117. // {{{ methods
  118. //{{{ focusOnDefaultComponent() method
  119. public void focusOnDefaultComponent()
  120. {
  121. text.requestFocus();
  122. } //}}}
  123. //{{{ load() method
  124. public void load()
  125. {
  126. EditBus.addToBus(this);
  127. addProjectListener();
  128. errorSource = new DefaultErrorSource("error parsing");
  129. } //}}}
  130. void addProjectListener()
  131. {
  132. if (listener != null) return;
  133. listener = new ProjectTreeListener(this);
  134. }
  135. //{{{ unload() method
  136. public void unload()
  137. {
  138. EditBus.removeFromBus(this);
  139. if (listener != null) {
  140. EditBus.removeFromBus(listener);
  141. listener.finalize();
  142. }
  143. ErrorSource.unregisterErrorSource(errorSource);
  144. Iterator<ShellState> iter = shellStateMap.values().iterator();
  145. while(iter.hasNext())
  146. {
  147. ShellState state = iter.next();
  148. state.shell.closeConsole(this);
  149. }
  150. animation.stop();
  151. } //}}}
  152. //{{{ getView() method
  153. public View getView()
  154. {
  155. return view;
  156. } //}}}
  157. //{{{ getShell() method
  158. public Shell getShell()
  159. {
  160. String shellName = (String)shellCombo.getSelectedItem();
  161. return Shell.getShell(shellName);
  162. } //}}}
  163. //{{{ setShell() method
  164. public Shell setShell(String shellStr)
  165. {
  166. Shell shell = Shell.getShell(shellStr);
  167. if (shell == null) throw new RuntimeException("Unknown Shell: " + shellStr);
  168. return setShell(shell);
  169. } //}}}
  170. //{{{ setShell() method
  171. /**
  172. * Creates a ShellState (output instance) if necessary.
  173. * Sets the current active shell to be this new shell.
  174. */
  175. public Shell setShell(Shell shell)
  176. {
  177. if(shell == null)
  178. return null;
  179. String name = shell.getName();
  180. String shellHistory = getShellHistory(shell);
  181. String limit = jEdit.getProperty("console.historyLimit");
  182. if(limit != null)
  183. {
  184. try
  185. {
  186. HistoryModel.getModel(shellHistory).setMax(Integer.parseInt(limit));
  187. }
  188. catch(NumberFormatException nfe)
  189. {
  190. jEdit.unsetProperty("console.historyLimit");
  191. }
  192. }
  193. text.setHistoryModel(shellHistory);
  194. shellState = shellStateMap.get(name);
  195. if(shellState == null)
  196. {
  197. shellState = new ShellState(shell);
  198. shellStateMap.put(shell.getName(),shellState);
  199. shell.printInfoMessage(shellState);
  200. shell.printPrompt(this,shellState);
  201. }
  202. jEdit.setProperty("console.shell", name);
  203. text.setDocument(shellState.scrollback);
  204. if (shell != this.currentShell) {
  205. shellCombo.setSelectedItem(name);
  206. }
  207. this.currentShell = shell;
  208. scrollToBottom();
  209. return shell;
  210. } //}}}
  211. public void scrollToBottom() {
  212. SwingUtilities.invokeLater(new Runnable()
  213. {
  214. public void run()
  215. {
  216. text.setCaretPosition(text.getDocument().getLength());
  217. text.scrollRectToVisible(text.getVisibleRect());
  218. updateAnimation();
  219. }
  220. });
  221. }
  222. //{{{ getConsolePane() method
  223. public ConsolePane getConsolePane()
  224. {
  225. return text;
  226. } //}}}
  227. //{{{ getOutputPane() method
  228. /**
  229. * @deprecated Use getConsolePane() instead.
  230. */
  231. public JTextPane getOutputPane()
  232. {
  233. return text;
  234. } //}}}
  235. //{{{ clear() method
  236. public void clear()
  237. {
  238. text.setText("");
  239. getShell().printInfoMessage(shellState);
  240. } //}}}
  241. //{{{ getOutput() methods
  242. /**
  243. * Returns the Output corresponding to a particular Shell, without changing
  244. * the selected Shell.
  245. */
  246. public Output getOutput(String shellName) {
  247. ShellState retval = shellStateMap.get(shellName);
  248. if (retval == null) {
  249. Shell s = Shell.getShell(shellName);
  250. retval = new ShellState(s);
  251. shellStateMap.put(shellName, retval);
  252. }
  253. return retval;
  254. }
  255. /**
  256. * Returns the output instance for the currently selected Shell.
  257. * @since Console 3.6
  258. */
  259. public Output getOutput()
  260. {
  261. return shellState;
  262. } //}}}
  263. //{{{ runLastCommand() method
  264. /**
  265. * Meant to be used as a user action.
  266. */
  267. public void runLastCommand()
  268. {
  269. HistoryModel history = text.getHistoryModel();
  270. if(history.getSize() == 0)
  271. {
  272. getToolkit().beep();
  273. return;
  274. }
  275. else
  276. run(getShell(),null, getOutput(), null, history.getItem(0));
  277. } //}}}
  278. //{{{ handleMessage() method
  279. public void handleMessage(EBMessage msg)
  280. {
  281. if(msg instanceof PropertiesChanged) propertiesChanged();
  282. else if (msg instanceof DockableWindowUpdate) {
  283. DockableWindowUpdate dwu = (DockableWindowUpdate) msg;
  284. if (dwu.getWhat() != null && dwu.getWhat().equals(DockableWindowUpdate.ACTIVATED))
  285. if (dwu.getDockable().equals("console"))
  286. scrollToBottom();
  287. }
  288. else if(msg instanceof PluginUpdate)
  289. handlePluginUpdate((PluginUpdate)msg);
  290. else if (msg instanceof VFSPathSelected)
  291. handleNodeSelected((VFSPathSelected)msg);
  292. else if (msg instanceof ViewUpdate)
  293. handleViewUpdate((ViewUpdate)msg);
  294. else if (listener != null) {
  295. listener.handleMessage(msg);
  296. }
  297. } // }}}
  298. //{{{ handleViewUpdate() method
  299. private void handleViewUpdate(ViewUpdate vu) {
  300. if (vu.getWhat() == ViewUpdate.CLOSED && vu.getView() == view)
  301. unload();
  302. }
  303. //}}}
  304. //{{{ getErrorSource() method
  305. /**
  306. * Returns this console's error source instance. Plugin shells can
  307. * either add errors to this error source, or use their own; both
  308. * methods will look the same to the user.
  309. */
  310. public DefaultErrorSource getErrorSource()
  311. {
  312. return errorSource;
  313. } //}}}
  314. //{{{ getInfoColor() method
  315. /**
  316. * Returns the informational text color.
  317. */
  318. public Color getInfoColor()
  319. {
  320. return infoColor;
  321. } //}}}
  322. //{{{ getWarningColor() method
  323. /**
  324. * Returns the warning text color.
  325. */
  326. public Color getWarningColor()
  327. {
  328. return warningColor;
  329. } //}}}
  330. //{{{ getErrorColor() method
  331. /**
  332. * Returns the error text color.
  333. */
  334. public Color getErrorColor()
  335. {
  336. return errorColor;
  337. } //}}}
  338. // {{{ getPlainColor() method
  339. public Color getPlainColor() {
  340. return plainColor;
  341. } // }}}
  342. // {{{ getId() method
  343. /** @return a unique identifier starting at 0, representing which instance of Console this is,
  344. or -1 if that value can not be determined.
  345. */
  346. public int getId() {
  347. int retval = 0;
  348. View v = jEdit.getFirstView();
  349. while (v != null) {
  350. /* In fact, this is not unique: there can be more than one Console per View.
  351. * A better way of enumerating instances of Console for new floating
  352. * instances is desired. */
  353. if (v == view) return retval;
  354. ++retval;
  355. v = v.getNext();
  356. }
  357. return -1;
  358. } // }}}
  359. //{{{ print() method
  360. /**
  361. * @deprecated Do not use the console as an <code>Output</code>
  362. * instance, use the <code>Output</code> given to you in
  363. * <code>Shell.execute()</code> instead.
  364. */
  365. public void print(Color color, String msg)
  366. {
  367. getOutput().print(color,msg);
  368. } //}}}
  369. //{{{ writeAttrs() method
  370. /**
  371. * @deprecated Do not use the console as an <code>Output</code>
  372. * instance, use the <code>Output</code> given to you in
  373. * <code>Shell.execute()</code> instead.
  374. *
  375. * see @ref Output for information about how to create additional
  376. * console Output instances.
  377. */
  378. public void writeAttrs(AttributeSet attrs, String msg)
  379. {
  380. getOutput().writeAttrs(attrs,msg);
  381. } //}}}
  382. //{{{ commandDone() method
  383. /**
  384. * @deprecated Do not use the console as an <code>Output</code>
  385. * instance, use the <code>Output</code> given to you in
  386. * <code>Shell.execute()</code> instead.
  387. */
  388. public void commandDone()
  389. {
  390. getOutput().commandDone();
  391. } //}}}
  392. //{{{ getShellState() method
  393. /**
  394. * @returns the Output of a Shell, assuming the Shell was already created....
  395. *
  396. * @since Console 4.0.2.
  397. */
  398. public ShellState getShellState(Shell shell)
  399. {
  400. return shellStateMap.get(shell.getName());
  401. } //}}}
  402. // {{{ stopAnimation() method
  403. public void stopAnimation() {
  404. shellState.commandRunning=false;
  405. animation.stop();
  406. } // }}}
  407. // {{{ startAnimation method
  408. public void startAnimation() {
  409. currentShell = getShell();
  410. shellState = getShellState(currentShell);
  411. shellState.commandRunning = true;
  412. animationLabel.setVisible(true);
  413. animation.start();
  414. } // }}}
  415. //{{{ run() methods
  416. /**
  417. * Runs the specified command. Note that with most shells, this
  418. * method returns immediately, and execution of the command continues
  419. * in a different thread. If you want to wait for command completion,
  420. * call the <code>waitFor()</code> method of the shell instance.
  421. *
  422. * @param shell The shell instance. Obtain one either with
  423. * <code>Console.getShell()</code> or <code>Shell.getShell()</code>.
  424. * @param input The input to send to the command
  425. * @param output The output stream. Either the return value of
  426. * <code>getOutput()</code>, or a new instance of
  427. * <code>BufferOutput</code>.
  428. * @param error The error stream. Either the return value of
  429. * <code>getOutput()</code>, or a new instance of
  430. * <code>BufferOutput</code>.
  431. * @param cmd The command
  432. */
  433. public void run(Shell shell, String input, Output output,
  434. Output error, String cmd)
  435. {
  436. run(shell,input,output,error,cmd,true);
  437. }
  438. public void run(Shell shell, String command) {
  439. run (shell, null, null, null, command);
  440. }
  441. /**
  442. * Convenience function currently used by some beanshell macros.
  443. * @param shell the shell to execute it in
  444. * @param output something to write to
  445. * @param command the thing to execute
  446. *
  447. */
  448. public void run(Shell shell, Output output, String command) {
  449. run(shell, null, output, null, command);
  450. }
  451. private void run(Shell shell, String input, Output output,
  452. Output error, String cmd, boolean printInput)
  453. {
  454. if(cmd.length() != 0)
  455. HistoryModel.getModel(getShellHistory(shell)).addItem(cmd);
  456. text.setHistoryIndex(-1);
  457. if(cmd.startsWith(":"))
  458. {
  459. Shell _shell = Shell.getShell(cmd.substring(1));
  460. if(_shell != null)
  461. {
  462. text.setInput(null);
  463. setShell(_shell);
  464. return;
  465. }
  466. }
  467. setShell(shell);
  468. if(output == null)
  469. output = getOutput();
  470. if(error == null)
  471. error = getOutput();
  472. this.text.setCaretPosition(this.text.getDocument().getLength());
  473. ShellState state = getShellState(shell);
  474. state.commandRunning = true;
  475. updateAnimation();
  476. Macros.Recorder recorder = view.getMacroRecorder();
  477. if(recorder != null)
  478. {
  479. if(output instanceof BufferOutput)
  480. {
  481. recorder.record("runCommandToBuffer(view,\""
  482. + shell.getName()
  483. + "\",\""
  484. + StandardUtilities.charsToEscapes(cmd)
  485. + "\");");
  486. }
  487. else
  488. {
  489. recorder.record("runCommandInConsole(view,\""
  490. + shell.getName()
  491. + "\",\""
  492. + StandardUtilities.charsToEscapes(cmd)
  493. + "\");");
  494. }
  495. }
  496. if(printInput)
  497. error.print(infoColor, cmd);
  498. else
  499. error.print(null,"");
  500. errorSource.clear();
  501. ErrorSource.unregisterErrorSource(errorSource);
  502. try
  503. {
  504. shell.execute(this, input, output, null, cmd);
  505. startAnimation();
  506. // shell.execute(this,input,output,error,cmd);
  507. }
  508. catch(RuntimeException e)
  509. {
  510. print(getErrorColor(),e.toString());
  511. Log.log(Log.ERROR,this,e);
  512. output.commandDone();
  513. // error.commandDone();
  514. }
  515. } //}}}
  516. //{{{ initGUI() method
  517. private void initGUI()
  518. {
  519. Box box = new Box(BoxLayout.X_AXIS);
  520. shellCombo = new JComboBox();
  521. updateShellList();
  522. shellCombo.addActionListener(new ActionHandler());
  523. shellCombo.setRequestFocusEnabled(false);
  524. box.add(shellCombo);
  525. box.add(Box.createGlue());
  526. animationLabel = new JLabel();
  527. animationLabel.setBorder(new EmptyBorder(2,3,2,3));
  528. initAnimation();
  529. animationLabel.setIcon(animation);
  530. animationLabel.setVisible(false);
  531. animation.stop();
  532. box.add(animationLabel);
  533. box.add(runAgain = new RolloverButton(RUN_AGAIN));
  534. runAgain.setToolTipText(jEdit.getProperty("run-last-console-command.label"));
  535. Insets margin = new Insets(0,0,0,0);
  536. runAgain.setMargin(margin);
  537. runAgain.addActionListener(new ActionHandler());
  538. runAgain.setRequestFocusEnabled(false);
  539. box.add(run = new RolloverButton(RUN));
  540. run.setToolTipText(jEdit.getProperty("console.run"));
  541. margin = new Insets(0,0,0,0);
  542. run.setMargin(margin);
  543. run.addActionListener(new RunActionHandler());
  544. run.setRequestFocusEnabled(false);
  545. box.add(toBuffer = new RolloverButton(TO_BUFFER));
  546. toBuffer.setToolTipText(jEdit.getProperty("console.to-buffer"));
  547. toBuffer.setMargin(margin);
  548. toBuffer.addActionListener(new RunActionHandler());
  549. toBuffer.setRequestFocusEnabled(false);
  550. box.add(stop = new RolloverButton(STOP));
  551. stop.setToolTipText(jEdit.getProperty("console.stop"));
  552. stop.setMargin(margin);
  553. stop.addActionListener(new ActionHandler());
  554. stop.setRequestFocusEnabled(false);
  555. box.add(clear = new RolloverButton(CLEAR));
  556. clear.setToolTipText(jEdit.getProperty("console.clear"));
  557. clear.setMargin(margin);
  558. clear.addActionListener(new ActionHandler());
  559. clear.setRequestFocusEnabled(false);
  560. add(BorderLayout.NORTH,box);
  561. text = new ConsolePane();
  562. InputMap inputMap = text.getInputMap();
  563. /* Press ctrl-enter to run command to buffer */
  564. KeyStroke ctrlEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_MASK);
  565. inputMap.put(ctrlEnter, new RunToBuffer());
  566. /* Press tab to complete input */
  567. inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,0),
  568. new CompletionAction());
  569. /* Press C+d to send EOF */
  570. inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D,
  571. InputEvent.CTRL_MASK),
  572. new EOFAction());
  573. /* Press C+z to detach process */
  574. inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z,
  575. InputEvent.CTRL_MASK),
  576. new DetachAction());
  577. text.addActionListener(new RunActionHandler());
  578. JScrollPane scroller = new JScrollPane(text);
  579. scroller.setPreferredSize(new Dimension(400,100));
  580. add(BorderLayout.CENTER,scroller);
  581. } //}}}
  582. //{{{ initAnimation() method
  583. private void initAnimation()
  584. {
  585. // TODO: First frame of animation icon should be visible at gui init
  586. Toolkit toolkit = getToolkit();
  587. Image processImg = toolkit.getImage(Console.class.getResource("/console/process-working.png"));
  588. Image standbyImg = null;
  589. int iconSize = 22;
  590. ArrayList<Image> frames = new ArrayList<Image>();
  591. // Wait for the image to load by setting up an icon and discarding it again
  592. new ImageIcon(processImg).getImage();
  593. int procImgWidth = processImg.getWidth(null);
  594. int procImgHeight = processImg.getHeight(null);
  595. int currentX = 0, currentY = 0;
  596. int frameNo = 0;
  597. while(currentY < procImgHeight)
  598. {
  599. BufferedImage bufImg = new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB);
  600. Graphics2D bufGraphics = bufImg.createGraphics();
  601. bufGraphics.drawImage(processImg,
  602. 0,
  603. 0,
  604. iconSize-1,
  605. iconSize-1,
  606. currentX,
  607. currentY,
  608. currentX + iconSize - 1,
  609. currentY + iconSize - 1,
  610. null);
  611. // First frame is the standby icon
  612. if(frameNo == 0)
  613. standbyImg = bufImg;
  614. else
  615. frames.add(bufImg);
  616. frameNo++;
  617. currentX += iconSize;
  618. if(currentX + iconSize > procImgWidth)
  619. {
  620. currentX = 0;
  621. currentY += iconSize;
  622. }
  623. }
  624. animation = new AnimatedIcon(
  625. standbyImg,
  626. frames.toArray(new Image[0]),
  627. 25,
  628. animationLabel
  629. );
  630. }
  631. //}}}
  632. //{{{ updateShellList() method
  633. private void updateShellList()
  634. {
  635. String[] shells = Shell.getShellNames();
  636. Arrays.sort(shells,new StandardUtilities.StringCompare<String>(true));
  637. shellCombo.setModel(new DefaultComboBoxModel(shells));
  638. shellCombo.setMaximumSize(shellCombo.getPreferredSize());
  639. } //}}}
  640. //{{{ propertiesChanged() method
  641. private void propertiesChanged()
  642. {
  643. if (jEdit.getBooleanProperty("textColors")) {
  644. plainColor = jEdit.getColorProperty("view.fgColor", Color.BLACK);
  645. text.setBackground(jEdit.getColorProperty("view.bgColor", Color.WHITE));
  646. text.setCaretColor(jEdit.getColorProperty("view.caretColor", plainColor));
  647. }
  648. else {
  649. plainColor = jEdit.getColorProperty("console.plainColor", Color.BLACK);
  650. text.setBackground(jEdit.getColorProperty("console.bgColor", Color.WHITE));
  651. text.setCaretColor(jEdit.getColorProperty("console.caretColor", plainColor));
  652. }
  653. text.setForeground(plainColor);
  654. text.setFont(jEdit.getFontProperty("console.font"));
  655. infoColor = jEdit.getColorProperty("console.infoColor");
  656. warningColor = jEdit.getColorProperty("console.warningColor");
  657. errorColor = jEdit.getColorProperty("console.errorColor");
  658. } //}}}
  659. // {{{ handleNodeSelected()
  660. public void handleNodeSelected(VFSPathSelected msg) {
  661. // Log.log(Log.WARNING, this, "VFSPathSelected: " + msg.getPath());
  662. if (view != msg.getView()) return;
  663. if (!isVisible()) return;
  664. if (!jEdit.getBooleanProperty("console.changedir.nodeselect")) return;
  665. String path = msg.getPath();
  666. File f = new File(path);
  667. if (!f.isDirectory())
  668. {
  669. path = f.getParent();
  670. f = new File(path);
  671. if (!f.isDirectory()) return;
  672. }
  673. Shell sysShell = Shell.getShell("System");
  674. SystemShell ss = (SystemShell) sysShell;
  675. ConsoleState cs = ss.getConsoleState(this);
  676. if (cs.currentDirectory.equals(path)) return;
  677. Output output = getShellState(sysShell);
  678. String cmd = "cd \"" + path + "\"";
  679. sysShell.execute(this, cmd, output);
  680. output.print(getPlainColor(), "\n");
  681. sysShell.printPrompt(this, output);
  682. } //}}}
  683. //{{{ handlePluginUpdate() method
  684. public void handlePluginUpdate(PluginUpdate pmsg)
  685. {
  686. if(pmsg.getWhat() == PluginUpdate.LOADED
  687. || pmsg.getWhat() == PluginUpdate.UNLOADED)
  688. {
  689. boolean resetShell = false;
  690. updateShellList();
  691. Iterator<String> iter = shellStateMap.keySet().iterator();
  692. while(iter.hasNext())
  693. {
  694. String name = iter.next();
  695. if(Shell.getShell(name) == null)
  696. {
  697. if(this.currentShell.getName().equals(name))
  698. resetShell = true;
  699. iter.remove();
  700. }
  701. }
  702. if(resetShell)
  703. setShell((String)shellStateMap.keySet().iterator().next());
  704. else
  705. shellCombo.setSelectedItem(currentShell.getName());
  706. }
  707. } //}}}
  708. //{{{ updateAnimation() method
  709. public void updateAnimation()
  710. {
  711. if(shellState.commandRunning)
  712. {
  713. animationLabel.setVisible(true);
  714. animation.start();
  715. }
  716. else
  717. {
  718. animationLabel.setVisible(false);
  719. animation.stop();
  720. }
  721. } //}}}
  722. //{{{ complete() method
  723. /**
  724. * TODO: update this so it uses the current APIs.
  725. */
  726. private void complete()
  727. {
  728. String input = text.getInput();
  729. int cmdStart = text.getInputStart();
  730. int caret = text.getCaretPosition();
  731. int offset = caret - cmdStart;
  732. Shell.CompletionInfo info = currentShell.getCompletions(this,
  733. input.substring(0,offset));
  734. if(info == null || info.completions.length == 0)
  735. getToolkit().beep();
  736. else if(info.completions.length == 1)
  737. {
  738. text.select(cmdStart + info.offset,caret);
  739. text.replaceSelection(info.completions[0]);
  740. }
  741. else //if(info.completions.length > 1)
  742. {
  743. // Find a partial completion
  744. String longestCommonStart = MiscUtilities
  745. .getLongestPrefix(info.completions,
  746. ProcessRunner.getProcessRunner()
  747. .isCaseSensitive());
  748. if(longestCommonStart.length() != 0)
  749. {
  750. if(offset - info.offset
  751. != longestCommonStart.length())
  752. {
  753. text.select(cmdStart + info.offset,caret);
  754. text.replaceSelection(longestCommonStart);
  755. return;
  756. }
  757. }
  758. getOutput().print(null,"");
  759. getOutput().print(getInfoColor(), jEdit.getProperty(
  760. "console.completions"));
  761. Arrays.sort(info.completions,new StandardUtilities.StringCompare<String>(true));
  762. for(int i = 0; i < info.completions.length; i++)
  763. print(null,info.completions[i]);
  764. getOutput().print(getInfoColor(),jEdit.getProperty(
  765. "console.completions-end"));
  766. currentShell.printPrompt(this,shellState);
  767. cmdStart = text.getDocument().getLength();
  768. getOutput().writeAttrs(null,input);
  769. text.setInputStart(cmdStart);
  770. text.setCaretPosition(cmdStart + offset);
  771. }
  772. } //}}}
  773. //{{{ getShellHistory() method
  774. private String getShellHistory(Shell shell)
  775. {
  776. return "console." + shell.getName();
  777. } //}}}
  778. // }}}
  779. // {{{ Inner classes
  780. // {{{ ShellState class
  781. /**
  782. * Each Shell of a Console has its own ShellState
  783. * A ShellState is a writable Output.
  784. * It holds the document which is the "scrollback buffer".
  785. */
  786. public class ShellState implements Output
  787. {
  788. Shell shell;
  789. Document scrollback;
  790. private boolean commandRunning;
  791. //{{{ getDocument() method
  792. public Document getDocument()
  793. {
  794. return scrollback;
  795. } //}}}
  796. public ShellState(Shell shell)
  797. {
  798. this.shell = shell;
  799. commandRunning = false;
  800. scrollback = new DefaultStyledDocument();
  801. ((DefaultStyledDocument)scrollback).setDocumentFilter(new LengthFilter());
  802. // ick! talk about tightly coupling two classes.
  803. shell.openConsole(Console.this);
  804. }
  805. //{{{ getInputStart() method
  806. public int getInputStart()
  807. {
  808. return ((Integer)scrollback.getProperty(
  809. ConsolePane.InputStart)).intValue();
  810. } //}}}
  811. //{{{ setInputStart() method
  812. public void setInputStart(int cmdStart)
  813. {
  814. scrollback.putProperty(ConsolePane.InputStart,
  815. Integer.valueOf(cmdStart));
  816. } //}}}
  817. //{{{ print() method
  818. public void print(Color color, String msg)
  819. {
  820. writeAttrs(ConsolePane.colorAttributes(color),
  821. msg + "\n");
  822. } //}}}
  823. //{{{ writeAttrs() method
  824. public void writeAttrs(final AttributeSet attrs,
  825. final String msg)
  826. {
  827. if(SwingUtilities.isEventDispatchThread())
  828. writeSafely(attrs,msg);
  829. else
  830. {
  831. SwingUtilities.invokeLater(new Runnable()
  832. {
  833. public void run()
  834. {
  835. writeSafely(attrs,msg);
  836. }
  837. });
  838. }
  839. } //}}}
  840. //{{{ setAttrs() method
  841. public void setAttrs(final int length, final AttributeSet attrs)
  842. {
  843. if(SwingUtilities.isEventDispatchThread())
  844. setSafely(scrollback.getLength() - length, length, attrs);
  845. else
  846. {
  847. SwingUtilities.invokeLater(new Runnable()
  848. {
  849. public void run()
  850. {
  851. setSafely(scrollback.getLength() - length, length, attrs);
  852. //writeSafely(null, " - " + (scrollback.getLength() - length) + ":" + length);
  853. }
  854. });
  855. }
  856. } //}}}
  857. //{{{ setSafely() method
  858. private void setSafely(int start, int length, AttributeSet attrs)
  859. {
  860. ((DefaultStyledDocument)scrollback).setCharacterAttributes(start, length,
  861. attrs, true);
  862. } //}}}
  863. //{{{ commandDone() method
  864. public void commandDone()
  865. {
  866. SwingUtilities.invokeLater(new Runnable()
  867. {
  868. public void run()
  869. {
  870. // WTF?
  871. if(commandRunning)
  872. shell.printPrompt(Console.this, ShellState.this);
  873. commandRunning = false;
  874. // updateAnimation();
  875. stopAnimation();
  876. if(errorSource.getErrorCount() != 0)
  877. ErrorSource.registerErrorSource(errorSource);
  878. }
  879. });
  880. } //}}}
  881. //{{{ writeSafely() method
  882. private void writeSafely(AttributeSet attrs, String msg)
  883. {
  884. try
  885. {
  886. if(attrs != null && StyleConstants.getIcon(attrs) != null)
  887. msg = " ";
  888. scrollback.insertString(scrollback.getLength(),
  889. msg,attrs);
  890. }
  891. catch(BadLocationException bl)
  892. {
  893. Log.log(Log.ERROR,this,bl);
  894. }
  895. setInputStart(scrollback.getLength());
  896. } //}}}
  897. } //}}}
  898. // {{{ LengthFilter class
  899. static private class LengthFilter extends DocumentFilter
  900. {
  901. public LengthFilter()
  902. {
  903. super();
  904. }
  905. //{{{ insertString() method
  906. public void insertString(DocumentFilter.FilterBypass fb, int offset,
  907. String str, AttributeSet attr) throws BadLocationException
  908. {
  909. replace(fb, offset, 0, str, attr);
  910. } //}}}
  911. //{{{ replace() method
  912. public void replace(DocumentFilter.FilterBypass fb, int offset,
  913. int length, String str, AttributeSet attrs)
  914. throws BadLocationException
  915. {
  916. int newLength = fb.getDocument().getLength() -
  917. length + str.length();
  918. fb.replace(offset, length, str, attrs);
  919. int limit = jEdit.getIntegerProperty("console.outputLimit", DEFAULT_LIMIT);
  920. if(newLength > limit)
  921. fb.remove(0, newLength - limit - 1);
  922. } //}}}
  923. // Not so large default limit to avoid performance down
  924. // with large output.
  925. // This will be sufficient to first use.
  926. private final int DEFAULT_LIMIT = 80/*column*/ * 1000/*lines*/;
  927. } //}}}
  928. // {{{ EvalAction class
  929. public static class EvalAction extends AbstractAction
  930. {
  931. private String command;
  932. public EvalAction(String label, String command)
  933. {
  934. super(label);
  935. this.command = command;
  936. }
  937. public void actionPerformed(ActionEvent evt)
  938. {
  939. Console console = (Console)GUIUtilities.getComponentParent(
  940. (Component)evt.getSource(),Console.class);
  941. console.run(console.getShell(), null, console.getOutput(),
  942. null, command);
  943. }
  944. } //}}}
  945. // {{{ ActionHandler class
  946. class ActionHandler implements ActionListener
  947. {
  948. public void actionPerformed(ActionEvent evt)
  949. {
  950. Object source = evt.getSource();
  951. if(source == shellCombo)
  952. setShell((String)shellCombo.getSelectedItem());
  953. else if(source == runAgain)
  954. runLastCommand();
  955. else if(source == stop)
  956. getShell().stop(Console.this);
  957. else if(source == clear)
  958. {
  959. clear();
  960. getShell().printPrompt(Console.this,shellState);
  961. }
  962. }
  963. } //}}}
  964. // {{{ RunActionHandler class
  965. class RunActionHandler implements ActionListener
  966. {
  967. public void actionPerformed(ActionEvent evt)
  968. {
  969. String cmd = text.getInput();
  970. Object source = evt.getSource();
  971. String input = view.getTextArea().getSelectedText();
  972. Output output = shellState;
  973. boolean printInput = false;
  974. if(source == run)
  975. printInput = true;
  976. else if(source == toBuffer)
  977. {
  978. output = new BufferOutput(Console.this);
  979. }
  980. run(getShell(), input, output, shellState, cmd, printInput);
  981. }
  982. } //}}}
  983. // {{{ runToBuffer class
  984. class RunToBuffer extends AbstractAction
  985. {
  986. public void actionPerformed(ActionEvent evt) {
  987. String cmd = text.getInput();
  988. Output output = new BufferOutput(Console.this);
  989. run(getShell(), null, output, shellState, cmd, false);
  990. }
  991. }
  992. // }}}
  993. // {{{ CompletionAction class
  994. class CompletionAction extends AbstractAction
  995. {
  996. public void actionPerformed(ActionEvent evt)
  997. {
  998. complete();
  999. }
  1000. } //}}}
  1001. // {{{ EOFAction class
  1002. class EOFAction extends AbstractAction
  1003. {
  1004. public void actionPerformed(ActionEvent evt)
  1005. {
  1006. currentShell.endOfFile(Console.this);
  1007. }
  1008. } //}}}
  1009. // {{{ DetachAction class
  1010. class DetachAction extends AbstractAction
  1011. {
  1012. public void actionPerformed(ActionEvent evt)
  1013. {
  1014. currentShell.detach(Console.this);
  1015. }
  1016. } //}}}
  1017. // }}}
  1018. private static final long serialVersionUID = -9185531673809120587L;
  1019. } // }}}