Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract shell #61

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
*.ipr
*.iws
target
/.settings
/.classpath
/.project
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<groupId>jline</groupId>
<artifactId>jline</artifactId>
<name>JLine</name>
<version>2.11-SNAPSHOT</version>
<version>2.12-SNAPSHOT</version>

<licenses>
<license>
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/jline/UnixTerminal.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ public void init() throws Exception {

setAnsiSupported(true);

// set the console to be character-buffered instead of line-buffered
// also make sure we're distinguishing carriage return from newline
settings.set("-icanon min 1 -icrnl -inlcr");
// Set the console to be character-buffered instead of line-buffered.
// Make sure we're distinguishing carriage return from newline.
// Allow ctrl-s keypress to be used (as forward search)
settings.set("-icanon min 1 -icrnl -inlcr -ixon");

setEchoEnabled(false);
}
Expand Down
199 changes: 156 additions & 43 deletions src/main/java/jline/console/ConsoleReader.java

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/main/java/jline/console/KeyMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ public static KeyMap emacs() {
public static final char CTRL_J = (char) 10;
public static final char CTRL_M = (char) 13;
public static final char CTRL_R = (char) 18;
public static final char CTRL_S = (char) 19;
public static final char CTRL_U = (char) 21;
public static final char CTRL_X = (char) 24;
public static final char CTRL_Y = (char) 25;
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/jline/console/completer/ArgumentParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2002-2012, the original author or authors.
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
* http://www.opensource.org/licenses/bsd-license.php
*/
package jline.console.completer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* An utility class to parse arguments for the {@link CommandArgumentsCompleter}
*
* @author Baptiste Mesta
*/
public class ArgumentParser {

private final String original;

private List<String> arguments;

private String command;

private String lastArgument;

private int offset;

/**
*
*/
public ArgumentParser(final String string) {
original = string;
final List<String> list = Arrays.asList(string.split("(\\s)+"));
if (list.size() > 0) {
command = list.get(0);
if (list.size() > 1) {
arguments = list.subList(1, list.size());
} else {
arguments = new ArrayList<String>();
}
} else {
arguments = new ArrayList<String>();
}
if (arguments.size() > 0) {
lastArgument = arguments.get(arguments.size() - 1);
offset = original.lastIndexOf(lastArgument);
} else {
offset = original.length();
}
}

public String getCommand() {
return command;
}

public String getLastArgument() {
return lastArgument;
}

public int getLastArgumentIndex() {
return arguments.size() - 1;
}

public int getOffset() {
return offset;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2002-2012, the original author or authors.
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
* http://www.opensource.org/licenses/bsd-license.php
*/
package jline.console.completer;

import static jline.internal.Preconditions.checkNotNull;

import java.util.HashMap;
import java.util.List;

import jline.shell.ShellContext;
import jline.shell.command.ShellCommand;

/**
* Allow to complete a set of given commands
* Each command can have different completer
* At the start of the line the completer complete with command name
* Then it completes the line using command's completers
*
* @author Baptiste Mesta
*/
public class CommandArgumentsCompleter<T extends ShellContext> implements Completer {

private final HashMap<String, ShellCommand<T>> commands;

private final StringsCompleter commandCompleter;

/**
* @param commands
*/
public CommandArgumentsCompleter(final HashMap<String, ShellCommand<T>> commands) {
this.commands = commands;
commandCompleter = new StringsCompleter(commands.keySet());
}

public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
checkNotNull(candidates);
final int pos = commandCompleter.complete(buffer, cursor, candidates);
if (pos != -1) {
return pos;
}
if (buffer != null) {
final ArgumentParser argumentParser = new ArgumentParser(buffer);
final String command = argumentParser.getCommand();
if (command != null) {
final int lastArgumentIndex = Math.max(argumentParser.getLastArgumentIndex(), 0);
// complete with element from completer of the command
final ShellCommand<T> clientCommand = commands.get(command);
if (clientCommand != null) {
final List<Completer> completers = clientCommand.getCompleters();
if (completers.size() > lastArgumentIndex) {
final Completer completer = completers.get(lastArgumentIndex);
final String lastArgument = argumentParser.getLastArgument();
final int complete = completer.complete(lastArgument, lastArgument != null ? lastArgument.length() : 0, candidates);
return complete + argumentParser.getOffset();
}
}
}
}

if (candidates.size() == 1) {
candidates.set(0, candidates.get(0) + " ");
}
return candidates.isEmpty() ? -1 : cursor;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2002-2012, the original author or authors.
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
* http://www.opensource.org/licenses/bsd-license.php
*/
package jline.console.completer;

import java.util.List;

/**
* @author Baptiste Mesta
*/
public abstract class ResolvingStringsCompleter extends StringsCompleter {

@Override
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
getStrings().clear();
final List<String> resolveStrings = resolveStrings();
if (resolveStrings != null) {
getStrings().addAll(resolveStrings);
}
return super.complete(buffer, cursor, candidates);
}

/**
* @return
*/
public abstract List<String> resolveStrings();
}
9 changes: 8 additions & 1 deletion src/main/java/jline/console/history/MemoryHistory.java
Original file line number Diff line number Diff line change
Expand Up @@ -337,5 +337,12 @@ public boolean next() {
return true;
}


@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Entry e : this) {
sb.append(e.toString() + "\n");
}
return sb.toString();
}
}
130 changes: 130 additions & 0 deletions src/main/java/jline/shell/BaseShell.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2002-2012, the original author or authors.
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
* http://www.opensource.org/licenses/bsd-license.php
*/
package jline.shell;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import jline.console.ConsoleReader;
import jline.console.completer.CommandArgumentsCompleter;
import jline.shell.command.HelpCommand;
import jline.shell.command.ShellCommand;

/**
* A basic shell
* Implement abstract methods
* to run it just execute (e.g. in a main)
* shell.run();
*
* @author Baptiste Mesta
*/
public abstract class BaseShell<T extends ShellContext> {

private HashMap<String, ShellCommand<T>> commands;

private HelpCommand<T> helpCommand;

protected void init() throws Exception {
final List<ShellCommand<T>> commandList = initShellCommands();
commands = new HashMap<String, ShellCommand<T>>();
for (final ShellCommand<T> shellCommand : commandList) {
commands.put(shellCommand.getName(), shellCommand);
}
helpCommand = getHelpCommand();
if (helpCommand != null) {
commands.put(helpCommand.getName(), helpCommand);
}

}

/**
* return the help command used
* Can be overridden
*/
protected HelpCommand<T> getHelpCommand() {
return new HelpCommand<T>(commands);
}

/**
* @return
* list of commands contributed to the shell
* @throws Exception
*/
protected abstract List<ShellCommand<T>> initShellCommands() throws Exception;

/**
* called by {@link BaseShell} when the shell is exited
*
* @throws Exception
*/
protected void destroy() throws Exception {
}

public void run() throws Exception {
init();
printWelcomeMessage();
final ConsoleReader reader = new ConsoleReader();
reader.setBellEnabled(false);
final CommandArgumentsCompleter<T> commandArgumentsCompleter = new CommandArgumentsCompleter<T>(commands);

reader.addCompleter(commandArgumentsCompleter);

String line;
while ((line = reader.readLine("\n" + getPrompt())) != null) {
final List<String> args = parse(line);
final String command = args.remove(0);
if (commands.containsKey(command)) {
final ShellCommand<T> clientCommand = commands.get(command);
if (clientCommand.validate(args)) {
try {
clientCommand.execute(args, getContext());
} catch (final Exception e) {
e.printStackTrace();
}
} else {
clientCommand.printHelp();
}
} else if ("exit".equals(line)) {
System.out.println("Exiting application");
destroy();
return;
} else {
System.out.println("Wrong argument");
helpCommand.printHelp();
}
}
destroy();
}

/**
* @return
*/
protected abstract T getContext();

/**
* Override this to print a welcom message
*/
protected abstract void printWelcomeMessage();

/**
* allow to specify the prompt used
*/
protected abstract String getPrompt();

/**
* used to parse arguments of the line
*
* @param line
* @return
*/
protected List<String> parse(final String line) {
return new ArrayList<String>(Arrays.asList(line.trim().split("(\\s)+")));
}

}
14 changes: 14 additions & 0 deletions src/main/java/jline/shell/ShellContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2002-2012, the original author or authors.
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
* http://www.opensource.org/licenses/bsd-license.php
*/
package jline.shell;

/**
* @author Baptiste Mesta
*/
public interface ShellContext {

}
Loading