Skip to content

Commit

Permalink
Improved subcommands help
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Mar 20, 2020
1 parent b00a9a0 commit 9ea33be
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 61 deletions.
80 changes: 44 additions & 36 deletions builtins/src/main/java/org/jline/builtins/Builtins.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.jline.builtins.Completers.FilesCompleter;
Expand Down Expand Up @@ -380,30 +382,50 @@ private List<Completer> ttopCompleter(String name) {
return completers;
}

private static String[] splitToLines(String message) {
return message.replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n");
}

private static AttributedString highlightComment(String comment) {
return HelpException.highlightComment(comment, HelpException.defaultStyle());
}

private static String[] helpLines(String helpMessage, boolean body) {
return new HelpLines(helpMessage, body).lines();
}

private static class HelpLines {
private String helpMessage;
private boolean body;
private boolean subcommands;

public HelpLines(String helpMessage, boolean body) {
this.helpMessage = helpMessage;
this.body = body;
}

public String[] lines() {
String out = "";
Matcher tm = Pattern.compile("(^|\\n)(Usage|Summary)(:)").matcher(helpMessage);
if (tm.find()) {
subcommands = tm.group(2).matches("Summary");
if (body) {
out = helpMessage.substring(tm.end(3));
} else {
out = helpMessage.substring(0,tm.start(1));
}
}
return out.split("\\r?\\n");
}

public boolean subcommands() {
return subcommands;
}
}

public static CmdDesc compileCommandDescription(String helpMessage) {
List<AttributedString> main = new ArrayList<>();
Map<String, List<AttributedString>> options = new HashMap<>();
String[] msg = splitToLines(helpMessage);
String prevOpt = null;
boolean mainDone = false;
boolean start = false;
for (String s: msg) {
if (!start) {
if (s.trim().startsWith("Usage: ")) {
s = s.split("Usage:")[1];
start = true;
} else {
continue;
}
}
HelpLines hl = new HelpLines(helpMessage, true);
for (String s : hl.lines()) {
if (s.matches("^\\s+-.*$")) {
mainDone = true;
int ind = s.lastIndexOf(" ");
Expand All @@ -424,24 +446,15 @@ public static CmdDesc compileCommandDescription(String helpMessage) {
prevOpt = null;
}
if (!mainDone) {
main.add(HelpException.highlightSyntax(s.trim(), HelpException.defaultStyle()));
main.add(HelpException.highlightSyntax(s.trim(), HelpException.defaultStyle(), hl.subcommands()));
}
}
return new CmdDesc(main, ArgDesc.doArgNames(Arrays.asList("")), options);
}

public static List<OptDesc> compileCommandOptions(String helpMessage) {
List<OptDesc> out = new ArrayList<>();
String[] msg = splitToLines(helpMessage);
boolean start = false;
for (String s: msg) {
if (!start) {
if (s.trim().startsWith("Usage: ")) {
s = s.split("Usage:")[1];
start = true;
}
continue;
}
for (String s : helpLines(helpMessage, true)) {
if (s.matches("^\\s+-.*$")) {
int ind = s.lastIndexOf(" ");
if (ind > 0) {
Expand Down Expand Up @@ -469,19 +482,14 @@ public static List<OptDesc> compileCommandOptions(String helpMessage) {

public static List<String> compileCommandInfo(String helpMessage) {
List<String> out = new ArrayList<>();
String[] msg = splitToLines(helpMessage);
boolean first = true;
for (String s : msg) {
if (s.trim().startsWith("Usage: ")) {
break;
for (String s : helpLines(helpMessage, false)) {
if (first && s.contains(" - ")) {
out.add(s.substring(s.indexOf(" - ") + 3).trim());
} else {
if (first && s.contains(" - ")) {
out.add(s.substring(s.indexOf(" - ") + 3).trim());
} else {
out.add(s.trim());
}
first = false;
out.add(s.trim());
}
first = false;
}
return out;
}
Expand Down
35 changes: 21 additions & 14 deletions builtins/src/main/java/org/jline/builtins/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,10 @@ public static StyleResolver style(String str) {
return new StyleResolver(colors::get);
}

public static AttributedString highlight(String msg, StyleResolver resolver) {
Matcher tm = Pattern.compile("(^|\\n)(Usage:)").matcher(msg);
public static AttributedString highlight(String msg, StyleResolver resolver) {
Matcher tm = Pattern.compile("(^|\\n)(Usage|Summary)(:)").matcher(msg);
if (tm.find()) {
boolean subcommand = tm.group(2).equals("Summary");
AttributedStringBuilder asb = new AttributedStringBuilder(msg.length());
// Command
AttributedStringBuilder acommand = new AttributedStringBuilder()
Expand All @@ -549,9 +550,9 @@ public static AttributedString highlight(String msg, StyleResolver resolver) {
Collections.singletonList(resolver.resolve(".co")));
asb.append(acommand);
// Title
asb.styled(resolver.resolve(".ti"), "Usage").append(":");
asb.styled(resolver.resolve(".ti"), tm.group(2)).append(":");
// Syntax
for (String line : msg.substring(tm.end(2)).split("\n")) {
for (String line : msg.substring(tm.end(3)).split("\n")) {
int ind = line.lastIndexOf(" ");
String syntax, comment;
if (ind > 20) {
Expand All @@ -562,7 +563,7 @@ public static AttributedString highlight(String msg, StyleResolver resolver) {
comment = "";

}
asb.append(_highlightSyntax(syntax, resolver));
asb.append(_highlightSyntax(syntax, resolver, subcommand));
asb.append(_highlightComment(comment, resolver));
asb.append("\n");
}
Expand All @@ -572,15 +573,19 @@ public static AttributedString highlight(String msg, StyleResolver resolver) {
}
}

public static AttributedString highlightSyntax(String syntax, StyleResolver resolver, boolean subcommands) {
return _highlightSyntax(syntax, resolver, subcommands).toAttributedString();
}

public static AttributedString highlightSyntax(String syntax, StyleResolver resolver) {
return _highlightSyntax(syntax, resolver).toAttributedString();
return _highlightSyntax(syntax, resolver, false).toAttributedString();
}

public static AttributedString highlightComment(String comment, StyleResolver resolver) {
return _highlightComment(comment, resolver).toAttributedString();
}

private static AttributedStringBuilder _highlightSyntax(String syntax, StyleResolver resolver) {
private static AttributedStringBuilder _highlightSyntax(String syntax, StyleResolver resolver, boolean subcommand) {
StringBuilder indent = new StringBuilder();
for (char c : syntax.toCharArray()) {
if (c != ' ') {
Expand All @@ -590,14 +595,16 @@ private static AttributedStringBuilder _highlightSyntax(String syntax, StyleReso
}
AttributedStringBuilder asyntax = new AttributedStringBuilder().append(syntax.substring(indent.length()));
// command
asyntax.styleMatches(Pattern.compile("(?:^)([a-z]+[a-z-]*){1}\\b"),
asyntax.styleMatches(Pattern.compile("(?:^)([a-z]+[a-z0-9-]*){1}\\b"),
Collections.singletonList(resolver.resolve(".co")));
// argument
asyntax.styleMatches(Pattern.compile("(?:<|\\[|\\s|=)([A-Za-z]+[A-Za-z_-]*){1}\\b"),
Collections.singletonList(resolver.resolve(".ar")));
// option
asyntax.styleMatches(Pattern.compile("(?:^|\\s|\\[)(-\\$|-\\?|[-]{1,2}[A-Za-z-]+\\b){1}"),
Collections.singletonList(resolver.resolve(".op")));
if (!subcommand) {
// argument
asyntax.styleMatches(Pattern.compile("(?:<|\\[|\\s|=)([A-Za-z]+[A-Za-z_-]*){1}\\b"),
Collections.singletonList(resolver.resolve(".ar")));
// option
asyntax.styleMatches(Pattern.compile("(?:^|\\s|\\[)(-\\$|-\\?|[-]{1,2}[A-Za-z-]+\\b){1}"),
Collections.singletonList(resolver.resolve(".op")));
}
return new AttributedStringBuilder().append(indent).append(asyntax);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1337,8 +1337,9 @@ private Object subcommand(Builtins.CommandInput input) {
Object out = null;
try {
out = subcommands.get(input.command()).invoke(input.session()
, input.args()[0]
, Arrays.copyOfRange(input.xargs(), 1, input.xargs().length));
, input.args().length > 0 ? input.args()[0] : "help"
, input.xargs().length > 1 ? Arrays.copyOfRange(input.xargs(), 1, input.xargs().length)
: new Object[] {});
} catch (Exception e) {
exception = e;
}
Expand Down
27 changes: 18 additions & 9 deletions demo/src/main/java/org/jline/demo/Repl.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,14 @@ public boolean hasCommand(String command) {
}

private String command(String name) {
return commandExecute.containsKey(name) ? name : null;
String out = name;
if (name.equals("-?") || name.equals("--help")) {
out = "help";
}
if (!hasCommand(out)) {
throw new IllegalArgumentException("Unknown command: " + name);
}
return out;
}

@Override
Expand All @@ -117,7 +124,7 @@ public Widgets.CmdDesc commandDescription(String command) {

private Object cmd1(Builtins.CommandInput input) {
final String[] usage = {
"cmd1 - cmd1 parse args, return opt.argObjects().get(0)",
"cmd1 - cmd1 parse input.args, return opt.argObjects[0]",
"Usage: cmd1 [OBJECT]",
" -? --help Displays command help"
};
Expand All @@ -132,7 +139,7 @@ private Object cmd1(Builtins.CommandInput input) {

private Object cmd2(Builtins.CommandInput input) {
final String[] usage = {
"cmd2 - cmd2 parse xargs, return opt.args().get(0)",
"cmd2 - cmd2 parse input.xargs, return opt.args[0]",
"Usage: cmd2",
" -? --help Displays command help"
};
Expand All @@ -147,7 +154,7 @@ private Object cmd2(Builtins.CommandInput input) {

private Object cmd3(Builtins.CommandInput input) {
final String[] usage = {
"cmd3 - cmd3 parse xargs, return opt.argObjects().get(0)",
"cmd3 - cmd3 parse input.xargs, return opt.argObjects[0]",
"Usage: cmd3 [OBJECT]",
" -? --help Displays command help"
};
Expand All @@ -162,11 +169,13 @@ private Object cmd3(Builtins.CommandInput input) {

private Object help(Builtins.CommandInput input) {
final String[] usage = {
" - execute cmd subcommands",
"Usage: cmd1 [OBJECT]",
" cmd2 [OBJECT]",
" cmd3 [OBJECT]",
" help"
" - demonstrates object parameter usages. ",
" cmd3 manage correctly object parameters",
" while cmd1 & cmd2 works only with string parameters",
"Summary: " + commandInfo("cmd1").get(0),
" " + commandInfo("cmd2").get(0),
" " + commandInfo("cmd3").get(0),
" help show subcommands help"
};
Options opt = Options.compile(usage).parse(input.args());
exception = new HelpException(opt.usage());
Expand Down

0 comments on commit 9ea33be

Please sign in to comment.