/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.karaf.shell.impl.console.commands.help; import java.io.BufferedReader; import java.io.PrintStream; import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.felix.utils.properties.InterpolationHelper; import org.apache.karaf.shell.api.console.Command; import org.apache.karaf.shell.api.console.CommandLine; import org.apache.karaf.shell.api.console.Completer; import org.apache.karaf.shell.api.console.Parser; import org.apache.karaf.shell.api.console.Registry; import org.apache.karaf.shell.api.console.Session; import org.apache.karaf.shell.api.console.SessionFactory; import org.apache.karaf.shell.support.CommandException; import org.apache.karaf.shell.support.completers.ArgumentCommandLine; import org.apache.karaf.shell.support.completers.StringsCompleter; import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_DEFAULT; import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_RED; import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_BOLD; import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_NORMAL; public class HelpCommand implements Command { public HelpCommand(SessionFactory factory) { Registry registry = factory.getRegistry(); registry.register(this); registry.register(new SimpleHelpProvider()); registry.register(new ShellHelpProvider()); registry.register(new SingleCommandHelpProvider()); registry.register(new CommandsHelpProvider()); registry.register(new CommandListHelpProvider()); registry.register(new BundleHelpProvider()); } @Override public String getScope() { return Session.SCOPE_GLOBAL; } @Override public String getName() { return "help"; } @Override public String getDescription() { return "Displays this help or help about a command"; } @Override public Object execute(Session session, List<Object> arguments) throws Exception { if (arguments.contains("--help")) { printHelp(System.out); return null; } if (arguments.size() > 1) { String msg = COLOR_RED + "Error executing command " + INTENSITY_BOLD + getName() + INTENSITY_NORMAL + COLOR_DEFAULT + ": " + "too many arguments specified"; throw new CommandException(msg); } String path = arguments.isEmpty() ? null : arguments.get(0) == null ? null : arguments.get(0).toString(); String help = getHelp(session, path); if (help != null) { try (BufferedReader reader = new BufferedReader(new StringReader(help))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } } return null; } @Override public Completer getCompleter(final boolean scoped) { return new Completer() { @Override public int complete(Session session, CommandLine commandLine, List<String> candidates) { String[] args = commandLine.getArguments(); int argIndex = commandLine.getCursorArgumentIndex(); StringsCompleter completer = new StringsCompleter(Collections.singletonList(getName())); if (argIndex == 0) { return completer.complete(session, new ArgumentCommandLine(args[argIndex], commandLine.getArgumentPosition()), candidates); } else if (!verifyCompleter(session, completer, args[0])) { return -1; } // TODO: use CommandNamesCompleter and better completion wrt parsing etc... completer = new StringsCompleter(); for (Command command : session.getRegistry().getCommands()) { if (!Session.SCOPE_GLOBAL.equals(command.getScope())) { completer.getStrings().add(command.getScope() + ":" + command.getName()); } completer.getStrings().add(command.getName()); } completer.getStrings().add("--help"); if (argIndex == 1) { int res; if (argIndex < args.length) { res = completer.complete(session, new ArgumentCommandLine(args[argIndex], commandLine.getArgumentPosition()), candidates); } else { res = completer.complete(session, new ArgumentCommandLine("", 0), candidates); } return res + (commandLine.getBufferPosition() - commandLine.getArgumentPosition()); } else if (!verifyCompleter(session, completer, args[1])) { return -1; } return -1; } protected boolean verifyCompleter(Session session, Completer completer, String argument) { List<String> candidates = new ArrayList<String>(); return completer.complete(session, new ArgumentCommandLine(argument, argument.length()), candidates) != -1 && !candidates.isEmpty(); } }; } @Override public Parser getParser() { return null; } protected void printHelp(PrintStream out) { out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL); out.print(" "); out.println(INTENSITY_BOLD + getName() + INTENSITY_NORMAL); out.println(); out.print("\t"); out.println(getDescription()); out.println(); out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL); out.print(" "); out.println(getName() + " [options] [command]"); out.println(); out.println(INTENSITY_BOLD + "ARGUMENTS" + INTENSITY_NORMAL); out.print(" "); out.println(INTENSITY_BOLD + "command" + INTENSITY_NORMAL); out.print(" "); out.println("Command to display help for"); out.println(); out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL); out.print(" "); out.println(INTENSITY_BOLD + "--help" + INTENSITY_NORMAL); out.print(" "); out.println("Display this help message"); out.println(); } public String getHelp(final Session session, String path) { if (path == null) { path = "%root%"; } Map<String,String> props = new HashMap<String,String>(); props.put("data", "${" + path + "}"); final List<HelpProvider> providers = session.getRegistry().getServices(HelpProvider.class); InterpolationHelper.performSubstitution(props, new InterpolationHelper.SubstitutionCallback() { public String getValue(final String key) { for (HelpProvider hp : providers) { String result = hp.getHelp(session, key); if (result != null) { return removeNewLine(result); } } return null; } }); return props.get("data"); } private String removeNewLine(String help) { if (help != null && help.endsWith("\n")) { help = help.substring(0, help.length() - 1); } return help; } }