|
From: <cr...@us...> - 2009-07-22 14:42:33
|
Revision: 5618
http://jnode.svn.sourceforge.net/jnode/?rev=5618&view=rev
Author: crawley
Date: 2009-07-22 14:42:31 +0000 (Wed, 22 Jul 2009)
Log Message:
-----------
Improvements to bjorne's command history and prompt handling. (Bjorne
now uses PS1 and PS2.)
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java
trunk/shell/src/shell/org/jnode/shell/CommandShell.java
trunk/shell/src/shell/org/jnode/shell/CommandShellReader.java
trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
trunk/shell/src/test/org/jnode/test/shell/CompletionHelper.java
trunk/shell/src/test/org/jnode/test/shell/CompletionTest.java
trunk/shell/src/test/org/jnode/test/shell/DefaultSyntaxCompletionTest.java
Removed Paths:
-------------
trunk/shell/src/shell/org/jnode/shell/MultilineInterpreter.java
Modified: trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -86,8 +86,24 @@
* @return the word with any necessary escaping or quoting added.
*/
String escapeWord(String word);
+
+ /**
+ * Test if the interpreter supports multiline commands.
+ *
+ * @return {@code true} if the interpreter supports multiline commands.
+ */
+ boolean supportsMultiline();
/**
+ * Get the command prompt.
+ *
+ * @param shell the shell that is supplying command input.
+ * @param continuation {@code true} if the interpreter is expecting a continuation line.
+ * @return the command prompt
+ */
+ String getPrompt(CommandShell shell, boolean continuation);
+
+ /**
* Get incremental help for the partial command line. If the interpreter
* does not support incremental help, it should simply return <code>false</code>.
*
Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -35,8 +35,6 @@
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.text.DateFormat;
-import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -142,12 +140,12 @@
private SyntaxManager syntaxMgr;
/**
- * Keeps a reference to the console this CommandShell is using *
+ * Keeps a reference to the console this CommandShell is using.
*/
private TextConsole console;
/**
- * Contains the archive of commands. *
+ * Contains the archive of commands.
*/
private InputHistory commandHistory = new InputHistory();
@@ -158,7 +156,9 @@
new InheritableThreadLocal<InputHistory>();
/**
- * When true, {@link complete(String)} performs command completion.
+ * When {@code true}, command input characters are being requested / read
+ * from the console. This controls whether command or application history
+ * is used, and whether command completion may be active.
*/
private boolean readingCommand;
@@ -274,7 +274,6 @@
new InputStreamReader(System.in),
new OutputStreamWriter(System.out),
new OutputStreamWriter(System.err));
- this.readingCommand = true;
}
@@ -321,7 +320,6 @@
try {
if (e.startsWith(COMMAND_KEY)) {
final String cmd = e.substring(COMMAND_KEY.length());
- outPW.println(prompt() + cmd);
runCommand(cmd);
}
} catch (Throwable ex) {
@@ -372,25 +370,17 @@
});
while (!isExited() && !VmSystem.isShuttingDown()) {
- String input = null;
CommandShellReader reader = null;
try {
clearEof();
- outPW.print(prompt());
- readingCommand = true;
- input = readInputLine();
- if (input.length() > 0) {
- try {
- clearEof();
- readingCommand = false;
- // Each interactive command is launched with a fresh history
- // for input completion
- applicationHistory.set(new InputHistory());
- reader = new CommandShellReader(input, interpreter, outPW, in);
- interpreter.interpret(this, reader, false, null, null);
- } finally {
- applicationHistory.set(null);
- }
+ try {
+ // Each interactive command is launched with a fresh history
+ // for input completion
+ applicationHistory.set(new InputHistory());
+ reader = new CommandShellReader(this, interpreter, outPW, in);
+ interpreter.interpret(this, reader, false, null, null);
+ } finally {
+ applicationHistory.set(null);
}
} catch (ShellException ex) {
diagnose(ex, null);
@@ -403,6 +393,11 @@
errPW.println("Uncaught exception while processing command(s): "
+ ex.getMessage());
stackTrace(ex);
+ try {
+ Thread.sleep(100000);
+ } catch (InterruptedException ex2) {
+
+ }
} finally {
if (reader != null) {
for (String line : reader.getLines()) {
@@ -449,6 +444,10 @@
ownThread = Thread.currentThread();
}
+ protected void setReadingCommand(boolean readingCommand) {
+ this.readingCommand = readingCommand;
+ }
+
@Override
public String getProperty(String propName) {
return propertyMap.get(propName);
@@ -522,18 +521,7 @@
ex.printStackTrace(errPW);
}
}
-
- private String readInputLine() throws IOException {
- StringBuffer sb = new StringBuffer(40);
- while (true) {
- int ch = in.read();
- if (ch == -1 || ch == '\n') {
- return sb.toString();
- }
- sb.append((char) ch);
- }
- }
-
+
private void clearEof() {
if (in instanceof KeyboardReader) {
((KeyboardReader) in).clearSoftEOF();
@@ -660,51 +648,6 @@
return CommandShell.applicationHistory.get();
}
}
-
- /**
- * Gets the expanded prompt
- */
- protected String prompt() {
- String prompt = getProperty(PROMPT_PROPERTY_NAME);
- final StringBuffer result = new StringBuffer();
- boolean commandMode = false;
- try {
- StringReader reader = new StringReader(prompt);
- int i;
- while ((i = reader.read()) != -1) {
- char c = (char) i;
- if (commandMode) {
- switch (c) {
- case 'P':
- result.append(new File(System.getProperty(DIRECTORY_PROPERTY_NAME, "")));
- break;
- case 'G':
- result.append("> ");
- break;
- case 'D':
- final Date now = new Date();
- DateFormat.getDateTimeInstance().format(now, result, null);
- break;
- default:
- result.append(c);
- }
- commandMode = false;
- } else {
- switch (c) {
- case '$':
- commandMode = true;
- break;
- default:
- result.append(c);
- }
- }
- }
- } catch (Exception ioex) {
- // This should never occur
- log.error("Error in prompt()", ioex);
- }
- return result.toString();
- }
/**
* This method is called by the console input driver to perform command line
Modified: trunk/shell/src/shell/org/jnode/shell/CommandShellReader.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandShellReader.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/CommandShellReader.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -37,28 +37,34 @@
private StringReader reader;
private final Reader in;
private final PrintWriter out;
- private final MultilineInterpreter interpreter;
+ private final CommandShell shell;
+ private final CommandInterpreter interpreter;
private final List<String> lines = new ArrayList<String>(1);
- public CommandShellReader(String command, CommandInterpreter interpreter, PrintWriter out, Reader in) {
- this.interpreter = (interpreter instanceof MultilineInterpreter) ?
- (MultilineInterpreter) interpreter : null;
-
- this.lines.add(command);
- if (interpreter != null) {
- command += "\n";
- }
- this.reader = new StringReader(command);
+ public CommandShellReader(CommandShell shell, CommandInterpreter interpreter,
+ PrintWriter out, Reader in)
+ throws IOException {
+ this.shell = shell;
+ this.interpreter = interpreter;
this.out = out;
this.in = in;
+ nextReader(true);
}
- private boolean nextReader() throws IOException {
- if (interpreter != null) {
- String prompt = interpreter.getContinuationPrompt();
- out.print(prompt);
- out.flush();
- StringBuilder sb = new StringBuilder(40);
+ private boolean nextReader(boolean first) throws IOException {
+ String prompt;
+ if (first) {
+ prompt = interpreter.getPrompt(shell, false);
+ } else if (interpreter.supportsMultiline()) {
+ prompt = interpreter.getPrompt(shell, true);
+ } else {
+ return false;
+ }
+ out.print(prompt);
+ out.flush();
+ StringBuilder sb = new StringBuilder(40);
+ try {
+ shell.setReadingCommand(true);
while (true) {
int ch = in.read();
if (ch == -1) {
@@ -72,22 +78,22 @@
sb.append((char) ch);
}
}
- this.lines.add(sb.toString());
- sb.append('\n');
- reader = new StringReader(sb.toString());
- return true;
- } else {
- return false;
+ } finally {
+ shell.setReadingCommand(false);
}
+ this.lines.add(sb.toString());
+ sb.append('\n');
+ reader = new StringReader(sb.toString());
+ return true;
}
@Override
public int read() throws IOException {
if (reader == null) {
- throw new IOException("CommandShellReader is closed");
+ return -1;
}
int res = reader.read();
- if (res == -1 && nextReader()) {
+ if (res == -1 && nextReader(false)) {
res = reader.read();
}
return res;
@@ -111,10 +117,10 @@
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
if (reader == null) {
- throw new IOException("CommandShellReader is closed");
+ return -1;
}
int res = reader.read(cbuf, off, len);
- if (res == 0 && nextReader()) {
+ if (res == 0 && nextReader(false)) {
res = reader.read(cbuf, off, len);
}
return res;
@@ -128,10 +134,10 @@
@Override
public int read(CharBuffer target) throws IOException {
if (reader == null) {
- throw new IOException("CommandShellReader is closed");
+ return -1;
}
int res = reader.read(target);
- if (res == 0 && nextReader()) {
+ if (res == 0 && nextReader(false)) {
res = reader.read(target);
}
return res;
@@ -140,9 +146,9 @@
@Override
public boolean ready() throws IOException {
if (reader == null) {
- throw new IOException("CommandShellReader is closed");
+ return false;
}
- return true;
+ return reader.ready();
}
@Override
Modified: trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -21,10 +21,14 @@
package org.jnode.shell;
import java.io.BufferedReader;
+import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
+import java.io.StringReader;
+import java.text.DateFormat;
import java.util.ArrayList;
+import java.util.Date;
import java.util.LinkedList;
import java.util.NoSuchElementException;
@@ -247,6 +251,56 @@
}
/**
+ * Get and expand the default command prompt.
+ */
+ public String getPrompt(CommandShell shell, boolean continuation) {
+ String prompt = shell.getProperty(CommandShell.PROMPT_PROPERTY_NAME);
+ final StringBuffer result = new StringBuffer();
+ boolean commandMode = false;
+ StringReader reader = new StringReader(prompt);
+ int i;
+ try {
+ while ((i = reader.read()) != -1) {
+ char c = (char) i;
+ if (commandMode) {
+ switch (c) {
+ case 'P':
+ result.append(new File(System.getProperty(CommandShell.DIRECTORY_PROPERTY_NAME, "")));
+ break;
+ case 'G':
+ result.append("> ");
+ break;
+ case 'D':
+ final Date now = new Date();
+ DateFormat.getDateTimeInstance().format(now, result, null);
+ break;
+ default:
+ result.append(c);
+ }
+ commandMode = false;
+ } else {
+ switch (c) {
+ case '$':
+ commandMode = true;
+ break;
+ default:
+ result.append(c);
+ }
+ }
+ }
+ } catch (IOException ex) {
+ // A StringReader shouldn't give an IOException unless we close it ... which we don't!
+ LOG.error("Impossible", ex);
+ }
+ return result.toString();
+ }
+
+ @Override
+ public boolean supportsMultiline() {
+ return false;
+ }
+
+ /**
* A simple command line tokenizer for the 'built-in' interpreters. It
* understands quoting, some '\' escapes, and (depending on constructor
* flags) certain "special" symbols.
Deleted: trunk/shell/src/shell/org/jnode/shell/MultilineInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/MultilineInterpreter.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/MultilineInterpreter.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -1,26 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2003-2009 JNode.org
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; If not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-package org.jnode.shell;
-
-public interface MultilineInterpreter extends CommandInterpreter {
-
- public String getContinuationPrompt();
-}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -136,6 +136,7 @@
this.holders = holders;
this.variables = new HashMap<String, VariableSlot>();
this.aliases = new TreeMap<String, String>();
+ initVariables();
}
public BjorneContext(BjorneInterpreter interpreter) {
@@ -151,6 +152,12 @@
return res;
}
+ private void initVariables() {
+ setVariable("PS1", "$ ");
+ setVariable("PS2", "> ");
+ setVariable("PS4", "+ ");
+ }
+
/**
* Create a copy of a context with the same initial variable bindings and
* streams. Stream ownership is not transferred.
@@ -1355,4 +1362,15 @@
public Collection<String> getVariableNames() {
return variables.keySet();
}
+
+ public String getVariable(String name) {
+ VariableSlot slot = variables.get(name);
+ if (slot == null) {
+ return "";
+ } else if (slot.getValue() == null) {
+ return "";
+ } else {
+ return slot.getValue();
+ }
+ }
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -40,10 +40,10 @@
import java.util.Map;
import java.util.Properties;
+import org.jnode.shell.CommandInterpreter;
import org.jnode.shell.CommandLine;
import org.jnode.shell.CommandShell;
import org.jnode.shell.Completable;
-import org.jnode.shell.MultilineInterpreter;
import org.jnode.shell.ShellException;
import org.jnode.shell.ShellFailureException;
import org.jnode.shell.ShellSyntaxException;
@@ -57,7 +57,7 @@
*
* @author cr...@jn...
*/
-public class BjorneInterpreter implements MultilineInterpreter {
+public class BjorneInterpreter implements CommandInterpreter {
public static final int CMD_EMPTY = 0;
@@ -218,7 +218,6 @@
do {
CommandNode tree = parser.parse();
if (tree == null) {
- // end of file ...
break;
}
if (DEBUG) {
@@ -271,10 +270,21 @@
}
@Override
- public String getContinuationPrompt() {
- return parser == null ? null : parser.getContinuationPrompt();
+ public String getPrompt(CommandShell shell, boolean continuation) {
+ String res = context.getVariable(continuation ? "PS2" : "PS1");
+ return (res == null) ? "$ " : expandPrompt(res);
}
+ private String expandPrompt(String prompt) {
+ // FIXME implement
+ return prompt;
+ }
+
+ @Override
+ public boolean supportsMultiline() {
+ return true;
+ }
+
private void bindShell(CommandShell shell) {
if (this.shell != shell) {
if (this.shell != null) {
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -138,13 +138,16 @@
*/
public CommandNode parse() throws ShellSyntaxException {
hereRedirections.clear();
- CommandNode command = null;
- // (The POSIX syntax doesn't seem to allow line breaks at the start, but I
- // don't think that can be right ...)
- skipLineBreaks();
- command = parseOptList();
- allowLineBreaks();
- captureHereDocuments();
+ CommandNode command = parseOptList();
+ if (command != null) {
+ allowLineBreaks();
+ captureHereDocuments();
+ } else {
+ noLineBreaks();
+ if (optNext(TOK_END_OF_LINE_BIT) != null) {
+ command = new SimpleCommandNode(CMD_COMMAND, new BjorneToken[0], false);
+ }
+ }
return command;
}
@@ -221,7 +224,7 @@
}
private CommandNode parseOptAndOr() throws ShellSyntaxException {
- allowLineBreaks();
+ // allowLineBreaks();
if (optPeek(TOK_LBRACE_BIT | TOK_LPAREN_BIT | TOK_COMMAND_NAME_BITS | TOK_FUNCTION_NAME_BITS |
TOK_IF_BIT | TOK_WHILE_BIT | TOK_UNTIL_BIT | TOK_CASE_BIT | TOK_FOR_BIT |
TOK_IO_NUMBER_BIT | TOK_LESS_BIT | TOK_GREAT_BIT | TOK_DLESS_BIT |
@@ -756,6 +759,10 @@
this.allowLineBreaks = true;
}
+ private void noLineBreaks() throws ShellSyntaxException {
+ this.allowLineBreaks = false;
+ }
+
/**
* Skip optional linebreaks.
* @param expectedSet the tokens expected after the line breaks
Modified: trunk/shell/src/test/org/jnode/test/shell/CompletionHelper.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/CompletionHelper.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/test/org/jnode/test/shell/CompletionHelper.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -28,6 +28,8 @@
import org.jnode.driver.console.CompletionInfo;
import org.jnode.shell.CommandShell;
+import org.jnode.test.shell.syntax.TestAliasManager;
+import org.jnode.test.shell.syntax.TestSyntaxManager;
/**
* Helper methods for doing completion tests.
@@ -35,8 +37,21 @@
* @author cr...@jn...
*/
public class CompletionHelper {
+
+ public static class TestCommandShell extends CommandShell {
+
+ protected TestCommandShell(TestAliasManager testAliasManager,
+ TestSyntaxManager testSyntaxManager) {
+ super(testAliasManager, testSyntaxManager);
+ }
- public static void checkCompletions(CommandShell cs, String line, String[] expected, int startPos) {
+ public void setReadingCommand(boolean readingCommand) {
+ super.setReadingCommand(readingCommand);
+ }
+ }
+
+ public static void checkCompletions(TestCommandShell cs, String line, String[] expected, int startPos) {
+ cs.setReadingCommand(true);
CompletionInfo ci = cs.complete(line);
SortedSet<String> completions = ci.getCompletions();
if (completions.size() != expected.length) {
Modified: trunk/shell/src/test/org/jnode/test/shell/CompletionTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/CompletionTest.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/test/org/jnode/test/shell/CompletionTest.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -96,9 +96,9 @@
System.setProperty("user.dir", userDirName);
}
- public class TestCommandShell extends CommandShell {
+ public class MyTestCommandShell extends CompletionHelper.TestCommandShell {
- public TestCommandShell() throws NameNotFoundException {
+ public MyTestCommandShell() throws NameNotFoundException {
super(new TestAliasManager(), new TestSyntaxManager());
ShellUtils.getShellManager().registerShell(this);
@@ -132,7 +132,7 @@
}
public void testDefaultInterpreterNewSyntax() throws Exception {
- TestCommandShell cs = new TestCommandShell();
+ MyTestCommandShell cs = new MyTestCommandShell();
cs.setProperty(CommandShell.INTERPRETER_PROPERTY_NAME, "default");
final String[] propertyCompletions = getExpectedPropertyNameCompletions();
Modified: trunk/shell/src/test/org/jnode/test/shell/DefaultSyntaxCompletionTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/DefaultSyntaxCompletionTest.java 2009-07-22 13:28:52 UTC (rev 5617)
+++ trunk/shell/src/test/org/jnode/test/shell/DefaultSyntaxCompletionTest.java 2009-07-22 14:42:31 UTC (rev 5618)
@@ -90,9 +90,9 @@
System.setProperty("user.dir", userDirName);
}
- public class TestCommandShell extends CommandShell {
+ public class MyTestCommandShell extends CompletionHelper.TestCommandShell {
- public TestCommandShell() throws NameNotFoundException {
+ public MyTestCommandShell() throws NameNotFoundException {
super(new TestAliasManager(), new TestSyntaxManager());
ShellUtils.getShellManager().registerShell(this);
@@ -114,7 +114,7 @@
}
public void testDefaultSyntax() throws Exception {
- TestCommandShell cs = new TestCommandShell();
+ MyTestCommandShell cs = new MyTestCommandShell();
cs.setProperty(CommandShell.INTERPRETER_PROPERTY_NAME, "default");
final String[] propertyCompletions = getExpectedPropertyNameCompletions();
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|