Skip to content

Commit

Permalink
Merge branch 'help-printer' of https://github.com/mattirn/jline3
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Mar 19, 2019
2 parents 1d664b1 + 5664137 commit 4f100ba
Show file tree
Hide file tree
Showing 8 changed files with 315 additions and 159 deletions.
4 changes: 4 additions & 0 deletions builtins/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
<groupId>org.jline</groupId>
<artifactId>jline-reader</artifactId>
</dependency>
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline-style</artifactId>
</dependency>

<dependency>
<groupId>com.googlecode.juniversalchardet</groupId>
Expand Down
62 changes: 26 additions & 36 deletions builtins/src/main/java/org/jline/builtins/Commands.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import org.jline.builtins.Completers.CompletionData;
import org.jline.builtins.Options;
import org.jline.builtins.Options.HelpException;
import org.jline.builtins.Source.StdInSource;
import org.jline.builtins.Source.URLSource;
import org.jline.keymap.KeyMap;
Expand Down Expand Up @@ -62,12 +63,9 @@ public static void tmux(Terminal terminal, PrintStream out, PrintStream err,
"Usage: tmux [command]",
" -? --help Show help",
};
// Simplified parsing
if (argv.length == 1 && ("--help".equals(argv[0]) || "-?".equals(argv[0]))) {
for (String s : usage) {
err.println(s);
}
return;
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
throw new HelpException(opt.usage());
}
// Tmux with no args
if (argv.length == 0) {
Expand Down Expand Up @@ -103,8 +101,7 @@ public static void nano(Terminal terminal, PrintStream out, PrintStream err,
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}
Nano edit = new Nano(terminal, currentDir);
edit.open(opt.args());
Expand All @@ -113,15 +110,15 @@ public static void nano(Terminal terminal, PrintStream out, PrintStream err,

public static void less(Terminal terminal, InputStream in, PrintStream out, PrintStream err,
Path currentDir,
String[] argv) throws IOException, InterruptedException {
String[] argv) throws Exception {
final String[] usage = {
"less - file pager",
"Usage: less [OPTIONS] [FILES]",
" -? --help Show help",
" -e --quit-at-eof Exit on second EOF",
" -E --QUIT-AT-EOF Exit on EOF",
" -q --quiet --silent Silent mode",
" -Q --QUIET --SILENT Completely silent",
" -Q --QUIET --SILENT Completely silent",
" -S --chop-long-lines Do not fold long lines",
" -i --ignore-case Search ignores lowercase case",
" -I --IGNORE-CASE Search ignores all case",
Expand All @@ -132,8 +129,7 @@ public static void less(Terminal terminal, InputStream in, PrintStream out, Prin
Options opt = Options.compile(usage).parse(argv);

if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}

Less less = new Less(terminal);
Expand Down Expand Up @@ -163,7 +159,7 @@ public static void less(Terminal terminal, InputStream in, PrintStream out, Prin
}

public static void history(LineReader reader, PrintStream out, PrintStream err,
String[] argv) throws IOException, IllegalArgumentException {
String[] argv) throws Exception {
final String[] usage = {
"history - list history of commands",
"Usage: history [-dnrfEi] [-m match] [first] [last]",
Expand All @@ -176,24 +172,23 @@ public static void history(LineReader reader, PrintStream out, PrintStream err,
" -m match If option -m is present the first argument is taken as a pattern",
" and only the history events matching the pattern will be shown",
" -d Print timestamps for each event",
" -f Print full time-date stamps in the US format",
" -E Print full time-date stamps in the European format",
" -i Print full time-date stamps in ISO8601 format",
" -f Print full time date stamps in the US format",
" -E Print full time date stamps in the European format",
" -i Print full time date stamps in ISO8601 format",
" -n Suppresses command numbers",
" -r Reverses the order of the commands",
" -A Appends the history out to the given file",
" -R Reads the history from the given file",
" -W Writes the history out to the given file",
" -I If added to -R, only the events that are not contained within the internal list are added",
" If added to -W/A, only the events that are new since the last incremental operation to",
" the file are added",
" If added to -W or -A, only the events that are new since the last incremental operation",
" to the file are added",
" [first] [last] These optional arguments are numbers. A negative number is",
" used as an offset to the current history event number"};
Options opt = Options.compile(usage).parse(argv);

if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}
History history = reader.getHistory();
boolean done = true;
Expand Down Expand Up @@ -300,7 +295,7 @@ private static int parseInteger(String s) throws IllegalArgumentException {

public static void complete(LineReader reader, PrintStream out, PrintStream err,
Map<String, List<CompletionData>> completions,
String[] argv) {
String[] argv) throws HelpException {
final String[] usage = {
"complete - edit command specific tab-completions",
"Usage: complete",
Expand All @@ -317,8 +312,7 @@ public static void complete(LineReader reader, PrintStream out, PrintStream err,
Options opt = Options.compile(usage).parse(argv);

if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}

String command = opt.get("command");
Expand Down Expand Up @@ -372,8 +366,7 @@ public static void widget(LineReader reader, PrintStream out, PrintStream err,
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}

int actions = (opt.isSet("N") ? 1 : 0)
Expand Down Expand Up @@ -437,7 +430,7 @@ else if (opt.args().size() == 1) {
public static void keymap(LineReader reader,
PrintStream out,
PrintStream err,
String[] argv) {
String[] argv) throws HelpException {
final String[] usage = {
"keymap - manipulate keymaps",
"Usage: keymap [options] -l [-L] [keymap ...]",
Expand All @@ -462,14 +455,13 @@ public static void keymap(LineReader reader,
" -e Select emacs keymap and bind it to main",
" -l List existing keymap names",
" -p List bindings which have given key sequence as a a prefix",
" -r Unbind specified in-strings",
" -s Bind each in-string to each out-string",
" -r Unbind specified in-strings ",
" -s Bind each in-string to each out-string ",
" -v Select viins keymap and bind it to main",
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}

Map<String, KeyMap<Binding>> keyMaps = reader.getKeyMaps();
Expand Down Expand Up @@ -784,7 +776,7 @@ else if (opt.isSet("s") || opt.args().size() > 1) {
public static void setopt(LineReader reader,
PrintStream out,
PrintStream err,
String[] argv) {
String[] argv) throws HelpException {
final String[] usage = {
"setopt - set options",
"Usage: setopt [-m] option ...",
Expand All @@ -794,8 +786,7 @@ public static void setopt(LineReader reader,
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}
if (opt.args().isEmpty()) {
for (Option option : Option.values()) {
Expand All @@ -813,7 +804,7 @@ public static void setopt(LineReader reader,
public static void unsetopt(LineReader reader,
PrintStream out,
PrintStream err,
String[] argv) {
String[] argv) throws HelpException {
final String[] usage = {
"unsetopt - unset options",
"Usage: unsetopt [-m] option ...",
Expand All @@ -823,8 +814,7 @@ public static void unsetopt(LineReader reader,
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
opt.usage(err);
return;
throw new HelpException(opt.usage());
}
if (opt.args().isEmpty()) {
for (Option option : Option.values()) {
Expand Down
163 changes: 160 additions & 3 deletions builtins/src/main/java/org/jline/builtins/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jline.terminal.Terminal;
import org.jline.utils.AttributedStyle;
import org.jline.utils.AttributedString;
import org.jline.utils.StyleResolver;

/**
* Yet another GNU long options parser. This one is configured by parsing its Usage string.
Expand Down Expand Up @@ -220,7 +227,12 @@ public List<String> args() {
return args;
}

// Added for backword compability
public void usage(PrintStream err) {
err.print(usage());
}

public String usage() {
StringBuilder buf = new StringBuilder();
int index = 0;

Expand All @@ -235,9 +247,7 @@ public void usage(PrintStream err) {
buf.append(NL);
}

String msg = buf.toString();

err.print(msg);
return buf.toString();
}

/**
Expand Down Expand Up @@ -505,4 +515,151 @@ public String toString() {
return "isSet" + optSet + "\nArg" + optArg + "\nargs" + xargs;
}

public static class HelpPrinter {
private final List<String> names = Arrays.asList("ti", "co", "ar", "op");
private final Pattern patternCommand = Pattern.compile("(^\\s*)([a-z]+[a-z-]*){1}\\b");
private final Pattern patternArgument = Pattern.compile("(\\[|\\s|=)([A-Za-z]+[A-Za-z_-]*){1}\\b");
private final Pattern patternArgumentInComment = Pattern.compile("(\\s)([a-z]+[-]+[a-z]+|[A-Z_]{2,}){1}(\\s)");
private final Pattern patternOption = Pattern.compile("(\\s|\\[)(-\\?|[-]{1,2}[A-Za-z-]+\\b){1}");
private final String title = "Usage";
private final String ansiReset = "\033[0m";
private String ansi4title = "";
private String ansi4command = "";
private String ansi4argument = "";
private String ansi4option= "";
private boolean color = true;
private Terminal terminal;

public HelpPrinter() {
this(null);
}

public HelpPrinter(Terminal terminal) {
this.terminal = terminal;
if (ansiSupported()) {
setColors("ti=1;34:co=1:ar=3:op=33");
} else {
this.color = false;
}
}

public void setColor(boolean color) {
this.color = color;
}

public void setColor4title(AttributedStyle style) {
this.ansi4title = styleToAnsiCode(style);
}

public void setColor4command(AttributedStyle style) {
this.ansi4command = styleToAnsiCode(style);
}

public void setColor4argument(AttributedStyle style) {
this.ansi4argument = styleToAnsiCode(style);
}

public void setColor4option(AttributedStyle style) {
this.ansi4option = styleToAnsiCode(style);
}

public void setColors (Map<String, String> colors) {
for (String n: names) {
if (colors.containsKey(n)) {
AttributedStyle s = new StyleResolver(colors::get).resolve(colors.get(n));
if (n.equals("ti")) {
setColor4title(s);
} else if (n.equals("co")) {
setColor4command(s);
} else if (n.equals("ar")) {
setColor4argument(s);
} else if (n.equals("op")) {
setColor4option(s);
}
}
}
}

public void setColors (String str) {
String sep = str.matches("[a-z]{2}=[0-9]*(;[0-9]+)*(:[a-z]{2}=[0-9]*(;[0-9]+)*)*") ? ":" : " ";
setColors(Arrays.stream(str.split(sep))
.collect(Collectors.toMap(s -> s.substring(0, s.indexOf('=')),
s -> s.substring(s.indexOf('=') + 1))));

}

private boolean ansiSupported () {
return (new AttributedString("HP", AttributedStyle.DEFAULT.foreground(AttributedStyle.RED))
.toAnsi(terminal).split("HP").length > 0);
}

private String styleToAnsiCode(AttributedStyle style) {
String[] as = new AttributedString("HP", style).toAnsi(terminal).split("HP");
return as.length > 0 ? as[0] : ansiReset;
}

public void print(PrintStream err, String msg) {
if (color) {
String[] p = msg.split(title + ":", 2);
if (p.length == 2) {
err.print(highlightCommand(p[0]));
err.print(ansi4title + title + ansiReset + ":");
for (String line: p[1].split("\n")) {
int ind = line.lastIndexOf(" ");
if (ind > 20) {
line = highlightSyntax(line.substring(0, ind)) + highlightComment(line.substring(ind + 1, line.length()));
} else {
line = highlightSyntax(line);
}
err.println(line);
}
} else {
err.print(msg);
}
} else {
err.print(msg);
}
}

private String highlightCommand(String command) {
Matcher matcher = patternCommand.matcher(command);
if (matcher.find()) {
command = matcher.replaceAll("$1" + ansi4command + "$2" + ansiReset);
}
return command;
}

private String highlightSyntax(String syntax) {
syntax = highlightCommand(syntax);
Matcher matcher = patternArgument.matcher(syntax);
if (matcher.find()) {
syntax = matcher.replaceAll("$1" + ansi4argument + "$2" + ansiReset);
}
matcher = patternOption.matcher(syntax);
if (matcher.find()) {
syntax = matcher.replaceAll("$1" + ansi4option + "$2" + ansiReset);
}
return syntax;
}

private String highlightComment(String comment) {
Matcher matcher = patternOption.matcher(comment);
if (matcher.find()) {
comment = matcher.replaceAll("$1" + ansi4option + "$2" + ansiReset);
}
matcher = patternArgumentInComment.matcher(comment);
if (matcher.find()) {
comment = matcher.replaceAll("$1" + ansi4argument + "$2" + ansiReset + "$3");
}
return comment;
}
}

@SuppressWarnings("serial")
public static class HelpException extends Exception {
public HelpException(String message) {
super(message);
}
}

}

0 comments on commit 4f100ba

Please sign in to comment.