
org.refcodes.console.impls.ArgsParserImpl Maven / Gradle / Ivy
Show all versions of refcodes-console Show documentation
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/LICENSE-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////
package org.refcodes.console.impls;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.refcodes.console.AmbiguousArgsException;
import org.refcodes.console.ArgsParser;
import org.refcodes.console.Condition;
import org.refcodes.console.ConsoleUtility;
import org.refcodes.console.Operand;
import org.refcodes.console.ParseArgsException;
import org.refcodes.console.SuperfluousArgsException;
import org.refcodes.console.SyntaxNotation;
import org.refcodes.console.UnknownArgsException;
import org.refcodes.data.AsciiColorPaletteConsts;
import org.refcodes.data.LicenseConsts;
import org.refcodes.data.RuntimeConsts;
import org.refcodes.graphical.BoxBorderMode;
import org.refcodes.runtime.SystemUtility;
import org.refcodes.textual.AsciiArtMode;
import org.refcodes.textual.ColumnWidthType;
import org.refcodes.textual.Font;
import org.refcodes.textual.FontStyle;
import org.refcodes.textual.FontType;
import org.refcodes.textual.HorizAlignTextMode;
import org.refcodes.textual.SplitTextMode;
import org.refcodes.textual.TableBuilder;
import org.refcodes.textual.TableStyle;
import org.refcodes.textual.impls.AsciiArtBuilderImpl;
import org.refcodes.textual.impls.FontImpl;
import org.refcodes.textual.impls.HorizAlignTextBuilderImpl;
import org.refcodes.textual.impls.TableBuilderImpl;
import org.refcodes.textual.impls.TextBlockBuilderImpl;
import org.refcodes.textual.impls.TextBorderBuilderImpl;
import org.refcodes.textual.impls.TextLineBuilderImpl;
import org.refcodes.textual.impls.VerboseTextBuilderImpl;
/**
* A straightforward implementation of the {@link ArgsParser} interface. The
* constructor only provides means to set the required attributes as the
* attributes to be adjusted optionally are already sufficiently pre-configured.
* For adjusting them, a flavor of the builder pattern is provided with which
* you can easily chain the configuration of this instance; as them methods
* return the instance of this class being configured. This helps to prevent the
* telescoping constructor anti-pattern.
*
* The {@link SyntaxNotation} is pre-set with the
* {@link SyntaxNotation#REFCODES} notation.
*
* The console width id pre-configured with the console's width as determined by
* the {@link SystemUtility#getConsoleWidth()}.
*
* The standard out {@link PrintStream} is pre-configured with the
* {@link System#out} {@link PrintStream}.
*
* The newline characters to be used for line breaks is "\r\n" on Windows
* machines and "\"n" on all other machines as of the
* {@link SystemUtility#getLineBreak()}.
*
* @see "http://en.wikipedia.org/wiki/Builder_pattern"
*
*/
public class ArgsParserImpl implements ArgsParser {
// /////////////////////////////////////////////////////////////////////////
// STATIC:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// CONSTANTS:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private Font _bannerFont = new FontImpl( FontType.DIALOG, FontStyle.PLAIN, 12 );
private char[] _bannerFontPalette = AsciiColorPaletteConsts.HALFTONE_GRAY;
private char _separatorChar = '-';
private Condition _rootCondition;
private SyntaxNotation _syntaxNotation = SyntaxNotation.REFCODES;
private PrintStream _standardOut = System.out;
private int _consoleWidth;
private int _maxConsoleWidth = -1;
private String _lineBreak = SystemUtility.getLineBreak();
private String _title = null;
private String _name = "foobar";
private String _description = "See the syntax declaration for usage, see the descriptions for the short- and the long-options. Option arguments are noted in angle brackets.";
private String _usageLabel = "Usage";
private String _licenseNote = LicenseConsts.LICENSE_NOTE;
private String _copyrightNote = LicenseConsts.COPYRIGHT_NOTE;
private PrintStream _errorOut = System.err;;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Constructs the {@link ArgsParser} instance with the given root
* {@link Condition} and the default {@link SyntaxNotation#REFCODES}.
*
* The constructor only provides means to set the required attributes as the
* attributes to be adjusted optionally are already sufficiently
* pre-configured. For adjusting them, a flavor of the builder pattern is
* provided with which you can easily chain the configuration of this
* instance; as them methods return the instance of this class being
* configured.
*
* @param aRootCondition The root condition being the node from which
* parsing the command line arguments starts.
*/
public ArgsParserImpl( Condition aRootCondition ) {
_rootCondition = aRootCondition;
setConsoleWidth( SystemUtility.getConsoleWidth() );
}
@Override
public void setSyntaxNotation( SyntaxNotation aSyntaxNotation ) {
_syntaxNotation = aSyntaxNotation;
}
@Override
public void setStandardOut( PrintStream aStandardOut ) {
_standardOut = aStandardOut;
}
@Override
public void setErrorOut( PrintStream aErrorOut ) {
_errorOut = aErrorOut;
}
@Override
public void setConsoleWidth( int aConsoleWidth ) {
if ( aConsoleWidth == -1 ) {
aConsoleWidth = SystemUtility.getConsoleWidth();
if ( aConsoleWidth < RuntimeConsts.NORM_CONSOLE_WIDTH ) {
aConsoleWidth = RuntimeConsts.NORM_CONSOLE_WIDTH;
}
}
_consoleWidth = _maxConsoleWidth != -1 ? (_maxConsoleWidth < aConsoleWidth ? _maxConsoleWidth : aConsoleWidth) : aConsoleWidth;
}
@Override
public void setLineBreak( String aLineBreak ) {
if ( aLineBreak == null ) {
aLineBreak = SystemUtility.getLineBreak();
}
_lineBreak = aLineBreak;
}
@Override
public void setDescription( String aDescription ) {
_description = aDescription;
}
@Override
public void setName( String aName ) {
_name = aName;
}
@Override
public void setLicenseNote( String aLicenseNote ) {
_licenseNote = aLicenseNote;
}
@Override
public void setUsageLabel( String aUsageLabel ) {
_usageLabel = aUsageLabel;
}
@Override
public void setCopyrightNote( String aCopyrightNote ) {
_copyrightNote = aCopyrightNote;
}
@Override
public void setSeparatorChar( char aSeparatorChar ) {
_separatorChar = aSeparatorChar;
}
@Override
public void setBannerFont( Font aBannerFont ) {
_bannerFont = aBannerFont;
}
@Override
public void setBannerFontPalette( char[] aColorPalette ) {
_bannerFontPalette = aColorPalette;
}
@Override
public void setTitle( String aTitle ) {
_title = aTitle;
}
@Override
public void setMaxConsoleWidth( int aMaxConsoleWidth ) {
_maxConsoleWidth = aMaxConsoleWidth;
_consoleWidth = _maxConsoleWidth != -1 ? (_maxConsoleWidth < _consoleWidth ? _maxConsoleWidth : _consoleWidth) : _consoleWidth;
}
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
@Override
public void printLicenseNote() {
String[] theLines = new TextBlockBuilderImpl().withText( _licenseNote ).withColumnWidth( _consoleWidth ).withSplitTextMode( SplitTextMode.AT_SPACE ).toStrings();
theLines = new HorizAlignTextBuilderImpl().withHorizAlignTextMode( HorizAlignTextMode.CENTER ).withText( theLines ).withColumnWidth( _consoleWidth ).withFillChar( ' ' ).toStrings();
_standardOut.println( fromTextBlock( theLines, _lineBreak ) );
}
@Override
public void printCopyrightNote() {
String[] theLines = new TextBlockBuilderImpl().withText( _copyrightNote ).withColumnWidth( _consoleWidth ).withSplitTextMode( SplitTextMode.AT_SPACE ).toStrings();
theLines = new HorizAlignTextBuilderImpl().withHorizAlignTextMode( HorizAlignTextMode.CENTER ).withText( theLines ).withColumnWidth( _consoleWidth ).withFillChar( ' ' ).toStrings();
_standardOut.println( fromTextBlock( theLines, _lineBreak ) );
}
@Override
public List extends Operand>> evalArgs( String[] aArgs ) throws UnknownArgsException, AmbiguousArgsException, SuperfluousArgsException, ParseArgsException {
List extends Operand>> theOperands = _rootCondition.parseArgs( aArgs );
String[] theSuperflousArgs = ConsoleUtility.toDiff( aArgs, theOperands );
if ( theSuperflousArgs != null && theSuperflousArgs.length > 0 ) { throw new SuperfluousArgsException( theSuperflousArgs, "Superflous command arguments " + new VerboseTextBuilderImpl().withElements( theSuperflousArgs ).toString() + " were provided but not evaluatable (supported)." ); }
return theOperands;
}
@Override
public void printHelp() {
printBanner();
printLicenseNote();
printSeparatorLn();
printUsage();
printSeparatorLn();
printDescription();
printSeparatorLn();
printOptions();
printSeparatorLn();
printCopyrightNote();
printSeparatorLn();
}
@Override
public void printUsage() {
// @formatter:off
// String theLine = _usageLabel + ": ";
// String[] theLines = toTextBlock( _name + " " + _rootCondition.parseSyntax( _syntaxNotation ), _consoleWidth - theLine.length(), TextSplitMode.AT_SPACE );
// theLines[0] = theLine + theLines[0];
// if ( theLines.length > 0 ) {
// theLine = DrawTextUtility.toLine( theLine.length(), ' ' );
// for ( int i = 1; i < theLines.length; i++ ) {
// theLines[i] = theLine + theLines[i];
// }
// }
// String theSyntax = fromTextBlock( theLines, _lineBreak );
// @formatter:on
String theSyntax = _usageLabel + ": " + _name + " " + _rootCondition.parseSyntax( _syntaxNotation );
_standardOut.println( theSyntax );
}
@Override
public void printDescription() {
String[] theLines = new TextBlockBuilderImpl().withText( _description ).withColumnWidth( _consoleWidth ).withSplitTextMode( SplitTextMode.AT_SPACE ).toStrings();
_standardOut.println( fromTextBlock( theLines, _lineBreak ) );
}
@Override
public void printLn( String aLine ) {
String[] theLines = new TextBlockBuilderImpl().withText( aLine ).withColumnWidth( _consoleWidth ).withSplitTextMode( SplitTextMode.AT_SPACE ).toStrings();
_standardOut.println( fromTextBlock( theLines, _lineBreak ) );
}
@Override
public void errorLn( String aLine ) {
String[] theLines = new TextBlockBuilderImpl().withText( aLine ).withColumnWidth( _consoleWidth ).withSplitTextMode( SplitTextMode.AT_SPACE ).toStrings();
_errorOut.println( fromTextBlock( theLines, _lineBreak ) );
}
@Override
public void printLn() {
_standardOut.println();
}
@Override
public void printSeparatorLn() {
_standardOut.println( new TextLineBuilderImpl().withColumnWidth( _consoleWidth ).withLineChar( _separatorChar ).toString() );
}
@Override
public void printBanner() {
int theBannerWidth = _consoleWidth - 4;
String[] theCanvas = new AsciiArtBuilderImpl().withText( _title != null ? _title : _name ).withFont( _bannerFont ).withAsciiColors( _bannerFontPalette ).withColumnWidth( theBannerWidth ).withAsciiArtMode( AsciiArtMode.NORMAL ).toStrings();
theCanvas = new HorizAlignTextBuilderImpl().withHorizAlignTextMode( HorizAlignTextMode.CENTER ).withText( theCanvas ).withColumnWidth( theBannerWidth ).withFillChar( ' ' ).toStrings();
theCanvas = new TextBorderBuilderImpl().withBoxBorderMode( BoxBorderMode.ALL ).withText( theCanvas ).withBorderWidth( 1 ).withBorderChar( ' ' ).toStrings();
theCanvas = new TextBorderBuilderImpl().withText( theCanvas ).withTableStyle( TableStyle.DOUBLE ).withBoxBorderMode( BoxBorderMode.ALL ).toStrings();
String theBanner = fromTextBlock( theCanvas, _lineBreak );
_standardOut.println( theBanner );
}
@Override
public void printOptions() {
// @formatter:off
// List extends Operand>> theOperands = _rootCondition.toOperands();
// List theOptionStrs = new ArrayList();
// for ( Operand> eOperand : theOperands ) {
// theOptionStrs.add( new String[] {
// ConsoleUtility.toSpec( eOperand ), eOperand.getDescription()
// } );
// }
// int theMaxLength = 0;
// for ( String[] eOptionStrs : theOptionStrs ) {
// if ( eOptionStrs[0].length() > theMaxLength ) {
// theMaxLength = eOptionStrs[0].length();
// }
// }
// String theColon = ": ";
// theMaxLength += theColon.length();
// String eLine;
// String[] eLines;
// for ( String[] eOptionStrs : theOptionStrs ) {
//
// eLine = AlignTextUtility.toAlignRight( eOptionStrs[0], theMaxLength, ' ' ) + theColon;
// eLines = toTextBlock( eOptionStrs[1], (_consoleWidth - theMaxLength) - theColon.length(), TextAlignMode.LEFT, TextSplitMode.AT_SPACE );
// eLines[0] = eLine + eLines[0];
// if ( eLines.length > 0 ) {
// eLine = DrawTextUtility.toLine( eLine.length(), ' ' );
// for ( int i = 1; i < eLines.length; i++ ) {
// eLines[i] = eLine + eLines[i];
// }
// }
// TextOutputUtility.printLines( eLines, _standardOut );
// }
// @formatter:on
List extends Operand>> theOperands = _rootCondition.toOperands();
List theOptArgs = new ArrayList();
int theMaxLength = 0;
String eOpt;
for ( Operand> eOperand : theOperands ) {
eOpt = ConsoleUtility.toSpec( eOperand ) + ":";
theOptArgs.add( new String[] {
eOpt, eOperand.getDescription()
} );
if ( eOpt.length() > theMaxLength ) theMaxLength = eOpt.length();
}
TableBuilder theOptTable = new TableBuilderImpl().withTableStyle( TableStyle.BLANK ).withRowWidth( _consoleWidth ).withPrintStream( _standardOut );
theOptTable.addColumn().withColumnHorizAlignTextMode( HorizAlignTextMode.RIGHT ).withColumnWidth( theMaxLength, ColumnWidthType.ABSOLUTE ).withLeftBorder( false ).withRightBorder( false );
theOptTable.addColumn().withColumnHorizAlignTextMode( HorizAlignTextMode.LEFT ).withLeftBorder( false ).withRightBorder( false ).withColumnSplitTextMode( SplitTextMode.AT_SPACE );
for ( String[] eOptArg : theOptArgs ) {
theOptTable.printRowContinue( eOptArg );
}
}
@Override
public Condition getRootCondition() {
return _rootCondition;
}
@Override
public void reset() {
if ( _rootCondition != null ) {
_rootCondition.reset();
}
}
// /////////////////////////////////////////////////////////////////////////
// HOOKS:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
private static String fromTextBlock( String[] aTextBlock, String aDelimeter ) {
StringBuilder theBuilder = new StringBuilder();
for ( String eString : aTextBlock ) {
if ( aDelimeter != null && aDelimeter.length() != 0 ) {
if ( theBuilder.length() > 0 ) {
theBuilder.append( aDelimeter );
}
}
theBuilder.append( eString );
}
return theBuilder.toString();
}
// /////////////////////////////////////////////////////////////////////////
// INNER CLASSES:
// /////////////////////////////////////////////////////////////////////////
}