/** * Copyright (c) 2002-2010 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.shell.apps; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.neo4j.helpers.Service; import org.neo4j.shell.App; import org.neo4j.shell.AppCommandParser; import org.neo4j.shell.AppShellServer; import org.neo4j.shell.Output; import org.neo4j.shell.Session; import org.neo4j.shell.ShellException; import org.neo4j.shell.ShellServer; import org.neo4j.shell.impl.AbstractApp; import org.neo4j.shell.impl.AbstractAppServer; import org.neo4j.shell.impl.ClassLister; /** * Prints a short manual for an {@link App}. */ @Service.Implementation( App.class ) public class Man extends AbstractApp { public static final int CONSOLE_WIDTH = 80; private static Collection<String> availableCommands; public String execute( AppCommandParser parser, Session session, Output out ) throws Exception { if ( parser.arguments().size() == 0 ) { out.println( getHelpString( getServer() ) ); return null; } App app = this.getApp( parser ); out.println( "" ); for ( String line : splitDescription( fixDesciption( app.getDescription() ), CONSOLE_WIDTH ) ) { out.println( line ); } println( out, "" ); boolean hasOptions = false; for ( String option : app.getAvailableOptions() ) { hasOptions = true; String description = fixDesciption( app.getDescription( option ) ); String[] descriptionLines = splitDescription( description, CONSOLE_WIDTH ); for ( int i = 0; i < descriptionLines.length; i++ ) { String line = ""; if ( i == 0 ) { String optionPrefix = option.length() > 1 ? "--" : "-"; line = optionPrefix + option; } line += "\t "; line += descriptionLines[ i ]; println( out, line ); } } if ( hasOptions ) { println( out, "" ); } return null; } private static String[] splitDescription( String description, int maxLength ) { List<String> lines = new ArrayList<String>(); while ( description.length() > 0 ) { String line = description.substring( 0, Math.min( maxLength, description.length() ) ); int position = line.indexOf( "\n" ); if ( position > -1 ) { line = description.substring( 0, position ); lines.add( line ); description = description.substring( position ); if ( description.length() > 0 ) { description = description.substring( 1 ); } } else { position = description.length() > maxLength ? findSpaceBefore( description, maxLength ) : description.length(); line = description.substring( 0, position ); lines.add( line ); description = description.substring( position ); } } return lines.toArray( new String[lines.size()] ); } private static int findSpaceBefore( String description, int position ) { while ( !Character.isWhitespace( description.charAt( position ) ) ) { position--; } return position + 1; } private static String getShortUsageString() { return "man <command>"; } private String fixDesciption( String description ) { if ( description == null ) { description = ""; } else if ( !description.endsWith( "." ) ) { description = description + "."; } return description; } private void println( Output out, String string ) throws RemoteException { out.println( " " + string ); } private App getApp( AppCommandParser parser ) throws Exception { String appName = parser.arguments().get( 0 ); App app = this.getServer().findApp( appName ); if ( app == null ) { throw new ShellException( "No manual entry for '" + appName + "'" ); } return app; } @Override public String getDescription() { return "Display a manual for a command or a general help message.\n" + "Usage: " + getShortUsageString(); } /** * Utility method for getting a short help string for a server. Basically it * contains an introductory message and also lists all available apps for * the server. * * @param server * the server to ask for * @return the short introductory help string. */ public static String getHelpString( ShellServer server ) { return "Available commands: " + availableCommandsAsString( server ) + "\n" + "Use " + getShortUsageString() + " for info about each command."; } /** * Uses {@link ClassLister} to list apps available at the server. * * @param server * the {@link ShellServer}. * @return a list of available commands a client can execute, whre the * server is an {@link AppShellServer}. */ public static synchronized Collection<String> getAvailableCommands( ShellServer server ) { if ( availableCommands == null ) { Collection<String> list = new ArrayList<String>(); // TODO Shouldn't trust the server to be an AbstractAppServer for ( String name : ( ( AbstractAppServer ) server ) .getAllAvailableCommands() ) { list.add( name ); } availableCommands = list; } return availableCommands; } private static synchronized String availableCommandsAsString( ShellServer server ) { StringBuffer commands = new StringBuffer(); for ( String command : getAvailableCommands( server ) ) { if ( commands.length() > 0 ) { commands.append( " " ); } commands.append( command ); } return commands.toString(); } }