From: <cr...@us...> - 2008-03-21 08:41:08
|
Revision: 3859 http://jnode.svn.sourceforge.net/jnode/?rev=3859&view=rev Author: crawley Date: 2008-03-21 01:41:06 -0700 (Fri, 21 Mar 2008) Log Message: ----------- Restructured the completion data structures / code / control flow Modified Paths: -------------- trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java trunk/core/src/driver/org/jnode/driver/console/textscreen/KeyboardInputStream.java trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java trunk/fs/src/fs/org/jnode/fs/nfs/command/NFSHostNameArgument.java trunk/shell/src/shell/org/jnode/shell/CommandLine.java trunk/shell/src/shell/org/jnode/shell/CommandShell.java trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java trunk/shell/src/shell/org/jnode/shell/Shell.java trunk/shell/src/shell/org/jnode/shell/command/test/SuiteCommand.java trunk/shell/src/shell/org/jnode/shell/help/Argument.java trunk/shell/src/shell/org/jnode/shell/help/CommandLineElement.java trunk/shell/src/shell/org/jnode/shell/help/Help.java trunk/shell/src/shell/org/jnode/shell/help/Parameter.java trunk/shell/src/shell/org/jnode/shell/help/Syntax.java trunk/shell/src/shell/org/jnode/shell/help/argument/AliasArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/ClassNameArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/DeviceArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/EnumOptionArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/FileArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/HostNameArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/InetAddressArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/IntegerArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/ListArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/LongArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/OptionArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/PluginArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/PropertyNameArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/StringArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/StringListArgument.java trunk/shell/src/shell/org/jnode/shell/help/argument/ThreadNameArgument.java Modified: trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java =================================================================== --- trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/core/src/driver/org/jnode/driver/console/CompletionInfo.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -18,98 +18,150 @@ * 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.driver.console; +import java.util.Collections; +import java.util.TreeSet; +import java.util.SortedSet; + /** * @author Ewout Prangsma (ep...@us...) + * @author cr...@jn... */ public class CompletionInfo { - private String[] items = null; + private static final SortedSet<String> NO_COMPLETIONS = + Collections.unmodifiableSortedSet(new TreeSet<String>()); - private String completed = null; + private TreeSet<String> completions; - private boolean newPrompt = false; + private int completionStart = -1; /** - * @return Returns the completed. + * 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 String getCompleted() { - return completed; + 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); } /** - * @param completed - * The completed to set. + * 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 setCompleted(String completed) { - this.completed = completed; + public void addCompletion(String completion) { + addCompletion(completion, false); } /** - * get the possible completions + * Retrieve the completion details. * - * @return Returns the items. + * @return a TreeSet consisting of all possible completions */ - public String[] getItems() { - return items; + public SortedSet<String> getCompletions() { + return completions == null ? NO_COMPLETIONS : completions; } /** - * Specify the possible completions - * - * @param items - * The items to set. + * Render for debug purposes */ - public void setItems(String[] items) { - this.items = items; - this.completed = null; - this.newPrompt = true; + 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(); } /** - * Do we have more than one possible completion ? + * The completion start is the offset in the original string of the first + * character to be replaced with the 'completed'. * - * @return + * @return the completion start position, or <code>-1</code> */ - public boolean hasItems() { - return items != null; + public int getCompletionStart() { + return completionStart; } /** - * Specify if we need a new prompt or not + * Set the completion start position. This can only be set once. After that, + * attempts to change the start position result in an + * IllegalArgumentException. * - * @param newPrompt + * @param completionStart */ - public void setNewPrompt(boolean newPrompt) { - this.newPrompt = newPrompt; + public void setCompletionStart(int completionStart) { + if (this.completionStart != completionStart) { + if (this.completionStart != -1) { + throw new IllegalArgumentException( + "completionStart cannot be changed"); + } + this.completionStart = completionStart; + } } /** - * @return true if we need to display a new prompt + * 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 boolean needNewPrompt() { - return newPrompt; - } - - public String toString() { - StringBuilder sb = new StringBuilder("CompletionInfo{"); - sb.append("completed=").append(completed == null ? "null" : completed); - sb.append(",items="); - if (items == null) { - sb.append("null"); + public String getCompletion() { + if (completions == null) { + return null; } - else { - sb.append("["); - for (int i = 0; i < items.length; i++) { - if (i > 0) { - sb.append(","); + 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; + } } - sb.append(items[i] == null ? "null" : items[i]); } - sb.append("]"); } - sb.append(",newPrompt=").append(newPrompt).append("}"); - return sb.toString(); + return common; } } Modified: trunk/core/src/driver/org/jnode/driver/console/textscreen/KeyboardInputStream.java =================================================================== --- trunk/core/src/driver/org/jnode/driver/console/textscreen/KeyboardInputStream.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/core/src/driver/org/jnode/driver/console/textscreen/KeyboardInputStream.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -223,8 +223,7 @@ // if it's the tab key, we want to trigger command line completion case '\t': if (completer != null) { - CompletionInfo completion = currentLine.complete(); - if (completion.needNewPrompt()) { + if (currentLine.complete()) { currentLine.start(true); } out.print(currentPrompt); Modified: trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java =================================================================== --- trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/core/src/driver/org/jnode/driver/console/textscreen/Line.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -22,6 +22,8 @@ package org.jnode.driver.console.textscreen; import java.util.Arrays; +import java.util.SortedSet; +import java.util.TreeSet; import org.jnode.driver.console.CompletionInfo; import org.jnode.driver.console.InputCompleter; @@ -158,63 +160,54 @@ } } - public CompletionInfo complete() { + public boolean complete() { CompletionInfo info = null; InputCompleter completer = console.getCompleter(); - if (posOnCurrentLine != currentLine.length()) { - String ending = currentLine.substring(posOnCurrentLine); - info = completer.complete(currentLine.substring(0, posOnCurrentLine)); - printList(info); - if (info.getCompleted() != null) { - setContent(info.getCompleted() + ending); - posOnCurrentLine = currentLine.length() - ending.length(); - } - } else { - info = completer.complete(currentLine.toString()); - printList(info); - if (info.getCompleted() != null) { - setContent(info.getCompleted()); - posOnCurrentLine = currentLine.length(); - } + String ending = + posOnCurrentLine != currentLine.length() ? currentLine.substring(posOnCurrentLine) : ""; + info = completer.complete(currentLine.substring(0, posOnCurrentLine)); + boolean res = printList(info); + String completion = info.getCompletion(); + if (completion != null) { + int startPos = info.getCompletionStart(); + setContent(currentLine.substring(0, startPos) + completion + ending); + // (This is the updated line's length ...) + posOnCurrentLine = currentLine.length() - ending.length(); } - - return info; + return res; } - protected void printList(CompletionInfo info) { - if ((info != null) && info.hasItems()) { - int oldPosOnCurrentLine = posOnCurrentLine; - moveEnd(); - refreshCurrentLine(); + protected boolean printList(CompletionInfo info) { + SortedSet<String> completions = info.getCompletions(); + if (completions == null || completions.size() <= 1) { + return false; + } + int oldPosOnCurrentLine = posOnCurrentLine; + moveEnd(); + refreshCurrentLine(); - out.println(); - String[] list = info.getItems(); - Arrays.sort(list); - - final int minItemsToSplit = 5; - if(list.length > minItemsToSplit) - { - list = splitInColumns(list); - } + out.println(); + String[] list = completions.toArray(new String[completions.size()]); - // display items column (may be single or multiple columns) - for (String item : list) - { - // item may actually be a single item or in fact multiple items - if((item.length() % SCREEN_WIDTH) == 0) - { - // we are already at the first column of the next line - out.print(item); - } - else - { - // we aren't at the first column of the next line - out.println(item); - } - } + final int minItemsToSplit = 5; + if (list.length > minItemsToSplit) { + list = splitInColumns(list); + } - posOnCurrentLine = oldPosOnCurrentLine; + // display items column (may be single or multiple columns) + for (String item : list) { + // item may actually be a single item or in fact multiple items + if (item.length() % SCREEN_WIDTH == 0) { + // we are already at the first column of the next line + out.print(item); + } + else { + // we aren't at the first column of the next line + out.println(item); + } } + posOnCurrentLine = oldPosOnCurrentLine; + return true; } protected String[] splitInColumns(String[] items) @@ -223,10 +216,8 @@ // compute the maximum width of items int maxWidth = 0; - for(String item : items) - { - if(item.length() > maxWidth) - { + for (String item : items) { + if (item.length() > maxWidth) { maxWidth = item.length(); } } @@ -239,21 +230,18 @@ String[] lines = new String[nbLines]; StringBuilder line = new StringBuilder(SCREEN_WIDTH); int lineNum = 0; - for(int itemNum = 0 ; itemNum < items.length ; ) - { - for(int c = 0 ; c < nbColumns ; c++) - { + for (int itemNum = 0 ; itemNum < items.length ; ) { + for (int c = 0 ; c < nbColumns ; c++) { final String item = items[itemNum++]; line.append(item); // add some blanks final int nbBlanks = columnWidth - item.length(); - for(int i = 0 ; i < nbBlanks ; i++) - { + for (int i = 0 ; i < nbBlanks ; i++) { line.append(' '); } - if(itemNum >= items.length) break; + if (itemNum >= items.length) break; } lines[lineNum++] = line.toString(); Modified: trunk/fs/src/fs/org/jnode/fs/nfs/command/NFSHostNameArgument.java =================================================================== --- trunk/fs/src/fs/org/jnode/fs/nfs/command/NFSHostNameArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/fs/src/fs/org/jnode/fs/nfs/command/NFSHostNameArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.List; +import org.jnode.driver.console.CompletionInfo; import org.jnode.net.nfs.Protocol; import org.jnode.net.nfs.nfs2.mount.ExportEntry; import org.jnode.net.nfs.nfs2.mount.Mount1Client; @@ -26,22 +27,18 @@ super(name, description); } - public String complete(String partial) { + public void complete(CompletionInfo completion, String partial) { - if (partial == null) { - return null; - } - int index = partial.indexOf(':'); if (index == -1) { - return partial; + return; } final InetAddress host; try { host = InetAddress.getByName(partial.substring(0, index)); } catch (UnknownHostException e) { - return partial; + return; } String partialDirectory = partial.substring(index + 1); @@ -50,12 +47,10 @@ try { exportEntryList = AccessController .doPrivileged(new PrivilegedExceptionAction<List<ExportEntry>>() { - public List<ExportEntry> run() throws IOException, - MountException { - - Mount1Client client = new Mount1Client(host, - Protocol.TCP, -1, -1); - + public List<ExportEntry> run() + throws IOException, MountException { + Mount1Client client = + new Mount1Client(host, Protocol.TCP, -1, -1); List<ExportEntry> exportEntryList; try { exportEntryList = client.export(); @@ -64,34 +59,24 @@ try { client.close(); } catch (IOException e) { - + // squash } } } return exportEntryList; - } }); } catch (PrivilegedActionException e) { - - return partial; + return; } - List<String> valueList = new ArrayList<String>(); for (int i = 0; i < exportEntryList.size(); i++) { ExportEntry exportEntry = exportEntryList.get(i); - if (exportEntry.getDirectory().startsWith(partialDirectory)) { - valueList.add(partial.substring(0, index) + ":" + completion.addCompletion(partial.substring(0, index) + ":" + exportEntry.getDirectory()); } - } - - String completed = complete(partial, valueList); - - return completed; - } public InetAddress getAddress(ParsedArguments args) Modified: trunk/shell/src/shell/org/jnode/shell/CommandLine.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/CommandLine.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/CommandLine.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -22,8 +22,6 @@ package org.jnode.shell; import java.io.Closeable; -import java.util.Collections; -import java.util.List; import java.util.NoSuchElementException; import org.apache.log4j.Logger; @@ -34,7 +32,6 @@ import org.jnode.shell.help.Parameter; import org.jnode.shell.syntax.CommandSyntaxException; -import org.jnode.shell.syntax.AliasArgument; import org.jnode.shell.syntax.FileArgument; import org.jnode.shell.syntax.ArgumentBundle; import org.jnode.shell.syntax.ArgumentSyntax; @@ -404,27 +401,30 @@ * This field holds the "cooked" representation of command line token. * By the time we reach the CommandLine, all shell meta-characters * should have been processed so that the value of the field represents - * a command name or argument. + * a command name or argument. */ public final String token; /** * This field represents the type of the token. The meaning is - * interpreter specific. + * interpreter specific. The value -1 indicates that no token type is + * available. */ public final int tokenType; /** * This field denotes the character offset of the first character of * this token in the source character sequence passed to the - * interpreter. + * interpreter. The value -1 indicates that no source start position is + * available. */ public final int start; /** * This field denotes the character offset + 1 for the last character of * this token in the source character sequence passed to the - * interpreter. + * interpreter. The value -1 indicates that no source end position is + * available. */ public final int end; @@ -442,7 +442,7 @@ } public Token(String token) { - this(token, 0, 0, 0, false); + this(token, -1, -1, -1, false); } @Override @@ -623,9 +623,7 @@ throws CompletionException { Logger log = Logger.getLogger(CommandLine.class); String cmd = (commandToken == null) ? "" : commandToken.token.trim(); - String result = null; if (!cmd.equals("") && (argumentTokens.length > 0 || argumentAnticipated)) { - log.debug("doing argument completion"); try { // get command's help info CommandInfo cmdClass = shell.getCommandClass(cmd); @@ -639,18 +637,16 @@ } // perform completion of the command arguments based on the - // command's - // help info / syntax ... if any. - result = info.complete(this); - + // command's help info / syntax ... if any. + info.complete(completion, this); } catch (ClassNotFoundException ex) { throw new CompletionException("Command class not found", ex); } } else { // do completion on the command name - log.debug("doing command name completion"); - result = defaultArg.complete(cmd); + log.debug("completing '" + cmd + "'"); + defaultArg.complete(completion, cmd); + completion.setCompletionStart(commandToken == null ? 0 : commandToken.start); } - completion.setCompleted(result); } } Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -36,10 +36,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Collections; import java.util.Date; -import java.util.List; import java.util.StringTokenizer; import javax.naming.NameNotFoundException; @@ -579,10 +576,7 @@ public CompletionInfo complete(String partial) { if (!readingCommand) { // dummy completion behavior for application input. - CompletionInfo completion = new CompletionInfo(); - completion.setCompleted(partial); - completion.setNewPrompt(true); - return completion; + return new CompletionInfo(); } // workaround to set the currentShell to this shell @@ -594,17 +588,13 @@ // do command completion completion = new CompletionInfo(); - boolean success = false; try { Completable cl = parseCommandLine(partial); if (cl != null) { cl.complete(completion, this); - if (!partial.equals(completion.getCompleted()) - && !completion.hasItems()) { - // we performed direct completion without listing - completion.setNewPrompt(false); + if (completion.getCompletionStart() == -1) { + completion.setCompletionStart(partial.length()); } - success = true; } } catch (ShellSyntaxException ex) { out.println(); // next line @@ -615,27 +605,12 @@ err.println("Problem in completer: " + ex.getMessage()); } - if (!success) { - // Make sure the caller knows to repaint the prompt - completion.setCompleted(partial); - completion.setNewPrompt(true); - } - // Make sure that the shell's completion context gets nulled. CompletionInfo myCompletion = completion; completion = null; return myCompletion; } - - public void list(String[] items) { - if (completion == null) { - throw new ShellFailureException( - "list called when no completion is in progress"); - } else { - completion.setItems(items); - } - } - + public void addCommandToHistory(String cmdLineStr) { // Add this command to the command history. if (isHistoryEnabled() && !cmdLineStr.equals(lastCommandLine)) { Modified: trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -37,6 +37,7 @@ import org.jnode.shell.help.CompletionException; import org.jnode.shell.help.Help; import org.jnode.shell.help.Parameter; +import org.jnode.shell.help.argument.AliasArgument; import org.jnode.shell.help.argument.FileArgument; import org.jnode.shell.syntax.CommandSyntaxException; @@ -96,30 +97,31 @@ } CommandDescriptor lastDesc = commands.get(nosCommands - 1); CommandLine lastCommand = lastDesc.commandLine; - CommandLine.Token lastToken = tokenizer.last(); + final CommandLine.Token lastToken = tokenizer.last(); boolean whitespaceAfter = tokenizer.whitespaceAfterLast(); lastCommand.setArgumentAnticipated(whitespaceAfter); switch (completionContext) { case COMPLETE_ALIAS: case COMPLETE_ARG: case COMPLETE_PIPE: - break; + return lastCommand; case COMPLETE_INPUT: - if (lastDesc.fromFileName == null || !whitespaceAfter) { - return new RedirectionCompleter(line, lastToken.start); - } - break; case COMPLETE_OUTPUT: - if (lastDesc.toFileName == null || !whitespaceAfter) { - return new RedirectionCompleter(line, lastToken.start); + if (!whitespaceAfter) { + return new Completable() { + public void complete(CompletionInfo completion, + CommandShell shell) throws CompletionException { + new AliasArgument("?", null).complete(completion, lastToken.token); + } + }; } - break; + else { + return lastCommand; + } default: throw new ShellFailureException("bad completion context (" + completionContext + ")"); } - return new SubcommandCompleter(lastCommand, line, - whitespaceAfter ? lastToken.end : lastToken.start); } private List<CommandDescriptor> parse(Tokenizer tokenizer, String line, @@ -429,60 +431,4 @@ this.pipeTo = pipeTo; } } - - private abstract class EmbeddedCompleter implements Completable { - private final String partial; - private final int startPos; - - public EmbeddedCompleter(String partial, int startPos) { - this.partial = partial; - this.startPos = startPos; - } - - public String getCompletableString() { - return partial.substring(startPos); - } - - public void setFullCompleted(CompletionInfo completion, String completed) { - completion.setCompleted(partial.substring(0, startPos) + completed); - } - } - - private class SubcommandCompleter extends EmbeddedCompleter { - private final CommandLine subcommand; - - public SubcommandCompleter(CommandLine subcommand, String partial, - int startPos) { - super(partial, startPos); - this.subcommand = subcommand; - } - - public void complete(CompletionInfo completion, CommandShell shell) - throws CompletionException { - subcommand.complete(completion, shell); - setFullCompleted(completion, completion.getCompleted()); - } - } - - private class RedirectionCompleter extends EmbeddedCompleter { - - private final Help.Info fileParameter = - new Help.Info("file", - "default parameter for file redirection completion", - new Parameter(new FileArgument("file", "a file", - Argument.SINGLE), Parameter.MANDATORY)); - - public RedirectionCompleter(String partial, int startPos) { - super(partial, startPos); - } - - public void complete(CompletionInfo completion, CommandShell shell) - throws CompletionException { - CommandLine command = - new CommandLine("?", - new String[] { getCompletableString() }); - String result = fileParameter.complete(command); - setFullCompleted(completion, result); - } - } } Modified: trunk/shell/src/shell/org/jnode/shell/Shell.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/Shell.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/Shell.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -43,11 +43,6 @@ public SyntaxManager getSyntaxManager(); /** - * Shell callback to register a list of choices for command line completion. - */ - public void list(String[] items); - - /** * Gets the shell's command InputHistory object. Unlike getInputHistory, * this method is not modal. */ Modified: trunk/shell/src/shell/org/jnode/shell/command/test/SuiteCommand.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/command/test/SuiteCommand.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/command/test/SuiteCommand.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -31,6 +31,7 @@ import junit.framework.Test; import junit.framework.TestSuite; +import org.jnode.driver.console.CompletionInfo; import org.jnode.shell.help.Argument; import org.jnode.shell.help.Help; import org.jnode.shell.help.Parameter; @@ -110,19 +111,13 @@ super(name, description); } - public String complete(String partial) { - final List<String> categories = new ArrayList<String>(); + public void complete(CompletionInfo completion, String partial) { Set<String> availCategories = TestManager.getInstance().getCategories(); - - for(String availCategory : availCategories) - { - if(availCategory.startsWith(partial)) - { - categories.add(availCategory); + for (String availCategory : availCategories) { + if (availCategory.startsWith(partial)) { + completion.addCompletion(availCategory); } } - - return complete(partial, categories); } protected boolean isValidValue(String category) { Modified: trunk/shell/src/shell/org/jnode/shell/help/Argument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/Argument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/Argument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,12 +21,8 @@ package org.jnode.shell.help; -import java.util.Collection; +import org.jnode.driver.console.CompletionInfo; -import javax.naming.NameNotFoundException; - -import org.jnode.shell.ShellUtils; - /** * @author qades */ @@ -66,25 +62,22 @@ private boolean satisfied = false; - public String complete(String partial) { - // No completion per default - return partial; + /** + * Perform argument completion on the supplied (partial) argument value. The + * results of the completion should be added to the supplied CompletionInfo. + * <p> + * The default behavior is to return the argument value as a partial completion. + * Subtypes of Argument should override this method if they are capable of doing + * non-trivial completion. Completions should be registered by calling one + * of the 'addCompletion' methods on the CompletionInfo. + * + * @param completion the CompletionInfo object for registering any completions. + * @param partial the argument string to be completed. + */ + public void complete(CompletionInfo completion, String partial) { + completion.addCompletion(partial, true); } - protected String complete(String partial, Collection<String> list) { - if (list.size() == 0) // none found - return partial; - - if (list.size() == 1) return (String) list.iterator().next() + " "; - - // list matching - String[] result = list.toArray(new String[list.size()]); - list(result); - - // return the common part, i.e. complete as much as possible - return common(result); - } - protected final void setValue(String value) { if (isMulti()) { String[] values = new String[ this.values.length + 1]; @@ -133,27 +126,4 @@ public final boolean isSatisfied() { return satisfied; } - - protected String common(String... items) { - if (items.length == 0) - return ""; - - String result = items[ 0]; - for (String item : items) { - while (!item.startsWith(result)) { - // shorten the result until it matches - result = result.substring(0, result.length() - 1); - } - } - return result; - } - - public void list(String... items) { - try { - ShellUtils.getShellManager().getCurrentShell().list(items); - } catch (NameNotFoundException ex) { - // should not happen! - System.err.println("Cannot find current shell: " + ex.getMessage()); - } - } } Modified: trunk/shell/src/shell/org/jnode/shell/help/CommandLineElement.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/CommandLineElement.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/CommandLineElement.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,6 +21,8 @@ package org.jnode.shell.help; +import org.jnode.driver.console.CompletionInfo; + /** * @author qades */ @@ -43,7 +45,7 @@ public abstract String format(); public abstract void describe(Help help); - public abstract String complete(String partial); + public abstract void complete(CompletionInfo completion, String partial); /** * Indicates if the element is satisfied. Modified: trunk/shell/src/shell/org/jnode/shell/help/Help.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/Help.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/Help.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -25,6 +25,7 @@ import javax.naming.NamingException; +import org.jnode.driver.console.CompletionInfo; import org.jnode.naming.InitialNaming; import org.jnode.plugin.PluginUtils; import org.jnode.shell.CommandLine; @@ -174,18 +175,17 @@ Help.getHelp().help(this, command); } - public String complete(CommandLine partial) throws CompletionException { + public String complete(CompletionInfo completion, CommandLine partial) + throws CompletionException { // The completion strategy is to try to complete each of the // syntaxes, and return the longest completion string. String max = ""; boolean foundCompletion = false; for (Syntax syntax : syntaxes) { try { - final String s = syntax.complete(partial); + syntax.complete(completion, partial); foundCompletion = true; - if (s.length() > max.length()) { - max = s; - } + } catch (CompletionException ex) { // just try the next syntax } Modified: trunk/shell/src/shell/org/jnode/shell/help/Parameter.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/Parameter.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/Parameter.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,6 +21,8 @@ package org.jnode.shell.help; +import org.jnode.driver.console.CompletionInfo; + /** * @author qades */ @@ -104,20 +106,20 @@ argument.describe(help); } - public final String complete(String partial) { - // delegate to argument, merely close the parameter if no argument exists - if (hasArgument()) { - if (Syntax.DEBUG) Syntax.LOGGER.debug("Parameter.complete: argument is " + - argument.format()); - return argument.complete(partial); - } - else { - // FIXME - this assumes that the partial string can never legitimately - // have leading/trailing whitespace. - if (Syntax.DEBUG) Syntax.LOGGER.debug("Parameter.complete: no argument"); - return partial.trim() + " "; + public final void complete(CompletionInfo completion, String partial) { + // delegate to argument, merely close the parameter if no argument exists + if (hasArgument()) { + if (Syntax.DEBUG) Syntax.LOGGER.debug("Parameter.complete: argument is " + + argument.format()); + argument.complete(completion, partial); + } + else { + // FIXME - this assumes that the partial string can never legitimately + // have leading/trailing whitespace. + if (Syntax.DEBUG) Syntax.LOGGER.debug("Parameter.complete: no argument"); + completion.addCompletion(" "); + } } - } public final boolean isSatisfied() { if( !hasArgument() ) Modified: trunk/shell/src/shell/org/jnode/shell/help/Syntax.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/Syntax.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/Syntax.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -27,6 +27,7 @@ import java.util.NoSuchElementException; import org.apache.log4j.Logger; +import org.jnode.driver.console.CompletionInfo; import org.jnode.shell.CommandLine; import org.jnode.shell.help.argument.OptionArgument; @@ -62,9 +63,10 @@ return params; } - public String complete(CommandLine partial) throws CompletionException { + public void complete(CompletionInfo completion, CommandLine partial) + throws CompletionException { Parameter param; - String value; + CommandLine.Token value; int tokenType; if (DEBUG) LOGGER.debug("Syntax.complete: this.description = " + this.description); @@ -81,7 +83,7 @@ partial.isArgumentAnticipated()); if (param != null && partial.isArgumentAnticipated()) { - value = ""; + value = null; tokenType = CommandLine.LITERAL; } else { param = visitor.getLastParam(); @@ -91,29 +93,24 @@ if (param == null) { if (DEBUG) LOGGER.debug("Syntax.complete: no param"); - return ""; + // completion.addCompletion(" "); + return; } if (DEBUG) LOGGER.debug("Syntax.complete: param = " + param.format() + ", value = " + value + ", tokenType = " + tokenType); - String res = ""; if (param.hasArgument()) { - res = param.complete(value); - // FIXME - we need to use the correct escaping syntax ... and ideally - // we need to know what escaping that was used in the original argument - // we are trying to complete. - if (res == null) { - res = param.isAnonymous() ? "" : ("-" + param.getName() + " "); + if (value != null) { + param.complete(completion, value.token); + completion.setCompletionStart(value.start); } - else if (tokenType == CommandLine.STRING) { - res = CommandLine.doEscape(res, true); + else { + param.complete(completion, ""); } } - if (partial.isArgumentAnticipated()) { - res = " " + res; + else if (!param.isAnonymous()) { + completion.addCompletion("-" + param.getName()); } - if (DEBUG) LOGGER.debug("Syntax.complete: returning '" + res + "'"); - return res; } synchronized ParsedArguments parse(CommandLine cmdLine) throws SyntaxErrorException { @@ -151,23 +148,23 @@ final ParameterIterator paramIterator = new ParameterIterator(); // FIXME - should use a Token iterator here ... - final Iterator<String> it = cmdLine.iterator(); + final Iterator<CommandLine.Token> it = cmdLine.tokenIterator(); boolean acceptNames = true; - String s = it.hasNext() ? it.next() : null; - while (s != null) { - if (DEBUG) LOGGER.debug("Syntax.visitor: arg '" + s + "'"); + CommandLine.Token token = it.hasNext() ? it.next() : null; + while (token != null) { + if (DEBUG) LOGGER.debug("Syntax.visitor: arg '" + token + "'"); if (param == null) { // Trying to match a Parameter. - if (acceptNames && "--".equals(s)) { + if (acceptNames && "--".equals(token)) { acceptNames = false; - s = it.hasNext() ? it.next() : null; + token = it.hasNext() ? it.next() : null; } else if (paramIterator.hasNext()) { param = (Parameter) paramIterator.next(); // FIXME real hacky stuff here!! I'm trying to stop anonymous parameters matching // "-name" ... except when they should ... if (param.isAnonymous()) { - if (s.charAt(0) != '-' || param.getArgument() instanceof OptionArgument) { + if (token.token.charAt(0) != '-' || param.getArgument() instanceof OptionArgument) { if (DEBUG) LOGGER.debug("Syntax.visitor: trying anonymous param " + param.format()); visitor.visitParameter(param); } @@ -175,10 +172,10 @@ param = null; } } - else if (acceptNames && s.equals("-" + param.getName())) { + else if (acceptNames && token.equals("-" + param.getName())) { if (DEBUG) LOGGER.debug("Syntax.visitor: trying named param " + param.format()); visitor.visitParameter(param); - s = it.hasNext() ? it.next() : null; + token = it.hasNext() ? it.next() : null; } else { if (DEBUG) LOGGER.debug("Syntax.visitor: skipping named param " + param.format()); @@ -186,8 +183,8 @@ } } else { - if (DEBUG) LOGGER.debug("Syntax.visitor: no param for '" + s + "'"); - throw new SyntaxErrorException("Unexpected argument '" + s + "'"); + if (DEBUG) LOGGER.debug("Syntax.visitor: no param for '" + token + "'"); + throw new SyntaxErrorException("Unexpected argument '" + token + "'"); } } if (param != null) { @@ -197,17 +194,17 @@ if (arg == null) { visitor.visitValue(null, last, CommandLine.LITERAL); } - else if (s != null) { - String value = visitor.visitValue(s, last, CommandLine.LITERAL); + else if (token != null) { + CommandLine.Token value = visitor.visitValue(token, last, CommandLine.LITERAL); if (visitor.isValueValid(arg, value, last)) { - arg.setValue(value); - s = it.hasNext() ? it.next() : null; + arg.setValue(value.token); + token = it.hasNext() ? it.next() : null; } else if (!param.isOptional()) { - if (DEBUG) LOGGER.debug("Syntax.visitor: bad value '" + s + + if (DEBUG) LOGGER.debug("Syntax.visitor: bad value '" + token + "' for mandatory param " + param.format()); throw new SyntaxErrorException("Invalid value for argument"); } else { - if (DEBUG) LOGGER.debug("Syntax.visitor: bad value '" + s + + if (DEBUG) LOGGER.debug("Syntax.visitor: bad value '" + token + "' optional param " + param.format()); if (DEBUG) LOGGER.debug("Syntax.visitor: clearing param"); param = null; @@ -254,14 +251,14 @@ public void visitParameter(Parameter p); - public String visitValue(String s, boolean last, int tokenType); + public CommandLine.Token visitValue(CommandLine.Token token, boolean last, int tokenType); - public boolean isValueValid(Argument arg, String value, boolean last); + public boolean isValueValid(Argument arg, CommandLine.Token value, boolean last); } private class CompletionVisitor implements CommandLineVisitor { private Parameter param = null; - private String value; + private CommandLine.Token value; private int tokenType; private boolean last; @@ -276,20 +273,21 @@ this.tokenType = 0; } - public String visitValue(String s, boolean last, int tokenType) { - if (DEBUG) LOGGER.debug("CompletionVisitor: value = '" + s + "', " + last + ", " + tokenType); + public CommandLine.Token visitValue( + CommandLine.Token token, boolean last, int tokenType) { + if (DEBUG) LOGGER.debug("CompletionVisitor: value = '" + token.token + "', " + last + ", " + tokenType); this.last = last; if (last) { - this.value = s; + this.value = token; this.tokenType = tokenType; } - return s; + return token; } - public boolean isValueValid(Argument arg, String value, boolean last) { + public boolean isValueValid(Argument arg, CommandLine.Token value, boolean last) { if (DEBUG) LOGGER.debug("CompletionVisitor: isValueValid " + arg.format() + ", " + last + ", " + tokenType); - boolean res = last || arg.isValidValue(value); + boolean res = last || arg.isValidValue(value.token); if (DEBUG) LOGGER.debug("CompletionVisitor: isValueValid -> " + res); return res; } @@ -298,7 +296,7 @@ return last ? this.param : null; } - public String getLastValue() { + public CommandLine.Token getLastValue() { return last ? this.value : null; } @@ -320,8 +318,8 @@ this.param = p; } - public String visitValue(String s, boolean last, int tokenType) { - if (last && "".equals(s)) return null; + public CommandLine.Token visitValue(CommandLine.Token s, boolean last, int tokenType) { + if (last && s == null) return null; valued = true; return s; } @@ -345,12 +343,12 @@ valued = false; } - public boolean isValueValid(Argument arg, String value, boolean last) { - return arg.isValidValue(value); + public boolean isValueValid(Argument arg, CommandLine.Token value, boolean last) { + return arg.isValidValue(value.token); } } - class ParameterIterator implements Iterator { + class ParameterIterator implements Iterator<Parameter> { final Parameter[] params = Syntax.this.params; final int length = params.length; @@ -363,7 +361,7 @@ return (nextParamsIdx < length); } - public Object next() { + public Parameter next() { if (nextParamsIdx < length) { return params[nextParamsIdx++]; } else { Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/AliasArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/AliasArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/AliasArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,11 +21,9 @@ package org.jnode.shell.help.argument; -import java.util.ArrayList; -import java.util.List; - import javax.naming.NameNotFoundException; +import org.jnode.driver.console.CompletionInfo; import org.jnode.shell.ShellUtils; import org.jnode.shell.alias.AliasManager; import org.jnode.shell.help.Argument; @@ -43,8 +41,7 @@ super(name, description); } - public String complete(String partial) { - final List<String> aliases = new ArrayList<String>(); + public void complete(CompletionInfo completion, String partial) { try { // get the alias manager final AliasManager aliasMgr = ShellUtils.getShellManager() @@ -53,14 +50,12 @@ // collect matching aliases for (String alias : aliasMgr.aliases()) { if (alias.startsWith(partial)) { - aliases.add(alias); + completion.addCompletion(alias); } } - - return complete(partial, aliases); } catch (NameNotFoundException ex) { // should not happen! - return partial; + return; } } } Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/ClassNameArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/ClassNameArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/ClassNameArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -40,7 +40,7 @@ // here the specific command line completion would be implemented - public Class getClass(ParsedArguments cmdLine) throws ClassNotFoundException { + public Class<?> getClass(ParsedArguments cmdLine) throws ClassNotFoundException { final ClassLoader cl = Thread.currentThread().getContextClassLoader(); return cl.loadClass(getValue(cmdLine)); } Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/DeviceArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/DeviceArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/DeviceArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,15 +21,13 @@ package org.jnode.shell.help.argument; -import java.util.ArrayList; -import java.util.List; - import javax.naming.NameNotFoundException; import org.jnode.driver.Device; import org.jnode.driver.DeviceAPI; import org.jnode.driver.DeviceManager; import org.jnode.driver.DeviceNotFoundException; +import org.jnode.driver.console.CompletionInfo; import org.jnode.naming.InitialNaming; import org.jnode.shell.help.Argument; import org.jnode.shell.help.ParsedArguments; @@ -71,8 +69,7 @@ } } - public String complete(String partial) { - final List<String> devIds = new ArrayList<String>(); + public void complete(CompletionInfo completion, String partial) { try { // get the alias manager final DeviceManager devMgr = InitialNaming @@ -85,13 +82,12 @@ final String devId = dev.getId(); if (devId.startsWith(partial)) { - devIds.add(devId); + completion.addCompletion(devId); } } - return complete(partial, devIds); } catch (NameNotFoundException ex) { // should not happen! - return partial; + return; } } } Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/EnumOptionArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/EnumOptionArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/EnumOptionArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,17 +21,14 @@ package org.jnode.shell.help.argument; -import java.util.ArrayList; -import java.util.List; +import java.lang.reflect.Array; +import org.jnode.driver.console.CompletionInfo; import org.jnode.shell.help.Argument; import org.jnode.shell.help.Help; import org.jnode.shell.help.Parameter; import org.jnode.shell.help.ParsedArguments; -import java.lang.Enum; -import java.lang.reflect.Array; - /** * @author qades */ @@ -61,16 +58,13 @@ option.describe(help); } - public String complete(String partial) { - final List<String> opts = new ArrayList<String>(); + public void complete(CompletionInfo completion, String partial) { for (EnumOption<T> option : options) { final String name = option.getName(); if (name.startsWith(partial)) { - opts.add(name); + completion.addCompletion(name); } } - - return complete(partial, opts); } public final T getEnum(ParsedArguments args, Class<T> type) { @@ -121,7 +115,7 @@ public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("Options: "); - for (EnumOption option : options) { + for (EnumOption<?> option : options) { sb.append(", "); sb.append(option.getName()); } Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/FileArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/FileArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/FileArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -24,10 +24,10 @@ import java.io.File; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import org.jnode.driver.console.CompletionInfo; import org.jnode.shell.PathnamePattern; import org.jnode.shell.help.Argument; import org.jnode.shell.help.ParsedArguments; @@ -85,11 +85,11 @@ return files.toArray(new File[files.size()]); } - public String complete(String partial) { + public void complete(CompletionInfo completion, String partial) { // Get last full directory final int idx = partial.lastIndexOf(File.separatorChar); final String dir; - if(idx == 0){ + if (idx == 0) { dir = String.valueOf(File.separatorChar); } else if (idx > 0) { dir = partial.substring(0, idx); @@ -109,28 +109,21 @@ } } }); - if (names == null) { - return partial; - } else if (names.length == 0) { - return partial; - } else { - final ArrayList<String> list = new ArrayList<String>(names.length); + if (names != null && names.length > 0) { final String prefix = (dir.length() == 0) ? "" : dir.equals("/") ? "/" : dir + File.separatorChar; for (String n : names) { - final String name = prefix + n; + String name = prefix + n; if (name.startsWith(partial)) { - list.add(name); + if (new File(f, name).isDirectory()) { + name += File.separatorChar; + completion.addCompletion(name, true); + } + else { + completion.addCompletion(name); + } } } - String completed = complete(partial, list); - if (completed.endsWith(" ")) { - String path = completed.substring(0, completed.length() - 1); - if (new File(path).isDirectory()) { - completed = path + File.separatorChar; - } - } - return completed; } } } Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/HostNameArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/HostNameArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/HostNameArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,12 +21,12 @@ package org.jnode.shell.help.argument; +import java.net.InetAddress; +import java.net.UnknownHostException; + import org.jnode.shell.help.Argument; import org.jnode.shell.help.ParsedArguments; -import java.net.InetAddress; -import java.net.UnknownHostException; - /** * @author Martin Hartvig */ Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/InetAddressArgument.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/help/argument/InetAddressArgument.java 2008-03-19 21:22:34 UTC (rev 3858) +++ trunk/shell/src/shell/org/jnode/shell/help/argument/InetAddressArgument.java 2008-03-21 08:41:06 UTC (rev 3859) @@ -21,7 +21,8 @@ package org.jnode.shell.help.argument; -import java.net.*; +import java.net.InetAddress; +import java.net.UnknownHostException; import org.jnode.shell.help.Argument; import org.jnode.shell.help.ParsedArguments; Modified: trunk/shell/src/shell/org/jnode/shell/help/argument/IntegerArgument.java =================================================================== --- trunk/shell/src/sh... [truncated message content] |