package act.cli.builtin;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import act.cli.CliContext;
import act.cli.CliDispatcher;
import act.cli.util.CommandLineParser;
import act.handler.CliHandler;
import act.handler.CliHandlerBase;
import org.osgl.util.C;
import org.osgl.util.S;
import java.util.List;
import static org.osgl.Osgl.T2;
public class Help extends CliHandlerBase {
public static final Help INSTANCE = new Help();
private static int maxWidth = 0;
private Help() {}
@Override
public void handle(CliContext context) {
List<String> args = context.arguments();
String command = null;
if (args.size() > 0) {
command = args.get(0);
if (showHelp(command, context)) {
return;
}
}
CommandLineParser parser = context.commandLine();
boolean sys = parser.getBoolean("-s", "--system");
boolean app = parser.getBoolean("-a", "--app");
if (!sys && !app) {
sys = true;
app = true;
}
CliDispatcher dispatcher = context.app().cliDispatcher();
List<String> sysCommands = dispatcher.commands(true, false);
List<String> appCommands = dispatcher.commands(false, true);
int maxLen;
if (sys && !app) {
maxLen = calMaxCmdLen(sysCommands);
} else if (app && !sys) {
maxLen = calMaxCmdLen(appCommands);
} else {
maxLen = calMaxCmdLen(C.list(sysCommands).append(appCommands));
}
String fmt = "%-" + (maxLen + 4) + "s - %s";
if (sys) {
list(command, "System commands", fmt, sysCommands, dispatcher, context);
}
if (app) {
if (sys) {
context.println("");
}
list(command, "Application commands", fmt, appCommands, dispatcher, context);
}
}
private void list(String search, String label, String fmt, List<String> commands, CliDispatcher dispatcher, CliContext context) {
List<String> lines = C.newList();
boolean noSearch = S.blank(search);
if (noSearch) {
lines.add(label.toUpperCase());
lines.add("");
}
for (String cmd : commands) {
CliHandler handler = dispatcher.handler(cmd);
T2<String, String> commandLine = handler.commandLine();
if (noSearch || commandLine._1.contains(search)) {
lines.add(S.fmt(fmt, cmd, commandLine._2));
}
}
context.println(S.join("\n", lines));
}
private int calMaxCmdLen(List<String> commands) {
int max = 0;
for (String c : commands) {
max = Math.max(max, c.length());
}
return max;
}
public boolean showHelp(String command, CliContext context) {
CliDispatcher dispatcher = context.app().cliDispatcher();
CliHandler handler = dispatcher.handler(command);
if (null == handler) {
// context.println("Unrecongized command: %s", command);
return false;
}
List<String> lines = C.newList();
List<String> names = dispatcher.names(handler);
T2<String, String> commandLine = handler.commandLine();
lines.add("Usage: " + names.get(0));
lines.add(commandLine._2);
String summary = handler.summary();
if (S.notBlank(summary)) {
lines.add("");
lines.add(summary);
}
List<T2<String, String>> options = handler.options();
if (!options.isEmpty()) {
lines.add("");
lines.add("Options:");
int maxLen = 0;
for (T2<String, String> t2: options) {
maxLen = Math.max(maxLen, t2._1.length());
}
String fmt = " %-" + (maxLen + 4) + "s %s";
for (T2<String, String> t2: options) {
lines.add(S.fmt(fmt, t2._1, t2._2));
}
}
if (names.size() > 1) {
lines.add("");
lines.add("Aliases: " + S.join(", ", C.list(names).tail()));
}
List<String> shortCuts = dispatcher.shortCuts(handler);
if (shortCuts.size() > 0) {
lines.add("");
lines.add("Shortcuts: " + S.join(", ", shortCuts));
}
context.println(S.join("\n", lines));
return true;
}
@Override
public T2<String, String> commandLine() {
return T2("help [options] [command]", "show help information");
}
@Override
public String summary() {
return "display information about a command if COMMAND is specified. " +
"Otherwise the list of help topics is printed. \n Note when " +
"COMMAND is specified, OPTIONS are ignored";
}
@Override
public List<T2<String, String>> options() {
List<T2<String, String>> retList = C.newList();
retList.add(T2("-s --system", "list system commands"));
retList.add(T2("-a --app", "list application commands"));
return retList;
}
private Object readResolve() {
return INSTANCE;
}
public static void updateMaxWidth(int width) {
maxWidth = Math.max(maxWidth, width);
}
}