KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > CommandInterpreter


1 /*
2  * CommmandInterpreter.java
3  *
4  * Copyright (C) 1998-2004 Peter Graves
5  * $Id: CommandInterpreter.java,v 1.26 2004/09/02 21:25:13 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

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 JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.OutputStreamWriter JavaDoc;
31 import javax.swing.Icon JavaDoc;
32 import javax.swing.SwingUtilities JavaDoc;
33 import javax.swing.undo.CompoundEdit JavaDoc;
34
35 public class CommandInterpreter extends Buffer
36 {
37     protected RE promptRE = new UncheckedRE(DEFAULT_SHELL_PROMPT_PATTERN);
38     protected OutputStreamWriter JavaDoc stdin;
39     protected ReaderThread stdoutThread;
40     protected ReaderThread stderrThread;
41     protected History history;
42     protected String JavaDoc input;
43     protected boolean stripEcho;
44     protected String JavaDoc shellCommand;
45
46     private Position posEndOfOutput;
47
48     protected CommandInterpreter()
49     {
50         super();
51         initializeUndo();
52         initializeHistory();
53     }
54
55     public final String JavaDoc 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 JavaDoc 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         // The original end-of-output line has been removed from the buffer.
100
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 JavaDoc getIcon()
126     {
127         return Utilities.getIconFromFile("jpty.png");
128     }
129
130     public int load()
131     {
132         try {
133             lockWrite();
134         }
135         catch (InterruptedException JavaDoc e) {
136             Log.debug(e);
137             return LOAD_FAILED; // Shouldn't happen.
138
}
139         try {
140             appendLine("");
141             setLoaded(true);
142         }
143         finally {
144             unlockWrite();
145         }
146         return LOAD_COMPLETED;
147     }
148
149     // Returns true if underlying process is alive and well.
150
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             // Ignore input before first prompt is displayed.
164
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             // We're not at the end of the buffer.
174
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 JavaDoc s)
184     {
185         final Editor editor = Editor.currentEditor();
186         Line dotLine = editor.getDotLine();
187         if (dotLine.next() != null) {
188             // Go to end of buffer (if we're not already there) to append input.
189
editor.eob();
190             dotLine = editor.getDotLine();
191
192             // Keep the prompt, but throw away anything after it.
193
final REMatch match = promptRE.getMatch(dotLine.getText());
194             if (match != null)
195                 dotLine.setText(dotLine.substring(0, match.getEndIndex()));
196
197             // Append s.
198
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 JavaDoc s)
216     {
217         try {
218             stdin.write(s);
219             if (!s.endsWith("\n"))
220                 stdin.write("\n");
221             stdin.flush();
222         }
223         catch (IOException JavaDoc e) {
224             Log.error(e);
225         }
226     }
227
228     protected String JavaDoc stripPrompt(String JavaDoc s)
229     {
230         if (promptRE != null) {
231             REMatch match = promptRE.getMatch(s);
232             if (match != null)
233                 return s.substring(match.getEndIndex());
234         }
235         // Look for login name or password prompt.
236
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             // There's a marked block, or we're not at the command line.
251
editor.escape();
252             return;
253         }
254         if (editor.escapeInternal())
255             return;
256         CompoundEdit JavaDoc 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         // BUG! Undo/redo delete region doesn't preserve markers correctly!
264
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 we're already at the prompt or to the left of it, go to column 0.
284
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 JavaDoc 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 JavaDoc currentInput;
325
326     private void getInputFromHistory(int direction)
327     {
328         if (getEndOfOutput() == null) {
329             // No prompt yet.
330
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 JavaDoc 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 JavaDoc 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             // BUG! Undo/redo delete region doesn't preserve markers correctly!
367
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 JavaDoc s)
375     {
376         try {
377             lockWrite();
378         }
379         catch (InterruptedException JavaDoc 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 JavaDoc e) {
425             Log.error(e);
426         }
427     }
428
429     protected String JavaDoc stdOutFilter(String JavaDoc s)
430     {
431         return removeEcho(s);
432     }
433
434     protected void stdOutUpdate(final String JavaDoc s)
435     {
436         Runnable JavaDoc r = new Runnable JavaDoc() {
437             public void run()
438             {
439                 appendString(s);
440                 updateDisplayInAllFrames();
441                 resetUndo();
442             }
443         };
444         SwingUtilities.invokeLater(r);
445     }
446
447     protected String JavaDoc stdErrFilter(String JavaDoc s)
448     {
449         return removeEcho(s);
450     }
451
452     protected void stdErrUpdate(final String JavaDoc s)
453     {
454         Runnable JavaDoc r = new Runnable JavaDoc() {
455             public void run()
456             {
457                 appendString(s);
458                 updateDisplayInAllFrames();
459                 resetUndo();
460             }
461         };
462         SwingUtilities.invokeLater(r);
463     }
464
465     private String JavaDoc removeEcho(String JavaDoc 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             // Strip echo only once per command line.
474
stripEcho = false;
475         }
476         return s;
477     }
478
479     protected class StdoutThread extends ReaderThread
480     {
481         public StdoutThread(InputStream JavaDoc stdout)
482         {
483             super(stdout);
484         }
485
486         public String JavaDoc filter(String JavaDoc s)
487         {
488             return stdOutFilter(s);
489         }
490
491         public void update(String JavaDoc s)
492         {
493             stdOutUpdate(s);
494         }
495     }
496
497     protected class StderrThread extends ReaderThread
498     {
499         public StderrThread(InputStream JavaDoc stderr)
500         {
501             super(stderr);
502         }
503
504         public String JavaDoc filter(String JavaDoc s)
505         {
506             return stdErrFilter(s);
507         }
508
509         public void update(String JavaDoc s)
510         {
511             stdErrUpdate(s);
512         }
513     }
514
515     // Commands.
516
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