diff --git a/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java b/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java index 8f79d34b5..3ce684f0c 100755 --- a/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java +++ b/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java @@ -1,7 +1,9 @@ package org.broadinstitute.sting.gatk; import org.broadinstitute.sting.utils.GATKErrorReport; +import org.broadinstitute.sting.utils.TextFormattingUtils; import org.broadinstitute.sting.utils.cmdLine.*; +import org.broadinstitute.sting.gatk.walkers.Walker; import java.io.PrintStream; import java.util.*; @@ -112,38 +114,73 @@ public class CommandLineGATK extends CommandLineExecutable { * @return A string summarizing the walkers available in this distribution. */ private String getAdditionalHelp() { - // Get the list of walker names from the walker manager. - Set walkerNames = GATKEngine.getWalkerNames(); - // Sort the list of walker names. - walkerNames = new TreeSet(walkerNames); + //HelpFormatter.LINE_WIDTH; - // Construct a help string to output available walkers. + final int PACKAGE_INDENT = 1; + final int WALKER_INDENT = 3; + final String FIELD_SEPARATOR = " | "; + + // Construct a help string to output available walkers. StringBuilder additionalHelp = new StringBuilder(); Formatter formatter = new Formatter(additionalHelp); - formatter.format("Available analyses:%n"); + formatter.format("Available analyses:%n%n"); - // Compute the max size of any walker name - int maxNameLength = 0; - for (String walkerName : walkerNames) { - if (maxNameLength < walkerName.length()) - maxNameLength = walkerName.length(); + // Get the list of walker names from the walker manager. + WalkerManager walkerManager = GATKEngine.getWalkerManager(); + Map>> walkers = walkerManager.getWalkerNamesByPackage(); + + int longestPackageName = 0; + int longestWalkerName = 0; + for(Map.Entry>> walkersByPackage: walkers.entrySet()) { + longestPackageName = Math.max(longestPackageName,walkerManager.getPackageDisplayName(walkersByPackage.getKey()).length()); + for(Class walkerType: walkersByPackage.getValue()) + longestWalkerName = Math.max(longestWalkerName,walkerManager.getName(walkerType).length()); } - final int fieldWidth = maxNameLength + HelpFormatter.FIELD_SEPARATION_WIDTH; - final int walkersPerLine = Math.min(HelpFormatter.LINE_WIDTH / fieldWidth, 4); - final int columnSpacing = Math.max((HelpFormatter.LINE_WIDTH - (fieldWidth * walkersPerLine)) / walkersPerLine, 1); + final int headerWidth = Math.max(longestPackageName+PACKAGE_INDENT,longestWalkerName+WALKER_INDENT); - int currentWalkerName = 0; - for (String walkerName : walkerNames) { - formatter.format("%-" + HelpFormatter.FIELD_SEPARATION_WIDTH + "s" + - "%-" + fieldWidth + "s" + - "%-" + columnSpacing + "s", "", walkerName, ""); - if (++currentWalkerName % walkersPerLine == 0) - formatter.format("%n"); + // Sort the list of walker names. + walkers = new TreeMap>>(walkers); + + for(String packageName: walkers.keySet()) { + String packageDisplayName = walkerManager.getPackageDisplayName(packageName); + String packageHelpText = walkerManager.getPackageHelpText(packageName); + printDescriptorLine(formatter,PACKAGE_INDENT,packageDisplayName,headerWidth,FIELD_SEPARATOR,packageHelpText, TextFormattingUtils.DEFAULT_LINE_WIDTH); + + for(Class walkerType: walkers.get(packageName)) { + String walkerName = walkerManager.getName(walkerType); + String walkerHelpText = walkerManager.getWalkerHelpText(walkerType); + printDescriptorLine(formatter,WALKER_INDENT,walkerName,headerWidth,FIELD_SEPARATOR,walkerHelpText, TextFormattingUtils.DEFAULT_LINE_WIDTH); + } + + // Print a blank line between sets of walkers. + printDescriptorLine(formatter,0,"",headerWidth,FIELD_SEPARATOR,"", TextFormattingUtils.DEFAULT_LINE_WIDTH); } return additionalHelp.toString(); } + + private void printDescriptorLine(Formatter formatter, + int headerIndentWidth, + String header, + int headerWidth, + String fieldSeparator, + String description, + int lineWidth) { + final int headerPaddingWidth = headerWidth - header.length() - headerIndentWidth; + final int descriptionWidth = lineWidth - fieldSeparator.length() - headerWidth; + List wordWrappedText = TextFormattingUtils.wordWrap(description,descriptionWidth); + + String headerIndentFormatString = headerIndentWidth > 0 ? "%" + headerIndentWidth + "s" : "%s"; + String headerPaddingFormatString = headerPaddingWidth > 0 ? "%" + headerPaddingWidth + "s" : "%s"; + String headerWidthFormatString = headerWidth > 0 ? "%" + headerWidth + "s" : "%s"; + + // Output description line. + formatter.format(headerIndentFormatString + "%s" + headerPaddingFormatString + "%s%s%n", + "", header, "", fieldSeparator, wordWrappedText.size()>0?wordWrappedText.get(0):""); + for(int i = 1; i < wordWrappedText.size(); i++) + formatter.format(headerWidthFormatString + "%s%s%n", "", fieldSeparator, wordWrappedText.get(i)); + } } diff --git a/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisEngine.java b/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisEngine.java index 910d0914f..3243985a7 100755 --- a/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisEngine.java +++ b/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisEngine.java @@ -175,15 +175,6 @@ public class GenomeAnalysisEngine { outputs.add(stub); } - /** - * Gets a set of the names of all walkers that the GATK has discovered. - * - * @return A set of the names of all discovered walkers. - */ - public Set getWalkerNames() { - return walkerManager.getWalkerNames(); - } - /** * Retrieves an instance of the walker based on the walker name. * @@ -219,6 +210,14 @@ public class GenomeAnalysisEngine { return Collections.unmodifiableSet(filters); } + /** + * Allow subclasses and others within this package direct access to the walker manager. + * @return The walker manager used by this package. + */ + protected WalkerManager getWalkerManager() { + return walkerManager; + } + private void initializeDataSources(Walker my_walker, Collection filters, GATKArgumentCollection argCollection) { validateSuppliedReadsAgainstWalker(my_walker, argCollection); logger.info("Strictness is " + argCollection.strictnessLevel); diff --git a/java/src/org/broadinstitute/sting/gatk/WalkerManager.java b/java/src/org/broadinstitute/sting/gatk/WalkerManager.java index e8d81210d..a5e134d05 100755 --- a/java/src/org/broadinstitute/sting/gatk/WalkerManager.java +++ b/java/src/org/broadinstitute/sting/gatk/WalkerManager.java @@ -26,6 +26,8 @@ package org.broadinstitute.sting.gatk; import java.util.*; +import java.io.InputStream; +import java.io.IOException; import org.broadinstitute.sting.gatk.walkers.*; import org.broadinstitute.sting.gatk.refdata.ReferenceOrderedDatum; @@ -50,16 +52,70 @@ public class WalkerManager extends PluginManager { */ private static Logger logger = Logger.getLogger(WalkerManager.class); + /** + * A collection of help text for walkers and their enclosing packages. + */ + private Properties helpText = new Properties(); + public WalkerManager() { super(Walker.class,"walker","Walker"); + InputStream helpSourceFile = getClass().getClassLoader().getResourceAsStream("help.properties"); + if(helpSourceFile != null) { + try { + helpText.load(helpSourceFile); + } + catch(IOException ex) { + throw new StingException("Unable to process help data"); + } + } } /** - * Get the list of walkers currently available to the GATK. + * Get the list of walkers currently available to the GATK, organized + * by package. * @return Names of currently available walkers. */ - public Set getWalkerNames() { - return Collections.unmodifiableSet( pluginsByName.keySet() ); + public Map>> getWalkerNamesByPackage() { + Map>> walkersByPackage = new HashMap>>(); + for(Class walker: pluginsByName.values()) { + String walkerPackage = walker.getPackage().getName(); + if(!walkersByPackage.containsKey(walkerPackage)) + walkersByPackage.put(walkerPackage,new ArrayList>()); + walkersByPackage.get(walkerPackage).add(walker); + } + return Collections.unmodifiableMap(walkersByPackage); + } + + /** + * Gets the display name for a given package. + * @param packageName Fully qualified package name. + * @return A suitable display name for the package. + */ + public String getPackageDisplayName(String packageName) { + return packageName.substring(packageName.lastIndexOf('.')+1); + } + + /** + * Gets the help text associated with a given package name. + * @param packageName Package for which to search for help text. + * @return Package help text, or "" if none exists. + */ + public String getPackageHelpText(String packageName) { + if(!helpText.containsKey(packageName)) + return ""; + return helpText.getProperty(packageName); + } + + /** + * Gets the help text associated with a given walker type. + * @param walkerType Type of walker for which to search for help text. + * @return Package help text, or "" if none exists. + */ + public String getWalkerHelpText(Class walkerType) { + String walkerName = walkerType.getName(); + if(!helpText.containsKey(walkerName)) + return ""; + return helpText.getProperty(walkerName); } /** diff --git a/java/src/org/broadinstitute/sting/utils/TextFormattingUtils.java b/java/src/org/broadinstitute/sting/utils/TextFormattingUtils.java new file mode 100644 index 000000000..fa6d24776 --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/TextFormattingUtils.java @@ -0,0 +1,43 @@ +package org.broadinstitute.sting.utils; + +import java.util.List; +import java.util.ArrayList; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * Common utilities for dealing with strings. + * + * @author mhanna + * @version 0.1 + */ +public class TextFormattingUtils { + /** + * The default line width, for GATK output written to the screen. + */ + public static final int DEFAULT_LINE_WIDTH = 100; + + /** + * Simple implementation of word-wrap for a line of text. Idea and + * regexp shamelessly stolen from http://joust.kano.net/weblog/archives/000060.html. + * Regexp can probably be simplified for our application. + * @param text Text to wrap. + * @param width Maximum line width. + * @return A list of word-wrapped lines. + */ + public static List wordWrap( String text, int width ) { + Pattern wrapper = Pattern.compile( String.format(".{0,%d}(?:\\S(?: |$)|$)", width-1) ); + Matcher matcher = wrapper.matcher( text ); + + List wrapped = new ArrayList(); + while( matcher.find() ) { + // Regular expression is supersensitive to whitespace. + // Assert that content is present before adding the line. + String line = matcher.group().trim(); + if( line.length() > 0 ) + wrapped.add( matcher.group() ); + } + return wrapped; + } + +} diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java b/java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java index 7b9cb51f5..b6f474fe7 100755 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java @@ -1,5 +1,7 @@ package org.broadinstitute.sting.utils.cmdLine; +import org.broadinstitute.sting.utils.TextFormattingUtils; + import java.util.Formatter; import java.util.List; import java.util.ArrayList; @@ -7,8 +9,6 @@ import java.util.Iterator; import java.util.Comparator; import java.util.Collection; import java.util.Collections; -import java.util.regex.Pattern; -import java.util.regex.Matcher; /** * User: hanna * Date: May 6, 2009 @@ -27,10 +27,6 @@ import java.util.regex.Matcher; */ public class HelpFormatter { - /** - * Target this line width. - */ - public static final int LINE_WIDTH = 100; public static final int FIELD_SEPARATION_WIDTH = 3; /** @@ -76,7 +72,7 @@ public class HelpFormatter { } // Word wrap the synopsis. - List wrappedSynopsis = wordWrap( lineBuilder.toString(), LINE_WIDTH ); + List wrappedSynopsis = TextFormattingUtils.wordWrap( lineBuilder.toString(), TextFormattingUtils.DEFAULT_LINE_WIDTH ); String header = "usage: "; int headerLength = header.length(); @@ -119,12 +115,12 @@ public class HelpFormatter { // Try to fit the entire argument definition across the screen, but impose an arbitrary cap of 3/4 * // LINE_WIDTH in case the length of the arguments gets out of control. - int argWidth = Math.min( findLongestArgumentCallingInfo(argumentDefinitions), (LINE_WIDTH*3)/4 - FIELD_SEPARATION_WIDTH ); - int docWidth = LINE_WIDTH - argWidth - FIELD_SEPARATION_WIDTH; + int argWidth = Math.min( findLongestArgumentCallingInfo(argumentDefinitions), (TextFormattingUtils.DEFAULT_LINE_WIDTH*3)/4 - FIELD_SEPARATION_WIDTH ); + int docWidth = TextFormattingUtils.DEFAULT_LINE_WIDTH - argWidth - FIELD_SEPARATION_WIDTH; for( ArgumentDefinition argumentDefinition: argumentDefinitions ) { - Iterator wordWrappedArgs = wordWrap( getArgumentCallingInfo(argumentDefinition), argWidth ).iterator(); - Iterator wordWrappedDoc = wordWrap( argumentDefinition.doc, docWidth ).iterator(); + Iterator wordWrappedArgs = TextFormattingUtils.wordWrap( getArgumentCallingInfo(argumentDefinition), argWidth ).iterator(); + Iterator wordWrappedDoc = TextFormattingUtils.wordWrap( argumentDefinition.doc, docWidth ).iterator(); while( wordWrappedArgs.hasNext() || wordWrappedDoc.hasNext() ) { String arg = wordWrappedArgs.hasNext() ? wordWrappedArgs.next() : ""; @@ -173,29 +169,6 @@ public class HelpFormatter { return longest; } - /** - * Simple implementation of word-wrap for a line of text. Idea and - * regexp shamelessly stolen from http://joust.kano.net/weblog/archives/000060.html. - * Regexp can probably be simplified for our application. - * @param text Text to wrap. - * @param width Maximum line width. - * @return A list of word-wrapped lines. - */ - private List wordWrap( String text, int width ) { - Pattern wrapper = Pattern.compile( String.format(".{0,%d}(?:\\S(?: |$)|$)", width-1) ); - Matcher matcher = wrapper.matcher( text ); - - List wrapped = new ArrayList(); - while( matcher.find() ) { - // Regular expression is supersensitive to whitespace. - // Assert that content is present before adding the line. - String line = matcher.group().trim(); - if( line.length() > 0 ) - wrapped.add( matcher.group() ); - } - return wrapped; - } - /** * Extract the argument definition groups from the argument definitions and arrange them appropriately. * For help, we want the arguments sorted as they are declared in the class. However, required arguments diff --git a/java/src/org/broadinstitute/sting/utils/doc/HelpExtractorDoclet.java b/java/src/org/broadinstitute/sting/utils/doc/HelpExtractorDoclet.java index 354cdaa5c..0db041617 100644 --- a/java/src/org/broadinstitute/sting/utils/doc/HelpExtractorDoclet.java +++ b/java/src/org/broadinstitute/sting/utils/doc/HelpExtractorDoclet.java @@ -22,6 +22,7 @@ public class HelpExtractorDoclet { * Extracts the contents of certain types of javadoc and adds them to an XML file. * @param rootDoc The documentation root. * @return Whether the JavaDoc run succeeded. + * @throws FileNotFoundException if output can't be written. */ public static boolean start(RootDoc rootDoc) throws FileNotFoundException { PrintStream out = System.out; @@ -56,9 +57,9 @@ public class HelpExtractorDoclet { } /** - * Validate the given options against - * @param option - * @return + * Validate the given options against options supported by this doclet. + * @param option Option to validate. + * @return Number of potential parameters; 0 if not supported. */ public static int optionLength(String option) { if(option.equals("-out")) {