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. |