View Javadoc
1   package org.argeo.cli;
2   
3   import java.io.PrintWriter;
4   import java.io.StringWriter;
5   import java.util.List;
6   import java.util.function.Function;
7   
8   import org.apache.commons.cli.HelpFormatter;
9   import org.apache.commons.cli.Options;
10  
11  /** A special command that can describe {@link DescribedCommand}. */
12  public class HelpCommand implements DescribedCommand<String> {
13  	private CommandsCli commandsCli;
14  	private CommandsCli parentCommandsCli;
15  
16  	// Help formatting
17  	private static int helpWidth = 80;
18  	private static int helpLeftPad = 4;
19  	private static int helpDescPad = 20;
20  
21  	public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) {
22  		super();
23  		this.parentCommandsCli = parentCommandsCli;
24  		this.commandsCli = commandsCli;
25  	}
26  
27  	@Override
28  	public String apply(List<String> args) {
29  		StringWriter out = new StringWriter();
30  
31  		if (args.size() == 0) {// overview
32  			printHelp(commandsCli, out);
33  		} else {
34  			String cmd = args.get(0);
35  			Function<List<String>, ?> function = commandsCli.getCommand(cmd);
36  			if (function == null)
37  				return "Command " + cmd + " not found.";
38  			Options options;
39  			String examples;
40  			DescribedCommand<?> command = null;
41  			if (function instanceof DescribedCommand) {
42  				command = (DescribedCommand<?>) function;
43  				options = command.getOptions();
44  				examples = command.getExamples();
45  			} else {
46  				options = new Options();
47  				examples = null;
48  			}
49  			String description = getShortDescription(function);
50  			String commandCall = getCommandUsage(cmd, command);
51  			HelpFormatter formatter = new HelpFormatter();
52  			formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad,
53  					helpDescPad, examples, false);
54  		}
55  		return out.toString();
56  	}
57  
58  	private static String getShortDescription(Function<List<String>, ?> function) {
59  		if (function instanceof DescribedCommand) {
60  			return ((DescribedCommand<?>) function).getDescription();
61  		} else {
62  			return function.toString();
63  		}
64  	}
65  
66  	public String getCommandUsage(String cmd, DescribedCommand<?> command) {
67  		String commandCall = getCommandCall(commandsCli) + " " + cmd;
68  		assert command != null;
69  		if (command != null && command.getUsage() != null) {
70  			commandCall = commandCall + " " + command.getUsage();
71  		}
72  		return commandCall;
73  	}
74  
75  	@Override
76  	public String getDescription() {
77  		return "Shows this help or describes a command";
78  	}
79  
80  	@Override
81  	public String getUsage() {
82  		return "[command]";
83  	}
84  
85  	public CommandsCli getParentCommandsCli() {
86  		return parentCommandsCli;
87  	}
88  
89  	protected String getCommandCall(CommandsCli commandsCli) {
90  		HelpCommand hc = commandsCli.getHelpCommand();
91  		if (hc.getParentCommandsCli() != null) {
92  			return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName();
93  		} else {
94  			return commandsCli.getCommandName();
95  		}
96  	}
97  
98  	public static void printHelp(DescribedCommand<?> command, StringWriter out) {
99  		String usage = "java " + command.getClass().getName()
100 				+ (command.getUsage() != null ? " " + command.getUsage() : "");
101 		HelpFormatter formatter = new HelpFormatter();
102 		formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
103 				helpLeftPad, helpDescPad, command.getExamples(), false);
104 
105 	}
106 
107 	public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) {
108 		DescribedCommand<?> command = (DescribedCommand<?>) commandsCli.getCommand(commandName);
109 		String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command);
110 		HelpFormatter formatter = new HelpFormatter();
111 		formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
112 				helpLeftPad, helpDescPad, command.getExamples(), false);
113 
114 	}
115 
116 	public static void printHelp(CommandsCli commandsCli, StringWriter out) {
117 		out.append(commandsCli.getDescription()).append('\n');
118 		String leftPad = spaces(helpLeftPad);
119 		for (String cmd : commandsCli.getSubCommands()) {
120 			Function<List<String>, ?> function = commandsCli.getCommand(cmd);
121 			assert function != null;
122 			out.append(leftPad);
123 			out.append(cmd);
124 			// TODO deal with long commands
125 			out.append(spaces(helpDescPad - cmd.length()));
126 			out.append(getShortDescription(function));
127 			out.append('\n');
128 		}
129 	}
130 
131 	private static String spaces(int count) {
132 		// Java 11
133 		// return " ".repeat(count);
134 		if (count <= 0)
135 			return "";
136 		else {
137 			StringBuilder sb = new StringBuilder(count);
138 			for (int i = 0; i < count; i++)
139 				sb.append(' ');
140 			return sb.toString();
141 		}
142 	}
143 }