|
From: <cr...@us...> - 2008-08-24 14:03:08
|
Revision: 4493
http://jnode.svn.sourceforge.net/jnode/?rev=4493&view=rev
Author: crawley
Date: 2008-08-24 14:03:04 +0000 (Sun, 24 Aug 2008)
Log Message:
-----------
Fix TAB completion to use the current interpreter to escape any
meta-characters in each completion found.
Modified Paths:
--------------
trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java
trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java
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/DefaultInterpreter.java
trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
trunk/shell/src/shell/org/jnode/shell/syntax/URLArgument.java
trunk/shell/src/test/org/jnode/test/shell/CompletionInfoTest.java
Added Paths:
-----------
trunk/shell/src/shell/org/jnode/shell/CommandCompletions.java
Modified: trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java
===================================================================
--- trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -29,14 +29,8 @@
* @author Ewout Prangsma (ep...@us...)
* @author cr...@jn...
*/
-public class CompletionInfo {
- private static final SortedSet<String> NO_COMPLETIONS =
- Collections.unmodifiableSortedSet(new TreeSet<String>());
+public interface CompletionInfo {
- private TreeSet<String> completions;
-
- private int completionStart = -1;
-
/**
* This method is called to register a possible completion. A null or empty
* completion string will be quietly ignored.
@@ -45,18 +39,7 @@
* @param partial if <code>true</code>, further completions of the
* completion string may be possible.
*/
- public void addCompletion(String completion, boolean partial) {
- if (completion == null || completion.length() == 0) {
- return;
- }
- if (completions == null) {
- completions = new TreeSet<String>();
- }
- if (!partial) {
- completion += ' ';
- }
- completions.add(completion);
- }
+ public void addCompletion(String completion, boolean partial);
/**
* This method is called to register a completion than cannot be completed
@@ -64,53 +47,22 @@
*
* @param completion the completion string
*/
- public void addCompletion(String completion) {
- addCompletion(completion, false);
- }
+ public void addCompletion(String completion);
/**
* Retrieve the completion details.
*
* @return a TreeSet consisting of all possible completions
*/
- public SortedSet<String> getCompletions() {
- return completions == null ? NO_COMPLETIONS : completions;
- }
+ public SortedSet<String> getCompletions();
/**
- * Render for debug purposes
- */
- public String toString() {
- StringBuilder sb = new StringBuilder("CompletionInfo{");
- sb.append("competionStart=").append(completionStart);
- sb.append(",completions=");
- if (completions == null) {
- sb.append("null");
- } else {
- sb.append("{");
- boolean first = true;
- for (String completion : completions) {
- if (first) {
- first = false;
- } else {
- sb.append(",");
- }
- sb.append(completion);
- }
- sb.append("]");
- }
- return sb.toString();
- }
-
- /**
* The completion start is the offset in the original string of the first
* character to be replaced with the 'completed'.
*
* @return the completion start position, or <code>-1</code>
*/
- public int getCompletionStart() {
- return completionStart;
- }
+ public int getCompletionStart();
/**
* Set the completion start position. This can only be set once. After that,
@@ -118,15 +70,7 @@
*
* @param completionStart
*/
- public void setCompletionStart(int completionStart) {
- if (this.completionStart != completionStart) {
- if (this.completionStart != -1) {
- throw new IllegalArgumentException(
- "completionStart cannot be changed");
- }
- this.completionStart = completionStart;
- }
- }
+ public void setCompletionStart(int completionStart);
/**
* Get the combined completion string. If there are multiple alternatives,
@@ -136,31 +80,5 @@
*
* @return the combined completion, or <code>null</code>.
*/
- public String getCompletion() {
- if (completions == null) {
- return null;
- }
- int nos = completions.size();
- if (nos == 0) {
- return null;
- }
- if (nos == 1) {
- return completions.first();
- }
- String common = completions.first();
- for (String completion : completions) {
- if (common != completion && !completion.startsWith(common)) {
- for (int i = 0; i < common.length(); i++) {
- if (common.charAt(i) != completion.charAt(i)) {
- if (i == 0) {
- return null;
- }
- common = common.substring(0, i);
- break;
- }
- }
- }
- }
- return common;
- }
+ public String getCompletion();
}
Modified: trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java
===================================================================
--- trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -231,9 +231,9 @@
final int nbLines = (items.length / nbColumns) + (lastLineIsFull ? 0 : 1);
String[] lines = new String[nbLines];
- StringBuilder line = new StringBuilder(SCREEN_WIDTH);
int lineNum = 0;
for (int itemNum = 0; itemNum < items.length;) {
+ StringBuilder line = new StringBuilder(SCREEN_WIDTH);
for (int c = 0; c < nbColumns; c++) {
final String item = items[itemNum++];
line.append(item);
@@ -246,9 +246,7 @@
if (itemNum >= items.length) break;
}
-
lines[lineNum++] = line.toString();
- line.setLength(0); // clear the buffer
}
return lines;
Added: trunk/shell/src/shell/org/jnode/shell/CommandCompletions.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandCompletions.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/CommandCompletions.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -0,0 +1,190 @@
+/*
+ * $Id: CompletionInfo.java 2224 2006-01-01 12:49:03Z epr $
+ *
+ * JNode.org
+ * Copyright (C) 2003-2006 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;
+
+import java.util.Collections;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.jnode.driver.console.CompletionInfo;
+
+/**
+ * @author Ewout Prangsma (ep...@us...)
+ * @author cr...@jn...
+ */
+public class CommandCompletions implements CompletionInfo {
+ private static final SortedSet<String> NO_COMPLETIONS =
+ Collections.unmodifiableSortedSet(new TreeSet<String>());
+
+ private TreeSet<String> completions;
+
+ private int completionStart = -1;
+
+ private final CommandInterpreter interpreter;
+
+ /**
+ * Instantiate with a CommandInterpreter instance that will be used
+ * to escape shell meta-characters in the completions.
+ * @param interpreter the CommandInterpreter for escaping completions.
+ */
+ public CommandCompletions(CommandInterpreter interpreter) {
+ this.interpreter = interpreter;
+ }
+
+ /**
+ * Instantiate without a CommandInterpreter. Completions are captured
+ * as-is.
+ */
+ public CommandCompletions() {
+ this.interpreter = null;
+ }
+
+ /**
+ * This method is called to register a possible completion. A null or empty
+ * completion string will be quietly ignored.
+ *
+ * @param completion the completion string
+ * @param partial if <code>true</code>, further completions of the
+ * completion string may be possible.
+ */
+ public void addCompletion(String completion, boolean partial) {
+ if (completion == null || completion.length() == 0) {
+ return;
+ }
+ if (completions == null) {
+ completions = new TreeSet<String>();
+ }
+ if (interpreter != null) {
+ completion = interpreter.escapeWord(completion);
+ }
+ if (!partial) {
+ completion += ' ';
+ }
+ completions.add(completion);
+ }
+
+ /**
+ * This method is called to register a completion than cannot be completed
+ * further. A null or empty completion string will be quietly ignored.
+ *
+ * @param completion the completion string
+ */
+ public void addCompletion(String completion) {
+ addCompletion(completion, false);
+ }
+
+ /**
+ * Retrieve the completion details.
+ *
+ * @return a TreeSet consisting of all possible completions
+ */
+ public SortedSet<String> getCompletions() {
+ return completions == null ? NO_COMPLETIONS : completions;
+ }
+
+ /**
+ * Render for debug purposes
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder("CompletionInfo{");
+ sb.append("competionStart=").append(completionStart);
+ sb.append(",completions=");
+ if (completions == null) {
+ sb.append("null");
+ } else {
+ sb.append("{");
+ boolean first = true;
+ for (String completion : completions) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(completion);
+ }
+ sb.append("]");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * The completion start is the offset in the original string of the first
+ * character to be replaced with the 'completed'.
+ *
+ * @return the completion start position, or <code>-1</code>
+ */
+ public int getCompletionStart() {
+ return completionStart;
+ }
+
+ /**
+ * Set the completion start position. This can only be set once. After that,
+ * attempts to change the start position will throw {@link IllegalArgumentException}.
+ *
+ * @param completionStart
+ */
+ public void setCompletionStart(int completionStart) {
+ if (this.completionStart != completionStart) {
+ if (this.completionStart != -1) {
+ throw new IllegalArgumentException(
+ "completionStart cannot be changed");
+ }
+ this.completionStart = completionStart;
+ }
+ }
+
+ /**
+ * Get the combined completion string. If there are multiple alternatives,
+ * this will be the longest common left substring of the alternatives. If
+ * the substring is zero length, or if there were no alternatives in the
+ * first place, the result is <code>null</code>.
+ *
+ * @return the combined completion, or <code>null</code>.
+ */
+ public String getCompletion() {
+ if (completions == null) {
+ return null;
+ }
+ int nos = completions.size();
+ if (nos == 0) {
+ return null;
+ }
+ if (nos == 1) {
+ return completions.first();
+ }
+ String common = completions.first();
+ for (String completion : completions) {
+ if (common != completion && !completion.startsWith(common)) {
+ for (int i = 0; i < common.length(); i++) {
+ if (common.charAt(i) != completion.charAt(i)) {
+ if (i == 0) {
+ return null;
+ }
+ common = common.substring(0, i);
+ break;
+ }
+ }
+ }
+ }
+ return common;
+ }
+}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/shell/org/jnode/shell/CommandInterpreter.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -64,4 +64,14 @@
* @return the name
*/
String getName();
+
+ /**
+ * Add escape sequences (or quotes) to protect any characters in the
+ * supplied word so that it can (for example) be appended to a partial
+ * command line by the completer.
+ *
+ * @param word the word to be escaped
+ * @return the word with any necessary escaping or quoting added.
+ */
+ String escapeWord(String word);
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -613,7 +613,7 @@
public CompletionInfo complete(String partial) {
if (!readingCommand) {
// dummy completion behavior for application input.
- return new CompletionInfo();
+ return new CommandCompletions();
}
// workaround to set the currentShell to this shell
@@ -625,7 +625,7 @@
}
// do command completion
- completion = new CompletionInfo();
+ completion = new CommandCompletions(interpreter);
try {
Completable cl = parseCommandLine(partial);
if (cl != null) {
Modified: trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/shell/org/jnode/shell/DefaultInterpreter.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -128,7 +128,73 @@
res.setArgumentAnticipated(tokenizer.whitespaceAfterLast());
return res;
}
+
+ @Override
+ public String escapeWord(String word) {
+ return escapeWord(word, false);
+ }
+ protected String escapeWord(String word, boolean escapeRedirects) {
+ final int len = word.length();
+ StringBuilder sb = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char ch = word.charAt(i);
+ switch (ch) {
+ case ESCAPE_B:
+ sb.append(ESCAPE_CHAR).append(B);
+ break;
+ case ESCAPE_N:
+ sb.append(ESCAPE_CHAR).append(N);
+ break;
+ case ESCAPE_R:
+ sb.append(ESCAPE_CHAR).append(R);
+ break;
+ case ESCAPE_T:
+ sb.append(ESCAPE_CHAR).append(T);
+ break;
+ case ESCAPE_CHAR:
+ sb.append(ESCAPE_CHAR).append(ESCAPE_CHAR);
+ break;
+ case FULL_ESCAPE_CHAR:
+ sb.append(ESCAPE_CHAR).append(FULL_ESCAPE_CHAR);
+ break;
+ case QUOTE_CHAR:
+ sb.append(ESCAPE_CHAR).append(QUOTE_CHAR);
+ break;
+ case COMMENT_CHAR:
+ sb.append(ESCAPE_CHAR).append(COMMENT_CHAR);
+ break;
+ case SPACE_CHAR:
+ sb.append(ESCAPE_CHAR).append(SPACE_CHAR);
+ break;
+ case PIPE_CHAR:
+ if (escapeRedirects) {
+ sb.append(ESCAPE_CHAR).append(PIPE_CHAR);
+ } else {
+ sb.append(PIPE_CHAR);
+ }
+ break;
+ case SEND_OUTPUT_TO_CHAR:
+ if (escapeRedirects) {
+ sb.append(ESCAPE_CHAR).append(SEND_OUTPUT_TO_CHAR);
+ } else {
+ sb.append(SEND_OUTPUT_TO_CHAR);
+ }
+ break;
+ case GET_INPUT_FROM_CHAR:
+ if (escapeRedirects) {
+ sb.append(ESCAPE_CHAR).append(GET_INPUT_FROM_CHAR);
+ } else {
+ sb.append(GET_INPUT_FROM_CHAR);
+ }
+ break;
+ default:
+ sb.append(ch);
+ }
+ }
+ return sb.toString();
+ }
+
/**
* A simple command line tokenizer for the 'built-in' interpreters. It
* understands quoting, some '\' escapes, and (depending on constructor
Modified: trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -81,6 +81,11 @@
List<CommandDescriptor> commands = new LinkedList<CommandDescriptor>();
return parse(tokenizer, commands, true);
}
+
+ @Override
+ public String escapeWord(String word) {
+ return escapeWord(word, true);
+ }
/**
* This method parses the shell input into command lines. If we are completing,
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -132,6 +132,12 @@
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public String escapeWord(String word) {
+ // TODO Auto-generated method stub
+ return null;
+ }
int interpret(CommandShell shell, String command, OutputStream capture, boolean source)
throws ShellException {
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/URLArgument.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/URLArgument.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/URLArgument.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -24,6 +24,7 @@
import java.net.URL;
import org.jnode.driver.console.CompletionInfo;
+import org.jnode.shell.CommandCompletions;
import org.jnode.shell.CommandLine.Token;
/**
@@ -71,7 +72,7 @@
(url.getQuery() == null || url.getQuery().length() == 0)) {
// Use a FileArgument to do the work of completing the pathname,
// capturing the results using our own CompletionInfo object.
- CompletionInfo myCompletion = new CompletionInfo();
+ CompletionInfo myCompletion = new CommandCompletions();
new FileArgument(null, getFlags()).complete(myCompletion, url.getPath());
// Then turn the completions back into "file:" URLs
for (String c : myCompletion.getCompletions()) {
Modified: trunk/shell/src/test/org/jnode/test/shell/CompletionInfoTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/CompletionInfoTest.java 2008-08-24 11:38:12 UTC (rev 4492)
+++ trunk/shell/src/test/org/jnode/test/shell/CompletionInfoTest.java 2008-08-24 14:03:04 UTC (rev 4493)
@@ -24,6 +24,7 @@
import java.util.SortedSet;
import junit.framework.TestCase;
import org.jnode.driver.console.CompletionInfo;
+import org.jnode.shell.CommandCompletions;
/**
* Test key methods of the CompletionInfo class.
@@ -33,11 +34,11 @@
public class CompletionInfoTest extends TestCase {
public void testConstructor() {
- new CompletionInfo();
+ new CommandCompletions();
}
public void testAddCompletion() {
- CompletionInfo ci = new CompletionInfo();
+ CompletionInfo ci = new CommandCompletions();
ci.addCompletion("full-1");
ci.addCompletion("full-2", false);
@@ -52,7 +53,7 @@
}
public void testSetCompletionStart() {
- CompletionInfo ci = new CompletionInfo();
+ CompletionInfo ci = new CommandCompletions();
assertEquals(-1, ci.getCompletionStart());
ci.setCompletionStart(-1);
assertEquals(-1, ci.getCompletionStart());
@@ -69,7 +70,7 @@
}
public void testGetCompletion() {
- CompletionInfo ci = new CompletionInfo();
+ CompletionInfo ci = new CommandCompletions();
assertEquals(null, ci.getCompletion());
ci.addCompletion("full-1");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|