From 5f7ec29cba16076f8819f5e0a409625ce481588d Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 7 Jan 2016 00:39:27 +0100 Subject: [PATCH 001/115] fixed git repo --- .gitignore | 11 ++ build.gradle | 27 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52271 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++++++++++++++ gradlew.bat | 90 ++++++++++ settings.gradle | 2 + .../java/de/codeshelf/consoleui/Basic.java | 113 ++++++++++++ .../elements/AbstractPromptableElement.java | 24 +++ .../consoleui/elements/Checkbox.java | 27 +++ .../consoleui/elements/InputValue.java | 54 ++++++ .../consoleui/elements/ListChoice.java | 27 +++ .../elements/PromptableElementIF.java | 8 + .../elements/items/CheckboxItemIF.java | 8 + .../elements/items/ConsoleUIItemIF.java | 9 + .../consoleui/elements/items/ListItemIF.java | 8 + .../elements/items/impl/CheckboxItem.java | 89 ++++++++++ .../items/impl/CheckboxItemBuilder.java | 63 +++++++ .../elements/items/impl/ListItem.java | 41 +++++ .../elements/items/impl/ListItemBuilder.java | 37 ++++ .../elements/items/impl/Message.java | 17 ++ .../elements/items/impl/Separator.java | 28 +++ .../consoleui/prompt/AbstractPrompt.java | 24 +++ .../consoleui/prompt/InputPrompt.java | 57 ++++++ .../consoleui/prompt/ListPrompt.java | 132 ++++++++++++++ .../codeshelf/consoleui/prompt/PromptIF.java | 14 ++ .../prompt/reader/ConsoleReaderImpl.java | 92 ++++++++++ .../consoleui/prompt/reader/ReaderIF.java | 65 +++++++ .../prompt/renderer/CUIRenderer.java | 88 ++++++++++ .../prompt/renderer/CheckboxItemRenderer.java | 8 + .../prompt/renderer/ListItemRenderer.java | 8 + .../codeshelf/consoleui/util/BuilderIF.java | 9 + .../consoleui/prompt/CheckboxPromptTest.java | 59 +++++++ 33 files changed, 1409 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/de/codeshelf/consoleui/Basic.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/Checkbox.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/InputValue.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/ListChoice.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java create mode 100644 src/main/java/de/codeshelf/consoleui/util/BuilderIF.java create mode 100644 src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3812bf94c --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/build +/bin +/.settings +/.gradle +/.classpath +/.project +/.idea +*.ipr +*.iws +/out +*iml diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..a32b61a2b --- /dev/null +++ b/build.gradle @@ -0,0 +1,27 @@ +group 'ConsoleUI' +version '1.0-SNAPSHOT' + +apply plugin: 'java' +apply plugin: 'idea' + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.11' + compile 'org.fusesource.jansi:jansi:1.11' + compile 'jline:jline:2.13' +} + + +jar { + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + + manifest { + attributes 'Implementation-Title': 'ConsoleUI', + 'Implementation-Version': version, + 'Main-Class': 'de.codeshelf.consoleui.Basic' + + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..30d399d8d2bf522ff5de94bf434a7cc43a9a74b5 GIT binary patch literal 52271 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 p \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..aec99730b --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..9222ea948 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'consoleui' + diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java new file mode 100644 index 000000000..38facc755 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -0,0 +1,113 @@ +package de.codeshelf.consoleui; + +import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.InputValue; +import de.codeshelf.consoleui.elements.ListChoice; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ListItemIF; +import de.codeshelf.consoleui.elements.items.impl.*; +import de.codeshelf.consoleui.prompt.CheckboxPrompt; +import de.codeshelf.consoleui.prompt.InputPrompt; +import de.codeshelf.consoleui.prompt.ListPrompt; +import jline.TerminalFactory; +import jline.console.ConsoleReader; +import jline.console.Operation; +import jline.console.completer.FileNameCompleter; +import jline.console.completer.StringsCompleter; +import org.fusesource.jansi.AnsiConsole; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: andy + * Date: 29.11.15 + */ +public class Basic { + + public static void main(String[] args) { + AnsiConsole.systemInstall(); + System.out.println(ansi().eraseScreen().render("@|red,italic Hello|@ @|green World|@\n@|blue no text|@")); + + + try { + checkBoxDemo(); + listChoiceDemo(); + inputDemo(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + TerminalFactory.get().restore(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + + private static void listChoiceDemo() throws IOException { + ListPrompt listPrompt = new ListPrompt(); + List list= new ArrayList(); + + ListItemBuilder listItemBuilder = ListItemBuilder.create(); + list.add(new ListItem("One")); + list.add(new ListItem("Two")); + list.add(listItemBuilder.name("3").text("Three").build()); + list.add(new Separator("some extra items")); + list.add(new ListItem("Four")); + list.add(new Separator()); + list.add(listItemBuilder.text("Five").build()); + ListChoice listChoice = new ListChoice("my first list choice", null, list); + LinkedHashSet result = listPrompt.prompt(listChoice); + //System.out.println("result = " + result); + } + + private static void checkBoxDemo() throws IOException { + CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); + List list=new ArrayList(); + + + list.add(new CheckboxItem("One")); + list.add(new CheckboxItem(true,"Two")); + list.add(CheckboxItemBuilder.create().name("3").text("Three").disabledText("always in").check().build()); + list.add(new Separator("some extra items")); + list.add(new CheckboxItem("Four")); + list.add(new Separator()); + list.add(new CheckboxItem(true,"Five")); + Checkbox checkbox = new Checkbox("my first checkbox", null, list); + LinkedHashSet result = checkboxPrompt.prompt(checkbox); + //System.out.println("result = " + result); + } + + private static void inputDemo() throws IOException { + InputPrompt inputPrompt = new InputPrompt(); + inputPrompt.prompt(new InputValue("name", "enter your name")); + inputPrompt.prompt(new InputValue("firstname","enter your first name",null,"John")); + InputValue branch = new InputValue("branch", "enter a branch name", null, null); + branch.addCompleter(new StringsCompleter("consoleui_1","consoleui_1_412_1","consoleui_1_769_2","simplegui_4_32")); + branch.addCompleter(new FileNameCompleter()); + inputPrompt.prompt(branch); + } + + private static void readBindingsDemo(ConsoleReader console) throws IOException { + Object o = console.readBinding(console.getKeys()); + System.out.println("o = " + o); + } + + private static void readCharsDemo(ConsoleReader console) throws IOException { + int c=0; + while (c != -1) { + Operation o = (Operation) console.readBinding(console.getKeys()); + System.out.println("o = " + o + " "+o.getClass().getName()); + String lastBinding = console.getLastBinding(); + System.out.println(lastBinding); + System.out.println("after read"); + } + //System.out.println("finished"); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java b/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java new file mode 100644 index 000000000..80e99647c --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java @@ -0,0 +1,24 @@ +package de.codeshelf.consoleui.elements; + +/** + * User: andy + * Date: 06.01.16 + */ +public class AbstractPromptableElement implements PromptableElementIF { + + protected String message; + protected String name; + + public AbstractPromptableElement(String message, String name) { + this.message = message; + this.name = name; + } + + public String getMessage() { + return message; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java new file mode 100644 index 000000000..d8517c684 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java @@ -0,0 +1,27 @@ +package de.codeshelf.consoleui.elements; + +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; + +import java.util.List; + +/** + * User: andy + * Date: 01.01.16 + */ +public class Checkbox extends AbstractPromptableElement { + + private List checkboxItemList; + + public Checkbox(String message, String name, List checkboxItemList) { + super(message,name); + this.checkboxItemList = checkboxItemList; + } + + public String getMessage() { + return message; + } + + public List getCheckboxItemList() { + return checkboxItemList; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java new file mode 100644 index 000000000..5a13746c4 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java @@ -0,0 +1,54 @@ +package de.codeshelf.consoleui.elements; + +import jline.console.completer.Completer; +import jline.console.completer.StringsCompleter; + +import java.util.ArrayList; +import java.util.List; + +/** + * User: andy + * Date: 06.01.16 + */ +public class InputValue extends AbstractPromptableElement { + private String value; + private String defaultValue; + private List completer; + + public InputValue(String name, String message) { + super(message, name); + this.value = null; + this.defaultValue = null; + } + + public InputValue(String name, String message, String value, String defaultValue) { + super(message, name); + //this.value = value; + if (value!=null) + throw new IllegalStateException("pre filled values for InputValue are not supported at the moment."); + this.defaultValue = defaultValue; + } + + public String getValue() { + return value; + } + + public String getDefaultValue() { + return defaultValue; + } + + public List getCompleter() { + return completer; + } + + public void setCompleter(List completer) { + this.completer = completer; + } + + public void addCompleter(Completer completer) { + if (this.completer==null) { + this.completer=new ArrayList(); + } + this.completer.add(completer); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java new file mode 100644 index 000000000..72f90d782 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java @@ -0,0 +1,27 @@ +package de.codeshelf.consoleui.elements; + +import de.codeshelf.consoleui.elements.items.ListItemIF; + +import java.util.List; + +/** + * User: andy + * Date: 04.01.16 + */ +public class ListChoice extends AbstractPromptableElement { + + private List listItemList; + + public ListChoice(String message, String name, List listItemList) { + super(message,name); + this.listItemList = listItemList; + } + + public String getMessage() { + return message; + } + + public List getListItemList() { + return listItemList; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java new file mode 100644 index 000000000..04e417d16 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java @@ -0,0 +1,8 @@ +package de.codeshelf.consoleui.elements; + +/** + * User: andy + * Date: 04.01.16 + */ +public interface PromptableElementIF { +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java new file mode 100644 index 000000000..5dce3c181 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java @@ -0,0 +1,8 @@ +package de.codeshelf.consoleui.elements.items; + +/** + * User: andy + * Date: 01.01.16 + */ +public interface CheckboxItemIF extends ConsoleUIItemIF { +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java new file mode 100644 index 000000000..1315bca3a --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java @@ -0,0 +1,9 @@ +package de.codeshelf.consoleui.elements.items; + +/** + * User: andy + * Date: 01.01.16 + */ +public interface ConsoleUIItemIF { + boolean isSelectable(); +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java new file mode 100644 index 000000000..1e31e69b1 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java @@ -0,0 +1,8 @@ +package de.codeshelf.consoleui.elements.items; + +/** + * User: andy + * Date: 01.01.16 + */ +public interface ListItemIF extends ConsoleUIItemIF { +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java new file mode 100644 index 000000000..f5046da20 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java @@ -0,0 +1,89 @@ +package de.codeshelf.consoleui.elements.items.impl; + +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; + +/** + * User: andy + * Date: 07.12.15 + */ +public class CheckboxItem implements CheckboxItemIF { + boolean checked; + String text; + String disabledText; + String name; + + public CheckboxItem(boolean checked, String text, String disabledText, String name) { + this.checked = checked; + this.text = text; + this.disabledText = disabledText; + this.name = name; + } + + public CheckboxItem(boolean checked, String text) { + this(checked, text, null, text); + } + + public CheckboxItem(String text) { + this(false, text, null, text); + } + + public CheckboxItem(String text, String disabledText) { + this(false, text, disabledText, text); + } + + public CheckboxItem() { + this(false, null, null, null); + } + + public boolean isChecked() { + return checked; + } + + public void setChecked(boolean checked) { + this.checked = checked; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isSelectable() { + return isEnabled(); + } + + public void setDisabled() { + disabledText = "disabled"; + } + + public void setDisabled(String disabledText) { + this.disabledText = disabledText; + } + + public void setEnabled() { + disabledText = null; + } + + public boolean isDisabled() { + return disabledText != null; + } + + public String getDisabledText() { + return disabledText; + } + + public boolean isEnabled() { + return disabledText == null; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java new file mode 100644 index 000000000..b7ffa56d0 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java @@ -0,0 +1,63 @@ +package de.codeshelf.consoleui.elements.items.impl; + +import de.codeshelf.consoleui.util.BuilderIF; + +/** + * User: andy + * Date: 04.01.16 + */ +public class CheckboxItemBuilder implements BuilderIF { + + private String text; + private String disabledText; + private String name; + private boolean checked; + + private CheckboxItemBuilder() { + } + + public static CheckboxItemBuilder create() { + return new CheckboxItemBuilder(); + } + + public CheckboxItemBuilder text(String text) { + this.text = text; + if (this.name == null) { + this.name = text; + } + + return this; + } + + public CheckboxItemBuilder name(String name) { + this.name = name; + return this; + } + + public CheckboxItemBuilder disabledText(String text) { + this.disabledText = text; + return this; + } + + public CheckboxItemBuilder check() { + this.checked = true; + return this; + } + + public CheckboxItemBuilder uncheck() { + this.checked = false; + return this; + } + + public CheckboxItemBuilder checked(boolean checked) { + this.checked = checked; + return this; + } + + + public CheckboxItem build() { + CheckboxItem checkboxItem = new CheckboxItem(checked, text, disabledText, name); + this.name = null; + return checkboxItem; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java new file mode 100644 index 000000000..c02db89a4 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java @@ -0,0 +1,41 @@ +package de.codeshelf.consoleui.elements.items.impl; + +import de.codeshelf.consoleui.elements.items.ListItemIF; + +/** + * User: andy + * Date: 01.01.16 + */ +public class ListItem implements ListItemIF { + String text; + String name; + + public ListItem(String text, String name) { + this.text = text; + this.name = name; + } + + public ListItem(String text) { + this(text,text); + } + + public ListItem() { + this(null,null); + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getName() { + return name; + } + + public boolean isSelectable() { + return true; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java new file mode 100644 index 000000000..fc81b29fd --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java @@ -0,0 +1,37 @@ +package de.codeshelf.consoleui.elements.items.impl; + +import de.codeshelf.consoleui.util.BuilderIF; + +/** + * User: andy + * Date: 04.01.16 + */ +public class ListItemBuilder implements BuilderIF { + ListItem item; + private String text; + private String name; + + private ListItemBuilder() { + this.item = new ListItem(null); + } + + static public ListItemBuilder create() { + return new ListItemBuilder(); + } + + public ListItemBuilder text(String text) { + this.text = text; + return this; + } + + public ListItem build() { + ListItem listItem = new ListItem(text,name); + this.name = null; + return listItem; + } + + public ListItemBuilder name(String name) { + this.name = name; + return this; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java new file mode 100644 index 000000000..b6aba3e60 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java @@ -0,0 +1,17 @@ +package de.codeshelf.consoleui.elements.items.impl; + +/** + * User: andy + * Date: 01.01.16 + */ +public class Message { + private final String message; + + public Message(String message) { + this.message =message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java new file mode 100644 index 000000000..508105248 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java @@ -0,0 +1,28 @@ +package de.codeshelf.consoleui.elements.items.impl; + +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ListItemIF; + +/** + * User: andy + * Date: 01.01.16 + */ +public class Separator implements CheckboxItemIF, ListItemIF { + private String message; + + public Separator(String message) { + this.message = message; + } + + public Separator() { + } + + public String getMessage() { + return message; + } + + public boolean isSelectable() { + return false; + } + +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java new file mode 100644 index 000000000..a91408186 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -0,0 +1,24 @@ +package de.codeshelf.consoleui.prompt; + +import org.fusesource.jansi.Ansi; + +import java.util.LinkedHashSet; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: andy + * Date: 06.01.16 + */ +public class AbstractPrompt { + protected int renderHeight; + + protected void renderMessagePromptAndResult(String message, String resultValue) { + + System.out.println(ansi().cursorUp(renderHeight - 1).a(renderMessagePrompt(message)).fg(Ansi.Color.CYAN).a(" " + resultValue).eraseScreen(Ansi.Erase.FORWARD).reset()); + } + + protected String renderMessagePrompt(String message) { + return (ansi().fg(Ansi.Color.GREEN).a("? ").fgBright(Ansi.Color.WHITE).a(message)).fg(Ansi.Color.DEFAULT).toString(); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java new file mode 100644 index 000000000..7b17f2c85 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -0,0 +1,57 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.InputValue; +import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; +import jline.console.completer.Completer; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: andy + * Date: 06.01.16 + */ +public class InputPrompt extends AbstractPrompt implements PromptIF { + + private InputValue inputElement; + private ReaderIF reader; + CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + + + public LinkedHashSet prompt(InputValue inputElement) throws IOException { + this.inputElement = inputElement; + + if (reader == null) { + reader = new ConsoleReaderImpl(); + } + + if (renderHeight == 0) { + renderHeight = 1; + } else { + System.out.println(ansi().cursorUp(renderHeight)); + } + + String prompt = renderMessagePrompt(this.inputElement.getMessage()) + itemRenderer.renderOptionalDefaultValue(this.inputElement); + //System.out.print(prompt + itemRenderer.renderValue(this.inputElement)); + //System.out.flush(); + List completer = inputElement.getCompleter(); + ReaderIF.ReaderInput readerInput = reader.readLine(completer,prompt,inputElement.getValue()); + + String lineInput = readerInput.getLineInput(); + + if (lineInput == null || lineInput.trim().length() == 0) { + lineInput = inputElement.getDefaultValue(); + } + renderMessagePromptAndResult(inputElement.getMessage(), lineInput); + + LinkedHashSet resultSet = new LinkedHashSet(); + resultSet.add(readerInput.getLineInput()); + return resultSet; + } + +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java new file mode 100644 index 000000000..c7157ddd2 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -0,0 +1,132 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.ListChoice; +import de.codeshelf.consoleui.elements.items.ListItemIF; +import de.codeshelf.consoleui.elements.items.impl.ListItem; +import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; +import org.fusesource.jansi.Ansi; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: andy + * Date: 01.01.16 + */ +public class ListPrompt extends AbstractPrompt implements PromptIF { + private ListChoice listChoice; + + ReaderIF reader; + + public void setReader(ReaderIF reader) { + this.reader = reader; + } + + int selectedItemIndex; + CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + + public ListPrompt() { + } + + + private void render() { + int itemNumber = 0; + List itemList = listChoice.getListItemList(); + + if (renderHeight == 0) { + renderHeight = 2 + itemList.size(); + } else { + System.out.println(ansi().cursorUp(renderHeight)); + } + + System.out.println(renderMessagePrompt(listChoice.getMessage())); + for (ListItemIF listItem : itemList) { + String renderedItem = itemRenderer.render(listItem,(selectedItemIndex == itemNumber)); + System.out.println(renderedItem); + itemNumber++; + } + } + + public LinkedHashSet prompt(ListChoice listChoice) throws IOException { + this.listChoice = listChoice; + List itemList = listChoice.getListItemList(); + if (reader == null) { + reader = new ConsoleReaderImpl(); + } + reader.addAllowedPrintableKey('j'); + reader.addAllowedPrintableKey('k'); + reader.addAllowedPrintableKey(' '); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); + + selectedItemIndex = getFirstSelectableItemIndex(); + + render(); + ReaderIF.ReaderInput readerInput = reader.read(); + while (readerInput.getSpecialKey() != ReaderIF.SpecialKey.ENTER) { + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { + if (readerInput.getPrintableKey().equals('j')) { + selectedItemIndex = getNextSelectableItemIndex(); + } else if (readerInput.getPrintableKey().equals('k')) { + selectedItemIndex = getPreviousSelectableItemIndex(); + } + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { + selectedItemIndex = getNextSelectableItemIndex(); + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { + selectedItemIndex = getPreviousSelectableItemIndex(); + } + + render(); + readerInput = reader.read(); + } + + LinkedHashSet selection = new LinkedHashSet(); + + ListItem listItem = (ListItem) itemList.get(selectedItemIndex); + selection.add(listItem.getName()); + renderMessagePromptAndResult(listChoice.getMessage(),selection.toString()); + return selection ; + } + + + private int getNextSelectableItemIndex() { + List itemList = listChoice.getListItemList(); + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); + ListItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + private int getPreviousSelectableItemIndex() { + List itemList = listChoice.getListItemList(); + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); + ListItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + private int getFirstSelectableItemIndex() { + int index = 0; + List itemList = listChoice.getListItemList(); + for (ListItemIF item : itemList) { + if (item.isSelectable()) + return index; + index++; + } + throw new IllegalStateException("no selectable item in list"); + } + + +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java new file mode 100644 index 000000000..9e7d10e41 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java @@ -0,0 +1,14 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.PromptableElementIF; + +import java.io.IOException; +import java.util.LinkedHashSet; + +/** + * User: andy + * Date: 01.01.16 + */ +public interface PromptIF { + LinkedHashSet prompt(T promptableElement) throws IOException; +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java new file mode 100644 index 000000000..73bc4d107 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -0,0 +1,92 @@ +package de.codeshelf.consoleui.prompt.reader; + +import jline.console.ConsoleReader; +import jline.console.Operation; +import jline.console.completer.Completer; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * User: andy + * Date: 02.01.16 + */ +public class ConsoleReaderImpl implements ReaderIF { + ConsoleReader console; + + private Set allowedSpecialKeys; + private Set allowedPrintableKeys; + + public ConsoleReaderImpl() throws IOException { + allowedPrintableKeys = new HashSet(); + allowedSpecialKeys = new HashSet(); + + console = new ConsoleReader(); + } + + public void setAllowedSpecialKeys(Set allowedSpecialKeys) { + this.allowedSpecialKeys.clear(); + this.allowedSpecialKeys.addAll(allowedSpecialKeys); + } + + public void setAllowedPrintableKeys(Set allowedPrintableKeys) { + this.allowedPrintableKeys.clear(); + this.allowedPrintableKeys.addAll(allowedPrintableKeys); + } + + public void addAllowedPrintableKey(Character character) { + this.allowedPrintableKeys.add(character); + } + + public void addAllowedSpecialKey(SpecialKey specialKey) { + this.allowedSpecialKeys.add(specialKey); + } + + public ReaderInput read() { + Object op; + while (true) { + try { + op = console.readBinding(console.getKeys()); + if (op instanceof Operation) { + Operation operation = (Operation) op; + if (operation == Operation.NEXT_HISTORY && this.allowedSpecialKeys.contains(SpecialKey.DOWN)) + return new ReaderInput(SpecialKey.DOWN); + if (operation == Operation.PREVIOUS_HISTORY && this.allowedSpecialKeys.contains(SpecialKey.UP)) + return new ReaderInput(SpecialKey.UP); + if (operation == Operation.ACCEPT_LINE && this.allowedSpecialKeys.contains(SpecialKey.ENTER)) + return new ReaderInput(SpecialKey.ENTER); + + if (operation == Operation.SELF_INSERT) { + String lastBinding = console.getLastBinding(); + Character c = lastBinding.charAt(0); + if (allowedPrintableKeys.contains(c)) { + return new ReaderInput(SpecialKey.PRINTABLE_KEY, c); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Wrapper around JLine 2 library. + * + * @param completer + * @param prompt + * @return + */ + public ReaderInput readLine(List completer, String prompt, String value) throws IOException { + if (completer != null) { + for (Completer c : completer) { + console.addCompleter(c); + } + } + String readLine = console.readLine(prompt, null, value); + + return new ReaderInput(SpecialKey.PRINTABLE_KEY, readLine); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java new file mode 100644 index 000000000..c43bfd9b3 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java @@ -0,0 +1,65 @@ +package de.codeshelf.consoleui.prompt.reader; + +import jline.console.completer.Completer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * User: andy + * Date: 02.01.16 + */ +public interface ReaderIF { + + public enum SpecialKey { + UP, + DOWN, + ENTER, + PRINTABLE_KEY, // not really a special key, but indicates an ordianry printable key + } + + void setAllowedSpecialKeys(Set allowedSpecialKeys); + + void setAllowedPrintableKeys(Set allowedPrintableKeys); + + void addAllowedPrintableKey(Character character); + + void addAllowedSpecialKey(SpecialKey specialKey); + + ReaderInput read(); + + ReaderInput readLine(List completer, String promt, String value) throws IOException; + + class ReaderInput { + private SpecialKey specialKey; + private Character printableKey; + private String lineInput; + + public ReaderInput(SpecialKey specialKey) { + this.specialKey = specialKey; + } + + public ReaderInput(SpecialKey specialKey, Character printableKey) { + this.specialKey = specialKey; + this.printableKey = printableKey; + } + + public ReaderInput(SpecialKey specialKey, String lineInput) { + this.specialKey = specialKey; + this.lineInput = lineInput; + } + + public SpecialKey getSpecialKey() { + return specialKey; + } + + public Character getPrintableKey() { + return printableKey; + } + + public String getLineInput() { + return lineInput; + } + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java new file mode 100644 index 000000000..6596cddd1 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -0,0 +1,88 @@ +package de.codeshelf.consoleui.prompt.renderer; + +import de.codeshelf.consoleui.elements.InputValue; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import de.codeshelf.consoleui.elements.items.impl.ListItem; +import de.codeshelf.consoleui.elements.items.impl.Separator; +import org.fusesource.jansi.Ansi; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: andy + * Date: 01.01.16 + */ +public class CUIRenderer { + private final String cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("> ").toString(); + private final String noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); + + private final String uncheckedBox; + private final String checkedBox; + private final String line; + + private static CUIRenderer renderer = new CUIRenderer(); + + public CUIRenderer() { + checkedBox = "\u25C9 "; + uncheckedBox = "\u25EF "; + + line = "\u2500─────────────"; + } + + public static CUIRenderer getRenderer() { + return renderer; + } + + public String render(ConsoleUIItemIF item, boolean withCursor) { + if (item instanceof CheckboxItem) { + CheckboxItem checkboxItem = (CheckboxItem) item; + String prefix; + if (withCursor) { + prefix = cursorSymbol; + } else { + prefix = noCursorSpace; + } + return prefix + ansi() + .fg(checkboxItem.isEnabled() ? Ansi.Color.GREEN : Ansi.Color.WHITE) + .a(checkboxItem.isChecked() ? checkedBox : uncheckedBox) + .reset().a(checkboxItem.getText() + + (checkboxItem.isDisabled() ? " (" + checkboxItem.getDisabledText() + ")" : "") + ).reset().toString(); + } + + if (item instanceof ListItem) { + ListItem listItem = (ListItem) item; + if (withCursor) { + return cursorSymbol+ansi() + .fg(Ansi.Color.CYAN).a(listItem.getText() + ).reset().toString(); + } else { + return noCursorSpace+ ansi() + .fg(Ansi.Color.DEFAULT).a(listItem.getText() + ).reset().toString(); + } + } + + if (item instanceof Separator) { + Separator separator = (Separator) item; + return ansi().fg(Ansi.Color.WHITE).a( + separator.getMessage() != null ? separator.getMessage() : line).reset().toString(); + } + return ""; + } + + public String renderOptionalDefaultValue(InputValue inputElement) { + if (inputElement.getDefaultValue()!=null) { + return " ("+inputElement.getDefaultValue()+") "; + } + return " "; + } + + public String renderValue(InputValue inputElement) { + if (inputElement.getValue()!=null) { + return inputElement.getValue(); + } + return ""; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java new file mode 100644 index 000000000..3be89b7e0 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java @@ -0,0 +1,8 @@ +package de.codeshelf.consoleui.prompt.renderer; + +/** + * User: andy + * Date: 01.01.16 + */ +public class CheckboxItemRenderer { +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java new file mode 100644 index 000000000..1f366afc2 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java @@ -0,0 +1,8 @@ +package de.codeshelf.consoleui.prompt.renderer; + +/** + * User: andy + * Date: 04.01.16 + */ +public class ListItemRenderer { +} diff --git a/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java b/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java new file mode 100644 index 000000000..b8d79b389 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java @@ -0,0 +1,9 @@ +package de.codeshelf.consoleui.util; + +/** + * User: andy + * Date: 04.01.16 + */ +public interface BuilderIF { + T build(); +} diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java new file mode 100644 index 000000000..6a28b4738 --- /dev/null +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -0,0 +1,59 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import de.codeshelf.consoleui.elements.items.impl.Separator; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import org.junit.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * User: andy + * Date: 07.12.15 + */ +public class CheckboxPromptTest { + @Test + public void renderSimpleList() throws IOException { + CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); + List list=new ArrayList(); + + list.add(new CheckboxItem("One")); + list.add(new CheckboxItem(true,"Two")); + CheckboxItem three = new CheckboxItem("Three"); + three.setDisabled("not available"); + list.add(three); + list.add(new Separator("some extra items")); + list.add(new CheckboxItem("Four")); + list.add(new CheckboxItem(true,"Five")); + + checkboxPrompt. setReader(new ReaderIF() { + public void setAllowedSpecialKeys(Set allowedSpecialKeys) { + + } + + public void setAllowedPrintableKeys(Set allowedPrintableKeys) { + + } + + public void addAllowedPrintableKey(Character character) { + + } + + public void addAllowedSpecialKey(SpecialKey specialKey) { + + } + + public ReaderInput read() { + return new ReaderInput(SpecialKey.ENTER); + } + }); + + checkboxPrompt.prompt(new Checkbox("no message", null, list)); + } + +} \ No newline at end of file From defdbde74568f0979503139fe9713b8fb67bfcc6 Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 7 Jan 2016 19:05:21 +0100 Subject: [PATCH 002/115] fixed missing CheckBoxPrompt --- .../consoleui/prompt/CheckboxPrompt.java | 131 ++++++++++++++++++ .../consoleui/prompt/CheckboxPromptTest.java | 5 + 2 files changed, 136 insertions(+) create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java new file mode 100644 index 000000000..95e41e702 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -0,0 +1,131 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; +import org.fusesource.jansi.Ansi; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; + +public class CheckboxPrompt extends AbstractPrompt implements PromptIF { + private Checkbox checkbox; + ReaderIF reader; + int selectedItemIndex; + + public void setReader(ReaderIF reader) { + this.reader = reader; + } + + CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + + private void render() { + int itemNumber = 0; + List itemList = this.checkbox.getCheckboxItemList(); + if (this.renderHeight == 0) { + this.renderHeight = (2 + itemList.size()); + } else { + System.out.println(Ansi.ansi().cursorUp(this.renderHeight)); + } + System.out.println(renderMessagePrompt(this.checkbox.getMessage())); + for (CheckboxItemIF checkboxItem : itemList) { + String renderedItem = this.itemRenderer.render(checkboxItem, this.selectedItemIndex == itemNumber); + System.out.println(renderedItem); + itemNumber++; + } + } + + public LinkedHashSet prompt(Checkbox checkbox) + throws IOException { + this.checkbox = checkbox; + List itemList = checkbox.getCheckboxItemList(); + if (this.reader == null) { + this.reader = new ConsoleReaderImpl(); + } + this.reader.addAllowedPrintableKey(Character.valueOf('j')); + this.reader.addAllowedPrintableKey(Character.valueOf('k')); + this.reader.addAllowedPrintableKey(Character.valueOf(' ')); + this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); + this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); + this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); + + this.selectedItemIndex = getFirstSelectableItemIndex(); + + render(); + ReaderIF.ReaderInput readerInput = this.reader.read(); + while (readerInput.getSpecialKey() != ReaderIF.SpecialKey.ENTER) { + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { + if (readerInput.getPrintableKey().equals(Character.valueOf(' '))) { + toggleSelection(); + } else if (readerInput.getPrintableKey().equals(Character.valueOf('j'))) { + this.selectedItemIndex = getNextSelectableItemIndex(); + } else if (readerInput.getPrintableKey().equals(Character.valueOf('k'))) { + this.selectedItemIndex = getPreviousSelectableItemIndex(); + } + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { + this.selectedItemIndex = getNextSelectableItemIndex(); + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { + this.selectedItemIndex = getPreviousSelectableItemIndex(); + } + render(); + readerInput = this.reader.read(); + } + LinkedHashSet selections = new LinkedHashSet(); + for (CheckboxItemIF item : itemList) { + if ((item instanceof CheckboxItem)) { + CheckboxItem checkboxItem = (CheckboxItem) item; + if (checkboxItem.isChecked()) { + selections.add(checkboxItem.getName()); + } + } + } + renderMessagePromptAndResult(checkbox.getMessage(), selections.toString()); + return selections; + } + + private int getNextSelectableItemIndex() { + List itemList = this.checkbox.getCheckboxItemList(); + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (this.selectedItemIndex + 1 + i) % itemList.size(); + CheckboxItemIF item = (CheckboxItemIF) itemList.get(newIndex); + if (item.isSelectable()) { + return newIndex; + } + } + return this.selectedItemIndex; + } + + private int getPreviousSelectableItemIndex() { + List itemList = this.checkbox.getCheckboxItemList(); + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (this.selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); + CheckboxItemIF item = (CheckboxItemIF) itemList.get(newIndex); + if (item.isSelectable()) { + return newIndex; + } + } + return this.selectedItemIndex; + } + + private int getFirstSelectableItemIndex() { + int index = 0; + List itemList = this.checkbox.getCheckboxItemList(); + for (CheckboxItemIF item : itemList) { + if (item.isSelectable()) { + return index; + } + index++; + } + throw new IllegalStateException("no selectable item in list"); + } + + private void toggleSelection() { + List itemList = this.checkbox.getCheckboxItemList(); + CheckboxItem checkboxItem = (CheckboxItem) itemList.get(this.selectedItemIndex); + checkboxItem.setChecked(!checkboxItem.isChecked()); + } +} diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java index 6a28b4738..85d37739a 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -5,6 +5,7 @@ import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; import de.codeshelf.consoleui.elements.items.impl.Separator; import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import jline.console.completer.Completer; import org.junit.Test; import java.io.IOException; @@ -51,6 +52,10 @@ public void addAllowedSpecialKey(SpecialKey specialKey) { public ReaderInput read() { return new ReaderInput(SpecialKey.ENTER); } + + public ReaderInput readLine(List completer, String promt, String value) throws IOException { + return null; + } }); checkboxPrompt.prompt(new Checkbox("no message", null, list)); From 4cccfb9533267ef32e1aec6fad1daa6414d87320 Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 7 Jan 2016 23:13:20 +0100 Subject: [PATCH 003/115] added new promts and choices --- .../consoleui/elements/ConfirmChoice.java | 11 +++++++ .../consoleui/elements/ExpandableChoice.java | 23 ++++++++++++++ .../consoleui/elements/InputValue.java | 1 - .../elements/items/impl/ChoiceItem.java | 31 +++++++++++++++++++ .../consoleui/prompt/AbstractPrompt.java | 2 -- .../prompt/ExpandableChoicePrompt.java | 20 ++++++++++++ .../consoleui/prompt/ListPrompt.java | 1 - 7 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java new file mode 100644 index 000000000..c46fe9c16 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java @@ -0,0 +1,11 @@ +package de.codeshelf.consoleui.elements; + +/** + * User: andy + * Date: 07.01.16 + */ +public class ConfirmChoice extends AbstractPromptableElement { + public ConfirmChoice(String message, String name) { + super(message, name); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java new file mode 100644 index 000000000..66e2fce9b --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java @@ -0,0 +1,23 @@ +package de.codeshelf.consoleui.elements; + +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; + +import java.util.LinkedHashSet; + +/** + * User: andy + * Date: 07.01.16 + */ +public class ExpandableChoice extends AbstractPromptableElement { + + private LinkedHashSet choiceItems; + + public ExpandableChoice(String message, String name, LinkedHashSet choiceItems) { + super(message, name); + this.choiceItems = choiceItems; + } + + public LinkedHashSet getChoiceItems() { + return choiceItems; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java index 5a13746c4..b2f59162a 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java +++ b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java @@ -1,7 +1,6 @@ package de.codeshelf.consoleui.elements; import jline.console.completer.Completer; -import jline.console.completer.StringsCompleter; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java new file mode 100644 index 000000000..c5e6fef81 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java @@ -0,0 +1,31 @@ +package de.codeshelf.consoleui.elements.items.impl; + +import de.codeshelf.consoleui.elements.PromptableElementIF; + +/** + * User: andy + * Date: 07.01.16 + */ +public class ChoiceItem implements PromptableElementIF { + private Character key; + private String name; + private String message; + + public ChoiceItem(Character key, String name, String message) { + this.key = key; + this.name = name; + this.message = message; + } + + public Character getKey() { + return key; + } + + public String getName() { + return name; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index a91408186..196480469 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -2,8 +2,6 @@ import org.fusesource.jansi.Ansi; -import java.util.LinkedHashSet; - import static org.fusesource.jansi.Ansi.ansi; /** diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java new file mode 100644 index 000000000..c8aafbf96 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -0,0 +1,20 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.ExpandableChoice; + +import java.io.IOException; +import java.util.LinkedHashSet; + +/** + * User: andy + * Date: 07.01.16 + */ +public class ExpandableChoicePrompt extends AbstractPrompt implements PromptIF { + enum RenderState { FOLDED, EXPANDED }; + + RenderState renderState = RenderState.FOLDED; + + public LinkedHashSet prompt(ExpandableChoice promptableElement) throws IOException { + return null; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index c7157ddd2..5dd94f36d 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -6,7 +6,6 @@ import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; -import org.fusesource.jansi.Ansi; import java.io.IOException; import java.util.LinkedHashSet; From f5c8055406431604b80d55198e7e21f62aa86ad6 Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 7 Jan 2016 23:16:34 +0100 Subject: [PATCH 004/115] fixed minor problems --- .../consoleui/prompt/CheckboxPrompt.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index 95e41e702..d8916df1e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -46,9 +46,9 @@ public LinkedHashSet prompt(Checkbox checkbox) if (this.reader == null) { this.reader = new ConsoleReaderImpl(); } - this.reader.addAllowedPrintableKey(Character.valueOf('j')); - this.reader.addAllowedPrintableKey(Character.valueOf('k')); - this.reader.addAllowedPrintableKey(Character.valueOf(' ')); + this.reader.addAllowedPrintableKey('j'); + this.reader.addAllowedPrintableKey('k'); + this.reader.addAllowedPrintableKey(' '); this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); @@ -59,11 +59,11 @@ public LinkedHashSet prompt(Checkbox checkbox) ReaderIF.ReaderInput readerInput = this.reader.read(); while (readerInput.getSpecialKey() != ReaderIF.SpecialKey.ENTER) { if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { - if (readerInput.getPrintableKey().equals(Character.valueOf(' '))) { + if (readerInput.getPrintableKey().equals(' ')) { toggleSelection(); - } else if (readerInput.getPrintableKey().equals(Character.valueOf('j'))) { + } else if (readerInput.getPrintableKey().equals('j')) { this.selectedItemIndex = getNextSelectableItemIndex(); - } else if (readerInput.getPrintableKey().equals(Character.valueOf('k'))) { + } else if (readerInput.getPrintableKey().equals('k')) { this.selectedItemIndex = getPreviousSelectableItemIndex(); } } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { @@ -74,7 +74,7 @@ public LinkedHashSet prompt(Checkbox checkbox) render(); readerInput = this.reader.read(); } - LinkedHashSet selections = new LinkedHashSet(); + LinkedHashSet selections = new LinkedHashSet(); for (CheckboxItemIF item : itemList) { if ((item instanceof CheckboxItem)) { CheckboxItem checkboxItem = (CheckboxItem) item; @@ -91,7 +91,7 @@ private int getNextSelectableItemIndex() { List itemList = this.checkbox.getCheckboxItemList(); for (int i = 0; i < itemList.size(); i++) { int newIndex = (this.selectedItemIndex + 1 + i) % itemList.size(); - CheckboxItemIF item = (CheckboxItemIF) itemList.get(newIndex); + CheckboxItemIF item = itemList.get(newIndex); if (item.isSelectable()) { return newIndex; } @@ -103,7 +103,7 @@ private int getPreviousSelectableItemIndex() { List itemList = this.checkbox.getCheckboxItemList(); for (int i = 0; i < itemList.size(); i++) { int newIndex = (this.selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); - CheckboxItemIF item = (CheckboxItemIF) itemList.get(newIndex); + CheckboxItemIF item = itemList.get(newIndex); if (item.isSelectable()) { return newIndex; } From 51b605e7c8af855bdc4a6411025e61df0ede6483 Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 10 Jan 2016 23:58:00 +0100 Subject: [PATCH 005/115] added incomplete ChoicePrompt --- .../java/de/codeshelf/consoleui/Basic.java | 21 ++- .../elements/items/impl/ChoiceItem.java | 7 +- .../prompt/ExpandableChoicePrompt.java | 133 +++++++++++++++++- .../prompt/reader/ConsoleReaderImpl.java | 2 + .../consoleui/prompt/reader/ReaderIF.java | 3 +- .../prompt/renderer/CUIRenderer.java | 21 ++- .../prompt/ExpandableChoicePromptTest.java | 18 +++ 7 files changed, 192 insertions(+), 13 deletions(-) create mode 100644 src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 38facc755..5f8f401a4 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -1,12 +1,14 @@ package de.codeshelf.consoleui; import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.ExpandableChoice; import de.codeshelf.consoleui.elements.InputValue; import de.codeshelf.consoleui.elements.ListChoice; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.*; import de.codeshelf.consoleui.prompt.CheckboxPrompt; +import de.codeshelf.consoleui.prompt.ExpandableChoicePrompt; import de.codeshelf.consoleui.prompt.InputPrompt; import de.codeshelf.consoleui.prompt.ListPrompt; import jline.TerminalFactory; @@ -29,15 +31,19 @@ */ public class Basic { - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { AnsiConsole.systemInstall(); - System.out.println(ansi().eraseScreen().render("@|red,italic Hello|@ @|green World|@\n@|blue no text|@")); + System.out.println(ansi().eraseScreen().render("@|red,italic Hello|@ @|green World|@\n@|reset " + + "This is a demonstration of ConsoleUI java library. It provides a simple console interface\n" + + "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written\n" + + "in JavaScrpt.|@")); try { checkBoxDemo(); listChoiceDemo(); inputDemo(); + exandableChoiceDemo(); } catch (IOException e) { e.printStackTrace(); } finally { @@ -94,6 +100,17 @@ private static void inputDemo() throws IOException { inputPrompt.prompt(branch); } + private static void exandableChoiceDemo() throws IOException { + ExpandableChoicePrompt expandableChoicePrompt = new ExpandableChoicePrompt(); + LinkedHashSet choiceItems=new LinkedHashSet(); + choiceItems.add(new ChoiceItem('o',"overwrite","Overwrite")); + choiceItems.add(new ChoiceItem('a',"overwriteAll","Overwrite this one and all next")); + choiceItems.add(new ChoiceItem('d',"diff","Show diff")); + choiceItems.add(new ChoiceItem('x',"abort","Abort")); + ExpandableChoice expChoice=new ExpandableChoice("Conflict in 'MyBestClass.java'", "conflict", choiceItems); + expandableChoicePrompt.prompt(expChoice); + } + private static void readBindingsDemo(ConsoleReader console) throws IOException { Object o = console.readBinding(console.getKeys()); System.out.println("o = " + o); diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java index c5e6fef81..64049c2c0 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java @@ -1,12 +1,13 @@ package de.codeshelf.consoleui.elements.items.impl; import de.codeshelf.consoleui.elements.PromptableElementIF; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; /** * User: andy * Date: 07.01.16 */ -public class ChoiceItem implements PromptableElementIF { +public class ChoiceItem implements PromptableElementIF, ConsoleUIItemIF { private Character key; private String name; private String message; @@ -28,4 +29,8 @@ public String getName() { public String getMessage() { return message; } + + public boolean isSelectable() { + return true; + } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index c8aafbf96..bb3ae889d 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -1,20 +1,145 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ExpandableChoice; +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; +import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; +import org.fusesource.jansi.Ansi; import java.io.IOException; import java.util.LinkedHashSet; +import static org.fusesource.jansi.Ansi.ansi; + /** * User: andy * Date: 07.01.16 */ public class ExpandableChoicePrompt extends AbstractPrompt implements PromptIF { - enum RenderState { FOLDED, EXPANDED }; + private ConsoleReaderImpl reader; + private ExpandableChoice expandableChoice; + CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + private int selectedItemIndex; + ChoiceItem choosenItem; + ChoiceItem defaultItem; + private ChoiceItem errorMessageItem = new ChoiceItem(' ', "error", "Please enter a valid command"); + + enum RenderState { + FOLDED, + FOLDED_ANSWERED, + EXPANDED + } RenderState renderState = RenderState.FOLDED; + LinkedHashSet choiceItems; + String promptString; + + private void render() { + if (renderState == RenderState.EXPANDED) { + int itemNumber = 0; + LinkedHashSet itemList = expandableChoice.getChoiceItems(); + + if (renderHeight == 0) { + renderHeight = 2 + itemList.size(); + } else { + System.out.println(ansi().cursorUp(renderHeight)); + } + + for (ChoiceItem choiceItem : itemList) { + String renderedItem = itemRenderer.render(choiceItem, (selectedItemIndex == itemNumber)); + System.out.println(renderedItem); + itemNumber++; + } + } else if (renderState == RenderState.FOLDED) { + System.out.println(""); + System.out.println(ansi().eraseLine().cursorUp(2)); + System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); + System.out.flush(); + renderHeight = 1; + } else if (renderState == RenderState.FOLDED_ANSWERED) { + System.out.println(""); + System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(choosenItem.getMessage())); + System.out.print(ansi().cursorUp(2)); + System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); + System.out.flush(); + renderHeight = 1; + } + } + + + public LinkedHashSet + + prompt(ExpandableChoice expandableChoice) throws IOException { + this.expandableChoice = expandableChoice; + if (reader == null) { + reader = new ConsoleReaderImpl(); + } + + choiceItems = expandableChoice.getChoiceItems(); + promptString = ""; + + for (ChoiceItem choiceItem : choiceItems) { + if (choiceItem.getKey() == 'h') { + throw new IllegalStateException("expandableChoice may not use the reserved key 'h' for an element."); + } + if (defaultItem == null) { + defaultItem = choiceItem; + } + reader.addAllowedPrintableKey(choiceItem.getKey()); + promptString += choiceItem.getKey(); + } + + choiceItems.add(new ChoiceItem('h',"help","Help, list all options")); + reader.addAllowedPrintableKey('h'); + promptString += "h"; + System.out.println("promptString = " + promptString); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.BACKSPACE); + renderState = RenderState.FOLDED; + + // first render call, we don't need to position the cursor up + renderHeight = 1; + render(); - public LinkedHashSet prompt(ExpandableChoice promptableElement) throws IOException { - return null; + ReaderIF.ReaderInput readerInput = this.reader.read(); + while (true) { + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { + if (choosenItem != null && choosenItem.getKey() == 'h') { + renderState = RenderState.EXPANDED; + render(); + readerInput = this.reader.read(); + } else { + LinkedHashSet hashSet = new LinkedHashSet(); + System.out.println(""); + if (choosenItem != null) { + renderMessagePromptAndResult(expandableChoice.getMessage(),choosenItem.getMessage()); + hashSet.add(choosenItem.getName()); + } else { + renderMessagePromptAndResult(expandableChoice.getMessage(),defaultItem.getMessage()); + hashSet.add(defaultItem.getName()); + } + return hashSet; + } + } + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { + Character pressedKey = readerInput.getPrintableKey(); + if (promptString.toLowerCase().contains("" + pressedKey)) { + // find the new choosen item + for (ChoiceItem choiceItem : choiceItems) { + if (choiceItem.getKey() == pressedKey) { + choosenItem = choiceItem; + break; + } + } + } else { + // not in valid choices + choosenItem = errorMessageItem; + } + renderState = RenderState.FOLDED_ANSWERED; + render(); + readerInput = this.reader.read(); + } + } } -} +} \ No newline at end of file diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 73bc4d107..815170e08 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -57,6 +57,8 @@ public ReaderInput read() { return new ReaderInput(SpecialKey.UP); if (operation == Operation.ACCEPT_LINE && this.allowedSpecialKeys.contains(SpecialKey.ENTER)) return new ReaderInput(SpecialKey.ENTER); + if (operation == Operation.BACKWARD_CHAR && this.allowedSpecialKeys.contains(SpecialKey.BACKSPACE)) + return new ReaderInput(SpecialKey.BACKSPACE); if (operation == Operation.SELF_INSERT) { String lastBinding = console.getLastBinding(); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java index c43bfd9b3..3ff05e56e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java @@ -16,7 +16,8 @@ public enum SpecialKey { UP, DOWN, ENTER, - PRINTABLE_KEY, // not really a special key, but indicates an ordianry printable key + BACKSPACE, + PRINTABLE_KEY, // not really a special key, but indicates an ordianry printable key } void setAllowedSpecialKeys(Set allowedSpecialKeys); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 6596cddd1..83e0630d8 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -3,6 +3,7 @@ import de.codeshelf.consoleui.elements.InputValue; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import de.codeshelf.consoleui.elements.items.impl.ListItem; import de.codeshelf.consoleui.elements.items.impl.Separator; import org.fusesource.jansi.Ansi; @@ -54,16 +55,26 @@ public String render(ConsoleUIItemIF item, boolean withCursor) { if (item instanceof ListItem) { ListItem listItem = (ListItem) item; if (withCursor) { - return cursorSymbol+ansi() + return cursorSymbol + ansi() .fg(Ansi.Color.CYAN).a(listItem.getText() ).reset().toString(); } else { - return noCursorSpace+ ansi() + return noCursorSpace + ansi() .fg(Ansi.Color.DEFAULT).a(listItem.getText() ).reset().toString(); } } + if (item instanceof ChoiceItem) { + ChoiceItem checkboxItem = (ChoiceItem) item; + if (withCursor) { + return cursorSymbol + ansi() + .fg(Ansi.Color.CYAN).a(checkboxItem.getMessage()).reset().toString(); + } else + return noCursorSpace + ansi() + .fg(Ansi.Color.DEFAULT).a(checkboxItem.getMessage()).reset().toString(); + } + if (item instanceof Separator) { Separator separator = (Separator) item; return ansi().fg(Ansi.Color.WHITE).a( @@ -73,14 +84,14 @@ public String render(ConsoleUIItemIF item, boolean withCursor) { } public String renderOptionalDefaultValue(InputValue inputElement) { - if (inputElement.getDefaultValue()!=null) { - return " ("+inputElement.getDefaultValue()+") "; + if (inputElement.getDefaultValue() != null) { + return " (" + inputElement.getDefaultValue() + ") "; } return " "; } public String renderValue(InputValue inputElement) { - if (inputElement.getValue()!=null) { + if (inputElement.getValue() != null) { return inputElement.getValue(); } return ""; diff --git a/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java new file mode 100644 index 000000000..f33e9830f --- /dev/null +++ b/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java @@ -0,0 +1,18 @@ +package de.codeshelf.consoleui.prompt; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * User: andy + * Date: 08.01.16 + */ +public class ExpandableChoicePromptTest { + + @Test + public void testPrompt() throws Exception { + + + } +} \ No newline at end of file From 930343e3f0bab75230b26102d3e378076fde26e2 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 20:41:48 +0100 Subject: [PATCH 006/115] added logo --- doc/ConsoleUI-Logo.png | Bin 0 -> 43312 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/ConsoleUI-Logo.png diff --git a/doc/ConsoleUI-Logo.png b/doc/ConsoleUI-Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..35290d12354167d40d2846938bd3788929063c5c GIT binary patch literal 43312 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 Fe*s&kE-(N9 literal 0 HcmV?d00001 From 103f911379838cfe92906238af3c611258531b81 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 20:42:08 +0100 Subject: [PATCH 007/115] fixed some layouting --- src/main/java/de/codeshelf/consoleui/Basic.java | 2 +- .../consoleui/prompt/ExpandableChoicePrompt.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 5f8f401a4..90f6223db 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -107,7 +107,7 @@ private static void exandableChoiceDemo() throws IOException { choiceItems.add(new ChoiceItem('a',"overwriteAll","Overwrite this one and all next")); choiceItems.add(new ChoiceItem('d',"diff","Show diff")); choiceItems.add(new ChoiceItem('x',"abort","Abort")); - ExpandableChoice expChoice=new ExpandableChoice("Conflict in 'MyBestClass.java'", "conflict", choiceItems); + ExpandableChoice expChoice=new ExpandableChoice("conflict in 'MyBestClass.java'", "conflict", choiceItems); expandableChoicePrompt.prompt(expChoice); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index bb3ae889d..7acc7d8b3 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -40,15 +40,19 @@ private void render() { int itemNumber = 0; LinkedHashSet itemList = expandableChoice.getChoiceItems(); - if (renderHeight == 0) { + if (renderHeight == 1) { + // first time we expand the list... renderHeight = 2 + itemList.size(); + System.out.println(""); + System.out.println(ansi().eraseLine().cursorUp(2).a(renderMessagePrompt(expandableChoice.getMessage())).eraseLine(Ansi.Erase.FORWARD)); + System.out.flush(); } else { System.out.println(ansi().cursorUp(renderHeight)); } for (ChoiceItem choiceItem : itemList) { String renderedItem = itemRenderer.render(choiceItem, (selectedItemIndex == itemNumber)); - System.out.println(renderedItem); + System.out.println(renderedItem+ansi().eraseLine(Ansi.Erase.FORWARD)); itemNumber++; } } else if (renderState == RenderState.FOLDED) { From e8877c6f9ef8d6e30c5632346d43c2e44c04b089 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Mon, 11 Jan 2016 20:43:20 +0100 Subject: [PATCH 008/115] Create README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..0d49b20e0 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + + +# consoleui + +Tiny java library that enables simple UI elements on ANSI console based terminals. + + From 133ea0a3f71c3e2c9fdf74ac4e1c8cad6c921789 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:17:02 +0100 Subject: [PATCH 009/115] small changes --- README.md | 5 +++-- doc/ConsoleUI-Logo-small.png | Bin 0 -> 7280 bytes 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 doc/ConsoleUI-Logo-small.png diff --git a/README.md b/README.md index 0d49b20e0..b888370f7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ +![](doc/ConsoleUI-Logo-small.png) - -# consoleui +# Console UI Tiny java library that enables simple UI elements on ANSI console based terminals. + diff --git a/doc/ConsoleUI-Logo-small.png b/doc/ConsoleUI-Logo-small.png new file mode 100644 index 0000000000000000000000000000000000000000..aebf70b730c6d15594f5b11ce9fa264807c0a1f4 GIT binary patch literal 7280 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 literal 0 HcmV?d00001 From 3fe8192f3e977e97cc380c43473ed1851d82f86f Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:39:23 +0100 Subject: [PATCH 010/115] small changes --- README.md | 2 +- doc/ConsoleUI-Logo-small.png | Bin 7280 -> 9659 bytes doc/ConsoleUI-Logo.svg | 115 +++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 doc/ConsoleUI-Logo.svg diff --git a/README.md b/README.md index b888370f7..4b8fb4c24 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](doc/ConsoleUI-Logo-small.png) +![](doc/ConsoleUI-Logo.svg) # Console UI diff --git a/doc/ConsoleUI-Logo-small.png b/doc/ConsoleUI-Logo-small.png index aebf70b730c6d15594f5b11ce9fa264807c0a1f4..2c164cba95970eb40dd101cc73b7425cf341ffad 100644 GIT binary patch literal 9659 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 literal 7280 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 diff --git a/doc/ConsoleUI-Logo.svg b/doc/ConsoleUI-Logo.svg new file mode 100644 index 000000000..b09edd168 --- /dev/null +++ b/doc/ConsoleUI-Logo.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? Console UI>_ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e915756aa2a7d4d062456be9b7a5bd053ebe0cba Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:47:00 +0100 Subject: [PATCH 011/115] added raw attribute --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b8fb4c24..c0c20a7a3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](doc/ConsoleUI-Logo.svg) +![](doc/ConsoleUI-Logo.svg?raw=true) # Console UI From 42c496954b2b6ada947aaf0d318df7452e2f03ed Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:53:22 +0100 Subject: [PATCH 012/115] added raw attribute --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0c20a7a3..061601130 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](doc/ConsoleUI-Logo.svg?raw=true) +![](doc/ConsoleUI-Logo.png =160x) # Console UI From 6e7cb6ecf926f92608bcfd18f338d12da6fb5100 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:54:43 +0100 Subject: [PATCH 013/115] changed path --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 061601130..879971f21 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](doc/ConsoleUI-Logo.png =160x) +![](./doc/ConsoleUI-Logo.png =160x) # Console UI From b3dbda554b4d2d493d328a2074a866c7aafeb11c Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:57:38 +0100 Subject: [PATCH 014/115] changed to img tag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 879971f21..ef2a4fb8c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](./doc/ConsoleUI-Logo.png =160x) + # Console UI From 97dc1d2920adafe91967bce5c99967f90fc498b6 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 21:58:52 +0100 Subject: [PATCH 015/115] changed to align right --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef2a4fb8c..0e5f09f9e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + # Console UI From 0b5894616553b9739f61a7790d5506a725fe346a Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 11 Jan 2016 22:38:22 +0100 Subject: [PATCH 016/115] some documentation --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e5f09f9e..ff272d0c4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,31 @@ # Console UI -Tiny java library that enables simple UI elements on ANSI console based terminals. +Tiny java library that provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by +[Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScrpt. + +# Intention + +I was impressed by JavaScript based Yeoman which leads the user through the process of creating new projects +by querying with a simple user interface on the console. An investigation how this is done, brought +me to Inquirer.js which implements a very simple and intuitive set of controls for checkbox, list and text input. + +Because I didn't found anything comparable to this in the Java eco system, I decided to write `Console UI` +as a library with the same easy 'look and feel'. Some parts of the API are also comparable, but Console UI is not +a Java clone of Inquirer.js. + +# Features + + Console UI currently supports: + + - Text input with completion and GNU ReadLine compatible editing + - Checkboxes + - Lists + - Expandable Choices (multiple key based answers for a question with help and optional list navigation) + + + + From 3b9a37f064706b2ba86e96e4cd6b2315e7a12af9 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 12 Jan 2016 07:19:28 +0100 Subject: [PATCH 017/115] added key to rendering --- .../de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 83e0630d8..437cf30cc 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -69,10 +69,10 @@ public String render(ConsoleUIItemIF item, boolean withCursor) { ChoiceItem checkboxItem = (ChoiceItem) item; if (withCursor) { return cursorSymbol + ansi() - .fg(Ansi.Color.CYAN).a(checkboxItem.getMessage()).reset().toString(); + .fg(Ansi.Color.CYAN).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()).reset().toString(); } else return noCursorSpace + ansi() - .fg(Ansi.Color.DEFAULT).a(checkboxItem.getMessage()).reset().toString(); + .fg(Ansi.Color.DEFAULT).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()).reset().toString(); } if (item instanceof Separator) { From 03eb5dfcf8c8e17ec8dc311b8627cc08086e67e3 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 12 Jan 2016 07:24:05 +0100 Subject: [PATCH 018/115] fixed long lines --- .../de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 7acc7d8b3..6ab560197 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -63,7 +63,7 @@ private void render() { renderHeight = 1; } else if (renderState == RenderState.FOLDED_ANSWERED) { System.out.println(""); - System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(choosenItem.getMessage())); + System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(choosenItem.getMessage()).eraseLine()); System.out.print(ansi().cursorUp(2)); System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); System.out.flush(); From f9d19917467923baac46d68e0b1fb01048be7653 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Tue, 12 Jan 2016 13:08:40 +0100 Subject: [PATCH 019/115] fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff272d0c4..42e904934 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # Console UI Tiny java library that provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by -[Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScrpt. +[Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScript. # Intention From 34cede2bef633d2749099f2f18437109eb533e29 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Tue, 12 Jan 2016 13:15:29 +0100 Subject: [PATCH 020/115] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 42e904934..714446682 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ a Java clone of Inquirer.js. - Lists - Expandable Choices (multiple key based answers for a question with help and optional list navigation) +# Dependencies + +Console UI uses jansi and jline for the dirty console things. + From e629512afe806d04a95de01525fdad386a26ba8a Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Tue, 12 Jan 2016 13:17:02 +0100 Subject: [PATCH 021/115] Create .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..ec46ce71c --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: groovy From fe873c6bd6e63d0d246c2eb5f96cd152cf3795f2 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Tue, 12 Jan 2016 13:20:03 +0100 Subject: [PATCH 022/115] added build status image --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 714446682..97e2d41f5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ +[![Build Status](https://travis-ci.org/awegmann/consoleui.svg?branch=master)](https://travis-ci.org/awegmann/consoleui) + # Console UI Tiny java library that provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by From 7647f94b1e353142fac0070483e4dd0068851565 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Tue, 12 Jan 2016 17:04:16 +0100 Subject: [PATCH 023/115] reformat --- .../de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 6ab560197..1fb0bddab 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -72,9 +72,7 @@ private void render() { } - public LinkedHashSet - - prompt(ExpandableChoice expandableChoice) throws IOException { + public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IOException { this.expandableChoice = expandableChoice; if (reader == null) { reader = new ConsoleReaderImpl(); From fa2a64b5167ac5978247ca7c396386ab4fe21f39 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 13 Jan 2016 23:12:52 +0100 Subject: [PATCH 024/115] changed name, added code for exandable choice --- .../java/de/codeshelf/consoleui/Basic.java | 2 +- .../elements/AbstractPromptableElement.java | 2 +- .../consoleui/elements/Checkbox.java | 2 +- .../consoleui/elements/ConfirmChoice.java | 2 +- .../consoleui/elements/ExpandableChoice.java | 2 +- .../consoleui/elements/InputValue.java | 2 +- .../consoleui/elements/ListChoice.java | 2 +- .../elements/PromptableElementIF.java | 2 +- .../elements/items/CheckboxItemIF.java | 2 +- .../elements/items/ChoiceItemIF.java | 8 ++ .../elements/items/ConsoleUIItemIF.java | 2 +- .../consoleui/elements/items/ListItemIF.java | 2 +- .../elements/items/impl/CheckboxItem.java | 2 +- .../items/impl/CheckboxItemBuilder.java | 2 +- .../elements/items/impl/ChoiceItem.java | 5 +- .../elements/items/impl/ListItem.java | 2 +- .../elements/items/impl/ListItemBuilder.java | 2 +- .../elements/items/impl/Message.java | 2 +- .../elements/items/impl/Separator.java | 5 +- .../consoleui/prompt/AbstractPrompt.java | 2 +- .../prompt/ExpandableChoicePrompt.java | 93 ++++++++++++++----- .../consoleui/prompt/InputPrompt.java | 2 +- .../consoleui/prompt/ListPrompt.java | 2 +- .../codeshelf/consoleui/prompt/PromptIF.java | 2 +- .../prompt/reader/ConsoleReaderImpl.java | 2 +- .../consoleui/prompt/reader/ReaderIF.java | 2 +- .../prompt/renderer/CUIRenderer.java | 2 +- .../prompt/renderer/CheckboxItemRenderer.java | 2 +- .../prompt/renderer/ListItemRenderer.java | 2 +- .../codeshelf/consoleui/util/BuilderIF.java | 2 +- .../consoleui/prompt/CheckboxPromptTest.java | 2 +- .../prompt/ExpandableChoicePromptTest.java | 2 +- 32 files changed, 113 insertions(+), 54 deletions(-) create mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 90f6223db..b19476497 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -26,7 +26,7 @@ import static org.fusesource.jansi.Ansi.ansi; /** - * User: andy + * User: Andreas Wegmann * Date: 29.11.15 */ public class Basic { diff --git a/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java b/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java index 80e99647c..033dbef4b 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java +++ b/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements; /** - * User: andy + * User: Andreas Wegmann * Date: 06.01.16 */ public class AbstractPromptableElement implements PromptableElementIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java index d8517c684..dbc3a3001 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java +++ b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java @@ -5,7 +5,7 @@ import java.util.List; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public class Checkbox extends AbstractPromptableElement { diff --git a/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java index c46fe9c16..5ad53b5f6 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements; /** - * User: andy + * User: Andreas Wegmann * Date: 07.01.16 */ public class ConfirmChoice extends AbstractPromptableElement { diff --git a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java index 66e2fce9b..095ffd740 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java @@ -5,7 +5,7 @@ import java.util.LinkedHashSet; /** - * User: andy + * User: Andreas Wegmann * Date: 07.01.16 */ public class ExpandableChoice extends AbstractPromptableElement { diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java index b2f59162a..1ee91f5fe 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java +++ b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java @@ -6,7 +6,7 @@ import java.util.List; /** - * User: andy + * User: Andreas Wegmann * Date: 06.01.16 */ public class InputValue extends AbstractPromptableElement { diff --git a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java index 72f90d782..3924f48cb 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java @@ -5,7 +5,7 @@ import java.util.List; /** - * User: andy + * User: Andreas Wegmann * Date: 04.01.16 */ public class ListChoice extends AbstractPromptableElement { diff --git a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java index 04e417d16..f5c3e74b3 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements; /** - * User: andy + * User: Andreas Wegmann * Date: 04.01.16 */ public interface PromptableElementIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java index 5dce3c181..0df83319c 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements.items; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public interface CheckboxItemIF extends ConsoleUIItemIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java new file mode 100644 index 000000000..e5e0400f9 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java @@ -0,0 +1,8 @@ +package de.codeshelf.consoleui.elements.items; + +/** + * User: Andreas Wegmann + * Date: 13.01.16 + */ +public interface ChoiceItemIF { +} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java index 1315bca3a..45e585627 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements.items; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public interface ConsoleUIItemIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java index 1e31e69b1..e38e5fc6a 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements.items; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public interface ListItemIF extends ConsoleUIItemIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java index f5046da20..02efbff4e 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java @@ -3,7 +3,7 @@ import de.codeshelf.consoleui.elements.items.CheckboxItemIF; /** - * User: andy + * User: Andreas Wegmann * Date: 07.12.15 */ public class CheckboxItem implements CheckboxItemIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java index b7ffa56d0..4e99a73f4 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java @@ -3,7 +3,7 @@ import de.codeshelf.consoleui.util.BuilderIF; /** - * User: andy + * User: Andreas Wegmann * Date: 04.01.16 */ public class CheckboxItemBuilder implements BuilderIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java index 64049c2c0..eb0060f6c 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java @@ -1,13 +1,14 @@ package de.codeshelf.consoleui.elements.items.impl; import de.codeshelf.consoleui.elements.PromptableElementIF; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; /** - * User: andy + * User: Andreas Wegmann * Date: 07.01.16 */ -public class ChoiceItem implements PromptableElementIF, ConsoleUIItemIF { +public class ChoiceItem implements PromptableElementIF, ConsoleUIItemIF, ChoiceItemIF { private Character key; private String name; private String message; diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java index c02db89a4..3225fb654 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java @@ -3,7 +3,7 @@ import de.codeshelf.consoleui.elements.items.ListItemIF; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public class ListItem implements ListItemIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java index fc81b29fd..520fe45ac 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java @@ -3,7 +3,7 @@ import de.codeshelf.consoleui.util.BuilderIF; /** - * User: andy + * User: Andreas Wegmann * Date: 04.01.16 */ public class ListItemBuilder implements BuilderIF { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java index b6aba3e60..f87b03004 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.elements.items.impl; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public class Message { diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java index 508105248..bbbf1afbe 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java @@ -1,13 +1,14 @@ package de.codeshelf.consoleui.elements.items.impl; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ -public class Separator implements CheckboxItemIF, ListItemIF { +public class Separator implements CheckboxItemIF, ListItemIF, ChoiceItemIF { private String message; public Separator(String message) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 196480469..f5293a940 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -5,7 +5,7 @@ import static org.fusesource.jansi.Ansi.ansi; /** - * User: andy + * User: Andreas Wegmann * Date: 06.01.16 */ public class AbstractPrompt { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 1fb0bddab..8e128e320 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -1,6 +1,8 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ExpandableChoice; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; @@ -8,12 +10,14 @@ import org.fusesource.jansi.Ansi; import java.io.IOException; +import java.util.ArrayList; import java.util.LinkedHashSet; +import java.util.List; import static org.fusesource.jansi.Ansi.ansi; /** - * User: andy + * User: Andreas Wegmann * Date: 07.01.16 */ public class ExpandableChoicePrompt extends AbstractPrompt implements PromptIF { @@ -24,6 +28,7 @@ public class ExpandableChoicePrompt extends AbstractPrompt implements PromptIF itemList; enum RenderState { FOLDED, @@ -37,24 +42,7 @@ enum RenderState { private void render() { if (renderState == RenderState.EXPANDED) { - int itemNumber = 0; - LinkedHashSet itemList = expandableChoice.getChoiceItems(); - - if (renderHeight == 1) { - // first time we expand the list... - renderHeight = 2 + itemList.size(); - System.out.println(""); - System.out.println(ansi().eraseLine().cursorUp(2).a(renderMessagePrompt(expandableChoice.getMessage())).eraseLine(Ansi.Erase.FORWARD)); - System.out.flush(); - } else { - System.out.println(ansi().cursorUp(renderHeight)); - } - - for (ChoiceItem choiceItem : itemList) { - String renderedItem = itemRenderer.render(choiceItem, (selectedItemIndex == itemNumber)); - System.out.println(renderedItem+ansi().eraseLine(Ansi.Erase.FORWARD)); - itemNumber++; - } + renderList(); } else if (renderState == RenderState.FOLDED) { System.out.println(""); System.out.println(ansi().eraseLine().cursorUp(2)); @@ -71,6 +59,24 @@ private void render() { } } + private void renderList() { + if (renderHeight == 1) { + // first time we expand the list... + renderHeight = 2 + itemList.size(); + System.out.println(""); + System.out.println(ansi().eraseLine().cursorUp(2).a(renderMessagePrompt(expandableChoice.getMessage())).eraseLine(Ansi.Erase.FORWARD)); + System.out.flush(); + } else { + System.out.println(ansi().cursorUp(renderHeight)); + } + + int itemNumber = 0; + for (ConsoleUIItemIF choiceItem : itemList) { + String renderedItem = itemRenderer.render(choiceItem, (selectedItemIndex == itemNumber)); + System.out.println(renderedItem + ansi().eraseLine(Ansi.Erase.FORWARD)); + itemNumber++; + } + } public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IOException { this.expandableChoice = expandableChoice; @@ -92,7 +98,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO promptString += choiceItem.getKey(); } - choiceItems.add(new ChoiceItem('h',"help","Help, list all options")); + choiceItems.add(new ChoiceItem('h', "help", "Help, list all options")); reader.addAllowedPrintableKey('h'); promptString += "h"; System.out.println("promptString = " + promptString); @@ -109,20 +115,31 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { if (choosenItem != null && choosenItem.getKey() == 'h') { renderState = RenderState.EXPANDED; + + itemList = new ArrayList(); + itemList.addAll(expandableChoice.getChoiceItems()); + render(); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); + readerInput = this.reader.read(); } else { LinkedHashSet hashSet = new LinkedHashSet(); System.out.println(""); if (choosenItem != null) { - renderMessagePromptAndResult(expandableChoice.getMessage(),choosenItem.getMessage()); + renderMessagePromptAndResult(expandableChoice.getMessage(), choosenItem.getMessage()); hashSet.add(choosenItem.getName()); } else { - renderMessagePromptAndResult(expandableChoice.getMessage(),defaultItem.getMessage()); + renderMessagePromptAndResult(expandableChoice.getMessage(), defaultItem.getMessage()); hashSet.add(defaultItem.getName()); } return hashSet; } + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { + + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { + } if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { Character pressedKey = readerInput.getPrintableKey(); @@ -144,4 +161,36 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO } } } + + private int getNextSelectableItemIndex() { + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); + ConsoleUIItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + private int getPreviousSelectableItemIndex() { + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); + ConsoleUIItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + private int getFirstSelectableItemIndex() { + int index = 0; + for (ConsoleUIItemIF item : itemList) { + if (item.isSelectable()) + return index; + index++; + } + throw new IllegalStateException("no selectable item in list"); + } + + } \ No newline at end of file diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 7b17f2c85..6704a7085 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -13,7 +13,7 @@ import static org.fusesource.jansi.Ansi.ansi; /** - * User: andy + * User: Andreas Wegmann * Date: 06.01.16 */ public class InputPrompt extends AbstractPrompt implements PromptIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 5dd94f36d..5c2bccc47 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -14,7 +14,7 @@ import static org.fusesource.jansi.Ansi.ansi; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public class ListPrompt extends AbstractPrompt implements PromptIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java index 9e7d10e41..79da1d248 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java @@ -6,7 +6,7 @@ import java.util.LinkedHashSet; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public interface PromptIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 815170e08..d2c3f7fd5 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -10,7 +10,7 @@ import java.util.Set; /** - * User: andy + * User: Andreas Wegmann * Date: 02.01.16 */ public class ConsoleReaderImpl implements ReaderIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java index 3ff05e56e..0c524a526 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java @@ -7,7 +7,7 @@ import java.util.Set; /** - * User: andy + * User: Andreas Wegmann * Date: 02.01.16 */ public interface ReaderIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 437cf30cc..6d8775428 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -11,7 +11,7 @@ import static org.fusesource.jansi.Ansi.ansi; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public class CUIRenderer { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java index 3be89b7e0..95779e809 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.prompt.renderer; /** - * User: andy + * User: Andreas Wegmann * Date: 01.01.16 */ public class CheckboxItemRenderer { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java index 1f366afc2..f63bdf237 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.prompt.renderer; /** - * User: andy + * User: Andreas Wegmann * Date: 04.01.16 */ public class ListItemRenderer { diff --git a/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java b/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java index b8d79b389..dda6a57dc 100644 --- a/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java +++ b/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.util; /** - * User: andy + * User: Andreas Wegmann * Date: 04.01.16 */ public interface BuilderIF { diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java index 85d37739a..21de3b798 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -14,7 +14,7 @@ import java.util.Set; /** - * User: andy + * User: Andreas Wegmann * Date: 07.12.15 */ public class CheckboxPromptTest { diff --git a/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java index f33e9830f..acae056d4 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.*; /** - * User: andy + * User: Andreas Wegmann * Date: 08.01.16 */ public class ExpandableChoicePromptTest { From 3581ffca39073f765560124cc4599f0cb2506523 Mon Sep 17 00:00:00 2001 From: awegmann Date: Fri, 15 Jan 2016 07:20:15 +0100 Subject: [PATCH 025/115] worked on expandable choice --- .../prompt/ExpandableChoicePrompt.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 8e128e320..3c9656e6a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -2,7 +2,6 @@ import de.codeshelf.consoleui.elements.ExpandableChoice; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; @@ -12,7 +11,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashSet; -import java.util.List; import static org.fusesource.jansi.Ansi.ansi; @@ -62,7 +60,7 @@ private void render() { private void renderList() { if (renderHeight == 1) { // first time we expand the list... - renderHeight = 2 + itemList.size(); + renderHeight = 1 + itemList.size(); System.out.println(""); System.out.println(ansi().eraseLine().cursorUp(2).a(renderMessagePrompt(expandableChoice.getMessage())).eraseLine(Ansi.Erase.FORWARD)); System.out.flush(); @@ -113,12 +111,14 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO ReaderIF.ReaderInput readerInput = this.reader.read(); while (true) { if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { + // if ENTER pressed if (choosenItem != null && choosenItem.getKey() == 'h') { renderState = RenderState.EXPANDED; itemList = new ArrayList(); itemList.addAll(expandableChoice.getChoiceItems()); + selectedItemIndex = getFirstSelectableItemIndex(); render(); reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); @@ -126,7 +126,11 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO readerInput = this.reader.read(); } else { LinkedHashSet hashSet = new LinkedHashSet(); - System.out.println(""); + if (renderState != RenderState.EXPANDED) { + System.out.println(""); + } else { + renderHeight++; + } if (choosenItem != null) { renderMessagePromptAndResult(expandableChoice.getMessage(), choosenItem.getMessage()); hashSet.add(choosenItem.getName()); @@ -137,28 +141,32 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO return hashSet; } } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - + this.selectedItemIndex = getPreviousSelectableItemIndex(); } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - + this.selectedItemIndex = getNextSelectableItemIndex(); } if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { Character pressedKey = readerInput.getPrintableKey(); if (promptString.toLowerCase().contains("" + pressedKey)) { // find the new choosen item + selectedItemIndex = 0; for (ChoiceItem choiceItem : choiceItems) { if (choiceItem.getKey() == pressedKey) { choosenItem = choiceItem; break; } + selectedItemIndex++; + } + if (renderState == RenderState.FOLDED) { + renderState = RenderState.FOLDED_ANSWERED; } } else { // not in valid choices choosenItem = errorMessageItem; } - renderState = RenderState.FOLDED_ANSWERED; - render(); - readerInput = this.reader.read(); } + render(); + readerInput = this.reader.read(); } } From be334a8c6003e2d304ed8bf8bd8d73168bd3305e Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Fri, 15 Jan 2016 14:45:03 +0100 Subject: [PATCH 026/115] added i18n resources --- .../de/codeshelf/consoleui/prompt/AbstractPrompt.java | 9 +++++++++ .../de/codeshelf/consoleui/prompt/CheckboxPrompt.java | 1 + .../consoleui/prompt/ExpandableChoicePrompt.java | 4 ++-- src/main/resources/consoleui.properties | 3 +++ src/main/resources/consoleui_de_DE.properties | 3 +++ 5 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/consoleui.properties create mode 100644 src/main/resources/consoleui_de_DE.properties diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index f5293a940..5f69cf694 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -2,6 +2,10 @@ import org.fusesource.jansi.Ansi; +import javax.swing.*; + +import java.util.ResourceBundle; + import static org.fusesource.jansi.Ansi.ansi; /** @@ -10,6 +14,7 @@ */ public class AbstractPrompt { protected int renderHeight; + protected ResourceBundle resourceBundle; protected void renderMessagePromptAndResult(String message, String resultValue) { @@ -19,4 +24,8 @@ protected void renderMessagePromptAndResult(String message, String resultValue) protected String renderMessagePrompt(String message) { return (ansi().fg(Ansi.Color.GREEN).a("? ").fgBright(Ansi.Color.WHITE).a(message)).fg(Ansi.Color.DEFAULT).toString(); } + + public AbstractPrompt() { + resourceBundle= ResourceBundle.getBundle("consoleui"); + } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index d8916df1e..69d97902f 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -8,6 +8,7 @@ import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; import org.fusesource.jansi.Ansi; +import javax.swing.*; import java.io.IOException; import java.util.LinkedHashSet; import java.util.List; diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 3c9656e6a..bb4bff511 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -25,7 +25,7 @@ public class ExpandableChoicePrompt extends AbstractPrompt implements PromptIF itemList; enum RenderState { @@ -96,7 +96,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO promptString += choiceItem.getKey(); } - choiceItems.add(new ChoiceItem('h', "help", "Help, list all options")); + choiceItems.add(new ChoiceItem('h', resourceBundle.getString("help"), resourceBundle.getString("help.list.all.options"))); reader.addAllowedPrintableKey('h'); promptString += "h"; System.out.println("promptString = " + promptString); diff --git a/src/main/resources/consoleui.properties b/src/main/resources/consoleui.properties new file mode 100644 index 000000000..b863ecd80 --- /dev/null +++ b/src/main/resources/consoleui.properties @@ -0,0 +1,3 @@ +help=help +help.list.all.options=Help, list all options +please.enter.a.valid.command=Please enter a valid command \ No newline at end of file diff --git a/src/main/resources/consoleui_de_DE.properties b/src/main/resources/consoleui_de_DE.properties new file mode 100644 index 000000000..e15fa2f2e --- /dev/null +++ b/src/main/resources/consoleui_de_DE.properties @@ -0,0 +1,3 @@ +help=help +help.list.all.options=Hilfe. Listet alle Optionen +please.enter.a.valid.command=Bitte ein gültiges Kürzel eingeben. \ No newline at end of file From 4cb9e20ee78c10e51dd130759efda854075fc11f Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Fri, 15 Jan 2016 15:05:13 +0100 Subject: [PATCH 027/115] fixed message resources --- .../java/de/codeshelf/consoleui/prompt/AbstractPrompt.java | 2 +- .../de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java | 4 ++-- .../{consoleui.properties => consoleui_messages.properties} | 1 - ...i_de_DE.properties => consoleui_messages_de_DE.properties} | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) rename src/main/resources/{consoleui.properties => consoleui_messages.properties} (91%) rename src/main/resources/{consoleui_de_DE.properties => consoleui_messages_de_DE.properties} (52%) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 5f69cf694..06d3c0ae2 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -26,6 +26,6 @@ protected String renderMessagePrompt(String message) { } public AbstractPrompt() { - resourceBundle= ResourceBundle.getBundle("consoleui"); + resourceBundle= ResourceBundle.getBundle("consoleui_messages"); } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index bb4bff511..77f5c4093 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -96,10 +96,10 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO promptString += choiceItem.getKey(); } - choiceItems.add(new ChoiceItem('h', resourceBundle.getString("help"), resourceBundle.getString("help.list.all.options"))); + choiceItems.add(new ChoiceItem('h', "help", resourceBundle.getString("help.list.all.options"))); reader.addAllowedPrintableKey('h'); promptString += "h"; - System.out.println("promptString = " + promptString); + reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); reader.addAllowedSpecialKey(ReaderIF.SpecialKey.BACKSPACE); renderState = RenderState.FOLDED; diff --git a/src/main/resources/consoleui.properties b/src/main/resources/consoleui_messages.properties similarity index 91% rename from src/main/resources/consoleui.properties rename to src/main/resources/consoleui_messages.properties index b863ecd80..a0a9787bb 100644 --- a/src/main/resources/consoleui.properties +++ b/src/main/resources/consoleui_messages.properties @@ -1,3 +1,2 @@ -help=help help.list.all.options=Help, list all options please.enter.a.valid.command=Please enter a valid command \ No newline at end of file diff --git a/src/main/resources/consoleui_de_DE.properties b/src/main/resources/consoleui_messages_de_DE.properties similarity index 52% rename from src/main/resources/consoleui_de_DE.properties rename to src/main/resources/consoleui_messages_de_DE.properties index e15fa2f2e..963f43fc2 100644 --- a/src/main/resources/consoleui_de_DE.properties +++ b/src/main/resources/consoleui_messages_de_DE.properties @@ -1,3 +1,2 @@ -help=help -help.list.all.options=Hilfe. Listet alle Optionen +help.list.all.options=Hilfe. Listet alle Optionen. please.enter.a.valid.command=Bitte ein gültiges Kürzel eingeben. \ No newline at end of file From 16c879b11b26a9f938f7381389b69c01e11a07a9 Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 17 Jan 2016 22:31:36 +0100 Subject: [PATCH 028/115] refactored initialisation of CUIRenderer --- .../codeshelf/consoleui/prompt/renderer/CUIRenderer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 6d8775428..83dc577bd 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -15,8 +15,9 @@ * Date: 01.01.16 */ public class CUIRenderer { - private final String cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("> ").toString(); - private final String noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); + //private final String cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("\uF078> ").toString(); + private final String cursorSymbol; + private final String noCursorSpace; private final String uncheckedBox; private final String checkedBox; @@ -27,8 +28,9 @@ public class CUIRenderer { public CUIRenderer() { checkedBox = "\u25C9 "; uncheckedBox = "\u25EF "; - line = "\u2500─────────────"; + cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("❯ ").toString(); + noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); } public static CUIRenderer getRenderer() { From d6e4412c0f973fe63f08c419aa16a3b7d6b3efcd Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 19 Jan 2016 22:36:12 +0100 Subject: [PATCH 029/115] refactored list management in prompts --- .../consoleui/elements/Checkbox.java | 6 ++- .../consoleui/elements/ListChoice.java | 6 ++- .../prompt/AbstractListablePrompt.java | 45 ++++++++++++++++ .../consoleui/prompt/AbstractPrompt.java | 3 +- .../consoleui/prompt/CheckboxPrompt.java | 53 +++--------------- .../prompt/ExpandableChoicePrompt.java | 54 ++++--------------- .../consoleui/prompt/InputPrompt.java | 1 - .../consoleui/prompt/ListPrompt.java | 45 ++-------------- .../prompt/renderer/CheckboxItemRenderer.java | 8 --- .../prompt/renderer/ListItemRenderer.java | 8 --- 10 files changed, 75 insertions(+), 154 deletions(-) create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java index dbc3a3001..5e67c803e 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java +++ b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java @@ -1,7 +1,9 @@ package de.codeshelf.consoleui.elements; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import java.util.ArrayList; import java.util.List; /** @@ -21,7 +23,7 @@ public String getMessage() { return message; } - public List getCheckboxItemList() { - return checkboxItemList; + public ArrayList getCheckboxItemList() { + return new ArrayList(checkboxItemList); } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java index 3924f48cb..9639c0a21 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java @@ -1,7 +1,9 @@ package de.codeshelf.consoleui.elements; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; +import java.util.ArrayList; import java.util.List; /** @@ -21,7 +23,7 @@ public String getMessage() { return message; } - public List getListItemList() { - return listItemList; + public ArrayList getListItemList() { + return new ArrayList(listItemList); } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java new file mode 100644 index 000000000..0f1b68c09 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java @@ -0,0 +1,45 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; + +import java.util.ArrayList; + +/** + * User: Andreas Wegmann + * Date: 19.01.16 + */ +public abstract class AbstractListablePrompt extends AbstractPrompt { + + protected int selectedItemIndex; + ArrayList itemList; + + protected int getNextSelectableItemIndex() { + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); + ConsoleUIItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + protected int getPreviousSelectableItemIndex() { + for (int i = 0; i < itemList.size(); i++) { + int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); + ConsoleUIItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + protected int getFirstSelectableItemIndex() { + int index = 0; + for (ConsoleUIItemIF item : itemList) { + if (item.isSelectable()) + return index; + index++; + } + throw new IllegalStateException("no selectable item in list"); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 06d3c0ae2..faa9aec89 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -2,8 +2,6 @@ import org.fusesource.jansi.Ansi; -import javax.swing.*; - import java.util.ResourceBundle; import static org.fusesource.jansi.Ansi.ansi; @@ -28,4 +26,5 @@ protected String renderMessagePrompt(String message) { public AbstractPrompt() { resourceBundle= ResourceBundle.getBundle("consoleui_messages"); } + } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index 69d97902f..f34c92e94 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -1,22 +1,19 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.Checkbox; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; import org.fusesource.jansi.Ansi; -import javax.swing.*; import java.io.IOException; import java.util.LinkedHashSet; -import java.util.List; -public class CheckboxPrompt extends AbstractPrompt implements PromptIF { +public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { private Checkbox checkbox; ReaderIF reader; - int selectedItemIndex; public void setReader(ReaderIF reader) { this.reader = reader; @@ -26,14 +23,14 @@ public void setReader(ReaderIF reader) { private void render() { int itemNumber = 0; - List itemList = this.checkbox.getCheckboxItemList(); + if (this.renderHeight == 0) { this.renderHeight = (2 + itemList.size()); } else { System.out.println(Ansi.ansi().cursorUp(this.renderHeight)); } System.out.println(renderMessagePrompt(this.checkbox.getMessage())); - for (CheckboxItemIF checkboxItem : itemList) { + for (ConsoleUIItemIF checkboxItem : itemList) { String renderedItem = this.itemRenderer.render(checkboxItem, this.selectedItemIndex == itemNumber); System.out.println(renderedItem); itemNumber++; @@ -43,7 +40,8 @@ private void render() { public LinkedHashSet prompt(Checkbox checkbox) throws IOException { this.checkbox = checkbox; - List itemList = checkbox.getCheckboxItemList(); + itemList = this.checkbox.getCheckboxItemList(); + if (this.reader == null) { this.reader = new ConsoleReaderImpl(); } @@ -76,7 +74,7 @@ public LinkedHashSet prompt(Checkbox checkbox) readerInput = this.reader.read(); } LinkedHashSet selections = new LinkedHashSet(); - for (CheckboxItemIF item : itemList) { + for (ConsoleUIItemIF item : itemList) { if ((item instanceof CheckboxItem)) { CheckboxItem checkboxItem = (CheckboxItem) item; if (checkboxItem.isChecked()) { @@ -88,44 +86,7 @@ public LinkedHashSet prompt(Checkbox checkbox) return selections; } - private int getNextSelectableItemIndex() { - List itemList = this.checkbox.getCheckboxItemList(); - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (this.selectedItemIndex + 1 + i) % itemList.size(); - CheckboxItemIF item = itemList.get(newIndex); - if (item.isSelectable()) { - return newIndex; - } - } - return this.selectedItemIndex; - } - - private int getPreviousSelectableItemIndex() { - List itemList = this.checkbox.getCheckboxItemList(); - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (this.selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); - CheckboxItemIF item = itemList.get(newIndex); - if (item.isSelectable()) { - return newIndex; - } - } - return this.selectedItemIndex; - } - - private int getFirstSelectableItemIndex() { - int index = 0; - List itemList = this.checkbox.getCheckboxItemList(); - for (CheckboxItemIF item : itemList) { - if (item.isSelectable()) { - return index; - } - index++; - } - throw new IllegalStateException("no selectable item in list"); - } - private void toggleSelection() { - List itemList = this.checkbox.getCheckboxItemList(); CheckboxItem checkboxItem = (CheckboxItem) itemList.get(this.selectedItemIndex); checkboxItem.setChecked(!checkboxItem.isChecked()); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 77f5c4093..98ae937eb 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -18,15 +18,13 @@ * User: Andreas Wegmann * Date: 07.01.16 */ -public class ExpandableChoicePrompt extends AbstractPrompt implements PromptIF { +public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { private ConsoleReaderImpl reader; private ExpandableChoice expandableChoice; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - private int selectedItemIndex; - ChoiceItem choosenItem; + ChoiceItem chosenItem; ChoiceItem defaultItem; private ChoiceItem errorMessageItem = new ChoiceItem(' ', "error", resourceBundle.getString("please.enter.a.valid.command")); - ArrayList itemList; enum RenderState { FOLDED, @@ -49,7 +47,7 @@ private void render() { renderHeight = 1; } else if (renderState == RenderState.FOLDED_ANSWERED) { System.out.println(""); - System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(choosenItem.getMessage()).eraseLine()); + System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(chosenItem.getMessage()).eraseLine()); System.out.print(ansi().cursorUp(2)); System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); System.out.flush(); @@ -112,7 +110,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO while (true) { if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { // if ENTER pressed - if (choosenItem != null && choosenItem.getKey() == 'h') { + if (chosenItem != null && chosenItem.getKey() == 'h') { renderState = RenderState.EXPANDED; itemList = new ArrayList(); @@ -131,9 +129,9 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO } else { renderHeight++; } - if (choosenItem != null) { - renderMessagePromptAndResult(expandableChoice.getMessage(), choosenItem.getMessage()); - hashSet.add(choosenItem.getName()); + if (chosenItem != null) { + renderMessagePromptAndResult(expandableChoice.getMessage(), chosenItem.getMessage()); + hashSet.add(chosenItem.getName()); } else { renderMessagePromptAndResult(expandableChoice.getMessage(), defaultItem.getMessage()); hashSet.add(defaultItem.getName()); @@ -148,11 +146,11 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { Character pressedKey = readerInput.getPrintableKey(); if (promptString.toLowerCase().contains("" + pressedKey)) { - // find the new choosen item + // find the new chosen item selectedItemIndex = 0; for (ChoiceItem choiceItem : choiceItems) { if (choiceItem.getKey() == pressedKey) { - choosenItem = choiceItem; + chosenItem = choiceItem; break; } selectedItemIndex++; @@ -162,43 +160,11 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO } } else { // not in valid choices - choosenItem = errorMessageItem; + chosenItem = errorMessageItem; } } render(); readerInput = this.reader.read(); } } - - private int getNextSelectableItemIndex() { - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); - ConsoleUIItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - private int getPreviousSelectableItemIndex() { - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); - ConsoleUIItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - private int getFirstSelectableItemIndex() { - int index = 0; - for (ConsoleUIItemIF item : itemList) { - if (item.isSelectable()) - return index; - index++; - } - throw new IllegalStateException("no selectable item in list"); - } - - } \ No newline at end of file diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 6704a7085..7d00042a4 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -53,5 +53,4 @@ public LinkedHashSet prompt(InputValue inputElement) throws IOException resultSet.add(readerInput.getLineInput()); return resultSet; } - } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 5c2bccc47..652639577 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ListChoice; -import de.codeshelf.consoleui.elements.items.ListItemIF; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.ListItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; @@ -9,7 +9,6 @@ import java.io.IOException; import java.util.LinkedHashSet; -import java.util.List; import static org.fusesource.jansi.Ansi.ansi; @@ -17,7 +16,7 @@ * User: Andreas Wegmann * Date: 01.01.16 */ -public class ListPrompt extends AbstractPrompt implements PromptIF { +public class ListPrompt extends AbstractListablePrompt implements PromptIF { private ListChoice listChoice; ReaderIF reader; @@ -26,7 +25,6 @@ public void setReader(ReaderIF reader) { this.reader = reader; } - int selectedItemIndex; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); public ListPrompt() { @@ -35,7 +33,6 @@ public ListPrompt() { private void render() { int itemNumber = 0; - List itemList = listChoice.getListItemList(); if (renderHeight == 0) { renderHeight = 2 + itemList.size(); @@ -44,7 +41,7 @@ private void render() { } System.out.println(renderMessagePrompt(listChoice.getMessage())); - for (ListItemIF listItem : itemList) { + for (ConsoleUIItemIF listItem : itemList) { String renderedItem = itemRenderer.render(listItem,(selectedItemIndex == itemNumber)); System.out.println(renderedItem); itemNumber++; @@ -53,7 +50,7 @@ private void render() { public LinkedHashSet prompt(ListChoice listChoice) throws IOException { this.listChoice = listChoice; - List itemList = listChoice.getListItemList(); + itemList = listChoice.getListItemList(); if (reader == null) { reader = new ConsoleReaderImpl(); } @@ -94,38 +91,4 @@ public LinkedHashSet prompt(ListChoice listChoice) throws IOException { } - private int getNextSelectableItemIndex() { - List itemList = listChoice.getListItemList(); - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); - ListItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - private int getPreviousSelectableItemIndex() { - List itemList = listChoice.getListItemList(); - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); - ListItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - private int getFirstSelectableItemIndex() { - int index = 0; - List itemList = listChoice.getListItemList(); - for (ListItemIF item : itemList) { - if (item.isSelectable()) - return index; - index++; - } - throw new IllegalStateException("no selectable item in list"); - } - - } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java deleted file mode 100644 index 95779e809..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CheckboxItemRenderer.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.codeshelf.consoleui.prompt.renderer; - -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ -public class CheckboxItemRenderer { -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java deleted file mode 100644 index f63bdf237..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/ListItemRenderer.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.codeshelf.consoleui.prompt.renderer; - -/** - * User: Andreas Wegmann - * Date: 04.01.16 - */ -public class ListItemRenderer { -} From 7040ac35cb5213eaf4d6a3b6fa155d28ef0e6950 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 19 Jan 2016 22:53:48 +0100 Subject: [PATCH 030/115] fixed minor result problems --- .../java/de/codeshelf/consoleui/Basic.java | 20 +++++++++++++------ .../prompt/ExpandableChoicePrompt.java | 8 +++++--- .../consoleui/prompt/InputPrompt.java | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index b19476497..1dca6436e 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -70,7 +70,7 @@ private static void listChoiceDemo() throws IOException { list.add(listItemBuilder.text("Five").build()); ListChoice listChoice = new ListChoice("my first list choice", null, list); LinkedHashSet result = listPrompt.prompt(listChoice); - //System.out.println("result = " + result); + System.out.println("result = " + result); } private static void checkBoxDemo() throws IOException { @@ -87,17 +87,24 @@ private static void checkBoxDemo() throws IOException { list.add(new CheckboxItem(true,"Five")); Checkbox checkbox = new Checkbox("my first checkbox", null, list); LinkedHashSet result = checkboxPrompt.prompt(checkbox); - //System.out.println("result = " + result); + System.out.println("result = " + result); } private static void inputDemo() throws IOException { + LinkedHashSet result; InputPrompt inputPrompt = new InputPrompt(); - inputPrompt.prompt(new InputValue("name", "enter your name")); - inputPrompt.prompt(new InputValue("firstname","enter your first name",null,"John")); + + result =inputPrompt.prompt(new InputValue("name", "enter your name")); + System.out.println("result = " + result); + + result =inputPrompt.prompt(new InputValue("firstname","enter your first name",null,"John")); + System.out.println("result = " + result); + InputValue branch = new InputValue("branch", "enter a branch name", null, null); branch.addCompleter(new StringsCompleter("consoleui_1","consoleui_1_412_1","consoleui_1_769_2","simplegui_4_32")); branch.addCompleter(new FileNameCompleter()); - inputPrompt.prompt(branch); + result = inputPrompt.prompt(branch); + System.out.println("result = " + result); } private static void exandableChoiceDemo() throws IOException { @@ -108,7 +115,8 @@ private static void exandableChoiceDemo() throws IOException { choiceItems.add(new ChoiceItem('d',"diff","Show diff")); choiceItems.add(new ChoiceItem('x',"abort","Abort")); ExpandableChoice expChoice=new ExpandableChoice("conflict in 'MyBestClass.java'", "conflict", choiceItems); - expandableChoicePrompt.prompt(expChoice); + LinkedHashSet result = expandableChoicePrompt.prompt(expChoice); + System.out.println("result = " + result); } private static void readBindingsDemo(ConsoleReader console) throws IOException { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 98ae937eb..14384a259 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -85,7 +85,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO for (ChoiceItem choiceItem : choiceItems) { if (choiceItem.getKey() == 'h') { - throw new IllegalStateException("expandableChoice may not use the reserved key 'h' for an element."); + throw new IllegalStateException("you may not use the reserved key 'h' for an element of expandableChoice."); } if (defaultItem == null) { defaultItem = choiceItem; @@ -139,9 +139,11 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO return hashSet; } } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - this.selectedItemIndex = getPreviousSelectableItemIndex(); + selectedItemIndex = getPreviousSelectableItemIndex(); + chosenItem = (ChoiceItem) itemList.get(selectedItemIndex); } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - this.selectedItemIndex = getNextSelectableItemIndex(); + selectedItemIndex = getNextSelectableItemIndex(); + chosenItem = (ChoiceItem) itemList.get(selectedItemIndex); } if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { Character pressedKey = readerInput.getPrintableKey(); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 7d00042a4..1a38252b6 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -50,7 +50,7 @@ public LinkedHashSet prompt(InputValue inputElement) throws IOException renderMessagePromptAndResult(inputElement.getMessage(), lineInput); LinkedHashSet resultSet = new LinkedHashSet(); - resultSet.add(readerInput.getLineInput()); + resultSet.add(lineInput); return resultSet; } } From 845166e59ad19a35622c4e43f4995fda592e6f8a Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Wed, 20 Jan 2016 16:07:29 +0100 Subject: [PATCH 031/115] added generic promt and builder --- .../consoleui/prompt/ConsolePrompt.java | 24 +++++++++++++++++++ .../consoleui/prompt/PromptBuilder.java | 17 +++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java new file mode 100644 index 000000000..95ff4c1f1 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -0,0 +1,24 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.PromptableElementIF; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; + +/** + * Created by Andreas Wegmann on 20.01.16. + */ +public class ConsolePrompt { + + public HashMap prompt(List promptableElementList) throws IOException + { + + return null; + } + + + public PromptBuilder getPromptBuilder() { + return new PromptBuilder(); + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java new file mode 100644 index 000000000..b6e1a57b6 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java @@ -0,0 +1,17 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.PromptableElementIF; + +import java.util.List; + +/** + * Created by andy on 20.01.16. + */ +public class PromptBuilder { + + + + public List build() { + return null; + } +} From 7b1cde66398eb51290372078c9775b6d98f445af Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 21 Jan 2016 07:20:21 +0100 Subject: [PATCH 032/115] added complete builder API --- .../consoleui/prompt/PromptBuilder.java | 155 ++++++++++++++++++ .../consoleui/prompt/PromptBuilderTest.java | 54 ++++++ 2 files changed, 209 insertions(+) create mode 100644 src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java index b6e1a57b6..421bb835b 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java @@ -14,4 +14,159 @@ public class PromptBuilder { public List build() { return null; } + + public InputValueBuilder createInputPrompt() { + return null; + } + + public ListPromptBuilder createListPrompt() { + return null; + } + + public ExpandableChoicePromptBuilder createChoicePrompt() { + return null; + } + + public CheckboxPromptBuilder createCheckboxPrompt() { + return null; + } + + public class InputValueBuilder { + public InputValueBuilder name(String name) { + return null; + } + + public InputValueBuilder defaultValue(String defaultValue) { + return null; + } + + public InputValueBuilder message(String message) { + return null; + } + + public PromptBuilder add() { + + return null; + } + } + + public class ListPromptBuilder { + public ListPromptBuilder name(String name) { + return null; + } + + public ListPromptBuilder message(String message) { + return null; + } + + public ListItemBuilder getItemBuilder() { + return null; + } + + public class ListItemBuilder { + public ListItemBuilder name(String name) { + return null; + } + + public ListItemBuilder text(String text) { + return null; + } + + public ListItemBuilder add() { + return null; + } + } + } + + + public class ExpandableChoicePromptBuilder { + public ExpandableChoicePromptBuilder name(String name) { + return null; + } + + public ExpandableChoicePromptBuilder text(String text) { + return null; + } + + public ExpandableChoicePromptBuilder message(String message) { + return null; + } + + public ExpandableChoiceItemBuilder getItemBuilder() { + return null; + } + + public class ExpandableChoiceItemBuilder { + public ExpandableChoiceItemBuilder name(String name1) { + return null; + } + + public ExpandableChoiceItemBuilder message(String message) { + return null; + } + + public ExpandableChoiceItemBuilder key(char key) { + return null; + } + + public ExpandableChoiceItemBuilder add() { + return null; + } + + public ExpandableChoiceItemBuilder asDefault() { + return null; + } + } + } + + public class CheckboxPromptBuilder { + public CheckboxPromptBuilder name(String name) { + return null; + } + + public CheckboxPromptBuilder message(String message) { + return null; + } + + public CheckboxItemBuilder getItemBuilder() { + return null; + } + + public class CheckboxItemBuilder { + private boolean checked; + + public CheckboxItemBuilder name(String name) { + return null; + } + + public CheckboxItemBuilder text(String text) { + return null; + } + + public CheckboxItemBuilder add() { + return null; + } + + public CheckboxItemBuilder disabledText(String disabledText) { + return null; + } + + public CheckboxItemBuilder check() { + return null; + } + + public CheckboxItemBuilder checked(boolean checked) { + this.checked = checked; + return this; + } + + public CheckboxItemBuilder separator() { + return null; + } + + public CheckboxItemBuilder separator(String text) { + return null; + } + } + } } diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java new file mode 100644 index 000000000..342814a42 --- /dev/null +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -0,0 +1,54 @@ +package de.codeshelf.consoleui.prompt; + +import org.junit.Test; + +/** + * User: ${FULL_NAME} + * Date: 20.01.16 + */ +public class PromptBuilderTest { + + @Test + public void testBuilder() throws Exception { + ConsolePrompt prompt = new ConsolePrompt(); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder.createInputPrompt() + .name("name") + .message("message") + .defaultValue("defaultValue") + .add(); + + promptBuilder.createListPrompt() + .name("name") + .message("message") + .getItemBuilder() + .name("item1.name").text("item1 text").add() + .name("item2.name").text("item2 text").add() + .name("item3.name").text("item3 text").add() + .name("item4.name").text("item4 text").add(); + + promptBuilder.createChoicePrompt() + .name("choicePrompt") + .message("choice Message") + .getItemBuilder() + .name("name1").message("message a").key('a').add() + .name("name2").message("message b").key('b').add() + .name("name3").message("message c").key('c').asDefault().add(); + + promptBuilder.createCheckboxPrompt() + .name("name") + .message("message") + .getItemBuilder() + .name("item1.name").text("item1 text").add() + .name("item2.name").text("item2 text").disabledText("I'm disabled").add() + .separator().add() + .name("item3.name").text("item3 text").check().add() + .name("item3.name").text("item3 text").add() + .separator("and the last...").add() + .name("item4.name").text("item4 text").checked(true).add(); + + + + } +} \ No newline at end of file From 1c7a481ac0083657b59af611aa7d9a975c3806d6 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Thu, 21 Jan 2016 10:48:31 +0100 Subject: [PATCH 033/115] polished API --- .../java/de/codeshelf/consoleui/Basic.java | 6 +- .../consoleui/prompt/PromptBuilder.java | 71 ++++++++++++++----- .../consoleui/prompt/PromptBuilderTest.java | 70 ++++++++++-------- 3 files changed, 97 insertions(+), 50 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 1dca6436e..1c6389af1 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -94,13 +94,13 @@ private static void inputDemo() throws IOException { LinkedHashSet result; InputPrompt inputPrompt = new InputPrompt(); - result =inputPrompt.prompt(new InputValue("name", "enter your name")); + result =inputPrompt.prompt(new InputValue("newItem", "enter your newItem")); System.out.println("result = " + result); - result =inputPrompt.prompt(new InputValue("firstname","enter your first name",null,"John")); + result =inputPrompt.prompt(new InputValue("firstname","enter your first newItem",null,"John")); System.out.println("result = " + result); - InputValue branch = new InputValue("branch", "enter a branch name", null, null); + InputValue branch = new InputValue("branch", "enter a branch newItem", null, null); branch.addCompleter(new StringsCompleter("consoleui_1","consoleui_1_412_1","consoleui_1_769_2","simplegui_4_32")); branch.addCompleter(new FileNameCompleter()); result = inputPrompt.prompt(branch); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java index 421bb835b..5649eec7a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java @@ -1,7 +1,9 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.PromptableElementIF; +import jline.console.completer.Completer; +import java.awt.peer.ChoicePeer; import java.util.List; /** @@ -10,7 +12,6 @@ public class PromptBuilder { - public List build() { return null; } @@ -44,7 +45,11 @@ public InputValueBuilder message(String message) { return null; } - public PromptBuilder add() { + public InputValueBuilder addCompleter(Completer completer) { + return null; + } + + public PromptBuilder addPrompt() { return null; } @@ -59,20 +64,29 @@ public ListPromptBuilder message(String message) { return null; } - public ListItemBuilder getItemBuilder() { + public ListItemBuilder newItem() { + return null; + } + + public ListItemBuilder newItem(String name) { + return null; + } + + public PromptBuilder addPrompt() { + return null; } public class ListItemBuilder { - public ListItemBuilder name(String name) { + public ListItemBuilder text(String text) { return null; } - public ListItemBuilder text(String text) { + public ListItemBuilder name(String name) { return null; } - public ListItemBuilder add() { + public ListPromptBuilder add() { return null; } } @@ -92,7 +106,20 @@ public ExpandableChoicePromptBuilder message(String message) { return null; } - public ExpandableChoiceItemBuilder getItemBuilder() { + public ExpandableChoiceItemBuilder newItem() { + return null; + } + + public ExpandableChoiceItemBuilder newItem(String name) { + return null; + } + + public PromptBuilder addPrompt() { + + return null; + } + + public ExpandableChoiceItemBuilder newSeparator(String text) { return null; } @@ -109,7 +136,7 @@ public ExpandableChoiceItemBuilder key(char key) { return null; } - public ExpandableChoiceItemBuilder add() { + public ExpandableChoicePromptBuilder add() { return null; } @@ -128,7 +155,23 @@ public CheckboxPromptBuilder message(String message) { return null; } - public CheckboxItemBuilder getItemBuilder() { + public CheckboxItemBuilder newItem() { + return null; + } + + public CheckboxItemBuilder newItem(String name) { + return null; + } + + public PromptBuilder addPrompt() { + return null; + } + + public CheckboxItemBuilder newSeparator() { + return null; + } + + public CheckboxItemBuilder newSeparator(String text) { return null; } @@ -143,7 +186,7 @@ public CheckboxItemBuilder text(String text) { return null; } - public CheckboxItemBuilder add() { + public CheckboxPromptBuilder add() { return null; } @@ -159,14 +202,6 @@ public CheckboxItemBuilder checked(boolean checked) { this.checked = checked; return this; } - - public CheckboxItemBuilder separator() { - return null; - } - - public CheckboxItemBuilder separator(String text) { - return null; - } } } } diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java index 342814a42..0a3216704 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -3,7 +3,7 @@ import org.junit.Test; /** - * User: ${FULL_NAME} + * User: Andreas Wegmann * Date: 20.01.16 */ public class PromptBuilderTest { @@ -15,40 +15,52 @@ public void testBuilder() throws Exception { promptBuilder.createInputPrompt() .name("name") - .message("message") - .defaultValue("defaultValue") - .add(); + .message("Please enter your name") + .defaultValue("John Doe") + .addPrompt(); promptBuilder.createListPrompt() - .name("name") - .message("message") - .getItemBuilder() - .name("item1.name").text("item1 text").add() - .name("item2.name").text("item2 text").add() - .name("item3.name").text("item3 text").add() - .name("item4.name").text("item4 text").add(); - - promptBuilder.createChoicePrompt() - .name("choicePrompt") - .message("choice Message") - .getItemBuilder() - .name("name1").message("message a").key('a').add() - .name("name2").message("message b").key('b').add() - .name("name3").message("message c").key('c').asDefault().add(); + .name("pizzatype") + .message("Which pizza do you want?") + .newItem().text("Margherita").add() // without name (name defaults to text) + .newItem("veneziana").text("Veniziana").add() + .newItem("hawai").text("Hawai").add() + .newItem("quattro").text("Quattro Stagioni").add() + .addPrompt(); promptBuilder.createCheckboxPrompt() - .name("name") - .message("message") - .getItemBuilder() - .name("item1.name").text("item1 text").add() - .name("item2.name").text("item2 text").disabledText("I'm disabled").add() - .separator().add() - .name("item3.name").text("item3 text").check().add() - .name("item3.name").text("item3 text").add() - .separator("and the last...").add() - .name("item4.name").text("item4 text").checked(true).add(); + .name("topping") + .message("Please select additional toppings:") + + .newSeparator("standard toppings").add() + + .newItem().name("cheese").text("Cheese").add() + .newItem("bacon").text("Bacon").add() + .newItem("onions").text("Onions").disabledText("Sorry. Out of stock.").add() + + .newSeparator().text("special toppings").add() + .newItem("salami").text("Very hot salami").check().add() + .newItem("salmon").text("Smoked Salmon").add() + .newSeparator("and our speciality...").add() + .newItem("special").text("Anchovies, and olives").checked(true).add() + .addPrompt(); + + promptBuilder.createChoicePrompt() + .name("payment") + .message("How do you want to pay?") + + .newItem().name("cash").message("Cash").key('c').asDefault().add() + .newItem("visa").message("Visa Card").key('v').add() + .newItem("master").message("Master Card").key('m').add() + .newSeparator("online payment").add() + .newItem("paypal").message("Paypal").key('p').add() + .addPrompt(); + + prompt.prompt(promptBuilder.build()); } + + } \ No newline at end of file From 608d46422ff0a8db792c41ede8b4d2f33709d05e Mon Sep 17 00:00:00 2001 From: awegmann Date: Fri, 22 Jan 2016 07:22:30 +0100 Subject: [PATCH 034/115] implemented fluent API --- .../java/de/codeshelf/consoleui/Basic.java | 3 +- .../consoleui/elements/Checkbox.java | 5 +- .../consoleui/elements/ExpandableChoice.java | 7 +- .../elements/PromptableElementIF.java | 2 + .../elements/items/ChoiceItemIF.java | 2 +- .../prompt/AbstractListablePrompt.java | 3 +- .../consoleui/prompt/ConsolePrompt.java | 47 +++- .../prompt/ExpandableChoicePrompt.java | 40 +-- .../consoleui/prompt/PromptBuilder.java | 253 ++++++++++++++---- .../consoleui/prompt/PromptBuilderTest.java | 7 +- 10 files changed, 290 insertions(+), 79 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 1c6389af1..b0c7bb89d 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -5,6 +5,7 @@ import de.codeshelf.consoleui.elements.InputValue; import de.codeshelf.consoleui.elements.ListChoice; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.*; import de.codeshelf.consoleui.prompt.CheckboxPrompt; @@ -109,7 +110,7 @@ private static void inputDemo() throws IOException { private static void exandableChoiceDemo() throws IOException { ExpandableChoicePrompt expandableChoicePrompt = new ExpandableChoicePrompt(); - LinkedHashSet choiceItems=new LinkedHashSet(); + LinkedHashSet choiceItems=new LinkedHashSet(); choiceItems.add(new ChoiceItem('o',"overwrite","Overwrite")); choiceItems.add(new ChoiceItem('a',"overwriteAll","Overwrite this one and all next")); choiceItems.add(new ChoiceItem('d',"diff","Show diff")); diff --git a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java index 5e67c803e..bf87b6b8c 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java +++ b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java @@ -1,7 +1,6 @@ package de.codeshelf.consoleui.elements; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import java.util.ArrayList; import java.util.List; @@ -23,7 +22,7 @@ public String getMessage() { return message; } - public ArrayList getCheckboxItemList() { - return new ArrayList(checkboxItemList); + public ArrayList getCheckboxItemList() { + return new ArrayList(checkboxItemList); } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java index 095ffd740..b1d3e724e 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java @@ -1,5 +1,6 @@ package de.codeshelf.consoleui.elements; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import java.util.LinkedHashSet; @@ -10,14 +11,14 @@ */ public class ExpandableChoice extends AbstractPromptableElement { - private LinkedHashSet choiceItems; + private LinkedHashSet choiceItems; - public ExpandableChoice(String message, String name, LinkedHashSet choiceItems) { + public ExpandableChoice(String message, String name, LinkedHashSet choiceItems) { super(message, name); this.choiceItems = choiceItems; } - public LinkedHashSet getChoiceItems() { + public LinkedHashSet getChoiceItems() { return choiceItems; } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java index f5c3e74b3..e74921b56 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java @@ -5,4 +5,6 @@ * Date: 04.01.16 */ public interface PromptableElementIF { + + String getName(); } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java index e5e0400f9..bc4e0846a 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java @@ -4,5 +4,5 @@ * User: Andreas Wegmann * Date: 13.01.16 */ -public interface ChoiceItemIF { +public interface ChoiceItemIF extends ConsoleUIItemIF { } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java index 0f1b68c09..27f3a74ca 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java @@ -1,5 +1,6 @@ package de.codeshelf.consoleui.prompt; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import java.util.ArrayList; @@ -11,7 +12,7 @@ public abstract class AbstractListablePrompt extends AbstractPrompt { protected int selectedItemIndex; - ArrayList itemList; + ArrayList itemList; protected int getNextSelectableItemIndex() { for (int i = 0; i < itemList.size(); i++) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 95ff4c1f1..1efb13e8c 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -1,9 +1,10 @@ package de.codeshelf.consoleui.prompt; -import de.codeshelf.consoleui.elements.PromptableElementIF; +import de.codeshelf.consoleui.elements.*; import java.io.IOException; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; /** @@ -11,10 +12,48 @@ */ public class ConsolePrompt { - public HashMap prompt(List promptableElementList) throws IOException - { + InputPrompt inputPrompt = new InputPrompt(); + ExpandableChoicePrompt expandableChoicePrompt = new ExpandableChoicePrompt(); + CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); + ListPrompt listPrompt = new ListPrompt(); - return null; + + public HashMap prompt(List promptableElementList) throws IOException { + HashMap resultMap = new HashMap(); + + for (int i = 0; i < promptableElementList.size(); i++) { + PromptableElementIF promptableElement = promptableElementList.get(i); + LinkedHashSet result=null; + if (promptableElement instanceof ListChoice) { + result = doPrompt((ListChoice) promptableElement); + } else if (promptableElement instanceof InputValue) { + result = doPrompt((InputValue) promptableElement); + } else if (promptableElement instanceof ExpandableChoice) { + result = doPrompt((ExpandableChoice) promptableElement); + } else if (promptableElement instanceof Checkbox) { + result = doPrompt((Checkbox) promptableElement); + } else { + throw new IllegalArgumentException("wrong type of promptable element"); + } + resultMap.put(promptableElement.getName(),result); + } + return resultMap; + } + + private LinkedHashSet doPrompt(ListChoice listChoice) throws IOException { + return listPrompt.prompt(listChoice); + } + + private LinkedHashSet doPrompt(InputValue listChoice) throws IOException { + return inputPrompt.prompt(listChoice); + } + + private LinkedHashSet doPrompt(Checkbox listChoice) throws IOException { + return checkboxPrompt.prompt(listChoice); + } + + private LinkedHashSet doPrompt(ExpandableChoice listChoice) throws IOException { + return expandableChoicePrompt.prompt(listChoice); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 14384a259..60d1a8ea0 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -1,6 +1,8 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ExpandableChoice; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; @@ -10,6 +12,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashSet; import static org.fusesource.jansi.Ansi.ansi; @@ -33,7 +36,7 @@ enum RenderState { } RenderState renderState = RenderState.FOLDED; - LinkedHashSet choiceItems; + LinkedHashSet choiceItems; String promptString; private void render() { @@ -83,15 +86,19 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO choiceItems = expandableChoice.getChoiceItems(); promptString = ""; - for (ChoiceItem choiceItem : choiceItems) { - if (choiceItem.getKey() == 'h') { - throw new IllegalStateException("you may not use the reserved key 'h' for an element of expandableChoice."); - } - if (defaultItem == null) { - defaultItem = choiceItem; + for (ChoiceItemIF choiceItem : choiceItems) { + if (choiceItem instanceof ChoiceItem) { + ChoiceItem item = (ChoiceItem) choiceItem; + + if (item.getKey() == 'h') { + throw new IllegalStateException("you may not use the reserved key 'h' for an element of expandableChoice."); + } + if (defaultItem == null) { + defaultItem = item; + } + reader.addAllowedPrintableKey(item.getKey()); + promptString += item.getKey(); } - reader.addAllowedPrintableKey(choiceItem.getKey()); - promptString += choiceItem.getKey(); } choiceItems.add(new ChoiceItem('h', "help", resourceBundle.getString("help.list.all.options"))); @@ -114,7 +121,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO renderState = RenderState.EXPANDED; itemList = new ArrayList(); - itemList.addAll(expandableChoice.getChoiceItems()); + itemList.addAll((Collection) expandableChoice.getChoiceItems()); selectedItemIndex = getFirstSelectableItemIndex(); render(); @@ -150,12 +157,15 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO if (promptString.toLowerCase().contains("" + pressedKey)) { // find the new chosen item selectedItemIndex = 0; - for (ChoiceItem choiceItem : choiceItems) { - if (choiceItem.getKey() == pressedKey) { - chosenItem = choiceItem; - break; + for (ChoiceItemIF choiceItem : choiceItems) { + if (choiceItem instanceof ChoiceItem) { + ChoiceItem item = (ChoiceItem) choiceItem; + if (item.getKey() == pressedKey) { + chosenItem = item; + break; + } + selectedItemIndex++; } - selectedItemIndex++; } if (renderState == RenderState.FOLDED) { renderState = RenderState.FOLDED_ANSWERED; diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java index 5649eec7a..ff4ee8600 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java @@ -1,122 +1,205 @@ package de.codeshelf.consoleui.prompt; -import de.codeshelf.consoleui.elements.PromptableElementIF; +import de.codeshelf.consoleui.elements.*; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; +import de.codeshelf.consoleui.elements.items.ListItemIF; +import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; +import de.codeshelf.consoleui.elements.items.impl.ListItem; +import de.codeshelf.consoleui.elements.items.impl.Separator; import jline.console.completer.Completer; -import java.awt.peer.ChoicePeer; +import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; /** - * Created by andy on 20.01.16. + * Created by Andreas Wegmann + * on 20.01.16. */ public class PromptBuilder { - + List promptList = new ArrayList(); public List build() { - return null; + return promptList; + } + + private void addPrompt(PromptableElementIF promptableElement) { + promptList.add(promptableElement); } public InputValueBuilder createInputPrompt() { - return null; + return new InputValueBuilder(this); } public ListPromptBuilder createListPrompt() { - return null; + return new ListPromptBuilder(this); } public ExpandableChoicePromptBuilder createChoicePrompt() { - return null; + return new ExpandableChoicePromptBuilder(this); } public CheckboxPromptBuilder createCheckboxPrompt() { - return null; + return new CheckboxPromptBuilder(this); } public class InputValueBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String defaultValue; + private String message; + private ArrayList completers; + + public InputValueBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } + public InputValueBuilder name(String name) { - return null; + this.name = name; + return this; } public InputValueBuilder defaultValue(String defaultValue) { - return null; + this.defaultValue = defaultValue; + return this; } public InputValueBuilder message(String message) { - return null; + this.message = message; + return this; } public InputValueBuilder addCompleter(Completer completer) { - return null; + if (completers == null) { + completers = new ArrayList(); + } + this.completers.add(completer); + return this; } public PromptBuilder addPrompt() { - - return null; + InputValue inputValue = new InputValue(name, message, null, defaultValue); + if (completers != null) { + inputValue.setCompleter(completers); + } + promptBuilder.addPrompt(inputValue); + return promptBuilder; } } public class ListPromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String message; + private List itemList = new ArrayList(); + + public ListPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } + public ListPromptBuilder name(String name) { - return null; + this.name = name; + return this; } public ListPromptBuilder message(String message) { - return null; + this.message = message; + return this; } public ListItemBuilder newItem() { - return null; + return new ListItemBuilder(this); } public ListItemBuilder newItem(String name) { - return null; + ListItemBuilder listItemBuilder = new ListItemBuilder(this); + return listItemBuilder.name(name); } public PromptBuilder addPrompt() { + ListChoice listChoice = new ListChoice(name, message, itemList); + promptBuilder.addPrompt(listChoice); + return promptBuilder; + } - return null; + private void addItem(ListItem listItem) { + this.itemList.add(listItem); } public class ListItemBuilder { + private final ListPromptBuilder listPromptBuilder; + private String text; + private String name; + + public ListItemBuilder(ListPromptBuilder listPromptBuilder) { + this.listPromptBuilder = listPromptBuilder; + } + public ListItemBuilder text(String text) { - return null; + this.text = text; + return this; } public ListItemBuilder name(String name) { - return null; + this.name = name; + return this; } public ListPromptBuilder add() { - return null; + listPromptBuilder.addItem(new ListItem(text, name)); + return listPromptBuilder; } } + } public class ExpandableChoicePromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String text; + private String message; + private LinkedHashSet itemList; + + public ExpandableChoicePromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + this.itemList = new LinkedHashSet(); + } + + private void addItem(ChoiceItemIF choiceItem) { + this.itemList.add(choiceItem); + } + public ExpandableChoicePromptBuilder name(String name) { - return null; + this.name = name; + return this; } public ExpandableChoicePromptBuilder text(String text) { - return null; + this.text = text; + return this; } public ExpandableChoicePromptBuilder message(String message) { - return null; + this.message = message; + return this; } public ExpandableChoiceItemBuilder newItem() { - return null; + return new ExpandableChoiceItemBuilder(this); } public ExpandableChoiceItemBuilder newItem(String name) { - return null; + ExpandableChoiceItemBuilder expandableChoiceItemBuilder = new ExpandableChoiceItemBuilder(this); + return expandableChoiceItemBuilder.name(name); } public PromptBuilder addPrompt() { - - return null; + ExpandableChoice expandableChoice = new ExpandableChoice(message, name, itemList); + promptBuilder.addPrompt(expandableChoice); + return promptBuilder; } public ExpandableChoiceItemBuilder newSeparator(String text) { @@ -124,78 +207,127 @@ public ExpandableChoiceItemBuilder newSeparator(String text) { } public class ExpandableChoiceItemBuilder { - public ExpandableChoiceItemBuilder name(String name1) { - return null; + private final ExpandableChoicePromptBuilder choicePromptBuilder; + private String name; + private String message; + private Character key; + + public ExpandableChoiceItemBuilder(ExpandableChoicePromptBuilder choicePromptBuilder) { + this.choicePromptBuilder = choicePromptBuilder; + } + + public ExpandableChoiceItemBuilder name(String name) { + this.name = name; + return this; } public ExpandableChoiceItemBuilder message(String message) { - return null; + this.message = message; + return this; } public ExpandableChoiceItemBuilder key(char key) { - return null; + this.key = key; + return this; } public ExpandableChoicePromptBuilder add() { - return null; + ChoiceItem choiceItem = new ChoiceItem(key, name, message); + choicePromptBuilder.addItem(choiceItem); + return choicePromptBuilder; } public ExpandableChoiceItemBuilder asDefault() { return null; } } + } public class CheckboxPromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String message; + private List itemList; + + public CheckboxPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + itemList = new ArrayList(); + } + + private void addItem(CheckboxItemIF checkboxItem) { + itemList.add(checkboxItem); + } + public CheckboxPromptBuilder name(String name) { - return null; + this.name = name; + return this; } public CheckboxPromptBuilder message(String message) { - return null; + this.message = message; + return this; } public CheckboxItemBuilder newItem() { - return null; + return new CheckboxItemBuilder(this); } public CheckboxItemBuilder newItem(String name) { - return null; + CheckboxItemBuilder checkboxItemBuilder = new CheckboxItemBuilder(this); + return checkboxItemBuilder.name(name); } public PromptBuilder addPrompt() { - return null; + Checkbox checkbox = new Checkbox(name, message, itemList); + promptBuilder.addPrompt(checkbox); + return promptBuilder; } - public CheckboxItemBuilder newSeparator() { - return null; + public CheckboxSeperatorBuilder newSeparator() { + return new CheckboxSeperatorBuilder(this); } - public CheckboxItemBuilder newSeparator(String text) { - return null; + public CheckboxSeperatorBuilder newSeparator(String text) { + CheckboxSeperatorBuilder checkboxSeperatorBuilder = new CheckboxSeperatorBuilder(this); + return checkboxSeperatorBuilder.text(text); } public class CheckboxItemBuilder { + private final CheckboxPromptBuilder checkboxPromptBuilder; private boolean checked; + private String name; + private String text; + private String disabledText; + + public CheckboxItemBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { + this.checkboxPromptBuilder = checkboxPromptBuilder; + } public CheckboxItemBuilder name(String name) { - return null; + this.name = name; + return this; } public CheckboxItemBuilder text(String text) { - return null; + this.text = text; + return this; } public CheckboxPromptBuilder add() { - return null; + CheckboxItemIF item = new CheckboxItem(checked, text, disabledText, name); + checkboxPromptBuilder.addItem(item); + return checkboxPromptBuilder; } public CheckboxItemBuilder disabledText(String disabledText) { - return null; + this.disabledText = disabledText; + return this; } public CheckboxItemBuilder check() { - return null; + this.checked = true; + return this; } public CheckboxItemBuilder checked(boolean checked) { @@ -203,5 +335,28 @@ public CheckboxItemBuilder checked(boolean checked) { return this; } } + + + public class CheckboxSeperatorBuilder { + private final CheckboxPromptBuilder promptBuilder; + private String text; + + public CheckboxSeperatorBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { + this.promptBuilder = checkboxPromptBuilder; + } + + public CheckboxPromptBuilder add() { + Separator separator = new Separator(text); + promptBuilder.addItem(separator); + + return promptBuilder; + } + + public CheckboxSeperatorBuilder text(String text) { + this.text = text; + return this; + } + } + } } diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java index 0a3216704..9b9113e54 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -1,5 +1,6 @@ package de.codeshelf.consoleui.prompt; +import jline.console.completer.StringsCompleter; import org.junit.Test; /** @@ -17,13 +18,14 @@ public void testBuilder() throws Exception { .name("name") .message("Please enter your name") .defaultValue("John Doe") + .addCompleter(new StringsCompleter("Jim", "Jack", "John")) .addPrompt(); promptBuilder.createListPrompt() .name("pizzatype") .message("Which pizza do you want?") .newItem().text("Margherita").add() // without name (name defaults to text) - .newItem("veneziana").text("Veniziana").add() + .newItem("veneziana").text("Veneziana").add() .newItem("hawai").text("Hawai").add() .newItem("quattro").text("Quattro Stagioni").add() .addPrompt(); @@ -32,7 +34,8 @@ public void testBuilder() throws Exception { .name("topping") .message("Please select additional toppings:") - .newSeparator("standard toppings").add() + .newSeparator("standard toppings") + .add() .newItem().name("cheese").text("Cheese").add() .newItem("bacon").text("Bacon").add() From 9566dee485c171e63ba18db340215b174e8336a8 Mon Sep 17 00:00:00 2001 From: awegmann Date: Fri, 22 Jan 2016 07:32:47 +0100 Subject: [PATCH 035/115] added complete builder API --- .../consoleui/prompt/ExpandableChoicePrompt.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 60d1a8ea0..6e1909a5a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -13,6 +13,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedHashSet; import static org.fusesource.jansi.Ansi.ansi; @@ -120,8 +121,11 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO if (chosenItem != null && chosenItem.getKey() == 'h') { renderState = RenderState.EXPANDED; - itemList = new ArrayList(); - itemList.addAll((Collection) expandableChoice.getChoiceItems()); + itemList = new ArrayList(); + for (Iterator iterator = expandableChoice.getChoiceItems().iterator(); iterator.hasNext(); ) { + Object next = iterator.next(); + itemList.add(next); + } selectedItemIndex = getFirstSelectableItemIndex(); render(); From 0d30dec4a4b7d936440a98d3f1c381e44fa0b9d8 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Fri, 22 Jan 2016 10:49:28 +0100 Subject: [PATCH 036/115] fixed fluent API --- .../java/de/codeshelf/consoleui/Basic.java | 8 ++-- .../consoleui/elements/ExpandableChoice.java | 7 ++-- .../elements/items/ConsoleUIItemIF.java | 2 + .../elements/items/impl/ChoiceItem.java | 12 ++++-- .../elements/items/impl/Message.java | 17 --------- .../elements/items/impl/Separator.java | 5 +++ .../prompt/AbstractListablePrompt.java | 3 +- .../prompt/ExpandableChoicePrompt.java | 20 +++------- .../consoleui/prompt/PromptBuilder.java | 37 ++++++++++++++----- .../consoleui/prompt/PromptBuilderTest.java | 8 +++- 10 files changed, 65 insertions(+), 54 deletions(-) delete mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index b0c7bb89d..91933b53b 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -111,10 +111,10 @@ private static void inputDemo() throws IOException { private static void exandableChoiceDemo() throws IOException { ExpandableChoicePrompt expandableChoicePrompt = new ExpandableChoicePrompt(); LinkedHashSet choiceItems=new LinkedHashSet(); - choiceItems.add(new ChoiceItem('o',"overwrite","Overwrite")); - choiceItems.add(new ChoiceItem('a',"overwriteAll","Overwrite this one and all next")); - choiceItems.add(new ChoiceItem('d',"diff","Show diff")); - choiceItems.add(new ChoiceItem('x',"abort","Abort")); + choiceItems.add(new ChoiceItem('o',"overwrite","Overwrite", false)); + choiceItems.add(new ChoiceItem('a',"overwriteAll","Overwrite this one and all next", false)); + choiceItems.add(new ChoiceItem('d',"diff","Show diff", false)); + choiceItems.add(new ChoiceItem('x',"abort","Abort", false)); ExpandableChoice expChoice=new ExpandableChoice("conflict in 'MyBestClass.java'", "conflict", choiceItems); LinkedHashSet result = expandableChoicePrompt.prompt(expChoice); System.out.println("result = " + result); diff --git a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java index b1d3e724e..6efae6532 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java @@ -1,8 +1,9 @@ package de.codeshelf.consoleui.elements; import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import java.util.ArrayList; import java.util.LinkedHashSet; /** @@ -18,7 +19,7 @@ public ExpandableChoice(String message, String name, LinkedHashSet this.choiceItems = choiceItems; } - public LinkedHashSet getChoiceItems() { - return choiceItems; + public ArrayList getChoiceItems() { + return new ArrayList(choiceItems); } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java index 45e585627..9a5b794e7 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java @@ -6,4 +6,6 @@ */ public interface ConsoleUIItemIF { boolean isSelectable(); + + String getName(); } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java index eb0060f6c..db7bc7e23 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java @@ -1,22 +1,22 @@ package de.codeshelf.consoleui.elements.items.impl; -import de.codeshelf.consoleui.elements.PromptableElementIF; import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; /** * User: Andreas Wegmann * Date: 07.01.16 */ -public class ChoiceItem implements PromptableElementIF, ConsoleUIItemIF, ChoiceItemIF { +public class ChoiceItem implements ChoiceItemIF { private Character key; private String name; private String message; + private boolean defaultChoice; - public ChoiceItem(Character key, String name, String message) { + public ChoiceItem(Character key, String name, String message, boolean isDefaultChoice) { this.key = key; this.name = name; this.message = message; + this.defaultChoice = isDefaultChoice; } public Character getKey() { @@ -34,4 +34,8 @@ public String getMessage() { public boolean isSelectable() { return true; } + + public boolean isDefaultChoice() { + return defaultChoice; + } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java deleted file mode 100644 index f87b03004..000000000 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Message.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.codeshelf.consoleui.elements.items.impl; - -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ -public class Message { - private final String message; - - public Message(String message) { - this.message =message; - } - - public String getMessage() { - return message; - } -} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java index bbbf1afbe..45546535f 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java @@ -26,4 +26,9 @@ public boolean isSelectable() { return false; } + @Override + public String getName() { + return null; + } + } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java index 27f3a74ca..c13ab58a3 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java @@ -2,6 +2,7 @@ import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import de.codeshelf.consoleui.elements.items.ListItemIF; import java.util.ArrayList; @@ -12,7 +13,7 @@ public abstract class AbstractListablePrompt extends AbstractPrompt { protected int selectedItemIndex; - ArrayList itemList; + ArrayList itemList; protected int getNextSelectableItemIndex() { for (int i = 0; i < itemList.size(); i++) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 6e1909a5a..2ac682d6b 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -1,8 +1,6 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ExpandableChoice; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; @@ -12,8 +10,6 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashSet; import static org.fusesource.jansi.Ansi.ansi; @@ -28,7 +24,7 @@ public class ExpandableChoicePrompt extends AbstractListablePrompt implements Pr CUIRenderer itemRenderer = CUIRenderer.getRenderer(); ChoiceItem chosenItem; ChoiceItem defaultItem; - private ChoiceItem errorMessageItem = new ChoiceItem(' ', "error", resourceBundle.getString("please.enter.a.valid.command")); + private ChoiceItem errorMessageItem = new ChoiceItem(' ', "error", resourceBundle.getString("please.enter.a.valid.command"), false); enum RenderState { FOLDED, @@ -37,7 +33,7 @@ enum RenderState { } RenderState renderState = RenderState.FOLDED; - LinkedHashSet choiceItems; + ArrayList choiceItems; String promptString; private void render() { @@ -87,7 +83,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO choiceItems = expandableChoice.getChoiceItems(); promptString = ""; - for (ChoiceItemIF choiceItem : choiceItems) { + for (ConsoleUIItemIF choiceItem : choiceItems) { if (choiceItem instanceof ChoiceItem) { ChoiceItem item = (ChoiceItem) choiceItem; @@ -102,7 +98,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO } } - choiceItems.add(new ChoiceItem('h', "help", resourceBundle.getString("help.list.all.options"))); + choiceItems.add(new ChoiceItem('h', "help", resourceBundle.getString("help.list.all.options"), false)); reader.addAllowedPrintableKey('h'); promptString += "h"; @@ -121,11 +117,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO if (chosenItem != null && chosenItem.getKey() == 'h') { renderState = RenderState.EXPANDED; - itemList = new ArrayList(); - for (Iterator iterator = expandableChoice.getChoiceItems().iterator(); iterator.hasNext(); ) { - Object next = iterator.next(); - itemList.add(next); - } + itemList = expandableChoice.getChoiceItems(); selectedItemIndex = getFirstSelectableItemIndex(); render(); @@ -161,7 +153,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO if (promptString.toLowerCase().contains("" + pressedKey)) { // find the new chosen item selectedItemIndex = 0; - for (ChoiceItemIF choiceItem : choiceItems) { + for (ConsoleUIItemIF choiceItem : choiceItems) { if (choiceItem instanceof ChoiceItem) { ChoiceItem item = (ChoiceItem) choiceItem; if (item.getKey() == pressedKey) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java index ff4ee8600..e5b4edf9f 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java @@ -159,7 +159,6 @@ public ListPromptBuilder add() { public class ExpandableChoicePromptBuilder { private final PromptBuilder promptBuilder; private String name; - private String text; private String message; private LinkedHashSet itemList; @@ -177,11 +176,6 @@ public ExpandableChoicePromptBuilder name(String name) { return this; } - public ExpandableChoicePromptBuilder text(String text) { - this.text = text; - return this; - } - public ExpandableChoicePromptBuilder message(String message) { this.message = message; return this; @@ -202,8 +196,9 @@ public PromptBuilder addPrompt() { return promptBuilder; } - public ExpandableChoiceItemBuilder newSeparator(String text) { - return null; + public ExpandableChoiceSeparatorBuilder newSeparator(String text) { + ExpandableChoiceSeparatorBuilder expandableChoiceSeparatorBuilder = new ExpandableChoiceSeparatorBuilder(this); + return expandableChoiceSeparatorBuilder.text(text); } public class ExpandableChoiceItemBuilder { @@ -211,6 +206,7 @@ public class ExpandableChoiceItemBuilder { private String name; private String message; private Character key; + private boolean asDefault; public ExpandableChoiceItemBuilder(ExpandableChoicePromptBuilder choicePromptBuilder) { this.choicePromptBuilder = choicePromptBuilder; @@ -232,16 +228,37 @@ public ExpandableChoiceItemBuilder key(char key) { } public ExpandableChoicePromptBuilder add() { - ChoiceItem choiceItem = new ChoiceItem(key, name, message); + ChoiceItem choiceItem = new ChoiceItem(key, name, message, asDefault); choicePromptBuilder.addItem(choiceItem); return choicePromptBuilder; } public ExpandableChoiceItemBuilder asDefault() { - return null; + this.asDefault = true; + return this; } } + public class ExpandableChoiceSeparatorBuilder { + private final ExpandableChoicePromptBuilder expandableChoicePromptBuilder; + private String text; + + public ExpandableChoiceSeparatorBuilder(ExpandableChoicePromptBuilder expandableChoicePromptBuilder) { + this.expandableChoicePromptBuilder = expandableChoicePromptBuilder; + } + + public ExpandableChoiceSeparatorBuilder text(String text) { + this.text = text; + return this; + } + + public ExpandableChoicePromptBuilder add() { + Separator separator = new Separator(text); + expandableChoicePromptBuilder.addItem(separator); + + return expandableChoicePromptBuilder; + } + } } public class CheckboxPromptBuilder { diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java index 9b9113e54..0639fead9 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -3,6 +3,10 @@ import jline.console.completer.StringsCompleter; import org.junit.Test; +import java.util.HashMap; + +import static org.junit.Assert.assertNotNull; + /** * User: Andreas Wegmann * Date: 20.01.16 @@ -51,6 +55,7 @@ public void testBuilder() throws Exception { .newItem("special").text("Anchovies, and olives").checked(true).add() .addPrompt(); + assertNotNull(promptBuilder); promptBuilder.createChoicePrompt() .name("payment") .message("How do you want to pay?") @@ -62,7 +67,8 @@ public void testBuilder() throws Exception { .newItem("paypal").message("Paypal").key('p').add() .addPrompt(); - prompt.prompt(promptBuilder.build()); + //HashMap result = prompt.prompt(promptBuilder.build()); + } From 51fb369bded41bb5c2e9f86337c1d80695d14d26 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Fri, 22 Jan 2016 10:55:34 +0100 Subject: [PATCH 037/115] fixed message and name bug --- .../java/de/codeshelf/consoleui/Basic.java | 59 +++++++++++++++++-- .../consoleui/prompt/PromptBuilder.java | 4 +- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 91933b53b..268948846 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -8,10 +8,7 @@ import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.*; -import de.codeshelf.consoleui.prompt.CheckboxPrompt; -import de.codeshelf.consoleui.prompt.ExpandableChoicePrompt; -import de.codeshelf.consoleui.prompt.InputPrompt; -import de.codeshelf.consoleui.prompt.ListPrompt; +import de.codeshelf.consoleui.prompt.*; import jline.TerminalFactory; import jline.console.ConsoleReader; import jline.console.Operation; @@ -21,6 +18,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -41,6 +39,59 @@ public static void main(String[] args) throws InterruptedException { try { + ConsolePrompt prompt = new ConsolePrompt(); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder.createInputPrompt() + .name("name") + .message("Please enter your name") + .defaultValue("John Doe") + .addCompleter(new StringsCompleter("Jim", "Jack", "John")) + .addPrompt(); + + promptBuilder.createListPrompt() + .name("pizzatype") + .message("Which pizza do you want?") + .newItem().text("Margherita").add() // without name (name defaults to text) + .newItem("veneziana").text("Veneziana").add() + .newItem("hawai").text("Hawai").add() + .newItem("quattro").text("Quattro Stagioni").add() + .addPrompt(); + + promptBuilder.createCheckboxPrompt() + .name("topping") + .message("Please select additional toppings:") + + .newSeparator("standard toppings") + .add() + + .newItem().name("cheese").text("Cheese").add() + .newItem("bacon").text("Bacon").add() + .newItem("onions").text("Onions").disabledText("Sorry. Out of stock.").add() + + .newSeparator().text("special toppings").add() + + .newItem("salami").text("Very hot salami").check().add() + .newItem("salmon").text("Smoked Salmon").add() + + .newSeparator("and our speciality...").add() + + .newItem("special").text("Anchovies, and olives").checked(true).add() + .addPrompt(); + + promptBuilder.createChoicePrompt() + .name("payment") + .message("How do you want to pay?") + + .newItem().name("cash").message("Cash").key('c').asDefault().add() + .newItem("visa").message("Visa Card").key('v').add() + .newItem("master").message("Master Card").key('m').add() + .newSeparator("online payment").add() + .newItem("paypal").message("Paypal").key('p').add() + .addPrompt(); + + HashMap result = prompt.prompt(promptBuilder.build()); + System.out.println("result = " + result); checkBoxDemo(); listChoiceDemo(); inputDemo(); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java index e5b4edf9f..8bb325b80 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java @@ -119,7 +119,7 @@ public ListItemBuilder newItem(String name) { } public PromptBuilder addPrompt() { - ListChoice listChoice = new ListChoice(name, message, itemList); + ListChoice listChoice = new ListChoice(message, name, itemList); promptBuilder.addPrompt(listChoice); return promptBuilder; } @@ -296,7 +296,7 @@ public CheckboxItemBuilder newItem(String name) { } public PromptBuilder addPrompt() { - Checkbox checkbox = new Checkbox(name, message, itemList); + Checkbox checkbox = new Checkbox(message, name, itemList); promptBuilder.addPrompt(checkbox); return promptBuilder; } From f4682c5e3eabaec87ced5c40509b8f4f531cac84 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Fri, 22 Jan 2016 11:13:57 +0100 Subject: [PATCH 038/115] refactored inner classe to package --- .../java/de/codeshelf/consoleui/Basic.java | 1 + .../consoleui/prompt/ConsolePrompt.java | 1 + .../consoleui/prompt/PromptBuilder.java | 379 ------------------ .../prompt/builder/CheckboxItemBuilder.java | 50 +++ .../prompt/builder/CheckboxPromptBuilder.java | 62 +++ .../builder/CheckboxSeperatorBuilder.java | 27 ++ .../builder/ExpandableChoiceItemBuilder.java | 44 ++ .../ExpandableChoicePromptBuilder.java | 56 +++ .../ExpandableChoiceSeparatorBuilder.java | 27 ++ .../prompt/builder/InputValueBuilder.java | 53 +++ .../prompt/builder/ListItemBuilder.java | 31 ++ .../prompt/builder/ListPromptBuilder.java | 52 +++ .../prompt/builder/PromptBuilder.java | 40 ++ .../consoleui/prompt/PromptBuilderTest.java | 3 +- 14 files changed, 445 insertions(+), 381 deletions(-) delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 268948846..482e40879 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -9,6 +9,7 @@ import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.*; import de.codeshelf.consoleui.prompt.*; +import de.codeshelf.consoleui.prompt.builder.PromptBuilder; import jline.TerminalFactory; import jline.console.ConsoleReader; import jline.console.Operation; diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 1efb13e8c..260962933 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -1,6 +1,7 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.*; +import de.codeshelf.consoleui.prompt.builder.PromptBuilder; import java.io.IOException; import java.util.HashMap; diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java deleted file mode 100644 index 8bb325b80..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptBuilder.java +++ /dev/null @@ -1,379 +0,0 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.*; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; -import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; -import de.codeshelf.consoleui.elements.items.impl.ListItem; -import de.codeshelf.consoleui.elements.items.impl.Separator; -import jline.console.completer.Completer; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; - -/** - * Created by Andreas Wegmann - * on 20.01.16. - */ -public class PromptBuilder { - List promptList = new ArrayList(); - - public List build() { - return promptList; - } - - private void addPrompt(PromptableElementIF promptableElement) { - promptList.add(promptableElement); - } - - public InputValueBuilder createInputPrompt() { - return new InputValueBuilder(this); - } - - public ListPromptBuilder createListPrompt() { - return new ListPromptBuilder(this); - } - - public ExpandableChoicePromptBuilder createChoicePrompt() { - return new ExpandableChoicePromptBuilder(this); - } - - public CheckboxPromptBuilder createCheckboxPrompt() { - return new CheckboxPromptBuilder(this); - } - - public class InputValueBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String defaultValue; - private String message; - private ArrayList completers; - - public InputValueBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - } - - public InputValueBuilder name(String name) { - this.name = name; - return this; - } - - public InputValueBuilder defaultValue(String defaultValue) { - this.defaultValue = defaultValue; - return this; - } - - public InputValueBuilder message(String message) { - this.message = message; - return this; - } - - public InputValueBuilder addCompleter(Completer completer) { - if (completers == null) { - completers = new ArrayList(); - } - this.completers.add(completer); - return this; - } - - public PromptBuilder addPrompt() { - InputValue inputValue = new InputValue(name, message, null, defaultValue); - if (completers != null) { - inputValue.setCompleter(completers); - } - promptBuilder.addPrompt(inputValue); - return promptBuilder; - } - } - - public class ListPromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private List itemList = new ArrayList(); - - public ListPromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - } - - public ListPromptBuilder name(String name) { - this.name = name; - return this; - } - - public ListPromptBuilder message(String message) { - this.message = message; - return this; - } - - public ListItemBuilder newItem() { - return new ListItemBuilder(this); - } - - public ListItemBuilder newItem(String name) { - ListItemBuilder listItemBuilder = new ListItemBuilder(this); - return listItemBuilder.name(name); - } - - public PromptBuilder addPrompt() { - ListChoice listChoice = new ListChoice(message, name, itemList); - promptBuilder.addPrompt(listChoice); - return promptBuilder; - } - - private void addItem(ListItem listItem) { - this.itemList.add(listItem); - } - - public class ListItemBuilder { - private final ListPromptBuilder listPromptBuilder; - private String text; - private String name; - - public ListItemBuilder(ListPromptBuilder listPromptBuilder) { - this.listPromptBuilder = listPromptBuilder; - } - - public ListItemBuilder text(String text) { - this.text = text; - return this; - } - - public ListItemBuilder name(String name) { - this.name = name; - return this; - } - - public ListPromptBuilder add() { - listPromptBuilder.addItem(new ListItem(text, name)); - return listPromptBuilder; - } - } - - } - - - public class ExpandableChoicePromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private LinkedHashSet itemList; - - public ExpandableChoicePromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - this.itemList = new LinkedHashSet(); - } - - private void addItem(ChoiceItemIF choiceItem) { - this.itemList.add(choiceItem); - } - - public ExpandableChoicePromptBuilder name(String name) { - this.name = name; - return this; - } - - public ExpandableChoicePromptBuilder message(String message) { - this.message = message; - return this; - } - - public ExpandableChoiceItemBuilder newItem() { - return new ExpandableChoiceItemBuilder(this); - } - - public ExpandableChoiceItemBuilder newItem(String name) { - ExpandableChoiceItemBuilder expandableChoiceItemBuilder = new ExpandableChoiceItemBuilder(this); - return expandableChoiceItemBuilder.name(name); - } - - public PromptBuilder addPrompt() { - ExpandableChoice expandableChoice = new ExpandableChoice(message, name, itemList); - promptBuilder.addPrompt(expandableChoice); - return promptBuilder; - } - - public ExpandableChoiceSeparatorBuilder newSeparator(String text) { - ExpandableChoiceSeparatorBuilder expandableChoiceSeparatorBuilder = new ExpandableChoiceSeparatorBuilder(this); - return expandableChoiceSeparatorBuilder.text(text); - } - - public class ExpandableChoiceItemBuilder { - private final ExpandableChoicePromptBuilder choicePromptBuilder; - private String name; - private String message; - private Character key; - private boolean asDefault; - - public ExpandableChoiceItemBuilder(ExpandableChoicePromptBuilder choicePromptBuilder) { - this.choicePromptBuilder = choicePromptBuilder; - } - - public ExpandableChoiceItemBuilder name(String name) { - this.name = name; - return this; - } - - public ExpandableChoiceItemBuilder message(String message) { - this.message = message; - return this; - } - - public ExpandableChoiceItemBuilder key(char key) { - this.key = key; - return this; - } - - public ExpandableChoicePromptBuilder add() { - ChoiceItem choiceItem = new ChoiceItem(key, name, message, asDefault); - choicePromptBuilder.addItem(choiceItem); - return choicePromptBuilder; - } - - public ExpandableChoiceItemBuilder asDefault() { - this.asDefault = true; - return this; - } - } - - public class ExpandableChoiceSeparatorBuilder { - private final ExpandableChoicePromptBuilder expandableChoicePromptBuilder; - private String text; - - public ExpandableChoiceSeparatorBuilder(ExpandableChoicePromptBuilder expandableChoicePromptBuilder) { - this.expandableChoicePromptBuilder = expandableChoicePromptBuilder; - } - - public ExpandableChoiceSeparatorBuilder text(String text) { - this.text = text; - return this; - } - - public ExpandableChoicePromptBuilder add() { - Separator separator = new Separator(text); - expandableChoicePromptBuilder.addItem(separator); - - return expandableChoicePromptBuilder; - } - } - } - - public class CheckboxPromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private List itemList; - - public CheckboxPromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - itemList = new ArrayList(); - } - - private void addItem(CheckboxItemIF checkboxItem) { - itemList.add(checkboxItem); - } - - public CheckboxPromptBuilder name(String name) { - this.name = name; - return this; - } - - public CheckboxPromptBuilder message(String message) { - this.message = message; - return this; - } - - public CheckboxItemBuilder newItem() { - return new CheckboxItemBuilder(this); - } - - public CheckboxItemBuilder newItem(String name) { - CheckboxItemBuilder checkboxItemBuilder = new CheckboxItemBuilder(this); - return checkboxItemBuilder.name(name); - } - - public PromptBuilder addPrompt() { - Checkbox checkbox = new Checkbox(message, name, itemList); - promptBuilder.addPrompt(checkbox); - return promptBuilder; - } - - public CheckboxSeperatorBuilder newSeparator() { - return new CheckboxSeperatorBuilder(this); - } - - public CheckboxSeperatorBuilder newSeparator(String text) { - CheckboxSeperatorBuilder checkboxSeperatorBuilder = new CheckboxSeperatorBuilder(this); - return checkboxSeperatorBuilder.text(text); - } - - public class CheckboxItemBuilder { - private final CheckboxPromptBuilder checkboxPromptBuilder; - private boolean checked; - private String name; - private String text; - private String disabledText; - - public CheckboxItemBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { - this.checkboxPromptBuilder = checkboxPromptBuilder; - } - - public CheckboxItemBuilder name(String name) { - this.name = name; - return this; - } - - public CheckboxItemBuilder text(String text) { - this.text = text; - return this; - } - - public CheckboxPromptBuilder add() { - CheckboxItemIF item = new CheckboxItem(checked, text, disabledText, name); - checkboxPromptBuilder.addItem(item); - return checkboxPromptBuilder; - } - - public CheckboxItemBuilder disabledText(String disabledText) { - this.disabledText = disabledText; - return this; - } - - public CheckboxItemBuilder check() { - this.checked = true; - return this; - } - - public CheckboxItemBuilder checked(boolean checked) { - this.checked = checked; - return this; - } - } - - - public class CheckboxSeperatorBuilder { - private final CheckboxPromptBuilder promptBuilder; - private String text; - - public CheckboxSeperatorBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { - this.promptBuilder = checkboxPromptBuilder; - } - - public CheckboxPromptBuilder add() { - Separator separator = new Separator(text); - promptBuilder.addItem(separator); - - return promptBuilder; - } - - public CheckboxSeperatorBuilder text(String text) { - this.text = text; - return this; - } - } - - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java new file mode 100644 index 000000000..392b03311 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java @@ -0,0 +1,50 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; + +/** + * Created by andy on 22.01.16. + */ +public class CheckboxItemBuilder { + private final CheckboxPromptBuilder checkboxPromptBuilder; + private boolean checked; + private String name; + private String text; + private String disabledText; + + public CheckboxItemBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { + this.checkboxPromptBuilder = checkboxPromptBuilder; + } + + public CheckboxItemBuilder name(String name) { + this.name = name; + return this; + } + + public CheckboxItemBuilder text(String text) { + this.text = text; + return this; + } + + public CheckboxPromptBuilder add() { + CheckboxItemIF item = new CheckboxItem(checked, text, disabledText, name); + checkboxPromptBuilder.addItem(item); + return checkboxPromptBuilder; + } + + public CheckboxItemBuilder disabledText(String disabledText) { + this.disabledText = disabledText; + return this; + } + + public CheckboxItemBuilder check() { + this.checked = true; + return this; + } + + public CheckboxItemBuilder checked(boolean checked) { + this.checked = checked; + return this; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java new file mode 100644 index 000000000..d0a52d395 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java @@ -0,0 +1,62 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by andy on 22.01.16. + */ +public class CheckboxPromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String message; + private List itemList; + + public CheckboxPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + itemList = new ArrayList(); + } + + void addItem(CheckboxItemIF checkboxItem) { + itemList.add(checkboxItem); + } + + public CheckboxPromptBuilder name(String name) { + this.name = name; + return this; + } + + public CheckboxPromptBuilder message(String message) { + this.message = message; + return this; + } + + public CheckboxItemBuilder newItem() { + return new CheckboxItemBuilder(this); + } + + public CheckboxItemBuilder newItem(String name) { + CheckboxItemBuilder checkboxItemBuilder = new CheckboxItemBuilder(this); + return checkboxItemBuilder.name(name); + } + + public PromptBuilder addPrompt() { + Checkbox checkbox = new Checkbox(message, name, itemList); + promptBuilder.addPrompt(checkbox); + return promptBuilder; + } + + public CheckboxSeperatorBuilder newSeparator() { + return new CheckboxSeperatorBuilder(this); + } + + public CheckboxSeperatorBuilder newSeparator(String text) { + CheckboxSeperatorBuilder checkboxSeperatorBuilder = new CheckboxSeperatorBuilder(this); + return checkboxSeperatorBuilder.text(text); + } + + +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java new file mode 100644 index 000000000..1e98e1b53 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java @@ -0,0 +1,27 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.items.impl.Separator; + +/** + * Created by andy on 22.01.16. + */ +public class CheckboxSeperatorBuilder { + private final CheckboxPromptBuilder promptBuilder; + private String text; + + public CheckboxSeperatorBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { + this.promptBuilder = checkboxPromptBuilder; + } + + public CheckboxPromptBuilder add() { + Separator separator = new Separator(text); + promptBuilder.addItem(separator); + + return promptBuilder; + } + + public CheckboxSeperatorBuilder text(String text) { + this.text = text; + return this; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java new file mode 100644 index 000000000..297d18731 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java @@ -0,0 +1,44 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; + +/** + * Created by andy on 22.01.16. + */ +public class ExpandableChoiceItemBuilder { + private final ExpandableChoicePromptBuilder choicePromptBuilder; + private String name; + private String message; + private Character key; + private boolean asDefault; + + public ExpandableChoiceItemBuilder(ExpandableChoicePromptBuilder choicePromptBuilder) { + this.choicePromptBuilder = choicePromptBuilder; + } + + public ExpandableChoiceItemBuilder name(String name) { + this.name = name; + return this; + } + + public ExpandableChoiceItemBuilder message(String message) { + this.message = message; + return this; + } + + public ExpandableChoiceItemBuilder key(char key) { + this.key = key; + return this; + } + + public ExpandableChoicePromptBuilder add() { + ChoiceItem choiceItem = new ChoiceItem(key, name, message, asDefault); + choicePromptBuilder.addItem(choiceItem); + return choicePromptBuilder; + } + + public ExpandableChoiceItemBuilder asDefault() { + this.asDefault = true; + return this; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java new file mode 100644 index 000000000..d131ffd35 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java @@ -0,0 +1,56 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.ExpandableChoice; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; + +import java.util.LinkedHashSet; + +/** + * Created by andy on 22.01.16. + */ +public class ExpandableChoicePromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String message; + private LinkedHashSet itemList; + + public ExpandableChoicePromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + this.itemList = new LinkedHashSet(); + } + + void addItem(ChoiceItemIF choiceItem) { + this.itemList.add(choiceItem); + } + + public ExpandableChoicePromptBuilder name(String name) { + this.name = name; + return this; + } + + public ExpandableChoicePromptBuilder message(String message) { + this.message = message; + return this; + } + + public ExpandableChoiceItemBuilder newItem() { + return new ExpandableChoiceItemBuilder(this); + } + + public ExpandableChoiceItemBuilder newItem(String name) { + ExpandableChoiceItemBuilder expandableChoiceItemBuilder = new ExpandableChoiceItemBuilder(this); + return expandableChoiceItemBuilder.name(name); + } + + public PromptBuilder addPrompt() { + ExpandableChoice expandableChoice = new ExpandableChoice(message, name, itemList); + promptBuilder.addPrompt(expandableChoice); + return promptBuilder; + } + + public ExpandableChoiceSeparatorBuilder newSeparator(String text) { + ExpandableChoiceSeparatorBuilder expandableChoiceSeparatorBuilder = new ExpandableChoiceSeparatorBuilder(this); + return expandableChoiceSeparatorBuilder.text(text); + } + +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java new file mode 100644 index 000000000..5bb6beb5d --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java @@ -0,0 +1,27 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.items.impl.Separator; + +/** + * Created by andy on 22.01.16. + */ +public class ExpandableChoiceSeparatorBuilder { + private final ExpandableChoicePromptBuilder expandableChoicePromptBuilder; + private String text; + + public ExpandableChoiceSeparatorBuilder(ExpandableChoicePromptBuilder expandableChoicePromptBuilder) { + this.expandableChoicePromptBuilder = expandableChoicePromptBuilder; + } + + public ExpandableChoiceSeparatorBuilder text(String text) { + this.text = text; + return this; + } + + public ExpandableChoicePromptBuilder add() { + Separator separator = new Separator(text); + expandableChoicePromptBuilder.addItem(separator); + + return expandableChoicePromptBuilder; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java new file mode 100644 index 000000000..e8b1f6de7 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java @@ -0,0 +1,53 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.InputValue; +import jline.console.completer.Completer; + +import java.util.ArrayList; + +/** + * Created by andy on 22.01.16. + */ +public class InputValueBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String defaultValue; + private String message; + private ArrayList completers; + + public InputValueBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } + + public InputValueBuilder name(String name) { + this.name = name; + return this; + } + + public InputValueBuilder defaultValue(String defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public InputValueBuilder message(String message) { + this.message = message; + return this; + } + + public InputValueBuilder addCompleter(Completer completer) { + if (completers == null) { + completers = new ArrayList(); + } + this.completers.add(completer); + return this; + } + + public PromptBuilder addPrompt() { + InputValue inputValue = new InputValue(name, message, null, defaultValue); + if (completers != null) { + inputValue.setCompleter(completers); + } + promptBuilder.addPrompt(inputValue); + return promptBuilder; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java new file mode 100644 index 000000000..5239d98ce --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java @@ -0,0 +1,31 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.items.impl.ListItem; + +/** + * Created by andy on 22.01.16. + */ +public class ListItemBuilder { + private final ListPromptBuilder listPromptBuilder; + private String text; + private String name; + + public ListItemBuilder(ListPromptBuilder listPromptBuilder) { + this.listPromptBuilder = listPromptBuilder; + } + + public ListItemBuilder text(String text) { + this.text = text; + return this; + } + + public ListItemBuilder name(String name) { + this.name = name; + return this; + } + + public ListPromptBuilder add() { + listPromptBuilder.addItem(new ListItem(text, name)); + return listPromptBuilder; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java new file mode 100644 index 000000000..689409958 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java @@ -0,0 +1,52 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.ListChoice; +import de.codeshelf.consoleui.elements.items.ListItemIF; +import de.codeshelf.consoleui.elements.items.impl.ListItem; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by andy on 22.01.16. + */ +public class ListPromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String message; + private List itemList = new ArrayList(); + + public ListPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } + + public ListPromptBuilder name(String name) { + this.name = name; + return this; + } + + public ListPromptBuilder message(String message) { + this.message = message; + return this; + } + + public ListItemBuilder newItem() { + return new ListItemBuilder(this); + } + + public ListItemBuilder newItem(String name) { + ListItemBuilder listItemBuilder = new ListItemBuilder(this); + return listItemBuilder.name(name); + } + + public PromptBuilder addPrompt() { + ListChoice listChoice = new ListChoice(message, name, itemList); + promptBuilder.addPrompt(listChoice); + return promptBuilder; + } + + void addItem(ListItem listItem) { + this.itemList.add(listItem); + } + +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java new file mode 100644 index 000000000..7adc5dc99 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java @@ -0,0 +1,40 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Andreas Wegmann + * on 20.01.16. + */ +public class PromptBuilder { + List promptList = new ArrayList(); + + public List build() { + return promptList; + } + + public void addPrompt(PromptableElementIF promptableElement) { + promptList.add(promptableElement); + } + + public InputValueBuilder createInputPrompt() { + return new InputValueBuilder(this); + } + + public ListPromptBuilder createListPrompt() { + return new ListPromptBuilder(this); + } + + public ExpandableChoicePromptBuilder createChoicePrompt() { + return new ExpandableChoicePromptBuilder(this); + } + + public CheckboxPromptBuilder createCheckboxPrompt() { + return new CheckboxPromptBuilder(this); + } + + +} diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java index 0639fead9..7f4c70d0f 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -1,10 +1,9 @@ package de.codeshelf.consoleui.prompt; +import de.codeshelf.consoleui.prompt.builder.PromptBuilder; import jline.console.completer.StringsCompleter; import org.junit.Test; -import java.util.HashMap; - import static org.junit.Assert.assertNotNull; /** From 09880078b6aae8ef6608c5b421d57347ec8c6ff7 Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 24 Jan 2016 23:43:19 +0100 Subject: [PATCH 039/115] added ChoicePrompt --- .../java/de/codeshelf/consoleui/Basic.java | 12 +- .../consoleui/elements/ConfirmChoice.java | 14 +++ .../prompt/AbstractListablePrompt.java | 4 + .../consoleui/prompt/AbstractPrompt.java | 14 ++- .../consoleui/prompt/CheckboxPrompt.java | 10 +- .../consoleui/prompt/ConfirmPrompt.java | 106 ++++++++++++++++++ .../consoleui/prompt/ConsolePrompt.java | 19 +++- .../prompt/ExpandableChoicePrompt.java | 10 +- .../consoleui/prompt/InputPrompt.java | 3 + .../consoleui/prompt/ListPrompt.java | 3 +- .../prompt/builder/ConfirmPromptBuilder.java | 38 +++++++ .../prompt/builder/PromptBuilder.java | 3 + .../prompt/renderer/CUIRenderer.java | 14 +++ .../resources/consoleui_messages.properties | 10 +- .../consoleui_messages_de_DE.properties | 9 +- .../consoleui/prompt/CheckboxPromptTest.java | 2 +- .../consoleui/prompt/PromptBuilderTest.java | 18 ++- 17 files changed, 261 insertions(+), 28 deletions(-) create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 482e40879..70a916e41 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -1,9 +1,6 @@ package de.codeshelf.consoleui; -import de.codeshelf.consoleui.elements.Checkbox; -import de.codeshelf.consoleui.elements.ExpandableChoice; -import de.codeshelf.consoleui.elements.InputValue; -import de.codeshelf.consoleui.elements.ListChoice; +import de.codeshelf.consoleui.elements.*; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.ChoiceItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; @@ -43,6 +40,13 @@ public static void main(String[] args) throws InterruptedException { ConsolePrompt prompt = new ConsolePrompt(); PromptBuilder promptBuilder = prompt.getPromptBuilder(); + promptBuilder.createConfirmPromp() + .name("wantapizza") + .message("Do you want to order a pizza?") + .defaultValue(ConfirmChoice.ConfirmationValue.YES) + .addPrompt(); + + promptBuilder.createInputPrompt() .name("name") .message("Please enter your name") diff --git a/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java index 5ad53b5f6..861f059f8 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java @@ -5,7 +5,21 @@ * Date: 07.01.16 */ public class ConfirmChoice extends AbstractPromptableElement { + + public enum ConfirmationValue {YES, NO} + + private ConfirmationValue defaultConfirmation = null; + public ConfirmChoice(String message, String name) { super(message, name); } + + public ConfirmChoice(String message, String name, ConfirmationValue defaultConfirmation) { + super(message, name); + this.defaultConfirmation = defaultConfirmation; + } + + public ConfirmationValue getDefaultConfirmation() { + return defaultConfirmation; + } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java index c13ab58a3..a9354036e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java @@ -4,6 +4,7 @@ import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.ListItemIF; +import java.io.IOException; import java.util.ArrayList; /** @@ -15,6 +16,9 @@ public abstract class AbstractListablePrompt extends AbstractPrompt { protected int selectedItemIndex; ArrayList itemList; + public AbstractListablePrompt() throws IOException { + } + protected int getNextSelectableItemIndex() { for (int i = 0; i < itemList.size(); i++) { int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index faa9aec89..3e826e4cf 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -1,7 +1,10 @@ package de.codeshelf.consoleui.prompt; +import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; import org.fusesource.jansi.Ansi; +import java.io.IOException; import java.util.ResourceBundle; import static org.fusesource.jansi.Ansi.ansi; @@ -10,9 +13,10 @@ * User: Andreas Wegmann * Date: 06.01.16 */ -public class AbstractPrompt { +public abstract class AbstractPrompt { protected int renderHeight; protected ResourceBundle resourceBundle; + ReaderIF reader; protected void renderMessagePromptAndResult(String message, String resultValue) { @@ -23,8 +27,12 @@ protected String renderMessagePrompt(String message) { return (ansi().fg(Ansi.Color.GREEN).a("? ").fgBright(Ansi.Color.WHITE).a(message)).fg(Ansi.Color.DEFAULT).toString(); } - public AbstractPrompt() { - resourceBundle= ResourceBundle.getBundle("consoleui_messages"); + public AbstractPrompt() throws IOException { + resourceBundle = ResourceBundle.getBundle("consoleui_messages"); + this.reader = new ConsoleReaderImpl(); } + public void setReader(ReaderIF reader) { + this.reader = reader; + } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index f34c92e94..19f8bf618 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -3,7 +3,6 @@ import de.codeshelf.consoleui.elements.Checkbox; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; -import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; import org.fusesource.jansi.Ansi; @@ -13,10 +12,10 @@ public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { private Checkbox checkbox; - ReaderIF reader; - public void setReader(ReaderIF reader) { - this.reader = reader; + + public CheckboxPrompt() throws IOException { + super(); } CUIRenderer itemRenderer = CUIRenderer.getRenderer(); @@ -42,9 +41,6 @@ public LinkedHashSet prompt(Checkbox checkbox) this.checkbox = checkbox; itemList = this.checkbox.getCheckboxItemList(); - if (this.reader == null) { - this.reader = new ConsoleReaderImpl(); - } this.reader.addAllowedPrintableKey('j'); this.reader.addAllowedPrintableKey('k'); this.reader.addAllowedPrintableKey(' '); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java new file mode 100644 index 000000000..b2bf338cd --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java @@ -0,0 +1,106 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.ConfirmChoice; +import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; +import de.codeshelf.consoleui.prompt.reader.ReaderIF; +import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; + +import java.io.IOException; +import java.util.LinkedHashSet; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: Andreas Wegmann + * Date: 06.01.16 + */ +public class ConfirmPrompt extends AbstractPrompt implements PromptIF { + + private ReaderIF reader; + CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + private ConfirmChoice confirmChoice; + char yes_key; + char no_key; + String yes_answer; + String no_answer; + ConfirmChoice.ConfirmationValue givenAnswer; + + public ConfirmPrompt() throws IOException { + super(); + yes_key = resourceBundle.getString("confirmation_yes_key").trim().charAt(0); + no_key = resourceBundle.getString("confirmation_no_key").trim().charAt(0); + yes_answer = resourceBundle.getString("confirmation_yes_answer"); + no_answer = resourceBundle.getString("confimation_no_answer"); + } + + + public LinkedHashSet prompt(ConfirmChoice confirmChoice) throws IOException { + givenAnswer = null; + this.confirmChoice = confirmChoice; + + if (reader == null) { + reader = new ConsoleReaderImpl(); + } + + if (renderHeight == 0) { + renderHeight = 1; + } else { + System.out.println(ansi().cursorUp(renderHeight)); + } + + this.reader.addAllowedPrintableKey(no_key); + this.reader.addAllowedPrintableKey(yes_key); + this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); + this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.BACKSPACE); + + render(); + ReaderIF.ReaderInput readerInput = this.reader.read(); + while (true) { + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { + if (givenAnswer != null) { + break; + } else if (confirmChoice.getDefaultConfirmation() != null) { + givenAnswer = confirmChoice.getDefaultConfirmation(); + break; + } + } + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { + if (readerInput.getPrintableKey().equals(yes_key)) { + givenAnswer = ConfirmChoice.ConfirmationValue.YES; + } else if (readerInput.getPrintableKey().equals(no_key)) { + givenAnswer = ConfirmChoice.ConfirmationValue.NO; + } + } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.BACKSPACE) { + givenAnswer = null; + } + render(); + readerInput = this.reader.read(); + } + String resultValue = calcResultValue(); + + System.out.println(); + renderMessagePromptAndResult(confirmChoice.getMessage(), resultValue); + + LinkedHashSet resultSet = new LinkedHashSet(); + resultSet.add(givenAnswer.toString()); + return resultSet; + } + + private void render() { + System.out.println(""); + System.out.println(ansi().eraseLine().cursorUp(2)); + System.out.print(renderMessagePrompt(this.confirmChoice.getMessage()) + + itemRenderer.renderConfirmChoiceOptions(this.confirmChoice) + " " + ansi().reset().a(calcResultValue()+" ").eraseLine()); + System.out.flush(); + renderHeight = 1; + } + + private String calcResultValue() { + if (givenAnswer == ConfirmChoice.ConfirmationValue.YES) { + return yes_answer; + } else if (givenAnswer == ConfirmChoice.ConfirmationValue.NO) { + return no_answer; + } + return ""; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 260962933..125364e57 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -13,10 +13,17 @@ */ public class ConsolePrompt { - InputPrompt inputPrompt = new InputPrompt(); - ExpandableChoicePrompt expandableChoicePrompt = new ExpandableChoicePrompt(); - CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); + InputPrompt inputPrompt; + ExpandableChoicePrompt expandableChoicePrompt; + CheckboxPrompt checkboxPrompt; ListPrompt listPrompt = new ListPrompt(); + ConfirmPrompt confirmPrompt = new ConfirmPrompt(); + + public ConsolePrompt() throws IOException { + inputPrompt = new InputPrompt(); + checkboxPrompt = new CheckboxPrompt(); + expandableChoicePrompt = new ExpandableChoicePrompt(); + } public HashMap prompt(List promptableElementList) throws IOException { @@ -33,6 +40,8 @@ public HashMap prompt(List promptableElemen result = doPrompt((ExpandableChoice) promptableElement); } else if (promptableElement instanceof Checkbox) { result = doPrompt((Checkbox) promptableElement); + } else if (promptableElement instanceof ConfirmChoice) { + result = doPrompt((ConfirmChoice) promptableElement); } else { throw new IllegalArgumentException("wrong type of promptable element"); } @@ -41,6 +50,10 @@ public HashMap prompt(List promptableElemen return resultMap; } + private LinkedHashSet doPrompt(ConfirmChoice confirmChoice) throws IOException { + return confirmPrompt.prompt(confirmChoice); + } + private LinkedHashSet doPrompt(ListChoice listChoice) throws IOException { return listPrompt.prompt(listChoice); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 2ac682d6b..087cf453e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -3,7 +3,6 @@ import de.codeshelf.consoleui.elements.ExpandableChoice; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; -import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; import org.fusesource.jansi.Ansi; @@ -19,13 +18,15 @@ * Date: 07.01.16 */ public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { - private ConsoleReaderImpl reader; private ExpandableChoice expandableChoice; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); ChoiceItem chosenItem; ChoiceItem defaultItem; private ChoiceItem errorMessageItem = new ChoiceItem(' ', "error", resourceBundle.getString("please.enter.a.valid.command"), false); + public ExpandableChoicePrompt() throws IOException { + } + enum RenderState { FOLDED, FOLDED_ANSWERED, @@ -76,9 +77,6 @@ private void renderList() { public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IOException { this.expandableChoice = expandableChoice; - if (reader == null) { - reader = new ConsoleReaderImpl(); - } choiceItems = expandableChoice.getChoiceItems(); promptString = ""; @@ -94,7 +92,7 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO defaultItem = item; } reader.addAllowedPrintableKey(item.getKey()); - promptString += item.getKey(); + promptString += item.isDefaultChoice() ? item.getKey().toString().toUpperCase() : item.getKey(); } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 1a38252b6..2fca2fb5a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -22,6 +22,9 @@ public class InputPrompt extends AbstractPrompt implements PromptIF private ReaderIF reader; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + public InputPrompt() throws IOException { + } + public LinkedHashSet prompt(InputValue inputElement) throws IOException { this.inputElement = inputElement; diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 652639577..3991d9462 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -27,7 +27,8 @@ public void setReader(ReaderIF reader) { CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - public ListPrompt() { + public ListPrompt() throws IOException { + super(); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java new file mode 100644 index 000000000..8c09a2a87 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java @@ -0,0 +1,38 @@ +package de.codeshelf.consoleui.prompt.builder; + +import de.codeshelf.consoleui.elements.ConfirmChoice; + +/** + * User: ${FULL_NAME} + * Date: 24.01.16 + */ +public class ConfirmPromptBuilder { + private final PromptBuilder promptBuilder; + private String name; + private String message; + private ConfirmChoice.ConfirmationValue defaultConfirmationValue; + + public ConfirmPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } + + public ConfirmPromptBuilder name(String name) { + this.name = name; + return this; + } + + public ConfirmPromptBuilder message(String message) { + this.message = message; + return this; + } + + public ConfirmPromptBuilder defaultValue(ConfirmChoice.ConfirmationValue confirmationValue) { + this.defaultConfirmationValue = confirmationValue; + return this; + } + + public PromptBuilder addPrompt() { + promptBuilder.addPrompt(new ConfirmChoice(message, name, defaultConfirmationValue)); + return promptBuilder; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java index 7adc5dc99..c3a71a642 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java @@ -37,4 +37,7 @@ public CheckboxPromptBuilder createCheckboxPrompt() { } + public ConfirmPromptBuilder createConfirmPromp() { + return new ConfirmPromptBuilder(this); + } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 83dc577bd..57ea0e71d 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -1,5 +1,6 @@ package de.codeshelf.consoleui.prompt.renderer; +import de.codeshelf.consoleui.elements.ConfirmChoice; import de.codeshelf.consoleui.elements.InputValue; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; @@ -8,6 +9,8 @@ import de.codeshelf.consoleui.elements.items.impl.Separator; import org.fusesource.jansi.Ansi; +import java.util.ResourceBundle; + import static org.fusesource.jansi.Ansi.ansi; /** @@ -24,6 +27,7 @@ public class CUIRenderer { private final String line; private static CUIRenderer renderer = new CUIRenderer(); + private final ResourceBundle resourceBundle; public CUIRenderer() { checkedBox = "\u25C9 "; @@ -31,6 +35,7 @@ public CUIRenderer() { line = "\u2500─────────────"; cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("❯ ").toString(); noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); + resourceBundle = ResourceBundle.getBundle("consoleui_messages"); } public static CUIRenderer getRenderer() { @@ -98,4 +103,13 @@ public String renderValue(InputValue inputElement) { } return ""; } + + public String renderConfirmChoiceOptions(ConfirmChoice confirmChoice) { + if (confirmChoice.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.YES) { + return resourceBundle.getString("confirmation_yes_default"); + } else if (confirmChoice.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.NO) { + return resourceBundle.getString("confirmation_no_default"); + } + return resourceBundle.getString("confimation_without_default"); + } } diff --git a/src/main/resources/consoleui_messages.properties b/src/main/resources/consoleui_messages.properties index a0a9787bb..4404ca69a 100644 --- a/src/main/resources/consoleui_messages.properties +++ b/src/main/resources/consoleui_messages.properties @@ -1,2 +1,10 @@ +confimation_without_default=\ (y/n) +confirmation_no_default=\ (y/N) +confirmation_yes_default=\ (Y/n) +confirmation_yes_key=y +confirmation_no_key=n + help.list.all.options=Help, list all options -please.enter.a.valid.command=Please enter a valid command \ No newline at end of file +please.enter.a.valid.command=Please enter a valid command +confimation_no_answer=no +confirmation_yes_answer=yes \ No newline at end of file diff --git a/src/main/resources/consoleui_messages_de_DE.properties b/src/main/resources/consoleui_messages_de_DE.properties index 963f43fc2..79ec121e5 100644 --- a/src/main/resources/consoleui_messages_de_DE.properties +++ b/src/main/resources/consoleui_messages_de_DE.properties @@ -1,2 +1,9 @@ +confimation_without_default=\ (j/n) +confirmation_no_default=\ (j/N) +confirmation_yes_default=\ (J/n) +confirmation_yes_key=j +confirmation_no_key=n help.list.all.options=Hilfe. Listet alle Optionen. -please.enter.a.valid.command=Bitte ein gültiges Kürzel eingeben. \ No newline at end of file +please.enter.a.valid.command=Bitte ein gültiges Kürzel eingeben. +confimation_no_answer=Nein +confirmation_yes_answer=Ja \ No newline at end of file diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java index 21de3b798..5b454e5e4 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -32,7 +32,7 @@ public void renderSimpleList() throws IOException { list.add(new CheckboxItem("Four")); list.add(new CheckboxItem(true,"Five")); - checkboxPrompt. setReader(new ReaderIF() { + checkboxPrompt.setReader(new ReaderIF() { public void setAllowedSpecialKeys(Set allowedSpecialKeys) { } diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java index 7f4c70d0f..2c66e21d3 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -1,9 +1,14 @@ package de.codeshelf.consoleui.prompt; +import de.codeshelf.consoleui.elements.ConfirmChoice; +import de.codeshelf.consoleui.elements.PromptableElementIF; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; import jline.console.completer.StringsCompleter; import org.junit.Test; +import java.util.HashMap; +import java.util.List; + import static org.junit.Assert.assertNotNull; /** @@ -17,6 +22,12 @@ public void testBuilder() throws Exception { ConsolePrompt prompt = new ConsolePrompt(); PromptBuilder promptBuilder = prompt.getPromptBuilder(); + promptBuilder.createConfirmPromp() + .name("wantapizza") + .message("Do you want to order a pizza?") + .defaultValue(ConfirmChoice.ConfirmationValue.YES) + .addPrompt(); + promptBuilder.createInputPrompt() .name("name") .message("Please enter your name") @@ -66,7 +77,12 @@ public void testBuilder() throws Exception { .newItem("paypal").message("Paypal").key('p').add() .addPrompt(); - //HashMap result = prompt.prompt(promptBuilder.build()); + List promptableElementList = promptBuilder.build(); + + // only for test. reset the default reader to a test reader to automate the input + //promptableElementList.get(0) + + //HashMap result = prompt.prompt(promptableElementList); } From e969b0a5346cbc582182b0408dbbd17fab1ef992 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 26 Jan 2016 22:05:36 +0100 Subject: [PATCH 040/115] added alternative rendering for windows --- .../prompt/renderer/CUIRenderer.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 57ea0e71d..d80392033 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -30,11 +30,20 @@ public class CUIRenderer { private final ResourceBundle resourceBundle; public CUIRenderer() { - checkedBox = "\u25C9 "; - uncheckedBox = "\u25EF "; - line = "\u2500─────────────"; - cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("❯ ").toString(); - noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); + String os = System.getProperty("os.name"); + if( os.startsWith("Windows") ) { + checkedBox = "(*) "; + uncheckedBox = "( ) "; + line = "---------"; + cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("> ").toString(); + noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); + } else { + checkedBox = "\u25C9 "; + uncheckedBox = "\u25EF "; + line = "\u2500─────────────"; + cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("❯ ").toString(); + noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); + } resourceBundle = ResourceBundle.getBundle("consoleui_messages"); } From 846c7ed5157e99d6c46bb1777a8bbfd99e9fc1c4 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Wed, 3 Feb 2016 10:32:39 +0100 Subject: [PATCH 041/115] removed old demo --- src/main/java/de/codeshelf/consoleui/Basic.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 70a916e41..bd65ad7fc 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -97,10 +97,10 @@ public static void main(String[] args) throws InterruptedException { HashMap result = prompt.prompt(promptBuilder.build()); System.out.println("result = " + result); - checkBoxDemo(); - listChoiceDemo(); - inputDemo(); - exandableChoiceDemo(); + //checkBoxDemo(); + //listChoiceDemo(); + //inputDemo(); + //exandableChoiceDemo(); } catch (IOException e) { e.printStackTrace(); } finally { From 446b85b3544f780534071f8a05a1da668457a135 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Wed, 3 Feb 2016 21:50:05 +0100 Subject: [PATCH 042/115] refactored results --- .../de/codeshelf/consoleui/prompt/ListPrompt.java | 7 +++---- .../de/codeshelf/consoleui/prompt/ListResult.java | 12 ++++++++++++ .../java/de/codeshelf/consoleui/prompt/PromptIF.java | 4 ++-- .../consoleui/prompt/PromtResultItemIF.java | 7 +++++++ 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ListResult.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 3991d9462..31966b2fa 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -16,7 +16,7 @@ * User: Andreas Wegmann * Date: 01.01.16 */ -public class ListPrompt extends AbstractListablePrompt implements PromptIF { +public class ListPrompt extends AbstractListablePrompt implements PromptIF { private ListChoice listChoice; ReaderIF reader; @@ -49,7 +49,7 @@ private void render() { } } - public LinkedHashSet prompt(ListChoice listChoice) throws IOException { + public ListResult prompt(ListChoice listChoice) throws IOException { this.listChoice = listChoice; itemList = listChoice.getListItemList(); if (reader == null) { @@ -83,10 +83,9 @@ public LinkedHashSet prompt(ListChoice listChoice) throws IOException { readerInput = reader.read(); } - LinkedHashSet selection = new LinkedHashSet(); ListItem listItem = (ListItem) itemList.get(selectedItemIndex); - selection.add(listItem.getName()); + ListResult selection=new ListResult(listItem.getName()); renderMessagePromptAndResult(listChoice.getMessage(),selection.toString()); return selection ; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java new file mode 100644 index 000000000..bcfdf380e --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java @@ -0,0 +1,12 @@ +package de.codeshelf.consoleui.prompt; + +/** + * Created by Andreas Wegmann on 03.02.16. + */ +public class ListResult implements PromtResultItemIF { + String selectedId; + + public ListResult(String selectedId) { + this.selectedId = selectedId; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java index 79da1d248..67fc85f75 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java @@ -9,6 +9,6 @@ * User: Andreas Wegmann * Date: 01.01.16 */ -public interface PromptIF { - LinkedHashSet prompt(T promptableElement) throws IOException; +public interface PromptIF { + R prompt(T promptableElement) throws IOException; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java new file mode 100644 index 000000000..fa6448852 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java @@ -0,0 +1,7 @@ +package de.codeshelf.consoleui.prompt; + +/** + * Created by Andreas Wegmann on 03.02.16. + */ +public interface PromtResultItemIF { +} From 15c1985c94ffd50eb042a9507bddd28eec57f4a4 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 3 Feb 2016 22:42:58 +0100 Subject: [PATCH 043/115] refactored to explicit result types --- .../java/de/codeshelf/consoleui/Basic.java | 10 +++--- .../elements/items/impl/ListItem.java | 4 ++- .../consoleui/prompt/CheckboxPrompt.java | 12 ++++--- .../consoleui/prompt/CheckboxResult.java | 26 ++++++++++++++++ .../consoleui/prompt/ConfirmPrompt.java | 8 ++--- .../consoleui/prompt/ConfirmResult.java | 26 ++++++++++++++++ .../consoleui/prompt/ConsolePrompt.java | 31 ++++++++++--------- .../prompt/ExpandableChoicePrompt.java | 11 +++---- .../prompt/ExpandableChoiceResult.java | 24 ++++++++++++++ .../consoleui/prompt/InputPrompt.java | 8 ++--- .../consoleui/prompt/InputResult.java | 24 ++++++++++++++ .../consoleui/prompt/ListPrompt.java | 2 +- .../consoleui/prompt/ListResult.java | 7 +++++ 13 files changed, 150 insertions(+), 43 deletions(-) create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java create mode 100644 src/main/java/de/codeshelf/consoleui/prompt/InputResult.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index bd65ad7fc..d82f8f30b 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -95,7 +95,7 @@ public static void main(String[] args) throws InterruptedException { .newItem("paypal").message("Paypal").key('p').add() .addPrompt(); - HashMap result = prompt.prompt(promptBuilder.build()); + HashMap result = prompt.prompt(promptBuilder.build()); System.out.println("result = " + result); //checkBoxDemo(); //listChoiceDemo(); @@ -126,7 +126,7 @@ private static void listChoiceDemo() throws IOException { list.add(new Separator()); list.add(listItemBuilder.text("Five").build()); ListChoice listChoice = new ListChoice("my first list choice", null, list); - LinkedHashSet result = listPrompt.prompt(listChoice); + ListResult result = listPrompt.prompt(listChoice); System.out.println("result = " + result); } @@ -143,12 +143,12 @@ private static void checkBoxDemo() throws IOException { list.add(new Separator()); list.add(new CheckboxItem(true,"Five")); Checkbox checkbox = new Checkbox("my first checkbox", null, list); - LinkedHashSet result = checkboxPrompt.prompt(checkbox); + CheckboxResult result = checkboxPrompt.prompt(checkbox); System.out.println("result = " + result); } private static void inputDemo() throws IOException { - LinkedHashSet result; + InputResult result; InputPrompt inputPrompt = new InputPrompt(); result =inputPrompt.prompt(new InputValue("newItem", "enter your newItem")); @@ -172,7 +172,7 @@ private static void exandableChoiceDemo() throws IOException { choiceItems.add(new ChoiceItem('d',"diff","Show diff", false)); choiceItems.add(new ChoiceItem('x',"abort","Abort", false)); ExpandableChoice expChoice=new ExpandableChoice("conflict in 'MyBestClass.java'", "conflict", choiceItems); - LinkedHashSet result = expandableChoicePrompt.prompt(expChoice); + ExpandableChoiceResult result = expandableChoicePrompt.prompt(expChoice); System.out.println("result = " + result); } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java index 3225fb654..d14c2e380 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java @@ -12,7 +12,9 @@ public class ListItem implements ListItemIF { public ListItem(String text, String name) { this.text = text; - this.name = name; + if (name ==null) { + this.name = text; + } } public ListItem(String text) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index 19f8bf618..cbc22fe2c 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -8,9 +8,9 @@ import org.fusesource.jansi.Ansi; import java.io.IOException; -import java.util.LinkedHashSet; +import java.util.HashSet; -public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { +public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { private Checkbox checkbox; @@ -36,7 +36,7 @@ private void render() { } } - public LinkedHashSet prompt(Checkbox checkbox) + public CheckboxResult prompt(Checkbox checkbox) throws IOException { this.checkbox = checkbox; itemList = this.checkbox.getCheckboxItemList(); @@ -69,7 +69,9 @@ public LinkedHashSet prompt(Checkbox checkbox) render(); readerInput = this.reader.read(); } - LinkedHashSet selections = new LinkedHashSet(); + + HashSet selections = new HashSet(); + for (ConsoleUIItemIF item : itemList) { if ((item instanceof CheckboxItem)) { CheckboxItem checkboxItem = (CheckboxItem) item; @@ -79,7 +81,7 @@ public LinkedHashSet prompt(Checkbox checkbox) } } renderMessagePromptAndResult(checkbox.getMessage(), selections.toString()); - return selections; + return new CheckboxResult(selections); } private void toggleSelection() { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java new file mode 100644 index 000000000..fb3e72c6b --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java @@ -0,0 +1,26 @@ +package de.codeshelf.consoleui.prompt; + +import java.util.HashSet; + +/** + * User: ${FULL_NAME} + * Date: 03.02.16 + */ +public class CheckboxResult implements PromtResultItemIF { + HashSet selectedIds; + + public CheckboxResult(HashSet selectedIds) { + this.selectedIds = selectedIds; + } + + public HashSet getSelectedIds() { + return selectedIds; + } + + @Override + public String toString() { + return "CheckboxResult{" + + "selectedIds=" + selectedIds + + '}'; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java index b2bf338cd..d1d8cbfaf 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java @@ -14,7 +14,7 @@ * User: Andreas Wegmann * Date: 06.01.16 */ -public class ConfirmPrompt extends AbstractPrompt implements PromptIF { +public class ConfirmPrompt extends AbstractPrompt implements PromptIF { private ReaderIF reader; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); @@ -34,7 +34,7 @@ public ConfirmPrompt() throws IOException { } - public LinkedHashSet prompt(ConfirmChoice confirmChoice) throws IOException { + public ConfirmResult prompt(ConfirmChoice confirmChoice) throws IOException { givenAnswer = null; this.confirmChoice = confirmChoice; @@ -81,9 +81,7 @@ public LinkedHashSet prompt(ConfirmChoice confirmChoice) throws IOExcept System.out.println(); renderMessagePromptAndResult(confirmChoice.getMessage(), resultValue); - LinkedHashSet resultSet = new LinkedHashSet(); - resultSet.add(givenAnswer.toString()); - return resultSet; + return new ConfirmResult(givenAnswer); } private void render() { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java new file mode 100644 index 000000000..311543150 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java @@ -0,0 +1,26 @@ +package de.codeshelf.consoleui.prompt; + +import de.codeshelf.consoleui.elements.ConfirmChoice; + +/** + * User: ${FULL_NAME} + * Date: 03.02.16 + */ +public class ConfirmResult implements PromtResultItemIF { + ConfirmChoice.ConfirmationValue confirmed; + + public ConfirmResult(ConfirmChoice.ConfirmationValue confirm) { + this.confirmed = confirm; + } + + public ConfirmChoice.ConfirmationValue getConfirmed() { + return confirmed; + } + + @Override + public String toString() { + return "ConfirmResult{" + + "confirmed=" + confirmed + + '}'; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 125364e57..bef459a18 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -26,47 +26,50 @@ public ConsolePrompt() throws IOException { } - public HashMap prompt(List promptableElementList) throws IOException { - HashMap resultMap = new HashMap(); + public HashMap prompt(List promptableElementList) throws IOException { + HashMap resultMap = new HashMap(); for (int i = 0; i < promptableElementList.size(); i++) { PromptableElementIF promptableElement = promptableElementList.get(i); - LinkedHashSet result=null; if (promptableElement instanceof ListChoice) { - result = doPrompt((ListChoice) promptableElement); + ListResult result = doPrompt((ListChoice) promptableElement); + resultMap.put(promptableElement.getName(),result); } else if (promptableElement instanceof InputValue) { - result = doPrompt((InputValue) promptableElement); + InputResult result = doPrompt((InputValue) promptableElement); + resultMap.put(promptableElement.getName(),result); } else if (promptableElement instanceof ExpandableChoice) { - result = doPrompt((ExpandableChoice) promptableElement); + ExpandableChoiceResult result = doPrompt((ExpandableChoice) promptableElement); + resultMap.put(promptableElement.getName(),result); } else if (promptableElement instanceof Checkbox) { - result = doPrompt((Checkbox) promptableElement); + CheckboxResult result = doPrompt((Checkbox) promptableElement); + resultMap.put(promptableElement.getName(),result); } else if (promptableElement instanceof ConfirmChoice) { - result = doPrompt((ConfirmChoice) promptableElement); + ConfirmResult result = doPrompt((ConfirmChoice) promptableElement); + resultMap.put(promptableElement.getName(),result); } else { throw new IllegalArgumentException("wrong type of promptable element"); } - resultMap.put(promptableElement.getName(),result); } return resultMap; } - private LinkedHashSet doPrompt(ConfirmChoice confirmChoice) throws IOException { + private ConfirmResult doPrompt(ConfirmChoice confirmChoice) throws IOException { return confirmPrompt.prompt(confirmChoice); } - private LinkedHashSet doPrompt(ListChoice listChoice) throws IOException { + private ListResult doPrompt(ListChoice listChoice) throws IOException { return listPrompt.prompt(listChoice); } - private LinkedHashSet doPrompt(InputValue listChoice) throws IOException { + private InputResult doPrompt(InputValue listChoice) throws IOException { return inputPrompt.prompt(listChoice); } - private LinkedHashSet doPrompt(Checkbox listChoice) throws IOException { + private CheckboxResult doPrompt(Checkbox listChoice) throws IOException { return checkboxPrompt.prompt(listChoice); } - private LinkedHashSet doPrompt(ExpandableChoice listChoice) throws IOException { + private ExpandableChoiceResult doPrompt(ExpandableChoice listChoice) throws IOException { return expandableChoicePrompt.prompt(listChoice); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 087cf453e..3031a34d5 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -9,7 +9,6 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.LinkedHashSet; import static org.fusesource.jansi.Ansi.ansi; @@ -17,7 +16,7 @@ * User: Andreas Wegmann * Date: 07.01.16 */ -public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { +public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { private ExpandableChoice expandableChoice; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); ChoiceItem chosenItem; @@ -75,7 +74,7 @@ private void renderList() { } } - public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IOException { + public ExpandableChoiceResult prompt(ExpandableChoice expandableChoice) throws IOException { this.expandableChoice = expandableChoice; choiceItems = expandableChoice.getChoiceItems(); @@ -124,7 +123,6 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO readerInput = this.reader.read(); } else { - LinkedHashSet hashSet = new LinkedHashSet(); if (renderState != RenderState.EXPANDED) { System.out.println(""); } else { @@ -132,12 +130,11 @@ public LinkedHashSet prompt(ExpandableChoice expandableChoice) throws IO } if (chosenItem != null) { renderMessagePromptAndResult(expandableChoice.getMessage(), chosenItem.getMessage()); - hashSet.add(chosenItem.getName()); + return new ExpandableChoiceResult(chosenItem.getName()); } else { renderMessagePromptAndResult(expandableChoice.getMessage(), defaultItem.getMessage()); - hashSet.add(defaultItem.getName()); + return new ExpandableChoiceResult(defaultItem.getName()); } - return hashSet; } } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { selectedItemIndex = getPreviousSelectableItemIndex(); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java new file mode 100644 index 000000000..5470a9f1d --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java @@ -0,0 +1,24 @@ +package de.codeshelf.consoleui.prompt; + +/** + * User: ${FULL_NAME} + * Date: 03.02.16 + */ +public class ExpandableChoiceResult implements PromtResultItemIF { + String selectedId; + + public ExpandableChoiceResult(String selectedId) { + this.selectedId = selectedId; + } + + public String getSelectedId() { + return selectedId; + } + + @Override + public String toString() { + return "ExpandableChoiceResult{" + + "selectedId='" + selectedId + '\'' + + '}'; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 2fca2fb5a..e04f1654d 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -16,7 +16,7 @@ * User: Andreas Wegmann * Date: 06.01.16 */ -public class InputPrompt extends AbstractPrompt implements PromptIF { +public class InputPrompt extends AbstractPrompt implements PromptIF { private InputValue inputElement; private ReaderIF reader; @@ -26,7 +26,7 @@ public InputPrompt() throws IOException { } - public LinkedHashSet prompt(InputValue inputElement) throws IOException { + public InputResult prompt(InputValue inputElement) throws IOException { this.inputElement = inputElement; if (reader == null) { @@ -52,8 +52,6 @@ public LinkedHashSet prompt(InputValue inputElement) throws IOException } renderMessagePromptAndResult(inputElement.getMessage(), lineInput); - LinkedHashSet resultSet = new LinkedHashSet(); - resultSet.add(lineInput); - return resultSet; + return new InputResult(lineInput); } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java b/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java new file mode 100644 index 000000000..adf897d43 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java @@ -0,0 +1,24 @@ +package de.codeshelf.consoleui.prompt; + +/** + * User: ${FULL_NAME} + * Date: 03.02.16 + */ +public class InputResult implements PromtResultItemIF { + String input; + + public InputResult(String input) { + this.input = input; + } + + public String getInput() { + return input; + } + + @Override + public String toString() { + return "InputResult{" + + "input='" + input + '\'' + + '}'; + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 31966b2fa..6a0556f04 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -86,7 +86,7 @@ public ListResult prompt(ListChoice listChoice) throws IOException { ListItem listItem = (ListItem) itemList.get(selectedItemIndex); ListResult selection=new ListResult(listItem.getName()); - renderMessagePromptAndResult(listChoice.getMessage(),selection.toString()); + renderMessagePromptAndResult(listChoice.getMessage(),((ListItem) itemList.get(selectedItemIndex)).getText()); return selection ; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java index bcfdf380e..19064ad58 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java @@ -9,4 +9,11 @@ public class ListResult implements PromtResultItemIF { public ListResult(String selectedId) { this.selectedId = selectedId; } + + @Override + public String toString() { + return "ListResult{" + + "selectedId='" + selectedId + '\'' + + '}'; + } } From 8ac69b6ff255712b7a75955b88618325cf7afc05 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 3 Feb 2016 23:04:13 +0100 Subject: [PATCH 044/115] changed demo class a bit --- .../java/de/codeshelf/consoleui/Basic.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index d82f8f30b..e7dd1835a 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -40,12 +40,6 @@ public static void main(String[] args) throws InterruptedException { ConsolePrompt prompt = new ConsolePrompt(); PromptBuilder promptBuilder = prompt.getPromptBuilder(); - promptBuilder.createConfirmPromp() - .name("wantapizza") - .message("Do you want to order a pizza?") - .defaultValue(ConfirmChoice.ConfirmationValue.YES) - .addPrompt(); - promptBuilder.createInputPrompt() .name("name") @@ -95,12 +89,19 @@ public static void main(String[] args) throws InterruptedException { .newItem("paypal").message("Paypal").key('p').add() .addPrompt(); + promptBuilder.createConfirmPromp() + .name("delivery") + .message("Is this pizza for delivery?") + .defaultValue(ConfirmChoice.ConfirmationValue.YES) + .addPrompt(); + HashMap result = prompt.prompt(promptBuilder.build()); System.out.println("result = " + result); - //checkBoxDemo(); - //listChoiceDemo(); - //inputDemo(); - //exandableChoiceDemo(); + + ConfirmResult delivery = (ConfirmResult) result.get("delivery"); + if (delivery.getConfirmed()== ConfirmChoice.ConfirmationValue.YES) { + System.out.println("We will deliver the pizza in 5 minutes"); + } } catch (IOException e) { e.printStackTrace(); } finally { From b5471ede85388531fb6c706ca0575abb23bcf0ea Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Thu, 4 Feb 2016 10:23:41 +0100 Subject: [PATCH 045/115] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 97e2d41f5..c009c1d3d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ a Java clone of Inquirer.js. - Checkboxes - Lists - Expandable Choices (multiple key based answers for a question with help and optional list navigation) + - Yes/No-Questions # Dependencies From a278261f8aa1efdc171a2974dc47914c09a80102 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 8 Feb 2016 06:30:16 +0100 Subject: [PATCH 046/115] changed for mavencentral --- build.gradle | 59 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index a32b61a2b..b1c0cba59 100644 --- a/build.gradle +++ b/build.gradle @@ -1,27 +1,64 @@ group 'ConsoleUI' -version '1.0-SNAPSHOT' +version '0.0.1-SNAPSHOT' apply plugin: 'java' apply plugin: 'idea' +apply plugin: 'maven' +apply plugin: 'signing' +apply plugin: 'distribution' repositories { - mavenCentral() + mavenCentral() } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.11' - compile 'org.fusesource.jansi:jansi:1.11' - compile 'jline:jline:2.13' + testCompile group: 'junit', name: 'junit', version: '4.11' + compile 'org.fusesource.jansi:jansi:1.11' + compile 'jline:jline:2.13' } +task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allSource +} jar { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + + manifest { + attributes 'Implementation-Title': 'ConsoleUI', + 'Implementation-Version': version, + 'Main-Class': 'de.codeshelf.consoleui.Basic' - manifest { - attributes 'Implementation-Title': 'ConsoleUI', - 'Implementation-Version': version, - 'Main-Class': 'de.codeshelf.consoleui.Basic' + } +} + +artifacts { + archives javadocJar, sourcesJar +} +/* +signing { + sign configurations.archives +} + +distributions { + custom {} +} +*/ + +group = "de.codeshelf.consoleui" +archivesBaseName = "consoleui" + +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } } -} \ No newline at end of file + } +} From 73a7cb1a0c6f392e6c20273a75a3d86dbf45dcf7 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Tue, 9 Feb 2016 17:54:01 +0100 Subject: [PATCH 047/115] added distribution config --- build.gradle | 53 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index b1c0cba59..caddb4ce6 100644 --- a/build.gradle +++ b/build.gradle @@ -8,38 +8,38 @@ apply plugin: 'signing' apply plugin: 'distribution' repositories { - mavenCentral() + mavenCentral() } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.11' - compile 'org.fusesource.jansi:jansi:1.11' - compile 'jline:jline:2.13' + testCompile group: 'junit', name: 'junit', version: '4.11' + compile 'org.fusesource.jansi:jansi:1.11' + compile 'jline:jline:2.13' } task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc + classifier = 'javadoc' + from javadoc } task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource + classifier = 'sources' + from sourceSets.main.allSource } jar { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } - manifest { - attributes 'Implementation-Title': 'ConsoleUI', - 'Implementation-Version': version, - 'Main-Class': 'de.codeshelf.consoleui.Basic' + manifest { + attributes 'Implementation-Title': 'ConsoleUI', + 'Implementation-Version': version, + 'Main-Class': 'de.codeshelf.consoleui.Basic' - } + } } artifacts { - archives javadocJar, sourcesJar + archives javadocJar, sourcesJar } /* @@ -52,13 +52,28 @@ distributions { } */ +distributions { + main { + //baseName = 'someName' + contents { + into("$name-$version") { + into('lib') { + from libsDir + include '*.jar' //copy the fat jar created by bootRepackage + } + } + } + } +} + + group = "de.codeshelf.consoleui" archivesBaseName = "consoleui" uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + } } - } } From d2b3bd15b3a1c49a7000fb97521b19cf963010f8 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 9 Feb 2016 21:51:36 +0100 Subject: [PATCH 048/115] added new wrapper, added distribution config --- build.gradle | 15 +++++++++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 52271 -> 52141 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index caddb4ce6..af12f5df2 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,11 @@ repositories { mavenCentral() } +task wrapper(type: Wrapper) { + gradleVersion = '2.11' +} + + dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' compile 'org.fusesource.jansi:jansi:1.11' @@ -70,6 +75,15 @@ distributions { group = "de.codeshelf.consoleui" archivesBaseName = "consoleui" +uploadArchives { + repositories { + mavenDeployer { + repository(url: "file://localhost/Users/andy/work/myRepo/") + } + } +} + +/* uploadArchives { repositories { mavenDeployer { @@ -77,3 +91,4 @@ uploadArchives { } } } +*/ \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 30d399d8d2bf522ff5de94bf434a7cc43a9a74b5..085a1cdc27db1185342f15a00441734e74fe3735 100644 GIT binary patch delta 8406 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 479e12ffe..22489ba76 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Nov 29 22:53:55 CET 2015 +#Tue Feb 09 21:49:29 CET 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip From 6489908fc157f20a7dfc9c34b7832aff90a932cd Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 21 Feb 2016 22:38:34 +0100 Subject: [PATCH 049/115] added deployment info --- build.gradle | 38 +++++++++++++++++------- gradle/wrapper/gradle-wrapper.properties | 4 +-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index af12f5df2..8a2a89fd0 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,7 @@ task sourcesJar(type: Jar) { from sourceSets.main.allSource } +/* jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } @@ -42,6 +43,7 @@ jar { } } +*/ artifacts { archives javadocJar, sourcesJar @@ -78,17 +80,31 @@ archivesBaseName = "consoleui" uploadArchives { repositories { mavenDeployer { - repository(url: "file://localhost/Users/andy/work/myRepo/") - } - } -} - -/* -uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + //repository(url: "file://localhost/${rootDir}/../myRepo/") + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name 'ConsoleUI' + packaging 'jar' + description 'Library for Ansi-Console user interaction' + url 'https://github.com/awegmann/consoleui/' + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } } + } } + } } -*/ \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 22489ba76..c1e50b0e9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Feb 09 21:49:29 CET 2016 +#Tue Feb 16 22:07:14 CET 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-all.zip From e33939af5ba3ee883adb25f7fcf1ab6146056f2d Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 22 Feb 2016 21:19:30 +0100 Subject: [PATCH 050/115] fixed deployment --- build.gradle | 69 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/build.gradle b/build.gradle index 8a2a89fd0..89ee8454c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'ConsoleUI' -version '0.0.1-SNAPSHOT' +version '0.0.1' apply plugin: 'java' apply plugin: 'idea' @@ -49,16 +49,18 @@ artifacts { archives javadocJar, sourcesJar } -/* + signing { sign configurations.archives } +/* distributions { custom {} } */ +/* distributions { main { //baseName = 'someName' @@ -73,35 +75,54 @@ distributions { } } +*/ group = "de.codeshelf.consoleui" archivesBaseName = "consoleui" -uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - //repository(url: "file://localhost/${rootDir}/../myRepo/") +if (project.hasProperty('release')) { + uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + /* + repository(url: "file://localhost/${rootDir}/../myRepo/") + */ + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } - snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - authentication(userName: ossrhUsername, password: ossrhPassword) - } + pom.project { + name 'ConsoleUI' + packaging 'jar' + description 'Library for Ansi-Console user interaction' + url 'https://github.com/awegmann/consoleui/' + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id "an10nn"; + name "Andreas Wegmann"; + email "andreas.we9mann@gmail.com"; + } + } - pom.project { - name 'ConsoleUI' - packaging 'jar' - description 'Library for Ansi-Console user interaction' - url 'https://github.com/awegmann/consoleui/' - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' + scm { + connection 'scm:git:git://github.com/awegmann/consoleui.git' + developerConnection 'scm:git:ssh://git@github.com:awegmann/consoleui.git' + url 'https://github.com/awegmann/consoleui/' } } } From cca561d26337b8e6b70ce4370f4b70a0b2cd17f0 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Tue, 23 Feb 2016 10:45:10 +0100 Subject: [PATCH 051/115] downgraded jline to 2.12 for groovy compatibility --- build.gradle | 16 +++++--- .../prompt/reader/ConsoleReaderImpl.java | 38 ++++++++++++------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index 89ee8454c..e360c70db 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,8 @@ -group 'ConsoleUI' -version '0.0.1' +group = "de.codeshelf.consoleui" +archivesBaseName = "consoleui" +version '0.0.2-SNAPSHOT' + +ext.isReleaseVersion = !version.endsWith("SNAPSHOT") apply plugin: 'java' apply plugin: 'idea' @@ -19,7 +22,7 @@ task wrapper(type: Wrapper) { dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' compile 'org.fusesource.jansi:jansi:1.11' - compile 'jline:jline:2.13' + compile 'jline:jline:2.12' } task javadocJar(type: Jar) { @@ -33,6 +36,7 @@ task sourcesJar(type: Jar) { } /* +// Fat-jar jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } @@ -43,6 +47,7 @@ jar { } } + */ artifacts { @@ -51,6 +56,8 @@ artifacts { signing { + required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } + sign configurations.archives } @@ -77,9 +84,6 @@ distributions { */ -group = "de.codeshelf.consoleui" -archivesBaseName = "consoleui" - if (project.hasProperty('release')) { uploadArchives { repositories { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index d2c3f7fd5..435e2f368 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -8,6 +8,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.Stack; /** * User: Andreas Wegmann @@ -46,9 +47,18 @@ public void addAllowedSpecialKey(SpecialKey specialKey) { public ReaderInput read() { Object op; - while (true) { - try { - op = console.readBinding(console.getKeys()); + + StringBuilder sb = new StringBuilder(); + Stack pushBackChar = new Stack(); + try { + while (true) { + int c = pushBackChar.isEmpty() ? console.readCharacter() : pushBackChar.pop (); + if (c == -1) { + return null; + } + sb.appendCodePoint(c); + + op = console.getKeys().getBound( sb ); if (op instanceof Operation) { Operation operation = (Operation) op; if (operation == Operation.NEXT_HISTORY && this.allowedSpecialKeys.contains(SpecialKey.DOWN)) @@ -61,25 +71,26 @@ public ReaderInput read() { return new ReaderInput(SpecialKey.BACKSPACE); if (operation == Operation.SELF_INSERT) { - String lastBinding = console.getLastBinding(); - Character c = lastBinding.charAt(0); - if (allowedPrintableKeys.contains(c)) { - return new ReaderInput(SpecialKey.PRINTABLE_KEY, c); + String lastBinding = sb.toString(); + Character cc = lastBinding.charAt(0); + if (allowedPrintableKeys.contains(cc)) { + return new ReaderInput(SpecialKey.PRINTABLE_KEY, cc); } } } - } catch (IOException e) { - e.printStackTrace(); } + } catch (IOException e) { + e.printStackTrace(); } + return null; } /** * Wrapper around JLine 2 library. * - * @param completer - * @param prompt - * @return + * @param completer List of completes to use + * @param prompt the text to display as prompt left side from the input + * @return a ReaderInput object with results */ public ReaderInput readLine(List completer, String prompt, String value) throws IOException { if (completer != null) { @@ -87,7 +98,8 @@ public ReaderInput readLine(List completer, String prompt, String val console.addCompleter(c); } } - String readLine = console.readLine(prompt, null, value); + //String readLine = console.readLine(prompt, null, value); + String readLine = console.readLine(prompt); return new ReaderInput(SpecialKey.PRINTABLE_KEY, readLine); } From 138832c27c04d0ba19df25475c1f1b300e85081b Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Tue, 23 Feb 2016 10:45:35 +0100 Subject: [PATCH 052/115] fixed bug in ListItem naming --- src/main/java/de/codeshelf/consoleui/Basic.java | 17 ----------------- .../consoleui/elements/items/impl/ListItem.java | 4 +++- .../codeshelf/consoleui/prompt/ListPrompt.java | 4 ---- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index e7dd1835a..4f51c3954 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -176,21 +176,4 @@ private static void exandableChoiceDemo() throws IOException { ExpandableChoiceResult result = expandableChoicePrompt.prompt(expChoice); System.out.println("result = " + result); } - - private static void readBindingsDemo(ConsoleReader console) throws IOException { - Object o = console.readBinding(console.getKeys()); - System.out.println("o = " + o); - } - - private static void readCharsDemo(ConsoleReader console) throws IOException { - int c=0; - while (c != -1) { - Operation o = (Operation) console.readBinding(console.getKeys()); - System.out.println("o = " + o + " "+o.getClass().getName()); - String lastBinding = console.getLastBinding(); - System.out.println(lastBinding); - System.out.println("after read"); - } - //System.out.println("finished"); - } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java index d14c2e380..24c5e6716 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java @@ -12,8 +12,10 @@ public class ListItem implements ListItemIF { public ListItem(String text, String name) { this.text = text; - if (name ==null) { + if (name==null) { this.name = text; + } else { + this.name = name; } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 6a0556f04..3744c9002 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -31,7 +31,6 @@ public ListPrompt() throws IOException { super(); } - private void render() { int itemNumber = 0; @@ -83,12 +82,9 @@ public ListResult prompt(ListChoice listChoice) throws IOException { readerInput = reader.read(); } - ListItem listItem = (ListItem) itemList.get(selectedItemIndex); ListResult selection=new ListResult(listItem.getName()); renderMessagePromptAndResult(listChoice.getMessage(),((ListItem) itemList.get(selectedItemIndex)).getText()); return selection ; } - - } From fd57a55e334ee8af087a173ab07a60f1b7a118a0 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Tue, 23 Feb 2016 13:51:41 +0100 Subject: [PATCH 053/115] minor changes --- build.gradle | 43 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index e360c70db..6e1d453f8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,12 @@ -group = "de.codeshelf.consoleui" -archivesBaseName = "consoleui" version '0.0.2-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") + apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' apply plugin: 'signing' -apply plugin: 'distribution' repositories { mavenCentral() @@ -35,20 +33,19 @@ task sourcesJar(type: Jar) { from sourceSets.main.allSource } -/* // Fat-jar -jar { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } - manifest { - attributes 'Implementation-Title': 'ConsoleUI', - 'Implementation-Version': version, - 'Main-Class': 'de.codeshelf.consoleui.Basic' +task fatJar(type: Jar) { + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + baseName = project.name + '-all' + manifest { + attributes 'Implementation-Title': 'ConsoleUI', + 'Implementation-Version': version, + 'Main-Class': 'de.codeshelf.consoleui.Basic' } } -*/ artifacts { archives javadocJar, sourcesJar @@ -61,35 +58,15 @@ signing { sign configurations.archives } -/* -distributions { - custom {} -} -*/ - -/* -distributions { - main { - //baseName = 'someName' - contents { - into("$name-$version") { - into('lib') { - from libsDir - include '*.jar' //copy the fat jar created by bootRepackage - } - } - } - } -} -*/ +group = "de.codeshelf.consoleui" if (project.hasProperty('release')) { uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - /* + /* just for testing repository(url: "file://localhost/${rootDir}/../myRepo/") */ From db169941cfd62b168c9504124c46b7a84c3a5443 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Tue, 23 Feb 2016 13:52:12 +0100 Subject: [PATCH 054/115] fixed minor bug in ListPrompt --- .../codeshelf/consoleui/prompt/builder/ListPromptBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java index 689409958..330b2bbb6 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java @@ -22,6 +22,7 @@ public ListPromptBuilder(PromptBuilder promptBuilder) { public ListPromptBuilder name(String name) { this.name = name; + this.message = name; return this; } @@ -36,7 +37,7 @@ public ListItemBuilder newItem() { public ListItemBuilder newItem(String name) { ListItemBuilder listItemBuilder = new ListItemBuilder(this); - return listItemBuilder.name(name); + return listItemBuilder.name(name).text(name); } public PromptBuilder addPrompt() { From d10f4953b82f3a180f44f9cd4be68b7b088c925e Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 23 Feb 2016 22:33:18 +0100 Subject: [PATCH 055/115] refactored (removed unused classes) and added documentation --- .../java/de/codeshelf/consoleui/Basic.java | 82 +--------- .../items/impl/CheckboxItemBuilder.java | 63 -------- .../elements/items/impl/ListItemBuilder.java | 37 ----- .../consoleui/prompt/ConsolePrompt.java | 149 +++++++++++++++--- .../prompt/ExpandableChoicePrompt.java | 2 +- .../prompt/builder/PromptBuilder.java | 2 + 6 files changed, 135 insertions(+), 200 deletions(-) delete mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java delete mode 100644 src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 4f51c3954..9bc48dfba 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -1,24 +1,16 @@ package de.codeshelf.consoleui; -import de.codeshelf.consoleui.elements.*; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; -import de.codeshelf.consoleui.elements.items.impl.*; -import de.codeshelf.consoleui.prompt.*; +import de.codeshelf.consoleui.elements.ConfirmChoice; +import de.codeshelf.consoleui.prompt.ConfirmResult; +import de.codeshelf.consoleui.prompt.ConsolePrompt; +import de.codeshelf.consoleui.prompt.PromtResultItemIF; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; import jline.TerminalFactory; -import jline.console.ConsoleReader; -import jline.console.Operation; -import jline.console.completer.FileNameCompleter; import jline.console.completer.StringsCompleter; import org.fusesource.jansi.AnsiConsole; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; import static org.fusesource.jansi.Ansi.ansi; @@ -112,68 +104,4 @@ public static void main(String[] args) throws InterruptedException { } } - } - - private static void listChoiceDemo() throws IOException { - ListPrompt listPrompt = new ListPrompt(); - List list= new ArrayList(); - - ListItemBuilder listItemBuilder = ListItemBuilder.create(); - list.add(new ListItem("One")); - list.add(new ListItem("Two")); - list.add(listItemBuilder.name("3").text("Three").build()); - list.add(new Separator("some extra items")); - list.add(new ListItem("Four")); - list.add(new Separator()); - list.add(listItemBuilder.text("Five").build()); - ListChoice listChoice = new ListChoice("my first list choice", null, list); - ListResult result = listPrompt.prompt(listChoice); - System.out.println("result = " + result); - } - - private static void checkBoxDemo() throws IOException { - CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); - List list=new ArrayList(); - - - list.add(new CheckboxItem("One")); - list.add(new CheckboxItem(true,"Two")); - list.add(CheckboxItemBuilder.create().name("3").text("Three").disabledText("always in").check().build()); - list.add(new Separator("some extra items")); - list.add(new CheckboxItem("Four")); - list.add(new Separator()); - list.add(new CheckboxItem(true,"Five")); - Checkbox checkbox = new Checkbox("my first checkbox", null, list); - CheckboxResult result = checkboxPrompt.prompt(checkbox); - System.out.println("result = " + result); - } - - private static void inputDemo() throws IOException { - InputResult result; - InputPrompt inputPrompt = new InputPrompt(); - - result =inputPrompt.prompt(new InputValue("newItem", "enter your newItem")); - System.out.println("result = " + result); - - result =inputPrompt.prompt(new InputValue("firstname","enter your first newItem",null,"John")); - System.out.println("result = " + result); - - InputValue branch = new InputValue("branch", "enter a branch newItem", null, null); - branch.addCompleter(new StringsCompleter("consoleui_1","consoleui_1_412_1","consoleui_1_769_2","simplegui_4_32")); - branch.addCompleter(new FileNameCompleter()); - result = inputPrompt.prompt(branch); - System.out.println("result = " + result); - } - - private static void exandableChoiceDemo() throws IOException { - ExpandableChoicePrompt expandableChoicePrompt = new ExpandableChoicePrompt(); - LinkedHashSet choiceItems=new LinkedHashSet(); - choiceItems.add(new ChoiceItem('o',"overwrite","Overwrite", false)); - choiceItems.add(new ChoiceItem('a',"overwriteAll","Overwrite this one and all next", false)); - choiceItems.add(new ChoiceItem('d',"diff","Show diff", false)); - choiceItems.add(new ChoiceItem('x',"abort","Abort", false)); - ExpandableChoice expChoice=new ExpandableChoice("conflict in 'MyBestClass.java'", "conflict", choiceItems); - ExpandableChoiceResult result = expandableChoicePrompt.prompt(expChoice); - System.out.println("result = " + result); - } -} + }} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java deleted file mode 100644 index 4e99a73f4..000000000 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItemBuilder.java +++ /dev/null @@ -1,63 +0,0 @@ -package de.codeshelf.consoleui.elements.items.impl; - -import de.codeshelf.consoleui.util.BuilderIF; - -/** - * User: Andreas Wegmann - * Date: 04.01.16 - */ -public class CheckboxItemBuilder implements BuilderIF { - - private String text; - private String disabledText; - private String name; - private boolean checked; - - private CheckboxItemBuilder() { - } - - public static CheckboxItemBuilder create() { - return new CheckboxItemBuilder(); - } - - public CheckboxItemBuilder text(String text) { - this.text = text; - if (this.name == null) { - this.name = text; - } - - return this; - } - - public CheckboxItemBuilder name(String name) { - this.name = name; - return this; - } - - public CheckboxItemBuilder disabledText(String text) { - this.disabledText = text; - return this; - } - - public CheckboxItemBuilder check() { - this.checked = true; - return this; - } - - public CheckboxItemBuilder uncheck() { - this.checked = false; - return this; - } - - public CheckboxItemBuilder checked(boolean checked) { - this.checked = checked; - return this; - } - - - public CheckboxItem build() { - CheckboxItem checkboxItem = new CheckboxItem(checked, text, disabledText, name); - this.name = null; - return checkboxItem; - } -} diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java deleted file mode 100644 index 520fe45ac..000000000 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItemBuilder.java +++ /dev/null @@ -1,37 +0,0 @@ -package de.codeshelf.consoleui.elements.items.impl; - -import de.codeshelf.consoleui.util.BuilderIF; - -/** - * User: Andreas Wegmann - * Date: 04.01.16 - */ -public class ListItemBuilder implements BuilderIF { - ListItem item; - private String text; - private String name; - - private ListItemBuilder() { - this.item = new ListItem(null); - } - - static public ListItemBuilder create() { - return new ListItemBuilder(); - } - - public ListItemBuilder text(String text) { - this.text = text; - return this; - } - - public ListItem build() { - ListItem listItem = new ListItem(text,name); - this.name = null; - return listItem; - } - - public ListItemBuilder name(String name) { - this.name = name; - return this; - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index bef459a18..dc16c3634 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -5,47 +5,113 @@ import java.io.IOException; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.List; /** + * ConsolePrompt encapsulates the prompting of a list of input questions for the user. + *

* Created by Andreas Wegmann on 20.01.16. */ public class ConsolePrompt { + // input prompt implementation + private InputPrompt inputPrompt; - InputPrompt inputPrompt; - ExpandableChoicePrompt expandableChoicePrompt; - CheckboxPrompt checkboxPrompt; - ListPrompt listPrompt = new ListPrompt(); - ConfirmPrompt confirmPrompt = new ConfirmPrompt(); + // expandable choice prompt implementation + private ExpandableChoicePrompt expandableChoicePrompt; + // checkbox prompt implementation + private CheckboxPrompt checkboxPrompt; + + // list box prompt implementation + private ListPrompt listPrompt; + + // confirmation prompt implementaion + private ConfirmPrompt confirmPrompt; + + /* Lazy getter for input prompt */ + private InputPrompt getInputPrompt() throws IOException { + if (inputPrompt == null) { + inputPrompt = new InputPrompt(); + } + return inputPrompt; + } + + /* Lazy getter for expandable choice prompt */ + private ExpandableChoicePrompt getExpandableChoicePrompt() throws IOException { + if (expandableChoicePrompt == null) { + expandableChoicePrompt = new ExpandableChoicePrompt(); + } + return expandableChoicePrompt; + } + + /* Lazy getter for checkbox prompt */ + private CheckboxPrompt getCheckboxPrompt() throws IOException { + if (checkboxPrompt == null) { + checkboxPrompt = new CheckboxPrompt(); + } + return checkboxPrompt; + } + + /* Lazy getter for list prompt */ + private ListPrompt getListPrompt() throws IOException { + if (listPrompt == null) { + listPrompt = new ListPrompt(); + } + return listPrompt; + } + + /* Lazy getter for confirm prompt */ + private ConfirmPrompt getConfirmPrompt() throws IOException { + if (confirmPrompt == null) { + confirmPrompt = new ConfirmPrompt(); + } + return confirmPrompt; + } + + /** + * Default constructor for this class. + * + * @throws IOException + */ public ConsolePrompt() throws IOException { inputPrompt = new InputPrompt(); checkboxPrompt = new CheckboxPrompt(); expandableChoicePrompt = new ExpandableChoicePrompt(); + listPrompt = new ListPrompt(); + confirmPrompt = new ConfirmPrompt(); } - - public HashMap prompt(List promptableElementList) throws IOException { + /** + * Prompt a list of choices (questions). This method takes a list of promptable elements, typically + * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and + * answers are filled in to the result map. The result map contains the key of each promtable element + * and the user entry as an object implementing {@link PromtResultItemIF}. + * + * @param promptableElementList the list of questions / promts to ask the user for. + * @return a map containing a result for each element of promptableElementList + * @throws IOException + */ + public HashMap prompt(List promptableElementList) + throws IOException { HashMap resultMap = new HashMap(); for (int i = 0; i < promptableElementList.size(); i++) { PromptableElementIF promptableElement = promptableElementList.get(i); if (promptableElement instanceof ListChoice) { ListResult result = doPrompt((ListChoice) promptableElement); - resultMap.put(promptableElement.getName(),result); + resultMap.put(promptableElement.getName(), result); } else if (promptableElement instanceof InputValue) { InputResult result = doPrompt((InputValue) promptableElement); - resultMap.put(promptableElement.getName(),result); + resultMap.put(promptableElement.getName(), result); } else if (promptableElement instanceof ExpandableChoice) { ExpandableChoiceResult result = doPrompt((ExpandableChoice) promptableElement); - resultMap.put(promptableElement.getName(),result); + resultMap.put(promptableElement.getName(), result); } else if (promptableElement instanceof Checkbox) { CheckboxResult result = doPrompt((Checkbox) promptableElement); - resultMap.put(promptableElement.getName(),result); + resultMap.put(promptableElement.getName(), result); } else if (promptableElement instanceof ConfirmChoice) { ConfirmResult result = doPrompt((ConfirmChoice) promptableElement); - resultMap.put(promptableElement.getName(),result); + resultMap.put(promptableElement.getName(), result); } else { throw new IllegalArgumentException("wrong type of promptable element"); } @@ -53,27 +119,66 @@ public ConsolePrompt() throws IOException { return resultMap; } + /** + * Process a {@link ConfirmChoice}. + * + * @param confirmChoice the confirmation to ask the user for. + * @return Object of type {@link ConfirmResult} holding the users answer + * @throws IOException + */ private ConfirmResult doPrompt(ConfirmChoice confirmChoice) throws IOException { - return confirmPrompt.prompt(confirmChoice); + return getConfirmPrompt().prompt(confirmChoice); } + /** + * Process a {@link ListChoice}. + * + * @param listChoice the list to let the user choose an item from. + * @return Object of type {@link ListResult} holding the uses choice. + * @throws IOException + */ private ListResult doPrompt(ListChoice listChoice) throws IOException { - return listPrompt.prompt(listChoice); + return getListPrompt().prompt(listChoice); } - private InputResult doPrompt(InputValue listChoice) throws IOException { - return inputPrompt.prompt(listChoice); + /** + * Process a {@link InputValue}. + * + * @param inputValue the input value to ask the user for. + * @return Object of type {@link InputResult} holding the uses input. + * @throws IOException + */ + private InputResult doPrompt(InputValue inputValue) throws IOException { + return getInputPrompt().prompt(inputValue); } - private CheckboxResult doPrompt(Checkbox listChoice) throws IOException { - return checkboxPrompt.prompt(listChoice); + /** + * Process a {@link Checkbox}. + * + * @param checkbox the checkbox displayed where the user can check values. + * @return Object of type {@link CheckboxResult} holding the uses choice. + * @throws IOException + */ + private CheckboxResult doPrompt(Checkbox checkbox) throws IOException { + return getCheckboxPrompt().prompt(checkbox); } - private ExpandableChoiceResult doPrompt(ExpandableChoice listChoice) throws IOException { - return expandableChoicePrompt.prompt(listChoice); + /** + * Process a {@link ExpandableChoice}. + * + * @param expandableChoice the expandable choice displayed where the user can select a value from. + * @return Object of type {@link ExpandableChoiceResult} holding the uses choice. + * @throws IOException + */ + private ExpandableChoiceResult doPrompt(ExpandableChoice expandableChoice) throws IOException { + return getExpandableChoicePrompt().prompt(expandableChoice); } - + /** + * Creates a {@link PromptBuilder}. + * + * @return a new prompt builder object. + */ public PromptBuilder getPromptBuilder() { return new PromptBuilder(); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 3031a34d5..cb190e3db 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -151,7 +151,7 @@ public ExpandableChoiceResult prompt(ExpandableChoice expandableChoice) throws I for (ConsoleUIItemIF choiceItem : choiceItems) { if (choiceItem instanceof ChoiceItem) { ChoiceItem item = (ChoiceItem) choiceItem; - if (item.getKey() == pressedKey) { + if (item.getKey().equals(pressedKey)) { chosenItem = item; break; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java index c3a71a642..69b6eb94b 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java @@ -6,6 +6,8 @@ import java.util.List; /** + * PromptBuilder is the builder class which creates + * * Created by Andreas Wegmann * on 20.01.16. */ From 75c7d6db7635ebec406880e4612a2ff77380a8b7 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 23 Feb 2016 23:09:56 +0100 Subject: [PATCH 056/115] added documentation --- .../prompt/AbstractListablePrompt.java | 31 +++++++++++++++++-- .../consoleui/prompt/AbstractPrompt.java | 31 ++++++++++++++++++- .../consoleui/prompt/CheckboxPrompt.java | 28 ++++++++++++++++- .../consoleui/prompt/ConsolePrompt.java | 25 ++++++--------- .../consoleui/prompt/InputResult.java | 5 +-- .../consoleui/prompt/ListPrompt.java | 10 ++---- .../codeshelf/consoleui/prompt/PromptIF.java | 10 +++++- 7 files changed, 109 insertions(+), 31 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java index a9354036e..849612635 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java @@ -1,24 +1,38 @@ package de.codeshelf.consoleui.prompt; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; import java.io.IOException; import java.util.ArrayList; /** + * Abstract base class for all listable prompts (checkbox, list and expandable choice). + * This class contains some helper methods for the list prompts. + * * User: Andreas Wegmann * Date: 19.01.16 */ public abstract class AbstractListablePrompt extends AbstractPrompt { + // holds the index of the selected item (of course) protected int selectedItemIndex; - ArrayList itemList; + // the item list of the prompt + protected ArrayList itemList; + + /** + * Empty default constructor. + * @throws IOException may be thrown by super class + */ public AbstractListablePrompt() throws IOException { + super(); } + /** + * Find the next selectable Item (user pressed 'down'). + * + * @return index of the next selectable item. + */ protected int getNextSelectableItemIndex() { for (int i = 0; i < itemList.size(); i++) { int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); @@ -29,6 +43,11 @@ protected int getNextSelectableItemIndex() { return selectedItemIndex; } + /** + * Find the previous selectable item (user pressed 'up'). + * + * @return index of the previous selectable item. + */ protected int getPreviousSelectableItemIndex() { for (int i = 0; i < itemList.size(); i++) { int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); @@ -39,6 +58,12 @@ protected int getPreviousSelectableItemIndex() { return selectedItemIndex; } + /** + * Find the first selectable item of the item list. + * + * @return index of the first selectable item. + * @throws IllegalStateException if no item is selectable. + */ protected int getFirstSelectableItemIndex() { int index = 0; for (ConsoleUIItemIF item : itemList) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 3e826e4cf..8a4e20146 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -10,28 +10,57 @@ import static org.fusesource.jansi.Ansi.ansi; /** + * Abstract base class for all prompt implementations. * User: Andreas Wegmann * Date: 06.01.16 */ public abstract class AbstractPrompt { protected int renderHeight; protected ResourceBundle resourceBundle; + + // the reader where we get the user input from ReaderIF reader; + /** + * Generic method to render the message prompt and the users input after the prompt. This method is + * used by all prompt implementations to display the question and result after the user has made + * the input. + * + * @param message message to render as colored prompt. + * @param resultValue result value generated from the prompt implementation + */ protected void renderMessagePromptAndResult(String message, String resultValue) { - System.out.println(ansi().cursorUp(renderHeight - 1).a(renderMessagePrompt(message)).fg(Ansi.Color.CYAN).a(" " + resultValue).eraseScreen(Ansi.Erase.FORWARD).reset()); } + /** + * Generic method to render a message prompt. The message (displayed white) is prefixed by a + * green question mark. + * + * @param message message to render as a colored prompt. + * @return String with ANSI-Color printable prompt. + */ protected String renderMessagePrompt(String message) { return (ansi().fg(Ansi.Color.GREEN).a("? ").fgBright(Ansi.Color.WHITE).a(message)).fg(Ansi.Color.DEFAULT).toString(); } + /** + * Default constructor. Initializes the resource bundle for localized messages. + * + * @throws IOException may be thrown from console reader + */ public AbstractPrompt() throws IOException { resourceBundle = ResourceBundle.getBundle("consoleui_messages"); this.reader = new ConsoleReaderImpl(); } + /** + * Setter for the reader implementation. Usually the prompt implementation uses the default + * {@link ConsoleReaderImpl} initialized in the constructor. + * This methods is mainly inteded for JUnit tests to inject a new reader for simulated uses input. + * + * @param reader reader implementation to use. + */ public void setReader(ReaderIF reader) { this.reader = reader; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index cbc22fe2c..fd2de48ac 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -10,16 +10,31 @@ import java.io.IOException; import java.util.HashSet; +/** + * CheckboxPrompt implements the checkbox choice handling. + */ public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { + + // checkbox object to prompt the user for. private Checkbox checkbox; + /** + * helper class with render functionality. + */ + CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + /** + * Empty default constructor. + * @throws IOException may be thrown by super class + */ public CheckboxPrompt() throws IOException { super(); } - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + /** + * render the checkbox on the terminal. + */ private void render() { int itemNumber = 0; @@ -36,6 +51,14 @@ private void render() { } } + /** + * Prompt the user for selecting zero to many choices from a checkbox. + * + * @param checkbox checkbox with items to choose from. + * @return {@link CheckboxResult} which holds the users choices. + * + * @throws IOException may be thrown by console reader + */ public CheckboxResult prompt(Checkbox checkbox) throws IOException { this.checkbox = checkbox; @@ -84,6 +107,9 @@ public CheckboxResult prompt(Checkbox checkbox) return new CheckboxResult(selections); } + /** + * Toggles the selection of the currently selected checkbox item. + */ private void toggleSelection() { CheckboxItem checkboxItem = (CheckboxItem) itemList.get(this.selectedItemIndex); checkboxItem.setChecked(!checkboxItem.isChecked()); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index dc16c3634..a51ec1ced 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -25,7 +25,7 @@ public class ConsolePrompt { // list box prompt implementation private ListPrompt listPrompt; - // confirmation prompt implementaion + // confirmation prompt implementation private ConfirmPrompt confirmPrompt; /* Lazy getter for input prompt */ @@ -70,15 +70,8 @@ private ConfirmPrompt getConfirmPrompt() throws IOException { /** * Default constructor for this class. - * - * @throws IOException */ - public ConsolePrompt() throws IOException { - inputPrompt = new InputPrompt(); - checkboxPrompt = new CheckboxPrompt(); - expandableChoicePrompt = new ExpandableChoicePrompt(); - listPrompt = new ListPrompt(); - confirmPrompt = new ConfirmPrompt(); + public ConsolePrompt() { } /** @@ -89,11 +82,11 @@ public ConsolePrompt() throws IOException { * * @param promptableElementList the list of questions / promts to ask the user for. * @return a map containing a result for each element of promptableElementList - * @throws IOException + * @throws IOException may be thrown by console reader */ public HashMap prompt(List promptableElementList) throws IOException { - HashMap resultMap = new HashMap(); + HashMap resultMap = new HashMap<>(); for (int i = 0; i < promptableElementList.size(); i++) { PromptableElementIF promptableElement = promptableElementList.get(i); @@ -124,7 +117,7 @@ public ConsolePrompt() throws IOException { * * @param confirmChoice the confirmation to ask the user for. * @return Object of type {@link ConfirmResult} holding the users answer - * @throws IOException + * @throws IOException may be thrown by console reader */ private ConfirmResult doPrompt(ConfirmChoice confirmChoice) throws IOException { return getConfirmPrompt().prompt(confirmChoice); @@ -135,7 +128,7 @@ private ConfirmResult doPrompt(ConfirmChoice confirmChoice) throws IOException { * * @param listChoice the list to let the user choose an item from. * @return Object of type {@link ListResult} holding the uses choice. - * @throws IOException + * @throws IOException may be thrown by console reader */ private ListResult doPrompt(ListChoice listChoice) throws IOException { return getListPrompt().prompt(listChoice); @@ -146,7 +139,7 @@ private ListResult doPrompt(ListChoice listChoice) throws IOException { * * @param inputValue the input value to ask the user for. * @return Object of type {@link InputResult} holding the uses input. - * @throws IOException + * @throws IOException may be thrown by console reader */ private InputResult doPrompt(InputValue inputValue) throws IOException { return getInputPrompt().prompt(inputValue); @@ -157,7 +150,7 @@ private InputResult doPrompt(InputValue inputValue) throws IOException { * * @param checkbox the checkbox displayed where the user can check values. * @return Object of type {@link CheckboxResult} holding the uses choice. - * @throws IOException + * @throws IOException may be thrown by console reader */ private CheckboxResult doPrompt(Checkbox checkbox) throws IOException { return getCheckboxPrompt().prompt(checkbox); @@ -168,7 +161,7 @@ private CheckboxResult doPrompt(Checkbox checkbox) throws IOException { * * @param expandableChoice the expandable choice displayed where the user can select a value from. * @return Object of type {@link ExpandableChoiceResult} holding the uses choice. - * @throws IOException + * @throws IOException may be thrown by console reader */ private ExpandableChoiceResult doPrompt(ExpandableChoice expandableChoice) throws IOException { return getExpandableChoicePrompt().prompt(expandableChoice); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java b/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java index adf897d43..3efca7d3e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java @@ -1,11 +1,12 @@ package de.codeshelf.consoleui.prompt; /** - * User: ${FULL_NAME} + * + * User: Andreas Wegmann * Date: 03.02.16 */ public class InputResult implements PromtResultItemIF { - String input; + private String input; public InputResult(String input) { this.input = input; diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 3744c9002..612f94ad9 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -8,23 +8,19 @@ import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; import java.io.IOException; -import java.util.LinkedHashSet; import static org.fusesource.jansi.Ansi.ansi; /** + * ListPrompt implements the list choice handling. + * * User: Andreas Wegmann * Date: 01.01.16 */ public class ListPrompt extends AbstractListablePrompt implements PromptIF { + // the list to let the user choose from private ListChoice listChoice; - ReaderIF reader; - - public void setReader(ReaderIF reader) { - this.reader = reader; - } - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); public ListPrompt() throws IOException { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java index 67fc85f75..2a33efeec 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java @@ -3,12 +3,20 @@ import de.codeshelf.consoleui.elements.PromptableElementIF; import java.io.IOException; -import java.util.LinkedHashSet; /** + * Interface for all prompt implementation. + * * User: Andreas Wegmann * Date: 01.01.16 */ public interface PromptIF { + /** + * Prompt the user for an imput. + * + * @param promptableElement prompt definition + * @return the prompt result + * @throws IOException may be thrown by getting the users input. + */ R prompt(T promptableElement) throws IOException; } From 34568a3ff18c6bb02f35dc168a14575f9f071804 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 23 Feb 2016 23:10:20 +0100 Subject: [PATCH 057/115] changed version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6e1d453f8..01188cdc6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -version '0.0.2-SNAPSHOT' +version '0.0.2' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") From 1286d897e88cb167ebd4a379af8d4c078e22bcc1 Mon Sep 17 00:00:00 2001 From: awegmann Date: Tue, 23 Feb 2016 23:14:14 +0100 Subject: [PATCH 058/115] fixed resource key naming --- .../java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java | 3 +-- .../de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java | 2 +- src/main/resources/consoleui_messages.properties | 4 ++-- src/main/resources/consoleui_messages_de_DE.properties | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java index d1d8cbfaf..92c21b1a7 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java @@ -6,7 +6,6 @@ import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; import java.io.IOException; -import java.util.LinkedHashSet; import static org.fusesource.jansi.Ansi.ansi; @@ -30,7 +29,7 @@ public ConfirmPrompt() throws IOException { yes_key = resourceBundle.getString("confirmation_yes_key").trim().charAt(0); no_key = resourceBundle.getString("confirmation_no_key").trim().charAt(0); yes_answer = resourceBundle.getString("confirmation_yes_answer"); - no_answer = resourceBundle.getString("confimation_no_answer"); + no_answer = resourceBundle.getString("confirmation_no_answer"); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index d80392033..1fd7a048f 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -119,6 +119,6 @@ public String renderConfirmChoiceOptions(ConfirmChoice confirmChoice) { } else if (confirmChoice.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.NO) { return resourceBundle.getString("confirmation_no_default"); } - return resourceBundle.getString("confimation_without_default"); + return resourceBundle.getString("confirmation_without_default"); } } diff --git a/src/main/resources/consoleui_messages.properties b/src/main/resources/consoleui_messages.properties index 4404ca69a..4517b40a2 100644 --- a/src/main/resources/consoleui_messages.properties +++ b/src/main/resources/consoleui_messages.properties @@ -1,4 +1,4 @@ -confimation_without_default=\ (y/n) +confirmation_without_default=\ (y/n) confirmation_no_default=\ (y/N) confirmation_yes_default=\ (Y/n) confirmation_yes_key=y @@ -6,5 +6,5 @@ confirmation_no_key=n help.list.all.options=Help, list all options please.enter.a.valid.command=Please enter a valid command -confimation_no_answer=no +confirmation_no_answer=no confirmation_yes_answer=yes \ No newline at end of file diff --git a/src/main/resources/consoleui_messages_de_DE.properties b/src/main/resources/consoleui_messages_de_DE.properties index 79ec121e5..e4e6b79dd 100644 --- a/src/main/resources/consoleui_messages_de_DE.properties +++ b/src/main/resources/consoleui_messages_de_DE.properties @@ -1,9 +1,9 @@ -confimation_without_default=\ (j/n) +confirmation_without_default=\ (j/n) confirmation_no_default=\ (j/N) confirmation_yes_default=\ (J/n) confirmation_yes_key=j confirmation_no_key=n help.list.all.options=Hilfe. Listet alle Optionen. please.enter.a.valid.command=Bitte ein gültiges Kürzel eingeben. -confimation_no_answer=Nein +confirmation_no_answer=Nein confirmation_yes_answer=Ja \ No newline at end of file From c493f2f8e4df3fab1c1157f6d2c49fc64e704f7a Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 24 Feb 2016 07:27:31 +0100 Subject: [PATCH 059/115] added documentation --- .../consoleui/prompt/CheckboxResult.java | 14 +++++++++- .../consoleui/prompt/ConfirmPrompt.java | 28 +++++++++++++++++-- .../consoleui/prompt/ConfirmResult.java | 14 +++++++++- .../prompt/ExpandableChoicePrompt.java | 6 ++++ 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java index fb3e72c6b..77374f4fe 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java @@ -3,16 +3,28 @@ import java.util.HashSet; /** - * User: ${FULL_NAME} + * Result of a checkbox choicee. CheckboxResult contains a {@link java.util.Set} with the + * IDs of the selected checkbox items. + *

+ * User: Andreas Wegmann * Date: 03.02.16 */ public class CheckboxResult implements PromtResultItemIF { HashSet selectedIds; + /** + * Default Constructor. + * @param selectedIds Selected IDs. + */ public CheckboxResult(HashSet selectedIds) { this.selectedIds = selectedIds; } + /** + * Returns the set with the IDs of selected checkbox items. + * + * @return set with IDs + */ public HashSet getSelectedIds() { return selectedIds; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java index 92c21b1a7..915c8d30f 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java @@ -10,10 +10,13 @@ import static org.fusesource.jansi.Ansi.ansi; /** + * Implementation of the confirm choice. The user will be asked for a yes/no questions. + * both of the answers can be the default choice. + *

* User: Andreas Wegmann * Date: 06.01.16 */ -public class ConfirmPrompt extends AbstractPrompt implements PromptIF { +public class ConfirmPrompt extends AbstractPrompt implements PromptIF { private ReaderIF reader; CUIRenderer itemRenderer = CUIRenderer.getRenderer(); @@ -24,6 +27,11 @@ public class ConfirmPrompt extends AbstractPrompt implements PromptIF + * User: Andreas Wegmann * Date: 03.02.16 */ public class ConfirmResult implements PromtResultItemIF { ConfirmChoice.ConfirmationValue confirmed; + /** + * Default constructor. + * + * @param confirm the result value to hold. + */ public ConfirmResult(ConfirmChoice.ConfirmationValue confirm) { this.confirmed = confirm; } + /** + * Returns the confirmation value. + * @return confirmation value. + */ public ConfirmChoice.ConfirmationValue getConfirmed() { return confirmed; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index cb190e3db..f22bad015 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -13,6 +13,12 @@ import static org.fusesource.jansi.Ansi.ansi; /** + * Implementation of the expandable choice. The user is asked a question to be answered with + * a single key. Each key represents a choice from a given set of items. + * + * Items with the key 'h' are not allowed. This key is reserved for the help message. With the + * help message the prompt can be expanded to a list with the answers. + * * User: Andreas Wegmann * Date: 07.01.16 */ From 5ea4989d41e23af60a4b0d26526b6a74d9756fbd Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Wed, 24 Feb 2016 14:18:11 +0100 Subject: [PATCH 060/115] added masked input for passwords in inputPrompt --- .../java/de/codeshelf/consoleui/Basic.java | 1 + .../consoleui/elements/InputValue.java | 9 +++++++++ .../consoleui/prompt/InputPrompt.java | 18 ++++++++++++++++-- .../prompt/builder/InputValueBuilder.java | 10 ++++++++++ .../prompt/reader/ConsoleReaderImpl.java | 12 +++++++++--- .../consoleui/prompt/reader/ReaderIF.java | 2 +- .../consoleui/prompt/CheckboxPromptTest.java | 2 +- 7 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 9bc48dfba..5660fde5a 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -37,6 +37,7 @@ public static void main(String[] args) throws InterruptedException { .name("name") .message("Please enter your name") .defaultValue("John Doe") + //.mask('*') .addCompleter(new StringsCompleter("Jim", "Jack", "John")) .addPrompt(); diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java index 1ee91f5fe..bb26897c6 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java +++ b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java @@ -13,6 +13,7 @@ public class InputValue extends AbstractPromptableElement { private String value; private String defaultValue; private List completer; + private Character mask; public InputValue(String name, String message) { super(message, name); @@ -50,4 +51,12 @@ public void addCompleter(Completer completer) { } this.completer.add(completer); } + + public void setMask(Character mask) { + this.mask = mask; + } + + public Character getMask() { + return mask; + } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index e04f1654d..77cb7b0db 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -43,14 +43,28 @@ public InputResult prompt(InputValue inputElement) throws IOException { //System.out.print(prompt + itemRenderer.renderValue(this.inputElement)); //System.out.flush(); List completer = inputElement.getCompleter(); - ReaderIF.ReaderInput readerInput = reader.readLine(completer,prompt,inputElement.getValue()); + Character mask = inputElement.getMask(); + ReaderIF.ReaderInput readerInput = reader.readLine(completer,prompt,inputElement.getValue(),mask); String lineInput = readerInput.getLineInput(); if (lineInput == null || lineInput.trim().length() == 0) { lineInput = inputElement.getDefaultValue(); } - renderMessagePromptAndResult(inputElement.getMessage(), lineInput); + + String result; + if (mask == null) { + result=lineInput; + } else { + result=""; + if (lineInput!=null) { + for (int i=0; i completers; public InputValueBuilder(PromptBuilder promptBuilder) { @@ -42,12 +43,21 @@ public InputValueBuilder addCompleter(Completer completer) { return this; } + public InputValueBuilder mask(char mask) { + this.mask = mask; + return this; + } + public PromptBuilder addPrompt() { InputValue inputValue = new InputValue(name, message, null, defaultValue); if (completers != null) { inputValue.setCompleter(completers); } + if (mask != null) { + inputValue.setMask(mask); + } promptBuilder.addPrompt(inputValue); return promptBuilder; } + } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 435e2f368..8d9e213ef 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -90,16 +90,22 @@ public ReaderInput read() { * * @param completer List of completes to use * @param prompt the text to display as prompt left side from the input + * @param mask * @return a ReaderInput object with results */ - public ReaderInput readLine(List completer, String prompt, String value) throws IOException { + public ReaderInput readLine(List completer, String prompt, String value, Character mask) throws IOException { if (completer != null) { for (Completer c : completer) { console.addCompleter(c); } } - //String readLine = console.readLine(prompt, null, value); - String readLine = console.readLine(prompt); + String readLine; + if (mask == null) { + readLine = console.readLine(prompt); + } else { + readLine = console.readLine(prompt, mask); + } + return new ReaderInput(SpecialKey.PRINTABLE_KEY, readLine); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java index 0c524a526..0bbf4eef3 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java @@ -30,7 +30,7 @@ public enum SpecialKey { ReaderInput read(); - ReaderInput readLine(List completer, String promt, String value) throws IOException; + ReaderInput readLine(List completer, String promt, String value, Character mask) throws IOException; class ReaderInput { private SpecialKey specialKey; diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java index 5b454e5e4..6f62c3d37 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -53,7 +53,7 @@ public ReaderInput read() { return new ReaderInput(SpecialKey.ENTER); } - public ReaderInput readLine(List completer, String promt, String value) throws IOException { + public ReaderInput readLine(List completer, String promt, String value, Character mask) throws IOException { return null; } }); From 4dfd6ed6ef289ff59486fc453529abbfbffd023c Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Wed, 24 Feb 2016 14:18:48 +0100 Subject: [PATCH 061/115] fixed fatjar, updated version --- build.gradle | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 01188cdc6..ca9c51087 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -version '0.0.2' +version '0.0.3-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") @@ -33,10 +33,12 @@ task sourcesJar(type: Jar) { from sourceSets.main.allSource } -// Fat-jar -task fatJar(type: Jar) { +// Fat-jar +task fatJar(type: Jar, dependsOn: [':compileJava', ':processResources']) { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from files(sourceSets.main.output.classesDir) + from files(sourceSets.main.resources) baseName = project.name + '-all' manifest { attributes 'Implementation-Title': 'ConsoleUI', From 69a54dd905f8b6f52209335fb194d32dcb140b17 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 24 Feb 2016 21:50:47 +0100 Subject: [PATCH 062/115] added documentation --- .../consoleui/prompt/CheckboxResult.java | 2 +- .../consoleui/prompt/ExpandableChoicePrompt.java | 6 +++--- .../consoleui/prompt/ExpandableChoiceResult.java | 15 ++++++++++++++- .../codeshelf/consoleui/prompt/InputPrompt.java | 6 +++++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java index 77374f4fe..d1823e90a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java @@ -3,7 +3,7 @@ import java.util.HashSet; /** - * Result of a checkbox choicee. CheckboxResult contains a {@link java.util.Set} with the + * Result of a checkbox choice. CheckboxResult contains a {@link java.util.Set} with the * IDs of the selected checkbox items. *

* User: Andreas Wegmann diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index f22bad015..cfe0b1d63 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -15,11 +15,11 @@ /** * Implementation of the expandable choice. The user is asked a question to be answered with * a single key. Each key represents a choice from a given set of items. - * + *

* Items with the key 'h' are not allowed. This key is reserved for the help message. With the * help message the prompt can be expanded to a list with the answers. - * - * User: Andreas Wegmann + *

+ * User: Andreas Wegmann
* Date: 07.01.16 */ public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java index 5470a9f1d..718822e7e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java @@ -1,16 +1,29 @@ package de.codeshelf.consoleui.prompt; /** - * User: ${FULL_NAME} + * Result of a an expandable choice. ExpandableChoiceResult contains a String with the + * IDs of the selected item. + *

+ * User: Andreas Wegmann
* Date: 03.02.16 */ public class ExpandableChoiceResult implements PromtResultItemIF { String selectedId; + /** + * Default constructor. + * + * @param selectedId the selected id + */ public ExpandableChoiceResult(String selectedId) { this.selectedId = selectedId; } + /** + * Returns the selected id. + * + * @return selected id. + */ public String getSelectedId() { return selectedId; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 77cb7b0db..f9403de0a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -13,7 +13,11 @@ import static org.fusesource.jansi.Ansi.ansi; /** - * User: Andreas Wegmann + * Implementation of the input choice prompt. The user will be asked for a string input value. + * With support of completers an automatic expansion of strings and filenames can be configured. + * Defining a mask character, a password like input is possible. + *

+ * User: Andreas Wegmann
* Date: 06.01.16 */ public class InputPrompt extends AbstractPrompt implements PromptIF { From 1dd94011a7208652843c27b7b840f1fc1c53cb03 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 24 Feb 2016 21:51:29 +0100 Subject: [PATCH 063/115] version 0.0.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ca9c51087..7356aecec 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -version '0.0.3-SNAPSHOT' +version '0.0.3' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") From 9bb1f2e78f0ff139f858531a60e003d636043f9d Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 24 Feb 2016 21:58:08 +0100 Subject: [PATCH 064/115] fixed comments --- .../de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java | 2 +- .../de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java | 2 +- src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java | 2 +- .../de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index cfe0b1d63..4e38d5b3e 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -19,7 +19,7 @@ * Items with the key 'h' are not allowed. This key is reserved for the help message. With the * help message the prompt can be expanded to a list with the answers. *

- * User: Andreas Wegmann
+ * User: Andreas Wegmann

* Date: 07.01.16 */ public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java index 718822e7e..c4b351779 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java @@ -4,7 +4,7 @@ * Result of a an expandable choice. ExpandableChoiceResult contains a String with the * IDs of the selected item. *

- * User: Andreas Wegmann
+ * User: Andreas Wegmann

* Date: 03.02.16 */ public class ExpandableChoiceResult implements PromtResultItemIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index f9403de0a..8db6f8dbd 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -17,7 +17,7 @@ * With support of completers an automatic expansion of strings and filenames can be configured. * Defining a mask character, a password like input is possible. *

- * User: Andreas Wegmann
+ * User: Andreas Wegmann

* Date: 06.01.16 */ public class InputPrompt extends AbstractPrompt implements PromptIF { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 8d9e213ef..03aab204a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -90,7 +90,7 @@ public ReaderInput read() { * * @param completer List of completes to use * @param prompt the text to display as prompt left side from the input - * @param mask + * @param mask optional mask character (may be used for password entry) * @return a ReaderInput object with results */ public ReaderInput readLine(List completer, String prompt, String value, Character mask) throws IOException { From 1a78fb024c719a14584dcdb66cae35aefc043558 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Thu, 25 Feb 2016 15:20:27 +0100 Subject: [PATCH 065/115] fixed message/text bug, fixed missing result getter --- .../codeshelf/consoleui/prompt/ListResult.java | 17 +++++++++++++++++ .../prompt/builder/ListPromptBuilder.java | 7 ++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java index 19064ad58..2846954d4 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java @@ -1,11 +1,28 @@ package de.codeshelf.consoleui.prompt; /** + * Result of a list choice. Holds the id of the selected item. + *

* Created by Andreas Wegmann on 03.02.16. */ public class ListResult implements PromtResultItemIF { + String selectedId; + /** + * Returns the ID of the selected item. + * + * @return id of selected item + */ + public String getSelectedId() { + return selectedId; + } + + /** + * Default constructor. + * + * @param selectedId id of selected item. + */ public ListResult(String selectedId) { this.selectedId = selectedId; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java index 330b2bbb6..042519083 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java @@ -22,12 +22,17 @@ public ListPromptBuilder(PromptBuilder promptBuilder) { public ListPromptBuilder name(String name) { this.name = name; - this.message = name; + if (message != null) { + this.message = name; + } return this; } public ListPromptBuilder message(String message) { this.message = message; + if (name == null) { + name = message; + } return this; } From 89d3da935127ab50448d54c030a31a367893c5d8 Mon Sep 17 00:00:00 2001 From: "Wegmann, Andreas" Date: Thu, 25 Feb 2016 15:22:14 +0100 Subject: [PATCH 066/115] fixed javadoc problem --- src/main/java/de/codeshelf/consoleui/prompt/ListResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java index 2846954d4..ed1c3feb2 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java @@ -2,7 +2,7 @@ /** * Result of a list choice. Holds the id of the selected item. - *

+ *

* Created by Andreas Wegmann on 03.02.16. */ public class ListResult implements PromtResultItemIF { From eb004f42ef1945e70b7e03c17d7de79c6812c903 Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 25 Feb 2016 22:09:39 +0100 Subject: [PATCH 067/115] added documentation --- .../consoleui/prompt/builder/CheckboxPromptBuilder.java | 6 ++++++ .../consoleui/prompt/builder/ConfirmPromptBuilder.java | 8 +++++++- .../prompt/builder/ExpandableChoicePromptBuilder.java | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java index d0a52d395..271e5c516 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java @@ -26,11 +26,17 @@ void addItem(CheckboxItemIF checkboxItem) { public CheckboxPromptBuilder name(String name) { this.name = name; + if (message == null) { + message = name; + } return this; } public CheckboxPromptBuilder message(String message) { this.message = message; + if (name == null) { + name = message; + } return this; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java index 8c09a2a87..b5a464c07 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java @@ -3,7 +3,7 @@ import de.codeshelf.consoleui.elements.ConfirmChoice; /** - * User: ${FULL_NAME} + * User: Andreas Wegmann * Date: 24.01.16 */ public class ConfirmPromptBuilder { @@ -18,11 +18,17 @@ public ConfirmPromptBuilder(PromptBuilder promptBuilder) { public ConfirmPromptBuilder name(String name) { this.name = name; + if (message == null) { + message = name; + } return this; } public ConfirmPromptBuilder message(String message) { this.message = message; + if (name == null) { + name = message; + } return this; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java index d131ffd35..d5a25ee0a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java @@ -25,11 +25,17 @@ void addItem(ChoiceItemIF choiceItem) { public ExpandableChoicePromptBuilder name(String name) { this.name = name; + if (message == null) { + message = name; + } return this; } public ExpandableChoicePromptBuilder message(String message) { this.message = message; + if (name == null) { + name = message; + } return this; } From b74ae126b13ee9ec86f39efa834546b8a3123c32 Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 25 Feb 2016 22:14:01 +0100 Subject: [PATCH 068/115] added gradle release plugin --- build.gradle | 13 ++++++++++++- gradle.properties | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gradle.properties diff --git a/build.gradle b/build.gradle index 7356aecec..e3742ecf4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,15 @@ -version '0.0.3' +buildscript { + repositories { + maven { + url 'https://plugins.gradle.org/m2/' + } + } + dependencies { + classpath 'net.researchgate:gradle-release:2.3.4' + } +} + +apply plugin: 'net.researchgate.release' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..e89df12f8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +version=0.0.4 \ No newline at end of file From c7a939c2ae5c96e3f24f411a56014b1a7694603a Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 25 Feb 2016 22:14:29 +0100 Subject: [PATCH 069/115] [Gradle Release Plugin] - new version commit: '0.0.5'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e89df12f8..113c42f62 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.4 \ No newline at end of file +version=0.0.5 \ No newline at end of file From c6ecf578c2a10d980c81d30ff8696e46cee4b4cf Mon Sep 17 00:00:00 2001 From: awegmann Date: Thu, 25 Feb 2016 22:18:25 +0100 Subject: [PATCH 070/115] [Gradle Release Plugin] - new version commit: '0.0.6'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 113c42f62..d2eaab3cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.5 \ No newline at end of file +version=0.0.6 \ No newline at end of file From 1f5a4de34128a6c82159944c1ddd76c449628e15 Mon Sep 17 00:00:00 2001 From: awegmann Date: Fri, 26 Feb 2016 19:18:20 +0100 Subject: [PATCH 071/115] fixed reading of single keypress --- .../de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 03aab204a..dc19d2155 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -75,6 +75,8 @@ public ReaderInput read() { Character cc = lastBinding.charAt(0); if (allowedPrintableKeys.contains(cc)) { return new ReaderInput(SpecialKey.PRINTABLE_KEY, cc); + } else { + sb = new StringBuilder(); } } } From 31f7c9a3afa6dae221e9ca6c41ff73e434b11e8f Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 29 Feb 2016 07:18:37 +0100 Subject: [PATCH 072/115] [Gradle Release Plugin] - pre tag commit: '0.0.7'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d2eaab3cd..707c93aa7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.6 \ No newline at end of file +version=0.0.7 \ No newline at end of file From 1ca980b5501c758d6b42a9b5cb2751b136b44b7d Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 29 Feb 2016 07:18:50 +0100 Subject: [PATCH 073/115] [Gradle Release Plugin] - new version commit: '0.0.8'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 707c93aa7..498a3494a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.7 \ No newline at end of file +version=0.0.8 \ No newline at end of file From d48814acae97fc6f25e82fddd271fb24f1f1685a Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 29 Feb 2016 07:21:48 +0100 Subject: [PATCH 074/115] [Gradle Release Plugin] - new version commit: '0.0.9'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 498a3494a..ad679b95a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.0.8 \ No newline at end of file +version=0.0.9 \ No newline at end of file From ac71154fb40daa6f3b28fcfed0b10327016cfc51 Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 6 Mar 2016 20:34:55 +0100 Subject: [PATCH 075/115] changed HashSet to LinkedHashSet to preserve order of results --- .../java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index fd2de48ac..68f300759 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.HashSet; +import java.util.LinkedHashSet; /** * CheckboxPrompt implements the checkbox choice handling. @@ -93,7 +94,7 @@ public CheckboxResult prompt(Checkbox checkbox) readerInput = this.reader.read(); } - HashSet selections = new HashSet(); + LinkedHashSet selections = new LinkedHashSet<>(); for (ConsoleUIItemIF item : itemList) { if ((item instanceof CheckboxItem)) { From 349ed707d13db25caa4b3496781e5caf41dcfc1a Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 6 Mar 2016 20:35:16 +0100 Subject: [PATCH 076/115] added text initialization --- .../consoleui/prompt/builder/CheckboxItemBuilder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java index 392b03311..8f78fabec 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java @@ -18,6 +18,9 @@ public CheckboxItemBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { } public CheckboxItemBuilder name(String name) { + if (text == null) { + text = name; + } this.name = name; return this; } From 05a19563b150948ea201d29d9723b087ea7b3c85 Mon Sep 17 00:00:00 2001 From: awegmann Date: Sun, 6 Mar 2016 21:07:22 +0100 Subject: [PATCH 077/115] added properties to become buildable in Travis CI --- build.gradle | 5 ++++- gradle.properties | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index e3742ecf4..99882d896 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,9 @@ task fatJar(type: Jar, dependsOn: [':compileJava', ':processResources']) { } } +task printEnv { + println "username "+sonatypeUsername +} artifacts { archives javadocJar, sourcesJar @@ -88,7 +91,7 @@ if (project.hasProperty('release')) { } snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - authentication(userName: ossrhUsername, password: ossrhPassword) + authentication(userName: sonatypeUsername, password: sonatypePassword) } pom.project { diff --git a/gradle.properties b/gradle.properties index ad679b95a..da762fe0f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,4 @@ -version=0.0.9 \ No newline at end of file +version=0.0.9 + +sonatypeUsername=dummy +sonatypePassword=dummy From f562401bdda40f4bf6b7fd86b917ee986c116855 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 7 Mar 2016 07:20:37 +0100 Subject: [PATCH 078/115] become compatible with java 1.6 --- build.gradle | 7 ++++++- .../java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java | 2 +- .../java/de/codeshelf/consoleui/prompt/ConsolePrompt.java | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 99882d896..9900f8ec2 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,6 @@ apply plugin: 'net.researchgate.release' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") - apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' @@ -23,6 +22,12 @@ repositories { mavenCentral() } +compileJava { + sourceCompatibility = 1.6 + targetCompatibility = 1.6 +} + + task wrapper(type: Wrapper) { gradleVersion = '2.11' } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index 68f300759..c7b0b1e4d 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -94,7 +94,7 @@ public CheckboxResult prompt(Checkbox checkbox) readerInput = this.reader.read(); } - LinkedHashSet selections = new LinkedHashSet<>(); + LinkedHashSet selections = new LinkedHashSet(); for (ConsoleUIItemIF item : itemList) { if ((item instanceof CheckboxItem)) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index a51ec1ced..7aa45b850 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -86,7 +86,7 @@ public ConsolePrompt() { */ public HashMap prompt(List promptableElementList) throws IOException { - HashMap resultMap = new HashMap<>(); + HashMap resultMap = new HashMap(); for (int i = 0; i < promptableElementList.size(); i++) { PromptableElementIF promptableElement = promptableElementList.get(i); From fe0ffe853d089b901e2b00ad20a6db0ba3409120 Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 7 Mar 2016 07:21:12 +0100 Subject: [PATCH 079/115] [Gradle Release Plugin] - new version commit: '0.0.10'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index da762fe0f..d6659a47a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=0.0.9 +version=0.0.10 sonatypeUsername=dummy sonatypePassword=dummy From 61c8c7c9f716e582e48e78ccde442878de53cbc5 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 16 Mar 2016 21:28:55 +0100 Subject: [PATCH 080/115] added documentation --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index c009c1d3d..44fd5afb8 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,42 @@ a Java clone of Inquirer.js. Console UI uses jansi and jline for the dirty console things. +# Usage + +Before you can use Console UI the AnsiConsole library has to be initialized. + + AnsiConsole.systemInstall(); + +Entry point to the builder classes is to create a new object of type `ConsolePrompt`. + + ConsolePrompt prompt = new ConsolePrompt(); + +From the prompt object, use the `getPromptBuilder()` method to create the builder for all subsequent UI elements +you want to use. + + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + +From with this `PromptBuilder` you can access UI builder with the following methods: + +- createCheckboxPrompt() + * creates a checkbox prompt. This prompt lets the user choose any number of items of a given list. +- createChoicePrompt() + * creates a choice prompt. This prompt lets the user choose one from a given number of possible answers. +- createConfirmPromp() + * creates a confirm prompt. This prompt lets the user answer with 'yes' or 'no' to a given question. +- createInputPrompt() + * creates a input prompt. This prompt is a classic entry line like a shell. Because of the underlying readline + implementation it offers you to provide completers (like file name completer or string completer). In addition + to his, you can define a mask character which is printed on the screen instead of the typed keys like used + for hidden password entry. +- createListPrompt() + * creates a list prompt. This prompt lets the user choose one item from a given list. + + + + + + From 36cb72fd793f59c3b49e7b20ef763e400e99c94e Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Wed, 27 Apr 2016 17:27:14 +0000 Subject: [PATCH 081/115] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c009c1d3d..bcb5f4393 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ # Console UI +[![Join the chat at https://gitter.im/awegmann/consoleui](https://badges.gitter.im/awegmann/consoleui.svg)](https://gitter.im/awegmann/consoleui?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Tiny java library that provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScript. From 682a73dbac93ebfd30ac048b7dc24037d6861fd0 Mon Sep 17 00:00:00 2001 From: MTyson Date: Wed, 27 Apr 2016 14:09:08 -0500 Subject: [PATCH 082/115] Small improvement to doc; added eclipse plugin to gradle --- README.md | 7 +++++++ build.gradle | 1 + 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index bcb5f4393..fc6b5a61f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,13 @@ a Java clone of Inquirer.js. Console UI uses jansi and jline for the dirty console things. +# Test Run + +You can get an idea how the project works by looking at `de.codeshelf.consoleui.Basic`. You can run this by executing the following from the project root: + +gradlew fatJar +java -jar build/libs/consoleui-all-0.0.10.jar + diff --git a/build.gradle b/build.gradle index 9900f8ec2..d7ca2d5ea 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' apply plugin: 'signing' +apply plugin: 'eclipse' repositories { mavenCentral() From 251bb8b9428f78e375d3260c0bff692c5e30e381 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Wed, 27 Apr 2016 22:36:37 +0200 Subject: [PATCH 083/115] Update README.md --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e36e40eb1..c0feff8cd 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ Console UI uses jansi and jline for the dirty console things. You can get an idea how the project works by looking at `de.codeshelf.consoleui.Basic`. You can run this by executing the following from the project root: -gradlew fatJar -java -jar build/libs/consoleui-all-0.0.10.jar # <- replace with the latest version + gradlew fatJar + java -jar build/libs/consoleui-all-0.0.10.jar # <- replace with the latest version # Usage @@ -70,12 +70,6 @@ From with this `PromptBuilder` you can access UI builder with the following meth for hidden password entry. - createListPrompt() * creates a list prompt. This prompt lets the user choose one item from a given list. - - - - - ->>>>>>> feature/documentation From 43991250c19b44f60b654447ad1c9fea1b530da1 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 27 Apr 2016 23:18:46 +0200 Subject: [PATCH 084/115] changed character to unicode escape --- .../de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 1fd7a048f..2b99680e3 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -41,7 +41,7 @@ public CUIRenderer() { checkedBox = "\u25C9 "; uncheckedBox = "\u25EF "; line = "\u2500─────────────"; - cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("❯ ").toString(); + cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("\u276F ").toString(); noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); } resourceBundle = ResourceBundle.getBundle("consoleui_messages"); From d73349b3ba34790481b3cb6f34eefd54a10d9919 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Mon, 2 May 2016 20:09:47 +0200 Subject: [PATCH 085/115] Added link to screen recording. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c0feff8cd..fbf244087 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ a Java clone of Inquirer.js. - Lists - Expandable Choices (multiple key based answers for a question with help and optional list navigation) - Yes/No-Questions - + + A screen recording of the basic elements demo can be fund on Youtube [console UI demo](https://youtu.be/6dB3CyOX9rU). + # Dependencies Console UI uses jansi and jline for the dirty console things. From 826f9a40d6fa15eb4d1170e92476e76f81085410 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Mon, 2 May 2016 20:39:00 +0200 Subject: [PATCH 086/115] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbf244087..cee2d96aa 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ a Java clone of Inquirer.js. - Expandable Choices (multiple key based answers for a question with help and optional list navigation) - Yes/No-Questions - A screen recording of the basic elements demo can be fund on Youtube [console UI demo](https://youtu.be/6dB3CyOX9rU). +A screen recording of the basic elements demo can be fund on Youtube [console UI demo](https://youtu.be/6dB3CyOX9rU). # Dependencies From 7df8251b1ef9999f9967fc52725597ca16dc8af5 Mon Sep 17 00:00:00 2001 From: MTyson Date: Fri, 27 May 2016 10:27:53 -0500 Subject: [PATCH 087/115] Fix encoding error on windows when running gradle install --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index d7ca2d5ea..2cd8963aa 100644 --- a/build.gradle +++ b/build.gradle @@ -40,6 +40,10 @@ dependencies { compile 'jline:jline:2.12' } +javadoc { + options.encoding = 'UTF-8' +} + task javadocJar(type: Jar) { classifier = 'javadoc' from javadoc From 5a097b85a501671ad9f163b985ef974b9a246644 Mon Sep 17 00:00:00 2001 From: MTyson Date: Fri, 27 May 2016 10:28:05 -0500 Subject: [PATCH 088/115] Close resources with shutdown() --- .../codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index dc19d2155..e0e47c37a 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -83,6 +83,9 @@ public ReaderInput read() { } } catch (IOException e) { e.printStackTrace(); + } finally { + System.out.println("!!!!!!!!!!!!!! UPDTED"); + console.shutdown(); } return null; } From 531b045beec966986e9df320b8c4a25862a5e920 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Tue, 20 Dec 2016 14:55:02 +0100 Subject: [PATCH 089/115] Set theme jekyll-theme-slate --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 000000000..c74188174 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file From 650856d0a1444b780bbdbb7d21a297dee2b1063a Mon Sep 17 00:00:00 2001 From: jcruz Date: Thu, 29 Aug 2019 11:10:45 -0300 Subject: [PATCH 090/115] Fix issue #10 --- .../consoleui/prompt/reader/ConsoleReaderImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index e0e47c37a..3e0234804 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -3,6 +3,7 @@ import jline.console.ConsoleReader; import jline.console.Operation; import jline.console.completer.Completer; +import jline.internal.NonBlockingInputStream; import java.io.IOException; import java.util.HashSet; @@ -16,6 +17,7 @@ */ public class ConsoleReaderImpl implements ReaderIF { ConsoleReader console; + NonBlockingInputStream in; private Set allowedSpecialKeys; private Set allowedPrintableKeys; @@ -25,6 +27,7 @@ public ConsoleReaderImpl() throws IOException { allowedSpecialKeys = new HashSet(); console = new ConsoleReader(); + in = (NonBlockingInputStream) console.getInput(); } public void setAllowedSpecialKeys(Set allowedSpecialKeys) { @@ -52,7 +55,7 @@ public ReaderInput read() { Stack pushBackChar = new Stack(); try { while (true) { - int c = pushBackChar.isEmpty() ? console.readCharacter() : pushBackChar.pop (); + int c = pushBackChar.isEmpty() ? in.read() : pushBackChar.pop (); if (c == -1) { return null; } @@ -84,8 +87,8 @@ public ReaderInput read() { } catch (IOException e) { e.printStackTrace(); } finally { - System.out.println("!!!!!!!!!!!!!! UPDTED"); - console.shutdown(); +// System.out.println("!!!!!!!!!!!!!! UPDTED"); +// console.shutdown(); } return null; } From 7e711f475f5c074cfae7edaf1ec0a97969281373 Mon Sep 17 00:00:00 2001 From: jcruz Date: Thu, 29 Aug 2019 15:07:01 -0300 Subject: [PATCH 091/115] Remove attribute NonBlockingInputStream --- .../codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 3e0234804..74ba52050 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -17,7 +17,6 @@ */ public class ConsoleReaderImpl implements ReaderIF { ConsoleReader console; - NonBlockingInputStream in; private Set allowedSpecialKeys; private Set allowedPrintableKeys; @@ -27,7 +26,6 @@ public ConsoleReaderImpl() throws IOException { allowedSpecialKeys = new HashSet(); console = new ConsoleReader(); - in = (NonBlockingInputStream) console.getInput(); } public void setAllowedSpecialKeys(Set allowedSpecialKeys) { @@ -55,7 +53,7 @@ public ReaderInput read() { Stack pushBackChar = new Stack(); try { while (true) { - int c = pushBackChar.isEmpty() ? in.read() : pushBackChar.pop (); + int c = pushBackChar.isEmpty() ? console.readCharacter() : pushBackChar.pop (); if (c == -1) { return null; } From 6646fdad9b677526bac1ec887fbb9b2810b8263e Mon Sep 17 00:00:00 2001 From: jcruz Date: Thu, 29 Aug 2019 23:19:16 -0300 Subject: [PATCH 092/115] Add SpecialKey.NONE --- .../consoleui/prompt/reader/ConsoleReaderImpl.java | 12 +++++++----- .../codeshelf/consoleui/prompt/reader/ReaderIF.java | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java index 74ba52050..f2a9bb566 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java @@ -1,16 +1,16 @@ package de.codeshelf.consoleui.prompt.reader; -import jline.console.ConsoleReader; -import jline.console.Operation; -import jline.console.completer.Completer; -import jline.internal.NonBlockingInputStream; - import java.io.IOException; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.Stack; +import jline.console.ConsoleReader; +import jline.console.Operation; +import jline.console.completer.Completer; + /** * User: Andreas Wegmann * Date: 02.01.16 @@ -80,7 +80,9 @@ public ReaderInput read() { sb = new StringBuilder(); } } + return new ReaderInput(SpecialKey.NONE); } + if(Objects.isNull(op)) return new ReaderInput(SpecialKey.NONE); } } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java index 0bbf4eef3..2f5e0bb98 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java @@ -13,6 +13,7 @@ public interface ReaderIF { public enum SpecialKey { + NONE, UP, DOWN, ENTER, From 6f3601dbbe17ae3ab9db615a741594db43efc4dd Mon Sep 17 00:00:00 2001 From: jcruz Date: Fri, 30 Aug 2019 09:27:57 -0300 Subject: [PATCH 093/115] Update java (1.8) --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2cd8963aa..abe9841b7 100644 --- a/build.gradle +++ b/build.gradle @@ -24,8 +24,8 @@ repositories { } compileJava { - sourceCompatibility = 1.6 - targetCompatibility = 1.6 + sourceCompatibility = 1.8 + targetCompatibility = 1.8 } From 165f771ffa504cdfbf8de56bab9a3b06570eb10b Mon Sep 17 00:00:00 2001 From: awegmann Date: Fri, 30 Aug 2019 18:27:10 +0200 Subject: [PATCH 094/115] updated gradle --- build.gradle | 19 ++++--------------- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index 2cd8963aa..3708c5ecd 100644 --- a/build.gradle +++ b/build.gradle @@ -4,33 +4,22 @@ buildscript { url 'https://plugins.gradle.org/m2/' } } - dependencies { - classpath 'net.researchgate:gradle-release:2.3.4' - } } -apply plugin: 'net.researchgate.release' - ext.isReleaseVersion = !version.endsWith("SNAPSHOT") apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' apply plugin: 'signing' -apply plugin: 'eclipse' repositories { mavenCentral() } compileJava { - sourceCompatibility = 1.6 - targetCompatibility = 1.6 -} - - -task wrapper(type: Wrapper) { - gradleVersion = '2.11' + sourceCompatibility = 1.8 + targetCompatibility = 1.8 } @@ -58,8 +47,8 @@ task sourcesJar(type: Jar) { // Fat-jar task fatJar(type: Jar, dependsOn: [':compileJava', ':processResources']) { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } - from files(sourceSets.main.output.classesDir) - from files(sourceSets.main.resources) + from sourceSets.main.output.classesDirs + from sourceSets.main.output.resourcesDir baseName = project.name + '-all' manifest { attributes 'Implementation-Title': 'ConsoleUI', diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1e50b0e9..7a5b21382 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip From 848b3449d476da8ca79546ccebd58797f62f6fbe Mon Sep 17 00:00:00 2001 From: jcruz Date: Sat, 31 Aug 2019 15:03:31 -0300 Subject: [PATCH 095/115] Fix issue #6 --- .../java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java | 4 ++-- .../codeshelf/consoleui/prompt/ExpandableChoicePrompt.java | 4 ++-- .../java/de/codeshelf/consoleui/prompt/InputPrompt.java | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java index 915c8d30f..723981706 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java @@ -56,7 +56,7 @@ public ConfirmResult prompt(ConfirmChoice confirmChoice) throws IOException { } if (renderHeight == 0) { - renderHeight = 1; + renderHeight = 2; } else { System.out.println(ansi().cursorUp(renderHeight)); } @@ -106,7 +106,7 @@ private void render() { System.out.print(renderMessagePrompt(this.confirmChoice.getMessage()) + itemRenderer.renderConfirmChoiceOptions(this.confirmChoice) + " " + ansi().reset().a(calcResultValue() + " ").eraseLine()); System.out.flush(); - renderHeight = 1; + renderHeight = 2; } /** diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 4e38d5b3e..3c6433b80 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -50,14 +50,14 @@ private void render() { System.out.println(ansi().eraseLine().cursorUp(2)); System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); System.out.flush(); - renderHeight = 1; + renderHeight = 2; } else if (renderState == RenderState.FOLDED_ANSWERED) { System.out.println(""); System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(chosenItem.getMessage()).eraseLine()); System.out.print(ansi().cursorUp(2)); System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); System.out.flush(); - renderHeight = 1; + renderHeight = 2; } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java index 8db6f8dbd..35c8c3774 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java @@ -38,10 +38,8 @@ public InputResult prompt(InputValue inputElement) throws IOException { } if (renderHeight == 0) { - renderHeight = 1; - } else { - System.out.println(ansi().cursorUp(renderHeight)); - } + renderHeight = 2; + } String prompt = renderMessagePrompt(this.inputElement.getMessage()) + itemRenderer.renderOptionalDefaultValue(this.inputElement); //System.out.print(prompt + itemRenderer.renderValue(this.inputElement)); From 39cebf13635ef3206fd986d8fb996046d69a4d32 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Mon, 8 Jun 2020 19:16:48 +0200 Subject: [PATCH 096/115] Create LICENSE.txt --- LICENSE.txt | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..bc955e3ef --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Andreas Wegmann + + 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. From 075e4e131debfb9d4ac98582a0ff02de92b3873a Mon Sep 17 00:00:00 2001 From: awegmann Date: Mon, 3 Aug 2020 20:43:48 +0200 Subject: [PATCH 097/115] updated jline2 to latest version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3708c5ecd..bf56d7a45 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ compileJava { dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' compile 'org.fusesource.jansi:jansi:1.11' - compile 'jline:jline:2.12' + compile 'jline:jline:2.14.6' } javadoc { From 2841c7958a2c3243a1d3547dfef71ff50d3e5d31 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 5 Aug 2020 07:20:53 +0200 Subject: [PATCH 098/115] fixed minor bug in ExpandableChoicePrompt, updated gradle --- build.gradle | 156 +++++++++--------- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../prompt/ExpandableChoicePrompt.java | 2 +- 4 files changed, 77 insertions(+), 85 deletions(-) diff --git a/build.gradle b/build.gradle index bf56d7a45..6f772ce7d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,28 @@ -buildscript { - repositories { - maven { - url 'https://plugins.gradle.org/m2/' - } - } +plugins { + id 'java-library' + id 'maven-publish' + id 'signing' } -ext.isReleaseVersion = !version.endsWith("SNAPSHOT") +project.group = "de.codeshelf.consoleui" +//project.version = "0.0.11" + +apply plugin: 'mavin-publish' -apply plugin: 'java' -apply plugin: 'idea' -apply plugin: 'maven' -apply plugin: 'signing' +java { + withJavadocJar() + withSourcesJar() +} +/* repositories { mavenCentral() } + */ compileJava { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 1.8 + targetCompatibility = 1.8 } @@ -31,35 +34,28 @@ dependencies { javadoc { options.encoding = 'UTF-8' -} - -task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc -} - -task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource + if (JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } } // Fat-jar task fatJar(type: Jar, dependsOn: [':compileJava', ':processResources']) { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } - from sourceSets.main.output.classesDirs - from sourceSets.main.output.resourcesDir - baseName = project.name + '-all' - manifest { - attributes 'Implementation-Title': 'ConsoleUI', - 'Implementation-Version': version, - 'Main-Class': 'de.codeshelf.consoleui.Basic' + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from sourceSets.main.output.classesDirs + from sourceSets.main.output.resourcesDir + project.archivesBaseName = project.name + '-all' + manifest { + attributes 'Implementation-Title': 'ConsoleUI', + 'Implementation-Version': project.version, + 'Main-Class': 'de.codeshelf.consoleui.Basic' } } task printEnv { - println "username "+sonatypeUsername + println "username " + sonatypeUsername } artifacts { @@ -67,61 +63,57 @@ artifacts { } -signing { - required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } - - sign configurations.archives -} - - -group = "de.codeshelf.consoleui" - -if (project.hasProperty('release')) { - uploadArchives { +publishing { repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - /* just for testing - repository(url: "file://localhost/${rootDir}/../myRepo/") - */ - - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: sonatypeUsername, password: sonatypePassword) + maven { + // change URLs to point to your repos, e.g. http://my.org/repo + def releasesRepoUrl = "$buildDir/repos/releases" + def snapshotsRepoUrl = "$buildDir/repos/snapshots" + url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + name = 'mavenTest' } - - snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - authentication(userName: sonatypeUsername, password: sonatypePassword) + maven { + // change URLs to point to your repos, e.g. http://my.org/repo + def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + authentication(userName: sonatypeUsername, password: sonatypePassword) + name = 'mavenCentral' } + } - pom.project { - name 'ConsoleUI' - packaging 'jar' - description 'Library for Ansi-Console user interaction' - url 'https://github.com/awegmann/consoleui/' - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - - developers { - developer { - id "an10nn"; - name "Andreas Wegmann"; - email "andreas.we9mann@gmail.com"; + publications { + consoleUI(MavenPublication) { + from components.java + pom { + name = 'ConsoleUI' + description = 'Library for Ansi-Console user interaction' + url = 'https://github.com/awegmann/consoleui/' + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + developers { + developer { + id = "an10nn"; + name = "Andreas Wegmann"; + email = "andreas.we9mann@gmail.com"; + } + } + scm { + connection = 'scm:git:git://github.com/awegmann/consoleui.git' + developerConnection = 'scm:git:ssh://git@github.com:awegmann/consoleui.git' + url = 'https://github.com/awegmann/consoleui/' + } } - } - - scm { - connection 'scm:git:git://github.com/awegmann/consoleui.git' - developerConnection 'scm:git:ssh://git@github.com:awegmann/consoleui.git' - url 'https://github.com/awegmann/consoleui/' - } } - } } - } } + +signing { + sign publishing.publications.consoleUI +} + diff --git a/gradle.properties b/gradle.properties index d6659a47a..54911ea02 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=0.0.10 +project.version=0.0.11 sonatypeUsername=dummy sonatypePassword=dummy diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7a5b21382..3a4e28153 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index 3c6433b80..e3146e8c3 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -62,7 +62,7 @@ private void render() { } private void renderList() { - if (renderHeight == 1) { + if (renderHeight == 2) { // first time we expand the list... renderHeight = 1 + itemList.size(); System.out.println(""); From 21f933d045e14ba24d320c1d3fe5b226c9fcc244 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 5 Aug 2020 22:20:35 +0200 Subject: [PATCH 099/115] fixed buildfile --- build.gradle | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 6f772ce7d..cadafd97c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,20 +5,17 @@ plugins { } project.group = "de.codeshelf.consoleui" -//project.version = "0.0.11" - -apply plugin: 'mavin-publish' +project.version = "0.0.10-SNAPSHOT" java { withJavadocJar() withSourcesJar() } -/* + repositories { mavenCentral() } - */ compileJava { sourceCompatibility = 1.8 @@ -58,27 +55,23 @@ task printEnv { println "username " + sonatypeUsername } -artifacts { - archives javadocJar, sourcesJar -} - - publishing { repositories { - maven { + mavenLocal { // change URLs to point to your repos, e.g. http://my.org/repo def releasesRepoUrl = "$buildDir/repos/releases" def snapshotsRepoUrl = "$buildDir/repos/snapshots" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - name = 'mavenTest' } - maven { + mavenCentral { // change URLs to point to your repos, e.g. http://my.org/repo def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - authentication(userName: sonatypeUsername, password: sonatypePassword) - name = 'mavenCentral' + credentials { + username = sonatypeUsername + password = sonatypePassword + } } } @@ -113,7 +106,10 @@ publishing { } } +/* signing { sign publishing.publications.consoleUI } + + */ \ No newline at end of file From acbad797db4327b36a583247afdc1dfe6f3f68d9 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 5 Aug 2020 22:23:51 +0200 Subject: [PATCH 100/115] prepared version 0.0.11 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cadafd97c..50219ed7a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } project.group = "de.codeshelf.consoleui" -project.version = "0.0.10-SNAPSHOT" +project.version = "0.0.11" java { withJavadocJar() From 144a0d11c54ec8f46551c11d7dbfc56dc43f818a Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 19 Aug 2020 00:10:26 +0200 Subject: [PATCH 101/115] fixed #20 and added documentation --- README.md | 30 +- build.gradle | 6 +- doc/howto.md | 294 ++++++++++++++++++ doc/screenshots/checkbox_prompt.png | Bin 0 -> 55868 bytes doc/screenshots/confirmation_prompt.png | Bin 0 -> 17020 bytes .../expandable_choice_prompt_1.png | Bin 0 -> 15792 bytes .../expandable_choice_prompt_2.png | Bin 0 -> 18501 bytes .../expandable_choice_prompt_3.png | Bin 0 -> 28612 bytes doc/screenshots/input_prompt.png | Bin 0 -> 18189 bytes doc/screenshots/list_prompt.png | Bin 0 -> 27848 bytes .../java/de/codeshelf/consoleui/Basic.java | 2 +- .../consoleui/elements/Checkbox.java | 18 +- .../consoleui/elements/ListChoice.java | 18 +- .../consoleui/elements/PageSizeType.java | 4 + .../elements/items/impl/ListItem.java | 6 +- .../consoleui/examples/LongList.java | 63 ++++ .../consoleui/examples/SimpleExample.java | 48 +++ .../prompt/AbstractListablePrompt.java | 156 +++++++++- .../consoleui/prompt/CheckboxPrompt.java | 93 ++++-- .../prompt/ExpandableChoicePrompt.java | 22 +- .../consoleui/prompt/ListPrompt.java | 87 ++++-- .../prompt/builder/CheckboxItemBuilder.java | 3 + .../prompt/builder/CheckboxPromptBuilder.java | 19 +- .../prompt/builder/ListPromptBuilder.java | 21 +- .../prompt/renderer/CUIRenderer.java | 5 +- .../consoleui/prompt/CheckboxPromptTest.java | 7 +- 26 files changed, 811 insertions(+), 91 deletions(-) create mode 100644 doc/howto.md create mode 100644 doc/screenshots/checkbox_prompt.png create mode 100644 doc/screenshots/confirmation_prompt.png create mode 100644 doc/screenshots/expandable_choice_prompt_1.png create mode 100644 doc/screenshots/expandable_choice_prompt_2.png create mode 100644 doc/screenshots/expandable_choice_prompt_3.png create mode 100644 doc/screenshots/input_prompt.png create mode 100644 doc/screenshots/list_prompt.png create mode 100644 src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java create mode 100644 src/main/java/de/codeshelf/consoleui/examples/LongList.java create mode 100644 src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java diff --git a/README.md b/README.md index cee2d96aa..5b9f9a690 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ - +ConsoleUI logo [![Build Status](https://travis-ci.org/awegmann/consoleui.svg?branch=master)](https://travis-ci.org/awegmann/consoleui) -# Console UI +# ConsoleUI [![Join the chat at https://gitter.im/awegmann/consoleui](https://badges.gitter.im/awegmann/consoleui.svg)](https://gitter.im/awegmann/consoleui?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -14,15 +14,15 @@ Tiny java library that provides simple UI elements on ANSI console based termina I was impressed by JavaScript based Yeoman which leads the user through the process of creating new projects by querying with a simple user interface on the console. An investigation how this is done, brought me to Inquirer.js which implements a very simple and intuitive set of controls for checkbox, list and text input. - + Because I didn't found anything comparable to this in the Java eco system, I decided to write `Console UI` as a library with the same easy 'look and feel'. Some parts of the API are also comparable, but Console UI is not a Java clone of Inquirer.js. # Features - + Console UI currently supports: - + - Text input with completion and GNU ReadLine compatible editing - Checkboxes - Lists @@ -35,23 +35,28 @@ A screen recording of the basic elements demo can be fund on Youtube [console UI Console UI uses jansi and jline for the dirty console things. +# Maven artefact + +ConsoleUI releases are available at Maven Central [de.codeshelf.consoleui » consoleui](https://mvnrepository.com/artifact/de.codeshelf.consoleui/consoleui) + # Test Run -You can get an idea how the project works by looking at `de.codeshelf.consoleui.Basic`. You can run this by executing the following from the project root: +You can get an idea how the project works by looking at `de.codeshelf.consoleui.Basic`. +You can run this by executing the following from the project root: gradlew fatJar java -jar build/libs/consoleui-all-0.0.10.jar # <- replace with the latest version # Usage -Before you can use Console UI the AnsiConsole library has to be initialized. +Before you can use ConsoleUI the AnsiConsole library has to be initialized. AnsiConsole.systemInstall(); - + Entry point to the builder classes is to create a new object of type `ConsolePrompt`. ConsolePrompt prompt = new ConsolePrompt(); - + From the prompt object, use the `getPromptBuilder()` method to create the builder for all subsequent UI elements you want to use. @@ -73,9 +78,16 @@ From with this `PromptBuilder` you can access UI builder with the following meth - createListPrompt() * creates a list prompt. This prompt lets the user choose one item from a given list. +*See the [how to](doc/howto.md) to get a more detailed documentation how to use ConsoleUI.* +# Changes +### Version 0.0.12 +- Fixed Bug #20: Lists higher than the terminal height were not handled correctly. + ConsoleUI now supports scrolling for checkbox promt and list prompt. + To configure the height of the view port, either an absolute number of lines or a fraction (percentage) of the + screen height can be defined. diff --git a/build.gradle b/build.gradle index 50219ed7a..dc388a51b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } project.group = "de.codeshelf.consoleui" -project.version = "0.0.11" +project.version = "0.0.12" java { withJavadocJar() @@ -106,10 +106,6 @@ publishing { } } -/* signing { sign publishing.publications.consoleUI } - - - */ \ No newline at end of file diff --git a/doc/howto.md b/doc/howto.md new file mode 100644 index 000000000..b77543abc --- /dev/null +++ b/doc/howto.md @@ -0,0 +1,294 @@ +# ConsoleUI programming guide + +This document contains a brief introduction in using ConsoleUI. + +## Introduction + +ConsoleUI is a library for prompting the user for different types of input. It provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScript. + +## Features + +Console UI currently supports: + +- Text input with completion and GNU ReadLine compatible editing +- Checkboxes +- Lists +- Expandable Choices (multiple key based answers for a question with help and optional list navigation) +- Yes/No-Questions + +## A small example + +The following code presents a simple, but complete code example to use CosoleUI for a selecting an item from a list. + +```java +package de.codeshelf.consoleui; + +import de.codeshelf.consoleui.prompt.ConsolePrompt; +import de.codeshelf.consoleui.prompt.PromtResultItemIF; +import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import jline.TerminalFactory; +import org.fusesource.jansi.AnsiConsole; + +import java.io.IOException; +import java.util.HashMap; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: Andreas Wegmann + * Date: 12.08.2020 + */ +public class SimpleExample { + + public static void main(String[] args) throws InterruptedException { + AnsiConsole.systemInstall(); // #1 + System.out.println(ansi().eraseScreen().render("Simple list example:")); + + try { + ConsolePrompt prompt = new ConsolePrompt(); // #2 + PromptBuilder promptBuilder = prompt.getPromptBuilder(); // #3 + + promptBuilder.createListPrompt() // #4 + .name("pizzatype") + .message("Which pizza do you want?") + .newItem().text("Margherita").add() // without name (name defaults to text) + .newItem("veneziana").text("Veneziana").add() + .newItem("hawai").text("Hawai").add() + .newItem("quattro").text("Quattro Stagioni").add() + .addPrompt(); + + HashMap result = prompt.prompt(promptBuilder.build()); // #5 + System.out.println("result = " + result); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + TerminalFactory.get().restore(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }} + +``` + +Basic steps: + +1. ConsoleUI uses [jansi](https://github.com/fusesource/jansi), so you have to initialize it first +2. Create a new `ConsolePrompt` object. +3. Create a `PromptBuilder`. All user interaction can be create with the prompt builder object. +4. In this example we create a `ListPrompt` + 1. give it a name ('pizzatype') + 2. assign a prompt message ("Which pizza do you want?") + 3. create items with and name (optinal) and a text and add them to the ListPrompt + 4. to finish call `addPrompt()` to create the ListPrompt and add it to the prompt builder object. +5. calling `prompt.prompt(promptBuilder.build())` builds all the promts (in this example only one) and enters the user interaction. After all prompts are processes, the `prompt()` method returns an object with the user input results. + +# Prompting for user input + +### Input + +The InputPrompt is a classic entry line like a shell. Because of the underlying readline implementation it offers you to provide completers (like file name completer or string completer). In addition to his, you can define a mask character which is printed on the screen instead of the typed keys like used for hidden password entry. + +```java +promptBuilder.createInputPrompt() // #1 + .name("name") // #2 + .message("Please enter your name") // #3 + .defaultValue("John Doe") // #4 + //.mask('*') // #5 + .addCompleter(new StringsCompleter("Jim", "Jack", "John")) // #6 + .addPrompt(); +``` + +Description: + +1. With the prompt builder call `createInputPrompt()` to create a new input prompt builder +2. Set a name for the prompt. Setting a name is neccessary to pick the right user input from the result object after the user interaction is finished. The resulting object is `HashMap` where each key is the name of a prompt you have created before. +3. Add a message which is printed in front of the user input. +4. (optional) By adding a default value, you offer the user just to press enter to accept the default value. The default value is printed in parentheses after the prompt. +5. (optional) If you add a masking character, each key pressed by the user echoed as this mask character on the console. That's useful for password entries. +6. (optional) You can add completers (like simple string competers, file completers or more complex completers) to simplify the user input. The user can use the TAB button to complete partitial input. See [jline/jline2](https://github.com/jline/jline2/tree/master/src/main/java/jline/console/completer) for details and examples. + +#### Console + +input prompt + +#### User Input + +The user can use readline compatible navigation (mainly Emacs control codes) inside the user input area. This includes CTRL-a to go to the beginning of input, CTRL-e to go to the end, and so on. + +After the input, the entered value is printed in different color right after the prompt. + +#### Result + +The result of this prompt is of type `InputResult` and has a method `getInput()` to the get user input. + +### List + +The ListPrompt lets the user choose one item from a given list. If the list is bigger than the terminal height, the list partially shown and scrolled if needed. + +```java +promptBuilder.createListPrompt() // #1 + .name("pizzatype") // #2 + .message("Which pizza do you want?") // #3 + .newItem().text("Margherita").add() // without name (name defaults to text) #4 + .newItem("veneziana").text("Veneziana").add() // #5 + .newItem("hawai").text("Hawai").add() + .newItem("quattro").text("Quattro Stagioni").add() + // .pageSize(10) #6 + // .relativePageSize(66) #7 + .addPrompt(); +``` + +Description: + +1. With the prompt builder call `createListPrompt()` to create a new list prompt builder. +2. Set a name for the prompt. +3. Add a message which is printed on top of list. +4. Add items to the list. If you call `newItem()` without a name for the item, the text of the item is used in the result. +5. Add items with `newItem()` to give the item a name which make it possible to use a technical key or an other value instead of the printed text as result. +6. (optional) For long lists, you can use `pageSize()` to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height. +7. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is display even when you select a very low value. + +#### Console + +list_prompt + +#### User input + +The user can use up and down keys or VI like the keys `'j'` for down and `'k'` for moving the selector in front of the items to the right position. Pressing the enter button selects the item. + +After the input, the list is erased from the screen and the selected value is printed in different color right after the prompt. + +#### Result + +The result of this prompt is of type `ListResult` and has a method `getSelectedId()` to the get user input. + +### Checkbox + +The checkox input lets the user choose any number of items of a given list. It's possible to add separators between items. Further it's possible to disable items and display a message text, why they are disabled. Sometimes this may be useful to present a consistent user interface with all usually displayed options and an explanation why some items are not usable here. + +```java +promptBuilder.createCheckboxPrompt() // #1 + .name("topping") // #2 + .message("Please select additional toppings:") // #3 + .newSeparator("standard toppings").add() // #4 + .newItem().name("cheese").text("Cheese").add() // #5 + .newItem("bacon").text("Bacon").add() // #6 + .newItem("onions").text("Onions").disabledText("Sorry. Out of stock.").add() // #7 + .newSeparator().text("special toppings").add() + .newItem("salami").text("Very hot salami").check().add() // #8 + .newItem("salmon").text("Smoked Salmon").add() + .newSeparator("and our speciality...").add() + .newItem("special").text("Anchovies, and olives").checked(true).add() // #9 + // .pageSize(10) #10 + // .relativePageSize(66) #11 + .addPrompt(); +``` + +Description: + +1. With the prompt builder call `createCheckboxPrompt()` to create a new checkbox prompt builder. +2. Set a name for the prompt. +3. Add a message which is printed on top of list. +4. Use `newSeparator()` to add a separation element with a describing text. +5. Use `newItem()` like in the list promt to add selectable elements to the checkbox prompt. +6. The name can be set directly with `newItem()` instead of using the `name()` method. +7. With `disabledText()` the item is not selectable, the text is displayed after the item. *Note:* even when the item is disabled it can be checked by default. +8. Use the `check()` method to pre check the corresponding item. +9. For more flexibility you can use `checked()` with a boolean value to select if the item is checked by default. +10. (optional) For long lists, you can use `pageSize()` to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height. +11. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is display even when you select a very low value. + +#### Console + +checkbox_prompt + +#### User input + +The user can use up and down keys or VI like the keys `'j'` for down and `'k'` for moving the selector in front of the items to the right position. Toggeling selection on an item is done with the space bar. Pressing the enter button finished the input. + +After the input, the list is erased from the screen and the names of the selected values are printed in different color right after the prompt. + +#### Result + +The result of this prompt is of type `CheckboxResult` and has a method `getSelectedIds()` to the get user input which is of type`HashSet` containing the names of the selected items. + +### Expandable choice + +The choice prompt lets the user choose one from a given number of possible answers. It is used for requesting input what would be done in a graphical user interface by a message box. It's usable for choices like "yes/no/cancel". Each entry is assigned with a single key stroke to provide a quick input by pressing that key. + +By default only the message and the possible keys are displayed which may make it difficult for new users to know what keystroke is associated with what answer. To get around this, a help mode is integrated. If the user pressed the 'h' button (for help), all possible answers with explanation are shown as a list where the user can choose from. + +```java +promptBuilder.createChoicePrompt() // #1 + .name("payment") // #2 + .message("How do you want to pay?") // #3 + .newItem().name("cash").message("Cash").key('c').asDefault().add() // #4 + .newItem("visa").message("Visa Card").key('v').add() // #5 + .newItem("master").message("Master Card").key('m').add() + .newSeparator("online payment").add() // #6 + .newItem("paypal").message("Paypal").key('p').add() + .addPrompt(); +``` + +Description: + +1. With the prompt builder call `createChoicePrompt()` to create a new choice prompt builder. +2. Set a name for the prompt. +3. Add a message which is printed on the screen. +4. Create new items with name, message and associated key. One of the items can be a default. +5. Create other non default items. +6. Use `newSeparator()` to add a separation element with a describing text. + +#### Console and user input + +By default, the message is displayed and a list of all short keys for selection. The defaults value key is printed in upper case to indicate the default value. The letter 'h' is added to the list by default to activate the more detailed helpful list view. + +expandable_choice_prompt_1 + +If the user presses one of the choice keys, the corresponding message is displayed and can be confirmed with the enter key. + +expandable_choice_prompt_2 + +If the user presses the 'h' key, the long list is displayed. + +expandable_choice_prompt_3 + +The detailed navigation is usable like the list prompt by pressing up and down arrow keys and selecting a value with the enter key. + +#### Result + +The result of this prompt is of type `ExpandableChoiceResult` and has a method `getSelectedId()` to the get user input. + +### Confirmation + +The confirmation prompt lets the user answer with 'yes' or 'no' to a given question. This is the minimalistic version of the choice prompt. + +```java +promptBuilder.createConfirmPromp() // #1 + .name("delivery") // #2 + .message("Is this pizza for delivery?") // #3 + .defaultValue(ConfirmChoice.ConfirmationValue.YES) // #4 + .addPrompt(); +``` + +Description: + +1. With the prompt builder call `createChonfirmPrompt()` to create a new confirmation prompt builder. +2. Set a name for the prompt. +3. Add a message which is printed as prompt. +4. With `defaultValue()` you can set either 'yes' or 'no' as a default. + +#### Console + +confirmation_prompt + +#### User input + +By pressing 'y' or 'n' (or 'j/n' in the german localization) the user can select beween 'yes' and 'no' as answer. By pressing the enter key the user confirms the input. + +#### Result + +The result of this prompt is of type `ConfirmResult` and has a method `getConfirmed()` to the get user input of type `ConfirmChoice.ConfirmationValue` which is an enum of either 'YES' or 'NO'. + diff --git a/doc/screenshots/checkbox_prompt.png b/doc/screenshots/checkbox_prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..74d715d807d79415bd3ec150dda7ebf9f28170e6 GIT binary patch literal 55868 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�)w*z`l06cese0jXvuR`odsJRKU9;7Rgk3SF<%VV$iyNEvL?LdZf;Y?iCrHYhfH_{gLP%>V*n%K1VGBopZ&ilr3xF zj0bjE2P<$_MQ4sntqp=_gOsgZkJsQQ#63Z3VHgp}MZ&>ii~4XfGb0wQQsjsW`U9ko zRNIuZ&xxi3B$j9tY^?YO|G6Pi!byOk#gQzkb8K3IC9lt&U1GNR*p^6bo17xo0!h&n z7%9DX7Z+-s{O}G-p5gI)ba!n0c4H{PZF@WL1u_$NMKAwmqIx;dWx4>~D!K%A&h%(i zdBvsL#J6Te-xp!uWQGrt40-b|kxn_T!pD*Fx*u z@{TUUqMo%tb>r7h91R@re{p&3d<}8Uf4Z9k=gTEAlqf=(0n7Pci^-n@83Jga-o-Wa z4TXCx-1P~86))79f0KTuE(HgW`d=@3@b_h85UKXw<>LH;C+h9|U0YjQ-%x#ZxF8SA z3X9otT@JTB4c&Tc)zQbty>E*4g0J_jC&YCSvsRA5{0k zIq_Qm5FJioWd%K)hKvHc##4n6SU6YYoGkPry&97b=lTM^yXx&{q*jz}7`uFcEYOam zu;Ox8sFGr>evuRL-(#KB1=xViOlcC=`(GMJ09PxP%H(%59edmUh$eKQBG%HfSp|N? zj2xrU4~zuMCeQ?WPgNQSd{@LLh~1qk8fkpLAXxX&m(qU_U_9m{$;@{|#C%qnZpmDZ z%kS==fLUZ_x!UyL1{1yu_PkAD)K=1~xBlu9am>|ujn2I(Hzs^kj z3-JLF@FPZI_FYQk-TLL@S`+dLOgV0^qaM}i{r$%er)_>i)G0eFqpaWuwUah^V5O!L zhFkkmW^gr$)Ywq9SZVt`+^j=RW!qA5cwFR(i2XrbS!gD!3e=BpCE>blrBttmTK==n zYT-0B0U!^0ko)VVX?P*icH^%E`Lm%Il;uJ`S9nz>15GRb3!EsUUrBi#-lh6%ziKG{ zHC06q58mZnrE(rkyeO)B=spZYW~ok8+hb~sJty_QAveV@^ik@_zKdut+fAL#ixIXh zdFdvTm5DoiBH8yqyJy7hpP@RxePh|Do`SVWD)CS%-lJBSa9A&(tT7PmHpaK@xh08@ zP@PG@i)-ll^@WI1H}7tKg3=jEFWZ^^Bf`M=z13vg4*SHJxNq2*wtC$AQD*(dY2W+H zecUV5VkM;goxB*-_2W5_$)lpj7rG!!KTuoR^viPC zG+p>L0@)!x3T@lV(u!d<^C@^j^W%J9zpQA`vnY_KiF|N)o})y-V^5duca=6>Wn`pP zu0!tFd0Y6*&RX3M8A@v?pXt~UaogprzEGavMyxnoN74zJZi8)-@fSUS>>quX7k@XrL9)QwNiNqrx7*6(JtS%R;#zxIJD-7GlJyrIRuU{h_w5&H}*p zxdfqK2=>MRR_LZ{iVaO^H@^>?XQ!kp7eVCIhcTvqN0bL;=)4}qI}CL5=H=j=kjN!2 z24#$n@+<&vGf_t)q=owFD7?>ApV)h_Wgl)rBq=Wt#Mvf)0sDl^M9>miAUOLbj%K@15JBk?GCB;PR)*{ak|~eAbSU8>;@;XhZ2-F zCSqcqp&b1-qR0NFXlR(_wp)-A+=4IQUhZE>fMhamJTW?GQ>=*e^Z6P<|2Lnb9TO$IQGmelNM-;cq+6w8Ne{4I7X-&5{Ve#oU`qK~lxkG$SDa-I$(m1jQhH(~-bR=C40MA!T+}Z} z4W^*pQjS3=k6tDW#!&gcAyZ+~Q1+OYuFxn^YsAbgkNPa6jWbXW;-Y8|zKH9$mK#pe zHY|ax8v(GVr^jP^!tan5a&)rRF_wQ(l=m?63)$}e>aZ1MX3+)t)rcp4Pe=AHLs*~H z!%YQPB_pyJVjy@4;7Mqs1Qt7q;q~XT{5mhjRxq7L;!-IUQVxiIw!F4} z?*{ADtthcjb9RbV%c?(&UQ0&}1__<(Khk8rp*efxgWU5e=RZ80c`)Gru98}1=Ds8D z!Hc>9U_Dk0GhOVM;N9gh3i9^pESPLBX61VB_&6jTnjgQa?TCLr2ulgUOMCIi)4)|f zHgb?|#tqmFQ{+A~+e)cbh`CW0*;Z~qY7KZqs#On9tVI;}!tRWR#o&qaaidGoBC~#- z0J`GdE}PDqyOpO$?P_!u8C9gv4AA2(zYJ6Vz?yoKF%k|=)!S;5RCTt`1N#B4#H@&evI>b91-zY{P0wJ zZ`^WFJ7Nxq2V2R0?^>J-gten|?n#sa>7HVtB7RE7KFnAr88U&rFZa-qO3#ORE&^>@ zZniwbjGhcl`dwJ#?mnGBI>G+_BJF4J>s+2GY!Cvk+-C+s3L{x5OApEBP}}ONRZG<- zBP3Ou%~zXW4uoNITyAIkGVeu*gtT?@k~y^($&M$M!(w<45X+A6B|E$?FCeg}Z^$-U zetD|tul6X;=o6hW%_7rD0Z_E2xWv#IP;Eyt_*^ys1|64T6WEF8a>g&<9rC(N&Hw$;=aIOr7gb#^14LnZ4bD zZ!eEuI|^Q7mWYV8Kexcz5a|-YYRrW{QY0nH4ID0fG9Pdhkl@L0#D$4+VhRuWsgn9$ z@|aYCH@Dlt-~5vl3RaDjk_g1L+lb4lHALWG!L(1ln`1njzvmqtHq}L+xJ{1?=A*Hi z#&_Adh=Q8fW#+L9s(617&oD#WIRMCvrv`k3ne`;x4Ld^}&R)4ocX$$WlF@!s7TwMnMQL=kk{ z*6>D0aoN{Te>}!xt^QRn2RLaWJaHFTwe%vx2b<$KDILAH-T^ z`)NIuNEX8+)UhFlwX6fkxim{@BjaidD0UqD2i3(%QaF*w58VgUh0$Ur-9#4>eSAo; zF8L+s;LEuiX+6pgSUh||K;#yxTb~14P>5&Oez57&6IrG)}7%ZT8`sm*bIsXDDljDg+ z=e+u`?081~RJUZxEO)3;K#jeARlPK{|Q$YNQ29BTjrQ+XZB z2g+Dgrkw2JiU5DtoCJNF)#zqn6V*;!uiDNcoM=!<@;q`)~|I~%+ z=u)pagdh16W?|f6<&!^zGCGHf_~APN&54tekn8r)&!JT-y%K?Uy(0K4tRC-%I+gMt z)VfLU?M)6}!X3YDUz-E9pMG0ko+iBs+l0i>9_Rq`1Tn_pnR8`}#>s_`y|v|c;ta&` z?ue44U>Y0fx0>ivIAnLgVb(KOI*fW4eZ@6cT|?ka@tup^{@o@H7kVzD_X-;^?3&>X z0FNftqAqp+%y$*gD0T)waE+$@d1`WzokCubMKxCprrnE?LS~JMKstOb$c1bq05Ncf zc!*r@uMlTt@4KE1?9dfL(bvs*>lJC=v4?y2zT(}HCiOk}*jyp)bsKh>l>q)3I(-v$ zd2g{;be}47OPvk^!bux((j*hsUEUWv6HX>)`y!Qtm>&+xMQYlg#wJ*>GP76Eu!7G+ zQN}Q(`*)XTdEzaUIMp)fr>Tii;$1e0aninK_kto7SolbKftK1-kFqZ%G}E6O z#+2ExUB^#^S-ygC;$E|P{hJ})@Lkv?Aln3e=zbY7pAMCajp$RyZE-r-lZ77($a=GC z0`vPW_QG4Jgz3sA3DWsX5R|z&L!XMP2+-5{d`OS-UB_C)wINM`$jqjrPNwUm?3HC? zvHX0USOsVG2$oM#@$yNik4fqWK*Q!Wn4QPX1DH)CNO0g0`A>Vew(LLU?-T?Y@x zlcRxb>~=SeI_<44Z!UHC!6BQGQImWZXw%GN&+D)c_tzsLaW}_p$HE3%rIfvD!JKbz zic2_fI`Pp@-UF;|&}CZ~*H+JZkke{8%X^QWI9QK}c&*>@R$#r$i{dz207YajEHRt( zam-IC5d$Wjd5@ciUL)_~i@>lJ{r;6p!k^V@3(pa9t`A!C10|)MvAy&Mi6|_8SFLzI zGkSUqEHh{k9R^ zl2_?Xe+ZT)_2XKDmuH@DN-QzEUk_GnS@v9iRgstz_n8zQVRFy%!<>P~&&LnX?DL)= zii2yu8j(ukQt~4YBAag?i`cIxXbr zq0c8%cGrU^UQP2cIHk7IvP8&D!O5n;Vrw)l`HPyV<5lPx_fbdmGuucqw^|{&Z0Ki-1mGvBDuJFbu4Yb#K@r@5|;y$)Nq>@A2l;&`RwtGm46L#5@U{fGeeO zB7T5lA*sN~IGo`+%^{&Wc|e;2lJi zUnS-HAj{hRT$PcIuY+Z~lA=IN#t>gJf4~flrwyf?dzn4`QccFeqh*Lr>lAP96yyrp z{YC#Wu3XxWh`pH$;_mFbEy?ek<*CJ_Ht&}ZdA51&=h0_6?!OZ7GQ~un?5~)bz zXl|ThQ)!Q)p^a3Su->?py9ifPX;-2et4M;VNJ{sK$A_C3##%h0qAw!x`2@PTg|54w zXKf|qs>3Lwft_$OJDjT@OPXR6mlf2WUA&LZ6s?`NbC)Td_Vp3>GJSOpBq$hv$n)zy z1~OK?d=4N#RL)1!$=B1z@Uy3XLKbcJKdrK7KCQkiDyfeOdMq6_x$*Oz9bUgcpr4n@i z=;P>NPzsf04W1Z^`@L|tfF8;OXm42d8GN?W#WG^2!q3XIOk6r&JjUM|HGpX)b2Q7e zI6nLqRekvuZmY&>G?je#LqKr@`(&Xa;d?E8U7@LN6k>jj#MRi`z>Vi6A5#HPq!C$s zEi?a8qys4e8r*e2&yo>j`!$P{%H8!b>u?Zw&TRRQdX_F4&EGcHxdt%a|ES}lZ{ezc z2(z*(Czj}|-ka=3@vS2cRy}#H$ptR}s!c?#Dg7{4tNlu+LE>k*4i$qm5?l*mBdJI{ z@|1VZVUdKqEcg?g3P4dHk)m<49anV^90LC|!=HEozES}4HfMW4s^I^~cXT#@_?}pg zY32Vv;yYO{5C9lDfiXS%N00}^`J8+VK$D-8%ebZfw+i?Xg;tcBx)(Wg=zqk)kMUAK z!^ko^ZKeE=RL_wCm6V9WN=6g&Kd0pgo)!FxzBHr%DdFG;m=^r3&PYW=KuIrf+n=p9 z>3xaMX{pd($f?#7?sG@E$vAbiy|FO}#5D7PU^|ETAi8disbnE_-0r_Z8j+M;afxsd z8-tWFiHw!aZvhSN08U({s%b6j@nSMU=!(Ulbx@Wzlj_-4^32_8eDdZ0DG6OSTzqLh zm))!aiO&H$L>s^dn2{~!mYJKZ99CmQKRbMybdssTk9T%MED!+_gqdk3t?aZWlV=}7| zi+nOuT!DPbFrcMAA<~CgX_jil^+yrP1Dg=Fh=@_6!&2!J+c>GvwB2lZjoJ9{a6BxU zpo&qIVTWF$<4WZ?qgFW`kTxOs72)v1?fE7UPK|GG7hEu^PXHp=@(DDG`G6%tO-HAA z{aGjHVkIA6lLeo8c0t3-06Lfj5K;dXh<9XVWwpQS@;#jwH{a%Gt;N{@DQM>b4`e6} z-n~ZR)V$uCDWfg^#H?5U!=lr;8zyswSis$r26_sKklQvt`)gKirznGFDHWg?m2&|y zFb>N*I`tx@nbqBpXb^y0>83@d#hU;#L+K!YO6gsM2ktT2>_`rYWW0js6JA4;>zq6gwG5gSZv z5Q#}g7(zkMYU5SDv$I8)ahrXWK{RacB2n2EV0X@JI&cB+Ho?mE$^s3tIjirOl%Ook z$K+0z_4`w;8**wC9{bxB;p6u6dJew{NnF|EK4yoU5s+ zz!xc`VPaaZXLOs@_- z?9oM}oPMas+)TtqQ;8Lju8I$Fc9Y@*08@v5mgx*HlzeqIy; z%^K-tA00g&g#YIEr@TV;U%jr=Mk2?c`t}q2e`ZaeT$j46%}Qs-5>)4YWt;ig#*oSC z*VE573JxDJYplje{0Luh=gAoVdPNZKKu<^aVP#T1Ez5Hau_6ah0_92kZ%m%eM&gUz z_3TU`UY~7<*7yjDRTO>{Lx3pJC8YxKTSoyY0wuvy2`@kdjKuYmSkB28!w|h;?Yzlt zzxriI?zH4Or5Kpy&DwoYN;Vl&9T)5}E~L%YfoOBLmG0=8h)3Lf)VklEJBO5(ec|(x zVEsGU@Kb47)X{pgsMnF>~ny(3GN*z#&)5M!dZ1QUi}NdyRgir-6J(2C{g(uXkfWzSU%u7^V~$`UU>rlEPbI; zKofQILs7ENAvv_4_E*#M)dWHF z7G*exJ1nmFo_{}^GXniwX8UIGtKLR$sQZGX$=Evu|5c##Ik5e=WJ+|PGC)G%Ud?0* zcnkwteXev}uGGV|ICwXPI$FlzAz5Tr^{{*E2$bZ`` zjkGAOAGICNM$ATqn3L9A!FFt*M-nv8q4Z&i5L8~TfIy*vrVn|iNMeqy`lASlh44|t z0<(}edv3A2ycj0a2vdg{fpPTZ-%s>Jk7yxdZzi4m7o7%nOVse9e2zP=1rwlN+*UL# zPmb#~IS@B04S2#(mY4Nth!u5#bqQfC=Iwq_EZ$!pM{>rU0|PXl6F~M989O0=?~TS! zl)nMvKwq!IX^-z6pysMqjlX%kSx@Msr}S?8u7}pQFZ~;|))$r~mP&6!!?KQ`-W};y z{2a)s3t4Wy^_{Fb$bzZPs{nT2 zITBA~>lYFGCd;G-8&gJzv8~bfFWgZnv3W*M%0hzB8X zf=SpL=g|U3u|WJr?Ah(&(^zASkNkbYxDyB|zep~NCr>>xgQGEr3?BTfqx6<`>7o+UFQPn|a75N4InC#*O}rfub9zkAky+bSl$*M9FLGXJ zrI1xOZ*V8k@7ye|^7+iv&?>a6El!a-`hRkFlxn6>?B+P-%QmZu@qB@^Ms`9dD;tJW zX!JDEb9Funs8&uz`w-sKbD6*QXq8$-2@N$A9G$tIUr;*yt!KlGm;4x9#%zj6`kucWbKd$4K0D;?FR3xbL5JgUdmZH2TWj>rstB zUMzZ$JtmUVG5oqxpo>$}>AE}CA;HudSy-hPAVBE-dJqKI@RHNL*VB^8DWDboZJ02n zM%TqUL4b~E`kMOA=dj_9o?uM}7eh8fXqxRCL4+|gOuqBxFnRhhK3Hc5bzjM{+oyau z=G16K5La|eV2xNGX&!-K=NI)b4?V*a7K01a zD}>+sRp7?nu*<%xC!KZKzRVKP$^N&h;yXg-G0&AJYm?J|t*#Q!V>jm`vEq+=d!DY| ze#ba-z%zSA$*K;%5+4Yg+F-w8b3($#w66?_!>%i&(tA(>*JMdYkeYP$IRHWI!<(g5 zsdFQu$>Xt@?0t!0(yc7^7sz=!saiYK)j2N{W}gk7LAu9hXJ$tx;xgqWf#vU7)H?6> z7|-bnfkDeIxz?*%e-~oBbUDZO%OdyH9)x%G^uK*53Ui8iqM=r8_eKgC6$t!}pN#SE zGl`kK3S8QuM7&Z3%o$((BRj-1)LlPdwauBaA{BKJr07P#jA&YdF?AMuP*(xda?*21 z_!%Pbmd7Eg zYDhM}O(D}Ay*n;^UoHrE<-Gldes_Pm?6J*5F}c25a0D+ck9;Hca8d>fi1=5nGlTj< zyq}%F6|tt2Qgq)`f+u=o{8UwN@ZNXVi{z2 zA}-@qAgpM0RwhL$a(Q z-G7g_s1U#EV>j#H$!weW9YKS4*}V0|?qU#yARJ)|fgpCidV*O+t-9`wlv)m+n3z}w zsozE1ayQ9#1TO3Ba`nC^fR^Eg#Z;dCyu(7*i+Q{-ebW?N;S;IidhB1!3R@+^tD1{M z)H*R+vSn_~YIv~4=yLt;E--W^IcDo)U(%HVc86>sIb3D~71vXEF$2k;Z*O$~X9Jhx z6({)dFkm`tiUR*gnzQov1@5sI)8!l;#4}|PbL0LPHT@r)Mum?2k!f=j-feY0{ z3pZR22xA&kLFX~NiP6qcAaWig_nr{Ixykh)8kV6FgTSJCxums+&E&-gZU~ppailjl6dYYTfp= zD$IM(hR5w*1#>ciAA!B$UQiG6O)6=JEnqDwPL>t%4ssp->H5EGj!ajCs0Q`75!mB6 zQ5vid4ET6qVRM2tMo(#@{rRsbKRpYqBwu}xTDC7P_|GH%W%?R~gUJHOD7lFOED-a3 zfUAy1>8GYh+v>-z10a|ZBVFp_6#$+FND=-1yUWCi#v^)G%E~%tpkx6~P+2(R`CK4^ z?!AOM%4r4}%LYBt&le$BcCohZPzbr9PV|aGM*k7?p9(*+NWm)Lce z4#>~*gj%hidJ%?!ZGtRMI>udO?O)8z91b9)_^K!h5-MsNsKNaIC;6h2uvDV1uC7{{ z7W1=T|6r+2yV~daSA$)z?=vm8NHHipjv*B>e0GM?KKmUR+1QB~}#7zR`e+2Rqo`1;0b4Q9&01Apkj{Cy< zCYu)pIXR*LR%f|g4IzE|PA{4I+41p+?A3+*&oKDoo-%^7UK)X2sTm+)B<6Shp)3q= z6t)-NdXXLD{v!$f{U1((tWH|3)I#>B`mpS60&!Q>t|;Q8o#ttH!C zZ_J%kYccX`U!htC5DP9lkvpVgNG7X{L_X%4!dXThH?O1K0$6;sqS_3w$!~PtA0-qj zrUwi5wx+K3hK$%%b1={`D|;D%O}T%l~AOl)>eb-aF9d%471Yj>zb|5O#Ows~P2 z@3=X#oMx**O=h#uSdroW%Z9(cM7?Mj@C2?S;nRfrT<#S>jI*)n@Km_ikk}oU1%X)~ z-H4;r>S`lY8+c;EJ<8l*Hz~i`#^^%eo07wad*+?n|=KXxNSgCdu3$Q=ou$^Iwoceqo@cH-9rH+7V zUE^G5)i1Y2o2w^Kw6;y^sBWj$Rh`t7EZ>WnnRJlP)ZwqbC{sm~XO5o(ZD)i07grfJ zd#_f&Adoyg`7FTltxM?j-F0k(#8#vQ=ia$Q`K=_1-=1w&0II<52Sd-*7xGbELCvb^ zl6zKiHZ``h<@jePCO4NWEiP69Xahtp3OYBTlmY?^rCJqVwmHG4gs6g2B~NK*V;sa; z$58t$zys>9M*x^VRuy?$K2t@H!M&7pM2UUmGC;2G(SJO1s ztrbmD(YcPJX;2qJq0eocx)PscjPK$znFM~Ovmj=oI1K0%7jEZU-w*G%BX`uPIxs0)W{yr^A3Kpo_KcXMe}m9=);B%ya7NN;6GDSEQS>yO3zFE}9z zL!BThMNhA(R7Ue+0g38(GZ!~;e@)GM^bU7c&OHr~>GSN#sCAxy#*_g-vtQd`8O9xh zkn0szP)X+YlId(~v1&-HH1G>2=ZDjQeIK2wTEJ2fyWQO7oqT(~y?+mIDP*ssIT08a zrPWp-x_)_48!MCh4h{p9`1>~WU#ol$9Qxq*RKe0l@0Qt3i*s5+$*aDs(!dg*22=H~ z>XJXtyDR5~q&~Db<%K^v@||?SKKm%QIF8lNhX!bgDm6!68ji zr@UM9wa+fIF}!P6%KX15`^umyxA$#9kS^J@beEKbG)RYZDcvRA-CZIe-62RLCEd~~ zAX0*KH%Pr}pWpwSqvzW@v&Uf=*-x!!t^2-e@tzB$U!KLXX5$-_MWt?2BanJkl9A$H z0fa{3^cKvLT`5IySZ!wQ&CO{YJ9RUmTI1%qrnSKJvzJ^V6rcsyN~j_ zq!%cPU*W`I%&e?h=8sR#*!emagGsAtXOnL=Qy$P}zM`&t19DP2j`1P+C{G)N8RdcG z^6`zq_BZG>3*fC7pswrXsgD)uu|@cT{o8!$|5%dDF(JX>IsqcP7yP(F|2{!kEkH@R zQWtLWQ)OGI9yRr%SG#~q1NZStB+CF$><$%djMMS0=jh$jJPAUk8pgYvYUUOI_Q+(*d?T^rn{tKQtwnzq$Bt_2B8O!lNCv%Ed>8iP3PxZAkBbtBlC}<6n?Dl`9dRym?cZukY!vx`~;U zQeMidrTp1|;M?u{`!hP4>m{G-GQpk?9a}|NHa0~+!xrWN75H(rGm{yrlNevQ24k|; z&;f{qEX|TjTtLGg|%J$pG$FVcO08vC1H0lZg6k2^Uqr>vtmlbC6gVU%2f}v zRE`U6-*-MgsxS$MJe0%0AmWk}>TRW0;6Dmlq+Z-3;cM-JRUcz__$dVyTGrigx*h5R z=+0Xc0(AvKy-xs+`%!7;bBjSLs7>Ow4AXJ?l%>NXp+xNh2eYuZvB&mi|IkhT_d#8a zXgrh((XUt6tTsKADR%XJQOwtzQ%d|v2HEVUCT{*IVd8c*Uc&p-7E9T?Ij?VS_q^9i zinIXlju#1hgjA|+!19=htdGK;skHA|B@|HyZSp5}7{?Y7&9T>{e`g}pZ3fmcla@-a=ePyeqh%?jymzNvb#glEVKUGKGX4JTRnYMqOukYS!oH&@I%se3V z^>L>sAT|YAYohAS>gu+=UggUlH?06F0iK zJUZvtfU0J5T_dx=!gjj9@crtGV4rz^H22~MNh|#~L-d;2=mkhBU7$MH_A-XTh$ySE zeEU2CUr}Y=zOGalNM>4EuAX@zrWOApi?G7qT3{rRCy|LRh5vX zU-pclVYsr)QKu~~(Om((fquvEam1@_K($OzB7!<*im%nE>qV5cevVr;yk~6tjV%UDF&Pyk3j#>pFP0(Z-@R@UH_N{)b$2Vr@z4v&_z8C71Z_dB8dk70+fFh zfmBd>v2%0t?Qiccv<)BtbthFIL)Rbn7;w~NP)`Sqj{|Mg-!Blj7A30OYF~wi^&3GOI;wNR(vvR6t7b^)Ov`FVsiGT zJ{%Y;nt$L~T|jLY;1yz{!hq_-qnD4?e=zUXv9b@f_s1N3FcF<5}Bm%%~A4AKKh=@0BH^e49?lu+Kz4+pNJz`^}`LU_vP|-=Ur%zKu(7 zTA*46xv)T2X${W{&Eq|I=O|GDmwN5XBBj*8DpX2>ewaT*8Y>}r5i z{JCWcswjsZ9E~6W#@BVF=dJ)43l#`-fG#rxLOx!zHOeKWlF@_(2NwrRdQBpPzs`1O z6;-344ewG~#IN6ccF>{s0LiUB{XVAsRkP-F3%jVL-Zzb<{$g$Mk_D$4YeF{#KWRJo zg1HsW(5bf$WrMPdr+d}zQxfzyUvt6|a6qjYHPujBH|6{Df!6)Nt8Z7YwmnXpoVF;S z?P4BTMe}h4Oy(M{x_)(@&htPzd5~-ZRi+Lb?NPKB2R_cDT&JGB+mb!I- z!nk^3H1039G`&Qa-~fG&fJ30$U;;fQ2LGX-w$IfX$N{Lv6#AoZB7+fv%VnTPbnDxx z7%VqxlKs{uf2{ue&h6Xz*Z0*IO$RsKJ9`>sam6mK@@3hjp7znZ9xC$E)!Hvz!*{RT z>Pu4__7l*rzxsBBoM$$gSr>2&Dy4xJmZ~U6yzocD26ltMh+TjK zk=p|9{w7h}`wak7yct031ikqHlV6LKaFtq$RKlON099rf%pav02HOA*r9AyI z0OZwlEG?(;?_K|==lFZh@ee`-FSzR?HAONjwTEAoB`KY4_KMbx61m^|6aU%tc+%00 zB-ecy4~E$>9-UZFzE1L>xE~U8_8>U}K( zxYb%^n0gy{>Ubf?Hqb@Gia&(iF$DN9l8WLXs>~NqfkmpkhLZnK{;jq56LY;Yd%o}H zSWY$Ya(4WBmuB->nso2M6Iw)YZv-4phPl5ZBa;|W4gx>3#e2}BI9@K(|1phU(kgz6 z&t0LrG4e0<^|-}_k|a@FT$sSs<%xaRlujhSK%s{iy$obYnP4^cEL z%O9!~9%=xNnb;#38RsW>c2N!AC~+H&5@3%(TE-VpofnR-UWJY$b)!MuYPE)tkN2xF zd@mV^6`wA89tbGdCc~O?`^&~j}zATYup7Rah94h)`!{)q>PJPwnV z7722SJWz*Z8AcV8@)};{!m_7Ov}ie0*>p6M845g| z0zZ8$k3JeQlQA){+8hHX%gz}wS6rI{G~ncQM|&niIO24aaAo^~tVkH{IzXJVNh_2+ z=fr9R*R@Y=ZyLJ9f6=~7-)t?b$bl1yVlQC1{8Q!vONLn!pKHA_Fjtg?9$q~i%^j?L z-T0*>qoCzLi!d|!3NDDmJ%8O==rd(8(N++DF)@q^?L zwMK`vxMjA50jLRW$U=?vW?bN-R|`s^h1g`?oj8 ze`%inDGbCYF`MFZMT<+%rR@ijSlXO)fANko)GJ6=P3h7dA)hPsKgH8fUy1H?iLHI2 ziHOlLRSxx)`GmZCRcpDm0}6e~`ADknz&`lt2w{B@MqM__CvW9Q(hk!{bE1^~T)$Kh zyXUJ%_Z*^BpWngpE%2$aT$f)g)>hnRYVKTUl@AoF<#$w7esHi_A6P{5?AoW@c_e{9 zq{^`I1!;wY5{2~}ku>Yvc)3oKRO}uaVHGaTD;`}KCY{f!OTE2s$KlfW3E6yxIRC6m z;$FhOeLXRvs#Z$nocQe(WzyV^QP~_SCXwJH>gh+a$aQ#9!RSY2%>55ptuODoE-Wx+4qn{+@=K0DiG^;w%G1Nb&!v@03d7>d45&RFA+zG`@i1oKu(W`wn2%w zBAG23MZL08V*tE=6&d=eQ=oJbP46PaJ!kRPuXqPmq|FnFXu^J=OL+PlJ9c^-fzu@! z!^-P;y;slp8ve?|)kE{K6;NLA%)Avw>PV=%zdi8feR5(8rl8|qBHK+_Ys7Fgx{QEv z0&A*p%Fe!#Q^?;lEm&V+9)F>N9mn(gP%P~XfWxfQ5^s)aRFd2wi?w@4mUa#+_)b0g zvwd4S=TL6dG^z6VPJ(-D3Jb{sWu5bYV~_f)o7$`DqdVvGJTis5vkKpDG;TThJVmA* zoik{bK}cxcMb>klq-{?T;o&3NK~|3mAjOn{ZFCQnhh2ePheY`qw5kehvYv zzTct+$&O^E@0~j_UZE*DbMgTENgF=AJ5Wlz2xzB?VKqVxMzrAHDXoDTaXgR-&&B-> zgT`^?_#9(yg5Wy;1c;@u{XfVcb6GR3Y0gw0-CpF|O&>_hZ!bz;RUe<5C>Qy9TO4-7 zR69a<4t8yklLmtZy|VYpxVaY8(Z+}UX#{}5X3 z|26_xHbuY%=(LzcXbjCplkhdYQ0fRnfIu$$%Fh(J>{{K9S_RB1oA?VIMH=k~LF&p+ zAWHhG(u)54CuUiCvVbb94l42>Fy1XJ8iS(MgX&R)VwRxyskt1m*1U05OaKtBAe1`w zj-~w_t)z;hhtuD2$H{P=h4$CdN>;?xcZ&&%l3I#% z(*wSx>hM{pA^+*>gki4{!O`+x{MlFt!&*=%<|C~Py@Mi3k?sxxv=+ z4N9N@$9}KZ7USsPVBGEpqYNCW1nkCPrC|26jia9PRaZ}P+MQK`jzl0IEMR)|NlF*6 zmmlOnQ%4Q7p^0E!>i_J#V+^!+AUFu~D+Z}4y1!FvTgrLvx6c{*FFp{6-O>fo`QB%i`BRF2DC0W z!_x3>y`Z;SmiCj0piT1T9#3uo7Q1|K2Fi8TTHe?)P!~266u1JSU4e)LeUcx2+rZL1 z;hzDNrR>(TmHMzx{d1tPSkQ*UJb2Pr=oNwJ+s30_qBVdO;@r3qiLAmz{6#_8HXnsF z4jYAFeF?hY?uw&IPlrmqMtD}EFz=zL$P5mndVc(4(cUF-kV1i)Jj46?K_eblI!zW84`qAU&`INSsUB5?f)&%h{*HmA72rX1dJ0ZDB+ zFkud_fL<{U_#Fx|WGRp~zkYmQmhJV-G)gXoUkge>K`A_B-@+J%eU=++`Wms@<@$0! z07LV91RSP8JM$bwH2mzwR!D#vgjzu!npj}rU+k+?m|ua{(P+oA-u%Ds**Dlv=iuEH_`hqg9w51xZV4jC_22Tf3kkG%lvcm5w#@EkyvaZB@M+$xC2tS}WF4G9T|aKrv>mgIVFI+%+e8b3 z3N4}STN6KJaG3iAe&fLCD4v|7NJZ7_J4MI3BKfrS*5MsgvN($a+ec*5JV=rx?)m3{ zDpXe@=0Xa65!>_bL90E!R)-v{oV!{E|M|ryxAm}M5Jf`w5==o2GAJndRl<;CFw1+q z9KQrc73+cy0fp~4Pgo|U9_+ZsfLN=H04QGv8fzRC%St<(YUBRL9i93zN964n+_Tk| z^9@z#cCD|(qR)^L;wANg(8pm?o_mYFLJ>ftc@iIFNf6hQ0mQWi$L=AIyng>N$JSz| zJfn`T#&P2%RI?HV=;SG<^n6WC-n~zgPO(@L@=&E&82s^94LziF%e*429o49>EMDDJ zy6^#S@oQL#B4wd$sHSxUsh6gF#~dPyzi-fL5@>nFPgh+)*7DbnMUns@MQzCeAja6y zYG|KqfK(fYb`)36IL4snrNL{!huYj2IT-@V>1C0BCN$Q;rsYhXm_|ZiYN|Q8i+h)? zh*zAG0TPUvj|bcJ z;O%x;ILcbMGZH496TZ7l{iU~W$CF*M4|#wsJQ`94RH-w8e!^t)btd|x7svQ7v-q;Y z)a^;*iWZKe#@MZ2KFLm(YoT_B%$*l_?j5%9ix#D}Y5xOfrp0h(#;?kAV?3hIdvWx! zVvhJ8?Zn?7+}{d`EVKcq{u=1-k2K&;ObStz_nlK0dW%Sl1mX$_7Ul$;#t?GKG%UYRq+6_W0_EN;(4Xn8PE|Y0a3+VEBf(IaQqoG*q|$r`q29oC91j)!bS%V z{%+rVhB0w;#(Q%iwjCRpUd-AKI;Sl?kLjuOkf1#Ypq2|OPasBasJ{U9@_P;;)6T6?*7Gh7#syplHM+s-i7 z!byCK^fPep=Ap!v#HY9o7owfotOH39`*Zw4@MxizFVYnwK%nlBFXVu=Gn74Q35LU= zn7HQ<1DEFLO&=nS1aFn;V@meocz_=0xqAI@#h-r6mgn~ua?no^*Q{;`OWzwx+!BBJ zR`TEos2t1jKJo>MzQ7W?gfeb6KaG}9t5-Fv1(edoA1lDKMQKYW< z$;ctS>=0}^_*p&pfE-^sb$l&<3&{)9fPsh@Vo1o@D(AJ^S2Ya_cz7X0*9B*dFXq@1 z#bYQ@7HpdOrA&!P9w*II%d<)h0vySep5GIZyW{SdYTL(BtP3U^ox4sq0_M^P_DSaHyoQ0l2(G@iV^ zXSFmu_B*8{-P{#koR5!kX7Fhx6*;^Z#E4>@(1#=_2;Hi(ZXZ1LjZzj-3RhztMn*=4 z5JiO;Wgy~yDpDT%5mcNlh0+?Ss;n%XW&c*VpAyRdk7rAE;ZORp4)@$Dx#D6Z1OWx1 z&SVLOH|8*^vWxtNmo4UallaVk;|OFitQ1a zr*ljT&^4^_C-6yNdxN@bMAxh`i&HyV$5x++(rZF1lRlye-Wu z03Gdlt`o%cZ}wcA+#U`JA^Kbj3Xl6QUkBDc(QPx?6caUj%@p9QjDPkh4Ty0zZBYPh3vORR7v9P zz0s3dN3oPX$(1nEAj)p7xolLvYh>sO-7#(%t#n4@A@RUCkfLu8AQQIqPN;#T(zEp- zU36^uHph%%FnY?0xZHxXNOeZhj~(-F(LufMkMu@HH4u7ay0u5Z2%gK9w>t%1J^1(a6PEg2pHFXriJv z^Zm%K8sn)p)eXLkrC72{gCLj#bU4$|+nA&rN)!+w7{)f>Im|h;NuO2x6c0N~%QqZd zK<*lvFA*mU*x9J~fL>k?Q&xdKInFTZ$z-30J-x|jF+B=Y+~%hS

m8J-J8_7!DnJ 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 Tld8Oto1n;M5;ObGpseN!Nl*OQ+{Y>y){5u6B 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 literal 0 HcmV?d00001 diff --git a/doc/screenshots/expandable_choice_prompt_2.png b/doc/screenshots/expandable_choice_prompt_2.png new file mode 100644 index 0000000000000000000000000000000000000000..4c77b50ce01e4439c6acd672d5de43b63aaf3e23 GIT binary patch literal 18501 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 literal 0 HcmV?d00001 diff --git a/doc/screenshots/expandable_choice_prompt_3.png b/doc/screenshots/expandable_choice_prompt_3.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e6fd1f1b475557ab6d2f1eb4a63aa3ba410559 GIT binary patch literal 28612 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 E10~U{oB#j- literal 0 HcmV?d00001 diff --git a/doc/screenshots/input_prompt.png b/doc/screenshots/input_prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..c4100131f9dfc3c51562825e1f07de0ff96d7b77 GIT binary patch literal 18189 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 O5J@pP(NbYO|NjSox$UI@ literal 0 HcmV?d00001 diff --git a/doc/screenshots/list_prompt.png b/doc/screenshots/list_prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..4096bfc49b1e8e0b5a2dd3f5071a0a2caa16f6cd GIT binary patch literal 27848 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 checkboxItemList; - public Checkbox(String message, String name, List checkboxItemList) { + public Checkbox(String message, String name, int pageSize, PageSizeType pageSizeType, List checkboxItemList) { super(message,name); + if (pageSizeType == PageSizeType.RELATIVE && (pageSize < 1 || pageSize >100)) + throw new IllegalArgumentException("for relative page size, the valid values are from 1 to 100"); + + this.pageSizeType = pageSizeType; + this.pageSize = pageSize; this.checkboxItemList = checkboxItemList; } @@ -25,4 +32,13 @@ public String getMessage() { public ArrayList getCheckboxItemList() { return new ArrayList(checkboxItemList); } + + public int getPageSize() { + return pageSize; + } + + public PageSizeType getPageSizeType() { + return pageSizeType; + } + } diff --git a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java index 9639c0a21..1f4a5e463 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java @@ -12,10 +12,18 @@ */ public class ListChoice extends AbstractPromptableElement { + private final int pageSize; + private final PageSizeType pageSizeType; private List listItemList; - public ListChoice(String message, String name, List listItemList) { + public ListChoice(String message, String name, int pageSize, PageSizeType pageSizeType, List listItemList) { super(message,name); + + if (pageSizeType == PageSizeType.RELATIVE && (pageSize < 1 || pageSize >100)) + throw new IllegalArgumentException("for relative page size, the valid values are from 1 to 100"); + + this.pageSizeType = pageSizeType; + this.pageSize = pageSize; this.listItemList = listItemList; } @@ -26,4 +34,12 @@ public String getMessage() { public ArrayList getListItemList() { return new ArrayList(listItemList); } + + public int getPageSize() { + return pageSize; + } + + public PageSizeType getPageSizeType() { + return pageSizeType; + } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java b/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java new file mode 100644 index 000000000..e7b3df971 --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java @@ -0,0 +1,4 @@ +package de.codeshelf.consoleui.elements; + +public enum PageSizeType { RELATIVE, ABSOLUTE } + diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java index 24c5e6716..059f8af2a 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java @@ -12,7 +12,7 @@ public class ListItem implements ListItemIF { public ListItem(String text, String name) { this.text = text; - if (name==null) { + if (name == null) { this.name = text; } else { this.name = name; @@ -20,11 +20,11 @@ public ListItem(String text, String name) { } public ListItem(String text) { - this(text,text); + this(text, text); } public ListItem() { - this(null,null); + this(null, null); } public String getText() { diff --git a/src/main/java/de/codeshelf/consoleui/examples/LongList.java b/src/main/java/de/codeshelf/consoleui/examples/LongList.java new file mode 100644 index 000000000..4dda9f0ac --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/examples/LongList.java @@ -0,0 +1,63 @@ +package de.codeshelf.consoleui.examples; + +import de.codeshelf.consoleui.prompt.ConsolePrompt; +import de.codeshelf.consoleui.prompt.PromtResultItemIF; +import de.codeshelf.consoleui.prompt.builder.CheckboxPromptBuilder; +import de.codeshelf.consoleui.prompt.builder.ListPromptBuilder; +import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import jline.TerminalFactory; +import org.fusesource.jansi.AnsiConsole; + +import java.io.IOException; +import java.util.HashMap; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: Andreas Wegmann + * Date: 29.11.15 + */ +public class LongList { + + public static void main(String[] args) throws InterruptedException { + AnsiConsole.systemInstall(); + System.out.println(ansi().eraseScreen().render("@|red,italic Hello|@ @|green World|@\n@|reset " + + "This is a demonstration of ConsoleUI java library. It provides a simple console interface\n" + + "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written\n" + + "in JavaScript.|@")); + + + try { + ConsolePrompt prompt = new ConsolePrompt(); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + ListPromptBuilder listPrompt = promptBuilder.createListPrompt(); + listPrompt.name("longlist").message("What's your favourite Letter?").relativePageSize(66); + + for (char letter = 'A'; letter <= 'C'; letter++) + for (char letter2 = 'A'; letter2 <= 'Z'; letter2++) + listPrompt.newItem().text("" + letter + letter2).add(); + listPrompt.addPrompt(); + + CheckboxPromptBuilder checkboxPrompt = promptBuilder.createCheckboxPrompt(); + checkboxPrompt.name("longcheckbox").message("What's your favourite Letter? Select all you want...").relativePageSize(66); + + for (char letter = 'A'; letter <= 'C'; letter++) + for (char letter2 = 'A'; letter2 <= 'Z'; letter2++) + checkboxPrompt.newItem().text("" + letter + letter2).add(); + checkboxPrompt.addPrompt(); + + HashMap result = prompt.prompt(promptBuilder.build()); + System.out.println("result = " + result); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + TerminalFactory.get().restore(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } +} diff --git a/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java b/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java new file mode 100644 index 000000000..bd4ddfefd --- /dev/null +++ b/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java @@ -0,0 +1,48 @@ +package de.codeshelf.consoleui.examples; + +import de.codeshelf.consoleui.prompt.ConsolePrompt; +import de.codeshelf.consoleui.prompt.PromtResultItemIF; +import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import jline.TerminalFactory; +import org.fusesource.jansi.AnsiConsole; + +import java.io.IOException; +import java.util.HashMap; + +import static org.fusesource.jansi.Ansi.ansi; + +/** + * User: Andreas Wegmann + * Date: 12.08.2020 + */ +public class SimpleExample { + + public static void main(String[] args) throws InterruptedException { + AnsiConsole.systemInstall(); + System.out.println(ansi().eraseScreen().render("Simple list example:")); + + try { + ConsolePrompt prompt = new ConsolePrompt(); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder.createListPrompt() + .name("pizzatype") + .message("Which pizza do you want?") + .newItem().text("Margherita").add() // without name (name defaults to text) + .newItem("veneziana").text("Veneziana").add() + .newItem("hawai").text("Hawai").add() + .newItem("quattro").text("Quattro Stagioni").add() + .addPrompt(); + + HashMap result = prompt.prompt(promptBuilder.build()); + System.out.println("result = " + result); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + TerminalFactory.get().restore(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java index 849612635..f49b34549 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java @@ -1,14 +1,19 @@ package de.codeshelf.consoleui.prompt; +import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import jline.Terminal; +import jline.TerminalFactory; import java.io.IOException; import java.util.ArrayList; +import static org.fusesource.jansi.Ansi.ansi; + /** * Abstract base class for all listable prompts (checkbox, list and expandable choice). * This class contains some helper methods for the list prompts. - * + *

* User: Andreas Wegmann * Date: 19.01.16 */ @@ -19,13 +24,85 @@ public abstract class AbstractListablePrompt extends AbstractPrompt { // the item list of the prompt protected ArrayList itemList; + protected Terminal terminal; + /** + * first item in view + */ + protected int topDisplayedItem; + protected int nearBottomMargin = 3; + protected int viewPortHeight; + protected Rollover rollOverMode; /** * Empty default constructor. - * @throws IOException may be thrown by super class + * + * @throws IOException may be thrown by super class */ public AbstractListablePrompt() throws IOException { super(); + terminal = TerminalFactory.get(); + } + + /** + * total height of screen + * @return number of lines on terminal. + */ + protected int screenHeight() { + return terminal.getHeight(); + } + + /** + * calculate renderHeight by relative or absolute type, screen size and item count. + */ + protected void initRendering() { + topDisplayedItem = 0; + if (getPageSizeType() == PageSizeType.ABSOLUTE) + // requested absolute page size plus header plus baseline, but not bigger than screen size + renderHeight = Math.min(screenHeight(), getPageSize() + 2); + else { + // relative page size for complete list plus header plus baseline + renderHeight = (screenHeight()) * getPageSize() / 100; + } + + // if less items than renderHeight, we reduce the height + renderHeight = Math.min(renderHeight, getItemSize() + 2); + + // renderHeight must be at least 3, for a single list item. may be smaller with relative or absolute + // settings, so we correct this to at least 3. + renderHeight = Math.max(3, renderHeight); + + // viewPortHeight is the height of the list items itself, without header and baseline + viewPortHeight = renderHeight - 2; + + // if list size is bigger than viewPort, then we disable the rollover feature. + if (viewPortHeight == getItemSize()) + rollOverMode = Rollover.ALLOWED; + else + rollOverMode = Rollover.HALT_AT_LIST_END; + } + + abstract protected int getPageSize(); + + abstract protected PageSizeType getPageSizeType(); + + protected void gotoRenderTop() { + System.out.println(ansi().cursorUp(renderHeight)); + //System.out.println(ansi().cursor(0, screenHeight() - renderHeight)); + } + + enum Rollover {ALLOWED, HALT_AT_LIST_END} + + /** + * Find the next selectable Item (user pressed 'down'). + * + * @param rollover enables or disables rollover feature when searching for next item + * @return index of the next selectable item. + */ + protected int getNextSelectableItemIndex(Rollover rollover) { + if (rollover == Rollover.ALLOWED) + return getNextSelectableItemIndexWithRollover(); + else + return getNextSelectableItemIndexWithoutRollover(); } /** @@ -33,7 +110,7 @@ public AbstractListablePrompt() throws IOException { * * @return index of the next selectable item. */ - protected int getNextSelectableItemIndex() { + private int getNextSelectableItemIndexWithRollover() { for (int i = 0; i < itemList.size(); i++) { int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); ConsoleUIItemIF item = itemList.get(newIndex); @@ -43,12 +120,40 @@ protected int getNextSelectableItemIndex() { return selectedItemIndex; } + /** + * Find the next selectable Item (user pressed 'down'), but does not start at the beginning + * if end of list is reached. + * + * @return index of the next selectable item. + */ + private int getNextSelectableItemIndexWithoutRollover() { + for (int newIndex = selectedItemIndex + 1; newIndex < itemList.size(); newIndex++) { + ConsoleUIItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + } + + /** + * Find the previous selectable item (user pressed 'up'). + * + * @param rollover enables or disables rollover feature when searching for previous item + * @return index of the previous selectable item. + */ + protected int getPreviousSelectableItemIndex(Rollover rollover) { + if (rollover == Rollover.ALLOWED) + return getPreviousSelectableItemIndexWithRollover(); + else + return getPreviousSelectableItemIndexWithoutRollover(); + } + /** * Find the previous selectable item (user pressed 'up'). * * @return index of the previous selectable item. */ - protected int getPreviousSelectableItemIndex() { + private int getPreviousSelectableItemIndexWithRollover() { for (int i = 0; i < itemList.size(); i++) { int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); ConsoleUIItemIF item = itemList.get(newIndex); @@ -58,6 +163,22 @@ protected int getPreviousSelectableItemIndex() { return selectedItemIndex; } + /** + * Find the previous selectable item (user pressed 'up'), but does not start at end of list if + * beginning of list is reached. + * + * @return index of the previous selectable item. + */ + private int getPreviousSelectableItemIndexWithoutRollover() { + for (int newIndex = selectedItemIndex - 1; newIndex >= 0; newIndex--) { + ConsoleUIItemIF item = itemList.get(newIndex); + if (item.isSelectable()) + return newIndex; + } + return selectedItemIndex; + + } + /** * Find the first selectable item of the item list. * @@ -73,4 +194,31 @@ protected int getFirstSelectableItemIndex() { } throw new IllegalStateException("no selectable item in list"); } + + protected void recalculateViewWindow(boolean upward, boolean downward) { + if (viewPortHeight < getItemSize()) { + if (downward && itemsBelowEnd() && selectedItemNearBottom()) + topDisplayedItem++; + if (upward && itemsAboveTop() && selectedItemNearTop()) + topDisplayedItem--; + } + } + + private boolean selectedItemNearTop() { + return topDisplayedItem + nearBottomMargin - 1 > selectedItemIndex; + } + + private boolean itemsAboveTop() { + return topDisplayedItem > 0; + } + + private boolean selectedItemNearBottom() { + return selectedItemIndex + nearBottomMargin > topDisplayedItem + viewPortHeight; + } + + private boolean itemsBelowEnd() { + return topDisplayedItem + viewPortHeight < getItemSize(); + } + + abstract int getItemSize(); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java index c7b0b1e4d..fde2d59f3 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java @@ -1,20 +1,19 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; import de.codeshelf.consoleui.prompt.reader.ReaderIF; import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; -import org.fusesource.jansi.Ansi; import java.io.IOException; -import java.util.HashSet; import java.util.LinkedHashSet; /** * CheckboxPrompt implements the checkbox choice handling. */ -public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { +public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { // checkbox object to prompt the user for. private Checkbox checkbox; @@ -26,30 +25,26 @@ public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF selections = new LinkedHashSet(); + LinkedHashSet selections = new LinkedHashSet<>(); for (ConsoleUIItemIF item : itemList) { if ((item instanceof CheckboxItem)) { @@ -108,6 +111,38 @@ public CheckboxResult prompt(Checkbox checkbox) return new CheckboxResult(selections); } + /** + * render the checkbox on the terminal. + */ + private void render() { + int itemNumber; + int renderedLines = 0; + + System.out.println(renderMessagePrompt(checkbox.getMessage())); + for (itemNumber = topDisplayedItem; renderedLines < viewPortHeight; itemNumber++, renderedLines++) { + String renderedItem = itemRenderer.render(itemList.get(itemNumber), (selectedItemIndex == itemNumber)); + System.out.println(renderedItem); + } + } + + /* + private void render() { + int itemNumber = 0; + + if (this.renderHeight == 0) { + this.renderHeight = (2 + itemList.size()); + } else { + System.out.println(Ansi.ansi().cursorUp(this.renderHeight)); + } + System.out.println(renderMessagePrompt(this.checkbox.getMessage())); + for (ConsoleUIItemIF checkboxItem : itemList) { + String renderedItem = this.itemRenderer.render(checkboxItem, this.selectedItemIndex == itemNumber); + System.out.println(renderedItem); + itemNumber++; + } + } + */ + /** * Toggles the selection of the currently selected checkbox item. */ diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java index e3146e8c3..bac88d439 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java @@ -1,6 +1,7 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ExpandableChoice; +import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; import de.codeshelf.consoleui.prompt.reader.ReaderIF; @@ -32,6 +33,21 @@ public class ExpandableChoicePrompt extends AbstractListablePrompt implements Pr public ExpandableChoicePrompt() throws IOException { } + @Override + protected int getPageSize() { + return 0; + } + + @Override + protected PageSizeType getPageSizeType() { + return null; + } + + @Override + int getItemSize() { + return expandableChoice.getChoiceItems().size(); + } + enum RenderState { FOLDED, FOLDED_ANSWERED, @@ -69,7 +85,7 @@ private void renderList() { System.out.println(ansi().eraseLine().cursorUp(2).a(renderMessagePrompt(expandableChoice.getMessage())).eraseLine(Ansi.Erase.FORWARD)); System.out.flush(); } else { - System.out.println(ansi().cursorUp(renderHeight)); + gotoRenderTop(); } int itemNumber = 0; @@ -143,10 +159,10 @@ public ExpandableChoiceResult prompt(ExpandableChoice expandableChoice) throws I } } } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - selectedItemIndex = getPreviousSelectableItemIndex(); + selectedItemIndex = getPreviousSelectableItemIndex(Rollover.ALLOWED); chosenItem = (ChoiceItem) itemList.get(selectedItemIndex); } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - selectedItemIndex = getNextSelectableItemIndex(); + selectedItemIndex = getNextSelectableItemIndex(Rollover.ALLOWED); chosenItem = (ChoiceItem) itemList.get(selectedItemIndex); } if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java index 612f94ad9..ef409a433 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java @@ -1,7 +1,7 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.ListChoice; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.impl.ListItem; import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; import de.codeshelf.consoleui.prompt.reader.ReaderIF; @@ -9,41 +9,53 @@ import java.io.IOException; -import static org.fusesource.jansi.Ansi.ansi; - /** * ListPrompt implements the list choice handling. - * + *

* User: Andreas Wegmann * Date: 01.01.16 */ -public class ListPrompt extends AbstractListablePrompt implements PromptIF { +public class ListPrompt extends AbstractListablePrompt implements PromptIF { + // the list to let the user choose from - private ListChoice listChoice; + protected ListChoice listChoice; + /** + * helper class with render functionality. + */ CUIRenderer itemRenderer = CUIRenderer.getRenderer(); + /** + * Empty default constructor. + * + * @throws IOException may be thrown by super class + */ public ListPrompt() throws IOException { super(); } - private void render() { - int itemNumber = 0; + @Override + protected int getPageSize() { + return listChoice.getPageSize(); + } - if (renderHeight == 0) { - renderHeight = 2 + itemList.size(); - } else { - System.out.println(ansi().cursorUp(renderHeight)); - } + @Override + protected PageSizeType getPageSizeType() { + return listChoice.getPageSizeType(); + } - System.out.println(renderMessagePrompt(listChoice.getMessage())); - for (ConsoleUIItemIF listItem : itemList) { - String renderedItem = itemRenderer.render(listItem,(selectedItemIndex == itemNumber)); - System.out.println(renderedItem); - itemNumber++; - } + @Override + protected int getItemSize() { + return itemList.size(); } + /** + * Prompt the user for selecting zero to many choices from a checkbox. + * + * @param listChoice list with items to choose from. + * @return {@link ListResult} which holds the users choices. + * @throws IOException may be thrown by console reader + */ public ListResult prompt(ListChoice listChoice) throws IOException { this.listChoice = listChoice; itemList = listChoice.getListItemList(); @@ -59,28 +71,49 @@ public ListResult prompt(ListChoice listChoice) throws IOException { selectedItemIndex = getFirstSelectableItemIndex(); + initRendering(); render(); ReaderIF.ReaderInput readerInput = reader.read(); while (readerInput.getSpecialKey() != ReaderIF.SpecialKey.ENTER) { + boolean downward = false; + boolean upward = false; + if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { if (readerInput.getPrintableKey().equals('j')) { - selectedItemIndex = getNextSelectableItemIndex(); + selectedItemIndex = getNextSelectableItemIndex(rollOverMode); + downward = true; } else if (readerInput.getPrintableKey().equals('k')) { - selectedItemIndex = getPreviousSelectableItemIndex(); + selectedItemIndex = getPreviousSelectableItemIndex(rollOverMode); + upward = true; } } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - selectedItemIndex = getNextSelectableItemIndex(); + selectedItemIndex = getNextSelectableItemIndex(rollOverMode); + downward = true; } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - selectedItemIndex = getPreviousSelectableItemIndex(); + selectedItemIndex = getPreviousSelectableItemIndex(rollOverMode); + upward = true; } - + if (upward || downward) + recalculateViewWindow(upward, downward); + gotoRenderTop(); render(); readerInput = reader.read(); } ListItem listItem = (ListItem) itemList.get(selectedItemIndex); - ListResult selection=new ListResult(listItem.getName()); - renderMessagePromptAndResult(listChoice.getMessage(),((ListItem) itemList.get(selectedItemIndex)).getText()); - return selection ; + ListResult selection = new ListResult(listItem.getName()); + renderMessagePromptAndResult(listChoice.getMessage(), ((ListItem) itemList.get(selectedItemIndex)).getText()); + return selection; + } + + private void render() { + int itemNumber; + int renderedLines = 0; + + System.out.println(renderMessagePrompt(listChoice.getMessage())); + for (itemNumber = topDisplayedItem; renderedLines < viewPortHeight; itemNumber++, renderedLines++) { + String renderedItem = itemRenderer.render(itemList.get(itemNumber), (selectedItemIndex == itemNumber)); + System.out.println(renderedItem); + } } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java index 8f78fabec..f8b3f7d6f 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java @@ -26,6 +26,9 @@ public CheckboxItemBuilder name(String name) { } public CheckboxItemBuilder text(String text) { + if (this.name == null) { + this.name = text; + } this.text = text; return this; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java index 271e5c516..c41970150 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java @@ -1,6 +1,7 @@ package de.codeshelf.consoleui.prompt.builder; import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import java.util.ArrayList; @@ -13,10 +14,14 @@ public class CheckboxPromptBuilder { private final PromptBuilder promptBuilder; private String name; private String message; + private int pageSize; + private PageSizeType pageSizeType; private List itemList; public CheckboxPromptBuilder(PromptBuilder promptBuilder) { this.promptBuilder = promptBuilder; + this.pageSize = 10; + this.pageSizeType = PageSizeType.ABSOLUTE; itemList = new ArrayList(); } @@ -40,6 +45,18 @@ public CheckboxPromptBuilder message(String message) { return this; } + public CheckboxPromptBuilder pageSize(int absoluteSize) { + this.pageSize = absoluteSize; + this.pageSizeType = PageSizeType.ABSOLUTE; + return this; + } + + public CheckboxPromptBuilder relativePageSize(int relativePageSize) { + this.pageSize = relativePageSize; + this.pageSizeType = PageSizeType.RELATIVE; + return this; + } + public CheckboxItemBuilder newItem() { return new CheckboxItemBuilder(this); } @@ -50,7 +67,7 @@ public CheckboxItemBuilder newItem(String name) { } public PromptBuilder addPrompt() { - Checkbox checkbox = new Checkbox(message, name, itemList); + Checkbox checkbox = new Checkbox(message, name, pageSize, pageSizeType, itemList); promptBuilder.addPrompt(checkbox); return promptBuilder; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java index 042519083..5fd0da599 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java @@ -3,6 +3,7 @@ import de.codeshelf.consoleui.elements.ListChoice; import de.codeshelf.consoleui.elements.items.ListItemIF; import de.codeshelf.consoleui.elements.items.impl.ListItem; +import de.codeshelf.consoleui.elements.PageSizeType; import java.util.ArrayList; import java.util.List; @@ -14,10 +15,14 @@ public class ListPromptBuilder { private final PromptBuilder promptBuilder; private String name; private String message; - private List itemList = new ArrayList(); + private int pageSize; + private PageSizeType pageSizeType; + private List itemList = new ArrayList<>(); public ListPromptBuilder(PromptBuilder promptBuilder) { this.promptBuilder = promptBuilder; + this.pageSize = 10; + this.pageSizeType = PageSizeType.ABSOLUTE; } public ListPromptBuilder name(String name) { @@ -36,6 +41,18 @@ public ListPromptBuilder message(String message) { return this; } + public ListPromptBuilder pageSize(int absoluteSize) { + this.pageSize = absoluteSize; + this.pageSizeType = PageSizeType.ABSOLUTE; + return this; + } + + public ListPromptBuilder relativePageSize(int relativePageSize) { + this.pageSize = relativePageSize; + this.pageSizeType = PageSizeType.RELATIVE; + return this; + } + public ListItemBuilder newItem() { return new ListItemBuilder(this); } @@ -46,7 +63,7 @@ public ListItemBuilder newItem(String name) { } public PromptBuilder addPrompt() { - ListChoice listChoice = new ListChoice(message, name, itemList); + ListChoice listChoice = new ListChoice(message, name, pageSize, pageSizeType, itemList); promptBuilder.addPrompt(listChoice); return promptBuilder; } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 2b99680e3..357ab6cd1 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -64,8 +64,9 @@ public String render(ConsoleUIItemIF item, boolean withCursor) { .fg(checkboxItem.isEnabled() ? Ansi.Color.GREEN : Ansi.Color.WHITE) .a(checkboxItem.isChecked() ? checkedBox : uncheckedBox) .reset().a(checkboxItem.getText() + - (checkboxItem.isDisabled() ? " (" + checkboxItem.getDisabledText() + ")" : "") - ).reset().toString(); + (checkboxItem.isDisabled() ? " (" + checkboxItem.getDisabledText() + ")" : "")) + .eraseLine(Ansi.Erase.FORWARD) + .reset().toString(); } if (item instanceof ListItem) { diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java index 6f62c3d37..baeb0e37e 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -1,6 +1,7 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; import de.codeshelf.consoleui.elements.items.impl.Separator; @@ -21,7 +22,7 @@ public class CheckboxPromptTest { @Test public void renderSimpleList() throws IOException { CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); - List list=new ArrayList(); + List list= new ArrayList<>(); list.add(new CheckboxItem("One")); list.add(new CheckboxItem(true,"Two")); @@ -53,12 +54,12 @@ public ReaderInput read() { return new ReaderInput(SpecialKey.ENTER); } - public ReaderInput readLine(List completer, String promt, String value, Character mask) throws IOException { + public ReaderInput readLine(List completer, String promt, String value, Character mask) { return null; } }); - checkboxPrompt.prompt(new Checkbox("no message", null, list)); + checkboxPrompt.prompt(new Checkbox("no message", null, 10, PageSizeType.ABSOLUTE, list)); } } \ No newline at end of file From 4088694f79fdaace00a3eacfa3f5720ce253aa0a Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 19 Aug 2020 00:16:33 +0200 Subject: [PATCH 102/115] resized images --- doc/screenshots/checkbox_prompt.png | Bin 55868 -> 62113 bytes doc/screenshots/confirmation_prompt.png | Bin 17020 -> 18942 bytes .../expandable_choice_prompt_1.png | Bin 15792 -> 17944 bytes .../expandable_choice_prompt_2.png | Bin 18501 -> 20711 bytes .../expandable_choice_prompt_3.png | Bin 28612 -> 31285 bytes doc/screenshots/input_prompt.png | Bin 18189 -> 19755 bytes doc/screenshots/list_prompt.png | Bin 27848 -> 30389 bytes 7 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/screenshots/checkbox_prompt.png b/doc/screenshots/checkbox_prompt.png index 74d715d807d79415bd3ec150dda7ebf9f28170e6..ff60b567b0ab5cf898d3cceb903ad28958286d9c 100644 GIT binary patch delta 58650 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%0D*wDX`}4N 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�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

m8J-J8_7!DnJ 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 Tldl80;0gAho0HHX=-Q9{i1&X_0 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 J<&wq${|_25knI2f delta 13200 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 diff --git a/doc/screenshots/expandable_choice_prompt_1.png b/doc/screenshots/expandable_choice_prompt_1.png index 597982b5eb0ae88d056f797f3c67828c0b4f93d4..9a2ea74584d248d6d8bbfd985866369e3b488377 100644 GIT binary patch delta 14131 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 delta 11962 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�#FqU>0sb*+aa2KAj!X!?pZ7W$ zWHSn6D3y+^?px(c{**jsBAZHd{+2e3b{IF-PPG$?SfX=Cp8zz7mK?{kB+ADL9;Zqn zGw{!*ya4F}RCFw=L2M>3P7q0ETsY<}kru+W%P>y)$pNguNzn-lF8qV;_BOZ8T zjmB%FyKkDI3m0)*oHxi|H}8*r?j(RdgCAvTZLi1Qt z;!-^k1{q(nxWQ(jlzxhKI8PI*Y2q&>axKG2RafVSf>E8%rl;lHb>FJ6DnEg{(X8T!WvVuU`^A+slb} zf8SF*5rDW`3;!|X;Oc7}rYLT}%IJQ)Us_qe+uOnF-WuO5LZRgJj&`4e(pL-i6Rrko zBR6tNhKjOkTI}wy9!5;HB%MTZReVYUxKamf3p1^^BB$Et@)V-9U}fhcBf;ZJiN#u3 zT{Uz8H*aZ(9BIX~Y&!PfOhoJ_NVPzck;Td!N3+}AQA7APCCg%LoHcI*47*vxVDqdrv+ z#LbzKh6|31PgQ2K_gU>|4(G>jAupfJMj?O4mLSf_i+v9)*4m0ZIYuNUes{I({$g67 zFGHho2hP49?N7;luW7B|yH1ow2f$o2DCX8)Yf4zf4*hImOOQD_OL*~Y2((*0KnsyS zyBO&f)I8t`$h>MCjlZ@8nrIPEe?$R=lmp+9-IW0GG$G5Wk@qfHtwPX&I1`v5%@Hun z(x`C9B(aTpu-?>qXLwS!)Vd?+|LhHMYi~g+uMob|Tc5`(Q>@U7EN|T4=Dw>195-isf_Jho0^+SUNbAj(V-f<6+`V@f}?LO zYopNrJ-qL5-XgZHa2+MKZb_(&UrU0ANCqIwvJ5rerruAl?BU4lzJ!anjuAB}MgZ6hn`1Q!A<}K zm`VIoxG)HWEUeewQ>Rc2@ZCN3UVjvP(OAHr&Hy_4g-oeJG|sKAuO{cW8WHrJugbtX z7EI>=(%*A7MI)f7m#a{sOEAUY3mf;#=rRf3#0LmGL&hC*h}lNe9oepP6IKWQOEJr8 zZC}~Z`z&q^;&>7Y&{<{muGLLf&r)H*8i2Sza(xte8oNR8n*6C|;$zF~HAg3&T1mr&DM&TxUZ?P8L2 zp%%Xu4~^SgV4Ey5MF}o!8^K+I82p*UCU=-j#NE;pMu2yQD)$HrysJQhpNWJz6Up%) zr%)I7TT&gu@8B0QNztehjeKHHyV9f;smF)OW$d4=Uo~!h#``{ZHP+0N2NS<%14@_E zdEZ57i7W7^i{+KR)Em2E3iNzE5r`r%NCGKn) zqng2{Sbn-ZdDnyl^|Z`)81xQ^NW_)7f`#IeiPzaNWpQ_Hjj+qX0}Q_+1$s%y{aK)A zb;)($$^D1C^~J3so8$vMauuV1rn{C|wlUo%o0S5NC|A6x70!{O3a`wDRe%3-v;`~m zh7yi1@8*#;(V8vI0HC+t^nwqM z#PIQk%j7dE^}P-DfRJP9HG(JIS+aQ88Lj9ES;Vwnq@4m?Rc`pb)oBi|M1#1puXJLp5 zG`WA@Es_IEz$}-j9t6Uv{m}ZwU0T449^equ{}JHpZ=a zpCeAPDw+E(SKjYPyK1vwIKJd{S{AFWx|Qn?@JULgmD^!wE9xyKjo8v!tzDU5yPQY% z?@y$R_?Ba~1eR7nY(?^$U&{u5M`)G-v;z5vb?;D!7IDZW4!{}rG}b2J1~YtZu1pDqDZ|!C5rIo+5YfF~*jjvY4~{QFv57UmE0nAE;>$YD^yYJfbcL z_%^^+N9@i{0}w7!$@W*#TN5zuY1I>2EQVmhdiZeA!sw8V&VFsNU&TO4@UVRU>65TR z{?PD^n|FbN%>h<>C8ZS)GCgJBU!*w#$R~g*;`4C;?q@Wtu7{mSCr&*i;}@8?v+ppC$Ci*33tkJ<-HaKa_8GMLmBTsV?vAH5Bm^OqoB8mdl<|_6ApJlwytTosh{8jrzxSDarlsruw&u@%-fKff(1|>BFFi6 z%o9mX?_hkIeizL*ZFJ)tAz)oW6uuAFPxT>Q$Cb9bnaWUz3#L71>9*t*{ray z57$RJR(sA~G0e7@P1oG^k+YrtiGQsUChm+ z42kkozZG!knS9^1-0O*b04VL%GC1E)C8v*8>tu0dxT4$Gbz{OGjKRb>uqb`2p#JoIf z8Pc2A-H!E3pfN7wrIO0@nA+&QMGXC!G zo;zo$uLv$AFzw_VKM|R2)6>=h8FC%Qs_b4OJhZ4Oi9B-J^D8<>1oHv| zU)k6F6r&HAXpgYyd~A7SgB%1-tT{~YWUGK)Tw?J`+s#d#11i`)ah_zQLOqat05V(y z|9Cd?`Ek*!hZ3eSYh8D?iyN=->-NK5J#a(xOaW`xA`EP&pQt`E>yDYVK^n>RN&GkX4D6u&6g*}?< zD{Q*%uD2E%L@cCoYNx1^xdhw!v&v<0nAtQjbb5-(7N=Iz^igB`6&)Yn2jNmeiK8W# z0iCR}%WFJNGbIXH(F9hF8nG@Z{74#@5y@s)jjMPiY`^z&>*m+?4fIcSq-U6Mb{I)g z_J8bwj>8x=57o3HFq^3!XW}Zhe;o4s>1Z=6>$)X}>21qTM8dorNzjQPTE&hTd(A!A z7?3fjB3k=pU)d%yAqt}I__U@K?Vbvd+jA8V?6-VAVEa*6Jqgo(8LG){vK(-cPiH`9 zelaqXz^0e3v2k{K_=<%zA=B;=AB;!sc!9C{n4@P=0~s_Y8C7?aYZQw&A^KE|!6%sk zB3zurtL!rZVGMei3gI6<-1QRROR6DBp28~FteMS|MwRu*S_vJwLh^)`; zD;X6LeR_)b#cNtZva3)f$jF^hIfK@s`z#Z8i^}r(Fx_M7-a^iNR3dqC@?hPHcVERj zAXnLDcNVM;e9~`2F)4|J91%|y#8O$u1Aa1wYSzv?v;33pi#?z4k9aRPy4F+G*1eFP zdLQM4sGZ9mCRx^nD6r^%J_h7edcHlx@c%vSmgG=PU(c;#nQv}RoN9x6(-^X<>B3W@ zKnlw3B8lbpw$TU~7wDG2LFM9>?l;70h3&}?2_=NuaWIXPJPGPgQjTCakWIg2buvS; zpzWUVJM6e>h&>HzuKNQo6Ja%c%q`#V^P7tF+00X~J@Fu|0l!g*-T_aBXO(YA32B|6 zr?VSs64_o+8$6dEdq=JPPN+~#H@@`cj}68#mHTP266XzTtwNX7@nGTML55iF?>L7Z zM3_T{iKJw2xER*e2=+VBOKZy}todF_QwY5HTKA6Z*G)bHFlYqqqonKzX>bYyVCT%FK(STpGGe=Tc=q-Hcp&QwP&tpCc{B@ z-|ht-q?%iyVX%v*?v!0;<*YY`j~IUIlFRjvmi@htwRX39?LZ6g@tIwD^2oZJKa6J7 z|4ex8AFZ{~9_wr{XPBnbgGGM-p6uGLE8MEg8!d)2j$rNG+h@nC3qtPi_*MW`XSbE~ zFqKyn&UFva)lVAJI-iA#2DFOF$nQsVtYxeNfj9ay2g)z4FtHq6$ z8!h?uGB9EJr@92d8kxS@nQlxtGkL_imT7Hk>t*b(lzt7?(Zu)u8 z5)eok;Hp*Y0tu?Y#J2aVBu_@scRHn?ZD?-%rFFnaKGx{5y3K_aAP{pv$8Lrl$+SHa z!A8~HIYu0LO8ETHY?x;ya1%1y5y%-@(@CJ^+^Ua!{^Y}JLIv2qlF4ngBsIATyHx5& zA}dm>?sz3en~gmD5OB!19{MX{e^CrDXcOVLrG~cl3S1$q+T%b^7$x3=XLiZWfbc^#X8wr z>w4R|*G6E6VbWVI_xy>>{74$2Rr!q()F>dU;&$(A4nNx4bBx3{4%J`fmlrMghh)Qz zi=@6TZ77A(2!zRpNER@>wFuabqZ2i0m9Wq!aXy;SrM2iC_rT$$)bcr_ANcu_hi=m~ zSk9ntoBcvbU$**lCTFwjS(Ie*_diu;6l^_Ttz$h4odpvV)OfuPjcLwKJ;x77S}Vy(~|1EAZV9$k`WusQe)ix z_n*{RFrLhzyl#(nTH4LW&T8EWJo^+OgU|fa7#AZ+`9^Y|vT9b_KLdJ+o$_s}mk2gs z>Mw>>fqE1F+C?EoxUZgi2P;XLeO%DyN0}o3!yVkK)1iScQi=>!SpwYMGwDehEH!!7 zuAHy%3cuy@jeSO;HFLoTN5kb(pKKV-c++RVK#ghRDI@T_3%re74M`Mx_((r%g^$a|BEDF9|wLvlVk$Sk+U_{OLmgQ_m^La>WXg%c@v8GW~FLCY)}1zpt0;$1jGX#gsVl1trKZNfv3O6Bj?1vUNYMCV30k8Fd#rub>m;7I(A0r7kSM3kn zf~ceGeHz$g233iqVHxWCX#2IGx~J?7vG6wJp)6KK%ULBlSlj$ zh%p-y$R$Od-(M&IB%XD8q|OLM9w;#WgGof4!$oqhZ6Dd`{wdf~g?%!Yo{x@&vuLJl}9zpHpvTurf-BdZe2?V{{43Sx*@A2r>uPasb%GEZSCS= z=jy3H9Sltckkc-3( z);eCq2N?71Cpu01GkMj|72>^wVjil-v4Nrqs@b}!Qo*4L?S<}-|3W+4Iljrg4+2s{@8TiD>m6EdH*dM8W_F0L|p|pxmI^k?X~a$UW;x$jN`*r%oj74iC1Td)0nFQzMx{6D;(yc z<#Y+Q>@{tI!AmS-ht#gBI>?NMujH7|M}ngmy_HS}MV6bFgH9JQrVPwiXFXeIz?N&G z)QM6(HR7y`b_>+QAlQ=_D80@?zT@hdM}G`M))~PAreRCz!OQ1U^%Yw_2>gj^eO6Xh z@bT`X-&Ghh?%UN0Ina>1EOk2LAywaQ?Q2r&po6%&yeL}M(hw^^;L!aS*^7T|uz@`i zOVwA1s|&>CmduqOFeJA1!4!ySxmZNyI&X8CVf$W?Iv=phV3nuvBJjib&%1mdqXpQ?{_>B$AONQ$RpVbAoGE`npB>zy?)8f%(%d5MKw`K?!u z%{bKzj+M`SI#*ofm8pF5A$Qwj+?J~FynROVk%vl@l$v>Q5lu6%bx4v3uml2DR3urp2t^7K?D!P-Os$jA1 zp?_&{N!`SkQ-a5j%izazL?gnDWG)3;Y-gEY>^#HC17!Z)!mL;ca zWc2+Lg7@3{3S=T5P*E10e2}E+_E~W2u|BJB-r(7(K=}dqJu{g~*T6M;44$7PZV!L4 zbPB(W;i}m7nYGS5GMi!c-~Nst4nCtqh>7nYSNsef;wg80G)W3usg*>gtv*KDOR zSqx<|=c9>*5HzeOH{gS~fccYY5UEn%9WFQ5mg6ZYqIYp>QDfN7O2A4A$3Pz_wa_nRG zYDbe~(8-BM|1N%h85Ml0ija_(b9TM9n^(9ykXJNCF4%4fakSlM#Ud1ZFFVP=y)}_NoNF`IxVw7lajVSvH6n`?$&Kgn=J+7~B!8_v)8(swb?c@T zqXIr-e1KCQK^HvHBv>ctAQ^P_Xe>eceEWz!t}bGIa^`zHe2o#ceYd7h7a#v1@*TaE zhU8(V*cwIsqY{%+DT^cdVc%{+fk6l2wd1NknD;b`O`s2K-3LLI-1DbWDCDW=iH=lv zjR&+KC{gD7G72Fx<@)l$W_|N%%LTr}8Mx96{I$H-AaXQ~Z6&^FSvo5W?hhl|)dSF4 z_#sWmAV%#@ryy+T-mHY={vrPOa?24fjqNDI`aa^7ySV$ z^ibOVYDPk4;<lcUL=p@~wj z2?-p_3ytFyg7W4U@)FJQ(mB*mP8nHG{PR{zj9wG(7H@AsmXR{*X#31W2*;Zb?D2~GP=B#4WE?Z5CJdq;^P-N2&f8==Hzh4`&SOmT^44KV zuVFrji$&T~QdiFoUZHeuTaq{vJ9ZNiArql(UOKnayc!_Q@BZe@Z9$|<(4JAzGGE}z zeG`(QJm@-)&|F}G#zOIZKR)A@&k57cwUgXLZAY-_=FOKT{Jr~tPwNN|D5O5$OtC@DlCu=3{t?`r_DV zlzc{HiM`Szy&nT%fu|w>MkHE}A9ch&^uVd9M{*NnVs|!cqk-+_FyXJ|R<%=D{CEFH zrDc-}lSU-pOi0vbi8^JTS&vK@RSiYU%e>QSoXMu^4{UmT1cUA zAdUgjDZ>D{XBDIX<0#vuyQyti33-C=r=bdUI470;ai8Gl{aEc2jvdNN^y4{$qL$Wg z-9_f>S$fDN@RlJ~^f z*lPo3O)f7_eKLu<^-O=c7=MOOnn_C}n7Ex7?4bJo@C6-|CY^`23}(E5!uK;rE3e)0 zL)u`$om+JUMdXYOYY1)_9}Rnyf}N=iOfJi`Dh9-iT1 z!yP_eGDm_FX}kCXaUn*M#Vr_Lv>W_%O;lkEnYT8ay>)oBh2hFoNrjBH_Bs3Vlqb@U zAHF`zjBacnH{1=ziI1X4Z|-%0&d!8~ zNtAv1{QFAPw&GpK_c?R&wP9oXS4Wyxo-N*bUM4mQUl^PnBsD}eOHx&=7Jzs`N}#2( zi9XS>Su^vhNq})&L8``5NAmdkBAKr8#lKcAb*~ws{C#M#9B_<-O?@eS*$`i2Q-Eo%x^DHWo5)%j2jEv{m<=6w5&=%J+dk9%Xy zHqH+dft>di1&B1R!B`{c&lFg534w3;{Ev zp9fw%z*q##v$0nd>{R2_C(2D7|HX!ld@lKSgS+ZXJI3(8wp1n1{XYM3SKG3&5`pID=oU2wfK99M=P4zrFNW!=VjTIM!>49 zK@Ss{-y_ac0QwEG0PNJzgmM8Ns&u-bbfB+krZQ|GvjjMViSe5UHkt1E4`HubUdpH8s5?vOJEYA z(Avltp=;XNLa&_ymH&H$Kt9y{VhZ_sB zLJin{3M@vNZXh)H9>t|nwdx@szTmw4j2hPG=(#OlAbNPf6@=C2UMhfBqWPW=wF4Z% z1(n9CZC=&QF;>;$m7*Djr+rluqFnnM#$7-;uK#XL(sDsva>ObP9M-f(-`$dPQSe8o z_);~yq|35mjI>*t*yGrEj{uIItXy9Z23X>Z%kg$_fy_E<79IX=W1$b1;^Cz^5@fPJ zDkJ1mxoIY4GRG1piVrQ|&D_0GbI$d%f6tmQg1NIOY}52<0Q|CH)U{HirE&Rq7TBZ8 zqKR_I@q$=T)A~eN{9wvRE9%0P$5I4PS>#2&lKaL|rTpXpi9l^x_QE=wm@DP|8h56b zL>CkJQ4#sbkzbZ8`i54P&#fJz8^ri8Bg`5qA;V?t$)yQ&pQ>Mt~ z^mqHFG0RIK(p4#<&mb7NGqgFb!kXzgI8U&f|Gt1+;ZBu%)lfLNu**F=#nH-B>-|F> zdeV@{*2&l#M4@8f(^9c%?0f#{{;Q9se$oi~4yl2}EIlqZ``pdZfrlA&w)+4OwlyWJ z5ZNUbGCO1uNYAxM`nev|M0%tAw*4KUTXZ+4AK!$E$2ys!Q!+jOWu+buA9Raq2#N1! zn)n->Rz=BhQ|I~?uHXyDaizTXX?>@l=8bqF)2w?+LC?xkegzX+*vVg#zItU;N#LF$ z=3MaLGbHjUDc6fFR@5kzbOJ!Tkm$!`G;peYhxeK&)7ts|zNe-(>@clds2XgpfXVwR z+;lIbH;zo9daR~~vqo1M_2BeKW|`Kd6-`M|!rAr`PzN=+uYcs4)ZGLN&19w*g*KY2nRbd`-xt= z@v%Ic;Ci<1a-{PMi!VgGbI)JY1@&LLM5R0p{$mo{*K#XiVl#;**o!{_G)rwrZpx@op-ZOq7@1pa2}~DNaJZBQG-e_DtDY# z=a*+%QipwTmrl!J8?#F$w+b4tH+r_tI;VgTzeU2IAIwZJUpRmde82zR!@zA0jTEkL z9Bdvtf4_F&bqEwCKH|5!>RBjEWV7~@AhMFEo#6syEkvHEhw?hBF?JPpnEbVv?b_T} zMB$fE&)XYn`K;WRTbzIS7u?8kj-wU+_|sG3U710R&5@V12+EU}Wc@lJ z-?N)0m*AgpxkY0Qdc%43wu!g5AfIFS`D?!7aE8p$yye9zSq}P#x^Lxvlyw$gId&mE=yOyXvn~_}!>*>gW<0c5>4iXiOLBMpBu!8esX)+? z^l78!s`K(&i61nbSGeJ;<{DS-81=Z!^4VUajm67&x4Ade^qM|n2XeKlaRGCQcn72` z-MstrOK;(7E%H#}0j?oW1{_B!Pd1-4|pA&r7QTU~RcAfR<bcv1l_4m~C=#A-TGDjA2fo%>4*ZsV7@f@fU3*3?(| z8gCiP4jybh%W1Iq{ha$it(VXG_>~OHR zi@WrIfS}Z74cjf9I1PA)+?+t_R{wReVZR=@sE6qx&L{JD%FSOa?+z}ssCU?J3I9pZ zQl3&(n2iRV09`h(}; zhegh+kZe!8&S1AkvZw9TaDLjw?CJq z4cgRlk(f%A%CXDw)BAU?mmu$l(>mtO-D}|wM7n& z8sZ}-_HRX6cGTt5>A;SI!<0k|RIDUw4T@5`@9YadBtTtR)eXLYb55dqX^)VduCDLY z5{P=VIc375p1L^<@7m6|ES6I2uj(mW#`KOp%gS%*S^<^_BH)y6*XX5vH46zbcyM z)&x$L{J(Bxi-)5%m&h)qsA_vMFExNMP&im-b ztrGV&=&EVDg?I79tOYRrDo;(Qfe;>wh}D2>SxmAduL2$knT$PoD@DN8m^|y=-XGcE z94~L*oRD>CqOIm8vu$cZB{+F8*RVNkeN5GzyqV^)0A%R%Bk6>jy^dh^bB|#Ok<$_n zCIinO(sd8}d`914n%?>^$=hlGZ4;QXvgvLE=LMwhzM|NAf86>m9TsomhV^6CT znmJU5PmTX#fgVJ(Ew;5O)+r*CC9Rf7>)mqlc72+FlR|H~3#zXGwrJD_$ z^4}wHTt~F4H?_aKm2Eqoy60hxoOrha@Ku zZ1@~v4%DPxZKZ`VqWIL~Wz#E`-qVQSfsyLbqYA#cmU&AE56r`qsW4k>?e_iQGBI(N z428Dm3XfnOjjNu2awwvSB-um9r*bnK;5Fc!8kjSEqSOIFjcArC z?dlr}8v)s8(_g2uHY78J41vu*DX;p!LX_VGydE+OoBZ<95se+b{5$+U<`~2!fKnlh zq<%WvcfY*jbvSkNpW9;Ox|mlV74pw%UI>`7@ml1R+E%BWv_m5Xdc+dri`5wgt%$-@ z5p4(V!>=wo^{g?H(JE_2viuxkiU(Bn&GJ(oca$5?l$f|PemG+^$Dsf@i+Y!seH4Sc zQlyv7_bw{*kNwG=_dh@CO$$-kMs>YPFRXa*MIe{vk058mxWC{b=A@hLr4J z6}ePJWaC`wg@b0*caXRv*=Xp%?Xge0w{FG0vims@{Q~TAiMB|Van@KKPh5GsMRBiC zDvqL@IV)2R{XRcP+bD(t7#aUU;PGZns|UU5r1a&dAUdhZUHEI=*>$}^ayZA+`aU=UrYf2yR;@9e;iE`mM15R;HfiBqS{0#t$~FvqDJ=^fF&kn$)9 z%!SVFj8=(tn-hAUErVJIQ=8s+b?2oFpkBH3J)?Q^vKuQ20V^U%Q&+$p}v* zuo&tc-;fax%C$2d&Of7hJQbVyjApZW^zNEPg5j`c*SqNyCwsx)_A5(Woq?uSwB9OP z7Hqv++uwFvrE}WX0b!L?ZMra3>C^<(U+l>CD^#v13>L8Q9W4~hqn>jVw}j59|B&O> z@WJ6P)WE{>V}BFA6meb}SXiDX9@MlNPiUi+7uT45M4dfXC<8!0p|?sF8G!b(H%xKR z#0U!P(%pHTE#OEInCN&8wuEcxA}l1=PLFeMnZ6g^$zcO-2OMG}8fz0}T_00B$7b*| zLB_wYQKXHE1r^}qFG_76`S6FvDSl;PcbX2+Lvjqb2QfU(*>C&(Yf+~$D!A5e2yY;63>ilW6qaQcLeMCjgWJ?T6_KUrG~{MGJB~=M10>ezu{MYuraKR6e{31 z+YC5<7rYD5u?=|U1&Os}+n`KpZLKE?`w-q&S)wmZ7Txmvx;Td>UL5<-neh(L}6#g%fqpt%^}`6r2?9M^TZW^uMcQKL%=fP;n6j$d==BSH^f&mi%~h|8l`z}-^p0-K}fo=~HX&+?D?6^-fL;LA2lQ$MieuAK8kf})4HG$u*SY*M z3iwx1=M<`RZTiis9AeJmft=gQcaz&y{Vc5<{;DSr4>A5KfY zR}flB^o+8L$EA)vKoVdhU0wubiR3GfxFkucP>U({F?>l6P+Fp5^?P2<9CS2V+^bIz zHSiE%+2O)ONgsU=WQ*?si>8>`-(b6V=eeIY!qcKSy23U@O|^L_jORIFmwMyRR$i(_ zNBK8F=JG5}d-Aq@<}G?gaeU8{%#Cl(ZN)+|DPChu>yDRE6B?{~x$SA;i17rsI_)Ge zDzEr~YH+qJ+MMb0QN;k-$WMcu;<9;5@1hDIVQAdan12X?_~;};C64!w?D8cwIuwNb zeZf(0a6IXqu1fiANILgZ0p9`$>-|o_zA(XDD7dLC?R$2eK`b_{Y@(H zh>w)4dViZ)s7D->D0%t;+*4|L$uy!LJ!4G;A(U)w+#U&i?^j=Pf5XD`6Yyoe-aX=@4gfoct_J?{5eWl zHIGw^9ur33#!?b#5Ek8bJDqlmxajJMgww|Oll-=er90T99Oe5u(gm@c`+@p@D(NH@ zqN5`{!R;X%`{G(4vv-d*h`2s{Dnsj@4+y9JT(Z*llIdM;$adF`(%Vlm91nj1kg3Hz zp)fQSaAMTQ4NQb5)8$WuHUB7?c2l5F@qz1|4%EvVIf-5Hq{{ZT-@H}RuI`t$1dh+p z;tlSyXjRnd+0W|kEH1N7_*Eq0wHeJYz>l&BxK)BjWyfi{Sw=z)7=RHE*ouPDlG=wSa3*L!PHVGAXXKIgXew@QCr) z&{=nxj-5?2E*wjrXHYZbImArC@hhnyTz42u{`8K@+7WY3?(p1ZQhqs;=DqQ!kp_6v z`Seo<&4ctUf$FAdjo6Z$4aCCyv0iNJ2L+#AZaLV|e5U6XUaaBl-(msCRETd?vg~NztTru7^;+YU53&x2VeAR0s>!H1rDfmX8f51z{%esBAZDLnt)SSj|I4p(v*Q2&7Tqtb5m8Os(v5C~H`Ba-nD z5N9#GQ)F3I%lT2?Tc550NS0Oe<3j8-T*pQCma!b?i+t(**vC9szV16_{i=bsU^&sl|L)@J=Ysg+;A=lezgMwJLJ5bAh z?c6YZ@S@=TvB7{9W>A>93slDEM!7jxFC5mEM@OAs&WkrU!X$3W)viU!;8u1Ze++cL zIpmF%1Rkt6?pjGQFOg@tSPYkZ~;r2tfDpPe|ywR)RZYg;iW=eYNCI5s(>IG4I%8Zv~nD|rV z-5#N+h3ps8S&mil>CyJy=5-u`3Z%bi?b;zwM{{n(%RgxomuW?k&*^ zFj#*vfBjmVkIwsgPHbrgP97!(bhynXBT3qB8Ej?>#E*yqE808cZlR1$(#OS`)+!w# z_b4p-1hQO5<3h}fu@nZRMBrcNRU|N|Yw9V{3ku{v@{pi2GjS{eTzUi^wxcC_Xw7u* z?#)36BrA?$DxLgLXa1cnKj>peHH`z2;kqWn%NK^bX3sQc#)!CY%BtBCHMN_HrxPRJ z%}p|uN^=45t_mIRjZ#s&uHAu~?D;Z3$LXA63AzK{3-qaIEtgz&F%-Li;k89$U+%Ku zE|j%e42{FZ9-;5V>eO|ir31}&#(wj){2d#8T74)!su!V(SH2~tKRb*SIh;bp$A_e4!Zcb zS+p_kUM&1sqoC9%FMC+e-w|Zs8>MvVogeFioMQB8b&>Dl^D3T}TsY)FsXUm~%s1P> zFNExDB*$_m6XhM{`o_dwKH*w?kjhq^rmZ(%@pD#Z=FqXg%)=#$IoQ`f`Zk%^pQK%- z`i=yEE|%5(o6PRdJof|PKiPThZ_08!$|4n<5A-=lW56w7uJo@48PDwYK-Momn$sQd zM+qg2|6@0NctWF`Okk*w{m}F)CJ9RuTt%Bv+&$owX>SxiYYI!Fqk`OxDA+YC8o^?X`p*2j{fAFFf}*u%RFVhPIkD&<-23nQ(ep#E@4-o zs9fFh9**bDu58PfFxy8j**{Nw73UlCDMcN^@ZR%2wO7w=SjktvPf}sHzfa(1cdPEr zXrZ%<0&4{8Rr{GVSV-nmF8nJlRy@+Rd`a}A?YwU_{BVj2^X*%#U1eyR47%&@I8~-x zrg~8(kdE+P^u1$lp@$EYtKa*pQaiH+{4&FD?424hHzWUESeG?C-paT(_vf4JMBTWd z&jH-y`*{S`Iio8-f{uceJh2Rf*1(?8vN)nLMj^eFBd=zwq{dL4D#i4iv{$fW%165G z&bSm&^AR5p*TfHsqKh1NvVMkBTsW-&9=l1bEJJ5mQE{K6AzNkFOgHhvo*YB@)fpNypd$1*mRleJe^Vsb>PdeoDkl_VdtR|7+I0hT zp39~NqtzpM)p&FK9%wl}qVZ>9oA{bhUtd!ae4J0x@&R+X2G8H}2X8>Lkjr%u>7PSQ zTTEkq!KYOHRTui;&f-cGYY++u-!&?E@JL~~jUyXX)>(9ERYl)&9|`JcYwhcz`K?&G z9(p$c4eIn83*wJ_2P<>G#i|}B_hfrA>SF|OM<=Vob@a8}?~7ET<%@`u7Q4AIl1T97 z>+wO+P>YQiCGxhP3TLfyU;Dz~pP*7;Lu{XkX}H@k;zYajB#`2>gY^#}_&3C?{6(!L zRfPGpD{RmS5#@z78mj&H%Wxv5?*Wq_(~f`9UrMuhVqFoUj$Nx{wW}0rL_T@HaeSl%JD2%OFDTvpmIzzY--TJXAl|!ABg- z!Sk|-^OPG%7e6OP^`JO!zPzWkkq#;}@it^AKKu?IshxAr+U!q)yhpPI35txoQfkkq zd7sL)GZ0XU7^q2>R?gLp1=$-1_I53vB19Z_Eq^>&G?;n9t(**W4#oA@Xx=NTP8t9+ zIN#fY=U>f+s$V9;zmADq2|Z?${*pxLqb8Pbjjn5?uVhMROo$n{ZWBGd1?c1G=1AC z9;sq-s*1ixXDpDD7ZBL!9sfLQ`r&RfiN@KqXx1 z9NpS%qoHhCvJZvOjJQ)W__(#1`PzKgh`7)5$>tT|n6Sf2|7+_KpSe#*p?>+@18UqF zbYjlwSh~@)Gp$qpbm|6`(-Apxbs0)wW~#ICrL_3FiBo_^N1ff9K=!WoJBF--T?;%S zXTRA63(*{W%?_Z*+i&M?iv;y2MwUz2XAWePk*%h<97=g-xgK9P(FpgzCN+dT^tL`Mzz%!bC{mWQo=xCt+;7Fb|J&5=?yBrGQ1s zxnt&=OS$R+Df5+Pa9^sHmX3>`ejJn>Ipf!-P2{L98QfCI(x|XiD}#mBKE}jCTmMW$h-gO4BE1|M?SQFR!;Wu8iYBgc;AuX3 z6p^2fm7Q_Arq2CoxTY6Ql!}(}+Up5P7}AlJ?Uv6)i?VNAr|HamkzQ&ZoIpi~56go= zKRxV9W&7;li|{tF%Vy?HTd*c7GRRziYaigM$_ZsLYX$%z5@ka7Cf-$=&2%&4T2sTZ}u;>2~d` zOk8mHjGhGwHRlkrz8o!-OjWXfxXRO8-p;+DB9M2t>s8WWa;qKRLRfJ@+6VWhzPG8s zX1=T+T9EH4LbYJ~fFmNyk%gci!6=+odNQ2G?nm=T*$tF)CZhS~B3dIGn^9j2l2Keu zXZo98%dpDKgnm={sYPlTWTxbjLwgmsBC&hU}VA-bgb*#RwGH>z1!M;E2YF| z!_+OB*rw`K13NJrnQ~AyNz@rt!q@;joqNE+OteexM;v?T-RJhKx-=RL z9Ut4R_0lCi{GEFFZLm$AVLzF2We)NYt)-2m%|&-;CO7~3^_e;nZN;0Tz@*0aQWZjM zK=?||c&It3V6=iu&iq~U(;u$E!cU1_iYS!C$#R|g3KdZizFsv&8A&<$Bl(HCli6%c zf4ea4`lWQ&PMlYsSPm%#h;Ok2TSs$R+;0rt2i)rps69R9d9BLJqbLSN@)snGWu>vz zEAOjzS%835-a*m20(#_NpFnkrr>bgPmukymNaTiT0-GMzm2R=`Lds3Y%JGQn&8J&R z=$BCzdR`u6-q=_9J#IXkdf>^7BZb$W6hIT^yTNiP*;6Oa%%DtM9GRuSvCADYRZ=*BI?0p}vhrjzp>Qm9#|XJYBY0%+CEM+TG#Y-q z)wr!jnny1(KM{V;59{!Y`W`OG^HM-6qe8o+SS6WeE`&khIuzLc=EyV&owK+qbZQ6z*AznK187g2!=!e(c;h0pu`F_NqHq_ZuPWEIxlv@#(S}RZ#WTEA8Nr3D9t;~51yT{lS!Cx(6%PCzIFoEa|FX_ zACLcfPC+^xS)dkD&~~V|iJ&`cB<=mf`?rFZU0H+2MeWdjvbx!VI6QR-!Vz$aw);0%Eg-R8Q8JfHUiP15p{`^X`pxWbS z2F?#~GruFmuhwDUIgPkH9_Jfpt;q#U29Yy}$2RQD-Y=_to@^qSQmxv{T8K8}{K5P` z+$hIoguL79%^-m$zAN&FuqVR{zcin**|MLDmauDTRarHKX(LlK)@rOI1|Qa>>d{!Z zd#ima5OqAZwf`KU2NV8}va8<>d6<`dH~xvR!C!A*97PjyHEo?4ad3Mv9RU5z%W64E z@Nx6CBl!(_?QL;!Phwtvk*SAa-h|0$Jm>VN118$aDg4QFab2K@{Pp!ArxOmNa7Ap<6CbhNw7=`p)aSoBCCgS36_aAZ9V zso+m6hmngIXLqaFrd&@m7?8lk?aY2ouiO4iAD7TrEyU`V^``41%C|>?ts};xZY*0g zwwiRSGe5C+_V3BvcjVKs%i~`RI8F$cjcK-#RW5mAhls_=A7U9%@_J}PS11$lS4&Up z!Zd!iSdai>?j-?5dXG(0j&{Ic`M+V-en1ms3i)D`wu@%YnQ~?V2+!fefNcFmzv)tW z)A-k>%Q9xR)V!50J7yAR@A?z2(C^5PQ4*dP@YA5h+RGJYD|mu14GDd5JD-Mk^881+ku~Ii4|Un$t>(|=GljeM~5;4Ci0ll zZQmN)dOtvs*Tw*JIW8-I$rWrqqjvc{!+9AOm@Gq*LR33qe{X5pIQKSJ0IJ64-}Vc> zac|v>nqxa_Ib^?7;ZB;{mmIArtXDUcI+-%PSPinSzQs8=t2XDUzTT*qNuk zGSPKC2UYDqjzeihFv9*hK=WrN2$=Rc$^~+jvFa?3+i)c zJ_m|GmLE3J3(Ot^pyK4o(8q-{hadS{e+Ok#v)3jHhi=xZ)l(fxUhf%FiJ$pi54HfQ zV%=nzQ2b^{`1N?&-N7}n^6RCMBcHJ4H)ZL!_^fc5B_oipF|#|Z0p0--n;yL!r>LQ; z--=EBYmbptz#y-o7@l}h^J)VE^B~s;7LjOhkN0#F#-s@u_AckDSJRt1Vwr2r^UuT$ zE4MDo&N$o47;Jo`%~mkR-tBMDmp?gwSfB*7uT<)2S^d8=Y&|gLt4K2 zmlZN!-gL6RSW7OQ51S%n5~T;Y;%x|=OH;hd6H7o(;zD{yjp@pNgD8Ir$%Nr7OPTG3 zi99hMqq=H_1Ewu;zvNJe+NRu~Ki%_c7fS_Q5gvJmo5Qa|@nS@}H3 zZ>Ayw8-p5@H@FoP9pzU4MDAo&mhnTSH$>Nt1XI3eMnl2d`I0Z|BVPgkJbLjHe!V;` zPBjjqu1jdGK{w-C+JfVvwfb}vk=MS&($ZHHeVvDGCe-K9PxchU4+LGzFP6OYL3;a* zK)j5W|3ofYKRnrDK7Z@8QzY}1&N6PHmqxH%{?g$9f4w|C%IN-^rSVr12YKEv1}0YX z)$BI~U%{C_DAOA&2LNBFe5_iMJhv`~IKkOx)`acL^xl_u@?L=n%0KUnw3EWJ8X$Z~ z5}^~lo!mflFP8D!SEVFex-O>%_9QM#6#(6?PR@_ZWKg!vkC1W3o7|LY0=OcR7O#<{@GJ_6Vuvta~2xap22#`g7E0}?oO z@L}xYa6&+kkM%%e{0nK0)^%ZW8JP6?h|8XS z!OlS1$h8acaL~l5Sw{mX*7ByehHN`+C+T^x+7Eg5Twlwro_u?Gt7OW!`K}_0g-*;h z`&fp$0=VX}vC+N-rK1relzCRtA2gsii1+zSkF>C!jHNg9joM?2O)y=g9-GE|4vS&Y zFoT_wbP{usrR4@0v8ceF<=I$B1o>eQQ^-H&gO5*4gaR)8)7zE#+W*W>CzU(KUE7wX zyiTEuQ`JvVbBVqm(yCFsWSHs3YTpnJ3Sh9){YaWd_9wxPPrZItqY3vR;whB}?r6|; zpV$Am)CP~$W+B2(tiPr(CL6U0WNKxI8Xfr%xTed++W%LWspzB76T$|@*W7Ga+?EW4 z?!ML^M^ns~2}|(Nbqzc_43VCW3qHJW#vmW{a0H!u*2(TI#BZbJ*ZN=(Ir@3zJwVH} z8QyEC9Bp90(l}T*@2Mz#`a5pxJ9&^@g>dcJEo{!}67k~of-INWEVgi@=q^nLm~LL9$2b|crk3y*(EhpKEiSOza-*f7Jf@l zL5uxgx6xDqsBx3?axIt#*?mB3NxsJD{qwL`%7h?(XpZCka>BvzjMf}KS?(6idpy?O zMQJ1NEx#?k<-`Y$ImQiR)15W6A4iC6hd8{a^@X zi2Jnp;a#6lnw4dWHk;}> z4+gOugqmKw^sYw*`)%-HjOxaI@q+?_EaB3(TjT7)6q)=!1YblFa9Jfc*q2q<8Q0`} zZ69dPkKj4I-tLL^h%@|a=|&#k7#?+akgoARv4@%Mt+F0O3@bKaP;q6?j*Vz(VsnZ# zeJ4su*4^x83+akmM~H*-NNU6^b$z%8LdVr*laKq`56)?51lu%$&-ay{a|V-@{` zKXa5ro20JsI8&1pNA-iI*<+7ybHMt`3+kA?3r_tM7OSu zw8a1+89sx}K+UdEtpXh#eLnhglhwN0({ZC9AkF~{QQjf%7iX&X=@V1a%i^#95z(Fr z0lc06L$gLC+)?}BX^>Q4X9N0VYC^XV_$O=mb=Lcq=ez(Ghnq< zAB%yHnL3zqlBZUnU$~GANR6`&dV%%!X_$UQXHao1@FQ@P!8>Kc+l6BFJg%f6z<)#|5A@k??g9MpfjeLRd(uDGswQ|depKB932lD) zpD;4AHRhpRoJ-e(x;y_;sOy&IU;YWcI2LXE3$Fg6WU{U=(tyHiFJ(!H%qViEfmXNA?>xGu+iIa>3?5a*Bv2+ddoXTxBjQ&>-!c` z5E-l;M^F8y1>H?9g>L|;iBfLn>A!#Y*Unzy8>q>?;%mmWYx+-5`k-qJ%4yoEWdEn* z|I45N|3_5*{{sd1f1r}DMwWN|@Pf;K4vD+W$S#L0MkoO~q^T(EkORPb6dj delta 14693 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 M>znD->9}D27j^zrwg3PC delta 24885 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 diff --git a/doc/screenshots/input_prompt.png b/doc/screenshots/input_prompt.png index c4100131f9dfc3c51562825e1f07de0ff96d7b77..9e964f4c4d44492ec5bdcab9a5369a05f9627285 100644 GIT binary patch delta 15956 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 y{eO$&-wh+2f5HDi9RF?@wf Date: Wed, 19 Aug 2020 19:52:29 +0200 Subject: [PATCH 103/115] fixed some typos --- README.md | 4 ++- doc/howto.md | 72 ++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 5b9f9a690..732b30c9d 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,9 @@ You can run this by executing the following from the project root: # Usage +*Hint: see the [how to](doc/HowTo.md) to get a more detailed documentation how to use ConsoleUI.* + + Before you can use ConsoleUI the AnsiConsole library has to be initialized. AnsiConsole.systemInstall(); @@ -78,7 +81,6 @@ From with this `PromptBuilder` you can access UI builder with the following meth - createListPrompt() * creates a list prompt. This prompt lets the user choose one item from a given list. -*See the [how to](doc/howto.md) to get a more detailed documentation how to use ConsoleUI.* # Changes diff --git a/doc/howto.md b/doc/howto.md index b77543abc..d23664aa3 100644 --- a/doc/howto.md +++ b/doc/howto.md @@ -1,10 +1,10 @@ # ConsoleUI programming guide -This document contains a brief introduction in using ConsoleUI. +This document contains a brief introduction using ConsoleUI. ## Introduction -ConsoleUI is a library for prompting the user for different types of input. It provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScript. +ConsoleUI is a library for prompting the user for different types of input. It provides simple UI elements on ANSI console-based terminals. ConsoleUI is inspired by [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScript. ## Features @@ -13,12 +13,12 @@ Console UI currently supports: - Text input with completion and GNU ReadLine compatible editing - Checkboxes - Lists -- Expandable Choices (multiple key based answers for a question with help and optional list navigation) +- Expandable Choices (multiple key-based answers for a question with help and optional list navigation) - Yes/No-Questions ## A small example -The following code presents a simple, but complete code example to use CosoleUI for a selecting an item from a list. +The following code presents a simple, but complete code example to use CosoleUI for selecting an item from a list. ```java package de.codeshelf.consoleui; @@ -76,19 +76,19 @@ Basic steps: 1. ConsoleUI uses [jansi](https://github.com/fusesource/jansi), so you have to initialize it first 2. Create a new `ConsolePrompt` object. -3. Create a `PromptBuilder`. All user interaction can be create with the prompt builder object. -4. In this example we create a `ListPrompt` +3. Create a `PromptBuilder`. All user interactions can be created with the prompt builder object. +4. In this example, we create a `ListPrompt` 1. give it a name ('pizzatype') 2. assign a prompt message ("Which pizza do you want?") - 3. create items with and name (optinal) and a text and add them to the ListPrompt + 3. create items with and name (optional) and a text and add them to the ListPrompt 4. to finish call `addPrompt()` to create the ListPrompt and add it to the prompt builder object. -5. calling `prompt.prompt(promptBuilder.build())` builds all the promts (in this example only one) and enters the user interaction. After all prompts are processes, the `prompt()` method returns an object with the user input results. +5. calling `prompt.prompt(promptBuilder.build())` builds all the prompts (in this example only one) and enters the user interaction. After all prompts are processes, the `prompt()` method returns an object with the user input results. # Prompting for user input ### Input -The InputPrompt is a classic entry line like a shell. Because of the underlying readline implementation it offers you to provide completers (like file name completer or string completer). In addition to his, you can define a mask character which is printed on the screen instead of the typed keys like used for hidden password entry. +The InputPrompt is a classic entry line like a shell. Because of the underlying readline implementation, it offers you to provide completers (like file name completer or string completer). In addition to his, you can define a mask character that is printed on the screen instead of the typed keys like used for hidden password entry. ```java promptBuilder.createInputPrompt() // #1 @@ -103,11 +103,11 @@ promptBuilder.createInputPrompt() // #1 Description: 1. With the prompt builder call `createInputPrompt()` to create a new input prompt builder -2. Set a name for the prompt. Setting a name is neccessary to pick the right user input from the result object after the user interaction is finished. The resulting object is `HashMap` where each key is the name of a prompt you have created before. +2. Set a name for the prompt. Setting a name is necessary to pick the right user input from the result object after the user interaction is finished. The resulting object is `HashMap` where each key is the name of a prompt you have created before. 3. Add a message which is printed in front of the user input. 4. (optional) By adding a default value, you offer the user just to press enter to accept the default value. The default value is printed in parentheses after the prompt. -5. (optional) If you add a masking character, each key pressed by the user echoed as this mask character on the console. That's useful for password entries. -6. (optional) You can add completers (like simple string competers, file completers or more complex completers) to simplify the user input. The user can use the TAB button to complete partitial input. See [jline/jline2](https://github.com/jline/jline2/tree/master/src/main/java/jline/console/completer) for details and examples. +5. (optional) If you add a masking character, each key pressed by the user echoed as masked character on the console. That's useful for password entries. +6. (optional) You can add completers (like simple string completers, file completers or more complex completers) to simplify the user input. The user can use the TAB button to complete partial input. See [jline/jline2](https://github.com/jline/jline2/tree/master/src/main/java/jline/console/completer) for details and examples. #### Console @@ -121,11 +121,11 @@ After the input, the entered value is printed in different color right after the #### Result -The result of this prompt is of type `InputResult` and has a method `getInput()` to the get user input. +The result of this prompt is of type `InputResult` and has a method `getInput()` to get user input. ### List -The ListPrompt lets the user choose one item from a given list. If the list is bigger than the terminal height, the list partially shown and scrolled if needed. +The ListPrompt lets the user choose one item from a given list. If the list is bigger than the terminal height, the list is partially shown and scrolled if needed. ```java promptBuilder.createListPrompt() // #1 @@ -144,11 +144,11 @@ Description: 1. With the prompt builder call `createListPrompt()` to create a new list prompt builder. 2. Set a name for the prompt. -3. Add a message which is printed on top of list. +3. Add a message which is printed on top of the list. 4. Add items to the list. If you call `newItem()` without a name for the item, the text of the item is used in the result. -5. Add items with `newItem()` to give the item a name which make it possible to use a technical key or an other value instead of the printed text as result. +5. Add items with `newItem()` to give the item a name which makes it possible to use a technical key or another value instead of the printed text as a result. 6. (optional) For long lists, you can use `pageSize()` to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height. -7. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is display even when you select a very low value. +7. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed, even when you select a very low value. #### Console @@ -158,15 +158,15 @@ Description: The user can use up and down keys or VI like the keys `'j'` for down and `'k'` for moving the selector in front of the items to the right position. Pressing the enter button selects the item. -After the input, the list is erased from the screen and the selected value is printed in different color right after the prompt. +After the input, the list is erased from the screen and the selected value is printed in a different color right after the prompt. #### Result -The result of this prompt is of type `ListResult` and has a method `getSelectedId()` to the get user input. +The result of this prompt is of type `ListResult` and has a method `getSelectedId()` to get user input. ### Checkbox -The checkox input lets the user choose any number of items of a given list. It's possible to add separators between items. Further it's possible to disable items and display a message text, why they are disabled. Sometimes this may be useful to present a consistent user interface with all usually displayed options and an explanation why some items are not usable here. +The checkbox input lets the user choose any number of items of a given list. It's possible to add separators between items. Further, it's possible to disable items and display a message text, why they are disabled. Sometimes this may be useful to present a consistent user interface with all usually displayed options and an explanation of why some items are not usable here. ```java promptBuilder.createCheckboxPrompt() // #1 @@ -190,15 +190,15 @@ Description: 1. With the prompt builder call `createCheckboxPrompt()` to create a new checkbox prompt builder. 2. Set a name for the prompt. -3. Add a message which is printed on top of list. +3. Add a message which is printed on top of the list. 4. Use `newSeparator()` to add a separation element with a describing text. -5. Use `newItem()` like in the list promt to add selectable elements to the checkbox prompt. +5. Use `newItem()` like in the list prompt to add selectable elements to the checkbox prompt. 6. The name can be set directly with `newItem()` instead of using the `name()` method. 7. With `disabledText()` the item is not selectable, the text is displayed after the item. *Note:* even when the item is disabled it can be checked by default. -8. Use the `check()` method to pre check the corresponding item. -9. For more flexibility you can use `checked()` with a boolean value to select if the item is checked by default. +8. Use the `check()` method to pre-check the corresponding item. +9. For more flexibility, you can use `checked()` with a boolean value to select if the item is checked by default. 10. (optional) For long lists, you can use `pageSize()` to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height. -11. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is display even when you select a very low value. +11. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed even when you select a very low value. #### Console @@ -206,19 +206,19 @@ Description: #### User input -The user can use up and down keys or VI like the keys `'j'` for down and `'k'` for moving the selector in front of the items to the right position. Toggeling selection on an item is done with the space bar. Pressing the enter button finished the input. +The user can use up and down keys or VI like the keys `'j'` for down and `'k'` for moving the selector in front of the items to the right position. Toggling selection on an item is done with the space bar. Pressing the enter button finished the input. -After the input, the list is erased from the screen and the names of the selected values are printed in different color right after the prompt. +After the input, the list is erased from the screen and the names of the selected values are printed in a different color right after the prompt. #### Result -The result of this prompt is of type `CheckboxResult` and has a method `getSelectedIds()` to the get user input which is of type`HashSet` containing the names of the selected items. +The result of this prompt is of type `CheckboxResult` and has a method `getSelectedIds()` to get user input which is of type`HashSet` containing the names of the selected items. ### Expandable choice -The choice prompt lets the user choose one from a given number of possible answers. It is used for requesting input what would be done in a graphical user interface by a message box. It's usable for choices like "yes/no/cancel". Each entry is assigned with a single key stroke to provide a quick input by pressing that key. +The choice prompt lets the user choose one from a given number of possible answers. It is used for requesting input that would be done in a graphical user interface by a message box. It's usable for choices like "yes/no/cancel". Each entry is assigned to a single keystroke to provide a quick input by pressing that key. -By default only the message and the possible keys are displayed which may make it difficult for new users to know what keystroke is associated with what answer. To get around this, a help mode is integrated. If the user pressed the 'h' button (for help), all possible answers with explanation are shown as a list where the user can choose from. +By default, only the message and the possible keys are displayed which may make it difficult for new users to know what keystroke is associated with what answer. To get around this, a help mode is integrated. If the user pressed the 'h' button (for help), all possible answers with explanations are shown as a list where the user can choose from. ```java promptBuilder.createChoicePrompt() // #1 @@ -237,13 +237,13 @@ Description: 1. With the prompt builder call `createChoicePrompt()` to create a new choice prompt builder. 2. Set a name for the prompt. 3. Add a message which is printed on the screen. -4. Create new items with name, message and associated key. One of the items can be a default. -5. Create other non default items. +4. Create new items with name, message, and an associated key. One of the items can be a default. +5. Create other non-default items. 6. Use `newSeparator()` to add a separation element with a describing text. #### Console and user input -By default, the message is displayed and a list of all short keys for selection. The defaults value key is printed in upper case to indicate the default value. The letter 'h' is added to the list by default to activate the more detailed helpful list view. +By default, the message is displayed and a list of all short keys for selection. The default value key is printed in upper case to indicate the default value. The letter 'h' is added to the list by default to activate the more detailed helpful list view. expandable_choice_prompt_1 @@ -259,7 +259,7 @@ The detailed navigation is usable like the list prompt by pressing up and down a #### Result -The result of this prompt is of type `ExpandableChoiceResult` and has a method `getSelectedId()` to the get user input. +The result of this prompt is of type `ExpandableChoiceResult` and has a method `getSelectedId()` to get user input. ### Confirmation @@ -286,9 +286,9 @@ Description: #### User input -By pressing 'y' or 'n' (or 'j/n' in the german localization) the user can select beween 'yes' and 'no' as answer. By pressing the enter key the user confirms the input. +By pressing 'y' or 'n' (or 'j/n' in the german localization) the user can select between 'yes' and 'no' as an answer. By pressing the enter key the user confirms the input. #### Result -The result of this prompt is of type `ConfirmResult` and has a method `getConfirmed()` to the get user input of type `ConfirmChoice.ConfirmationValue` which is an enum of either 'YES' or 'NO'. +The result of this prompt is of type `ConfirmResult` and has a method `getConfirmed()` to get user input of type `ConfirmChoice.ConfirmationValue` which is an enum of either 'YES' or 'NO'. From 02c2bfcf042e7158799979ab4bf225fb7083cf99 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 19 Aug 2020 21:14:53 +0200 Subject: [PATCH 104/115] fixed link to howto --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 732b30c9d..78aace705 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ You can run this by executing the following from the project root: # Usage -*Hint: see the [how to](doc/HowTo.md) to get a more detailed documentation how to use ConsoleUI.* +*Hint: see the [how to](doc/howto.md) to get a more detailed documentation how to use ConsoleUI.* Before you can use ConsoleUI the AnsiConsole library has to be initialized. From 503cdb9eaf3ba52ff9e8962ea27a79a3a763d2a3 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 19 Aug 2020 22:29:04 +0200 Subject: [PATCH 105/115] fixed bug #22, redering list items does not clean the line correctly --- build.gradle | 2 +- .../consoleui/prompt/renderer/CUIRenderer.java | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index dc388a51b..e07fcc36c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } project.group = "de.codeshelf.consoleui" -project.version = "0.0.12" +project.version = "0.0.13" java { withJavadocJar() diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java index 357ab6cd1..791537e54 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java @@ -73,12 +73,14 @@ public String render(ConsoleUIItemIF item, boolean withCursor) { ListItem listItem = (ListItem) item; if (withCursor) { return cursorSymbol + ansi() - .fg(Ansi.Color.CYAN).a(listItem.getText() - ).reset().toString(); + .fg(Ansi.Color.CYAN).a(listItem.getText()) + .eraseLine(Ansi.Erase.FORWARD) + .reset().toString(); } else { return noCursorSpace + ansi() - .fg(Ansi.Color.DEFAULT).a(listItem.getText() - ).reset().toString(); + .fg(Ansi.Color.DEFAULT).a(listItem.getText()) + .eraseLine(Ansi.Erase.FORWARD) + .reset().toString(); } } @@ -86,10 +88,14 @@ public String render(ConsoleUIItemIF item, boolean withCursor) { ChoiceItem checkboxItem = (ChoiceItem) item; if (withCursor) { return cursorSymbol + ansi() - .fg(Ansi.Color.CYAN).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()).reset().toString(); + .fg(Ansi.Color.CYAN).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()) + .eraseLine(Ansi.Erase.FORWARD) + .reset().toString(); } else return noCursorSpace + ansi() - .fg(Ansi.Color.DEFAULT).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()).reset().toString(); + .fg(Ansi.Color.DEFAULT).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()) + .eraseLine(Ansi.Erase.FORWARD) + .reset().toString(); } if (item instanceof Separator) { From c5e0c6ff22d1db77c7abf343a11e345f709a8163 Mon Sep 17 00:00:00 2001 From: awegmann Date: Wed, 19 Aug 2020 23:09:43 +0200 Subject: [PATCH 106/115] updated change log --- README.md | 4 ++++ doc/howto.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 78aace705..192553711 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,10 @@ From with this `PromptBuilder` you can access UI builder with the following meth # Changes +### Version 0.0.13 + +- Fixed bug #22: lists are not rendered correctly + ### Version 0.0.12 - Fixed Bug #20: Lists higher than the terminal height were not handled correctly. diff --git a/doc/howto.md b/doc/howto.md index d23664aa3..d772da382 100644 --- a/doc/howto.md +++ b/doc/howto.md @@ -111,7 +111,7 @@ Description: #### Console -input prompt +input prompt #### User Input From 08991c0841b8f4a089a50b747cffec2ec0dcfff4 Mon Sep 17 00:00:00 2001 From: Andreas Wegmann Date: Thu, 20 Aug 2020 08:58:22 +0200 Subject: [PATCH 107/115] Changed link to point to search.maven.org in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 192553711..09c41bab6 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Console UI uses jansi and jline for the dirty console things. # Maven artefact -ConsoleUI releases are available at Maven Central [de.codeshelf.consoleui » consoleui](https://mvnrepository.com/artifact/de.codeshelf.consoleui/consoleui) +ConsoleUI releases are available at Maven Central [de.codeshelf.consoleui » consoleui](https://search.maven.org/artifact/de.codeshelf.consoleui/consoleui) # Test Run From 8183dd995da505bf3c75c4d91bacfa1202612e16 Mon Sep 17 00:00:00 2001 From: mattirn Date: Wed, 3 Feb 2021 19:50:34 +0100 Subject: [PATCH 108/115] Upgrade JLine to 3.19.0 --- build.gradle | 3 +- .../java/de/codeshelf/consoleui/Basic.java | 74 ++- .../consoleui/elements/Checkbox.java | 4 +- .../consoleui/elements/ExpandableChoice.java | 9 +- .../consoleui/elements/InputValue.java | 21 - .../consoleui/elements/ListChoice.java | 4 +- .../elements/PromptableElementIF.java | 1 + .../elements/items/CheckboxItemIF.java | 3 + .../elements/items/ChoiceItemIF.java | 9 +- .../elements/items/ConsoleUIItemIF.java | 10 + .../elements/items/impl/CheckboxItem.java | 3 +- .../elements/items/impl/ChoiceItem.java | 4 + .../elements/items/impl/Separator.java | 4 + .../consoleui/examples/LongList.java | 46 +- .../consoleui/examples/SimpleExample.java | 37 +- .../prompt/AbstractListablePrompt.java | 224 ------- .../consoleui/prompt/AbstractPrompt.java | 592 ++++++++++++++++-- .../consoleui/prompt/CheckboxPrompt.java | 153 ----- .../consoleui/prompt/CheckboxResult.java | 14 +- .../consoleui/prompt/ConfirmPrompt.java | 125 ---- .../consoleui/prompt/ConfirmResult.java | 6 +- .../consoleui/prompt/ConsolePrompt.java | 328 ++++++---- .../prompt/ExpandableChoicePrompt.java | 195 ------ .../prompt/ExpandableChoiceResult.java | 6 +- .../consoleui/prompt/InputPrompt.java | 73 --- .../consoleui/prompt/InputResult.java | 6 +- .../consoleui/prompt/ListPrompt.java | 119 ---- .../consoleui/prompt/ListResult.java | 6 +- .../codeshelf/consoleui/prompt/PromptIF.java | 2 +- ...ultItemIF.java => PromptResultItemIF.java} | 3 +- .../ExpandableChoicePromptBuilder.java | 7 +- .../prompt/builder/InputValueBuilder.java | 15 - .../prompt/reader/ConsoleReaderImpl.java | 120 ---- .../consoleui/prompt/reader/ReaderIF.java | 67 -- .../prompt/renderer/CUIRenderer.java | 131 ---- .../resources/consoleui_messages.properties | 6 +- .../consoleui_messages_de_DE.properties | 6 +- .../consoleui/prompt/CheckboxPromptTest.java | 33 - .../consoleui/prompt/PromptBuilderTest.java | 9 +- 39 files changed, 898 insertions(+), 1580 deletions(-) delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/ListPrompt.java rename src/main/java/de/codeshelf/consoleui/prompt/{PromtResultItemIF.java => PromptResultItemIF.java} (60%) delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java delete mode 100644 src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java diff --git a/build.gradle b/build.gradle index e07fcc36c..b46722ba4 100644 --- a/build.gradle +++ b/build.gradle @@ -25,8 +25,7 @@ compileJava { dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' - compile 'org.fusesource.jansi:jansi:1.11' - compile 'jline:jline:2.14.6' + compile 'org.jline:jline:3.19.0' } javadoc { diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index 3b9ec17a2..cef614e4c 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -3,16 +3,19 @@ import de.codeshelf.consoleui.elements.ConfirmChoice; import de.codeshelf.consoleui.prompt.ConfirmResult; import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.PromtResultItemIF; +import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; +import de.codeshelf.consoleui.prompt.PromptResultItemIF; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; -import jline.TerminalFactory; -import jline.console.completer.StringsCompleter; -import org.fusesource.jansi.AnsiConsole; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; +import org.jline.utils.AttributedStyle; +import org.jline.utils.OSUtils; -import java.io.IOException; -import java.util.HashMap; - -import static org.fusesource.jansi.Ansi.ansi; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * User: Andreas Wegmann @@ -20,16 +23,35 @@ */ public class Basic { - public static void main(String[] args) throws InterruptedException { - AnsiConsole.systemInstall(); - System.out.println(ansi().eraseScreen().render("@|red,italic Hello|@ @|green World|@\n@|reset " + - "This is a demonstration of ConsoleUI java library. It provides a simple console interface\n" + - "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written\n" + - "in JavaScript.|@")); - - - try { - ConsolePrompt prompt = new ConsolePrompt(); + private static void addInHeader(List header, String text) { + addInHeader(header, AttributedStyle.DEFAULT, text); + } + + private static void addInHeader(List header, AttributedStyle style, String text) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.style(style).append(text); + header.add(asb.toAttributedString()); + } + + public static void main(String[] args) { + List header = new ArrayList<>(); + AttributedStyle style = new AttributedStyle(); + addInHeader(header, style.italic().foreground(2), "Hello World!"); + addInHeader(header, "This is a demonstration of ConsoleUI java library. It provides a simple console interface"); + addInHeader(header, "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written"); + addInHeader(header, "in JavaScript."); + try (Terminal terminal = TerminalBuilder.builder().build()) { + UiConfig config; + if (terminal.getType().equals(Terminal.TYPE_DUMB) || terminal.getType().equals(Terminal.TYPE_DUMB_COLOR)) { + System.out.println(terminal.getName() + ": " + terminal.getType()); + throw new IllegalStateException("Dumb terminal detected.\nConsoleUi requires real terminal to work!\n" + + "Note: On Windows Jansi or JNA library must be included in classpath."); + } else if (OSUtils.IS_WINDOWS) { + config = new UiConfig(">", "( )", "(x)", "( )"); + } else { + config = new UiConfig("\u276F", "\u25EF ", "\u25C9 ", "\u25EF "); + } + ConsolePrompt prompt = new ConsolePrompt(terminal, config); PromptBuilder promptBuilder = prompt.getPromptBuilder(); @@ -37,8 +59,7 @@ public static void main(String[] args) throws InterruptedException { .name("name") .message("Please enter your name") .defaultValue("John Doe") - //.mask('*') - .addCompleter(new StringsCompleter("Jim", "Jack", "John")) + // .mask('*') .addPrompt(); promptBuilder.createListPrompt() @@ -88,21 +109,16 @@ public static void main(String[] args) throws InterruptedException { .defaultValue(ConfirmChoice.ConfirmationValue.YES) .addPrompt(); - HashMap result = prompt.prompt(promptBuilder.build()); + Map result = prompt.prompt(header, promptBuilder.build()); System.out.println("result = " + result); ConfirmResult delivery = (ConfirmResult) result.get("delivery"); - if (delivery.getConfirmed()== ConfirmChoice.ConfirmationValue.YES) { + if (delivery.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) { System.out.println("We will deliver the pizza in 5 minutes"); } - } catch (IOException e) { + + } catch (Exception e) { e.printStackTrace(); - } finally { - try { - TerminalFactory.get().restore(); - } catch (Exception e) { - e.printStackTrace(); - } } }} diff --git a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java index 290b51531..285197a0b 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java +++ b/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java @@ -29,8 +29,8 @@ public String getMessage() { return message; } - public ArrayList getCheckboxItemList() { - return new ArrayList(checkboxItemList); + public List getCheckboxItemList() { + return checkboxItemList; } public int getPageSize() { diff --git a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java index 6efae6532..8ed6d9fe6 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.LinkedHashSet; +import java.util.List; /** * User: Andreas Wegmann @@ -12,14 +13,14 @@ */ public class ExpandableChoice extends AbstractPromptableElement { - private LinkedHashSet choiceItems; + private List choiceItems; - public ExpandableChoice(String message, String name, LinkedHashSet choiceItems) { + public ExpandableChoice(String message, String name, List choiceItems) { super(message, name); this.choiceItems = choiceItems; } - public ArrayList getChoiceItems() { - return new ArrayList(choiceItems); + public List getChoiceItems() { + return choiceItems; } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java index bb26897c6..05e3d7ddd 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java +++ b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java @@ -1,10 +1,5 @@ package de.codeshelf.consoleui.elements; -import jline.console.completer.Completer; - -import java.util.ArrayList; -import java.util.List; - /** * User: Andreas Wegmann * Date: 06.01.16 @@ -12,7 +7,6 @@ public class InputValue extends AbstractPromptableElement { private String value; private String defaultValue; - private List completer; private Character mask; public InputValue(String name, String message) { @@ -37,21 +31,6 @@ public String getDefaultValue() { return defaultValue; } - public List getCompleter() { - return completer; - } - - public void setCompleter(List completer) { - this.completer = completer; - } - - public void addCompleter(Completer completer) { - if (this.completer==null) { - this.completer=new ArrayList(); - } - this.completer.add(completer); - } - public void setMask(Character mask) { this.mask = mask; } diff --git a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java index 1f4a5e463..d4ced2b8d 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java +++ b/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java @@ -31,8 +31,8 @@ public String getMessage() { return message; } - public ArrayList getListItemList() { - return new ArrayList(listItemList); + public List getListItemList() { + return listItemList; } public int getPageSize() { diff --git a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java index e74921b56..d4265a231 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java @@ -7,4 +7,5 @@ public interface PromptableElementIF { String getName(); + String getMessage(); } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java index 0df83319c..dd5855af7 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java @@ -5,4 +5,7 @@ * Date: 01.01.16 */ public interface CheckboxItemIF extends ConsoleUIItemIF { + default boolean isChecked() { + return false; + } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java index bc4e0846a..c50c86d52 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java @@ -4,5 +4,12 @@ * User: Andreas Wegmann * Date: 13.01.16 */ -public interface ChoiceItemIF extends ConsoleUIItemIF { +public interface ChoiceItemIF extends ConsoleUIItemIF, ListItemIF { + default boolean isDefaultChoice() { + return false; + } + + default Character getKey() { + return ' '; + } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java index 9a5b794e7..942fe3c8e 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java @@ -8,4 +8,14 @@ public interface ConsoleUIItemIF { boolean isSelectable(); String getName(); + + default boolean isDisabled() { + return false; + } + + String getText(); + + default String getDisabledText() { + return ""; + } } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java index 02efbff4e..2ff0260cf 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java @@ -1,12 +1,13 @@ package de.codeshelf.consoleui.elements.items.impl; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; /** * User: Andreas Wegmann * Date: 07.12.15 */ -public class CheckboxItem implements CheckboxItemIF { +public class CheckboxItem implements CheckboxItemIF, ConsoleUIItemIF { boolean checked; String text; String disabledText; diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java index db7bc7e23..e965b9930 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java @@ -31,6 +31,10 @@ public String getMessage() { return message; } + public String getText() { + return message; + } + public boolean isSelectable() { return true; } diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java index 45546535f..b21aa8b49 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java +++ b/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java @@ -22,6 +22,10 @@ public String getMessage() { return message; } + public String getText() { + return message; + } + public boolean isSelectable() { return false; } diff --git a/src/main/java/de/codeshelf/consoleui/examples/LongList.java b/src/main/java/de/codeshelf/consoleui/examples/LongList.java index 4dda9f0ac..1723e61ec 100644 --- a/src/main/java/de/codeshelf/consoleui/examples/LongList.java +++ b/src/main/java/de/codeshelf/consoleui/examples/LongList.java @@ -1,17 +1,20 @@ package de.codeshelf.consoleui.examples; import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.PromtResultItemIF; +import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; +import de.codeshelf.consoleui.prompt.PromptResultItemIF; import de.codeshelf.consoleui.prompt.builder.CheckboxPromptBuilder; import de.codeshelf.consoleui.prompt.builder.ListPromptBuilder; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; -import jline.TerminalFactory; -import org.fusesource.jansi.AnsiConsole; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; import java.io.IOException; -import java.util.HashMap; - -import static org.fusesource.jansi.Ansi.ansi; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * User: Andreas Wegmann @@ -19,16 +22,18 @@ */ public class LongList { - public static void main(String[] args) throws InterruptedException { - AnsiConsole.systemInstall(); - System.out.println(ansi().eraseScreen().render("@|red,italic Hello|@ @|green World|@\n@|reset " + - "This is a demonstration of ConsoleUI java library. It provides a simple console interface\n" + - "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written\n" + - "in JavaScript.|@")); - - - try { - ConsolePrompt prompt = new ConsolePrompt(); + public static void main(String[] args) { + List header = new ArrayList<>(); + header.add(new AttributedStringBuilder() + .append("This is a demonstration of ConsoleUI java library. It provides a simple console interface").toAttributedString()); + header.add(new AttributedStringBuilder() + .append("for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written").toAttributedString()); + header.add(new AttributedStringBuilder() + .append("in JavaScript.").toAttributedString()); + + try (Terminal terminal = TerminalBuilder.builder().build()) { + UiConfig config = new UiConfig(">", "( )", "(x)", "( )"); + ConsolePrompt prompt = new ConsolePrompt(terminal, config); PromptBuilder promptBuilder = prompt.getPromptBuilder(); ListPromptBuilder listPrompt = promptBuilder.createListPrompt(); @@ -47,17 +52,10 @@ public static void main(String[] args) throws InterruptedException { checkboxPrompt.newItem().text("" + letter + letter2).add(); checkboxPrompt.addPrompt(); - HashMap result = prompt.prompt(promptBuilder.build()); + Map result = prompt.prompt(header, promptBuilder.build()); System.out.println("result = " + result); } catch (IOException e) { e.printStackTrace(); - } finally { - try { - TerminalFactory.get().restore(); - } catch (Exception e) { - e.printStackTrace(); - } } - } } diff --git a/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java b/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java index bd4ddfefd..69c8a4f8b 100644 --- a/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java +++ b/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java @@ -1,15 +1,17 @@ package de.codeshelf.consoleui.examples; import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.PromtResultItemIF; +import de.codeshelf.consoleui.prompt.PromptResultItemIF; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; -import jline.TerminalFactory; -import org.fusesource.jansi.AnsiConsole; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; import java.io.IOException; -import java.util.HashMap; - -import static org.fusesource.jansi.Ansi.ansi; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * User: Andreas Wegmann @@ -17,12 +19,12 @@ */ public class SimpleExample { - public static void main(String[] args) throws InterruptedException { - AnsiConsole.systemInstall(); - System.out.println(ansi().eraseScreen().render("Simple list example:")); + public static void main(String[] args) { + List header = new ArrayList<>(); + header.add(new AttributedStringBuilder().append("Simple list example:").toAttributedString()); - try { - ConsolePrompt prompt = new ConsolePrompt(); + try (Terminal terminal = TerminalBuilder.builder().build()) { + ConsolePrompt prompt = new ConsolePrompt(terminal); PromptBuilder promptBuilder = prompt.getPromptBuilder(); promptBuilder.createListPrompt() @@ -33,16 +35,11 @@ public static void main(String[] args) throws InterruptedException { .newItem("hawai").text("Hawai").add() .newItem("quattro").text("Quattro Stagioni").add() .addPrompt(); - - HashMap result = prompt.prompt(promptBuilder.build()); + + Map result = prompt.prompt(header, promptBuilder.build()); System.out.println("result = " + result); } catch (IOException e) { e.printStackTrace(); - } finally { - try { - TerminalFactory.get().restore(); - } catch (Exception e) { - e.printStackTrace(); - } } - }} + } +} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java deleted file mode 100644 index f49b34549..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractListablePrompt.java +++ /dev/null @@ -1,224 +0,0 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.PageSizeType; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import jline.Terminal; -import jline.TerminalFactory; - -import java.io.IOException; -import java.util.ArrayList; - -import static org.fusesource.jansi.Ansi.ansi; - -/** - * Abstract base class for all listable prompts (checkbox, list and expandable choice). - * This class contains some helper methods for the list prompts. - *

- * User: Andreas Wegmann - * Date: 19.01.16 - */ -public abstract class AbstractListablePrompt extends AbstractPrompt { - - // holds the index of the selected item (of course) - protected int selectedItemIndex; - - // the item list of the prompt - protected ArrayList itemList; - protected Terminal terminal; - /** - * first item in view - */ - protected int topDisplayedItem; - protected int nearBottomMargin = 3; - protected int viewPortHeight; - protected Rollover rollOverMode; - - /** - * Empty default constructor. - * - * @throws IOException may be thrown by super class - */ - public AbstractListablePrompt() throws IOException { - super(); - terminal = TerminalFactory.get(); - } - - /** - * total height of screen - * @return number of lines on terminal. - */ - protected int screenHeight() { - return terminal.getHeight(); - } - - /** - * calculate renderHeight by relative or absolute type, screen size and item count. - */ - protected void initRendering() { - topDisplayedItem = 0; - if (getPageSizeType() == PageSizeType.ABSOLUTE) - // requested absolute page size plus header plus baseline, but not bigger than screen size - renderHeight = Math.min(screenHeight(), getPageSize() + 2); - else { - // relative page size for complete list plus header plus baseline - renderHeight = (screenHeight()) * getPageSize() / 100; - } - - // if less items than renderHeight, we reduce the height - renderHeight = Math.min(renderHeight, getItemSize() + 2); - - // renderHeight must be at least 3, for a single list item. may be smaller with relative or absolute - // settings, so we correct this to at least 3. - renderHeight = Math.max(3, renderHeight); - - // viewPortHeight is the height of the list items itself, without header and baseline - viewPortHeight = renderHeight - 2; - - // if list size is bigger than viewPort, then we disable the rollover feature. - if (viewPortHeight == getItemSize()) - rollOverMode = Rollover.ALLOWED; - else - rollOverMode = Rollover.HALT_AT_LIST_END; - } - - abstract protected int getPageSize(); - - abstract protected PageSizeType getPageSizeType(); - - protected void gotoRenderTop() { - System.out.println(ansi().cursorUp(renderHeight)); - //System.out.println(ansi().cursor(0, screenHeight() - renderHeight)); - } - - enum Rollover {ALLOWED, HALT_AT_LIST_END} - - /** - * Find the next selectable Item (user pressed 'down'). - * - * @param rollover enables or disables rollover feature when searching for next item - * @return index of the next selectable item. - */ - protected int getNextSelectableItemIndex(Rollover rollover) { - if (rollover == Rollover.ALLOWED) - return getNextSelectableItemIndexWithRollover(); - else - return getNextSelectableItemIndexWithoutRollover(); - } - - /** - * Find the next selectable Item (user pressed 'down'). - * - * @return index of the next selectable item. - */ - private int getNextSelectableItemIndexWithRollover() { - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (selectedItemIndex + 1 + i) % itemList.size(); - ConsoleUIItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - /** - * Find the next selectable Item (user pressed 'down'), but does not start at the beginning - * if end of list is reached. - * - * @return index of the next selectable item. - */ - private int getNextSelectableItemIndexWithoutRollover() { - for (int newIndex = selectedItemIndex + 1; newIndex < itemList.size(); newIndex++) { - ConsoleUIItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - /** - * Find the previous selectable item (user pressed 'up'). - * - * @param rollover enables or disables rollover feature when searching for previous item - * @return index of the previous selectable item. - */ - protected int getPreviousSelectableItemIndex(Rollover rollover) { - if (rollover == Rollover.ALLOWED) - return getPreviousSelectableItemIndexWithRollover(); - else - return getPreviousSelectableItemIndexWithoutRollover(); - } - - /** - * Find the previous selectable item (user pressed 'up'). - * - * @return index of the previous selectable item. - */ - private int getPreviousSelectableItemIndexWithRollover() { - for (int i = 0; i < itemList.size(); i++) { - int newIndex = (selectedItemIndex - 1 - i + itemList.size()) % itemList.size(); - ConsoleUIItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - } - - /** - * Find the previous selectable item (user pressed 'up'), but does not start at end of list if - * beginning of list is reached. - * - * @return index of the previous selectable item. - */ - private int getPreviousSelectableItemIndexWithoutRollover() { - for (int newIndex = selectedItemIndex - 1; newIndex >= 0; newIndex--) { - ConsoleUIItemIF item = itemList.get(newIndex); - if (item.isSelectable()) - return newIndex; - } - return selectedItemIndex; - - } - - /** - * Find the first selectable item of the item list. - * - * @return index of the first selectable item. - * @throws IllegalStateException if no item is selectable. - */ - protected int getFirstSelectableItemIndex() { - int index = 0; - for (ConsoleUIItemIF item : itemList) { - if (item.isSelectable()) - return index; - index++; - } - throw new IllegalStateException("no selectable item in list"); - } - - protected void recalculateViewWindow(boolean upward, boolean downward) { - if (viewPortHeight < getItemSize()) { - if (downward && itemsBelowEnd() && selectedItemNearBottom()) - topDisplayedItem++; - if (upward && itemsAboveTop() && selectedItemNearTop()) - topDisplayedItem--; - } - } - - private boolean selectedItemNearTop() { - return topDisplayedItem + nearBottomMargin - 1 > selectedItemIndex; - } - - private boolean itemsAboveTop() { - return topDisplayedItem > 0; - } - - private boolean selectedItemNearBottom() { - return selectedItemIndex + nearBottomMargin > topDisplayedItem + viewPortHeight; - } - - private boolean itemsBelowEnd() { - return topDisplayedItem + viewPortHeight < getItemSize(); - } - - abstract int getItemSize(); -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 8a4e20146..8e1f94bc9 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -1,67 +1,543 @@ package de.codeshelf.consoleui.prompt; -import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; -import de.codeshelf.consoleui.prompt.reader.ReaderIF; -import org.fusesource.jansi.Ansi; +import de.codeshelf.consoleui.elements.Checkbox; +import de.codeshelf.consoleui.elements.ConfirmChoice; +import de.codeshelf.consoleui.elements.ExpandableChoice; +import de.codeshelf.consoleui.elements.InputValue; +import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import de.codeshelf.consoleui.elements.items.ChoiceItemIF; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import de.codeshelf.consoleui.elements.items.ListItemIF; +import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; +import de.codeshelf.consoleui.elements.items.impl.Separator; +import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; +import org.jline.keymap.BindingReader; +import org.jline.keymap.KeyMap; +import org.jline.terminal.Size; +import org.jline.terminal.Terminal; +import org.jline.utils.*; -import java.io.IOException; -import java.util.ResourceBundle; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import static org.fusesource.jansi.Ansi.ansi; +import static org.jline.keymap.KeyMap.*; /** - * Abstract base class for all prompt implementations. - * User: Andreas Wegmann - * Date: 06.01.16 + * Classes for all prompt implementations. + * + * @author Matti Rinta-Nikkola */ -public abstract class AbstractPrompt { - protected int renderHeight; - protected ResourceBundle resourceBundle; - - // the reader where we get the user input from - ReaderIF reader; - - /** - * Generic method to render the message prompt and the users input after the prompt. This method is - * used by all prompt implementations to display the question and result after the user has made - * the input. - * - * @param message message to render as colored prompt. - * @param resultValue result value generated from the prompt implementation - */ - protected void renderMessagePromptAndResult(String message, String resultValue) { - System.out.println(ansi().cursorUp(renderHeight - 1).a(renderMessagePrompt(message)).fg(Ansi.Color.CYAN).a(" " + resultValue).eraseScreen(Ansi.Erase.FORWARD).reset()); - } - - /** - * Generic method to render a message prompt. The message (displayed white) is prefixed by a - * green question mark. - * - * @param message message to render as a colored prompt. - * @return String with ANSI-Color printable prompt. - */ - protected String renderMessagePrompt(String message) { - return (ansi().fg(Ansi.Color.GREEN).a("? ").fgBright(Ansi.Color.WHITE).a(message)).fg(Ansi.Color.DEFAULT).toString(); - } - - /** - * Default constructor. Initializes the resource bundle for localized messages. - * - * @throws IOException may be thrown from console reader - */ - public AbstractPrompt() throws IOException { - resourceBundle = ResourceBundle.getBundle("consoleui_messages"); - this.reader = new ConsoleReaderImpl(); - } - - /** - * Setter for the reader implementation. Usually the prompt implementation uses the default - * {@link ConsoleReaderImpl} initialized in the constructor. - * This methods is mainly inteded for JUnit tests to inject a new reader for simulated uses input. - * - * @param reader reader implementation to use. - */ - public void setReader(ReaderIF reader) { - this.reader = reader; +public abstract class AbstractPrompt { + protected final Terminal terminal; + protected final BindingReader bindingReader; + private final List header; + private final AttributedString message; + protected final List items; + protected final int firstItemRow; + private final Size size = new Size(); + private final ConsolePrompt.UiConfig config; + private Display display; + + public AbstractPrompt(Terminal terminal, List header, AttributedString message, ConsolePrompt.UiConfig cfg) { + this(terminal, header, message, new ArrayList<>(), cfg); + } + + public AbstractPrompt(Terminal terminal, List header, AttributedString message, List items + , ConsolePrompt.UiConfig cfg) { + this.terminal = terminal; + this.bindingReader = new BindingReader(terminal.reader()); + this.header = header; + this.message = message; + this.items = items; + this.firstItemRow = header.size() + 1; + this.config = cfg; + } + + protected void resetDisplay() { + display = new Display(terminal, true); + size.copy(terminal.getSize()); + display.clear(); + display.reset(); + } + + protected void refreshDisplay(int row) { + refreshDisplay(row, 0, null); + } + + protected void refreshDisplay(int row, Set selected) { + display.resize(size.getRows(), size.getColumns()); + display.reset(); + display.update(displayLines(row, selected), size.cursorPos(firstItemRow + items.size(), 0)); + } + + protected void refreshDisplay(int row, int column, String buffer, boolean newline) { + display.resize(size.getRows(), size.getColumns()); + AttributedStringBuilder asb = new AttributedStringBuilder(); + int crow = column == 0 ? firstItemRow + items.size() : row; + if (buffer != null) { + if (newline && !buffer.isEmpty()) { + asb.style(config.style(".pr")).append(">> "); + } + asb.style(AttributedStyle.DEFAULT).append(buffer); + } + display.update(displayLines(row, asb.toAttributedString(), newline), size.cursorPos(crow, column)); + } + + protected void refreshDisplay(int row, int column, String buffer) { + refreshDisplay(row, column, buffer, false); + } + + private List displayLines(int cursorRow, Set selected) { + List out = new ArrayList<>(header); + int i = firstItemRow; + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + out.add(asb.toAttributedString()); + for (ConsoleUIItemIF s : items) { + asb = new AttributedStringBuilder(); + if (s.isSelectable()) { + asb = i == cursorRow ? asb.append(config.indicator()).style(AttributedStyle.DEFAULT).append(" ") + : fillIndicatorSpace(asb).append(" "); + asb = selected.contains(s.getName()) ? asb.append(config.checkedBox()) + : asb.append(config.uncheckedBox()); + } else if (s instanceof CheckboxItem) { + fillIndicatorSpace(asb); + asb.append(" "); + if (s.isDisabled()) { + asb.append(config.unavailable()); + } else { + fillCheckboxSpace(asb); + } + } + asb.append(s.getText()).toAttributedString(); + if (s.isDisabled()) { + asb.append(" (").append(s.getDisabledText()).append(")"); + } + out.add(asb.toAttributedString()); + i++; + } + return out; } + + private AttributedStringBuilder fillIndicatorSpace(AttributedStringBuilder asb) { + for (int i = 0; i < config.indicator().length(); i++) { + asb.append(" "); + } + return asb; + } + + private void fillCheckboxSpace(AttributedStringBuilder asb) { + for (int i = 0; i < config.checkedBox().length(); i++) { + asb.append(" "); + } + } + + private List displayLines(int cursorRow, AttributedString buffer, boolean newline) { + List out = new ArrayList<>(header); + int i = firstItemRow; + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + if (buffer != null && !newline) { + asb.append(buffer); + } + out.add(asb.toAttributedString()); + if (buffer != null && newline) { + asb = new AttributedStringBuilder(); + asb.append(buffer); + out.add(asb.toAttributedString()); + } + for (ConsoleUIItemIF s : items) { + asb = new AttributedStringBuilder(); + String key = s instanceof ChoiceItem ? ((ChoiceItem)s).getKey() + " - " : ""; + if (i == cursorRow) { + out.add(asb.append(config.indicator()).style(config.style(".se")).append(" ").append(key) + .append(s.getText()).toAttributedString()); + } else if (!(s instanceof Separator)) { + fillIndicatorSpace(asb); + out.add(asb.append(" ").append(key).append(s.getText()).toAttributedString()); + } else { + out.add(asb.append(s.getText()).toAttributedString()); + } + i++; + } + return out; + } + + protected static class ExpandableChoicePrompt extends AbstractPrompt { + private enum Operation {INSERT, EXIT} + private final int startColumn; + private final List items; + private final UiConfig config; + + private ExpandableChoicePrompt(Terminal terminal, List header, AttributedString message + , ExpandableChoice expandableChoice, UiConfig cfg) { + super(terminal, header, message, cfg); + startColumn = message.columnLength(); + items = expandableChoice.getChoiceItems(); + config = cfg; + } + + public static ExpandableChoicePrompt getPrompt(Terminal terminal, List header, AttributedString message + , ExpandableChoice expandableChoice, UiConfig cfg) { + return new ExpandableChoicePrompt(terminal, header, message, expandableChoice, cfg); + } + + private void bindKeys(KeyMap map) { + for (char i = 32; i < KEYMAP_LENGTH; i++) { + map.bind(Operation.INSERT, Character.toString(i)); + } + map.bind(Operation.EXIT,"\r"); + } + + public ExpandableChoiceResult execute() { + resetDisplay(); + int row = firstItemRow - 1; + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + StringBuilder buffer = new StringBuilder(); + String selectedId = null; + boolean expandChoiceList = false; + for (ChoiceItemIF cu : items) { + if (cu.isSelectable() && cu.isDefaultChoice()) { + selectedId = cu.getName(); + break; + } + } + while (true) { + refreshDisplay(row, startColumn, buffer.toString(), true); + Operation op = bindingReader.readBinding(keyMap); + buffer = new StringBuilder(); + switch (op) { + case INSERT: + String ch = bindingReader.getLastBinding(); + if (ch.equals("h")) { + expandChoiceList = true; + buffer.append(config.resourceBundle().getString("help.list.all.options")); + } else { + selectedId = null; + expandChoiceList = false; + boolean found = false; + for (ChoiceItemIF cu : items) { + if (cu.isSelectable() && cu.getKey().toString().equals(ch)) { + selectedId = cu.getName(); + buffer.append(selectedId); + found = true; + break; + } + } + if (!found) { + buffer.append(config.resourceBundle().getString("please.enter.a.valid.command")); + } + } + break; + case EXIT: + if (selectedId == null || expandChoiceList) { + if (expandChoiceList) { + throw new ExpandableChoiceException(); + } + break; + } + return new ExpandableChoiceResult(selectedId); + } + } + } + + } + + @SuppressWarnings("serial") + protected static class ExpandableChoiceException extends RuntimeException { + } + + protected static class ConfirmPrompt extends AbstractPrompt { + private enum Operation {NO, YES, EXIT} + private final int startColumn; + private final ConfirmChoice.ConfirmationValue defaultValue; + private final UiConfig config; + + private ConfirmPrompt(Terminal terminal, List header, AttributedString message + , ConfirmChoice confirmChoice, UiConfig cfg) { + super(terminal, header, message, cfg); + startColumn = message.columnLength(); + defaultValue = confirmChoice.getDefaultConfirmation(); + config = cfg; + } + + public static ConfirmPrompt getPrompt(Terminal terminal, List header, AttributedString message + , ConfirmChoice confirmChoice, UiConfig cfg) { + return new ConfirmPrompt(terminal, header, message, confirmChoice, cfg); + } + + private void bindKeys(KeyMap map) { + String yes = config.resourceBundle().getString("confirmation_yes_key"); + String no = config.resourceBundle().getString("confirmation_no_key"); + map.bind(Operation.YES, yes, yes.toUpperCase()); + map.bind(Operation.NO, no, no.toUpperCase()); + map.bind(Operation.EXIT,"\r"); + } + + public ConfirmResult execute() { + resetDisplay(); + int row = firstItemRow - 1; + int column = startColumn; + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + StringBuilder buffer = new StringBuilder(); + ConfirmChoice.ConfirmationValue confirm = defaultValue; + while (true) { + refreshDisplay(row, column, buffer.toString()); + Operation op = bindingReader.readBinding(keyMap); + buffer = new StringBuilder(); + switch (op) { + case YES: + buffer.append(config.resourceBundle().getString("confirmation_yes_answer")); + confirm = ConfirmChoice.ConfirmationValue.YES; + column = startColumn + 3; + break; + case NO: + buffer.append(config.resourceBundle().getString("confirmation_no_answer")); + confirm = ConfirmChoice.ConfirmationValue.NO; + column = startColumn + 2; + break; + case EXIT: + if (confirm == null) { + break; + } + return new ConfirmResult(confirm); + } + } + } + + } + + protected static class InputValuePrompt extends AbstractPrompt { + private enum Operation {INSERT, BACKSPACE, DELETE, RIGHT, LEFT, BEGINNING_OF_LINE, END_OF_LINE, EXIT} + private final int startColumn; + private final String defaultValue; + private final Character mask; + + private InputValuePrompt(Terminal terminal, List header, AttributedString message + , InputValue inputValue, UiConfig cfg) { + super(terminal, header, message, cfg); + defaultValue = inputValue.getDefaultValue(); + startColumn = message.columnLength(); + mask = inputValue.getMask(); + } + + public static InputValuePrompt getPrompt(Terminal terminal, List header, AttributedString message + , InputValue inputValue, UiConfig cfg) { + return new InputValuePrompt(terminal, header, message, inputValue, cfg); + } + + private void bindKeys(KeyMap map) { + map.setUnicode(Operation.INSERT); + for (char i = 32; i < KEYMAP_LENGTH; i++) { + map.bind(Operation.INSERT, Character.toString(i)); + } + map.bind(Operation.BACKSPACE, del()); + map.bind(Operation.DELETE, ctrl('D'), key(terminal, InfoCmp.Capability.key_dc)); + map.bind(Operation.BACKSPACE, ctrl('H')); + map.bind(Operation.EXIT,"\r"); + map.bind(Operation.RIGHT, key(terminal, InfoCmp.Capability.key_right)); + map.bind(Operation.LEFT, key(terminal, InfoCmp.Capability.key_left)); + map.bind(Operation.BEGINNING_OF_LINE, ctrl('A'), key(terminal, InfoCmp.Capability.key_home)); + map.bind(Operation.END_OF_LINE, ctrl('E'), key(terminal, InfoCmp.Capability.key_end)); + map.bind(Operation.RIGHT, ctrl('F')); + map.bind(Operation.LEFT, ctrl('B')); + } + + public InputResult execute() { + resetDisplay(); + int row = firstItemRow - 1; + int column = startColumn; + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + StringBuilder buffer = new StringBuilder(); + while (true) { + refreshDisplay(row, column, buffer.toString()); + Operation op = bindingReader.readBinding(keyMap); + switch (op) { + case LEFT: + if (column > startColumn) { + column--; + } + break; + case RIGHT: + if (column < startColumn + buffer.length()) { + column++; + } + break; + case INSERT: + buffer.insert(column - startColumn, mask == null ? bindingReader.getLastBinding() : mask); + column++; + break; + case BACKSPACE: + if (column > startColumn) { + buffer.deleteCharAt(column - startColumn - 1); + } + column--; + break; + case DELETE: + if (column < startColumn + buffer.length() && column >= startColumn) { + buffer.deleteCharAt(column - startColumn); + } + break; + case BEGINNING_OF_LINE: + column = startColumn; + break; + case END_OF_LINE: + column = startColumn + buffer.length(); + break; + case EXIT: + if (buffer.toString().isEmpty()) { + buffer.append(defaultValue); + } + return new InputResult(buffer.toString()); + } + } + } + + } + + private static int nextRow(int row, int firstItemRow, List items) { + int itemsSize = items.size(); + int next; + for (next = row + 1; next - firstItemRow < itemsSize && !items.get(next - firstItemRow).isSelectable(); next++) { + } + if (next - firstItemRow >= itemsSize) { + for (next = firstItemRow; next - firstItemRow < itemsSize && !items.get(next - firstItemRow).isSelectable(); next++) { + } + } + return next; + } + private static int prevRow(int row, int firstItemRow, List items) { + int itemsSize = items.size(); + int prev; + for (prev = row - 1; prev - firstItemRow >= 0 && !items.get(prev - firstItemRow).isSelectable(); prev--) { + } + if (prev - firstItemRow < 0) { + for (prev = firstItemRow + itemsSize - 1; prev - firstItemRow >= 0 && !items.get(prev - firstItemRow).isSelectable(); prev--) { + } + } + return prev; + } + + protected static class ListChoicePrompt extends AbstractPrompt { + private enum Operation {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, INSERT, EXIT} + private final List items; + + private ListChoicePrompt(Terminal terminal, List header, AttributedString message + , List listItems, UiConfig cfg) { + super(terminal, header, message, listItems, cfg); + items = listItems; + } + + public static ListChoicePrompt getPrompt(Terminal terminal, List header + , AttributedString message, List listItems, UiConfig cfg) { + return new ListChoicePrompt<>(terminal, header, message, listItems, cfg); + } + + private void bindKeys(KeyMap map) { + for (char i = 32; i < KEYMAP_LENGTH; i++) { + map.bind(Operation.INSERT, Character.toString(i)); + } + map.bind(Operation.FORWARD_ONE_LINE, "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); + map.bind(Operation.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); + map.bind(Operation.EXIT,"\r"); + } + + public ListResult execute() { + resetDisplay(); + int selectRow = nextRow(firstItemRow - 1, firstItemRow, items); + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + while (true) { + refreshDisplay(selectRow); + Operation op = bindingReader.readBinding(keyMap); + switch (op) { + case FORWARD_ONE_LINE: + selectRow = nextRow(selectRow, firstItemRow, items); + break; + case BACKWARD_ONE_LINE: + selectRow = prevRow(selectRow, firstItemRow, items); + break; + case INSERT: + String ch = bindingReader.getLastBinding(); + int id = 0; + for (ListItemIF cu : items) { + if (cu instanceof ChoiceItem) { + ChoiceItem ci = (ChoiceItem) cu; + if (ci.isSelectable() && ci.getKey().toString().equals(ch)) { + selectRow = firstItemRow + id; + break; + } + } + id++; + } + break; + case EXIT: + T listItem = items.get(selectRow - firstItemRow); + return new ListResult(listItem.getName()); + } + } + } + } + + protected static class CheckboxPrompt extends AbstractPrompt { + private enum Operation {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, TOGGLE, EXIT} + + private final List items; + + private CheckboxPrompt(Terminal terminal, List header, AttributedString message + , Checkbox checkbox, UiConfig cfg) { + super(terminal, header, message, checkbox.getCheckboxItemList(), cfg); + items = checkbox.getCheckboxItemList(); + } + + public static CheckboxPrompt getPrompt(Terminal terminal, List header, AttributedString message + , Checkbox checkbox, UiConfig cfg) { + return new CheckboxPrompt(terminal, header, message, checkbox, cfg); + } + + private void bindKeys(KeyMap map) { + map.bind(Operation.FORWARD_ONE_LINE, "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); + map.bind(Operation.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); + map.bind(Operation.TOGGLE," "); + map.bind(Operation.EXIT,"\r"); + } + + public CheckboxResult execute() { + resetDisplay(); + int selectRow = nextRow(firstItemRow - 1, firstItemRow, items); + Set selected = items.stream().filter(CheckboxItemIF::isChecked) + .flatMap(it -> Stream.of(it.getName())).collect(Collectors.toSet()); + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + while (true) { + refreshDisplay(selectRow, selected); + Operation op = bindingReader.readBinding(keyMap); + switch (op) { + case FORWARD_ONE_LINE: + selectRow = nextRow(selectRow, firstItemRow, items); + break; + case BACKWARD_ONE_LINE: + selectRow = prevRow(selectRow, firstItemRow, items); + break; + case TOGGLE: + if (selected.contains(items.get(selectRow - firstItemRow).getName())) { + selected.remove(items.get(selectRow - firstItemRow).getName()); + } else { + selected.add(items.get(selectRow - firstItemRow).getName()); + } + break; + case EXIT: + return new CheckboxResult(selected); + } + } + } + } + } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java deleted file mode 100644 index fde2d59f3..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxPrompt.java +++ /dev/null @@ -1,153 +0,0 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.Checkbox; -import de.codeshelf.consoleui.elements.PageSizeType; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; -import de.codeshelf.consoleui.prompt.reader.ReaderIF; -import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; - -import java.io.IOException; -import java.util.LinkedHashSet; - -/** - * CheckboxPrompt implements the checkbox choice handling. - */ -public class CheckboxPrompt extends AbstractListablePrompt implements PromptIF { - - // checkbox object to prompt the user for. - private Checkbox checkbox; - - /** - * helper class with render functionality. - */ - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - - /** - * Empty default constructor. - * - * @throws IOException may be thrown by super class - */ - public CheckboxPrompt() throws IOException { - super(); - } - - @Override - protected int getPageSize() { - return checkbox.getPageSize(); - } - - @Override - protected PageSizeType getPageSizeType() { - return checkbox.getPageSizeType(); - } - - @Override - int getItemSize() { - return checkbox.getCheckboxItemList().size(); - } - - /** - * Prompt the user for selecting zero to many choices from a checkbox. - * - * @param checkbox checkbox with items to choose from. - * @return {@link CheckboxResult} which holds the users choices. - */ - public CheckboxResult prompt(Checkbox checkbox) { - this.checkbox = checkbox; - itemList = this.checkbox.getCheckboxItemList(); - - this.reader.addAllowedPrintableKey('j'); - this.reader.addAllowedPrintableKey('k'); - this.reader.addAllowedPrintableKey(' '); - this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); - this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); - this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); - - this.selectedItemIndex = getFirstSelectableItemIndex(); - - initRendering(); - render(); - ReaderIF.ReaderInput readerInput = this.reader.read(); - while (readerInput.getSpecialKey() != ReaderIF.SpecialKey.ENTER) { - boolean downward = false; - boolean upward = false; - - if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { - if (readerInput.getPrintableKey().equals(' ')) { - toggleSelection(); - } else if (readerInput.getPrintableKey().equals('j')) { - this.selectedItemIndex = getNextSelectableItemIndex(rollOverMode); - downward = true; - } else if (readerInput.getPrintableKey().equals('k')) { - this.selectedItemIndex = getPreviousSelectableItemIndex(rollOverMode); - upward = true; - } - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - this.selectedItemIndex = getNextSelectableItemIndex(rollOverMode); - downward = true; - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - this.selectedItemIndex = getPreviousSelectableItemIndex(rollOverMode); - upward = true; - } - if (upward || downward) - recalculateViewWindow(upward, downward); - gotoRenderTop(); - render(); - readerInput = this.reader.read(); - } - - LinkedHashSet selections = new LinkedHashSet<>(); - - for (ConsoleUIItemIF item : itemList) { - if ((item instanceof CheckboxItem)) { - CheckboxItem checkboxItem = (CheckboxItem) item; - if (checkboxItem.isChecked()) { - selections.add(checkboxItem.getName()); - } - } - } - renderMessagePromptAndResult(checkbox.getMessage(), selections.toString()); - return new CheckboxResult(selections); - } - - /** - * render the checkbox on the terminal. - */ - private void render() { - int itemNumber; - int renderedLines = 0; - - System.out.println(renderMessagePrompt(checkbox.getMessage())); - for (itemNumber = topDisplayedItem; renderedLines < viewPortHeight; itemNumber++, renderedLines++) { - String renderedItem = itemRenderer.render(itemList.get(itemNumber), (selectedItemIndex == itemNumber)); - System.out.println(renderedItem); - } - } - - /* - private void render() { - int itemNumber = 0; - - if (this.renderHeight == 0) { - this.renderHeight = (2 + itemList.size()); - } else { - System.out.println(Ansi.ansi().cursorUp(this.renderHeight)); - } - System.out.println(renderMessagePrompt(this.checkbox.getMessage())); - for (ConsoleUIItemIF checkboxItem : itemList) { - String renderedItem = this.itemRenderer.render(checkboxItem, this.selectedItemIndex == itemNumber); - System.out.println(renderedItem); - itemNumber++; - } - } - */ - - /** - * Toggles the selection of the currently selected checkbox item. - */ - private void toggleSelection() { - CheckboxItem checkboxItem = (CheckboxItem) itemList.get(this.selectedItemIndex); - checkboxItem.setChecked(!checkboxItem.isChecked()); - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java index d1823e90a..6903627f6 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java @@ -1,6 +1,6 @@ package de.codeshelf.consoleui.prompt; -import java.util.HashSet; +import java.util.Set; /** * Result of a checkbox choice. CheckboxResult contains a {@link java.util.Set} with the @@ -9,14 +9,14 @@ * User: Andreas Wegmann * Date: 03.02.16 */ -public class CheckboxResult implements PromtResultItemIF { - HashSet selectedIds; +public class CheckboxResult implements PromptResultItemIF { + Set selectedIds; /** * Default Constructor. * @param selectedIds Selected IDs. */ - public CheckboxResult(HashSet selectedIds) { + public CheckboxResult(Set selectedIds) { this.selectedIds = selectedIds; } @@ -25,10 +25,14 @@ public CheckboxResult(HashSet selectedIds) { * * @return set with IDs */ - public HashSet getSelectedIds() { + public Set getSelectedIds() { return selectedIds; } + public String getResult() { + return selectedIds.toString(); + } + @Override public String toString() { return "CheckboxResult{" + diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java deleted file mode 100644 index 723981706..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmPrompt.java +++ /dev/null @@ -1,125 +0,0 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.ConfirmChoice; -import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; -import de.codeshelf.consoleui.prompt.reader.ReaderIF; -import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; - -import java.io.IOException; - -import static org.fusesource.jansi.Ansi.ansi; - -/** - * Implementation of the confirm choice. The user will be asked for a yes/no questions. - * both of the answers can be the default choice. - *

- * User: Andreas Wegmann - * Date: 06.01.16 - */ -public class ConfirmPrompt extends AbstractPrompt implements PromptIF { - - private ReaderIF reader; - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - private ConfirmChoice confirmChoice; - char yes_key; - char no_key; - String yes_answer; - String no_answer; - ConfirmChoice.ConfirmationValue givenAnswer; - - /** - * Default Constructor. Initializes the localized strings and keys from resourceBundle. - * - * @throws IOException can be thrown by base class construction. - */ - public ConfirmPrompt() throws IOException { - super(); - yes_key = resourceBundle.getString("confirmation_yes_key").trim().charAt(0); - no_key = resourceBundle.getString("confirmation_no_key").trim().charAt(0); - yes_answer = resourceBundle.getString("confirmation_yes_answer"); - no_answer = resourceBundle.getString("confirmation_no_answer"); - } - - /** - * Prompt the user for a question which can be answered with yes or no. - * - * @param confirmChoice the question for the user. - * @return {@link ConfirmResult} object with answer. - * @throws IOException can be thrown by the console reader. - */ - public ConfirmResult prompt(ConfirmChoice confirmChoice) throws IOException { - givenAnswer = null; - this.confirmChoice = confirmChoice; - - if (reader == null) { - reader = new ConsoleReaderImpl(); - } - - if (renderHeight == 0) { - renderHeight = 2; - } else { - System.out.println(ansi().cursorUp(renderHeight)); - } - - this.reader.addAllowedPrintableKey(no_key); - this.reader.addAllowedPrintableKey(yes_key); - this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); - this.reader.addAllowedSpecialKey(ReaderIF.SpecialKey.BACKSPACE); - - render(); - ReaderIF.ReaderInput readerInput = this.reader.read(); - while (true) { - if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { - if (givenAnswer != null) { - break; - } else if (confirmChoice.getDefaultConfirmation() != null) { - givenAnswer = confirmChoice.getDefaultConfirmation(); - break; - } - } - if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { - if (readerInput.getPrintableKey().equals(yes_key)) { - givenAnswer = ConfirmChoice.ConfirmationValue.YES; - } else if (readerInput.getPrintableKey().equals(no_key)) { - givenAnswer = ConfirmChoice.ConfirmationValue.NO; - } - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.BACKSPACE) { - givenAnswer = null; - } - render(); - readerInput = this.reader.read(); - } - String resultValue = calcResultValue(); - - System.out.println(); - renderMessagePromptAndResult(confirmChoice.getMessage(), resultValue); - - return new ConfirmResult(givenAnswer); - } - - /** - * Renders the confirmation message on the screen. - */ - private void render() { - System.out.println(""); - System.out.println(ansi().eraseLine().cursorUp(2)); - System.out.print(renderMessagePrompt(this.confirmChoice.getMessage()) + - itemRenderer.renderConfirmChoiceOptions(this.confirmChoice) + " " + ansi().reset().a(calcResultValue() + " ").eraseLine()); - System.out.flush(); - renderHeight = 2; - } - - /** - * Returns the localized string representation of 'yes' or 'no' depending on the given answer. - * - * @return localized answer string. - */ - private String calcResultValue() { - if (givenAnswer == ConfirmChoice.ConfirmationValue.YES) { - return yes_answer; - } else if (givenAnswer == ConfirmChoice.ConfirmationValue.NO) { - return no_answer; - } - return ""; - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java index e8691005a..5c0da59e2 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java @@ -9,7 +9,7 @@ * User: Andreas Wegmann * Date: 03.02.16 */ -public class ConfirmResult implements PromtResultItemIF { +public class ConfirmResult implements PromptResultItemIF { ConfirmChoice.ConfirmationValue confirmed; /** @@ -29,6 +29,10 @@ public ConfirmChoice.ConfirmationValue getConfirmed() { return confirmed; } + public String getResult() { + return confirmed.toString(); + } + @Override public String toString() { return "ConfirmResult{" + diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 7aa45b850..127e00184 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -1,178 +1,234 @@ package de.codeshelf.consoleui.prompt; import de.codeshelf.consoleui.elements.*; +import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; +import de.codeshelf.consoleui.prompt.AbstractPrompt.*; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import org.jline.builtins.Styles; +import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.terminal.Attributes; +import org.jline.terminal.Terminal; +import org.jline.utils.*; import java.io.IOException; -import java.util.HashMap; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * ConsolePrompt encapsulates the prompting of a list of input questions for the user. - *

- * Created by Andreas Wegmann on 20.01.16. + * + * @author Matti Rinta-Nikkola */ public class ConsolePrompt { - // input prompt implementation - private InputPrompt inputPrompt; + private final Terminal terminal; + private final UiConfig config; - // expandable choice prompt implementation - private ExpandableChoicePrompt expandableChoicePrompt; - - // checkbox prompt implementation - private CheckboxPrompt checkboxPrompt; - - // list box prompt implementation - private ListPrompt listPrompt; - - // confirmation prompt implementation - private ConfirmPrompt confirmPrompt; - - /* Lazy getter for input prompt */ - private InputPrompt getInputPrompt() throws IOException { - if (inputPrompt == null) { - inputPrompt = new InputPrompt(); - } - return inputPrompt; - } - - /* Lazy getter for expandable choice prompt */ - private ExpandableChoicePrompt getExpandableChoicePrompt() throws IOException { - if (expandableChoicePrompt == null) { - expandableChoicePrompt = new ExpandableChoicePrompt(); - } - return expandableChoicePrompt; - } - - /* Lazy getter for checkbox prompt */ - private CheckboxPrompt getCheckboxPrompt() throws IOException { - if (checkboxPrompt == null) { - checkboxPrompt = new CheckboxPrompt(); - } - return checkboxPrompt; - } - - /* Lazy getter for list prompt */ - private ListPrompt getListPrompt() throws IOException { - if (listPrompt == null) { - listPrompt = new ListPrompt(); - } - return listPrompt; - } - - /* Lazy getter for confirm prompt */ - private ConfirmPrompt getConfirmPrompt() throws IOException { - if (confirmPrompt == null) { - confirmPrompt = new ConfirmPrompt(); - } - return confirmPrompt; + /** + * + * @param terminal the terminal. + */ + public ConsolePrompt(Terminal terminal) { + this(terminal, new UiConfig()); } - /** - * Default constructor for this class. + * + * @param terminal the terminal. + * @param config ConsolePrompt cursor pointer and checkbox configuration */ - public ConsolePrompt() { + public ConsolePrompt(Terminal terminal, UiConfig config) { + this.terminal = terminal; + this.config = config; } /** * Prompt a list of choices (questions). This method takes a list of promptable elements, typically * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and * answers are filled in to the result map. The result map contains the key of each promtable element - * and the user entry as an object implementing {@link PromtResultItemIF}. + * and the user entry as an object implementing {@link PromptResultItemIF}. * - * @param promptableElementList the list of questions / promts to ask the user for. + * @param promptableElementList the list of questions / prompts to ask the user for. * @return a map containing a result for each element of promptableElementList - * @throws IOException may be thrown by console reader + * @throws IOException may be thrown by terminal */ - public HashMap prompt(List promptableElementList) - throws IOException { - HashMap resultMap = new HashMap(); - - for (int i = 0; i < promptableElementList.size(); i++) { - PromptableElementIF promptableElement = promptableElementList.get(i); - if (promptableElement instanceof ListChoice) { - ListResult result = doPrompt((ListChoice) promptableElement); - resultMap.put(promptableElement.getName(), result); - } else if (promptableElement instanceof InputValue) { - InputResult result = doPrompt((InputValue) promptableElement); - resultMap.put(promptableElement.getName(), result); - } else if (promptableElement instanceof ExpandableChoice) { - ExpandableChoiceResult result = doPrompt((ExpandableChoice) promptableElement); - resultMap.put(promptableElement.getName(), result); - } else if (promptableElement instanceof Checkbox) { - CheckboxResult result = doPrompt((Checkbox) promptableElement); - resultMap.put(promptableElement.getName(), result); - } else if (promptableElement instanceof ConfirmChoice) { - ConfirmResult result = doPrompt((ConfirmChoice) promptableElement); - resultMap.put(promptableElement.getName(), result); - } else { - throw new IllegalArgumentException("wrong type of promptable element"); - } - } - return resultMap; + public Map prompt(List promptableElementList) { + return prompt(new ArrayList<>(), promptableElementList); } - /** - * Process a {@link ConfirmChoice}. + * Prompt a list of choices (questions). This method takes a list of promptable elements, typically + * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and + * answers are filled in to the result map. The result map contains the key of each promtable element + * and the user entry as an object implementing {@link PromptResultItemIF}. * - * @param confirmChoice the confirmation to ask the user for. - * @return Object of type {@link ConfirmResult} holding the users answer - * @throws IOException may be thrown by console reader + * @param header info to be displayed before first prompt. + * @param promptableElementList the list of questions / prompts to ask the user for. + * @return a map containing a result for each element of promptableElementList + * @throws IOException may be thrown by terminal */ - private ConfirmResult doPrompt(ConfirmChoice confirmChoice) throws IOException { - return getConfirmPrompt().prompt(confirmChoice); + public Map prompt(List header + , List promptableElementList) { + Attributes attributes = terminal.enterRawMode(); + try { + terminal.puts(InfoCmp.Capability.enter_ca_mode); + terminal.puts(InfoCmp.Capability.keypad_xmit); + terminal.writer().flush(); + + Map resultMap = new HashMap<>(); + + for (PromptableElementIF pe : promptableElementList) { + AttributedStringBuilder message = new AttributedStringBuilder(); + message.style(config.style(".pr")).append("? "); + message.style(config.style(".me")).append(pe.getMessage()).append(" "); + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + asb.style(AttributedStyle.DEFAULT); + PromptResultItemIF result; + if (pe instanceof ListChoice) { + ListChoice lc = (ListChoice) pe; + result = ListChoicePrompt.getPrompt(terminal, header, asb.toAttributedString() + , lc.getListItemList(), config).execute(); + } else if (pe instanceof InputValue) { + InputValue ip = (InputValue) pe; + if (ip.getDefaultValue() != null) { + asb.append("(").append(ip.getDefaultValue()).append(") "); + } + result = InputValuePrompt.getPrompt(terminal, header, asb.toAttributedString(), ip, config).execute(); + } else if (pe instanceof ExpandableChoice) { + ExpandableChoice ec = (ExpandableChoice) pe; + asb.append("("); + for (ConsoleUIItemIF item : ec.getChoiceItems()) { + if (item instanceof ChoiceItem) { + ChoiceItem ci = (ChoiceItem) item; + if (ci.isSelectable()) { + asb.append(ci.isDefaultChoice() ? Character.toUpperCase(ci.getKey()) : ci.getKey()); + } + } + } + asb.append("h) "); + try { + result = ExpandableChoicePrompt.getPrompt(terminal, header + , asb.toAttributedString(), ec, config).execute(); + } catch (ExpandableChoiceException e) { + result = ListChoicePrompt.getPrompt(terminal, header, message.toAttributedString() + , ec.getChoiceItems(), config).execute(); + } + } else if (pe instanceof Checkbox) { + Checkbox cb = (Checkbox) pe; + result = CheckboxPrompt.getPrompt(terminal, header, message.toAttributedString(), cb, config).execute(); + } else if (pe instanceof ConfirmChoice) { + ConfirmChoice cc = (ConfirmChoice) pe; + if (cc.getDefaultConfirmation() == null) { + asb.append(config.resourceBundle().getString("confirmation_without_default")); + } else if (cc.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.YES) { + asb.append(config.resourceBundle().getString("confirmation_yes_default")); + } else { + asb.append(config.resourceBundle().getString("confirmation_no_default")); + } + asb.append(" "); + result = ConfirmPrompt.getPrompt(terminal, header, asb.toAttributedString(), cc, config).execute(); + } else { + throw new IllegalArgumentException("wrong type of promptable element"); + } + String resp = result.getResult(); + if (result instanceof ConfirmResult) { + ConfirmResult cr = (ConfirmResult)result; + if (cr.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) { + resp = config.resourceBundle().getString("confirmation_yes_answer"); + } else { + resp = config.resourceBundle().getString("confirmation_no_answer"); + } + } + message.style(config.style(".an")).append(resp); + header.add(message.toAttributedString()); + resultMap.put(pe.getName(), result); + } + return resultMap; + } finally { + terminal.setAttributes(attributes); + terminal.puts(InfoCmp.Capability.exit_ca_mode); + terminal.puts(InfoCmp.Capability.keypad_local); + terminal.writer().flush(); + for (AttributedString as : header) { + as.println(terminal); + } + terminal.writer().flush(); + } } /** - * Process a {@link ListChoice}. + * Creates a {@link PromptBuilder}. * - * @param listChoice the list to let the user choose an item from. - * @return Object of type {@link ListResult} holding the uses choice. - * @throws IOException may be thrown by console reader + * @return a new prompt builder object. */ - private ListResult doPrompt(ListChoice listChoice) throws IOException { - return getListPrompt().prompt(listChoice); + public PromptBuilder getPromptBuilder() { + return new PromptBuilder(); } /** - * Process a {@link InputValue}. - * - * @param inputValue the input value to ask the user for. - * @return Object of type {@link InputResult} holding the uses input. - * @throws IOException may be thrown by console reader + * ConsoleUI configuration: colors, cursor pointer and selected/unselected/unavailable boxes. + * ConsoleUI colors are configurable using UI_COLORS environment variable */ - private InputResult doPrompt(InputValue inputValue) throws IOException { - return getInputPrompt().prompt(inputValue); - } + public static class UiConfig { + static final String DEFAULT_UI_COLORS = "cu=36:be=32:bd=37:pr=32:me=1:an=36:se=36"; + static final String UI_COLORS = "UI_COLORS"; + private final AttributedString indicator; + private final AttributedString uncheckedBox; + private final AttributedString checkedBox; + private final AttributedString unavailable; + private final StyleResolver resolver; + private final ResourceBundle resourceBundle; + + public UiConfig() { + this(null, null, null, null); + } - /** - * Process a {@link Checkbox}. - * - * @param checkbox the checkbox displayed where the user can check values. - * @return Object of type {@link CheckboxResult} holding the uses choice. - * @throws IOException may be thrown by console reader - */ - private CheckboxResult doPrompt(Checkbox checkbox) throws IOException { - return getCheckboxPrompt().prompt(checkbox); - } + public UiConfig(String indicator, String uncheckedBox, String checkedBox, String unavailable) { + String uc = System.getenv(UI_COLORS); + String uiColors = uc != null && Styles.isAnsiStylePattern(uc) ? uc : DEFAULT_UI_COLORS; + this.resolver = resolver(uiColors); + this.indicator = toAttributedString((indicator != null ? indicator : ">"), ".cu"); + this.uncheckedBox = toAttributedString((uncheckedBox != null ? uncheckedBox : " "), ".be"); + this.checkedBox = toAttributedString((checkedBox != null ? checkedBox : "x "), ".be"); + this.unavailable = toAttributedString((unavailable != null ? unavailable : "- "), ".bd"); + this.resourceBundle = ResourceBundle.getBundle("consoleui_messages"); + } - /** - * Process a {@link ExpandableChoice}. - * - * @param expandableChoice the expandable choice displayed where the user can select a value from. - * @return Object of type {@link ExpandableChoiceResult} holding the uses choice. - * @throws IOException may be thrown by console reader - */ - private ExpandableChoiceResult doPrompt(ExpandableChoice expandableChoice) throws IOException { - return getExpandableChoicePrompt().prompt(expandableChoice); - } + private AttributedString toAttributedString(String string, String styleKey) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.style(style(styleKey)); + asb.append(string); + return asb.toAttributedString(); + } + + public AttributedString indicator() { + return indicator; + } + + public AttributedString uncheckedBox() { + return uncheckedBox; + } + + public AttributedString checkedBox() { + return checkedBox; + } + + public AttributedString unavailable() { + return unavailable; + } + + public AttributedStyle style(String key) { + return resolver.resolve(key); + } + + public ResourceBundle resourceBundle() { + return resourceBundle; + } + + private static StyleResolver resolver(String style) { + Map colors = Arrays.stream(style.split(":")) + .collect(Collectors.toMap(s -> s.substring(0, s.indexOf('=')), + s -> s.substring(s.indexOf('=') + 1))); + return new StyleResolver(colors::get); + } - /** - * Creates a {@link PromptBuilder}. - * - * @return a new prompt builder object. - */ - public PromptBuilder getPromptBuilder() { - return new PromptBuilder(); } } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java deleted file mode 100644 index bac88d439..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoicePrompt.java +++ /dev/null @@ -1,195 +0,0 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.ExpandableChoice; -import de.codeshelf.consoleui.elements.PageSizeType; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; -import de.codeshelf.consoleui.prompt.reader.ReaderIF; -import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; -import org.fusesource.jansi.Ansi; - -import java.io.IOException; -import java.util.ArrayList; - -import static org.fusesource.jansi.Ansi.ansi; - -/** - * Implementation of the expandable choice. The user is asked a question to be answered with - * a single key. Each key represents a choice from a given set of items. - *

- * Items with the key 'h' are not allowed. This key is reserved for the help message. With the - * help message the prompt can be expanded to a list with the answers. - *

- * User: Andreas Wegmann

- * Date: 07.01.16 - */ -public class ExpandableChoicePrompt extends AbstractListablePrompt implements PromptIF { - private ExpandableChoice expandableChoice; - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - ChoiceItem chosenItem; - ChoiceItem defaultItem; - private ChoiceItem errorMessageItem = new ChoiceItem(' ', "error", resourceBundle.getString("please.enter.a.valid.command"), false); - - public ExpandableChoicePrompt() throws IOException { - } - - @Override - protected int getPageSize() { - return 0; - } - - @Override - protected PageSizeType getPageSizeType() { - return null; - } - - @Override - int getItemSize() { - return expandableChoice.getChoiceItems().size(); - } - - enum RenderState { - FOLDED, - FOLDED_ANSWERED, - EXPANDED - } - - RenderState renderState = RenderState.FOLDED; - ArrayList choiceItems; - String promptString; - - private void render() { - if (renderState == RenderState.EXPANDED) { - renderList(); - } else if (renderState == RenderState.FOLDED) { - System.out.println(""); - System.out.println(ansi().eraseLine().cursorUp(2)); - System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); - System.out.flush(); - renderHeight = 2; - } else if (renderState == RenderState.FOLDED_ANSWERED) { - System.out.println(""); - System.out.println(ansi().fg(Ansi.Color.CYAN).a(">> ").reset().a(chosenItem.getMessage()).eraseLine()); - System.out.print(ansi().cursorUp(2)); - System.out.print(renderMessagePrompt(expandableChoice.getMessage()) + " (" + promptString + ") "); - System.out.flush(); - renderHeight = 2; - } - } - - private void renderList() { - if (renderHeight == 2) { - // first time we expand the list... - renderHeight = 1 + itemList.size(); - System.out.println(""); - System.out.println(ansi().eraseLine().cursorUp(2).a(renderMessagePrompt(expandableChoice.getMessage())).eraseLine(Ansi.Erase.FORWARD)); - System.out.flush(); - } else { - gotoRenderTop(); - } - - int itemNumber = 0; - for (ConsoleUIItemIF choiceItem : itemList) { - String renderedItem = itemRenderer.render(choiceItem, (selectedItemIndex == itemNumber)); - System.out.println(renderedItem + ansi().eraseLine(Ansi.Erase.FORWARD)); - itemNumber++; - } - } - - public ExpandableChoiceResult prompt(ExpandableChoice expandableChoice) throws IOException { - this.expandableChoice = expandableChoice; - - choiceItems = expandableChoice.getChoiceItems(); - promptString = ""; - - for (ConsoleUIItemIF choiceItem : choiceItems) { - if (choiceItem instanceof ChoiceItem) { - ChoiceItem item = (ChoiceItem) choiceItem; - - if (item.getKey() == 'h') { - throw new IllegalStateException("you may not use the reserved key 'h' for an element of expandableChoice."); - } - if (defaultItem == null) { - defaultItem = item; - } - reader.addAllowedPrintableKey(item.getKey()); - promptString += item.isDefaultChoice() ? item.getKey().toString().toUpperCase() : item.getKey(); - } - } - - choiceItems.add(new ChoiceItem('h', "help", resourceBundle.getString("help.list.all.options"), false)); - reader.addAllowedPrintableKey('h'); - promptString += "h"; - - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.BACKSPACE); - renderState = RenderState.FOLDED; - - // first render call, we don't need to position the cursor up - renderHeight = 1; - render(); - - ReaderIF.ReaderInput readerInput = this.reader.read(); - while (true) { - if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.ENTER) { - // if ENTER pressed - if (chosenItem != null && chosenItem.getKey() == 'h') { - renderState = RenderState.EXPANDED; - - itemList = expandableChoice.getChoiceItems(); - - selectedItemIndex = getFirstSelectableItemIndex(); - render(); - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); - - readerInput = this.reader.read(); - } else { - if (renderState != RenderState.EXPANDED) { - System.out.println(""); - } else { - renderHeight++; - } - if (chosenItem != null) { - renderMessagePromptAndResult(expandableChoice.getMessage(), chosenItem.getMessage()); - return new ExpandableChoiceResult(chosenItem.getName()); - } else { - renderMessagePromptAndResult(expandableChoice.getMessage(), defaultItem.getMessage()); - return new ExpandableChoiceResult(defaultItem.getName()); - } - } - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - selectedItemIndex = getPreviousSelectableItemIndex(Rollover.ALLOWED); - chosenItem = (ChoiceItem) itemList.get(selectedItemIndex); - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - selectedItemIndex = getNextSelectableItemIndex(Rollover.ALLOWED); - chosenItem = (ChoiceItem) itemList.get(selectedItemIndex); - } - if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { - Character pressedKey = readerInput.getPrintableKey(); - if (promptString.toLowerCase().contains("" + pressedKey)) { - // find the new chosen item - selectedItemIndex = 0; - for (ConsoleUIItemIF choiceItem : choiceItems) { - if (choiceItem instanceof ChoiceItem) { - ChoiceItem item = (ChoiceItem) choiceItem; - if (item.getKey().equals(pressedKey)) { - chosenItem = item; - break; - } - selectedItemIndex++; - } - } - if (renderState == RenderState.FOLDED) { - renderState = RenderState.FOLDED_ANSWERED; - } - } else { - // not in valid choices - chosenItem = errorMessageItem; - } - } - render(); - readerInput = this.reader.read(); - } - } -} \ No newline at end of file diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java index c4b351779..9532a4067 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java @@ -7,7 +7,7 @@ * User: Andreas Wegmann

* Date: 03.02.16 */ -public class ExpandableChoiceResult implements PromtResultItemIF { +public class ExpandableChoiceResult implements PromptResultItemIF { String selectedId; /** @@ -28,6 +28,10 @@ public String getSelectedId() { return selectedId; } + public String getResult() { + return selectedId; + } + @Override public String toString() { return "ExpandableChoiceResult{" + diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java deleted file mode 100644 index 35c8c3774..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/InputPrompt.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.InputValue; -import de.codeshelf.consoleui.prompt.reader.ConsoleReaderImpl; -import de.codeshelf.consoleui.prompt.reader.ReaderIF; -import de.codeshelf.consoleui.prompt.renderer.CUIRenderer; -import jline.console.completer.Completer; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.List; - -import static org.fusesource.jansi.Ansi.ansi; - -/** - * Implementation of the input choice prompt. The user will be asked for a string input value. - * With support of completers an automatic expansion of strings and filenames can be configured. - * Defining a mask character, a password like input is possible. - *

- * User: Andreas Wegmann

- * Date: 06.01.16 - */ -public class InputPrompt extends AbstractPrompt implements PromptIF { - - private InputValue inputElement; - private ReaderIF reader; - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - - public InputPrompt() throws IOException { - } - - - public InputResult prompt(InputValue inputElement) throws IOException { - this.inputElement = inputElement; - - if (reader == null) { - reader = new ConsoleReaderImpl(); - } - - if (renderHeight == 0) { - renderHeight = 2; - } - - String prompt = renderMessagePrompt(this.inputElement.getMessage()) + itemRenderer.renderOptionalDefaultValue(this.inputElement); - //System.out.print(prompt + itemRenderer.renderValue(this.inputElement)); - //System.out.flush(); - List completer = inputElement.getCompleter(); - Character mask = inputElement.getMask(); - ReaderIF.ReaderInput readerInput = reader.readLine(completer,prompt,inputElement.getValue(),mask); - - String lineInput = readerInput.getLineInput(); - - if (lineInput == null || lineInput.trim().length() == 0) { - lineInput = inputElement.getDefaultValue(); - } - - String result; - if (mask == null) { - result=lineInput; - } else { - result=""; - if (lineInput!=null) { - for (int i=0; i - * User: Andreas Wegmann - * Date: 01.01.16 - */ -public class ListPrompt extends AbstractListablePrompt implements PromptIF { - - // the list to let the user choose from - protected ListChoice listChoice; - - /** - * helper class with render functionality. - */ - CUIRenderer itemRenderer = CUIRenderer.getRenderer(); - - /** - * Empty default constructor. - * - * @throws IOException may be thrown by super class - */ - public ListPrompt() throws IOException { - super(); - } - - @Override - protected int getPageSize() { - return listChoice.getPageSize(); - } - - @Override - protected PageSizeType getPageSizeType() { - return listChoice.getPageSizeType(); - } - - @Override - protected int getItemSize() { - return itemList.size(); - } - - /** - * Prompt the user for selecting zero to many choices from a checkbox. - * - * @param listChoice list with items to choose from. - * @return {@link ListResult} which holds the users choices. - * @throws IOException may be thrown by console reader - */ - public ListResult prompt(ListChoice listChoice) throws IOException { - this.listChoice = listChoice; - itemList = listChoice.getListItemList(); - if (reader == null) { - reader = new ConsoleReaderImpl(); - } - reader.addAllowedPrintableKey('j'); - reader.addAllowedPrintableKey('k'); - reader.addAllowedPrintableKey(' '); - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.DOWN); - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.UP); - reader.addAllowedSpecialKey(ReaderIF.SpecialKey.ENTER); - - selectedItemIndex = getFirstSelectableItemIndex(); - - initRendering(); - render(); - ReaderIF.ReaderInput readerInput = reader.read(); - while (readerInput.getSpecialKey() != ReaderIF.SpecialKey.ENTER) { - boolean downward = false; - boolean upward = false; - - if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.PRINTABLE_KEY) { - if (readerInput.getPrintableKey().equals('j')) { - selectedItemIndex = getNextSelectableItemIndex(rollOverMode); - downward = true; - } else if (readerInput.getPrintableKey().equals('k')) { - selectedItemIndex = getPreviousSelectableItemIndex(rollOverMode); - upward = true; - } - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.DOWN) { - selectedItemIndex = getNextSelectableItemIndex(rollOverMode); - downward = true; - } else if (readerInput.getSpecialKey() == ReaderIF.SpecialKey.UP) { - selectedItemIndex = getPreviousSelectableItemIndex(rollOverMode); - upward = true; - } - if (upward || downward) - recalculateViewWindow(upward, downward); - gotoRenderTop(); - render(); - readerInput = reader.read(); - } - - ListItem listItem = (ListItem) itemList.get(selectedItemIndex); - ListResult selection = new ListResult(listItem.getName()); - renderMessagePromptAndResult(listChoice.getMessage(), ((ListItem) itemList.get(selectedItemIndex)).getText()); - return selection; - } - - private void render() { - int itemNumber; - int renderedLines = 0; - - System.out.println(renderMessagePrompt(listChoice.getMessage())); - for (itemNumber = topDisplayedItem; renderedLines < viewPortHeight; itemNumber++, renderedLines++) { - String renderedItem = itemRenderer.render(itemList.get(itemNumber), (selectedItemIndex == itemNumber)); - System.out.println(renderedItem); - } - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java index ed1c3feb2..679eba4aa 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java @@ -5,7 +5,7 @@ *

* Created by Andreas Wegmann on 03.02.16. */ -public class ListResult implements PromtResultItemIF { +public class ListResult implements PromptResultItemIF { String selectedId; @@ -18,6 +18,10 @@ public String getSelectedId() { return selectedId; } + public String getResult() { + return selectedId; + } + /** * Default constructor. * diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java index 2a33efeec..01844fae8 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java @@ -10,7 +10,7 @@ * User: Andreas Wegmann * Date: 01.01.16 */ -public interface PromptIF { +public interface PromptIF { /** * Prompt the user for an imput. * diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java b/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java similarity index 60% rename from src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java rename to src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java index fa6448852..dc1dac15d 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/PromtResultItemIF.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java @@ -3,5 +3,6 @@ /** * Created by Andreas Wegmann on 03.02.16. */ -public interface PromtResultItemIF { +public interface PromptResultItemIF { + String getResult(); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java index d5a25ee0a..541b2bb61 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java @@ -3,7 +3,8 @@ import de.codeshelf.consoleui.elements.ExpandableChoice; import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import java.util.LinkedHashSet; +import java.util.ArrayList; +import java.util.List; /** * Created by andy on 22.01.16. @@ -12,11 +13,11 @@ public class ExpandableChoicePromptBuilder { private final PromptBuilder promptBuilder; private String name; private String message; - private LinkedHashSet itemList; + private List itemList; public ExpandableChoicePromptBuilder(PromptBuilder promptBuilder) { this.promptBuilder = promptBuilder; - this.itemList = new LinkedHashSet(); + this.itemList = new ArrayList<>(); } void addItem(ChoiceItemIF choiceItem) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java index 219a2d6ac..4526b24fd 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java @@ -1,9 +1,6 @@ package de.codeshelf.consoleui.prompt.builder; import de.codeshelf.consoleui.elements.InputValue; -import jline.console.completer.Completer; - -import java.util.ArrayList; /** * Created by andy on 22.01.16. @@ -14,7 +11,6 @@ public class InputValueBuilder { private String defaultValue; private String message; private Character mask; - private ArrayList completers; public InputValueBuilder(PromptBuilder promptBuilder) { this.promptBuilder = promptBuilder; @@ -35,14 +31,6 @@ public InputValueBuilder message(String message) { return this; } - public InputValueBuilder addCompleter(Completer completer) { - if (completers == null) { - completers = new ArrayList(); - } - this.completers.add(completer); - return this; - } - public InputValueBuilder mask(char mask) { this.mask = mask; return this; @@ -50,9 +38,6 @@ public InputValueBuilder mask(char mask) { public PromptBuilder addPrompt() { InputValue inputValue = new InputValue(name, message, null, defaultValue); - if (completers != null) { - inputValue.setCompleter(completers); - } if (mask != null) { inputValue.setMask(mask); } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java deleted file mode 100644 index f2a9bb566..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ConsoleReaderImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -package de.codeshelf.consoleui.prompt.reader; - -import java.io.IOException; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.Stack; - -import jline.console.ConsoleReader; -import jline.console.Operation; -import jline.console.completer.Completer; - -/** - * User: Andreas Wegmann - * Date: 02.01.16 - */ -public class ConsoleReaderImpl implements ReaderIF { - ConsoleReader console; - - private Set allowedSpecialKeys; - private Set allowedPrintableKeys; - - public ConsoleReaderImpl() throws IOException { - allowedPrintableKeys = new HashSet(); - allowedSpecialKeys = new HashSet(); - - console = new ConsoleReader(); - } - - public void setAllowedSpecialKeys(Set allowedSpecialKeys) { - this.allowedSpecialKeys.clear(); - this.allowedSpecialKeys.addAll(allowedSpecialKeys); - } - - public void setAllowedPrintableKeys(Set allowedPrintableKeys) { - this.allowedPrintableKeys.clear(); - this.allowedPrintableKeys.addAll(allowedPrintableKeys); - } - - public void addAllowedPrintableKey(Character character) { - this.allowedPrintableKeys.add(character); - } - - public void addAllowedSpecialKey(SpecialKey specialKey) { - this.allowedSpecialKeys.add(specialKey); - } - - public ReaderInput read() { - Object op; - - StringBuilder sb = new StringBuilder(); - Stack pushBackChar = new Stack(); - try { - while (true) { - int c = pushBackChar.isEmpty() ? console.readCharacter() : pushBackChar.pop (); - if (c == -1) { - return null; - } - sb.appendCodePoint(c); - - op = console.getKeys().getBound( sb ); - if (op instanceof Operation) { - Operation operation = (Operation) op; - if (operation == Operation.NEXT_HISTORY && this.allowedSpecialKeys.contains(SpecialKey.DOWN)) - return new ReaderInput(SpecialKey.DOWN); - if (operation == Operation.PREVIOUS_HISTORY && this.allowedSpecialKeys.contains(SpecialKey.UP)) - return new ReaderInput(SpecialKey.UP); - if (operation == Operation.ACCEPT_LINE && this.allowedSpecialKeys.contains(SpecialKey.ENTER)) - return new ReaderInput(SpecialKey.ENTER); - if (operation == Operation.BACKWARD_CHAR && this.allowedSpecialKeys.contains(SpecialKey.BACKSPACE)) - return new ReaderInput(SpecialKey.BACKSPACE); - - if (operation == Operation.SELF_INSERT) { - String lastBinding = sb.toString(); - Character cc = lastBinding.charAt(0); - if (allowedPrintableKeys.contains(cc)) { - return new ReaderInput(SpecialKey.PRINTABLE_KEY, cc); - } else { - sb = new StringBuilder(); - } - } - return new ReaderInput(SpecialKey.NONE); - } - if(Objects.isNull(op)) return new ReaderInput(SpecialKey.NONE); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { -// System.out.println("!!!!!!!!!!!!!! UPDTED"); -// console.shutdown(); - } - return null; - } - - /** - * Wrapper around JLine 2 library. - * - * @param completer List of completes to use - * @param prompt the text to display as prompt left side from the input - * @param mask optional mask character (may be used for password entry) - * @return a ReaderInput object with results - */ - public ReaderInput readLine(List completer, String prompt, String value, Character mask) throws IOException { - if (completer != null) { - for (Completer c : completer) { - console.addCompleter(c); - } - } - String readLine; - if (mask == null) { - readLine = console.readLine(prompt); - } else { - readLine = console.readLine(prompt, mask); - } - - - return new ReaderInput(SpecialKey.PRINTABLE_KEY, readLine); - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java b/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java deleted file mode 100644 index 2f5e0bb98..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/reader/ReaderIF.java +++ /dev/null @@ -1,67 +0,0 @@ -package de.codeshelf.consoleui.prompt.reader; - -import jline.console.completer.Completer; - -import java.io.IOException; -import java.util.List; -import java.util.Set; - -/** - * User: Andreas Wegmann - * Date: 02.01.16 - */ -public interface ReaderIF { - - public enum SpecialKey { - NONE, - UP, - DOWN, - ENTER, - BACKSPACE, - PRINTABLE_KEY, // not really a special key, but indicates an ordianry printable key - } - - void setAllowedSpecialKeys(Set allowedSpecialKeys); - - void setAllowedPrintableKeys(Set allowedPrintableKeys); - - void addAllowedPrintableKey(Character character); - - void addAllowedSpecialKey(SpecialKey specialKey); - - ReaderInput read(); - - ReaderInput readLine(List completer, String promt, String value, Character mask) throws IOException; - - class ReaderInput { - private SpecialKey specialKey; - private Character printableKey; - private String lineInput; - - public ReaderInput(SpecialKey specialKey) { - this.specialKey = specialKey; - } - - public ReaderInput(SpecialKey specialKey, Character printableKey) { - this.specialKey = specialKey; - this.printableKey = printableKey; - } - - public ReaderInput(SpecialKey specialKey, String lineInput) { - this.specialKey = specialKey; - this.lineInput = lineInput; - } - - public SpecialKey getSpecialKey() { - return specialKey; - } - - public Character getPrintableKey() { - return printableKey; - } - - public String getLineInput() { - return lineInput; - } - } -} diff --git a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java b/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java deleted file mode 100644 index 791537e54..000000000 --- a/src/main/java/de/codeshelf/consoleui/prompt/renderer/CUIRenderer.java +++ /dev/null @@ -1,131 +0,0 @@ -package de.codeshelf.consoleui.prompt.renderer; - -import de.codeshelf.consoleui.elements.ConfirmChoice; -import de.codeshelf.consoleui.elements.InputValue; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; -import de.codeshelf.consoleui.elements.items.impl.ListItem; -import de.codeshelf.consoleui.elements.items.impl.Separator; -import org.fusesource.jansi.Ansi; - -import java.util.ResourceBundle; - -import static org.fusesource.jansi.Ansi.ansi; - -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ -public class CUIRenderer { - //private final String cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("\uF078> ").toString(); - private final String cursorSymbol; - private final String noCursorSpace; - - private final String uncheckedBox; - private final String checkedBox; - private final String line; - - private static CUIRenderer renderer = new CUIRenderer(); - private final ResourceBundle resourceBundle; - - public CUIRenderer() { - String os = System.getProperty("os.name"); - if( os.startsWith("Windows") ) { - checkedBox = "(*) "; - uncheckedBox = "( ) "; - line = "---------"; - cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("> ").toString(); - noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); - } else { - checkedBox = "\u25C9 "; - uncheckedBox = "\u25EF "; - line = "\u2500─────────────"; - cursorSymbol = ansi().fg(Ansi.Color.CYAN).a("\u276F ").toString(); - noCursorSpace = ansi().fg(Ansi.Color.DEFAULT).a(" ").toString(); - } - resourceBundle = ResourceBundle.getBundle("consoleui_messages"); - } - - public static CUIRenderer getRenderer() { - return renderer; - } - - public String render(ConsoleUIItemIF item, boolean withCursor) { - if (item instanceof CheckboxItem) { - CheckboxItem checkboxItem = (CheckboxItem) item; - String prefix; - if (withCursor) { - prefix = cursorSymbol; - } else { - prefix = noCursorSpace; - } - return prefix + ansi() - .fg(checkboxItem.isEnabled() ? Ansi.Color.GREEN : Ansi.Color.WHITE) - .a(checkboxItem.isChecked() ? checkedBox : uncheckedBox) - .reset().a(checkboxItem.getText() + - (checkboxItem.isDisabled() ? " (" + checkboxItem.getDisabledText() + ")" : "")) - .eraseLine(Ansi.Erase.FORWARD) - .reset().toString(); - } - - if (item instanceof ListItem) { - ListItem listItem = (ListItem) item; - if (withCursor) { - return cursorSymbol + ansi() - .fg(Ansi.Color.CYAN).a(listItem.getText()) - .eraseLine(Ansi.Erase.FORWARD) - .reset().toString(); - } else { - return noCursorSpace + ansi() - .fg(Ansi.Color.DEFAULT).a(listItem.getText()) - .eraseLine(Ansi.Erase.FORWARD) - .reset().toString(); - } - } - - if (item instanceof ChoiceItem) { - ChoiceItem checkboxItem = (ChoiceItem) item; - if (withCursor) { - return cursorSymbol + ansi() - .fg(Ansi.Color.CYAN).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()) - .eraseLine(Ansi.Erase.FORWARD) - .reset().toString(); - } else - return noCursorSpace + ansi() - .fg(Ansi.Color.DEFAULT).a(checkboxItem.getKey() + " - " + checkboxItem.getMessage()) - .eraseLine(Ansi.Erase.FORWARD) - .reset().toString(); - } - - if (item instanceof Separator) { - Separator separator = (Separator) item; - return ansi().fg(Ansi.Color.WHITE).a( - separator.getMessage() != null ? separator.getMessage() : line).reset().toString(); - } - return ""; - } - - public String renderOptionalDefaultValue(InputValue inputElement) { - if (inputElement.getDefaultValue() != null) { - return " (" + inputElement.getDefaultValue() + ") "; - } - return " "; - } - - public String renderValue(InputValue inputElement) { - if (inputElement.getValue() != null) { - return inputElement.getValue(); - } - return ""; - } - - public String renderConfirmChoiceOptions(ConfirmChoice confirmChoice) { - if (confirmChoice.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.YES) { - return resourceBundle.getString("confirmation_yes_default"); - } else if (confirmChoice.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.NO) { - return resourceBundle.getString("confirmation_no_default"); - } - return resourceBundle.getString("confirmation_without_default"); - } -} diff --git a/src/main/resources/consoleui_messages.properties b/src/main/resources/consoleui_messages.properties index 4517b40a2..a73f37932 100644 --- a/src/main/resources/consoleui_messages.properties +++ b/src/main/resources/consoleui_messages.properties @@ -1,6 +1,6 @@ -confirmation_without_default=\ (y/n) -confirmation_no_default=\ (y/N) -confirmation_yes_default=\ (Y/n) +confirmation_without_default=(y/n) +confirmation_no_default=(y/N) +confirmation_yes_default=(Y/n) confirmation_yes_key=y confirmation_no_key=n diff --git a/src/main/resources/consoleui_messages_de_DE.properties b/src/main/resources/consoleui_messages_de_DE.properties index e4e6b79dd..1da57b1f5 100644 --- a/src/main/resources/consoleui_messages_de_DE.properties +++ b/src/main/resources/consoleui_messages_de_DE.properties @@ -1,6 +1,6 @@ -confirmation_without_default=\ (j/n) -confirmation_no_default=\ (j/N) -confirmation_yes_default=\ (J/n) +confirmation_without_default=(j/n) +confirmation_no_default=(j/N) +confirmation_yes_default=(J/n) confirmation_yes_key=j confirmation_no_key=n help.list.all.options=Hilfe. Listet alle Optionen. diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java index baeb0e37e..ab3e641a4 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java @@ -1,18 +1,13 @@ package de.codeshelf.consoleui.prompt; -import de.codeshelf.consoleui.elements.Checkbox; -import de.codeshelf.consoleui.elements.PageSizeType; import de.codeshelf.consoleui.elements.items.CheckboxItemIF; import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; import de.codeshelf.consoleui.elements.items.impl.Separator; -import de.codeshelf.consoleui.prompt.reader.ReaderIF; -import jline.console.completer.Completer; import org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * User: Andreas Wegmann @@ -21,7 +16,6 @@ public class CheckboxPromptTest { @Test public void renderSimpleList() throws IOException { - CheckboxPrompt checkboxPrompt = new CheckboxPrompt(); List list= new ArrayList<>(); list.add(new CheckboxItem("One")); @@ -33,33 +27,6 @@ public void renderSimpleList() throws IOException { list.add(new CheckboxItem("Four")); list.add(new CheckboxItem(true,"Five")); - checkboxPrompt.setReader(new ReaderIF() { - public void setAllowedSpecialKeys(Set allowedSpecialKeys) { - - } - - public void setAllowedPrintableKeys(Set allowedPrintableKeys) { - - } - - public void addAllowedPrintableKey(Character character) { - - } - - public void addAllowedSpecialKey(SpecialKey specialKey) { - - } - - public ReaderInput read() { - return new ReaderInput(SpecialKey.ENTER); - } - - public ReaderInput readLine(List completer, String promt, String value, Character mask) { - return null; - } - }); - - checkboxPrompt.prompt(new Checkbox("no message", null, 10, PageSizeType.ABSOLUTE, list)); } } \ No newline at end of file diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java index 2c66e21d3..651b14d79 100644 --- a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java @@ -3,10 +3,10 @@ import de.codeshelf.consoleui.elements.ConfirmChoice; import de.codeshelf.consoleui.elements.PromptableElementIF; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; -import jline.console.completer.StringsCompleter; +import org.jline.terminal.TerminalBuilder; import org.junit.Test; -import java.util.HashMap; +import java.io.IOException; import java.util.List; import static org.junit.Assert.assertNotNull; @@ -18,8 +18,8 @@ public class PromptBuilderTest { @Test - public void testBuilder() throws Exception { - ConsolePrompt prompt = new ConsolePrompt(); + public void testBuilder() throws IOException { + ConsolePrompt prompt = new ConsolePrompt(TerminalBuilder.builder().build()); PromptBuilder promptBuilder = prompt.getPromptBuilder(); promptBuilder.createConfirmPromp() @@ -32,7 +32,6 @@ public void testBuilder() throws Exception { .name("name") .message("Please enter your name") .defaultValue("John Doe") - .addCompleter(new StringsCompleter("Jim", "Jack", "John")) .addPrompt(); promptBuilder.createListPrompt() From e20abd5a139fb3d2611dfcfc508bd253ba7ec31c Mon Sep 17 00:00:00 2001 From: mattirn Date: Sat, 6 Feb 2021 09:18:29 +0100 Subject: [PATCH 109/115] Fix a long list scrolling --- .../consoleui/prompt/AbstractPrompt.java | 70 +++++++++++++++---- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 8e1f94bc9..6b438140b 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -41,6 +41,7 @@ public abstract class AbstractPrompt { private final Size size = new Size(); private final ConsolePrompt.UiConfig config; private Display display; + private ListRange range = null; public AbstractPrompt(Terminal terminal, List header, AttributedString message, ConsolePrompt.UiConfig cfg) { this(terminal, header, message, new ArrayList<>(), cfg); @@ -71,13 +72,14 @@ protected void refreshDisplay(int row) { protected void refreshDisplay(int row, Set selected) { display.resize(size.getRows(), size.getColumns()); display.reset(); - display.update(displayLines(row, selected), size.cursorPos(firstItemRow + items.size(), 0)); + display.update(displayLines(row, selected), size.cursorPos(Math.min(size.getRows() - 1, firstItemRow + items.size()) + , 0)); } protected void refreshDisplay(int row, int column, String buffer, boolean newline) { display.resize(size.getRows(), size.getColumns()); AttributedStringBuilder asb = new AttributedStringBuilder(); - int crow = column == 0 ? firstItemRow + items.size() : row; + int crow = column == 0 ? Math.min(size.getRows() - 1, firstItemRow + items.size()) : row; if (buffer != null) { if (newline && !buffer.isEmpty()) { asb.style(config.style(".pr")).append(">> "); @@ -92,15 +94,19 @@ protected void refreshDisplay(int row, int column, String buffer) { } private List displayLines(int cursorRow, Set selected) { - List out = new ArrayList<>(header); - int i = firstItemRow; + computeListRange(cursorRow); + List out = new ArrayList<>(); + for (int i = range.headerStart; i < header.size(); i++) { + out.add(header.get(i)); + } AttributedStringBuilder asb = new AttributedStringBuilder(); asb.append(message); out.add(asb.toAttributedString()); - for (ConsoleUIItemIF s : items) { + for (int i = range.first; i < range.last - 1; i++) { + ConsoleUIItemIF s = items.get(i); asb = new AttributedStringBuilder(); if (s.isSelectable()) { - asb = i == cursorRow ? asb.append(config.indicator()).style(AttributedStyle.DEFAULT).append(" ") + asb = i + firstItemRow == cursorRow ? asb.append(config.indicator()).style(AttributedStyle.DEFAULT).append(" ") : fillIndicatorSpace(asb).append(" "); asb = selected.contains(s.getName()) ? asb.append(config.checkedBox()) : asb.append(config.uncheckedBox()); @@ -118,8 +124,8 @@ private List displayLines(int cursorRow, Set selected) asb.append(" (").append(s.getDisabledText()).append(")"); } out.add(asb.toAttributedString()); - i++; } + addFooter(out); // footer is necessary for making the long item list scroll correctly return out; } @@ -136,9 +142,48 @@ private void fillCheckboxSpace(AttributedStringBuilder asb) { } } + private static class ListRange { + final int first; + final int last; + final int headerStart; + + public ListRange(int headerStart, int first, int last) { + this.headerStart = headerStart; + this.first = first; + this.last = last; + } + } + + private void computeListRange(int cursorRow) { + if (range != null && range.first <= cursorRow - firstItemRow && range.last - 1 > cursorRow - firstItemRow) { + return; + } + range = new ListRange(0, 0, items.size() + 1); + if (size.getRows() < header.size() + items.size()) { + int itemId = cursorRow - firstItemRow; + int headerStart = header.size() + 1 > 10 ? header.size() - 9 : 0; + int forList = size.getRows() - header.size() + headerStart - 1; + if (itemId < forList - 1) { + range = new ListRange(headerStart, 0, forList); + } else { + range = new ListRange(headerStart, itemId - forList + 2, itemId + 2); + } + } + } + + private void addFooter(List lines) { + if (size.getRows() < header.size() + items.size()) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + lines.add(asb.append(".").toAttributedString()); + } + } + private List displayLines(int cursorRow, AttributedString buffer, boolean newline) { - List out = new ArrayList<>(header); - int i = firstItemRow; + computeListRange(cursorRow); + List out = new ArrayList<>(); + for (int i = range.headerStart; i < header.size(); i++) { + out.add(header.get(i)); + } AttributedStringBuilder asb = new AttributedStringBuilder(); asb.append(message); if (buffer != null && !newline) { @@ -150,10 +195,11 @@ private List displayLines(int cursorRow, AttributedString buff asb.append(buffer); out.add(asb.toAttributedString()); } - for (ConsoleUIItemIF s : items) { + for (int i = range.first; i < range.last - 1; i++) { + ConsoleUIItemIF s = items.get(i); asb = new AttributedStringBuilder(); String key = s instanceof ChoiceItem ? ((ChoiceItem)s).getKey() + " - " : ""; - if (i == cursorRow) { + if (i + firstItemRow == cursorRow) { out.add(asb.append(config.indicator()).style(config.style(".se")).append(" ").append(key) .append(s.getText()).toAttributedString()); } else if (!(s instanceof Separator)) { @@ -162,8 +208,8 @@ private List displayLines(int cursorRow, AttributedString buff } else { out.add(asb.append(s.getText()).toAttributedString()); } - i++; } + addFooter(out); return out; } From 85aefac597ed3a9cda75b728bd6bb4b41f2de37f Mon Sep 17 00:00:00 2001 From: mattirn Date: Sat, 6 Feb 2021 18:56:32 +0100 Subject: [PATCH 110/115] Add tab completion --- .../java/de/codeshelf/consoleui/Basic.java | 16 +- .../consoleui/elements/InputValue.java | 12 + .../consoleui/prompt/AbstractPrompt.java | 208 ++++++++++++++++-- .../consoleui/prompt/ConsolePrompt.java | 23 +- .../prompt/builder/InputValueBuilder.java | 9 + 5 files changed, 248 insertions(+), 20 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/src/main/java/de/codeshelf/consoleui/Basic.java index cef614e4c..1c5405402 100644 --- a/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/src/main/java/de/codeshelf/consoleui/Basic.java @@ -6,6 +6,10 @@ import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; import de.codeshelf.consoleui.prompt.PromptResultItemIF; import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import org.jline.builtins.Completers; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.impl.completer.StringsCompleter; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.utils.AttributedString; @@ -13,6 +17,7 @@ import org.jline.utils.AttributedStyle; import org.jline.utils.OSUtils; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -51,7 +56,12 @@ public static void main(String[] args) { } else { config = new UiConfig("\u276F", "\u25EF ", "\u25C9 ", "\u25EF "); } - ConsolePrompt prompt = new ConsolePrompt(terminal, config); + // + // LineReader is needed only if you are adding JLine Completers in your prompts. + // If you are not using Completers you do not need to create LineReader. + // + LineReader reader = LineReaderBuilder.builder().terminal(terminal).build(); + ConsolePrompt prompt = new ConsolePrompt(reader, terminal, config); PromptBuilder promptBuilder = prompt.getPromptBuilder(); @@ -59,7 +69,9 @@ public static void main(String[] args) { .name("name") .message("Please enter your name") .defaultValue("John Doe") - // .mask('*') + //.mask('*') + .addCompleter(new Completers.FilesCompleter(() -> Paths.get(System.getProperty("user.dir")))) +// .addCompleter(new StringsCompleter("Jim", "Jack", "John")) .addPrompt(); promptBuilder.createListPrompt() diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java index 05e3d7ddd..91975d056 100644 --- a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java +++ b/src/main/java/de/codeshelf/consoleui/elements/InputValue.java @@ -1,5 +1,7 @@ package de.codeshelf.consoleui.elements; +import org.jline.reader.Completer; + /** * User: Andreas Wegmann * Date: 06.01.16 @@ -8,6 +10,7 @@ public class InputValue extends AbstractPromptableElement { private String value; private String defaultValue; private Character mask; + private Completer completer; public InputValue(String name, String message) { super(message, name); @@ -38,4 +41,13 @@ public void setMask(Character mask) { public Character getMask() { return mask; } + + public void setCompleter(Completer completer) { + this.completer = completer; + } + + public Completer getCompleter() { + return completer; + } + } diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index 6b438140b..c8f1a3b28 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -14,13 +14,13 @@ import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; import org.jline.keymap.BindingReader; import org.jline.keymap.KeyMap; +import org.jline.reader.*; +import org.jline.reader.impl.CompletionMatcherImpl; import org.jline.terminal.Size; import org.jline.terminal.Terminal; import org.jline.utils.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -39,7 +39,7 @@ public abstract class AbstractPrompt { protected final List items; protected final int firstItemRow; private final Size size = new Size(); - private final ConsolePrompt.UiConfig config; + protected final ConsolePrompt.UiConfig config; private Display display; private ListRange range = null; @@ -66,7 +66,7 @@ protected void resetDisplay() { } protected void refreshDisplay(int row) { - refreshDisplay(row, 0, null); + refreshDisplay(row, 0, null, false); } protected void refreshDisplay(int row, Set selected) { @@ -89,8 +89,74 @@ protected void refreshDisplay(int row, int column, String buffer, boolean newlin display.update(displayLines(row, asb.toAttributedString(), newline), size.cursorPos(crow, column)); } - protected void refreshDisplay(int row, int column, String buffer) { - refreshDisplay(row, column, buffer, false); + protected void refreshDisplay(int buffRow, int buffCol, String buffer, int candRow, int candCol, List candidates) { + display.resize(size.getRows(), size.getColumns()); + AttributedStringBuilder asb = new AttributedStringBuilder(); + if (buffer != null) { + asb.style(AttributedStyle.DEFAULT).append(buffer); + } + display.update(displayLines(candRow, candCol, asb.toAttributedString(), candidates), size.cursorPos(buffRow, buffCol)); + } + + private int candidateStartPosition(int candidatesColumn, String buffer, List cands) { + List values = cands.stream().map(c -> AttributedString.stripAnsi(c.displ())) + .filter(c -> !c.matches("\\w+") && c.length() > 1).collect(Collectors.toList()); + Set notDelimiters = new HashSet<>(); + values.forEach(v -> v.substring(0, v.length() - 1).chars() + .filter(c -> !Character.isDigit(c) && !Character.isAlphabetic(c)) + .forEach(c -> notDelimiters.add(Character.toString((char)c)))); + int out = candidatesColumn; + for (int i = buffer.length(); i > 0; i--) { + if (buffer.substring(0, i).matches(".*\\W") + && !notDelimiters.contains(buffer.substring(i - 1, i))) { + out += i; + break; + } + } + return out; + } + + private List displayLines(int cursorRow, int candidatesColumn, AttributedString buffer + , List candidates) { + List out = new ArrayList<>(header); + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + asb.append(buffer); + out.add(asb.toAttributedString()); + if (candidates.size() < size.getRows() - header.size()) { + int listStart; + if (cursorRow - firstItemRow >= 0) { + String dc = candidates.get(cursorRow - firstItemRow).displ(); + listStart = candidatesColumn + buffer.columnLength() - display.wcwidth(dc) + + (AttributedString.stripAnsi(dc).endsWith("*") ? 1 : 0); + } else { + listStart = candidateStartPosition(candidatesColumn, buffer.toString(), candidates); + } + int width = Math.max(candidates.stream().map(Candidate::displ).mapToInt(display::wcwidth).max().orElse(20), 20); + int i = firstItemRow; + for (Candidate c : candidates) { + asb = new AttributedStringBuilder(); + AttributedStringBuilder tmp = new AttributedStringBuilder(); + tmp.ansiAppend(c.displ()); + asb.style(tmp.styleAt(0)); + if (i == cursorRow) { + asb.style(new AttributedStyle().inverse()); + } + asb.append(AttributedString.stripAnsi(c.displ())); + int cl = asb.columnLength(); + for (int k = cl; k < width; k++) { + asb.append(" "); + } + AttributedStringBuilder asb2 = new AttributedStringBuilder(); + asb2.tabs(listStart); + asb2.append("\t"); + asb2.style(config.style(".cb")); + asb2.append(asb).append(" "); + out.add(asb2.toAttributedString()); + i++; + } + } + return out; } private List displayLines(int cursorRow, Set selected) { @@ -334,7 +400,7 @@ public ConfirmResult execute() { StringBuilder buffer = new StringBuilder(); ConfirmChoice.ConfirmationValue confirm = defaultValue; while (true) { - refreshDisplay(row, column, buffer.toString()); + refreshDisplay(row, column, buffer.toString(), false); Operation op = bindingReader.readBinding(keyMap); buffer = new StringBuilder(); switch (op) { @@ -360,22 +426,27 @@ public ConfirmResult execute() { } protected static class InputValuePrompt extends AbstractPrompt { - private enum Operation {INSERT, BACKSPACE, DELETE, RIGHT, LEFT, BEGINNING_OF_LINE, END_OF_LINE, EXIT} + private enum Operation {INSERT, BACKSPACE, DELETE, RIGHT, LEFT, BEGINNING_OF_LINE, END_OF_LINE, SELECT_CANDIDATE, EXIT} + private enum SelectOp {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, EXIT} private final int startColumn; private final String defaultValue; private final Character mask; + private final LineReader reader; + private final Completer completer; - private InputValuePrompt(Terminal terminal, List header, AttributedString message + private InputValuePrompt(LineReader reader, Terminal terminal, List header, AttributedString message , InputValue inputValue, UiConfig cfg) { super(terminal, header, message, cfg); + this.reader = reader; defaultValue = inputValue.getDefaultValue(); startColumn = message.columnLength(); mask = inputValue.getMask(); + this.completer = inputValue.getCompleter(); } - public static InputValuePrompt getPrompt(Terminal terminal, List header, AttributedString message + public static InputValuePrompt getPrompt(LineReader reader, Terminal terminal, List header, AttributedString message , InputValue inputValue, UiConfig cfg) { - return new InputValuePrompt(terminal, header, message, inputValue, cfg); + return new InputValuePrompt(reader, terminal, header, message, inputValue, cfg); } private void bindKeys(KeyMap map) { @@ -393,17 +464,35 @@ private void bindKeys(KeyMap map) { map.bind(Operation.END_OF_LINE, ctrl('E'), key(terminal, InfoCmp.Capability.key_end)); map.bind(Operation.RIGHT, ctrl('F')); map.bind(Operation.LEFT, ctrl('B')); + map.bind(Operation.SELECT_CANDIDATE, "\t"); + } + + private void bindSelectKeys(KeyMap map) { + map.bind(SelectOp.FORWARD_ONE_LINE, "\t", "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); + map.bind(SelectOp.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); + map.bind(SelectOp.EXIT,"\r"); } public InputResult execute() { resetDisplay(); int row = firstItemRow - 1; int column = startColumn; + List matches = new ArrayList<>(); KeyMap keyMap = new KeyMap<>(); bindKeys(keyMap); StringBuilder buffer = new StringBuilder(); + CompletionMatcher completionMatcher = new CompletionMatcherImpl(); while (true) { - refreshDisplay(row, column, buffer.toString()); + if (completer != null && reader != null) { + List possible = new ArrayList<>(); + CompletingWord completingWord = new CompletingWord(buffer.toString()); + completer.complete(reader, completingWord, possible); + completionMatcher.compile(config.completionOptions(), false, completingWord, false, 0 + , null); + matches = completionMatcher.matches(possible).stream().sorted(Comparator.naturalOrder()) + .collect(Collectors.toList()); + } + refreshDisplay(firstItemRow - 1, column, buffer.toString(), row, startColumn, matches); Operation op = bindingReader.readBinding(keyMap); switch (op) { case LEFT: @@ -423,8 +512,8 @@ public InputResult execute() { case BACKSPACE: if (column > startColumn) { buffer.deleteCharAt(column - startColumn - 1); + column--; } - column--; break; case DELETE: if (column < startColumn + buffer.length() && column >= startColumn) { @@ -437,6 +526,12 @@ public InputResult execute() { case END_OF_LINE: column = startColumn + buffer.length(); break; + case SELECT_CANDIDATE: + String selected = selectCandidate(firstItemRow - 1, buffer.toString(),row + 1, startColumn, matches); + buffer.delete(0, buffer.length()); + buffer.append(selected); + column = startColumn + buffer.length(); + break; case EXIT: if (buffer.toString().isEmpty()) { buffer.append(defaultValue); @@ -446,6 +541,91 @@ public InputResult execute() { } } + String selectCandidate(int buffRow, String buffer, int row, int column, List candidates) { + if (candidates.isEmpty()) { + return buffer; + } else if (candidates.size() == 1) { + return candidates.get(0).value(); + } + KeyMap keyMap = new KeyMap<>(); + bindSelectKeys(keyMap); + while (true) { + String selected = candidates.get(row - buffRow - 1).value(); + refreshDisplay(buffRow, column + selected.length(), selected, row, column, candidates); + SelectOp op = bindingReader.readBinding(keyMap); + switch (op) { + case FORWARD_ONE_LINE: + if (row < buffRow + candidates.size()) { + row++; + } else { + row = buffRow + 1; + } + break; + case BACKWARD_ONE_LINE: + if (row > buffRow + 1) { + row--; + } else { + row = buffRow + candidates.size() - 1; + } + break; + case EXIT: + return selected; + } + } + } + } + + private static class CompletingWord implements CompletingParsedLine { + private final String word; + + public CompletingWord(String word) { + this.word = word; + } + + @Override + public CharSequence escape(CharSequence candidate, boolean complete) { + return null; + } + + @Override + public int rawWordCursor() { + return word.length(); + } + + @Override + public int rawWordLength() { + return word.length(); + } + + @Override + public String word() { + return word; + } + + @Override + public int wordCursor() { + return word.length(); + } + + @Override + public int wordIndex() { + return 0; + } + + @Override + public List words() { + return new ArrayList<>(Collections.singletonList(word)); + } + + @Override + public String line() { + return word; + } + + @Override + public int cursor() { + return word.length(); + } } private static int nextRow(int row, int firstItemRow, List items) { diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 127e00184..0bebcefea 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -6,6 +6,7 @@ import de.codeshelf.consoleui.prompt.builder.PromptBuilder; import org.jline.builtins.Styles; import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.reader.LineReader; import org.jline.terminal.Attributes; import org.jline.terminal.Terminal; import org.jline.utils.*; @@ -20,6 +21,7 @@ * @author Matti Rinta-Nikkola */ public class ConsolePrompt { + private final LineReader reader; private final Terminal terminal; private final UiConfig config; @@ -28,16 +30,20 @@ public class ConsolePrompt { * @param terminal the terminal. */ public ConsolePrompt(Terminal terminal) { - this(terminal, new UiConfig()); + this(null, terminal, new UiConfig()); + } + public ConsolePrompt(Terminal terminal, UiConfig config) { + this(null, terminal, config); } /** * * @param terminal the terminal. * @param config ConsolePrompt cursor pointer and checkbox configuration */ - public ConsolePrompt(Terminal terminal, UiConfig config) { + public ConsolePrompt(LineReader reader, Terminal terminal, UiConfig config) { this.terminal = terminal; this.config = config; + this.reader = reader; } /** @@ -91,7 +97,7 @@ public Map prompt(List header if (ip.getDefaultValue() != null) { asb.append("(").append(ip.getDefaultValue()).append(") "); } - result = InputValuePrompt.getPrompt(terminal, header, asb.toAttributedString(), ip, config).execute(); + result = InputValuePrompt.getPrompt(reader, terminal, header, asb.toAttributedString(), ip, config).execute(); } else if (pe instanceof ExpandableChoice) { ExpandableChoice ec = (ExpandableChoice) pe; asb.append("("); @@ -168,7 +174,7 @@ public PromptBuilder getPromptBuilder() { * ConsoleUI colors are configurable using UI_COLORS environment variable */ public static class UiConfig { - static final String DEFAULT_UI_COLORS = "cu=36:be=32:bd=37:pr=32:me=1:an=36:se=36"; + static final String DEFAULT_UI_COLORS = "cu=36:be=32:bd=37:pr=32:me=1:an=36:se=36:cb=100"; static final String UI_COLORS = "UI_COLORS"; private final AttributedString indicator; private final AttributedString uncheckedBox; @@ -176,6 +182,7 @@ public static class UiConfig { private final AttributedString unavailable; private final StyleResolver resolver; private final ResourceBundle resourceBundle; + private Map completionOptions = new HashMap<>(); public UiConfig() { this(null, null, null, null); @@ -223,6 +230,14 @@ public ResourceBundle resourceBundle() { return resourceBundle; } + public void setCompletionOptions(Map completionOptions) { + this.completionOptions = completionOptions; + } + + public Map completionOptions() { + return completionOptions; + } + private static StyleResolver resolver(String style) { Map colors = Arrays.stream(style.split(":")) .collect(Collectors.toMap(s -> s.substring(0, s.indexOf('=')), diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java b/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java index 4526b24fd..01fbb8949 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java @@ -1,6 +1,7 @@ package de.codeshelf.consoleui.prompt.builder; import de.codeshelf.consoleui.elements.InputValue; +import org.jline.reader.Completer; /** * Created by andy on 22.01.16. @@ -11,6 +12,7 @@ public class InputValueBuilder { private String defaultValue; private String message; private Character mask; + private Completer completer; public InputValueBuilder(PromptBuilder promptBuilder) { this.promptBuilder = promptBuilder; @@ -41,8 +43,15 @@ public PromptBuilder addPrompt() { if (mask != null) { inputValue.setMask(mask); } + if (completer != null) { + inputValue.setCompleter(completer); + } promptBuilder.addPrompt(inputValue); return promptBuilder; } + public InputValueBuilder addCompleter(Completer completer) { + this.completer = completer; + return this; + } } From 9ae5a362f593b9791ce91b3618e975b8c3610f11 Mon Sep 17 00:00:00 2001 From: mattirn Date: Sun, 7 Feb 2021 10:33:59 +0100 Subject: [PATCH 111/115] tab completion: manage long candidate list and better integration with JLine --- .../consoleui/prompt/AbstractPrompt.java | 117 ++++++++++-------- .../consoleui/prompt/ConsolePrompt.java | 23 +++- 2 files changed, 85 insertions(+), 55 deletions(-) diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java index c8f1a3b28..f8132e368 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java @@ -16,6 +16,7 @@ import org.jline.keymap.KeyMap; import org.jline.reader.*; import org.jline.reader.impl.CompletionMatcherImpl; +import org.jline.reader.impl.ReaderUtils; import org.jline.terminal.Size; import org.jline.terminal.Terminal; import org.jline.utils.*; @@ -37,7 +38,7 @@ public abstract class AbstractPrompt { private final List header; private final AttributedString message; protected final List items; - protected final int firstItemRow; + protected int firstItemRow; private final Size size = new Size(); protected final ConsolePrompt.UiConfig config; private Display display; @@ -47,7 +48,7 @@ public AbstractPrompt(Terminal terminal, List header, Attribut this(terminal, header, message, new ArrayList<>(), cfg); } - public AbstractPrompt(Terminal terminal, List header, AttributedString message, List items + public AbstractPrompt(Terminal terminal, List header, AttributedString message, List items , ConsolePrompt.UiConfig cfg) { this.terminal = terminal; this.bindingReader = new BindingReader(terminal.reader()); @@ -58,6 +59,10 @@ public AbstractPrompt(Terminal terminal, List header, Attribu this.config = cfg; } + protected void resetHeader() { + this.firstItemRow = header.size() + 1; + } + protected void resetDisplay() { display = new Display(terminal, true); size.copy(terminal.getSize()); @@ -118,49 +123,51 @@ private int candidateStartPosition(int candidatesColumn, String buffer, List displayLines(int cursorRow, int candidatesColumn, AttributedString buffer , List candidates) { - List out = new ArrayList<>(header); + computeListRange(cursorRow, candidates.size()); + List out = new ArrayList<>(); + for (int i = range.headerStart; i < header.size(); i++) { + out.add(header.get(i)); + } AttributedStringBuilder asb = new AttributedStringBuilder(); asb.append(message); asb.append(buffer); out.add(asb.toAttributedString()); - if (candidates.size() < size.getRows() - header.size()) { - int listStart; - if (cursorRow - firstItemRow >= 0) { - String dc = candidates.get(cursorRow - firstItemRow).displ(); - listStart = candidatesColumn + buffer.columnLength() - display.wcwidth(dc) + int listStart; + if (cursorRow - firstItemRow >= 0) { + String dc = candidates.get(cursorRow - firstItemRow).displ(); + listStart = candidatesColumn + buffer.columnLength() - display.wcwidth(dc) + (AttributedString.stripAnsi(dc).endsWith("*") ? 1 : 0); - } else { - listStart = candidateStartPosition(candidatesColumn, buffer.toString(), candidates); + } else { + listStart = candidateStartPosition(candidatesColumn, buffer.toString(), candidates); + } + int width = Math.max(candidates.stream().map(Candidate::displ).mapToInt(display::wcwidth).max().orElse(20), 20); + for (int i = range.first; i < range.last - 1; i++) { + Candidate c = candidates.get(i); + asb = new AttributedStringBuilder(); + AttributedStringBuilder tmp = new AttributedStringBuilder(); + tmp.ansiAppend(c.displ()); + asb.style(tmp.styleAt(0)); + if (i + firstItemRow == cursorRow) { + asb.style(new AttributedStyle().inverse()); } - int width = Math.max(candidates.stream().map(Candidate::displ).mapToInt(display::wcwidth).max().orElse(20), 20); - int i = firstItemRow; - for (Candidate c : candidates) { - asb = new AttributedStringBuilder(); - AttributedStringBuilder tmp = new AttributedStringBuilder(); - tmp.ansiAppend(c.displ()); - asb.style(tmp.styleAt(0)); - if (i == cursorRow) { - asb.style(new AttributedStyle().inverse()); - } - asb.append(AttributedString.stripAnsi(c.displ())); - int cl = asb.columnLength(); - for (int k = cl; k < width; k++) { - asb.append(" "); - } - AttributedStringBuilder asb2 = new AttributedStringBuilder(); - asb2.tabs(listStart); - asb2.append("\t"); - asb2.style(config.style(".cb")); - asb2.append(asb).append(" "); - out.add(asb2.toAttributedString()); - i++; + asb.append(AttributedString.stripAnsi(c.displ())); + int cl = asb.columnLength(); + for (int k = cl; k < width; k++) { + asb.append(" "); } - } + AttributedStringBuilder asb2 = new AttributedStringBuilder(); + asb2.tabs(listStart); + asb2.append("\t"); + asb2.style(config.style(".cb")); + asb2.append(asb).append(" "); + out.add(asb2.toAttributedString()); + } + addFooter(out, candidates.size()); return out; } private List displayLines(int cursorRow, Set selected) { - computeListRange(cursorRow); + computeListRange(cursorRow, items.size()); List out = new ArrayList<>(); for (int i = range.headerStart; i < header.size(); i++) { out.add(header.get(i)); @@ -191,7 +198,7 @@ private List displayLines(int cursorRow, Set selected) } out.add(asb.toAttributedString()); } - addFooter(out); // footer is necessary for making the long item list scroll correctly + addFooter(out, items.size()); // footer is necessary for making the long item list scroll correctly return out; } @@ -220,14 +227,15 @@ public ListRange(int headerStart, int first, int last) { } } - private void computeListRange(int cursorRow) { + private void computeListRange(int cursorRow, int itemsSize) { if (range != null && range.first <= cursorRow - firstItemRow && range.last - 1 > cursorRow - firstItemRow) { return; } - range = new ListRange(0, 0, items.size() + 1); - if (size.getRows() < header.size() + items.size()) { + range = new ListRange(0, 0, itemsSize + 1); + if (size.getRows() < header.size() + itemsSize + 1) { int itemId = cursorRow - firstItemRow; int headerStart = header.size() + 1 > 10 ? header.size() - 9 : 0; + firstItemRow = firstItemRow - headerStart; int forList = size.getRows() - header.size() + headerStart - 1; if (itemId < forList - 1) { range = new ListRange(headerStart, 0, forList); @@ -237,15 +245,15 @@ private void computeListRange(int cursorRow) { } } - private void addFooter(List lines) { - if (size.getRows() < header.size() + items.size()) { + private void addFooter(List lines, int itemsSize) { + if (size.getRows() < header.size() + itemsSize + 1) { AttributedStringBuilder asb = new AttributedStringBuilder(); lines.add(asb.append(".").toAttributedString()); } } private List displayLines(int cursorRow, AttributedString buffer, boolean newline) { - computeListRange(cursorRow); + computeListRange(cursorRow, items.size()); List out = new ArrayList<>(); for (int i = range.headerStart; i < header.size(); i++) { out.add(header.get(i)); @@ -275,7 +283,7 @@ private List displayLines(int cursorRow, AttributedString buff out.add(asb.append(s.getText()).toAttributedString()); } } - addFooter(out); + addFooter(out, items.size()); return out; } @@ -482,17 +490,23 @@ public InputResult execute() { bindKeys(keyMap); StringBuilder buffer = new StringBuilder(); CompletionMatcher completionMatcher = new CompletionMatcherImpl(); + boolean tabCompletion = completer != null && reader != null; while (true) { - if (completer != null && reader != null) { + boolean displayCandidates = true; + if (tabCompletion) { List possible = new ArrayList<>(); CompletingWord completingWord = new CompletingWord(buffer.toString()); completer.complete(reader, completingWord, possible); - completionMatcher.compile(config.completionOptions(), false, completingWord, false, 0 + completionMatcher.compile(config.readerOptions(), false, completingWord, false, 0 , null); matches = completionMatcher.matches(possible).stream().sorted(Comparator.naturalOrder()) .collect(Collectors.toList()); + if (matches.size() > ReaderUtils.getInt(reader, LineReader.MENU_LIST_MAX, 10)) { + displayCandidates = false; + } } - refreshDisplay(firstItemRow - 1, column, buffer.toString(), row, startColumn, matches); + refreshDisplay(firstItemRow - 1, column, buffer.toString(), row, startColumn + , displayCandidates ? matches : new ArrayList<>()); Operation op = bindingReader.readBinding(keyMap); switch (op) { case LEFT: @@ -527,10 +541,13 @@ public InputResult execute() { column = startColumn + buffer.length(); break; case SELECT_CANDIDATE: - String selected = selectCandidate(firstItemRow - 1, buffer.toString(),row + 1, startColumn, matches); - buffer.delete(0, buffer.length()); - buffer.append(selected); - column = startColumn + buffer.length(); + if (tabCompletion && matches.size() < ReaderUtils.getInt(reader, LineReader.LIST_MAX, 50)) { + String selected = selectCandidate(firstItemRow - 1, buffer.toString(), row + 1, startColumn, matches); + resetHeader(); + buffer.delete(0, buffer.length()); + buffer.append(selected); + column = startColumn + buffer.length(); + } break; case EXIT: if (buffer.toString().isEmpty()) { @@ -565,7 +582,7 @@ String selectCandidate(int buffRow, String buffer, int row, int column, List buffRow + 1) { row--; } else { - row = buffRow + candidates.size() - 1; + row = buffRow + candidates.size(); } break; case EXIT: diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java index 0bebcefea..4b6ab6fe9 100644 --- a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java @@ -32,11 +32,17 @@ public class ConsolePrompt { public ConsolePrompt(Terminal terminal) { this(null, terminal, new UiConfig()); } + /** + * + * @param terminal the terminal. + * @param config ConsolePrompt cursor pointer and checkbox configuration + */ public ConsolePrompt(Terminal terminal, UiConfig config) { this(null, terminal, config); } /** * + * @param reader the lineReader. * @param terminal the terminal. * @param config ConsolePrompt cursor pointer and checkbox configuration */ @@ -44,6 +50,13 @@ public ConsolePrompt(LineReader reader, Terminal terminal, UiConfig config) { this.terminal = terminal; this.config = config; this.reader = reader; + if (reader != null) { + Map options = new HashMap<>(); + for (LineReader.Option option : LineReader.Option.values()) { + options.put(option, reader.isSet(option)); + } + config.setReaderOptions(options); + } } /** @@ -182,7 +195,7 @@ public static class UiConfig { private final AttributedString unavailable; private final StyleResolver resolver; private final ResourceBundle resourceBundle; - private Map completionOptions = new HashMap<>(); + private Map readerOptions = new HashMap<>(); public UiConfig() { this(null, null, null, null); @@ -230,12 +243,12 @@ public ResourceBundle resourceBundle() { return resourceBundle; } - public void setCompletionOptions(Map completionOptions) { - this.completionOptions = completionOptions; + protected void setReaderOptions(Map readerOptions) { + this.readerOptions = readerOptions; } - public Map completionOptions() { - return completionOptions; + public Map readerOptions() { + return readerOptions; } private static StyleResolver resolver(String style) { From df8945ede9a5a9fe945f8a0d7db2cb6274e6dc44 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 23 Jan 2024 13:39:55 +0100 Subject: [PATCH 112/115] move into subfolder --- .gitignore => console-ui/.gitignore | 0 .travis.yml => console-ui/.travis.yml | 0 LICENSE.txt => console-ui/LICENSE.txt | 0 README.md => console-ui/README.md | 0 _config.yml => console-ui/_config.yml | 0 build.gradle => console-ui/build.gradle | 0 {doc => console-ui/doc}/ConsoleUI-Logo-small.png | Bin {doc => console-ui/doc}/ConsoleUI-Logo.png | Bin {doc => console-ui/doc}/ConsoleUI-Logo.svg | 0 {doc => console-ui/doc}/howto.md | 0 .../doc}/screenshots/checkbox_prompt.png | Bin .../doc}/screenshots/confirmation_prompt.png | Bin .../doc}/screenshots/expandable_choice_prompt_1.png | Bin .../doc}/screenshots/expandable_choice_prompt_2.png | Bin .../doc}/screenshots/expandable_choice_prompt_3.png | Bin .../doc}/screenshots/input_prompt.png | Bin {doc => console-ui/doc}/screenshots/list_prompt.png | Bin gradle.properties => console-ui/gradle.properties | 0 .../gradle}/wrapper/gradle-wrapper.jar | Bin .../gradle}/wrapper/gradle-wrapper.properties | 0 gradlew => console-ui/gradlew | 0 gradlew.bat => console-ui/gradlew.bat | 0 settings.gradle => console-ui/settings.gradle | 0 .../main/java/de/codeshelf/consoleui/Basic.java | 0 .../elements/AbstractPromptableElement.java | 0 .../de/codeshelf/consoleui/elements/Checkbox.java | 0 .../codeshelf/consoleui/elements/ConfirmChoice.java | 0 .../consoleui/elements/ExpandableChoice.java | 0 .../de/codeshelf/consoleui/elements/InputValue.java | 0 .../de/codeshelf/consoleui/elements/ListChoice.java | 0 .../codeshelf/consoleui/elements/PageSizeType.java | 0 .../consoleui/elements/PromptableElementIF.java | 0 .../consoleui/elements/items/CheckboxItemIF.java | 0 .../consoleui/elements/items/ChoiceItemIF.java | 0 .../consoleui/elements/items/ConsoleUIItemIF.java | 0 .../consoleui/elements/items/ListItemIF.java | 0 .../consoleui/elements/items/impl/CheckboxItem.java | 0 .../consoleui/elements/items/impl/ChoiceItem.java | 0 .../consoleui/elements/items/impl/ListItem.java | 0 .../consoleui/elements/items/impl/Separator.java | 0 .../de/codeshelf/consoleui/examples/LongList.java | 0 .../codeshelf/consoleui/examples/SimpleExample.java | 0 .../codeshelf/consoleui/prompt/AbstractPrompt.java | 0 .../codeshelf/consoleui/prompt/CheckboxResult.java | 0 .../codeshelf/consoleui/prompt/ConfirmResult.java | 0 .../codeshelf/consoleui/prompt/ConsolePrompt.java | 0 .../consoleui/prompt/ExpandableChoiceResult.java | 0 .../de/codeshelf/consoleui/prompt/InputResult.java | 0 .../de/codeshelf/consoleui/prompt/ListResult.java | 0 .../de/codeshelf/consoleui/prompt/PromptIF.java | 0 .../consoleui/prompt/PromptResultItemIF.java | 0 .../prompt/builder/CheckboxItemBuilder.java | 0 .../prompt/builder/CheckboxPromptBuilder.java | 0 .../prompt/builder/CheckboxSeperatorBuilder.java | 0 .../prompt/builder/ConfirmPromptBuilder.java | 0 .../prompt/builder/ExpandableChoiceItemBuilder.java | 0 .../builder/ExpandableChoicePromptBuilder.java | 0 .../builder/ExpandableChoiceSeparatorBuilder.java | 0 .../consoleui/prompt/builder/InputValueBuilder.java | 0 .../consoleui/prompt/builder/ListItemBuilder.java | 0 .../consoleui/prompt/builder/ListPromptBuilder.java | 0 .../consoleui/prompt/builder/PromptBuilder.java | 0 .../java/de/codeshelf/consoleui/util/BuilderIF.java | 0 .../main/resources/consoleui_messages.properties | 0 .../resources/consoleui_messages_de_DE.properties | 0 .../consoleui/prompt/CheckboxPromptTest.java | 0 .../prompt/ExpandableChoicePromptTest.java | 0 .../consoleui/prompt/PromptBuilderTest.java | 0 68 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => console-ui/.gitignore (100%) rename .travis.yml => console-ui/.travis.yml (100%) rename LICENSE.txt => console-ui/LICENSE.txt (100%) rename README.md => console-ui/README.md (100%) rename _config.yml => console-ui/_config.yml (100%) rename build.gradle => console-ui/build.gradle (100%) rename {doc => console-ui/doc}/ConsoleUI-Logo-small.png (100%) rename {doc => console-ui/doc}/ConsoleUI-Logo.png (100%) rename {doc => console-ui/doc}/ConsoleUI-Logo.svg (100%) rename {doc => console-ui/doc}/howto.md (100%) rename {doc => console-ui/doc}/screenshots/checkbox_prompt.png (100%) rename {doc => console-ui/doc}/screenshots/confirmation_prompt.png (100%) rename {doc => console-ui/doc}/screenshots/expandable_choice_prompt_1.png (100%) rename {doc => console-ui/doc}/screenshots/expandable_choice_prompt_2.png (100%) rename {doc => console-ui/doc}/screenshots/expandable_choice_prompt_3.png (100%) rename {doc => console-ui/doc}/screenshots/input_prompt.png (100%) rename {doc => console-ui/doc}/screenshots/list_prompt.png (100%) rename gradle.properties => console-ui/gradle.properties (100%) rename {gradle => console-ui/gradle}/wrapper/gradle-wrapper.jar (100%) rename {gradle => console-ui/gradle}/wrapper/gradle-wrapper.properties (100%) rename gradlew => console-ui/gradlew (100%) rename gradlew.bat => console-ui/gradlew.bat (100%) rename settings.gradle => console-ui/settings.gradle (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/Basic.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/Checkbox.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/InputValue.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/ListChoice.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/PageSizeType.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/examples/LongList.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/examples/SimpleExample.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/InputResult.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/ListResult.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/PromptIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java (100%) rename {src => console-ui/src}/main/java/de/codeshelf/consoleui/util/BuilderIF.java (100%) rename {src => console-ui/src}/main/resources/consoleui_messages.properties (100%) rename {src => console-ui/src}/main/resources/consoleui_messages_de_DE.properties (100%) rename {src => console-ui/src}/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java (100%) rename {src => console-ui/src}/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java (100%) rename {src => console-ui/src}/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java (100%) diff --git a/.gitignore b/console-ui/.gitignore similarity index 100% rename from .gitignore rename to console-ui/.gitignore diff --git a/.travis.yml b/console-ui/.travis.yml similarity index 100% rename from .travis.yml rename to console-ui/.travis.yml diff --git a/LICENSE.txt b/console-ui/LICENSE.txt similarity index 100% rename from LICENSE.txt rename to console-ui/LICENSE.txt diff --git a/README.md b/console-ui/README.md similarity index 100% rename from README.md rename to console-ui/README.md diff --git a/_config.yml b/console-ui/_config.yml similarity index 100% rename from _config.yml rename to console-ui/_config.yml diff --git a/build.gradle b/console-ui/build.gradle similarity index 100% rename from build.gradle rename to console-ui/build.gradle diff --git a/doc/ConsoleUI-Logo-small.png b/console-ui/doc/ConsoleUI-Logo-small.png similarity index 100% rename from doc/ConsoleUI-Logo-small.png rename to console-ui/doc/ConsoleUI-Logo-small.png diff --git a/doc/ConsoleUI-Logo.png b/console-ui/doc/ConsoleUI-Logo.png similarity index 100% rename from doc/ConsoleUI-Logo.png rename to console-ui/doc/ConsoleUI-Logo.png diff --git a/doc/ConsoleUI-Logo.svg b/console-ui/doc/ConsoleUI-Logo.svg similarity index 100% rename from doc/ConsoleUI-Logo.svg rename to console-ui/doc/ConsoleUI-Logo.svg diff --git a/doc/howto.md b/console-ui/doc/howto.md similarity index 100% rename from doc/howto.md rename to console-ui/doc/howto.md diff --git a/doc/screenshots/checkbox_prompt.png b/console-ui/doc/screenshots/checkbox_prompt.png similarity index 100% rename from doc/screenshots/checkbox_prompt.png rename to console-ui/doc/screenshots/checkbox_prompt.png diff --git a/doc/screenshots/confirmation_prompt.png b/console-ui/doc/screenshots/confirmation_prompt.png similarity index 100% rename from doc/screenshots/confirmation_prompt.png rename to console-ui/doc/screenshots/confirmation_prompt.png diff --git a/doc/screenshots/expandable_choice_prompt_1.png b/console-ui/doc/screenshots/expandable_choice_prompt_1.png similarity index 100% rename from doc/screenshots/expandable_choice_prompt_1.png rename to console-ui/doc/screenshots/expandable_choice_prompt_1.png diff --git a/doc/screenshots/expandable_choice_prompt_2.png b/console-ui/doc/screenshots/expandable_choice_prompt_2.png similarity index 100% rename from doc/screenshots/expandable_choice_prompt_2.png rename to console-ui/doc/screenshots/expandable_choice_prompt_2.png diff --git a/doc/screenshots/expandable_choice_prompt_3.png b/console-ui/doc/screenshots/expandable_choice_prompt_3.png similarity index 100% rename from doc/screenshots/expandable_choice_prompt_3.png rename to console-ui/doc/screenshots/expandable_choice_prompt_3.png diff --git a/doc/screenshots/input_prompt.png b/console-ui/doc/screenshots/input_prompt.png similarity index 100% rename from doc/screenshots/input_prompt.png rename to console-ui/doc/screenshots/input_prompt.png diff --git a/doc/screenshots/list_prompt.png b/console-ui/doc/screenshots/list_prompt.png similarity index 100% rename from doc/screenshots/list_prompt.png rename to console-ui/doc/screenshots/list_prompt.png diff --git a/gradle.properties b/console-ui/gradle.properties similarity index 100% rename from gradle.properties rename to console-ui/gradle.properties diff --git a/gradle/wrapper/gradle-wrapper.jar b/console-ui/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from gradle/wrapper/gradle-wrapper.jar rename to console-ui/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/console-ui/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from gradle/wrapper/gradle-wrapper.properties rename to console-ui/gradle/wrapper/gradle-wrapper.properties diff --git a/gradlew b/console-ui/gradlew similarity index 100% rename from gradlew rename to console-ui/gradlew diff --git a/gradlew.bat b/console-ui/gradlew.bat similarity index 100% rename from gradlew.bat rename to console-ui/gradlew.bat diff --git a/settings.gradle b/console-ui/settings.gradle similarity index 100% rename from settings.gradle rename to console-ui/settings.gradle diff --git a/src/main/java/de/codeshelf/consoleui/Basic.java b/console-ui/src/main/java/de/codeshelf/consoleui/Basic.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/Basic.java rename to console-ui/src/main/java/de/codeshelf/consoleui/Basic.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/Checkbox.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/InputValue.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/InputValue.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/InputValue.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/ListChoice.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java diff --git a/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java b/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java rename to console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java diff --git a/src/main/java/de/codeshelf/consoleui/examples/LongList.java b/console-ui/src/main/java/de/codeshelf/consoleui/examples/LongList.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/examples/LongList.java rename to console-ui/src/main/java/de/codeshelf/consoleui/examples/LongList.java diff --git a/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java b/console-ui/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java rename to console-ui/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/InputResult.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/ListResult.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java b/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java rename to console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java diff --git a/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java b/console-ui/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java similarity index 100% rename from src/main/java/de/codeshelf/consoleui/util/BuilderIF.java rename to console-ui/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java diff --git a/src/main/resources/consoleui_messages.properties b/console-ui/src/main/resources/consoleui_messages.properties similarity index 100% rename from src/main/resources/consoleui_messages.properties rename to console-ui/src/main/resources/consoleui_messages.properties diff --git a/src/main/resources/consoleui_messages_de_DE.properties b/console-ui/src/main/resources/consoleui_messages_de_DE.properties similarity index 100% rename from src/main/resources/consoleui_messages_de_DE.properties rename to console-ui/src/main/resources/consoleui_messages_de_DE.properties diff --git a/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/console-ui/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java similarity index 100% rename from src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java rename to console-ui/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java diff --git a/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java b/console-ui/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java similarity index 100% rename from src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java rename to console-ui/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java diff --git a/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/console-ui/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java similarity index 100% rename from src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java rename to console-ui/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java From 2f162bc429093ab28521d83bc0990030b98aa395 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 23 Jan 2024 13:45:17 +0100 Subject: [PATCH 113/115] Rename package --- .../jline}/consoleui/Basic.java | 17 +++---- .../elements/AbstractPromptableElement.java | 2 +- .../jline}/consoleui/elements/Checkbox.java | 4 +- .../consoleui/elements/ConfirmChoice.java | 2 +- .../consoleui/elements/ExpandableChoice.java | 5 +- .../jline}/consoleui/elements/InputValue.java | 2 +- .../jline}/consoleui/elements/ListChoice.java | 5 +- .../consoleui/elements/PageSizeType.java | 2 +- .../elements/PromptableElementIF.java | 2 +- .../elements/items/CheckboxItemIF.java | 2 +- .../elements/items/ChoiceItemIF.java | 2 +- .../elements/items/ConsoleUIItemIF.java | 2 +- .../consoleui/elements/items/ListItemIF.java | 2 +- .../elements/items/impl/CheckboxItem.java | 6 +-- .../elements/items/impl/ChoiceItem.java | 4 +- .../elements/items/impl/ListItem.java | 4 +- .../elements/items/impl/Separator.java | 8 +-- .../jline}/consoleui/examples/LongList.java | 16 +++--- .../consoleui/examples/SimpleExample.java | 8 +-- .../consoleui/prompt/AbstractPrompt.java | 51 +++++++++---------- .../consoleui/prompt/CheckboxResult.java | 2 +- .../consoleui/prompt/ConfirmResult.java | 4 +- .../consoleui/prompt/ConsolePrompt.java | 11 ++-- .../prompt/ExpandableChoiceResult.java | 2 +- .../jline}/consoleui/prompt/InputResult.java | 2 +- .../jline}/consoleui/prompt/ListResult.java | 2 +- .../jline}/consoleui/prompt/PromptIF.java | 4 +- .../consoleui/prompt/PromptResultItemIF.java | 2 +- .../prompt/builder/CheckboxItemBuilder.java | 6 +-- .../prompt/builder/CheckboxPromptBuilder.java | 8 +-- .../builder/CheckboxSeperatorBuilder.java | 4 +- .../prompt/builder/ConfirmPromptBuilder.java | 4 +- .../builder/ExpandableChoiceItemBuilder.java | 4 +- .../ExpandableChoicePromptBuilder.java | 6 +-- .../ExpandableChoiceSeparatorBuilder.java | 4 +- .../prompt/builder/InputValueBuilder.java | 4 +- .../prompt/builder/ListItemBuilder.java | 4 +- .../prompt/builder/ListPromptBuilder.java | 10 ++-- .../prompt/builder/PromptBuilder.java | 3 +- .../jline}/consoleui/util/BuilderIF.java | 2 +- .../consoleui/prompt/CheckboxPromptTest.java | 8 +-- .../prompt/ExpandableChoicePromptTest.java | 2 +- .../consoleui/prompt/PromptBuilderTest.java | 9 ++-- 43 files changed, 126 insertions(+), 127 deletions(-) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/Basic.java (92%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/AbstractPromptableElement.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/Checkbox.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/ConfirmChoice.java (93%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/ExpandableChoice.java (74%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/InputValue.java (96%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/ListChoice.java (86%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/PageSizeType.java (55%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/PromptableElementIF.java (76%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/CheckboxItemIF.java (78%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/ChoiceItemIF.java (84%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/ConsoleUIItemIF.java (85%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/ListItemIF.java (69%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/impl/CheckboxItem.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/impl/ChoiceItem.java (87%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/impl/ListItem.java (85%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/elements/items/impl/Separator.java (67%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/examples/LongList.java (84%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/examples/SimpleExample.java (86%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/AbstractPrompt.java (95%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/CheckboxResult.java (95%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/ConfirmResult.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/ConsolePrompt.java (97%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/ExpandableChoiceResult.java (95%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/InputResult.java (91%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/ListResult.java (94%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/PromptIF.java (82%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/PromptResultItemIF.java (74%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/CheckboxItemBuilder.java (87%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/CheckboxPromptBuilder.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/CheckboxSeperatorBuilder.java (83%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/ConfirmPromptBuilder.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java (86%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/InputValueBuilder.java (92%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/ListItemBuilder.java (84%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/ListPromptBuilder.java (86%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/prompt/builder/PromptBuilder.java (90%) rename console-ui/src/main/java/{de/codeshelf => org/jline}/consoleui/util/BuilderIF.java (72%) rename console-ui/src/test/java/{de/codeshelf => org/jline}/consoleui/prompt/CheckboxPromptTest.java (73%) rename console-ui/src/test/java/{de/codeshelf => org/jline}/consoleui/prompt/ExpandableChoicePromptTest.java (84%) rename console-ui/src/test/java/{de/codeshelf => org/jline}/consoleui/prompt/PromptBuilderTest.java (91%) diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/Basic.java b/console-ui/src/main/java/org/jline/consoleui/Basic.java similarity index 92% rename from console-ui/src/main/java/de/codeshelf/consoleui/Basic.java rename to console-ui/src/main/java/org/jline/consoleui/Basic.java index 1c5405402..75f9effde 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/Basic.java +++ b/console-ui/src/main/java/org/jline/consoleui/Basic.java @@ -1,15 +1,14 @@ -package de.codeshelf.consoleui; - -import de.codeshelf.consoleui.elements.ConfirmChoice; -import de.codeshelf.consoleui.prompt.ConfirmResult; -import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; -import de.codeshelf.consoleui.prompt.PromptResultItemIF; -import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +package org.jline.consoleui; + +import org.jline.consoleui.elements.ConfirmChoice; +import org.jline.consoleui.prompt.ConfirmResult; +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.ConsolePrompt.UiConfig; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.PromptBuilder; import org.jline.builtins.Completers; import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; -import org.jline.reader.impl.completer.StringsCompleter; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.utils.AttributedString; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java b/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java rename to console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java index 033dbef4b..4af69bdd6 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/AbstractPromptableElement.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java b/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java rename to console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java index 285197a0b..271b7903d 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/Checkbox.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.items.CheckboxItemIF; import java.util.ArrayList; import java.util.List; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java similarity index 93% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java rename to console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java index 861f059f8..05e9efc2e 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/ConfirmChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java similarity index 74% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java rename to console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java index 8ed6d9fe6..c5e53b7aa 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/ExpandableChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java @@ -1,7 +1,6 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.consoleui.elements.items.ChoiceItemIF; import java.util.ArrayList; import java.util.LinkedHashSet; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/InputValue.java b/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java similarity index 96% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/InputValue.java rename to console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java index 91975d056..2ed4a4843 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/InputValue.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; import org.jline.reader.Completer; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java similarity index 86% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java rename to console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java index d4ced2b8d..4e113cce2 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/ListChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java @@ -1,7 +1,6 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; +import org.jline.consoleui.elements.items.ListItemIF; import java.util.ArrayList; import java.util.List; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java b/console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java similarity index 55% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java rename to console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java index e7b3df971..6a32a380a 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/PageSizeType.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; public enum PageSizeType { RELATIVE, ABSOLUTE } diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java similarity index 76% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java rename to console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java index d4265a231..190370ba8 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/PromptableElementIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements; +package org.jline.consoleui.elements; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java similarity index 78% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java index dd5855af7..9f6d9fe98 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/CheckboxItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements.items; +package org.jline.consoleui.elements.items; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java similarity index 84% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java index c50c86d52..f987e10dd 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ChoiceItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements.items; +package org.jline.consoleui.elements.items; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java similarity index 85% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java index 942fe3c8e..97c2d3614 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ConsoleUIItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements.items; +package org.jline.consoleui.elements.items; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java similarity index 69% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java index e38e5fc6a..4dde51b30 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/ListItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.elements.items; +package org.jline.consoleui.elements.items; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java index 2ff0260cf..6c151d2dc 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/CheckboxItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java @@ -1,7 +1,7 @@ -package de.codeshelf.consoleui.elements.items.impl; +package org.jline.consoleui.elements.items.impl; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.items.ConsoleUIItemIF; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java similarity index 87% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java index e965b9930..f51c86fc2 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ChoiceItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.elements.items.impl; +package org.jline.consoleui.elements.items.impl; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; +import org.jline.consoleui.elements.items.ChoiceItemIF; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java similarity index 85% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java index 059f8af2a..285e05e43 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/ListItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.elements.items.impl; +package org.jline.consoleui.elements.items.impl; -import de.codeshelf.consoleui.elements.items.ListItemIF; +import org.jline.consoleui.elements.items.ListItemIF; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java similarity index 67% rename from console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java rename to console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java index b21aa8b49..1a0f79048 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/elements/items/impl/Separator.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java @@ -1,8 +1,8 @@ -package de.codeshelf.consoleui.elements.items.impl; +package org.jline.consoleui.elements.items.impl; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; +import org.jline.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.items.ChoiceItemIF; +import org.jline.consoleui.elements.items.ListItemIF; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/examples/LongList.java b/console-ui/src/main/java/org/jline/consoleui/examples/LongList.java similarity index 84% rename from console-ui/src/main/java/de/codeshelf/consoleui/examples/LongList.java rename to console-ui/src/main/java/org/jline/consoleui/examples/LongList.java index 1723e61ec..b5eccc9c5 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/examples/LongList.java +++ b/console-ui/src/main/java/org/jline/consoleui/examples/LongList.java @@ -1,11 +1,11 @@ -package de.codeshelf.consoleui.examples; - -import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; -import de.codeshelf.consoleui.prompt.PromptResultItemIF; -import de.codeshelf.consoleui.prompt.builder.CheckboxPromptBuilder; -import de.codeshelf.consoleui.prompt.builder.ListPromptBuilder; -import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +package org.jline.consoleui.examples; + +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.ConsolePrompt.UiConfig; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.CheckboxPromptBuilder; +import org.jline.consoleui.prompt.builder.ListPromptBuilder; +import org.jline.consoleui.prompt.builder.PromptBuilder; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.utils.AttributedString; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java b/console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java similarity index 86% rename from console-ui/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java rename to console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java index 69c8a4f8b..22b627b2c 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/examples/SimpleExample.java +++ b/console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java @@ -1,8 +1,8 @@ -package de.codeshelf.consoleui.examples; +package org.jline.consoleui.examples; -import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.PromptResultItemIF; -import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.PromptBuilder; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.utils.AttributedString; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java b/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java similarity index 95% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java index f8132e368..ba684152c 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/AbstractPrompt.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java @@ -1,17 +1,16 @@ -package de.codeshelf.consoleui.prompt; - -import de.codeshelf.consoleui.elements.Checkbox; -import de.codeshelf.consoleui.elements.ConfirmChoice; -import de.codeshelf.consoleui.elements.ExpandableChoice; -import de.codeshelf.consoleui.elements.InputValue; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; -import de.codeshelf.consoleui.elements.items.ListItemIF; -import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; -import de.codeshelf.consoleui.elements.items.impl.Separator; -import de.codeshelf.consoleui.prompt.ConsolePrompt.UiConfig; +package org.jline.consoleui.prompt; + +import org.jline.consoleui.elements.Checkbox; +import org.jline.consoleui.elements.ConfirmChoice; +import org.jline.consoleui.elements.ExpandableChoice; +import org.jline.consoleui.elements.InputValue; +import org.jline.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.items.ChoiceItemIF; +import org.jline.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.consoleui.elements.items.ListItemIF; +import org.jline.consoleui.elements.items.impl.CheckboxItem; +import org.jline.consoleui.elements.items.impl.ChoiceItem; +import org.jline.consoleui.elements.items.impl.Separator; import org.jline.keymap.BindingReader; import org.jline.keymap.KeyMap; import org.jline.reader.*; @@ -291,10 +290,10 @@ protected static class ExpandableChoicePrompt extends AbstractPrompt private enum Operation {INSERT, EXIT} private final int startColumn; private final List items; - private final UiConfig config; + private final ConsolePrompt.UiConfig config; private ExpandableChoicePrompt(Terminal terminal, List header, AttributedString message - , ExpandableChoice expandableChoice, UiConfig cfg) { + , ExpandableChoice expandableChoice, ConsolePrompt.UiConfig cfg) { super(terminal, header, message, cfg); startColumn = message.columnLength(); items = expandableChoice.getChoiceItems(); @@ -302,7 +301,7 @@ private ExpandableChoicePrompt(Terminal terminal, List header, } public static ExpandableChoicePrompt getPrompt(Terminal terminal, List header, AttributedString message - , ExpandableChoice expandableChoice, UiConfig cfg) { + , ExpandableChoice expandableChoice, ConsolePrompt.UiConfig cfg) { return new ExpandableChoicePrompt(terminal, header, message, expandableChoice, cfg); } @@ -376,10 +375,10 @@ protected static class ConfirmPrompt extends AbstractPrompt { private enum Operation {NO, YES, EXIT} private final int startColumn; private final ConfirmChoice.ConfirmationValue defaultValue; - private final UiConfig config; + private final ConsolePrompt.UiConfig config; private ConfirmPrompt(Terminal terminal, List header, AttributedString message - , ConfirmChoice confirmChoice, UiConfig cfg) { + , ConfirmChoice confirmChoice, ConsolePrompt.UiConfig cfg) { super(terminal, header, message, cfg); startColumn = message.columnLength(); defaultValue = confirmChoice.getDefaultConfirmation(); @@ -387,7 +386,7 @@ private ConfirmPrompt(Terminal terminal, List header, Attribut } public static ConfirmPrompt getPrompt(Terminal terminal, List header, AttributedString message - , ConfirmChoice confirmChoice, UiConfig cfg) { + , ConfirmChoice confirmChoice, ConsolePrompt.UiConfig cfg) { return new ConfirmPrompt(terminal, header, message, confirmChoice, cfg); } @@ -443,7 +442,7 @@ private enum SelectOp {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, EXIT} private final Completer completer; private InputValuePrompt(LineReader reader, Terminal terminal, List header, AttributedString message - , InputValue inputValue, UiConfig cfg) { + , InputValue inputValue, ConsolePrompt.UiConfig cfg) { super(terminal, header, message, cfg); this.reader = reader; defaultValue = inputValue.getDefaultValue(); @@ -453,7 +452,7 @@ private InputValuePrompt(LineReader reader, Terminal terminal, List header, AttributedString message - , InputValue inputValue, UiConfig cfg) { + , InputValue inputValue, ConsolePrompt.UiConfig cfg) { return new InputValuePrompt(reader, terminal, header, message, inputValue, cfg); } @@ -673,13 +672,13 @@ private enum Operation {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, INSERT, EXIT} private final List items; private ListChoicePrompt(Terminal terminal, List header, AttributedString message - , List listItems, UiConfig cfg) { + , List listItems, ConsolePrompt.UiConfig cfg) { super(terminal, header, message, listItems, cfg); items = listItems; } public static ListChoicePrompt getPrompt(Terminal terminal, List header - , AttributedString message, List listItems, UiConfig cfg) { + , AttributedString message, List listItems, ConsolePrompt.UiConfig cfg) { return new ListChoicePrompt<>(terminal, header, message, listItems, cfg); } @@ -735,13 +734,13 @@ private enum Operation {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, TOGGLE, EXIT} private final List items; private CheckboxPrompt(Terminal terminal, List header, AttributedString message - , Checkbox checkbox, UiConfig cfg) { + , Checkbox checkbox, ConsolePrompt.UiConfig cfg) { super(terminal, header, message, checkbox.getCheckboxItemList(), cfg); items = checkbox.getCheckboxItemList(); } public static CheckboxPrompt getPrompt(Terminal terminal, List header, AttributedString message - , Checkbox checkbox, UiConfig cfg) { + , Checkbox checkbox, ConsolePrompt.UiConfig cfg) { return new CheckboxPrompt(terminal, header, message, checkbox, cfg); } diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java similarity index 95% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java index 6903627f6..dc11977e0 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/CheckboxResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; import java.util.Set; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java index 5c0da59e2..243305a04 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConfirmResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; -import de.codeshelf.consoleui.elements.ConfirmChoice; +import org.jline.consoleui.elements.ConfirmChoice; /** * Result of a confirmation choice. Holds a single value of 'yes' or 'no' diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java similarity index 97% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java index 4b6ab6fe9..2a7c9527e 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ConsolePrompt.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java @@ -1,11 +1,12 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; import de.codeshelf.consoleui.elements.*; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; -import de.codeshelf.consoleui.prompt.AbstractPrompt.*; -import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import org.jline.consoleui.elements.items.impl.ChoiceItem; +import org.jline.consoleui.prompt.AbstractPrompt.*; +import org.jline.consoleui.prompt.builder.PromptBuilder; import org.jline.builtins.Styles; -import de.codeshelf.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.consoleui.elements.items.ConsoleUIItemIF; +import org.jline.consoleui.elements.*; import org.jline.reader.LineReader; import org.jline.terminal.Attributes; import org.jline.terminal.Terminal; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java similarity index 95% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java index 9532a4067..655f63a77 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ExpandableChoiceResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; /** * Result of a an expandable choice. ExpandableChoiceResult contains a String with the diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java similarity index 91% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java index 3b6bf9230..91dc5fb58 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/InputResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; /** * diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java similarity index 94% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java index 679eba4aa..93ba662f3 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/ListResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; /** * Result of a list choice. Holds the id of the selected item. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java similarity index 82% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java index 01844fae8..e2a78657f 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; -import de.codeshelf.consoleui.elements.PromptableElementIF; +import org.jline.consoleui.elements.PromptableElementIF; import java.io.IOException; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java similarity index 74% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java index dc1dac15d..21c594697 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/PromptResultItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; /** * Created by Andreas Wegmann on 03.02.16. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java similarity index 87% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java index f8b3f7d6f..d83876e33 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java @@ -1,7 +1,7 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; +import org.jline.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.items.impl.CheckboxItem; /** * Created by andy on 22.01.16. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java index c41970150..4609072f0 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java @@ -1,8 +1,8 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.Checkbox; -import de.codeshelf.consoleui.elements.PageSizeType; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.Checkbox; +import org.jline.consoleui.elements.PageSizeType; +import org.jline.consoleui.elements.items.CheckboxItemIF; import java.util.ArrayList; import java.util.List; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java similarity index 83% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java index 1e98e1b53..cfa4885ed 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/CheckboxSeperatorBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.items.impl.Separator; +import org.jline.consoleui.elements.items.impl.Separator; /** * Created by andy on 22.01.16. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java index b5a464c07..f603322d5 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ConfirmPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.ConfirmChoice; +import org.jline.consoleui.elements.ConfirmChoice; /** * User: Andreas Wegmann diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java index 297d18731..9248ab733 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.items.impl.ChoiceItem; +import org.jline.consoleui.elements.items.impl.ChoiceItem; /** * Created by andy on 22.01.16. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java index 541b2bb61..bdaa31382 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java @@ -1,7 +1,7 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.ExpandableChoice; -import de.codeshelf.consoleui.elements.items.ChoiceItemIF; +import org.jline.consoleui.elements.ExpandableChoice; +import org.jline.consoleui.elements.items.ChoiceItemIF; import java.util.ArrayList; import java.util.List; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java similarity index 86% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java index 5bb6beb5d..5a6409ee6 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.items.impl.Separator; +import org.jline.consoleui.elements.items.impl.Separator; /** * Created by andy on 22.01.16. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java similarity index 92% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java index 01fbb8949..7078c0c0f 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/InputValueBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.InputValue; +import org.jline.consoleui.elements.InputValue; import org.jline.reader.Completer; /** diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java similarity index 84% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java index 5239d98ce..81b292995 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java @@ -1,6 +1,6 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.items.impl.ListItem; +import org.jline.consoleui.elements.items.impl.ListItem; /** * Created by andy on 22.01.16. diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java similarity index 86% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java index 5fd0da599..751d5b3fb 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/ListPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java @@ -1,9 +1,9 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.ListChoice; -import de.codeshelf.consoleui.elements.items.ListItemIF; -import de.codeshelf.consoleui.elements.items.impl.ListItem; -import de.codeshelf.consoleui.elements.PageSizeType; +import org.jline.consoleui.elements.ListChoice; +import org.jline.consoleui.elements.items.ListItemIF; +import org.jline.consoleui.elements.items.impl.ListItem; +import org.jline.consoleui.elements.PageSizeType; import java.util.ArrayList; import java.util.List; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java similarity index 90% rename from console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java rename to console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java index 69b6eb94b..e7c51e26f 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/prompt/builder/PromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java @@ -1,6 +1,7 @@ -package de.codeshelf.consoleui.prompt.builder; +package org.jline.consoleui.prompt.builder; import de.codeshelf.consoleui.elements.*; +import org.jline.consoleui.elements.PromptableElementIF; import java.util.ArrayList; import java.util.List; diff --git a/console-ui/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java b/console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java similarity index 72% rename from console-ui/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java rename to console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java index dda6a57dc..873965782 100644 --- a/console-ui/src/main/java/de/codeshelf/consoleui/util/BuilderIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.util; +package org.jline.consoleui.util; /** * User: Andreas Wegmann diff --git a/console-ui/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java similarity index 73% rename from console-ui/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java rename to console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java index ab3e641a4..7b7bb70fc 100644 --- a/console-ui/src/test/java/de/codeshelf/consoleui/prompt/CheckboxPromptTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java @@ -1,8 +1,8 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; -import de.codeshelf.consoleui.elements.items.CheckboxItemIF; -import de.codeshelf.consoleui.elements.items.impl.CheckboxItem; -import de.codeshelf.consoleui.elements.items.impl.Separator; +import org.jline.consoleui.elements.items.CheckboxItemIF; +import org.jline.consoleui.elements.items.impl.CheckboxItem; +import org.jline.consoleui.elements.items.impl.Separator; import org.junit.Test; import java.io.IOException; diff --git a/console-ui/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java similarity index 84% rename from console-ui/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java rename to console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java index acae056d4..99840fc09 100644 --- a/console-ui/src/test/java/de/codeshelf/consoleui/prompt/ExpandableChoicePromptTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java @@ -1,4 +1,4 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; import org.junit.Test; diff --git a/console-ui/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java similarity index 91% rename from console-ui/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java rename to console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java index 651b14d79..0819381f7 100644 --- a/console-ui/src/test/java/de/codeshelf/consoleui/prompt/PromptBuilderTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java @@ -1,8 +1,9 @@ -package de.codeshelf.consoleui.prompt; +package org.jline.consoleui.prompt; -import de.codeshelf.consoleui.elements.ConfirmChoice; -import de.codeshelf.consoleui.elements.PromptableElementIF; -import de.codeshelf.consoleui.prompt.builder.PromptBuilder; +import org.jline.consoleui.elements.ConfirmChoice; +import org.jline.consoleui.elements.PromptableElementIF; +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.builder.PromptBuilder; import org.jline.terminal.TerminalBuilder; import org.junit.Test; From e5a491a5f71d8ae443ce89150fd2487eb5b9ecde Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 23 Jan 2024 13:46:24 +0100 Subject: [PATCH 114/115] Prepare merge --- console-ui/.gitignore | 11 - console-ui/.travis.yml | 1 - console-ui/README.md | 41 +- console-ui/_config.yml | 1 - console-ui/build.gradle | 110 -- console-ui/doc/howto.md | 101 +- console-ui/gradle.properties | 4 - console-ui/gradle/wrapper/gradle-wrapper.jar | Bin 52141 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - console-ui/gradlew | 164 -- console-ui/gradlew.bat | 90 - console-ui/jline-console-ui.bat | 64 + console-ui/jline-console-ui.sh | 84 + console-ui/pom.xml | 47 + console-ui/settings.gradle | 2 - .../main/java/org/jline/consoleui/Basic.java | 135 -- .../elements/AbstractPromptableElement.java | 32 +- .../jline/consoleui/elements/Checkbox.java | 77 +- .../consoleui/elements/ConfirmChoice.java | 35 +- .../consoleui/elements/ExpandableChoice.java | 30 +- .../jline/consoleui/elements/InputValue.java | 93 +- .../jline/consoleui/elements/ListChoice.java | 60 +- .../consoleui/elements/PageSizeType.java | 14 +- .../elements/PromptableElementIF.java | 13 +- .../elements/items/CheckboxItemIF.java | 8 + .../elements/items/ChoiceItemIF.java | 8 + .../elements/items/ConsoleUIItemIF.java | 26 +- .../consoleui/elements/items/ListItemIF.java | 11 +- .../elements/items/impl/CheckboxItem.java | 166 +- .../elements/items/impl/ChoiceItem.java | 78 +- .../elements/items/impl/ListItem.java | 64 +- .../elements/items/impl/Separator.java | 46 +- .../jline/consoleui/examples/LongList.java | 61 - .../consoleui/examples/SimpleExample.java | 45 - .../consoleui/prompt/AbstractPrompt.java | 1476 +++++++++-------- .../consoleui/prompt/CheckboxResult.java | 56 +- .../jline/consoleui/prompt/ConfirmResult.java | 56 +- .../jline/consoleui/prompt/ConsolePrompt.java | 458 ++--- .../prompt/ExpandableChoiceResult.java | 60 +- .../jline/consoleui/prompt/InputResult.java | 38 +- .../jline/consoleui/prompt/ListResult.java | 58 +- .../org/jline/consoleui/prompt/PromptIF.java | 22 - .../consoleui/prompt/PromptResultItemIF.java | 8 + .../prompt/builder/CheckboxItemBuilder.java | 94 +- .../prompt/builder/CheckboxPromptBuilder.java | 130 +- .../builder/CheckboxSeparatorBuilder.java | 35 + .../builder/CheckboxSeperatorBuilder.java | 27 - .../prompt/builder/ConfirmPromptBuilder.java | 62 +- .../builder/ExpandableChoiceItemBuilder.java | 78 +- .../ExpandableChoicePromptBuilder.java | 111 +- .../ExpandableChoiceSeparatorBuilder.java | 36 +- .../prompt/builder/InputValueBuilder.java | 98 +- .../prompt/builder/ListItemBuilder.java | 44 +- .../prompt/builder/ListPromptBuilder.java | 113 +- .../prompt/builder/PromptBuilder.java | 58 +- .../org/jline/consoleui/util/BuilderIF.java | 9 - .../org/jline/consoleui/examples/Basic.java | 185 +++ .../jline/consoleui/examples/LongList.java | 72 + .../consoleui/examples/SimpleExample.java | 62 + .../consoleui/prompt/CheckboxPromptTest.java | 45 +- .../prompt/ExpandableChoicePromptTest.java | 21 +- .../consoleui/prompt/PromptBuilderTest.java | 197 ++- 62 files changed, 2856 insertions(+), 2581 deletions(-) delete mode 100644 console-ui/.gitignore delete mode 100644 console-ui/.travis.yml delete mode 100644 console-ui/_config.yml delete mode 100644 console-ui/build.gradle delete mode 100644 console-ui/gradle.properties delete mode 100644 console-ui/gradle/wrapper/gradle-wrapper.jar delete mode 100644 console-ui/gradle/wrapper/gradle-wrapper.properties delete mode 100755 console-ui/gradlew delete mode 100644 console-ui/gradlew.bat create mode 100644 console-ui/jline-console-ui.bat create mode 100755 console-ui/jline-console-ui.sh create mode 100644 console-ui/pom.xml delete mode 100644 console-ui/settings.gradle delete mode 100644 console-ui/src/main/java/org/jline/consoleui/Basic.java delete mode 100644 console-ui/src/main/java/org/jline/consoleui/examples/LongList.java delete mode 100644 console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java delete mode 100644 console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java create mode 100644 console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java delete mode 100644 console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java delete mode 100644 console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java create mode 100644 console-ui/src/test/java/org/jline/consoleui/examples/Basic.java create mode 100644 console-ui/src/test/java/org/jline/consoleui/examples/LongList.java create mode 100644 console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java diff --git a/console-ui/.gitignore b/console-ui/.gitignore deleted file mode 100644 index 3812bf94c..000000000 --- a/console-ui/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -/build -/bin -/.settings -/.gradle -/.classpath -/.project -/.idea -*.ipr -*.iws -/out -*iml diff --git a/console-ui/.travis.yml b/console-ui/.travis.yml deleted file mode 100644 index ec46ce71c..000000000 --- a/console-ui/.travis.yml +++ /dev/null @@ -1 +0,0 @@ -language: groovy diff --git a/console-ui/README.md b/console-ui/README.md index 09c41bab6..8325ccc19 100644 --- a/console-ui/README.md +++ b/console-ui/README.md @@ -1,21 +1,20 @@ ConsoleUI logo -[![Build Status](https://travis-ci.org/awegmann/consoleui.svg?branch=master)](https://travis-ci.org/awegmann/consoleui) - # ConsoleUI -[![Join the chat at https://gitter.im/awegmann/consoleui](https://badges.gitter.im/awegmann/consoleui.svg)](https://gitter.im/awegmann/consoleui?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - Tiny java library that provides simple UI elements on ANSI console based terminals. ConsoleUI is inspired by [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) which is written in JavaScript. +ConsoleUI has been initially implemented using JLine2 by Andreas Wegmann. After ConsoleUI has been upgraded to use JLine3 +it has been merged into JLine3. + # Intention I was impressed by JavaScript based Yeoman which leads the user through the process of creating new projects by querying with a simple user interface on the console. An investigation how this is done, brought me to Inquirer.js which implements a very simple and intuitive set of controls for checkbox, list and text input. -Because I didn't found anything comparable to this in the Java eco system, I decided to write `Console UI` +Because I didn't find anything comparable to this in the Java ecosystem, I decided to write `Console UI` as a library with the same easy 'look and feel'. Some parts of the API are also comparable, but Console UI is not a Java clone of Inquirer.js. @@ -29,33 +28,28 @@ a Java clone of Inquirer.js. - Expandable Choices (multiple key based answers for a question with help and optional list navigation) - Yes/No-Questions -A screen recording of the basic elements demo can be fund on Youtube [console UI demo](https://youtu.be/6dB3CyOX9rU). +A screen recording of the basic elements demo can be fund on YouTube [console UI demo](https://youtu.be/6dB3CyOX9rU). # Dependencies -Console UI uses jansi and jline for the dirty console things. +Console UI uses JLine for the dirty console things. # Maven artefact -ConsoleUI releases are available at Maven Central [de.codeshelf.consoleui » consoleui](https://search.maven.org/artifact/de.codeshelf.consoleui/consoleui) +ConsoleUI releases are available at Maven Central [org.jline.console-ui » console-ui](https://search.maven.org/artifact/org.jline.console-ui/console-ui) # Test Run -You can get an idea how the project works by looking at `de.codeshelf.consoleui.Basic`. +You can get an idea how the project works by looking at `org.jline.consoleui.examples.Basic`. You can run this by executing the following from the project root: - gradlew fatJar - java -jar build/libs/consoleui-all-0.0.10.jar # <- replace with the latest version + ./jline-console-ui.sh # Usage *Hint: see the [how to](doc/howto.md) to get a more detailed documentation how to use ConsoleUI.* -Before you can use ConsoleUI the AnsiConsole library has to be initialized. - - AnsiConsole.systemInstall(); - Entry point to the builder classes is to create a new object of type `ConsolePrompt`. ConsolePrompt prompt = new ConsolePrompt(); @@ -72,9 +66,9 @@ From with this `PromptBuilder` you can access UI builder with the following meth - createChoicePrompt() * creates a choice prompt. This prompt lets the user choose one from a given number of possible answers. - createConfirmPromp() - * creates a confirm prompt. This prompt lets the user answer with 'yes' or 'no' to a given question. + * creates a confirmation prompt. This prompt lets the user answer with 'yes' or 'no' to a given question. - createInputPrompt() - * creates a input prompt. This prompt is a classic entry line like a shell. Because of the underlying readline + * creates an input prompt. This prompt is a classic entry line like a shell. Because of the underlying readline implementation it offers you to provide completers (like file name completer or string completer). In addition to his, you can define a mask character which is printed on the screen instead of the typed keys like used for hidden password entry. @@ -82,18 +76,5 @@ From with this `PromptBuilder` you can access UI builder with the following meth * creates a list prompt. This prompt lets the user choose one item from a given list. -# Changes - -### Version 0.0.13 - -- Fixed bug #22: lists are not rendered correctly - -### Version 0.0.12 - -- Fixed Bug #20: Lists higher than the terminal height were not handled correctly. - ConsoleUI now supports scrolling for checkbox promt and list prompt. - To configure the height of the view port, either an absolute number of lines or a fraction (percentage) of the - screen height can be defined. - diff --git a/console-ui/_config.yml b/console-ui/_config.yml deleted file mode 100644 index c74188174..000000000 --- a/console-ui/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file diff --git a/console-ui/build.gradle b/console-ui/build.gradle deleted file mode 100644 index b46722ba4..000000000 --- a/console-ui/build.gradle +++ /dev/null @@ -1,110 +0,0 @@ -plugins { - id 'java-library' - id 'maven-publish' - id 'signing' -} - -project.group = "de.codeshelf.consoleui" -project.version = "0.0.13" - -java { - withJavadocJar() - withSourcesJar() -} - - -repositories { - mavenCentral() -} - -compileJava { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 -} - - -dependencies { - testCompile group: 'junit', name: 'junit', version: '4.11' - compile 'org.jline:jline:3.19.0' -} - -javadoc { - options.encoding = 'UTF-8' - if (JavaVersion.current().isJava9Compatible()) { - options.addBooleanOption('html5', true) - } -} - - -// Fat-jar -task fatJar(type: Jar, dependsOn: [':compileJava', ':processResources']) { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } - from sourceSets.main.output.classesDirs - from sourceSets.main.output.resourcesDir - project.archivesBaseName = project.name + '-all' - manifest { - attributes 'Implementation-Title': 'ConsoleUI', - 'Implementation-Version': project.version, - 'Main-Class': 'de.codeshelf.consoleui.Basic' - - } -} - -task printEnv { - println "username " + sonatypeUsername -} - -publishing { - repositories { - mavenLocal { - // change URLs to point to your repos, e.g. http://my.org/repo - def releasesRepoUrl = "$buildDir/repos/releases" - def snapshotsRepoUrl = "$buildDir/repos/snapshots" - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - } - mavenCentral { - // change URLs to point to your repos, e.g. http://my.org/repo - def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - credentials { - username = sonatypeUsername - password = sonatypePassword - } - } - } - - publications { - consoleUI(MavenPublication) { - from components.java - pom { - name = 'ConsoleUI' - description = 'Library for Ansi-Console user interaction' - url = 'https://github.com/awegmann/consoleui/' - - licenses { - license { - name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - developers { - developer { - id = "an10nn"; - name = "Andreas Wegmann"; - email = "andreas.we9mann@gmail.com"; - } - } - scm { - connection = 'scm:git:git://github.com/awegmann/consoleui.git' - developerConnection = 'scm:git:ssh://git@github.com:awegmann/consoleui.git' - url = 'https://github.com/awegmann/consoleui/' - } - } - } - } -} - -signing { - sign publishing.publications.consoleUI -} diff --git a/console-ui/doc/howto.md b/console-ui/doc/howto.md index d772da382..f311343b4 100644 --- a/console-ui/doc/howto.md +++ b/console-ui/doc/howto.md @@ -18,71 +18,72 @@ Console UI currently supports: ## A small example -The following code presents a simple, but complete code example to use CosoleUI for selecting an item from a list. +The following code presents a simple, but complete code example to use ConsoleUI for selecting an item from a list. ```java -package de.codeshelf.consoleui; - -import de.codeshelf.consoleui.prompt.ConsolePrompt; -import de.codeshelf.consoleui.prompt.PromtResultItemIF; -import de.codeshelf.consoleui.prompt.builder.PromptBuilder; -import jline.TerminalFactory; -import org.fusesource.jansi.AnsiConsole; +package org.jline.consoleui.examples; import java.io.IOException; -import java.util.HashMap; - -import static org.fusesource.jansi.Ansi.ansi; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.PromptBuilder; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; -/** - * User: Andreas Wegmann - * Date: 12.08.2020 - */ public class SimpleExample { - public static void main(String[] args) throws InterruptedException { - AnsiConsole.systemInstall(); // #1 - System.out.println(ansi().eraseScreen().render("Simple list example:")); - - try { - ConsolePrompt prompt = new ConsolePrompt(); // #2 - PromptBuilder promptBuilder = prompt.getPromptBuilder(); // #3 - - promptBuilder.createListPrompt() // #4 - .name("pizzatype") - .message("Which pizza do you want?") - .newItem().text("Margherita").add() // without name (name defaults to text) - .newItem("veneziana").text("Veneziana").add() - .newItem("hawai").text("Hawai").add() - .newItem("quattro").text("Quattro Stagioni").add() - .addPrompt(); - - HashMap result = prompt.prompt(promptBuilder.build()); // #5 - System.out.println("result = " + result); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - TerminalFactory.get().restore(); - } catch (Exception e) { - e.printStackTrace(); + public static void main(String[] args) { + List header = new ArrayList<>(); + header.add(new AttributedStringBuilder().append("Simple list example:").toAttributedString()); + + try (Terminal terminal = TerminalBuilder.builder().build()) { + ConsolePrompt prompt = new ConsolePrompt(terminal); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder + .createListPrompt() + .name("pizzatype") + .message("Which pizza do you want?") + .newItem() + .text("Margherita") + .add() // without name (name defaults to text) + .newItem("veneziana") + .text("Veneziana") + .add() + .newItem("hawai") + .text("Hawai") + .add() + .newItem("quattro") + .text("Quattro Stagioni") + .add() + .addPrompt(); + + Map result = prompt.prompt(header, promptBuilder.build()); + System.out.println("result = " + result); + } catch (IOException e) { + e.printStackTrace(); } - } - }} + } +} ``` Basic steps: -1. ConsoleUI uses [jansi](https://github.com/fusesource/jansi), so you have to initialize it first -2. Create a new `ConsolePrompt` object. -3. Create a `PromptBuilder`. All user interactions can be created with the prompt builder object. -4. In this example, we create a `ListPrompt` +1. Create a new `ConsolePrompt` object. +2. Create a `PromptBuilder`. All user interactions can be created with the prompt builder object. +3. In this example, we create a `ListPrompt` 1. give it a name ('pizzatype') 2. assign a prompt message ("Which pizza do you want?") 3. create items with and name (optional) and a text and add them to the ListPrompt 4. to finish call `addPrompt()` to create the ListPrompt and add it to the prompt builder object. -5. calling `prompt.prompt(promptBuilder.build())` builds all the prompts (in this example only one) and enters the user interaction. After all prompts are processes, the `prompt()` method returns an object with the user input results. +4. calling `prompt.prompt(promptBuilder.build())` builds all the prompts (in this example only one) and enters the user interaction. After all prompts are processes, the `prompt()` method returns an object with the user input results. # Prompting for user input @@ -148,7 +149,7 @@ Description: 4. Add items to the list. If you call `newItem()` without a name for the item, the text of the item is used in the result. 5. Add items with `newItem()` to give the item a name which makes it possible to use a technical key or another value instead of the printed text as a result. 6. (optional) For long lists, you can use `pageSize()` to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height. -7. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed, even when you select a very low value. +7. (optional) Further you can use `relativePageSize()` to set a percentage size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed, even when you select a very low value. #### Console @@ -198,7 +199,7 @@ Description: 8. Use the `check()` method to pre-check the corresponding item. 9. For more flexibility, you can use `checked()` with a boolean value to select if the item is checked by default. 10. (optional) For long lists, you can use `pageSize()` to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height. -11. (optional) Further you can use `relativePageSize()` to set a percentual size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed even when you select a very low value. +11. (optional) Further you can use `relativePageSize()` to set a percentage size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed even when you select a very low value. #### Console diff --git a/console-ui/gradle.properties b/console-ui/gradle.properties deleted file mode 100644 index 54911ea02..000000000 --- a/console-ui/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -project.version=0.0.11 - -sonatypeUsername=dummy -sonatypePassword=dummy diff --git a/console-ui/gradle/wrapper/gradle-wrapper.jar b/console-ui/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 085a1cdc27db1185342f15a00441734e74fe3735..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52141 zcmafaW0a=B^559DjdyI@wy|T|wr$(CJv+9!W822gY&N+!|K#4>Bz;ajPk*RBjZ;RV75EK-U36r8Y(BB5~-#>pF^k0$_Qx&35mhPenc zNjoahrs}{XFFPtR8Xs)MImdo3(FfIbReeZ6|xbrftHf0>dl5l+$$VLbG+m|;Uk##see6$CK4I^ ziDe}0)5eiLr!R5hk6u9aKT36^C>3`nJ0l07RQ1h438axccsJk z{kKyd*$G`m`zrtre~(!7|FcIGPiGfXTSX`PzlY^wY3ls9=iw>j>SAGP=VEDW=wk2m zk3%R`v9(7LLh{1^gpVy8R2tN#ZmfE#9!J?P7~nw1MnW^mRmsT;*cyVG*SVY6CqC3a zMccC8L%tQqGz+E@0i)gy&0g_7PV@3~zaE~h-2zQ|SdqjALBoQBT2pPYH^#-Hv8!mV z-r%F^bXb!hjQwm2^oEuNkVelqJLf029>h5N1XzEvYb=HA`@uO_*rgQZG`tKgMrKh~aq~ z6oX{k?;tz&tW3rPe+`Q8F5(m5dJHyv`VX0of2nf;*UaVsiMR!)TjB`jnN2)6z~3CK@xZ_0x>|31=5G$w!HcYiYRDdK3mtO1GgiFavDsn&1zs zF|lz}sx*wA(IJoVYnkC+jmhbirgPO_Y1{luB>!3Jr2eOB{X?e2Vh8>z7F^h$>GKmb z?mzET;(r({HD^;NNqbvUS$lhHSBHOWI#xwT0Y?b!TRic{ z>a%hUpta3P2TbRe_O;s5@KjZ#Dijg4f=MWJ9euZnmd$UCUNS4I#WDUT2{yhVWt#Ee z?upJB_de&7>FHYm0Y4DU!Kxso=?RabJ*qsZ2r4K8J#pQ)NF?zFqW#XG1fX6dFC}qh z3%NlVXc@Re3vkXi*-&m)~SYS?OA8J?ygD3?N}Pq zrt_G*8B7^(uS7$OrAFL5LvQdQE2o40(6v`se%21Njk4FoLV-L0BN%%w40%k6Z1ydO zb@T(MiW@?G-j^j5Ypl@!r`Vw&lkJtR3B#%N~=C z@>#A{z8xFL=2)?mzv;5#+HAFR7$3BMS-F=U<&^217zGkGFFvNktqX z3z79GH^!htJe$D-`^(+kG*);7qocnfnPr^ieTpx&P;Z$+{aC8@h<0DDPkVx`_J~J> zdvwQxbiM1B{J6_V?~PNusoB5B88S%q#$F@Fxs4&l==UW@>9w2iU?9qMOgQWCl@7C* zsbi$wiEQEnaum!v49B_|^IjgM-TqMW!vBhhvP?oB!Ll4o-j?u3JLLFHM4ZVfl9Y_L zAjz@_3X5r=uaf|nFreX#gCtWU44~pA!yjZNXiZkoHhE$l@=ZTuxcLh53KdMOfanVe zPEX(#8GM7#%2*2}5rrdBk8p#FmzpIC>%1I9!2nRakS|^I*QHbG_^4<=p)(YOKvsTp zE#DzUI>Y&g)4mMaU6Bhrm8rSC{F_4J9sJlF0S5y5_=^l!{?W_n&SPj&7!dEvLzNIRMZBYyYU@Qftts7Zr7r>W- zqqk46|LEF|&6bn#CE~yMbiF&vEoLUA(}WzwmXH_=<~|I(9~{AE$ireF7~XBqPV2)* zcqjOCdi&>tUEuq31s(|TFqx>Wuo(ooWO(sd!W~Hu@AXg=iQgq^O3Lv9xH$vx*vrgDAirQqs9_DLS1e45HcUPdEMziO?Mm1v!)n93L%REy=7 zUxcX!jo!vyl_l0)O(Y~OT``;8mB(tcf}`Rh^weqPnDVDe-ngsZ~C z`onh0WLdaShAAb-3b{hT5ej9a$POQ9;RlPy}IYzKyv+8-HzB7fV!6X@a_T61qZ zWqb&&ip*@{;D-1vR3F2Q&}%Q>TFH&2n?2w8u8g=Y{!|;>P%<@AlshvM;?r7I)yXG% z^IpXZ(~)V*j^~sOG#cWCa+b8LC1IgqFx+Mq$I`6VYGE#AUajA9^$u-{0X#4h49a77 zH>d>h3P@u!{7h2>1j+*KYSNrKE-Q(z`C;n9N>mfdrlWo$!dB35;G4eTWA}(aUj&mNyi-N+lcYGpA zt1<~&u`$tIurZ2-%Tzb1>mb(~B8;f^0?FoPVdJ`NCAOE~hjEPS) z&r7EY4JrG~azq$9$V*bhKxeC;tbBnMds48pDuRy=pHoP*GfkO(UI;rT;Lg9ZH;JU~ zO6gTCRuyEbZ97jQyV7hM!Nfwr=jKjYsR;u8o(`(;qJ(MVo(yA<3kJximtAJjOqT=3 z8Bv-^`)t{h)WUo&t3alsZRJXGPOk&eYf}k2JO!7Au8>cvdJ3wkFE3*WP!m_glB-Rt z!uB>HV9WGcR#2n(rm=s}ulY7tXn5hC#UrNob)-1gzn-KH8T?GEs+JBEU!~9Vg*f6x z_^m1N20Do}>UIURE4srAMM6fAdzygdCLwHe$>CsoWE;S2x@C=1PRwT438P@Vt(Nk` zF~yz7O0RCS!%hMmUSsKwK$)ZtC#wO|L4GjyC?|vzagOP#7;W3*;;k?pc!CA=_U8>% z%G^&5MtFhvKq}RcAl))WF8I#w$So?>+_VEdDm_2=l^K320w~Bn2}p+4zEOt#OjZ6b zxEYoTYzvs$%+ZYwj;mZ@fF42F1-Hb<&72{1J)(D~VyVpo4!dq259t-_Oo3Yg7*R`N zUg!js4NRyfMbS*NLEF}rGrlXz0lHz))&&+B#Tdo@wlh-Q8wr7~9)$;s9+yJH0|m=F zSD9mUW>@HLt}mhAApYrhdviKhW`BfNU3bPSz=hD+!q`t*IhG+Z4XK;_e#AkF5 z&(W7iUWF4PNQ+N!-b-^3B$J4KeA1}&ta@HK=o2khx!I&g#2Y&SWo-;|KXDw!Xb)mP z$`WzPA!F(h*E=QP4;hu7@8J&T|ZPQ2H({7Vau6&g;mer3q?1K!!^`|0ld26 zq|J&h7L-!zn!GnYhjp`c7rG>kd1Y%8yJE9M0-KtN=)8mXh45d&i*bEmm%(4~f&}q@ z1uq)^@SQ~L?aVCAU7ZYFEbZ<730{&m?Un?Q!pxI7DwA^*?HloDysHW{L!JY!oQ8WMK(vT z@fFakL6Ijo$S$GH;cfXcoNvwVc8R7bQnOX2N1s$2fbX@qzTv>748In?JUSk@41;-8 zBw`fUVf$Jxguy{m1t_Z&Q6N$Ww*L9e%6V*r3Yp8&jVpxyM+W?l0km=pwm21ch9}+q z$Z&eb9BARV1?HVgjAzhy);(y1l6)+YZ3+u%f@Y3stu5sSYjQl;3DsM719wz98y4uClWqeD>l(n@ce)pal~-24U~{wq!1Z_ z2`t+)Hjy@nlMYnUu@C`_kopLb7Qqp+6~P=36$O!d2oW=46CGG54Md`6LV3lnTwrBs z!PN}$Kd}EQs!G22mdAfFHuhft!}y;8%)h&@l7@DF0|oy?FR|*E&Zuf=e{8c&hTNu# z6{V#^p+GD@A_CBDV5sM%OA*NwX@k1t?2|)HIBeKk(9!eX#J>jN;)XQ%xq^qVe$I}& z{{cL^a}>@*ZD$Ve)sJVYC!nrAHpV~JiCH3b7AQfAsEfzB$?RgU%+x7jQ_5XQ8Gf*N`i<1mZE zg6*_1dR3B`$&9CxHzk{&&Hf1EHD*JJF2glyBR+hBPnwP@PurN`F80!5{J57z;=kAc za65ouFAve7QEOmfcKg*~HZ04-Ze%9f)9pgrVMf7jcVvOdS{rf+MOsayTFPT}3}YuH z$`%^f$}lBC8IGAma+=j9ruB&42ynhH!5)$xu`tu7idwGOr&t=)a=Y2Sib&Di`^u9X zHQ=liR@by^O`ph|A~{#yG3hHXkO>V|(%=lUmf3vnJa#c%Hc>UNDJZRJ91k%?wnCnF zLJzR5MXCp)Vwu3Ew{OKUb?PFEl6kBOqCd&Qa4q=QDD-N$;F36Z_%SG}6{h2GX6*57 zRQIbqtpQeEIc4v{OI+qzMg_lH=!~Ow%Xx9U+%r9jhMU=7$;L7yJt)q+CF#lHydiPP zQSD=AtDqdsr4G!m%%IauT@{MQs+n7zk)^q5!VQrp?mFajX%NQT#yG9%PTFP>QNtfTM%6+b^n%O`Bk74Ih| zb>Fh1ic{a<8g<{oJzd|@J)fVVqs&^DGPR-*mj?!Z?nr<f)C8^oI(N4feAst}o?y z-9Ne339xN7Lt|Tc50a48C*{21Ii$0a-fzG1KNwDxfO9wkvVTRuAaF41CyVgT?b46; zQvjU!6L0pZM%DH&;`u`!x+!;LaPBfT8{<_OsEC5>>MoJQ5L+#3cmoiH9=67gZa;rvlDJ7_(CYt3KSR$Q#UR*+0hyk z>Dkd2R$q~_^IL2^LtY|xNZR(XzMZJ_IFVeNSsy;CeEVH|xuS#>itf+~;XXYSZ9t%1moPWayiX=iA z!aU~)WgV!vNTU=N;SpQ((yz#I1R#rZ&q!XD=wdlJk4L&BRcq(>6asB_j$7NKLR%v; z9SSp$oL7O|kne`e@>Bdf7!sJ*MqAtBlyt9;OP3UU1O=u6eGnFWKT%2?VHlR86@ugy z>K)(@ICcok6NTTr-Jh7rk=3jr9`ao!tjF;r~GXtH~_&Wb9J^ zd%FYu_4^3_v&odTH~%mHE;RYmeo+x^tUrB>x}Is&K{f+57e-7Y%$|uN%mf;l5Za95 zvojcY`uSCH~kno zs4pMlci*Y>O_pcxZY#?gt1^b-;f(1l9}Ov7ZpHtxfbVMHbX;579A>16C&H5Q>pVpH5LLr<_=!7ZfX23b1L4^WhtD?5WG;^zM}T>FUHRJv zK~xq88?P);SX-DS*1LmYUkC?LNwPRXLYNoh0Qwj@mw9OP&u{w=bKPQ)_F0-ptGcL0 zhPPLKIbHq|SZ`@1@P5=G^_@i+U2QOp@MX#G9OI20NzJm60^OE;^n?A8CH+XMS&3ek zP#E7Y==p;4UucIV{^B`LaH~>g6WqcfeuB#1&=l!@L=UMoQ0$U*q|y(}M(Y&P$Xs&| zJ&|dUymE?`x$DBj27PcDTJJn0`H8>7EPTV(nLEIsO&9Cw1Dc&3(&XFt9FTc{-_(F+ z-}h1wWjyG5(ihWu_3qwi; zAccCjB3fJjK`p=0VQo!nPkr0fT|FG;gbH}|1p`U>guv9M8g2phJBkPC`}ISoje6+? zvX|r5a%Y-@WjDM1&-dIH2XM}4{{d&zAVJQEG9HB8FjX&+h*H=wK=xOgNh8WgwBxW+ z0=^CzC4|O_GM>^_%C!!2jd&x*n2--yT>PZJ`Mok6Vf4YFqYp@a%)W}F4^DpKh`Cr7 z{>Z7xw-4UfT@##s#6h%@4^s^7~$}p2$v^iR5uJljApd9%#>QuxvX+CSZv18MPeXPCizQ*bm);q zWhnVEeM}dlCQP*^8;Q7OM|SSgP+J;DQy|bBhuFwJ2y*^|dBwz96-H;~RNsc}#i= zwu`Tp4$bwRVb7dxGr_e1+bJEc=mxLxN_f>hwb#^|hNdewcYdqXPrOxDE;|mP#H|a% z{u8#Vn}zVP(yJ}+-dx;!8<1in=Q8KsU%Q5CFV%5mGi8L;)*m%Vs0+S`ZY(z7aZ$VCjp?{r>C<9@$zVN;LVhxzPEdDPdb8g<)pckA z?mG@Ri>ode(r|hjNwV#*{!B^l2KO@4A+!X;#PW#?v2U!ydYIFHiXC3>i2k7{VTfji>h z8-(^;x!>f)Qh$mlD-z^1Nxu})XPbN=AUsb%qhmTKjd=1BjKr(L9gb1w4Y8p+duWfS zU>%C>*lCR@+(ku!(>_SA6=4CeM|$k4-zv|3!wHy+H&Oc$SHr%QM(IaBS@#s}O?R7j ztiQ>j^{X)jmTPq-%fFDxtm%p|^*M;>yA;3WM(rLV_PiB~#Eaicp!*NztJNH;q5BW$ zqqlfSq@C0A7@#?oRbzrZTNgP1*TWt(1qHii6cp5U@n|vsFxJ|AG5;)3qdrM4JElmN z+$u4wOW7(>$mMVRVJHsR8roIe8Vif+ml3~-?mpRos62r0k#YjdjmK;rHd{;QxB?JV zyoIBkfqYBZ!LZDdOZArQlgXUGmbpe7B-y7MftT;>%aM1fy3?^CuC{al$2-tfcA?d) z<=t7}BWsxH3ElE^?E&|f{ODX&bs+Ax>axcdY5oQ`8hT)YfF%_1-|p*a9$R~C=-sT| zRA~-Q$_9|G(Pf9I+y!zc>fu)&JACoq&;PMB^E;gIj6WeU=I!+scfSr}I%oD1fh+AQ zB^Q^b@ti5`bhx+(5XG5*+##vV>30UCR>QLYxHYY~k!AR`O6O_a3&wuW61eyHaq;HL zqy@?I*fmB)XY;Z@RH^IR|6m1nwWv>PDONtZV-{3@RkM_JcroRNLTM9?=CI}l%p86A zdxv|{zFWNI;L8K9hFSxD+`-pwvnyS|O?{H-rg6dPH<3oXgF0vU5;~yXtBUXd>lDs~ zX!y3-Pr9l;1Q^Z<15_k1kg|fR%aJKzwkIyED%CdxoXql=^QB;^*=2nVfi{w?0c@Dj z_MQEYjDpf^`%)$|4h>XnnKw05e5p4Jy69{uJ5p|PzY+S?FF~KWAd0$W<`;?=M+^d zhH&>)@D9v1JH2DP?tsjABL+OLE2@IB)sa@R!iKTz4AHYhMiArm)d-*zitT+1e4=B( zUpObeG_s*FMg$#?Kn4%GKd{(2HnXx*@phT7rEV?dhE>LGR3!C9!M>3DgjkVR>W)p3 zCD0L3Ex5-#aJQS6lJXP9_VsQaki5#jx}+mM1`#(C8ga~rPL{2Z;^^b+0{X)_618Sw z0y6LTkk;)quIAYpPY{)fHJLk?)(vxt?roO24{C!ck}A)_$gGS>g!V^@`F#wg+%Cok zzt6hJE|ESs@S^oHMp3H?3SzqBh4AN(5SGi#(HCarl^(Jli#(%PaSP9sPJ-9plwZv{ z1lkTGk4UAXYP^>V+4;nQ4A~n-<+1N)1lPzXIbG{Q;e3~T_=Trak{WyjW+n!zhT*%)q?gx zTl4(Gf6Y|ALS!H$8O?=}AlN=^3yZCTX@)9g5b_fif_E{lWS~0t`KpH8kkSnWWz+G1 zjFrz}gTnQ2k-`oag*031Nj7=MZfP}gvrNvv_crWzf9Cdzv^LyBeEyF2#hGg8_C8jW)NCAhsm2W_P21DeX7x$4EDD){~vBiLoby=d+&(;_f(?PMfamC zI_z%>Nq-rC%#z#1UC49j4@m63@_7LWD$ze=1%GPh`%@PB7yGH6Zh=1#L%&%hU7z%Y zs!IN(ef@!+|1YR28@#kw^XR= zxB$*nNZm7Y@L0&IlmoN}kEI?dBee+z+!MWCy+e4P4MYpOgr}2Q(wnR1ZiA>5_P*Cg zB4BMlcx?(v*+V3O+p~Buk;wIN6v!Ut?gYpl+KFu~elf}{E4`9+lcR0k$bC>+I zWxO5jD8sYPbMS)4c3i2UojI4T7uzE*Zz;POw{0d0`*iHJ%(Pb=sa^pV{t_JtHoPeC zX+t_k*=D%+Sv#+5CeoRfI)G`T90~AE@K9RaFR%8*w#*x9>H$ahFd>PUg_zP`VVPSR zr#Rb;I--8Rq;eTBju;dx2cmZ9Al>aiDY z#7(4S(A#aRvl7jm78sQ+O^S5eUS8|W%5@Pt9fm?J=r`~=l-gdv(LB~C-Gi#srwEDQ z4cCvA*XiRj9VDR6Ccy2k(Nvxic;~%YrfNeWl$cJpa%WO_4k?wxKZ{&`V#!&#jV@x+ z7!!YxOskc;cAF~`&aRWp8E)fnELtvb3-eHkeBPb~lR&iH=lZd^ZB(T6jDg5PnkJQFu9? z+24ww5L%opvEkE$LUHkZDd0ljo!W}0clObhAz`cPFx2)X3Sk91#yLL}N6AE0_O`l| z7ZhaKuAi7$?8uuZAFL(G0x3wE<-~^neGm=*HgJa(((J;yQI$NB)J;i0?vr`M1v+R? zd+{rD^zK}0Gi!2lXo0P+jVQ$HNYn^sRMONYVZPPT@enUb1pHHYgZMo5GN~SIz*;gv z1H<4(%53!6$4+VX_@Kp!>A9wwo{(KdWx)ja>x3&4=H(Urbn?0Vh}W3%ly5SgJ<+X5?N7-B=byoKyICr>3 zIFXe;chMk7-cak~YKL8Bf>VbZbX{5L9ygP_XS?oByNL*zmp8&n9{D42I^=W=TTM4X zwb_0axNK?kQ;)QUg?4FvxxV7L@sndJL0O12M6TMorI&cAL%Q464id6?Tbd_H!;=SRW9w2M*wc00yKVFslv|WN( zY7=Yikt+VY@DpzKq7@z_bVqr7D5B3xRbMrU5IO7;~w2nNyP7J_Gp>>7z?3!#uT4%-~h6)Ee1H z&^g}vZ{g}DIs@FDzE$QG_smSuEyso@I#ID3-kkYXR=nYuaa0{%;$WzZC@j)MDi+jC z!8KC;1mGCHGKr>dR;3;eDyp^0%DH`1?c7JcsCx$=m(cs^4G& zl@Fi8z|>J`^Z-faK{mhsK|;m%9?luacM+~uhN@<20dfp4ZN@qsi%gM67zZ`OHw=PE zr95O@U(HheB7OBYtyF=*Z5V&m?WDvIQ`edwpnT?bV`boB z!wPf&-@7 z0SoTB^Cy>rDHm%^b0cv@xBO%02~^=M79S}TG8cbVhj72!yN_87}iA1;J$_xTb+Zi@76a{<{OP0h&*Yx`U+mkA#x3YQ} zPmJsUz}U0r?foPOWd5JFI_hs_%wHNa_@)?(QJXg>@=W_S23#0{chEio`80k%1S?FWp1U;4#$xlI-5%PEzJcm zxjp$&(9f2xEx!&CyZZw|PGx&4$gQbVM|<2J&H7rpu;@Mc$YmF9sz}-k0QZ!YT$DUw z_I=P(NWFl!G-}aofV?5egW%oyhhdVp^TZH%Q4 zA2gia^vW{}T19^8q9&jtsgGO4R70}XzC-x?W0dBo+P+J8ik=6}CdPUq-VxQ#u4JVJ zo7bigUNyEcjG432-Epy)Rp_WDgwjoYP%W|&U~Gq-r`XK=jsnWGmXW6F}c7eg;$PHh>KZ@{cbTI<`ZP>s(M@zy=aHMA2nb(L0COlVcl8UXK+6`@Di+Wai;lJf^7s6V%NkKcad zDYY%2utqcw#CJFT9*V9U_{DyP&VYb)(6y`Z%Rq& z!PTtuI#psBgLPoNu{xvs^y26`oY;p!fE=bJW!cP^T>bUE*UKBV5Bd%!U{Q5{bKwN> zv)pn@Oc{6RyIS>!@Yvkv+hVLe+bmQ6fY2L}tT)Vbewg8`A`PFYyP+@QmL?b{RED;; zR6fwAAD}Ogejah(58bv{VG&WJhll7X-hjO9dK`8m5uFvthD1+FkJtT_>*{yKA(lXx zKucHMz#F_G)yTJw!)I3XQ7^9ydSlr9D)z?e*jKYE?xTKjR|ci30McU^4unzPsHGKN zMqwGd{W_1_jBQ_oeU^4!Ih}*#AKF%7txXZ0GD}Jzcf+i*?WLAe6#R_R-bSr17K%If z8O2SwYwMviXiJ?+$% zse=E~rK*PH@1Md4PFP)t(NhV%L3$657FUMap?fugnm3|N z79w3|qE%QyqZB}2WG&yc>iOaweUb`5o5p9PgyjqdU*sXP=pi$-1$9fGXYgS2?grS6 zwo#J~)tUTa0tmGNk!bg*Pss&uthJDJ$n)EgE>GAWRGOXeygh;f@HGAi4f){s40n?k z=6IO?H1_Z9XGzBIYESSEPCJQrmru?=DG_47*>STd@5s;1Y|r*+(7s4|t+RHvH<2!K z%leY$lIA{>PD_0bptxA`NZx-L!v}T4JecK#92kr*swa}@IVsyk{x(S}eI)5X+uhpS z8x~2mNLf$>ZCBxqUo(>~Yy4Z3LMYahA0S6NW;rB%)9Q z8@37&h7T$v2%L|&#dkP}N$&Jn*Eqv81Y*#vDw~2rM7*&nWf&wHeAwyfdRd%`>ykby zC*W9p2UbiX>R^-!H-ubrR;5Z}og8xx!%)^&CMl(*!F%or1y&({bg?6((#og-6Hey&3th3S%!n3N|Z2ZCZHJxvQ9rt zv|N#i*1=qehIz_=n*TWC6x-ab)fGr8cu!oYV+N)}3M;H4%$jwO>L!e53sxmJC~;O; zhJw|^&=2p!b8uk{-M|Z*J9n0{(8^>P+Y7vlFLc8#weQMg2iB8MFCe-*^BJV6uVWjg zWZe{-t0f67J<|IIn4{wsKlG*Amy{-yOWMMW)g}rh>uEE;jbkS-om>uAjeTzCg51683UTmY4+yT zW!qe`?~F{~1Y>mPJ9M0hNRBW$%ZwOA-NdIeaE6_K z>y8D3tAD7{3FouIXX9_MbY;zq%Ce0}VmT;aO~=*Mk4mflb_i4CApxEtZ^TDNoOzy_ z-eIE(&n1Vz*j&(BjO*fVvSCozTJU4?tWC8m4=d|D{WV0k+0M2!F1=T}z7V4-JA*y( z!;H(sOBmg=%7p&LLf%z%>VgtdN6jl2y95aXY}v9U;m~YWx{2#lwLpEJWGgs`sE*15 zvK`DtH-Q^ix>9@qVG+d*-C{lYPBbts1|%3!CkLP1t4iz%LO-di4lY%{8>jd{turVrD*_lLv!ShQC~S#SXjCO?##c zh2aZKVAHDf1sQpZiH^C7NRu?44JuEp?%W4-?d;Dg z;`gKA9$oC{WlQuT?fex!ci3GJhU;1J!YLHbyh8B-jsZ~pl59LGannKg9}1qxlbOOq zaJhTl zEJ`2Xd_ffdK^EE1v>8kUZG`eMXw(9S+?Lxx#yTUo?WdV}5kjC|glSJqX zv8RO|m#Ed@hW=};Yfl&2_@11Xm}pz0*SRx%OH_NODo@>e$cMAv(0u`~Yo|qbQ~mzA zMKt^U+GIXKH^xuD9n}NfU|?ZTOSS>XJwlg`lYHgea)!ZR?m^=oj+qyKBd6SJvPZk* zwc-2$b%%V~k$5{=(rG!OcR{;u2V3um|C+oT5F?rt`CER|iU9-!_|GxMe^!f$d6*iz z{?~JnR84mS+!gFUxugG?g9uGFI(?Q0SADS8=n=#aCK^`6@rm4r=LJTBm;)cY zm_6c5!ni$SWFOuj36eKau>6=kl_p=-7>VL_fJuJZI}0=3kASf|t;B~;Mt(vuhCU+c zKCF@SJ5#1>8YLfe{pf?sH*v6C)rOvO1~%@+wN}#>dkcrLw8U@xAySc{UeaP?7^AQ5 zmThfw^(i@*GMlM!xf+dzhRtbo8#;6Ql_s$t15q%*KeCm3`JrXnU*T^hV-aGX)bmxF z;O%jGc{6G+$gZ$YvOM2bZ!?>X<^-D zbT+YCx722}NY88YhKnw?yjF1#vo1v+pjId;cdyT*SH@Bc>6(GV*IBkddKx%b?y!r6 z=?0sTwf`I_Jcm(J8D~X@ESiO`X&i53!9}5l}PXzSYf9 zd&=h`{8BP-R?E*Nk$yzSSFhz2uVerdhbcCWF{S7reTkzXB;U@{9`hvC0AscwoqqU( zKQavt5OPm9y1UpKL%O(SWSSX=eo2rky_8jJ-ew7>iw~T=Xrt3EEzc!slebwG)FrE> z>ASkjJk%#@%SFWs-X4)?TzbBtDuwF#;WVw}?(K`UYqm`3vKbFKuqQ8uL2Y5}%T0y5 zia#E?tyZgnuk$LD^ihIn(i~|1qs(%NpH844QX-2S5E)E7lSM=V56o>5vLB^7??Vy_ zgEIztL|85kDrYF(VUnJ$^5hA;|41_6k-zO#<7gdprPj;eY_Et)Wexf!udXbBkCUA)>vi1E!r2P_NTw6Vl6)%M!WiK+jLRKEoHMR zinUK!i4qkppano|OyK(5p(Dv3DW`<#wQVfDMXH~H(jJdP47Y~`% z#ue|pQaVSv^h#bToy|pL!rWz8FQ53tnbEQ5j#7op?#c#(tj@SM2X*uH!;v8KtS5Fo zW_HE8)jSL zYO}ii#_KujRL4G*5peU)-lDW0%E}!YwL#IKUX_1l9ijy~GTFhO?W^=vEBe?m+tvBe zLaGWcoKg==%dO#6R}`U0>M)2+{b*~uamlaUNN<_NVZTGY4-(ORqK6|HvKFMKwp6^L zR+MC^`6^|^=u^Do;wy8mUp^Oct9~=vQ74vfO-m&Q0#~-mkqkpw&dMkVJ(So<)tf3h z46~mW_3T@Mzh<2XZYO7@F4j|BbhhXjs*hayIjTKyGoYO}`jEFn^!4Y! zL30ubp4U(r>Nx&RhaJkGXuRe%%f%D;1-Zdw2-9^Mq{rP-ZNLMpi~m+v?L=sPSAGcc z{j+Y!3CVrm);@{ z;T?sp1|%lk1Q&`&bz+#6#NFT*?Zv3k!hEnMBRfN47vcpR20yJAYT(5MQ@k;5Xv@+J zLjFd{X_il?74aOAMr~6XUh7sT4^yyLl%D89Io`m5=qK_pimk+af+T^EF>Y)Z{^#b# zt%%Bj9>JW!1Zx_1exoU~obfxHy6mBA{V6E)12gLp-3=21=O82wENQ}H@{=SO89z&c*S8Veq8`a3l@EQO zqaNR8IItz4^}>9d+Oj%YUQlb;;*C0!iC&8gaiDJ)bqg(92<>RbXiqFI3t#jqI%3Y( zPop=j=AyLA?pMYaqp0eHbDViOWV-5IUVwx+Fl6M54*?i+MadJHIRjiQoUe?v-1XdQ z5S305nVbg|sy~qPr2C6}q!v)8E%$i~p5_jGPA0%3*F%>XW6g)@4-z73pVcvWs$J2m zpLeW4!!31%k#VUG76V__S**9oC{-&P6=^fGM$2q<+1eC}Fa2EB3^s{ru^hI}e^KPM zMyj;bLtsRex^QMcgF)1U0biJ|ATXX`YuhzWMwP73e0U?P=>L|R?+13$8(PB23(4Js zy@KS0vvS~rk*^07Bd4}^gpc|e5%248Mei_y^mrD;zUYniPazU>1Dun%bVQ0T7DNXr zMq4Y09V_Dr1OQ$ni)BSyXJZ+D7 zXHh02bToWd;4AlF-G`mk23kD=$9B)}*I@kF9$WcOHc%d6BdemN(!^z0B3rvR>NPQ? z+vv#Qa~Ht|BiTdcN;g6;eb6!Jso)MFD3{sf{T;!fM^OwcEtoJI#ta?+R>|R;Ty2E% zjF8@wgWC=}Kkv52c@8Psigo4#G#E?T(;i}rq+t}E(I(gAekZX;HbTR5ukI>8n5}oC zXXTcy>tC{sG$yFf?bIqBAK3C^X3OAY^Too{qI_uZga0cK4Z$g?Zu$#Eg|UEusQ)t% z{l}Zjf5OrK?wkKJ?X3yvfi{Nz4Jp5|WTnOlT{4sc3cH*z8xY(06G;n&C;_R!EYP+m z2jl$iTz%_W=^)Lhd_8hWvN4&HPyPTchm-PGl-v~>rM$b>?aX;E&%3$1EB7{?uznxn z%yp0FSFh(SyaNB@T`|yVbS!n-K0P|_9dl=oE`7b?oisW)if(`g73bkt^_NHNR_|XU z=g?00`gZRHZm+0B(KvZ0?&(n<#j!sFvr|;G2;8qWg3u%P;M1+UL!9nj)q!}cd}jxK zdw=K$?NuLj?2#YzTCEw1SfLr#3`3x(MB2F(j!6BMK!{jXF%qs;!bIFpar}^=OYmYm z86RJ9cZl5SuR6emPB>yrO)xg5>VucBcrV3UxTgZcUu(pYr+Sa=vl>4ql{NQy4-T%M zlCPf>t}rpgAS15uevdwJR_*5_H?USp=RR?a>$gSk-+w;VuIhukt9186ppP=Lzy1L7 ztx(smiwEKL>hkjH7Y))GcUk`Y z5ECCi%1tZE!rM4TU=lk^UdvMlTfvxem>?j&r?OZ>W4w?APw@uZ8qL`fTtS zQtB<7SczI&5ZKELNH8DU6UNe1SFyvU%S#WTlf%`QC8Z+*k{IQx`J}f79r+Sj-x|4f<|Jux>{!M|pWYf+ z-ST5a#Kn+V{DNZ0224A_ddrj3nA#XfsiTE9S+P9jnY<}MtGSKvVl|Em)=o#A607CfVjjA9S%vhb@C~*a2EQP= zy%omjzEs5x58jMrb>4HOurbxT7SUM@$dcH_k6U7LsyzmU9Bx3>q_Ct|QX{Zxr4Fz@ zGJYP!*yY~eryK`JRpCpC84p3mL?Gk0Gh48K+R$+<|KOB+nBL`QDC%?)zHXgyxS2}o zf!(A9x9Wgcv%(sn!?7Ec!-?CcP%no4K?dJHyyT)*$AiuGoyt=pM`gqw%S^@k8>V0V z4i~0?c>K{$I?NY;_`hy_j6Q{m~KDzkiGK z_ffu;+_e|m4d z_15oa@X;ab>43Run@zSszD-O!Nzy19m6h=R&twRlK+X3D)oKgLC~V9;J?XX>R3RGu zN|Unh(=HTQW)p?RT?&YNvMAv~vJ}zfcgn1a!J8UlwFd3TtiZ$TBtodeiE>6A>GCn^ zA`xU#q8UUJtPK*ND2fFUQVkl2(kzOkmFLZzH`JfJN%Y^99H_ZWjp0hL1Vw3?&qfM3@+M^tH0_;<4Av)eE{sGa?Elr02@SE;bbunGzjUVjG@9;L4^O6+mQdA@W)T zTdtB=Wto*&%qAF#4J`~oH7H5JSQw_Dpu=pkcTn!@9BcAv(bAckzhn|(lO7cYmsWwQ zN(_flmMl~iTNR2`&kt!SQrAcDY-u4!ZVrZ|Q3XOkVMWs#p&I(S^f6PD*XMguv@Vfl4&3R1!c}Ak zBM$#qTN-oX{d(%C%SrM_<*eHXl(?L3Mg==FJ2!2c)#Ow0-i>BCO;Qa9yt3Tb^7_mL zwro0iju!_*mSh=n>&{rY!B2_kLrPvTKiU~GH>}Il_aG5{LX1VsQEHw*hq0g$>i8&L z^J{Kn@_5#Z;7fs>a=lwox7_>f(`d(Km)uh&t$P_kzUi>LH;-Ah-hm)|V#J7yMiZ8) zoT4U>gw4kXOYWe-T=wlRp6!uz>t8CLLfy=`j@KUyZv;hyTVD%zSoUr+p4+Y&C$JR` zBLz45pFnB`Ag$l-2*UxHN0HvlE-;D%Uka-_M?VIu9|NBS)jpJz!QLzOJ+bi&NA0jE zEHVN-`b9V=TIL|?d!DtKK|r|TuiC*7p%J2n4xtB;kY3(M(4AQ14fR=3cDE={p=1hc z2hi^e3gAJ#f#Q4kS{M`;xDQ}UJ1milbEbWyNIF#gLCO@wCLYp)^#TiYQ14g^5X~rZ zg@vM!RKaL+1&I_Vbccb04rS@hET`LIZ+XDYe$`7j2Q7}R?A0aGJfiV{c<2p;kZB>-U zQEN|->iffGid`~+-bj7N#NHG+UOWHh#zy{=tLdR??HPLP-~=X04ZUtcjU&e8!wQP! z`+$WGQ^2o|tIno1Rg<;*UpI|iX|+k7x3zttENrC?7FcN|4HmOL6z7=(Cj}#rIu5Z+ zTEN;1Yo73xqzv{Yw}{r*T5EIM5!cA>E1c>XE08)aE2*k-yE-?Pje$)5dIR7P*TSUl z8C*d!g;gGY@TT4B(r}4enl8-t(arQsGX}dc4rV-HY-26MiHx|ry7w{R^>as@Gh#6O|j}_Gy*U>z}Is<#1ysnyhy3cq|$9zaz=lU1M zZJz1tbH;b4Z?~W8jAp^#kw2&kPe^ILsmc_m$P8nZIuZL|m!{R}FSRk)xG@{NFld&< zz$VX0NZXZNH%he}fVmUyQ$zY7CTSovrQ^9b;1-eG*kA9MmC=2!Ay7ye?QWMlC#Gb5 zTHwU<<%!(N9OYa!QxJxf$b4nMXc+v!9^W3wp?jI8ds(1-O0a+=mC5I4kF%XRP`YqL z?6yR@EcyC3+Q>nzy)iuCvhEYi|C_7w&zR?b0gH0f&ef6CQNDPYNEoBB9H>!J)HXu( zAtE=R%tZxC#8eOzs%nIpLgx+0a%2Q-t_`iM(7Wu`d|I+-J*9>`W3StC7wdele$4yj zU-x8yN`ybnWhedK>AJk#_S*G&9Nqo71zL}$ep-O`JL8Gz+-Tue7~wk)$5{||7?1nf zcY3(H1BTgH_j`!AIHpqy2Wggz^!9$!HZ29_SOnd|Hg`hGX_l+Pk(2v1Ly`n5dQT}4m zR;x~`dICosOtpbb%oCR;0nE#x=Hl&IP2eaeYH4hV^-PN=t@q-Df{p#18#yM&%^

)Mf(9O=$zt#xQMm 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/console-ui/gradlew.bat b/console-ui/gradlew.bat deleted file mode 100644 index aec99730b..000000000 --- a/console-ui/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/console-ui/jline-console-ui.bat b/console-ui/jline-console-ui.bat new file mode 100644 index 000000000..3edca9fb7 --- /dev/null +++ b/console-ui/jline-console-ui.bat @@ -0,0 +1,64 @@ +@echo off + +set DIRNAME=%~dp0% +set ROOTDIR=%DIRNAME%\.. +set TARGETDIR=%DIRNAME%target + +rem initialization +if not exist %TARGETDIR%\lib ( + echo Build jline with maven before running the demo + goto END +) + +goto :SETUP_CLASSPATH + +: APPEND_TO_CLASSPATH +set filename=%~1 +set cp=%cp%;%TARGETDIR%\lib\%filename% +goto :EOF + +:SETUP_CLASSPATH +set cp=%TARGETDIR%\classes;%TARGETDIR%\test-classes +rem JLINE +pushd %TARGETDIR%\lib +for %%G in (jline-*.jar) do call:APPEND_TO_CLASSPATH %%G + +set "opts=%JLINE_OPTS%" +:RUN_LOOP + if "%1" == "jansi" goto :EXECUTE_JANSI + if "%1" == "jna" goto :EXECUTE_JNA + if "%1" == "debug" goto :EXECUTE_DEBUG + if "%1" == "debugs" goto :EXECUTE_DEBUGS + if "%1" == "" goto :EXECUTE_MAIN + set "opts=%opts% %~1" + shift + goto :RUN_LOOP + +:EXECUTE_JANSI + for %%G in (jansi-*.jar) do call:APPEND_TO_CLASSPATH %%G + shift + goto :RUN_LOOP + +:EXECUTE_JNA + for %%G in (jna-*.jar) do call:APPEND_TO_CLASSPATH %%G + shift + goto :RUN_LOOP + +:EXECUTE_DEBUG + set "opts=%opts% -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" + shift + goto :RUN_LOOP + +:EXECUTE_DEBUGS + set "opts=%opts% -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" + shift + goto :RUN_LOOP + +:EXECUTE_MAIN +popd + +echo Launching ConsoleUI... +echo Classpath: %cp% +java -cp %cp% %opts% org.jline.consoleui.examples.Basic + +:END \ No newline at end of file diff --git a/console-ui/jline-console-ui.sh b/console-ui/jline-console-ui.sh new file mode 100755 index 000000000..f878b4fda --- /dev/null +++ b/console-ui/jline-console-ui.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +realpath() { + OURPWD=${PWD} + cd "$(dirname "${1}")" + LINK=$(readlink "$(basename "${1}")") + while [ "${LINK}" ]; do + cd "$(dirname "${LINK}")" + LINK=$(readlink "$(basename "${1}")") + done + REALPATH="${PWD}/$(basename "${1}")" + cd "${OURPWD}" + echo "${REALPATH}" +} + +REALNAME=$(realpath "$0") +DIRNAME=$(dirname "${REALNAME}") +PROGNAME=$(basename "${REALNAME}") +ROOTDIR=${DIRNAME}/.. +TARGETDIR=${DIRNAME}/target + +if [ ! -e ${TARGETDIR}/lib ] ; then + echo "Build jline with maven before running the demo" + exit +fi; + +cp=${TARGETDIR}/classes:${TARGETDIR}/test-classes +# JLINE +cp=${cp}$(find ${TARGETDIR}/lib -name "jline-*.jar" -exec printf :{} ';') + +opts="${JLINE_OPTS}" +while [ "${1}" != "" ]; do + case ${1} in + 'debug') + opts="${opts} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" + shift + ;; + 'debugs') + opts="${opts} -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" + shift + ;; + 'jansi') + cp=${cp}$(find ${TARGETDIR}/lib -name "jansi-*.jar" -exec printf :{} ';') + shift + ;; + 'jna') + cp=${cp}$(find ${TARGETDIR}/lib -name "jna-*.jar" -exec printf :{} ';') + shift + ;; + *) + opts="${opts} ${1}" + shift + ;; + esac +done + +cygwin=false +mingw=false +case "$(uname)" in + CYGWIN*) + cygwin=true + ;; + MINGW*) + mingw=true + ;; +esac +if ${cygwin}; then + cp=$(cygpath --path --windows "${cp}") + DIRNAME=$(cygpath --path --windows "${DIRNAME}") +fi + +nothing() { + # nothing to do here + a=a +} +trap 'nothing' TSTP + +echo "Launching ConsoleUI..." +echo "Classpath: $cp" +set mouse=a +java -cp $cp \ + $opts \ + org.jline.consoleui.examples.Basic + diff --git a/console-ui/pom.xml b/console-ui/pom.xml new file mode 100644 index 000000000..d9f3116fc --- /dev/null +++ b/console-ui/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + + org.jline + jline-parent + 3.25.1-SNAPSHOT + + + jline-console-ui + JLine Console UI + + + org.jline.consoleui + + + + + org.jline + jline-builtins + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + maven-dependency-plugin + + + copy + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + diff --git a/console-ui/settings.gradle b/console-ui/settings.gradle deleted file mode 100644 index 9222ea948..000000000 --- a/console-ui/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'consoleui' - diff --git a/console-ui/src/main/java/org/jline/consoleui/Basic.java b/console-ui/src/main/java/org/jline/consoleui/Basic.java deleted file mode 100644 index 75f9effde..000000000 --- a/console-ui/src/main/java/org/jline/consoleui/Basic.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.jline.consoleui; - -import org.jline.consoleui.elements.ConfirmChoice; -import org.jline.consoleui.prompt.ConfirmResult; -import org.jline.consoleui.prompt.ConsolePrompt; -import org.jline.consoleui.prompt.ConsolePrompt.UiConfig; -import org.jline.consoleui.prompt.PromptResultItemIF; -import org.jline.consoleui.prompt.builder.PromptBuilder; -import org.jline.builtins.Completers; -import org.jline.reader.LineReader; -import org.jline.reader.LineReaderBuilder; -import org.jline.terminal.Terminal; -import org.jline.terminal.TerminalBuilder; -import org.jline.utils.AttributedString; -import org.jline.utils.AttributedStringBuilder; -import org.jline.utils.AttributedStyle; -import org.jline.utils.OSUtils; - -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * User: Andreas Wegmann - * Date: 29.11.15 - */ -public class Basic { - - private static void addInHeader(List header, String text) { - addInHeader(header, AttributedStyle.DEFAULT, text); - } - - private static void addInHeader(List header, AttributedStyle style, String text) { - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.style(style).append(text); - header.add(asb.toAttributedString()); - } - - public static void main(String[] args) { - List header = new ArrayList<>(); - AttributedStyle style = new AttributedStyle(); - addInHeader(header, style.italic().foreground(2), "Hello World!"); - addInHeader(header, "This is a demonstration of ConsoleUI java library. It provides a simple console interface"); - addInHeader(header, "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written"); - addInHeader(header, "in JavaScript."); - try (Terminal terminal = TerminalBuilder.builder().build()) { - UiConfig config; - if (terminal.getType().equals(Terminal.TYPE_DUMB) || terminal.getType().equals(Terminal.TYPE_DUMB_COLOR)) { - System.out.println(terminal.getName() + ": " + terminal.getType()); - throw new IllegalStateException("Dumb terminal detected.\nConsoleUi requires real terminal to work!\n" - + "Note: On Windows Jansi or JNA library must be included in classpath."); - } else if (OSUtils.IS_WINDOWS) { - config = new UiConfig(">", "( )", "(x)", "( )"); - } else { - config = new UiConfig("\u276F", "\u25EF ", "\u25C9 ", "\u25EF "); - } - // - // LineReader is needed only if you are adding JLine Completers in your prompts. - // If you are not using Completers you do not need to create LineReader. - // - LineReader reader = LineReaderBuilder.builder().terminal(terminal).build(); - ConsolePrompt prompt = new ConsolePrompt(reader, terminal, config); - PromptBuilder promptBuilder = prompt.getPromptBuilder(); - - - promptBuilder.createInputPrompt() - .name("name") - .message("Please enter your name") - .defaultValue("John Doe") - //.mask('*') - .addCompleter(new Completers.FilesCompleter(() -> Paths.get(System.getProperty("user.dir")))) -// .addCompleter(new StringsCompleter("Jim", "Jack", "John")) - .addPrompt(); - - promptBuilder.createListPrompt() - .name("pizzatype") - .message("Which pizza do you want?") - .newItem().text("Margherita").add() // without name (name defaults to text) - .newItem("veneziana").text("Veneziana").add() - .newItem("hawai").text("Hawai").add() - .newItem("quattro").text("Quattro Stagioni").add() - .addPrompt(); - - promptBuilder.createCheckboxPrompt() - .name("topping") - .message("Please select additional toppings:") - - .newSeparator("standard toppings") - .add() - - .newItem().name("cheese").text("Cheese").add() - .newItem("bacon").text("Bacon").add() - .newItem("onions").text("Onions").disabledText("Sorry. Out of stock.").add() - - .newSeparator().text("special toppings").add() - - .newItem("salami").text("Very hot salami").check().add() - .newItem("salmon").text("Smoked Salmon").add() - - .newSeparator("and our speciality...").add() - - .newItem("special").text("Anchovies, and olives").checked(true).add() - .addPrompt(); - - promptBuilder.createChoicePrompt() - .name("payment") - .message("How do you want to pay?") - - .newItem().name("cash").message("Cash").key('c').asDefault().add() - .newItem("visa").message("Visa Card").key('v').add() - .newItem("master").message("Master Card").key('m').add() - .newSeparator("online payment").add() - .newItem("paypal").message("Paypal").key('p').add() - .addPrompt(); - - promptBuilder.createConfirmPromp() - .name("delivery") - .message("Is this pizza for delivery?") - .defaultValue(ConfirmChoice.ConfirmationValue.YES) - .addPrompt(); - - Map result = prompt.prompt(header, promptBuilder.build()); - System.out.println("result = " + result); - - ConfirmResult delivery = (ConfirmResult) result.get("delivery"); - if (delivery.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) { - System.out.println("We will deliver the pizza in 5 minutes"); - } - - } catch (Exception e) { - e.printStackTrace(); - } - - }} diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java b/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java index 4af69bdd6..69b1e77f3 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; /** @@ -6,19 +14,19 @@ */ public class AbstractPromptableElement implements PromptableElementIF { - protected String message; - protected String name; + protected String message; + protected String name; - public AbstractPromptableElement(String message, String name) { - this.message = message; - this.name = name; - } + public AbstractPromptableElement(String message, String name) { + this.message = message; + this.name = name; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public String getName() { - return name; - } + public String getName() { + return name; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java b/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java index 271b7903d..216860f92 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java @@ -1,44 +1,55 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; -import org.jline.consoleui.elements.items.CheckboxItemIF; - -import java.util.ArrayList; import java.util.List; +import org.jline.consoleui.elements.items.CheckboxItemIF; + /** * User: Andreas Wegmann * Date: 01.01.16 */ public class Checkbox extends AbstractPromptableElement { - private final int pageSize; - private final PageSizeType pageSizeType; - private List checkboxItemList; - - public Checkbox(String message, String name, int pageSize, PageSizeType pageSizeType, List checkboxItemList) { - super(message,name); - if (pageSizeType == PageSizeType.RELATIVE && (pageSize < 1 || pageSize >100)) - throw new IllegalArgumentException("for relative page size, the valid values are from 1 to 100"); - - this.pageSizeType = pageSizeType; - this.pageSize = pageSize; - this.checkboxItemList = checkboxItemList; - } - - public String getMessage() { - return message; - } - - public List getCheckboxItemList() { - return checkboxItemList; - } - - public int getPageSize() { - return pageSize; - } - - public PageSizeType getPageSizeType() { - return pageSizeType; - } - + private final int pageSize; + private final PageSizeType pageSizeType; + private final List checkboxItemList; + + public Checkbox( + String message, + String name, + int pageSize, + PageSizeType pageSizeType, + List checkboxItemList) { + super(message, name); + if (pageSizeType == PageSizeType.RELATIVE && (pageSize < 1 || pageSize > 100)) + throw new IllegalArgumentException("for relative page size, the valid values are from 1 to 100"); + + this.pageSizeType = pageSizeType; + this.pageSize = pageSize; + this.checkboxItemList = checkboxItemList; + } + + public String getMessage() { + return message; + } + + public List getCheckboxItemList() { + return checkboxItemList; + } + + public int getPageSize() { + return pageSize; + } + + public PageSizeType getPageSizeType() { + return pageSizeType; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java index 05e9efc2e..b3834f06b 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; /** @@ -6,20 +14,23 @@ */ public class ConfirmChoice extends AbstractPromptableElement { - public enum ConfirmationValue {YES, NO} + public enum ConfirmationValue { + YES, + NO + } - private ConfirmationValue defaultConfirmation = null; + private ConfirmationValue defaultConfirmation = null; - public ConfirmChoice(String message, String name) { - super(message, name); - } + public ConfirmChoice(String message, String name) { + super(message, name); + } - public ConfirmChoice(String message, String name, ConfirmationValue defaultConfirmation) { - super(message, name); - this.defaultConfirmation = defaultConfirmation; - } + public ConfirmChoice(String message, String name, ConfirmationValue defaultConfirmation) { + super(message, name); + this.defaultConfirmation = defaultConfirmation; + } - public ConfirmationValue getDefaultConfirmation() { - return defaultConfirmation; - } + public ConfirmationValue getDefaultConfirmation() { + return defaultConfirmation; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java index c5e53b7aa..2c2729411 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java @@ -1,25 +1,31 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; -import org.jline.consoleui.elements.items.ChoiceItemIF; - -import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; +import org.jline.consoleui.elements.items.ChoiceItemIF; + /** * User: Andreas Wegmann * Date: 07.01.16 */ public class ExpandableChoice extends AbstractPromptableElement { - private List choiceItems; + private final List choiceItems; - public ExpandableChoice(String message, String name, List choiceItems) { - super(message, name); - this.choiceItems = choiceItems; - } + public ExpandableChoice(String message, String name, List choiceItems) { + super(message, name); + this.choiceItems = choiceItems; + } - public List getChoiceItems() { - return choiceItems; - } + public List getChoiceItems() { + return choiceItems; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java b/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java index 2ed4a4843..1e0853b01 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; import org.jline.reader.Completer; @@ -7,47 +15,46 @@ * Date: 06.01.16 */ public class InputValue extends AbstractPromptableElement { - private String value; - private String defaultValue; - private Character mask; - private Completer completer; - - public InputValue(String name, String message) { - super(message, name); - this.value = null; - this.defaultValue = null; - } - - public InputValue(String name, String message, String value, String defaultValue) { - super(message, name); - //this.value = value; - if (value!=null) - throw new IllegalStateException("pre filled values for InputValue are not supported at the moment."); - this.defaultValue = defaultValue; - } - - public String getValue() { - return value; - } - - public String getDefaultValue() { - return defaultValue; - } - - public void setMask(Character mask) { - this.mask = mask; - } - - public Character getMask() { - return mask; - } - - public void setCompleter(Completer completer) { - this.completer = completer; - } - - public Completer getCompleter() { - return completer; - } - + private String value; + private final String defaultValue; + private Character mask; + private Completer completer; + + public InputValue(String name, String message) { + super(message, name); + this.value = null; + this.defaultValue = null; + } + + public InputValue(String name, String message, String value, String defaultValue) { + super(message, name); + // this.value = value; + if (value != null) + throw new IllegalStateException("pre filled values for InputValue are not supported at the moment."); + this.defaultValue = defaultValue; + } + + public String getValue() { + return value; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setMask(Character mask) { + this.mask = mask; + } + + public Character getMask() { + return mask; + } + + public void setCompleter(Completer completer) { + this.completer = completer; + } + + public Completer getCompleter() { + return completer; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java index 4e113cce2..65a4f1ead 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java @@ -1,44 +1,52 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; -import org.jline.consoleui.elements.items.ListItemIF; - -import java.util.ArrayList; import java.util.List; +import org.jline.consoleui.elements.items.ListItemIF; + /** * User: Andreas Wegmann * Date: 04.01.16 */ public class ListChoice extends AbstractPromptableElement { - private final int pageSize; - private final PageSizeType pageSizeType; - private List listItemList; + private final int pageSize; + private final PageSizeType pageSizeType; + private final List listItemList; - public ListChoice(String message, String name, int pageSize, PageSizeType pageSizeType, List listItemList) { - super(message,name); + public ListChoice( + String message, String name, int pageSize, PageSizeType pageSizeType, List listItemList) { + super(message, name); - if (pageSizeType == PageSizeType.RELATIVE && (pageSize < 1 || pageSize >100)) - throw new IllegalArgumentException("for relative page size, the valid values are from 1 to 100"); + if (pageSizeType == PageSizeType.RELATIVE && (pageSize < 1 || pageSize > 100)) + throw new IllegalArgumentException("for relative page size, the valid values are from 1 to 100"); - this.pageSizeType = pageSizeType; - this.pageSize = pageSize; - this.listItemList = listItemList; - } + this.pageSizeType = pageSizeType; + this.pageSize = pageSize; + this.listItemList = listItemList; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public List getListItemList() { - return listItemList; - } + public List getListItemList() { + return listItemList; + } - public int getPageSize() { - return pageSize; - } + public int getPageSize() { + return pageSize; + } - public PageSizeType getPageSizeType() { - return pageSizeType; - } + public PageSizeType getPageSizeType() { + return pageSizeType; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java b/console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java index 6a32a380a..63a7c9723 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/PageSizeType.java @@ -1,4 +1,14 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; -public enum PageSizeType { RELATIVE, ABSOLUTE } - +public enum PageSizeType { + RELATIVE, + ABSOLUTE +} diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java index 190370ba8..6a1e4f498 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements; /** @@ -6,6 +14,7 @@ */ public interface PromptableElementIF { - String getName(); - String getMessage(); + String getName(); + + String getMessage(); } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java index 9f6d9fe98..97ca42563 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items; /** diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java index f987e10dd..3d2ed8030 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items; /** diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java index 97c2d3614..a2513d709 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items; /** @@ -5,17 +13,17 @@ * Date: 01.01.16 */ public interface ConsoleUIItemIF { - boolean isSelectable(); + boolean isSelectable(); - String getName(); + String getName(); - default boolean isDisabled() { - return false; - } + default boolean isDisabled() { + return false; + } - String getText(); + String getText(); - default String getDisabledText() { - return ""; - } + default String getDisabledText() { + return ""; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java index 4dde51b30..d8f19b6a7 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java @@ -1,8 +1,15 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items; /** * User: Andreas Wegmann * Date: 01.01.16 */ -public interface ListItemIF extends ConsoleUIItemIF { -} +public interface ListItemIF extends ConsoleUIItemIF {} diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java index 6c151d2dc..ad2028a3c 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items.impl; import org.jline.consoleui.elements.items.CheckboxItemIF; @@ -8,83 +16,83 @@ * Date: 07.12.15 */ public class CheckboxItem implements CheckboxItemIF, ConsoleUIItemIF { - boolean checked; - String text; - String disabledText; - String name; - - public CheckboxItem(boolean checked, String text, String disabledText, String name) { - this.checked = checked; - this.text = text; - this.disabledText = disabledText; - this.name = name; - } - - public CheckboxItem(boolean checked, String text) { - this(checked, text, null, text); - } - - public CheckboxItem(String text) { - this(false, text, null, text); - } - - public CheckboxItem(String text, String disabledText) { - this(false, text, disabledText, text); - } - - public CheckboxItem() { - this(false, null, null, null); - } - - public boolean isChecked() { - return checked; - } - - public void setChecked(boolean checked) { - this.checked = checked; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public boolean isSelectable() { - return isEnabled(); - } - - public void setDisabled() { - disabledText = "disabled"; - } - - public void setDisabled(String disabledText) { - this.disabledText = disabledText; - } - - public void setEnabled() { - disabledText = null; - } - - public boolean isDisabled() { - return disabledText != null; - } - - public String getDisabledText() { - return disabledText; - } - - public boolean isEnabled() { - return disabledText == null; - } + boolean checked; + String text; + String disabledText; + String name; + + public CheckboxItem(boolean checked, String text, String disabledText, String name) { + this.checked = checked; + this.text = text; + this.disabledText = disabledText; + this.name = name; + } + + public CheckboxItem(boolean checked, String text) { + this(checked, text, null, text); + } + + public CheckboxItem(String text) { + this(false, text, null, text); + } + + public CheckboxItem(String text, String disabledText) { + this(false, text, disabledText, text); + } + + public CheckboxItem() { + this(false, null, null, null); + } + + public boolean isChecked() { + return checked; + } + + public void setChecked(boolean checked) { + this.checked = checked; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isSelectable() { + return isEnabled(); + } + + public void setDisabled() { + disabledText = "disabled"; + } + + public void setDisabled(String disabledText) { + this.disabledText = disabledText; + } + + public void setEnabled() { + disabledText = null; + } + + public boolean isDisabled() { + return disabledText != null; + } + + public String getDisabledText() { + return disabledText; + } + + public boolean isEnabled() { + return disabledText == null; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java index f51c86fc2..3984762c5 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items.impl; import org.jline.consoleui.elements.items.ChoiceItemIF; @@ -7,39 +15,39 @@ * Date: 07.01.16 */ public class ChoiceItem implements ChoiceItemIF { - private Character key; - private String name; - private String message; - private boolean defaultChoice; - - public ChoiceItem(Character key, String name, String message, boolean isDefaultChoice) { - this.key = key; - this.name = name; - this.message = message; - this.defaultChoice = isDefaultChoice; - } - - public Character getKey() { - return key; - } - - public String getName() { - return name; - } - - public String getMessage() { - return message; - } - - public String getText() { - return message; - } - - public boolean isSelectable() { - return true; - } - - public boolean isDefaultChoice() { - return defaultChoice; - } + private final Character key; + private final String name; + private final String message; + private final boolean defaultChoice; + + public ChoiceItem(Character key, String name, String message, boolean isDefaultChoice) { + this.key = key; + this.name = name; + this.message = message; + this.defaultChoice = isDefaultChoice; + } + + public Character getKey() { + return key; + } + + public String getName() { + return name; + } + + public String getMessage() { + return message; + } + + public String getText() { + return message; + } + + public boolean isSelectable() { + return true; + } + + public boolean isDefaultChoice() { + return defaultChoice; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java index 285e05e43..cb867f8d1 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items.impl; import org.jline.consoleui.elements.items.ListItemIF; @@ -7,39 +15,39 @@ * Date: 01.01.16 */ public class ListItem implements ListItemIF { - String text; - String name; - - public ListItem(String text, String name) { - this.text = text; - if (name == null) { - this.name = text; - } else { - this.name = name; + String text; + String name; + + public ListItem(String text, String name) { + this.text = text; + if (name == null) { + this.name = text; + } else { + this.name = name; + } } - } - public ListItem(String text) { - this(text, text); - } + public ListItem(String text) { + this(text, text); + } - public ListItem() { - this(null, null); - } + public ListItem() { + this(null, null); + } - public String getText() { - return text; - } + public String getText() { + return text; + } - public void setText(String text) { - this.text = text; - } + public void setText(String text) { + this.text = text; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public boolean isSelectable() { - return true; - } + public boolean isSelectable() { + return true; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java index 1a0f79048..cce29a3ff 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.elements.items.impl; import org.jline.consoleui.elements.items.CheckboxItemIF; @@ -9,30 +17,28 @@ * Date: 01.01.16 */ public class Separator implements CheckboxItemIF, ListItemIF, ChoiceItemIF { - private String message; - - public Separator(String message) { - this.message = message; - } + private String message; - public Separator() { - } + public Separator(String message) { + this.message = message; + } - public String getMessage() { - return message; - } + public Separator() {} - public String getText() { - return message; - } + public String getMessage() { + return message; + } - public boolean isSelectable() { - return false; - } + public String getText() { + return message; + } - @Override - public String getName() { - return null; - } + public boolean isSelectable() { + return false; + } + @Override + public String getName() { + return null; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/examples/LongList.java b/console-ui/src/main/java/org/jline/consoleui/examples/LongList.java deleted file mode 100644 index b5eccc9c5..000000000 --- a/console-ui/src/main/java/org/jline/consoleui/examples/LongList.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.jline.consoleui.examples; - -import org.jline.consoleui.prompt.ConsolePrompt; -import org.jline.consoleui.prompt.ConsolePrompt.UiConfig; -import org.jline.consoleui.prompt.PromptResultItemIF; -import org.jline.consoleui.prompt.builder.CheckboxPromptBuilder; -import org.jline.consoleui.prompt.builder.ListPromptBuilder; -import org.jline.consoleui.prompt.builder.PromptBuilder; -import org.jline.terminal.Terminal; -import org.jline.terminal.TerminalBuilder; -import org.jline.utils.AttributedString; -import org.jline.utils.AttributedStringBuilder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * User: Andreas Wegmann - * Date: 29.11.15 - */ -public class LongList { - - public static void main(String[] args) { - List header = new ArrayList<>(); - header.add(new AttributedStringBuilder() - .append("This is a demonstration of ConsoleUI java library. It provides a simple console interface").toAttributedString()); - header.add(new AttributedStringBuilder() - .append("for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written").toAttributedString()); - header.add(new AttributedStringBuilder() - .append("in JavaScript.").toAttributedString()); - - try (Terminal terminal = TerminalBuilder.builder().build()) { - UiConfig config = new UiConfig(">", "( )", "(x)", "( )"); - ConsolePrompt prompt = new ConsolePrompt(terminal, config); - PromptBuilder promptBuilder = prompt.getPromptBuilder(); - - ListPromptBuilder listPrompt = promptBuilder.createListPrompt(); - listPrompt.name("longlist").message("What's your favourite Letter?").relativePageSize(66); - - for (char letter = 'A'; letter <= 'C'; letter++) - for (char letter2 = 'A'; letter2 <= 'Z'; letter2++) - listPrompt.newItem().text("" + letter + letter2).add(); - listPrompt.addPrompt(); - - CheckboxPromptBuilder checkboxPrompt = promptBuilder.createCheckboxPrompt(); - checkboxPrompt.name("longcheckbox").message("What's your favourite Letter? Select all you want...").relativePageSize(66); - - for (char letter = 'A'; letter <= 'C'; letter++) - for (char letter2 = 'A'; letter2 <= 'Z'; letter2++) - checkboxPrompt.newItem().text("" + letter + letter2).add(); - checkboxPrompt.addPrompt(); - - Map result = prompt.prompt(header, promptBuilder.build()); - System.out.println("result = " + result); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java b/console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java deleted file mode 100644 index 22b627b2c..000000000 --- a/console-ui/src/main/java/org/jline/consoleui/examples/SimpleExample.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.jline.consoleui.examples; - -import org.jline.consoleui.prompt.ConsolePrompt; -import org.jline.consoleui.prompt.PromptResultItemIF; -import org.jline.consoleui.prompt.builder.PromptBuilder; -import org.jline.terminal.Terminal; -import org.jline.terminal.TerminalBuilder; -import org.jline.utils.AttributedString; -import org.jline.utils.AttributedStringBuilder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * User: Andreas Wegmann - * Date: 12.08.2020 - */ -public class SimpleExample { - - public static void main(String[] args) { - List header = new ArrayList<>(); - header.add(new AttributedStringBuilder().append("Simple list example:").toAttributedString()); - - try (Terminal terminal = TerminalBuilder.builder().build()) { - ConsolePrompt prompt = new ConsolePrompt(terminal); - PromptBuilder promptBuilder = prompt.getPromptBuilder(); - - promptBuilder.createListPrompt() - .name("pizzatype") - .message("Which pizza do you want?") - .newItem().text("Margherita").add() // without name (name defaults to text) - .newItem("veneziana").text("Veneziana").add() - .newItem("hawai").text("Hawai").add() - .newItem("quattro").text("Quattro Stagioni").add() - .addPrompt(); - - Map result = prompt.prompt(header, promptBuilder.build()); - System.out.println("result = " + result); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java b/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java index ba684152c..fc1a883e5 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java @@ -1,5 +1,17 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.jline.consoleui.elements.Checkbox; import org.jline.consoleui.elements.ConfirmChoice; import org.jline.consoleui.elements.ExpandableChoice; @@ -20,10 +32,6 @@ import org.jline.terminal.Terminal; import org.jline.utils.*; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import static org.jline.keymap.KeyMap.*; /** @@ -31,755 +39,871 @@ * * @author Matti Rinta-Nikkola */ -public abstract class AbstractPrompt { - protected final Terminal terminal; - protected final BindingReader bindingReader; - private final List header; - private final AttributedString message; - protected final List items; - protected int firstItemRow; - private final Size size = new Size(); - protected final ConsolePrompt.UiConfig config; - private Display display; - private ListRange range = null; - - public AbstractPrompt(Terminal terminal, List header, AttributedString message, ConsolePrompt.UiConfig cfg) { - this(terminal, header, message, new ArrayList<>(), cfg); - } - - public AbstractPrompt(Terminal terminal, List header, AttributedString message, List items - , ConsolePrompt.UiConfig cfg) { - this.terminal = terminal; - this.bindingReader = new BindingReader(terminal.reader()); - this.header = header; - this.message = message; - this.items = items; - this.firstItemRow = header.size() + 1; - this.config = cfg; - } - - protected void resetHeader() { - this.firstItemRow = header.size() + 1; - } - - protected void resetDisplay() { - display = new Display(terminal, true); - size.copy(terminal.getSize()); - display.clear(); - display.reset(); - } - - protected void refreshDisplay(int row) { - refreshDisplay(row, 0, null, false); - } - - protected void refreshDisplay(int row, Set selected) { - display.resize(size.getRows(), size.getColumns()); - display.reset(); - display.update(displayLines(row, selected), size.cursorPos(Math.min(size.getRows() - 1, firstItemRow + items.size()) - , 0)); - } - - protected void refreshDisplay(int row, int column, String buffer, boolean newline) { - display.resize(size.getRows(), size.getColumns()); - AttributedStringBuilder asb = new AttributedStringBuilder(); - int crow = column == 0 ? Math.min(size.getRows() - 1, firstItemRow + items.size()) : row; - if (buffer != null) { - if (newline && !buffer.isEmpty()) { - asb.style(config.style(".pr")).append(">> "); - } - asb.style(AttributedStyle.DEFAULT).append(buffer); - } - display.update(displayLines(row, asb.toAttributedString(), newline), size.cursorPos(crow, column)); - } - - protected void refreshDisplay(int buffRow, int buffCol, String buffer, int candRow, int candCol, List candidates) { - display.resize(size.getRows(), size.getColumns()); - AttributedStringBuilder asb = new AttributedStringBuilder(); - if (buffer != null) { - asb.style(AttributedStyle.DEFAULT).append(buffer); - } - display.update(displayLines(candRow, candCol, asb.toAttributedString(), candidates), size.cursorPos(buffRow, buffCol)); - } - - private int candidateStartPosition(int candidatesColumn, String buffer, List cands) { - List values = cands.stream().map(c -> AttributedString.stripAnsi(c.displ())) - .filter(c -> !c.matches("\\w+") && c.length() > 1).collect(Collectors.toList()); - Set notDelimiters = new HashSet<>(); - values.forEach(v -> v.substring(0, v.length() - 1).chars() - .filter(c -> !Character.isDigit(c) && !Character.isAlphabetic(c)) - .forEach(c -> notDelimiters.add(Character.toString((char)c)))); - int out = candidatesColumn; - for (int i = buffer.length(); i > 0; i--) { - if (buffer.substring(0, i).matches(".*\\W") - && !notDelimiters.contains(buffer.substring(i - 1, i))) { - out += i; - break; - } - } - return out; - } - - private List displayLines(int cursorRow, int candidatesColumn, AttributedString buffer - , List candidates) { - computeListRange(cursorRow, candidates.size()); - List out = new ArrayList<>(); - for (int i = range.headerStart; i < header.size(); i++) { - out.add(header.get(i)); - } - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.append(message); - asb.append(buffer); - out.add(asb.toAttributedString()); - int listStart; - if (cursorRow - firstItemRow >= 0) { - String dc = candidates.get(cursorRow - firstItemRow).displ(); - listStart = candidatesColumn + buffer.columnLength() - display.wcwidth(dc) - + (AttributedString.stripAnsi(dc).endsWith("*") ? 1 : 0); - } else { - listStart = candidateStartPosition(candidatesColumn, buffer.toString(), candidates); - } - int width = Math.max(candidates.stream().map(Candidate::displ).mapToInt(display::wcwidth).max().orElse(20), 20); - for (int i = range.first; i < range.last - 1; i++) { - Candidate c = candidates.get(i); - asb = new AttributedStringBuilder(); - AttributedStringBuilder tmp = new AttributedStringBuilder(); - tmp.ansiAppend(c.displ()); - asb.style(tmp.styleAt(0)); - if (i + firstItemRow == cursorRow) { - asb.style(new AttributedStyle().inverse()); - } - asb.append(AttributedString.stripAnsi(c.displ())); - int cl = asb.columnLength(); - for (int k = cl; k < width; k++) { - asb.append(" "); - } - AttributedStringBuilder asb2 = new AttributedStringBuilder(); - asb2.tabs(listStart); - asb2.append("\t"); - asb2.style(config.style(".cb")); - asb2.append(asb).append(" "); - out.add(asb2.toAttributedString()); +public abstract class AbstractPrompt { + protected final Terminal terminal; + protected final BindingReader bindingReader; + private final List header; + private final AttributedString message; + protected final List items; + protected int firstItemRow; + private final Size size = new Size(); + protected final ConsolePrompt.UiConfig config; + private Display display; + private ListRange range = null; + + public AbstractPrompt( + Terminal terminal, List header, AttributedString message, ConsolePrompt.UiConfig cfg) { + this(terminal, header, message, new ArrayList<>(), cfg); + } + + public AbstractPrompt( + Terminal terminal, + List header, + AttributedString message, + List items, + ConsolePrompt.UiConfig cfg) { + this.terminal = terminal; + this.bindingReader = new BindingReader(terminal.reader()); + this.header = header; + this.message = message; + this.items = items; + this.firstItemRow = header.size() + 1; + this.config = cfg; + } + + protected void resetHeader() { + this.firstItemRow = header.size() + 1; + } + + protected void resetDisplay() { + display = new Display(terminal, true); + size.copy(terminal.getSize()); + display.clear(); + display.reset(); + } + + protected void refreshDisplay(int row) { + refreshDisplay(row, 0, null, false); + } + + protected void refreshDisplay(int row, Set selected) { + display.resize(size.getRows(), size.getColumns()); + display.reset(); + display.update( + displayLines(row, selected), + size.cursorPos(Math.min(size.getRows() - 1, firstItemRow + items.size()), 0)); + } + + protected void refreshDisplay(int row, int column, String buffer, boolean newline) { + display.resize(size.getRows(), size.getColumns()); + AttributedStringBuilder asb = new AttributedStringBuilder(); + int crow = column == 0 ? Math.min(size.getRows() - 1, firstItemRow + items.size()) : row; + if (buffer != null) { + if (newline && !buffer.isEmpty()) { + asb.style(config.style(".pr")).append(">> "); + } + asb.style(AttributedStyle.DEFAULT).append(buffer); + } + display.update(displayLines(row, asb.toAttributedString(), newline), size.cursorPos(crow, column)); } - addFooter(out, candidates.size()); - return out; - } - - private List displayLines(int cursorRow, Set selected) { - computeListRange(cursorRow, items.size()); - List out = new ArrayList<>(); - for (int i = range.headerStart; i < header.size(); i++) { - out.add(header.get(i)); + + protected void refreshDisplay( + int buffRow, int buffCol, String buffer, int candRow, int candCol, List candidates) { + display.resize(size.getRows(), size.getColumns()); + AttributedStringBuilder asb = new AttributedStringBuilder(); + if (buffer != null) { + asb.style(AttributedStyle.DEFAULT).append(buffer); + } + display.update( + displayLines(candRow, candCol, asb.toAttributedString(), candidates), size.cursorPos(buffRow, buffCol)); + } + + private int candidateStartPosition(int candidatesColumn, String buffer, List cands) { + List values = cands.stream() + .map(c -> AttributedString.stripAnsi(c.displ())) + .filter(c -> !c.matches("\\w+") && c.length() > 1) + .collect(Collectors.toList()); + Set notDelimiters = new HashSet<>(); + values.forEach(v -> v.substring(0, v.length() - 1) + .chars() + .filter(c -> !Character.isDigit(c) && !Character.isAlphabetic(c)) + .forEach(c -> notDelimiters.add(Character.toString((char) c)))); + int out = candidatesColumn; + for (int i = buffer.length(); i > 0; i--) { + if (buffer.substring(0, i).matches(".*\\W") && !notDelimiters.contains(buffer.substring(i - 1, i))) { + out += i; + break; + } + } + return out; } - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.append(message); - out.add(asb.toAttributedString()); - for (int i = range.first; i < range.last - 1; i++) { - ConsoleUIItemIF s = items.get(i); - asb = new AttributedStringBuilder(); - if (s.isSelectable()) { - asb = i + firstItemRow == cursorRow ? asb.append(config.indicator()).style(AttributedStyle.DEFAULT).append(" ") - : fillIndicatorSpace(asb).append(" "); - asb = selected.contains(s.getName()) ? asb.append(config.checkedBox()) - : asb.append(config.uncheckedBox()); - } else if (s instanceof CheckboxItem) { - fillIndicatorSpace(asb); - asb.append(" "); - if (s.isDisabled()) { - asb.append(config.unavailable()); + + private List displayLines( + int cursorRow, int candidatesColumn, AttributedString buffer, List candidates) { + computeListRange(cursorRow, candidates.size()); + List out = new ArrayList<>(); + for (int i = range.headerStart; i < header.size(); i++) { + out.add(header.get(i)); + } + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + asb.append(buffer); + out.add(asb.toAttributedString()); + int listStart; + if (cursorRow - firstItemRow >= 0) { + String dc = candidates.get(cursorRow - firstItemRow).displ(); + listStart = candidatesColumn + + buffer.columnLength() + - display.wcwidth(dc) + + (AttributedString.stripAnsi(dc).endsWith("*") ? 1 : 0); } else { - fillCheckboxSpace(asb); - } - } - asb.append(s.getText()).toAttributedString(); - if (s.isDisabled()) { - asb.append(" (").append(s.getDisabledText()).append(")"); - } - out.add(asb.toAttributedString()); + listStart = candidateStartPosition(candidatesColumn, buffer.toString(), candidates); + } + int width = Math.max( + candidates.stream() + .map(Candidate::displ) + .mapToInt(display::wcwidth) + .max() + .orElse(20), + 20); + for (int i = range.first; i < range.last - 1; i++) { + Candidate c = candidates.get(i); + asb = new AttributedStringBuilder(); + AttributedStringBuilder tmp = new AttributedStringBuilder(); + tmp.ansiAppend(c.displ()); + asb.style(tmp.styleAt(0)); + if (i + firstItemRow == cursorRow) { + asb.style(new AttributedStyle().inverse()); + } + asb.append(AttributedString.stripAnsi(c.displ())); + int cl = asb.columnLength(); + for (int k = cl; k < width; k++) { + asb.append(" "); + } + AttributedStringBuilder asb2 = new AttributedStringBuilder(); + asb2.tabs(listStart); + asb2.append("\t"); + asb2.style(config.style(".cb")); + asb2.append(asb).append(" "); + out.add(asb2.toAttributedString()); + } + addFooter(out, candidates.size()); + return out; } - addFooter(out, items.size()); // footer is necessary for making the long item list scroll correctly - return out; - } - private AttributedStringBuilder fillIndicatorSpace(AttributedStringBuilder asb) { - for (int i = 0; i < config.indicator().length(); i++) { - asb.append(" "); + private List displayLines(int cursorRow, Set selected) { + computeListRange(cursorRow, items.size()); + List out = new ArrayList<>(); + for (int i = range.headerStart; i < header.size(); i++) { + out.add(header.get(i)); + } + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + out.add(asb.toAttributedString()); + for (int i = range.first; i < range.last - 1; i++) { + ConsoleUIItemIF s = items.get(i); + asb = new AttributedStringBuilder(); + if (s.isSelectable()) { + asb = i + firstItemRow == cursorRow + ? asb.append(config.indicator()) + .style(AttributedStyle.DEFAULT) + .append(" ") + : fillIndicatorSpace(asb).append(" "); + asb = selected.contains(s.getName()) + ? asb.append(config.checkedBox()) + : asb.append(config.uncheckedBox()); + } else if (s instanceof CheckboxItem) { + fillIndicatorSpace(asb); + asb.append(" "); + if (s.isDisabled()) { + asb.append(config.unavailable()); + } else { + fillCheckboxSpace(asb); + } + } + asb.append(s.getText()).toAttributedString(); + if (s.isDisabled()) { + asb.append(" (").append(s.getDisabledText()).append(")"); + } + out.add(asb.toAttributedString()); + } + addFooter(out, items.size()); // footer is necessary for making the long item list scroll correctly + return out; } - return asb; - } - private void fillCheckboxSpace(AttributedStringBuilder asb) { - for (int i = 0; i < config.checkedBox().length(); i++) { - asb.append(" "); + private AttributedStringBuilder fillIndicatorSpace(AttributedStringBuilder asb) { + for (int i = 0; i < config.indicator().length(); i++) { + asb.append(" "); + } + return asb; } - } - - private static class ListRange { - final int first; - final int last; - final int headerStart; - public ListRange(int headerStart, int first, int last) { - this.headerStart = headerStart; - this.first = first; - this.last = last; + private void fillCheckboxSpace(AttributedStringBuilder asb) { + for (int i = 0; i < config.checkedBox().length(); i++) { + asb.append(" "); + } } - } - private void computeListRange(int cursorRow, int itemsSize) { - if (range != null && range.first <= cursorRow - firstItemRow && range.last - 1 > cursorRow - firstItemRow) { - return; - } - range = new ListRange(0, 0, itemsSize + 1); - if (size.getRows() < header.size() + itemsSize + 1) { - int itemId = cursorRow - firstItemRow; - int headerStart = header.size() + 1 > 10 ? header.size() - 9 : 0; - firstItemRow = firstItemRow - headerStart; - int forList = size.getRows() - header.size() + headerStart - 1; - if (itemId < forList - 1) { - range = new ListRange(headerStart, 0, forList); - } else { - range = new ListRange(headerStart, itemId - forList + 2, itemId + 2); - } - } - } + private static class ListRange { + final int first; + final int last; + final int headerStart; - private void addFooter(List lines, int itemsSize) { - if (size.getRows() < header.size() + itemsSize + 1) { - AttributedStringBuilder asb = new AttributedStringBuilder(); - lines.add(asb.append(".").toAttributedString()); + public ListRange(int headerStart, int first, int last) { + this.headerStart = headerStart; + this.first = first; + this.last = last; + } } - } - private List displayLines(int cursorRow, AttributedString buffer, boolean newline) { - computeListRange(cursorRow, items.size()); - List out = new ArrayList<>(); - for (int i = range.headerStart; i < header.size(); i++) { - out.add(header.get(i)); - } - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.append(message); - if (buffer != null && !newline) { - asb.append(buffer); - } - out.add(asb.toAttributedString()); - if (buffer != null && newline) { - asb = new AttributedStringBuilder(); - asb.append(buffer); - out.add(asb.toAttributedString()); - } - for (int i = range.first; i < range.last - 1; i++) { - ConsoleUIItemIF s = items.get(i); - asb = new AttributedStringBuilder(); - String key = s instanceof ChoiceItem ? ((ChoiceItem)s).getKey() + " - " : ""; - if (i + firstItemRow == cursorRow) { - out.add(asb.append(config.indicator()).style(config.style(".se")).append(" ").append(key) - .append(s.getText()).toAttributedString()); - } else if (!(s instanceof Separator)) { - fillIndicatorSpace(asb); - out.add(asb.append(" ").append(key).append(s.getText()).toAttributedString()); - } else { - out.add(asb.append(s.getText()).toAttributedString()); - } - } - addFooter(out, items.size()); - return out; - } - - protected static class ExpandableChoicePrompt extends AbstractPrompt { - private enum Operation {INSERT, EXIT} - private final int startColumn; - private final List items; - private final ConsolePrompt.UiConfig config; - - private ExpandableChoicePrompt(Terminal terminal, List header, AttributedString message - , ExpandableChoice expandableChoice, ConsolePrompt.UiConfig cfg) { - super(terminal, header, message, cfg); - startColumn = message.columnLength(); - items = expandableChoice.getChoiceItems(); - config = cfg; + private void computeListRange(int cursorRow, int itemsSize) { + if (range != null && range.first <= cursorRow - firstItemRow && range.last - 1 > cursorRow - firstItemRow) { + return; + } + range = new ListRange(0, 0, itemsSize + 1); + if (size.getRows() < header.size() + itemsSize + 1) { + int itemId = cursorRow - firstItemRow; + int headerStart = header.size() + 1 > 10 ? header.size() - 9 : 0; + firstItemRow = firstItemRow - headerStart; + int forList = size.getRows() - header.size() + headerStart - 1; + if (itemId < forList - 1) { + range = new ListRange(headerStart, 0, forList); + } else { + range = new ListRange(headerStart, itemId - forList + 2, itemId + 2); + } + } } - public static ExpandableChoicePrompt getPrompt(Terminal terminal, List header, AttributedString message - , ExpandableChoice expandableChoice, ConsolePrompt.UiConfig cfg) { - return new ExpandableChoicePrompt(terminal, header, message, expandableChoice, cfg); + private void addFooter(List lines, int itemsSize) { + if (size.getRows() < header.size() + itemsSize + 1) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + lines.add(asb.append(".").toAttributedString()); + } } - private void bindKeys(KeyMap map) { - for (char i = 32; i < KEYMAP_LENGTH; i++) { - map.bind(Operation.INSERT, Character.toString(i)); - } - map.bind(Operation.EXIT,"\r"); + private List displayLines(int cursorRow, AttributedString buffer, boolean newline) { + computeListRange(cursorRow, items.size()); + List out = new ArrayList<>(); + for (int i = range.headerStart; i < header.size(); i++) { + out.add(header.get(i)); + } + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + if (buffer != null && !newline) { + asb.append(buffer); + } + out.add(asb.toAttributedString()); + if (buffer != null && newline) { + asb = new AttributedStringBuilder(); + asb.append(buffer); + out.add(asb.toAttributedString()); + } + for (int i = range.first; i < range.last - 1; i++) { + ConsoleUIItemIF s = items.get(i); + asb = new AttributedStringBuilder(); + String key = s instanceof ChoiceItem ? ((ChoiceItem) s).getKey() + " - " : ""; + if (i + firstItemRow == cursorRow) { + out.add(asb.append(config.indicator()) + .style(config.style(".se")) + .append(" ") + .append(key) + .append(s.getText()) + .toAttributedString()); + } else if (!(s instanceof Separator)) { + fillIndicatorSpace(asb); + out.add(asb.append(" ").append(key).append(s.getText()).toAttributedString()); + } else { + out.add(asb.append(s.getText()).toAttributedString()); + } + } + addFooter(out, items.size()); + return out; } - public ExpandableChoiceResult execute() { - resetDisplay(); - int row = firstItemRow - 1; - KeyMap keyMap = new KeyMap<>(); - bindKeys(keyMap); - StringBuilder buffer = new StringBuilder(); - String selectedId = null; - boolean expandChoiceList = false; - for (ChoiceItemIF cu : items) { - if (cu.isSelectable() && cu.isDefaultChoice()) { - selectedId = cu.getName(); - break; - } - } - while (true) { - refreshDisplay(row, startColumn, buffer.toString(), true); - Operation op = bindingReader.readBinding(keyMap); - buffer = new StringBuilder(); - switch (op) { - case INSERT: - String ch = bindingReader.getLastBinding(); - if (ch.equals("h")) { - expandChoiceList = true; - buffer.append(config.resourceBundle().getString("help.list.all.options")); - } else { - selectedId = null; - expandChoiceList = false; - boolean found = false; - for (ChoiceItemIF cu : items) { - if (cu.isSelectable() && cu.getKey().toString().equals(ch)) { - selectedId = cu.getName(); - buffer.append(selectedId); - found = true; - break; + protected static class ExpandableChoicePrompt extends AbstractPrompt { + private enum Operation { + INSERT, + EXIT + } + + private final int startColumn; + private final List items; + private final ConsolePrompt.UiConfig config; + + private ExpandableChoicePrompt( + Terminal terminal, + List header, + AttributedString message, + ExpandableChoice expandableChoice, + ConsolePrompt.UiConfig cfg) { + super(terminal, header, message, cfg); + startColumn = message.columnLength(); + items = expandableChoice.getChoiceItems(); + config = cfg; + } + + public static ExpandableChoicePrompt getPrompt( + Terminal terminal, + List header, + AttributedString message, + ExpandableChoice expandableChoice, + ConsolePrompt.UiConfig cfg) { + return new ExpandableChoicePrompt(terminal, header, message, expandableChoice, cfg); + } + + private void bindKeys(KeyMap map) { + for (char i = 32; i < KEYMAP_LENGTH; i++) { + map.bind(Operation.INSERT, Character.toString(i)); + } + map.bind(Operation.EXIT, "\r"); + } + + public ExpandableChoiceResult execute() { + resetDisplay(); + int row = firstItemRow - 1; + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + StringBuilder buffer = new StringBuilder(); + String selectedId = null; + boolean expandChoiceList = false; + for (ChoiceItemIF cu : items) { + if (cu.isSelectable() && cu.isDefaultChoice()) { + selectedId = cu.getName(); + break; } - } - if (!found) { - buffer.append(config.resourceBundle().getString("please.enter.a.valid.command")); - } } - break; - case EXIT: - if (selectedId == null || expandChoiceList) { - if (expandChoiceList) { - throw new ExpandableChoiceException(); - } - break; + while (true) { + refreshDisplay(row, startColumn, buffer.toString(), true); + Operation op = bindingReader.readBinding(keyMap); + buffer = new StringBuilder(); + switch (op) { + case INSERT: + String ch = bindingReader.getLastBinding(); + if (ch.equals("h")) { + expandChoiceList = true; + buffer.append(config.resourceBundle().getString("help.list.all.options")); + } else { + selectedId = null; + expandChoiceList = false; + boolean found = false; + for (ChoiceItemIF cu : items) { + if (cu.isSelectable() && cu.getKey().toString().equals(ch)) { + selectedId = cu.getName(); + buffer.append(selectedId); + found = true; + break; + } + } + if (!found) { + buffer.append(config.resourceBundle().getString("please.enter.a.valid.command")); + } + } + break; + case EXIT: + if (selectedId == null || expandChoiceList) { + if (expandChoiceList) { + throw new ExpandableChoiceException(); + } + break; + } + return new ExpandableChoiceResult(selectedId); + } } - return new ExpandableChoiceResult(selectedId); } - } } - } - - @SuppressWarnings("serial") - protected static class ExpandableChoiceException extends RuntimeException { - } + @SuppressWarnings("serial") + protected static class ExpandableChoiceException extends RuntimeException {} - protected static class ConfirmPrompt extends AbstractPrompt { - private enum Operation {NO, YES, EXIT} - private final int startColumn; - private final ConfirmChoice.ConfirmationValue defaultValue; - private final ConsolePrompt.UiConfig config; + protected static class ConfirmPrompt extends AbstractPrompt { + private enum Operation { + NO, + YES, + EXIT + } - private ConfirmPrompt(Terminal terminal, List header, AttributedString message - , ConfirmChoice confirmChoice, ConsolePrompt.UiConfig cfg) { - super(terminal, header, message, cfg); - startColumn = message.columnLength(); - defaultValue = confirmChoice.getDefaultConfirmation(); - config = cfg; - } + private final int startColumn; + private final ConfirmChoice.ConfirmationValue defaultValue; + private final ConsolePrompt.UiConfig config; + + private ConfirmPrompt( + Terminal terminal, + List header, + AttributedString message, + ConfirmChoice confirmChoice, + ConsolePrompt.UiConfig cfg) { + super(terminal, header, message, cfg); + startColumn = message.columnLength(); + defaultValue = confirmChoice.getDefaultConfirmation(); + config = cfg; + } - public static ConfirmPrompt getPrompt(Terminal terminal, List header, AttributedString message - , ConfirmChoice confirmChoice, ConsolePrompt.UiConfig cfg) { - return new ConfirmPrompt(terminal, header, message, confirmChoice, cfg); - } + public static ConfirmPrompt getPrompt( + Terminal terminal, + List header, + AttributedString message, + ConfirmChoice confirmChoice, + ConsolePrompt.UiConfig cfg) { + return new ConfirmPrompt(terminal, header, message, confirmChoice, cfg); + } - private void bindKeys(KeyMap map) { - String yes = config.resourceBundle().getString("confirmation_yes_key"); - String no = config.resourceBundle().getString("confirmation_no_key"); - map.bind(Operation.YES, yes, yes.toUpperCase()); - map.bind(Operation.NO, no, no.toUpperCase()); - map.bind(Operation.EXIT,"\r"); - } + private void bindKeys(KeyMap map) { + String yes = config.resourceBundle().getString("confirmation_yes_key"); + String no = config.resourceBundle().getString("confirmation_no_key"); + map.bind(Operation.YES, yes, yes.toUpperCase()); + map.bind(Operation.NO, no, no.toUpperCase()); + map.bind(Operation.EXIT, "\r"); + } - public ConfirmResult execute() { - resetDisplay(); - int row = firstItemRow - 1; - int column = startColumn; - KeyMap keyMap = new KeyMap<>(); - bindKeys(keyMap); - StringBuilder buffer = new StringBuilder(); - ConfirmChoice.ConfirmationValue confirm = defaultValue; - while (true) { - refreshDisplay(row, column, buffer.toString(), false); - Operation op = bindingReader.readBinding(keyMap); - buffer = new StringBuilder(); - switch (op) { - case YES: - buffer.append(config.resourceBundle().getString("confirmation_yes_answer")); - confirm = ConfirmChoice.ConfirmationValue.YES; - column = startColumn + 3; - break; - case NO: - buffer.append(config.resourceBundle().getString("confirmation_no_answer")); - confirm = ConfirmChoice.ConfirmationValue.NO; - column = startColumn + 2; - break; - case EXIT: - if (confirm == null) { - break; + public ConfirmResult execute() { + resetDisplay(); + int row = firstItemRow - 1; + int column = startColumn; + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + StringBuilder buffer = new StringBuilder(); + ConfirmChoice.ConfirmationValue confirm = defaultValue; + while (true) { + refreshDisplay(row, column, buffer.toString(), false); + Operation op = bindingReader.readBinding(keyMap); + buffer = new StringBuilder(); + switch (op) { + case YES: + buffer.append(config.resourceBundle().getString("confirmation_yes_answer")); + confirm = ConfirmChoice.ConfirmationValue.YES; + column = startColumn + 3; + break; + case NO: + buffer.append(config.resourceBundle().getString("confirmation_no_answer")); + confirm = ConfirmChoice.ConfirmationValue.NO; + column = startColumn + 2; + break; + case EXIT: + if (confirm == null) { + break; + } + return new ConfirmResult(confirm); + } } - return new ConfirmResult(confirm); } - } } - } - - protected static class InputValuePrompt extends AbstractPrompt { - private enum Operation {INSERT, BACKSPACE, DELETE, RIGHT, LEFT, BEGINNING_OF_LINE, END_OF_LINE, SELECT_CANDIDATE, EXIT} - private enum SelectOp {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, EXIT} - private final int startColumn; - private final String defaultValue; - private final Character mask; - private final LineReader reader; - private final Completer completer; - - private InputValuePrompt(LineReader reader, Terminal terminal, List header, AttributedString message - , InputValue inputValue, ConsolePrompt.UiConfig cfg) { - super(terminal, header, message, cfg); - this.reader = reader; - defaultValue = inputValue.getDefaultValue(); - startColumn = message.columnLength(); - mask = inputValue.getMask(); - this.completer = inputValue.getCompleter(); - } + protected static class InputValuePrompt extends AbstractPrompt { + private enum Operation { + INSERT, + BACKSPACE, + DELETE, + RIGHT, + LEFT, + BEGINNING_OF_LINE, + END_OF_LINE, + SELECT_CANDIDATE, + EXIT + } - public static InputValuePrompt getPrompt(LineReader reader, Terminal terminal, List header, AttributedString message - , InputValue inputValue, ConsolePrompt.UiConfig cfg) { - return new InputValuePrompt(reader, terminal, header, message, inputValue, cfg); - } + private enum SelectOp { + FORWARD_ONE_LINE, + BACKWARD_ONE_LINE, + EXIT + } - private void bindKeys(KeyMap map) { - map.setUnicode(Operation.INSERT); - for (char i = 32; i < KEYMAP_LENGTH; i++) { - map.bind(Operation.INSERT, Character.toString(i)); - } - map.bind(Operation.BACKSPACE, del()); - map.bind(Operation.DELETE, ctrl('D'), key(terminal, InfoCmp.Capability.key_dc)); - map.bind(Operation.BACKSPACE, ctrl('H')); - map.bind(Operation.EXIT,"\r"); - map.bind(Operation.RIGHT, key(terminal, InfoCmp.Capability.key_right)); - map.bind(Operation.LEFT, key(terminal, InfoCmp.Capability.key_left)); - map.bind(Operation.BEGINNING_OF_LINE, ctrl('A'), key(terminal, InfoCmp.Capability.key_home)); - map.bind(Operation.END_OF_LINE, ctrl('E'), key(terminal, InfoCmp.Capability.key_end)); - map.bind(Operation.RIGHT, ctrl('F')); - map.bind(Operation.LEFT, ctrl('B')); - map.bind(Operation.SELECT_CANDIDATE, "\t"); - } + private final int startColumn; + private final String defaultValue; + private final Character mask; + private final LineReader reader; + private final Completer completer; + + private InputValuePrompt( + LineReader reader, + Terminal terminal, + List header, + AttributedString message, + InputValue inputValue, + ConsolePrompt.UiConfig cfg) { + super(terminal, header, message, cfg); + this.reader = reader; + defaultValue = inputValue.getDefaultValue(); + startColumn = message.columnLength(); + mask = inputValue.getMask(); + this.completer = inputValue.getCompleter(); + } - private void bindSelectKeys(KeyMap map) { - map.bind(SelectOp.FORWARD_ONE_LINE, "\t", "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); - map.bind(SelectOp.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); - map.bind(SelectOp.EXIT,"\r"); - } + public static InputValuePrompt getPrompt( + LineReader reader, + Terminal terminal, + List header, + AttributedString message, + InputValue inputValue, + ConsolePrompt.UiConfig cfg) { + return new InputValuePrompt(reader, terminal, header, message, inputValue, cfg); + } - public InputResult execute() { - resetDisplay(); - int row = firstItemRow - 1; - int column = startColumn; - List matches = new ArrayList<>(); - KeyMap keyMap = new KeyMap<>(); - bindKeys(keyMap); - StringBuilder buffer = new StringBuilder(); - CompletionMatcher completionMatcher = new CompletionMatcherImpl(); - boolean tabCompletion = completer != null && reader != null; - while (true) { - boolean displayCandidates = true; - if (tabCompletion) { - List possible = new ArrayList<>(); - CompletingWord completingWord = new CompletingWord(buffer.toString()); - completer.complete(reader, completingWord, possible); - completionMatcher.compile(config.readerOptions(), false, completingWord, false, 0 - , null); - matches = completionMatcher.matches(possible).stream().sorted(Comparator.naturalOrder()) - .collect(Collectors.toList()); - if (matches.size() > ReaderUtils.getInt(reader, LineReader.MENU_LIST_MAX, 10)) { - displayCandidates = false; - } - } - refreshDisplay(firstItemRow - 1, column, buffer.toString(), row, startColumn - , displayCandidates ? matches : new ArrayList<>()); - Operation op = bindingReader.readBinding(keyMap); - switch (op) { - case LEFT: - if (column > startColumn) { - column--; - } - break; - case RIGHT: - if (column < startColumn + buffer.length()) { - column++; - } - break; - case INSERT: - buffer.insert(column - startColumn, mask == null ? bindingReader.getLastBinding() : mask); - column++; - break; - case BACKSPACE: - if (column > startColumn) { - buffer.deleteCharAt(column - startColumn - 1); - column--; + private void bindKeys(KeyMap map) { + map.setUnicode(Operation.INSERT); + for (char i = 32; i < KEYMAP_LENGTH; i++) { + map.bind(Operation.INSERT, Character.toString(i)); } - break; - case DELETE: - if (column < startColumn + buffer.length() && column >= startColumn) { - buffer.deleteCharAt(column - startColumn); - } - break; - case BEGINNING_OF_LINE: - column = startColumn; - break; - case END_OF_LINE: - column = startColumn + buffer.length(); - break; - case SELECT_CANDIDATE: - if (tabCompletion && matches.size() < ReaderUtils.getInt(reader, LineReader.LIST_MAX, 50)) { - String selected = selectCandidate(firstItemRow - 1, buffer.toString(), row + 1, startColumn, matches); - resetHeader(); - buffer.delete(0, buffer.length()); - buffer.append(selected); - column = startColumn + buffer.length(); - } - break; - case EXIT: - if (buffer.toString().isEmpty()) { - buffer.append(defaultValue); + map.bind(Operation.BACKSPACE, del()); + map.bind(Operation.DELETE, ctrl('D'), key(terminal, InfoCmp.Capability.key_dc)); + map.bind(Operation.BACKSPACE, ctrl('H')); + map.bind(Operation.EXIT, "\r"); + map.bind(Operation.RIGHT, key(terminal, InfoCmp.Capability.key_right)); + map.bind(Operation.LEFT, key(terminal, InfoCmp.Capability.key_left)); + map.bind(Operation.BEGINNING_OF_LINE, ctrl('A'), key(terminal, InfoCmp.Capability.key_home)); + map.bind(Operation.END_OF_LINE, ctrl('E'), key(terminal, InfoCmp.Capability.key_end)); + map.bind(Operation.RIGHT, ctrl('F')); + map.bind(Operation.LEFT, ctrl('B')); + map.bind(Operation.SELECT_CANDIDATE, "\t"); + } + + private void bindSelectKeys(KeyMap map) { + map.bind(SelectOp.FORWARD_ONE_LINE, "\t", "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); + map.bind(SelectOp.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); + map.bind(SelectOp.EXIT, "\r"); + } + + public InputResult execute() { + resetDisplay(); + int row = firstItemRow - 1; + int column = startColumn; + List matches = new ArrayList<>(); + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + StringBuilder buffer = new StringBuilder(); + CompletionMatcher completionMatcher = new CompletionMatcherImpl(); + boolean tabCompletion = completer != null && reader != null; + while (true) { + boolean displayCandidates = true; + if (tabCompletion) { + List possible = new ArrayList<>(); + CompletingWord completingWord = new CompletingWord(buffer.toString()); + completer.complete(reader, completingWord, possible); + completionMatcher.compile(config.readerOptions(), false, completingWord, false, 0, null); + matches = completionMatcher.matches(possible).stream() + .sorted(Comparator.naturalOrder()) + .collect(Collectors.toList()); + if (matches.size() > ReaderUtils.getInt(reader, LineReader.MENU_LIST_MAX, 10)) { + displayCandidates = false; + } + } + refreshDisplay( + firstItemRow - 1, + column, + buffer.toString(), + row, + startColumn, + displayCandidates ? matches : new ArrayList<>()); + Operation op = bindingReader.readBinding(keyMap); + switch (op) { + case LEFT: + if (column > startColumn) { + column--; + } + break; + case RIGHT: + if (column < startColumn + buffer.length()) { + column++; + } + break; + case INSERT: + buffer.insert(column - startColumn, mask == null ? bindingReader.getLastBinding() : mask); + column++; + break; + case BACKSPACE: + if (column > startColumn) { + buffer.deleteCharAt(column - startColumn - 1); + column--; + } + break; + case DELETE: + if (column < startColumn + buffer.length() && column >= startColumn) { + buffer.deleteCharAt(column - startColumn); + } + break; + case BEGINNING_OF_LINE: + column = startColumn; + break; + case END_OF_LINE: + column = startColumn + buffer.length(); + break; + case SELECT_CANDIDATE: + if (tabCompletion && matches.size() < ReaderUtils.getInt(reader, LineReader.LIST_MAX, 50)) { + String selected = + selectCandidate(firstItemRow - 1, buffer.toString(), row + 1, startColumn, matches); + resetHeader(); + buffer.delete(0, buffer.length()); + buffer.append(selected); + column = startColumn + buffer.length(); + } + break; + case EXIT: + if (buffer.toString().isEmpty()) { + buffer.append(defaultValue); + } + return new InputResult(buffer.toString()); + } } - return new InputResult(buffer.toString()); } - } - } - String selectCandidate(int buffRow, String buffer, int row, int column, List candidates) { - if (candidates.isEmpty()) { - return buffer; - } else if (candidates.size() == 1) { - return candidates.get(0).value(); - } - KeyMap keyMap = new KeyMap<>(); - bindSelectKeys(keyMap); - while (true) { - String selected = candidates.get(row - buffRow - 1).value(); - refreshDisplay(buffRow, column + selected.length(), selected, row, column, candidates); - SelectOp op = bindingReader.readBinding(keyMap); - switch (op) { - case FORWARD_ONE_LINE: - if (row < buffRow + candidates.size()) { - row++; - } else { - row = buffRow + 1; + String selectCandidate(int buffRow, String buffer, int row, int column, List candidates) { + if (candidates.isEmpty()) { + return buffer; + } else if (candidates.size() == 1) { + return candidates.get(0).value(); } - break; - case BACKWARD_ONE_LINE: - if (row > buffRow + 1) { - row--; - } else { - row = buffRow + candidates.size(); + KeyMap keyMap = new KeyMap<>(); + bindSelectKeys(keyMap); + while (true) { + String selected = candidates.get(row - buffRow - 1).value(); + refreshDisplay(buffRow, column + selected.length(), selected, row, column, candidates); + SelectOp op = bindingReader.readBinding(keyMap); + switch (op) { + case FORWARD_ONE_LINE: + if (row < buffRow + candidates.size()) { + row++; + } else { + row = buffRow + 1; + } + break; + case BACKWARD_ONE_LINE: + if (row > buffRow + 1) { + row--; + } else { + row = buffRow + candidates.size(); + } + break; + case EXIT: + return selected; + } } - break; - case EXIT: - return selected; } - } } - } - private static class CompletingWord implements CompletingParsedLine { - private final String word; + private static class CompletingWord implements CompletingParsedLine { + private final String word; - public CompletingWord(String word) { - this.word = word; - } + public CompletingWord(String word) { + this.word = word; + } - @Override - public CharSequence escape(CharSequence candidate, boolean complete) { - return null; - } + @Override + public CharSequence escape(CharSequence candidate, boolean complete) { + return null; + } - @Override - public int rawWordCursor() { - return word.length(); - } + @Override + public int rawWordCursor() { + return word.length(); + } - @Override - public int rawWordLength() { - return word.length(); - } + @Override + public int rawWordLength() { + return word.length(); + } - @Override - public String word() { - return word; - } + @Override + public String word() { + return word; + } - @Override - public int wordCursor() { - return word.length(); - } + @Override + public int wordCursor() { + return word.length(); + } - @Override - public int wordIndex() { - return 0; - } + @Override + public int wordIndex() { + return 0; + } - @Override - public List words() { - return new ArrayList<>(Collections.singletonList(word)); - } + @Override + public List words() { + return new ArrayList<>(Collections.singletonList(word)); + } - @Override - public String line() { - return word; - } + @Override + public String line() { + return word; + } - @Override - public int cursor() { - return word.length(); + @Override + public int cursor() { + return word.length(); + } } - } - private static int nextRow(int row, int firstItemRow, List items) { - int itemsSize = items.size(); - int next; - for (next = row + 1; next - firstItemRow < itemsSize && !items.get(next - firstItemRow).isSelectable(); next++) { - } - if (next - firstItemRow >= itemsSize) { - for (next = firstItemRow; next - firstItemRow < itemsSize && !items.get(next - firstItemRow).isSelectable(); next++) { - } - } - return next; - } - private static int prevRow(int row, int firstItemRow, List items) { - int itemsSize = items.size(); - int prev; - for (prev = row - 1; prev - firstItemRow >= 0 && !items.get(prev - firstItemRow).isSelectable(); prev--) { - } - if (prev - firstItemRow < 0) { - for (prev = firstItemRow + itemsSize - 1; prev - firstItemRow >= 0 && !items.get(prev - firstItemRow).isSelectable(); prev--) { - } + private static int nextRow(int row, int firstItemRow, List items) { + int itemsSize = items.size(); + int next; + for (next = row + 1; + next - firstItemRow < itemsSize + && !items.get(next - firstItemRow).isSelectable(); + next++) {} + if (next - firstItemRow >= itemsSize) { + for (next = firstItemRow; + next - firstItemRow < itemsSize + && !items.get(next - firstItemRow).isSelectable(); + next++) {} + } + return next; + } + + private static int prevRow(int row, int firstItemRow, List items) { + int itemsSize = items.size(); + int prev; + for (prev = row - 1; + prev - firstItemRow >= 0 && !items.get(prev - firstItemRow).isSelectable(); + prev--) {} + if (prev - firstItemRow < 0) { + for (prev = firstItemRow + itemsSize - 1; + prev - firstItemRow >= 0 && !items.get(prev - firstItemRow).isSelectable(); + prev--) {} + } + return prev; } - return prev; - } - protected static class ListChoicePrompt extends AbstractPrompt { - private enum Operation {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, INSERT, EXIT} - private final List items; + protected static class ListChoicePrompt extends AbstractPrompt { + private enum Operation { + FORWARD_ONE_LINE, + BACKWARD_ONE_LINE, + INSERT, + EXIT + } - private ListChoicePrompt(Terminal terminal, List header, AttributedString message - , List listItems, ConsolePrompt.UiConfig cfg) { - super(terminal, header, message, listItems, cfg); - items = listItems; - } + private final List items; - public static ListChoicePrompt getPrompt(Terminal terminal, List header - , AttributedString message, List listItems, ConsolePrompt.UiConfig cfg) { - return new ListChoicePrompt<>(terminal, header, message, listItems, cfg); - } + private ListChoicePrompt( + Terminal terminal, + List header, + AttributedString message, + List listItems, + ConsolePrompt.UiConfig cfg) { + super(terminal, header, message, listItems, cfg); + items = listItems; + } - private void bindKeys(KeyMap map) { - for (char i = 32; i < KEYMAP_LENGTH; i++) { - map.bind(Operation.INSERT, Character.toString(i)); - } - map.bind(Operation.FORWARD_ONE_LINE, "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); - map.bind(Operation.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); - map.bind(Operation.EXIT,"\r"); - } + public static ListChoicePrompt getPrompt( + Terminal terminal, + List header, + AttributedString message, + List listItems, + ConsolePrompt.UiConfig cfg) { + return new ListChoicePrompt<>(terminal, header, message, listItems, cfg); + } - public ListResult execute() { - resetDisplay(); - int selectRow = nextRow(firstItemRow - 1, firstItemRow, items); - KeyMap keyMap = new KeyMap<>(); - bindKeys(keyMap); - while (true) { - refreshDisplay(selectRow); - Operation op = bindingReader.readBinding(keyMap); - switch (op) { - case FORWARD_ONE_LINE: - selectRow = nextRow(selectRow, firstItemRow, items); - break; - case BACKWARD_ONE_LINE: - selectRow = prevRow(selectRow, firstItemRow, items); - break; - case INSERT: - String ch = bindingReader.getLastBinding(); - int id = 0; - for (ListItemIF cu : items) { - if (cu instanceof ChoiceItem) { - ChoiceItem ci = (ChoiceItem) cu; - if (ci.isSelectable() && ci.getKey().toString().equals(ch)) { - selectRow = firstItemRow + id; - break; + private void bindKeys(KeyMap map) { + for (char i = 32; i < KEYMAP_LENGTH; i++) { + map.bind(Operation.INSERT, Character.toString(i)); + } + map.bind(Operation.FORWARD_ONE_LINE, "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); + map.bind(Operation.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); + map.bind(Operation.EXIT, "\r"); + } + + public ListResult execute() { + resetDisplay(); + int selectRow = nextRow(firstItemRow - 1, firstItemRow, items); + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + while (true) { + refreshDisplay(selectRow); + Operation op = bindingReader.readBinding(keyMap); + switch (op) { + case FORWARD_ONE_LINE: + selectRow = nextRow(selectRow, firstItemRow, items); + break; + case BACKWARD_ONE_LINE: + selectRow = prevRow(selectRow, firstItemRow, items); + break; + case INSERT: + String ch = bindingReader.getLastBinding(); + int id = 0; + for (ListItemIF cu : items) { + if (cu instanceof ChoiceItem) { + ChoiceItem ci = (ChoiceItem) cu; + if (ci.isSelectable() && ci.getKey().toString().equals(ch)) { + selectRow = firstItemRow + id; + break; + } + } + id++; + } + break; + case EXIT: + T listItem = items.get(selectRow - firstItemRow); + return new ListResult(listItem.getName()); } - } - id++; } - break; - case EXIT: - T listItem = items.get(selectRow - firstItemRow); - return new ListResult(listItem.getName()); } - } } - } - protected static class CheckboxPrompt extends AbstractPrompt { - private enum Operation {FORWARD_ONE_LINE, BACKWARD_ONE_LINE, TOGGLE, EXIT} + protected static class CheckboxPrompt extends AbstractPrompt { + private enum Operation { + FORWARD_ONE_LINE, + BACKWARD_ONE_LINE, + TOGGLE, + EXIT + } - private final List items; + private final List items; - private CheckboxPrompt(Terminal terminal, List header, AttributedString message - , Checkbox checkbox, ConsolePrompt.UiConfig cfg) { - super(terminal, header, message, checkbox.getCheckboxItemList(), cfg); - items = checkbox.getCheckboxItemList(); - } + private CheckboxPrompt( + Terminal terminal, + List header, + AttributedString message, + Checkbox checkbox, + ConsolePrompt.UiConfig cfg) { + super(terminal, header, message, checkbox.getCheckboxItemList(), cfg); + items = checkbox.getCheckboxItemList(); + } - public static CheckboxPrompt getPrompt(Terminal terminal, List header, AttributedString message - , Checkbox checkbox, ConsolePrompt.UiConfig cfg) { - return new CheckboxPrompt(terminal, header, message, checkbox, cfg); - } + public static CheckboxPrompt getPrompt( + Terminal terminal, + List header, + AttributedString message, + Checkbox checkbox, + ConsolePrompt.UiConfig cfg) { + return new CheckboxPrompt(terminal, header, message, checkbox, cfg); + } - private void bindKeys(KeyMap map) { - map.bind(Operation.FORWARD_ONE_LINE, "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); - map.bind(Operation.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); - map.bind(Operation.TOGGLE," "); - map.bind(Operation.EXIT,"\r"); - } + private void bindKeys(KeyMap map) { + map.bind(Operation.FORWARD_ONE_LINE, "e", ctrl('E'), key(terminal, InfoCmp.Capability.key_down)); + map.bind(Operation.BACKWARD_ONE_LINE, "y", ctrl('Y'), key(terminal, InfoCmp.Capability.key_up)); + map.bind(Operation.TOGGLE, " "); + map.bind(Operation.EXIT, "\r"); + } - public CheckboxResult execute() { - resetDisplay(); - int selectRow = nextRow(firstItemRow - 1, firstItemRow, items); - Set selected = items.stream().filter(CheckboxItemIF::isChecked) - .flatMap(it -> Stream.of(it.getName())).collect(Collectors.toSet()); - KeyMap keyMap = new KeyMap<>(); - bindKeys(keyMap); - while (true) { - refreshDisplay(selectRow, selected); - Operation op = bindingReader.readBinding(keyMap); - switch (op) { - case FORWARD_ONE_LINE: - selectRow = nextRow(selectRow, firstItemRow, items); - break; - case BACKWARD_ONE_LINE: - selectRow = prevRow(selectRow, firstItemRow, items); - break; - case TOGGLE: - if (selected.contains(items.get(selectRow - firstItemRow).getName())) { - selected.remove(items.get(selectRow - firstItemRow).getName()); - } else { - selected.add(items.get(selectRow - firstItemRow).getName()); + public CheckboxResult execute() { + resetDisplay(); + int selectRow = nextRow(firstItemRow - 1, firstItemRow, items); + Set selected = items.stream() + .filter(CheckboxItemIF::isChecked) + .flatMap(it -> Stream.of(it.getName())) + .collect(Collectors.toSet()); + KeyMap keyMap = new KeyMap<>(); + bindKeys(keyMap); + while (true) { + refreshDisplay(selectRow, selected); + Operation op = bindingReader.readBinding(keyMap); + switch (op) { + case FORWARD_ONE_LINE: + selectRow = nextRow(selectRow, firstItemRow, items); + break; + case BACKWARD_ONE_LINE: + selectRow = prevRow(selectRow, firstItemRow, items); + break; + case TOGGLE: + if (selected.contains( + items.get(selectRow - firstItemRow).getName())) { + selected.remove(items.get(selectRow - firstItemRow).getName()); + } else { + selected.add(items.get(selectRow - firstItemRow).getName()); + } + break; + case EXIT: + return new CheckboxResult(selected); + } } - break; - case EXIT: - return new CheckboxResult(selected); } - } } - } - } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java index dc11977e0..fd1b8046d 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; import java.util.Set; @@ -10,33 +18,31 @@ * Date: 03.02.16 */ public class CheckboxResult implements PromptResultItemIF { - Set selectedIds; + Set selectedIds; - /** - * Default Constructor. - * @param selectedIds Selected IDs. - */ - public CheckboxResult(Set selectedIds) { - this.selectedIds = selectedIds; - } + /** + * Default Constructor. + * @param selectedIds Selected IDs. + */ + public CheckboxResult(Set selectedIds) { + this.selectedIds = selectedIds; + } - /** - * Returns the set with the IDs of selected checkbox items. - * - * @return set with IDs - */ - public Set getSelectedIds() { - return selectedIds; - } + /** + * Returns the set with the IDs of selected checkbox items. + * + * @return set with IDs + */ + public Set getSelectedIds() { + return selectedIds; + } - public String getResult() { - return selectedIds.toString(); - } + public String getResult() { + return selectedIds.toString(); + } - @Override - public String toString() { - return "CheckboxResult{" + - "selectedIds=" + selectedIds + - '}'; - } + @Override + public String toString() { + return "CheckboxResult{" + "selectedIds=" + selectedIds + '}'; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java index 243305a04..c630832f4 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; import org.jline.consoleui.elements.ConfirmChoice; @@ -10,33 +18,31 @@ * Date: 03.02.16 */ public class ConfirmResult implements PromptResultItemIF { - ConfirmChoice.ConfirmationValue confirmed; + ConfirmChoice.ConfirmationValue confirmed; - /** - * Default constructor. - * - * @param confirm the result value to hold. - */ - public ConfirmResult(ConfirmChoice.ConfirmationValue confirm) { - this.confirmed = confirm; - } + /** + * Default constructor. + * + * @param confirm the result value to hold. + */ + public ConfirmResult(ConfirmChoice.ConfirmationValue confirm) { + this.confirmed = confirm; + } - /** - * Returns the confirmation value. - * @return confirmation value. - */ - public ConfirmChoice.ConfirmationValue getConfirmed() { - return confirmed; - } + /** + * Returns the confirmation value. + * @return confirmation value. + */ + public ConfirmChoice.ConfirmationValue getConfirmed() { + return confirmed; + } - public String getResult() { - return confirmed.toString(); - } + public String getResult() { + return confirmed.toString(); + } - @Override - public String toString() { - return "ConfirmResult{" + - "confirmed=" + confirmed + - '}'; - } + @Override + public String toString() { + return "ConfirmResult{" + "confirmed=" + confirmed + '}'; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java index 2a7c9527e..7a740f5b6 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java @@ -1,263 +1,275 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; -import de.codeshelf.consoleui.elements.*; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +import org.jline.builtins.Styles; +import org.jline.consoleui.elements.*; +import org.jline.consoleui.elements.items.ConsoleUIItemIF; import org.jline.consoleui.elements.items.impl.ChoiceItem; import org.jline.consoleui.prompt.AbstractPrompt.*; import org.jline.consoleui.prompt.builder.PromptBuilder; -import org.jline.builtins.Styles; -import org.jline.consoleui.elements.items.ConsoleUIItemIF; -import org.jline.consoleui.elements.*; import org.jline.reader.LineReader; import org.jline.terminal.Attributes; import org.jline.terminal.Terminal; import org.jline.utils.*; -import java.io.IOException; -import java.util.*; -import java.util.stream.Collectors; - /** * ConsolePrompt encapsulates the prompting of a list of input questions for the user. * * @author Matti Rinta-Nikkola */ public class ConsolePrompt { - private final LineReader reader; - private final Terminal terminal; - private final UiConfig config; + private final LineReader reader; + private final Terminal terminal; + private final UiConfig config; - /** - * - * @param terminal the terminal. - */ - public ConsolePrompt(Terminal terminal) { - this(null, terminal, new UiConfig()); - } - /** - * - * @param terminal the terminal. - * @param config ConsolePrompt cursor pointer and checkbox configuration - */ - public ConsolePrompt(Terminal terminal, UiConfig config) { - this(null, terminal, config); - } - /** - * - * @param reader the lineReader. - * @param terminal the terminal. - * @param config ConsolePrompt cursor pointer and checkbox configuration - */ - public ConsolePrompt(LineReader reader, Terminal terminal, UiConfig config) { - this.terminal = terminal; - this.config = config; - this.reader = reader; - if (reader != null) { - Map options = new HashMap<>(); - for (LineReader.Option option : LineReader.Option.values()) { - options.put(option, reader.isSet(option)); - } - config.setReaderOptions(options); + /** + * + * @param terminal the terminal. + */ + public ConsolePrompt(Terminal terminal) { + this(null, terminal, new UiConfig()); + } + /** + * + * @param terminal the terminal. + * @param config ConsolePrompt cursor pointer and checkbox configuration + */ + public ConsolePrompt(Terminal terminal, UiConfig config) { + this(null, terminal, config); + } + /** + * + * @param reader the lineReader. + * @param terminal the terminal. + * @param config ConsolePrompt cursor pointer and checkbox configuration + */ + public ConsolePrompt(LineReader reader, Terminal terminal, UiConfig config) { + this.terminal = terminal; + this.config = config; + this.reader = reader; + if (reader != null) { + Map options = new HashMap<>(); + for (LineReader.Option option : LineReader.Option.values()) { + options.put(option, reader.isSet(option)); + } + config.setReaderOptions(options); + } } - } - /** - * Prompt a list of choices (questions). This method takes a list of promptable elements, typically - * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and - * answers are filled in to the result map. The result map contains the key of each promtable element - * and the user entry as an object implementing {@link PromptResultItemIF}. - * - * @param promptableElementList the list of questions / prompts to ask the user for. - * @return a map containing a result for each element of promptableElementList - * @throws IOException may be thrown by terminal - */ - public Map prompt(List promptableElementList) { - return prompt(new ArrayList<>(), promptableElementList); - } - /** - * Prompt a list of choices (questions). This method takes a list of promptable elements, typically - * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and - * answers are filled in to the result map. The result map contains the key of each promtable element - * and the user entry as an object implementing {@link PromptResultItemIF}. - * - * @param header info to be displayed before first prompt. - * @param promptableElementList the list of questions / prompts to ask the user for. - * @return a map containing a result for each element of promptableElementList - * @throws IOException may be thrown by terminal - */ - public Map prompt(List header - , List promptableElementList) { - Attributes attributes = terminal.enterRawMode(); - try { - terminal.puts(InfoCmp.Capability.enter_ca_mode); - terminal.puts(InfoCmp.Capability.keypad_xmit); - terminal.writer().flush(); + /** + * Prompt a list of choices (questions). This method takes a list of promptable elements, typically + * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and + * answers are filled in to the result map. The result map contains the key of each promptable element + * and the user entry as an object implementing {@link PromptResultItemIF}. + * + * @param promptableElementList the list of questions / prompts to ask the user for. + * @return a map containing a result for each element of promptableElementList + * @throws IOException may be thrown by terminal + */ + public Map prompt(List promptableElementList) throws IOException { + return prompt(new ArrayList<>(), promptableElementList); + } + /** + * Prompt a list of choices (questions). This method takes a list of promptable elements, typically + * created with {@link PromptBuilder}. Each of the elements is processed and the user entries and + * answers are filled in to the result map. The result map contains the key of each promptable element + * and the user entry as an object implementing {@link PromptResultItemIF}. + * + * @param header info to be displayed before first prompt. + * @param promptableElementList the list of questions / prompts to ask the user for. + * @return a map containing a result for each element of promptableElementList + * @throws IOException may be thrown by terminal + */ + public Map prompt( + List header, List promptableElementList) throws IOException { + Attributes attributes = terminal.enterRawMode(); + try { + terminal.puts(InfoCmp.Capability.enter_ca_mode); + terminal.puts(InfoCmp.Capability.keypad_xmit); + terminal.writer().flush(); - Map resultMap = new HashMap<>(); + Map resultMap = new HashMap<>(); - for (PromptableElementIF pe : promptableElementList) { - AttributedStringBuilder message = new AttributedStringBuilder(); - message.style(config.style(".pr")).append("? "); - message.style(config.style(".me")).append(pe.getMessage()).append(" "); - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.append(message); - asb.style(AttributedStyle.DEFAULT); - PromptResultItemIF result; - if (pe instanceof ListChoice) { - ListChoice lc = (ListChoice) pe; - result = ListChoicePrompt.getPrompt(terminal, header, asb.toAttributedString() - , lc.getListItemList(), config).execute(); - } else if (pe instanceof InputValue) { - InputValue ip = (InputValue) pe; - if (ip.getDefaultValue() != null) { - asb.append("(").append(ip.getDefaultValue()).append(") "); - } - result = InputValuePrompt.getPrompt(reader, terminal, header, asb.toAttributedString(), ip, config).execute(); - } else if (pe instanceof ExpandableChoice) { - ExpandableChoice ec = (ExpandableChoice) pe; - asb.append("("); - for (ConsoleUIItemIF item : ec.getChoiceItems()) { - if (item instanceof ChoiceItem) { - ChoiceItem ci = (ChoiceItem) item; - if (ci.isSelectable()) { - asb.append(ci.isDefaultChoice() ? Character.toUpperCase(ci.getKey()) : ci.getKey()); - } + for (PromptableElementIF pe : promptableElementList) { + AttributedStringBuilder message = new AttributedStringBuilder(); + message.style(config.style(".pr")).append("? "); + message.style(config.style(".me")).append(pe.getMessage()).append(" "); + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.append(message); + asb.style(AttributedStyle.DEFAULT); + PromptResultItemIF result; + if (pe instanceof ListChoice) { + ListChoice lc = (ListChoice) pe; + result = ListChoicePrompt.getPrompt( + terminal, header, asb.toAttributedString(), lc.getListItemList(), config) + .execute(); + } else if (pe instanceof InputValue) { + InputValue ip = (InputValue) pe; + if (ip.getDefaultValue() != null) { + asb.append("(").append(ip.getDefaultValue()).append(") "); + } + result = InputValuePrompt.getPrompt(reader, terminal, header, asb.toAttributedString(), ip, config) + .execute(); + } else if (pe instanceof ExpandableChoice) { + ExpandableChoice ec = (ExpandableChoice) pe; + asb.append("("); + for (ConsoleUIItemIF item : ec.getChoiceItems()) { + if (item instanceof ChoiceItem) { + ChoiceItem ci = (ChoiceItem) item; + if (ci.isSelectable()) { + asb.append(ci.isDefaultChoice() ? Character.toUpperCase(ci.getKey()) : ci.getKey()); + } + } + } + asb.append("h) "); + try { + result = ExpandableChoicePrompt.getPrompt( + terminal, header, asb.toAttributedString(), ec, config) + .execute(); + } catch (ExpandableChoiceException e) { + result = ListChoicePrompt.getPrompt( + terminal, header, message.toAttributedString(), ec.getChoiceItems(), config) + .execute(); + } + } else if (pe instanceof Checkbox) { + Checkbox cb = (Checkbox) pe; + result = CheckboxPrompt.getPrompt(terminal, header, message.toAttributedString(), cb, config) + .execute(); + } else if (pe instanceof ConfirmChoice) { + ConfirmChoice cc = (ConfirmChoice) pe; + if (cc.getDefaultConfirmation() == null) { + asb.append(config.resourceBundle().getString("confirmation_without_default")); + } else if (cc.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.YES) { + asb.append(config.resourceBundle().getString("confirmation_yes_default")); + } else { + asb.append(config.resourceBundle().getString("confirmation_no_default")); + } + asb.append(" "); + result = ConfirmPrompt.getPrompt(terminal, header, asb.toAttributedString(), cc, config) + .execute(); + } else { + throw new IllegalArgumentException("wrong type of promptable element"); + } + String resp = result.getResult(); + if (result instanceof ConfirmResult) { + ConfirmResult cr = (ConfirmResult) result; + if (cr.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) { + resp = config.resourceBundle().getString("confirmation_yes_answer"); + } else { + resp = config.resourceBundle().getString("confirmation_no_answer"); + } + } + message.style(config.style(".an")).append(resp); + header.add(message.toAttributedString()); + resultMap.put(pe.getName(), result); } - } - asb.append("h) "); - try { - result = ExpandableChoicePrompt.getPrompt(terminal, header - , asb.toAttributedString(), ec, config).execute(); - } catch (ExpandableChoiceException e) { - result = ListChoicePrompt.getPrompt(terminal, header, message.toAttributedString() - , ec.getChoiceItems(), config).execute(); - } - } else if (pe instanceof Checkbox) { - Checkbox cb = (Checkbox) pe; - result = CheckboxPrompt.getPrompt(terminal, header, message.toAttributedString(), cb, config).execute(); - } else if (pe instanceof ConfirmChoice) { - ConfirmChoice cc = (ConfirmChoice) pe; - if (cc.getDefaultConfirmation() == null) { - asb.append(config.resourceBundle().getString("confirmation_without_default")); - } else if (cc.getDefaultConfirmation() == ConfirmChoice.ConfirmationValue.YES) { - asb.append(config.resourceBundle().getString("confirmation_yes_default")); - } else { - asb.append(config.resourceBundle().getString("confirmation_no_default")); - } - asb.append(" "); - result = ConfirmPrompt.getPrompt(terminal, header, asb.toAttributedString(), cc, config).execute(); - } else { - throw new IllegalArgumentException("wrong type of promptable element"); - } - String resp = result.getResult(); - if (result instanceof ConfirmResult) { - ConfirmResult cr = (ConfirmResult)result; - if (cr.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) { - resp = config.resourceBundle().getString("confirmation_yes_answer"); - } else { - resp = config.resourceBundle().getString("confirmation_no_answer"); - } + return resultMap; + } finally { + terminal.setAttributes(attributes); + terminal.puts(InfoCmp.Capability.exit_ca_mode); + terminal.puts(InfoCmp.Capability.keypad_local); + terminal.writer().flush(); + for (AttributedString as : header) { + as.println(terminal); + } + terminal.writer().flush(); } - message.style(config.style(".an")).append(resp); - header.add(message.toAttributedString()); - resultMap.put(pe.getName(), result); - } - return resultMap; - } finally { - terminal.setAttributes(attributes); - terminal.puts(InfoCmp.Capability.exit_ca_mode); - terminal.puts(InfoCmp.Capability.keypad_local); - terminal.writer().flush(); - for (AttributedString as : header) { - as.println(terminal); - } - terminal.writer().flush(); } - } - /** - * Creates a {@link PromptBuilder}. - * - * @return a new prompt builder object. - */ - public PromptBuilder getPromptBuilder() { - return new PromptBuilder(); - } + /** + * Creates a {@link PromptBuilder}. + * + * @return a new prompt builder object. + */ + public PromptBuilder getPromptBuilder() { + return new PromptBuilder(); + } - /** - * ConsoleUI configuration: colors, cursor pointer and selected/unselected/unavailable boxes. - * ConsoleUI colors are configurable using UI_COLORS environment variable - */ - public static class UiConfig { - static final String DEFAULT_UI_COLORS = "cu=36:be=32:bd=37:pr=32:me=1:an=36:se=36:cb=100"; - static final String UI_COLORS = "UI_COLORS"; - private final AttributedString indicator; - private final AttributedString uncheckedBox; - private final AttributedString checkedBox; - private final AttributedString unavailable; - private final StyleResolver resolver; - private final ResourceBundle resourceBundle; - private Map readerOptions = new HashMap<>(); + /** + * ConsoleUI configuration: colors, cursor pointer and selected/unselected/unavailable boxes. + * ConsoleUI colors are configurable using UI_COLORS environment variable + */ + public static class UiConfig { + static final String DEFAULT_UI_COLORS = "cu=36:be=32:bd=37:pr=32:me=1:an=36:se=36:cb=100"; + static final String UI_COLORS = "UI_COLORS"; + private final AttributedString indicator; + private final AttributedString uncheckedBox; + private final AttributedString checkedBox; + private final AttributedString unavailable; + private final StyleResolver resolver; + private final ResourceBundle resourceBundle; + private Map readerOptions = new HashMap<>(); - public UiConfig() { - this(null, null, null, null); - } + public UiConfig() { + this(null, null, null, null); + } - public UiConfig(String indicator, String uncheckedBox, String checkedBox, String unavailable) { - String uc = System.getenv(UI_COLORS); - String uiColors = uc != null && Styles.isAnsiStylePattern(uc) ? uc : DEFAULT_UI_COLORS; - this.resolver = resolver(uiColors); - this.indicator = toAttributedString((indicator != null ? indicator : ">"), ".cu"); - this.uncheckedBox = toAttributedString((uncheckedBox != null ? uncheckedBox : " "), ".be"); - this.checkedBox = toAttributedString((checkedBox != null ? checkedBox : "x "), ".be"); - this.unavailable = toAttributedString((unavailable != null ? unavailable : "- "), ".bd"); - this.resourceBundle = ResourceBundle.getBundle("consoleui_messages"); - } + public UiConfig(String indicator, String uncheckedBox, String checkedBox, String unavailable) { + String uc = System.getenv(UI_COLORS); + String uiColors = uc != null && Styles.isStylePattern(uc) ? uc : DEFAULT_UI_COLORS; + this.resolver = resolver(uiColors); + this.indicator = toAttributedString(resolver, (indicator != null ? indicator : ">"), ".cu"); + this.uncheckedBox = toAttributedString(resolver, (uncheckedBox != null ? uncheckedBox : " "), ".be"); + this.checkedBox = toAttributedString(resolver, (checkedBox != null ? checkedBox : "x "), ".be"); + this.unavailable = toAttributedString(resolver, (unavailable != null ? unavailable : "- "), ".bd"); + this.resourceBundle = ResourceBundle.getBundle("consoleui_messages"); + } - private AttributedString toAttributedString(String string, String styleKey) { - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.style(style(styleKey)); - asb.append(string); - return asb.toAttributedString(); - } + private static AttributedString toAttributedString(StyleResolver resolver, String string, String styleKey) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.style(resolver.resolve(styleKey)); + asb.append(string); + return asb.toAttributedString(); + } - public AttributedString indicator() { - return indicator; - } + public AttributedString indicator() { + return indicator; + } - public AttributedString uncheckedBox() { - return uncheckedBox; - } + public AttributedString uncheckedBox() { + return uncheckedBox; + } - public AttributedString checkedBox() { - return checkedBox; - } + public AttributedString checkedBox() { + return checkedBox; + } - public AttributedString unavailable() { - return unavailable; - } + public AttributedString unavailable() { + return unavailable; + } - public AttributedStyle style(String key) { - return resolver.resolve(key); - } + public AttributedStyle style(String key) { + return resolver.resolve(key); + } - public ResourceBundle resourceBundle() { - return resourceBundle; - } + public ResourceBundle resourceBundle() { + return resourceBundle; + } - protected void setReaderOptions(Map readerOptions) { - this.readerOptions = readerOptions; - } + protected void setReaderOptions(Map readerOptions) { + this.readerOptions = readerOptions; + } - public Map readerOptions() { - return readerOptions; - } + public Map readerOptions() { + return readerOptions; + } - private static StyleResolver resolver(String style) { - Map colors = Arrays.stream(style.split(":")) - .collect(Collectors.toMap(s -> s.substring(0, s.indexOf('=')), - s -> s.substring(s.indexOf('=') + 1))); - return new StyleResolver(colors::get); + private static StyleResolver resolver(String style) { + Map colors = Arrays.stream(style.split(":")) + .collect(Collectors.toMap( + s -> s.substring(0, s.indexOf('=')), s -> s.substring(s.indexOf('=') + 1))); + return new StyleResolver(colors::get); + } } - - } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java index 655f63a77..0f1423a87 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java @@ -1,41 +1,47 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; /** - * Result of a an expandable choice. ExpandableChoiceResult contains a String with the + * Result of an expandable choice. ExpandableChoiceResult contains a String with the * IDs of the selected item. *

* User: Andreas Wegmann

* Date: 03.02.16 */ public class ExpandableChoiceResult implements PromptResultItemIF { - String selectedId; + String selectedId; - /** - * Default constructor. - * - * @param selectedId the selected id - */ - public ExpandableChoiceResult(String selectedId) { - this.selectedId = selectedId; - } + /** + * Default constructor. + * + * @param selectedId the selected id + */ + public ExpandableChoiceResult(String selectedId) { + this.selectedId = selectedId; + } - /** - * Returns the selected id. - * - * @return selected id. - */ - public String getSelectedId() { - return selectedId; - } + /** + * Returns the selected id. + * + * @return selected id. + */ + public String getSelectedId() { + return selectedId; + } - public String getResult() { - return selectedId; - } + public String getResult() { + return selectedId; + } - @Override - public String toString() { - return "ExpandableChoiceResult{" + - "selectedId='" + selectedId + '\'' + - '}'; - } + @Override + public String toString() { + return "ExpandableChoiceResult{" + "selectedId='" + selectedId + '\'' + '}'; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java index 91dc5fb58..d34a8ff3d 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; /** @@ -6,24 +14,22 @@ * Date: 03.02.16 */ public class InputResult implements PromptResultItemIF { - private String input; + private final String input; - public InputResult(String input) { - this.input = input; - } + public InputResult(String input) { + this.input = input; + } - public String getInput() { - return input; - } + public String getInput() { + return input; + } - public String getResult() { - return input; - } + public String getResult() { + return input; + } - @Override - public String toString() { - return "InputResult{" + - "input='" + input + '\'' + - '}'; - } + @Override + public String toString() { + return "InputResult{" + "input='" + input + '\'' + '}'; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java index 93ba662f3..eabb2ebbe 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; /** @@ -7,34 +15,32 @@ */ public class ListResult implements PromptResultItemIF { - String selectedId; + String selectedId; - /** - * Returns the ID of the selected item. - * - * @return id of selected item - */ - public String getSelectedId() { - return selectedId; - } + /** + * Returns the ID of the selected item. + * + * @return id of selected item + */ + public String getSelectedId() { + return selectedId; + } - public String getResult() { - return selectedId; - } + public String getResult() { + return selectedId; + } - /** - * Default constructor. - * - * @param selectedId id of selected item. - */ - public ListResult(String selectedId) { - this.selectedId = selectedId; - } + /** + * Default constructor. + * + * @param selectedId id of selected item. + */ + public ListResult(String selectedId) { + this.selectedId = selectedId; + } - @Override - public String toString() { - return "ListResult{" + - "selectedId='" + selectedId + '\'' + - '}'; - } + @Override + public String toString() { + return "ListResult{" + "selectedId='" + selectedId + '\'' + '}'; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java deleted file mode 100644 index e2a78657f..000000000 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/PromptIF.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.jline.consoleui.prompt; - -import org.jline.consoleui.elements.PromptableElementIF; - -import java.io.IOException; - -/** - * Interface for all prompt implementation. - * - * User: Andreas Wegmann - * Date: 01.01.16 - */ -public interface PromptIF { - /** - * Prompt the user for an imput. - * - * @param promptableElement prompt definition - * @return the prompt result - * @throws IOException may be thrown by getting the users input. - */ - R prompt(T promptableElement) throws IOException; -} diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java index 21c594697..26f85013c 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; /** diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java index d83876e33..99fee53ad 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; import org.jline.consoleui.elements.items.CheckboxItemIF; @@ -7,50 +15,50 @@ * Created by andy on 22.01.16. */ public class CheckboxItemBuilder { - private final CheckboxPromptBuilder checkboxPromptBuilder; - private boolean checked; - private String name; - private String text; - private String disabledText; - - public CheckboxItemBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { - this.checkboxPromptBuilder = checkboxPromptBuilder; - } - - public CheckboxItemBuilder name(String name) { - if (text == null) { - text = name; + private final CheckboxPromptBuilder checkboxPromptBuilder; + private boolean checked; + private String name; + private String text; + private String disabledText; + + public CheckboxItemBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { + this.checkboxPromptBuilder = checkboxPromptBuilder; + } + + public CheckboxItemBuilder name(String name) { + if (text == null) { + text = name; + } + this.name = name; + return this; + } + + public CheckboxItemBuilder text(String text) { + if (this.name == null) { + this.name = text; + } + this.text = text; + return this; + } + + public CheckboxPromptBuilder add() { + CheckboxItemIF item = new CheckboxItem(checked, text, disabledText, name); + checkboxPromptBuilder.addItem(item); + return checkboxPromptBuilder; + } + + public CheckboxItemBuilder disabledText(String disabledText) { + this.disabledText = disabledText; + return this; + } + + public CheckboxItemBuilder check() { + this.checked = true; + return this; } - this.name = name; - return this; - } - public CheckboxItemBuilder text(String text) { - if (this.name == null) { - this.name = text; + public CheckboxItemBuilder checked(boolean checked) { + this.checked = checked; + return this; } - this.text = text; - return this; - } - - public CheckboxPromptBuilder add() { - CheckboxItemIF item = new CheckboxItem(checked, text, disabledText, name); - checkboxPromptBuilder.addItem(item); - return checkboxPromptBuilder; - } - - public CheckboxItemBuilder disabledText(String disabledText) { - this.disabledText = disabledText; - return this; - } - - public CheckboxItemBuilder check() { - this.checked = true; - return this; - } - - public CheckboxItemBuilder checked(boolean checked) { - this.checked = checked; - return this; - } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java index 4609072f0..34ea8ffbd 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java @@ -1,85 +1,91 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; +import java.util.ArrayList; +import java.util.List; + import org.jline.consoleui.elements.Checkbox; import org.jline.consoleui.elements.PageSizeType; import org.jline.consoleui.elements.items.CheckboxItemIF; -import java.util.ArrayList; -import java.util.List; - /** * Created by andy on 22.01.16. */ public class CheckboxPromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private int pageSize; - private PageSizeType pageSizeType; - private List itemList; - - public CheckboxPromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - this.pageSize = 10; - this.pageSizeType = PageSizeType.ABSOLUTE; - itemList = new ArrayList(); - } - - void addItem(CheckboxItemIF checkboxItem) { - itemList.add(checkboxItem); - } - - public CheckboxPromptBuilder name(String name) { - this.name = name; - if (message == null) { - message = name; + private final PromptBuilder promptBuilder; + private String name; + private String message; + private int pageSize; + private PageSizeType pageSizeType; + private final List itemList; + + public CheckboxPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + this.pageSize = 10; + this.pageSizeType = PageSizeType.ABSOLUTE; + itemList = new ArrayList<>(); } - return this; - } - public CheckboxPromptBuilder message(String message) { - this.message = message; - if (name == null) { - name = message; + void addItem(CheckboxItemIF checkboxItem) { + itemList.add(checkboxItem); } - return this; - } - public CheckboxPromptBuilder pageSize(int absoluteSize) { - this.pageSize = absoluteSize; - this.pageSizeType = PageSizeType.ABSOLUTE; - return this; - } + public CheckboxPromptBuilder name(String name) { + this.name = name; + if (message == null) { + message = name; + } + return this; + } - public CheckboxPromptBuilder relativePageSize(int relativePageSize) { - this.pageSize = relativePageSize; - this.pageSizeType = PageSizeType.RELATIVE; - return this; - } + public CheckboxPromptBuilder message(String message) { + this.message = message; + if (name == null) { + name = message; + } + return this; + } - public CheckboxItemBuilder newItem() { - return new CheckboxItemBuilder(this); - } + public CheckboxPromptBuilder pageSize(int absoluteSize) { + this.pageSize = absoluteSize; + this.pageSizeType = PageSizeType.ABSOLUTE; + return this; + } - public CheckboxItemBuilder newItem(String name) { - CheckboxItemBuilder checkboxItemBuilder = new CheckboxItemBuilder(this); - return checkboxItemBuilder.name(name); - } + public CheckboxPromptBuilder relativePageSize(int relativePageSize) { + this.pageSize = relativePageSize; + this.pageSizeType = PageSizeType.RELATIVE; + return this; + } - public PromptBuilder addPrompt() { - Checkbox checkbox = new Checkbox(message, name, pageSize, pageSizeType, itemList); - promptBuilder.addPrompt(checkbox); - return promptBuilder; - } + public CheckboxItemBuilder newItem() { + return new CheckboxItemBuilder(this); + } - public CheckboxSeperatorBuilder newSeparator() { - return new CheckboxSeperatorBuilder(this); - } + public CheckboxItemBuilder newItem(String name) { + CheckboxItemBuilder checkboxItemBuilder = new CheckboxItemBuilder(this); + return checkboxItemBuilder.name(name); + } - public CheckboxSeperatorBuilder newSeparator(String text) { - CheckboxSeperatorBuilder checkboxSeperatorBuilder = new CheckboxSeperatorBuilder(this); - return checkboxSeperatorBuilder.text(text); - } + public PromptBuilder addPrompt() { + Checkbox checkbox = new Checkbox(message, name, pageSize, pageSizeType, itemList); + promptBuilder.addPrompt(checkbox); + return promptBuilder; + } + public CheckboxSeparatorBuilder newSeparator() { + return new CheckboxSeparatorBuilder(this); + } + public CheckboxSeparatorBuilder newSeparator(String text) { + CheckboxSeparatorBuilder checkboxSeperatorBuilder = new CheckboxSeparatorBuilder(this); + return checkboxSeperatorBuilder.text(text); + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java new file mode 100644 index 000000000..f70617afe --- /dev/null +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package org.jline.consoleui.prompt.builder; + +import org.jline.consoleui.elements.items.impl.Separator; + +/** + * Created by andy on 22.01.16. + */ +public class CheckboxSeparatorBuilder { + private final CheckboxPromptBuilder promptBuilder; + private String text; + + public CheckboxSeparatorBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { + this.promptBuilder = checkboxPromptBuilder; + } + + public CheckboxPromptBuilder add() { + Separator separator = new Separator(text); + promptBuilder.addItem(separator); + + return promptBuilder; + } + + public CheckboxSeparatorBuilder text(String text) { + this.text = text; + return this; + } +} diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java deleted file mode 100644 index cfa4885ed..000000000 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeperatorBuilder.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.jline.consoleui.prompt.builder; - -import org.jline.consoleui.elements.items.impl.Separator; - -/** - * Created by andy on 22.01.16. - */ -public class CheckboxSeperatorBuilder { - private final CheckboxPromptBuilder promptBuilder; - private String text; - - public CheckboxSeperatorBuilder(CheckboxPromptBuilder checkboxPromptBuilder) { - this.promptBuilder = checkboxPromptBuilder; - } - - public CheckboxPromptBuilder add() { - Separator separator = new Separator(text); - promptBuilder.addItem(separator); - - return promptBuilder; - } - - public CheckboxSeperatorBuilder text(String text) { - this.text = text; - return this; - } -} diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java index f603322d5..3e753bccd 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; import org.jline.consoleui.elements.ConfirmChoice; @@ -7,38 +15,38 @@ * Date: 24.01.16 */ public class ConfirmPromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private ConfirmChoice.ConfirmationValue defaultConfirmationValue; + private final PromptBuilder promptBuilder; + private String name; + private String message; + private ConfirmChoice.ConfirmationValue defaultConfirmationValue; - public ConfirmPromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - } + public ConfirmPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } - public ConfirmPromptBuilder name(String name) { - this.name = name; - if (message == null) { - message = name; + public ConfirmPromptBuilder name(String name) { + this.name = name; + if (message == null) { + message = name; + } + return this; } - return this; - } - public ConfirmPromptBuilder message(String message) { - this.message = message; - if (name == null) { - name = message; + public ConfirmPromptBuilder message(String message) { + this.message = message; + if (name == null) { + name = message; + } + return this; } - return this; - } - public ConfirmPromptBuilder defaultValue(ConfirmChoice.ConfirmationValue confirmationValue) { - this.defaultConfirmationValue = confirmationValue; - return this; - } + public ConfirmPromptBuilder defaultValue(ConfirmChoice.ConfirmationValue confirmationValue) { + this.defaultConfirmationValue = confirmationValue; + return this; + } - public PromptBuilder addPrompt() { - promptBuilder.addPrompt(new ConfirmChoice(message, name, defaultConfirmationValue)); - return promptBuilder; - } + public PromptBuilder addPrompt() { + promptBuilder.addPrompt(new ConfirmChoice(message, name, defaultConfirmationValue)); + return promptBuilder; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java index 9248ab733..488bf9fb6 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; import org.jline.consoleui.elements.items.impl.ChoiceItem; @@ -6,39 +14,39 @@ * Created by andy on 22.01.16. */ public class ExpandableChoiceItemBuilder { - private final ExpandableChoicePromptBuilder choicePromptBuilder; - private String name; - private String message; - private Character key; - private boolean asDefault; - - public ExpandableChoiceItemBuilder(ExpandableChoicePromptBuilder choicePromptBuilder) { - this.choicePromptBuilder = choicePromptBuilder; - } - - public ExpandableChoiceItemBuilder name(String name) { - this.name = name; - return this; - } - - public ExpandableChoiceItemBuilder message(String message) { - this.message = message; - return this; - } - - public ExpandableChoiceItemBuilder key(char key) { - this.key = key; - return this; - } - - public ExpandableChoicePromptBuilder add() { - ChoiceItem choiceItem = new ChoiceItem(key, name, message, asDefault); - choicePromptBuilder.addItem(choiceItem); - return choicePromptBuilder; - } - - public ExpandableChoiceItemBuilder asDefault() { - this.asDefault = true; - return this; - } + private final ExpandableChoicePromptBuilder choicePromptBuilder; + private String name; + private String message; + private Character key; + private boolean asDefault; + + public ExpandableChoiceItemBuilder(ExpandableChoicePromptBuilder choicePromptBuilder) { + this.choicePromptBuilder = choicePromptBuilder; + } + + public ExpandableChoiceItemBuilder name(String name) { + this.name = name; + return this; + } + + public ExpandableChoiceItemBuilder message(String message) { + this.message = message; + return this; + } + + public ExpandableChoiceItemBuilder key(char key) { + this.key = key; + return this; + } + + public ExpandableChoicePromptBuilder add() { + ChoiceItem choiceItem = new ChoiceItem(key, name, message, asDefault); + choicePromptBuilder.addItem(choiceItem); + return choicePromptBuilder; + } + + public ExpandableChoiceItemBuilder asDefault() { + this.asDefault = true; + return this; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java index bdaa31382..208589411 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java @@ -1,63 +1,70 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; -import org.jline.consoleui.elements.ExpandableChoice; -import org.jline.consoleui.elements.items.ChoiceItemIF; - import java.util.ArrayList; import java.util.List; +import org.jline.consoleui.elements.ExpandableChoice; +import org.jline.consoleui.elements.items.ChoiceItemIF; + /** * Created by andy on 22.01.16. */ public class ExpandableChoicePromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private List itemList; - - public ExpandableChoicePromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - this.itemList = new ArrayList<>(); - } - - void addItem(ChoiceItemIF choiceItem) { - this.itemList.add(choiceItem); - } - - public ExpandableChoicePromptBuilder name(String name) { - this.name = name; - if (message == null) { - message = name; - } - return this; - } - - public ExpandableChoicePromptBuilder message(String message) { - this.message = message; - if (name == null) { - name = message; - } - return this; - } - - public ExpandableChoiceItemBuilder newItem() { - return new ExpandableChoiceItemBuilder(this); - } - - public ExpandableChoiceItemBuilder newItem(String name) { - ExpandableChoiceItemBuilder expandableChoiceItemBuilder = new ExpandableChoiceItemBuilder(this); - return expandableChoiceItemBuilder.name(name); - } - - public PromptBuilder addPrompt() { - ExpandableChoice expandableChoice = new ExpandableChoice(message, name, itemList); - promptBuilder.addPrompt(expandableChoice); - return promptBuilder; - } - - public ExpandableChoiceSeparatorBuilder newSeparator(String text) { - ExpandableChoiceSeparatorBuilder expandableChoiceSeparatorBuilder = new ExpandableChoiceSeparatorBuilder(this); - return expandableChoiceSeparatorBuilder.text(text); - } + private final PromptBuilder promptBuilder; + private String name; + private String message; + private final List itemList; + + public ExpandableChoicePromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + this.itemList = new ArrayList<>(); + } + + void addItem(ChoiceItemIF choiceItem) { + this.itemList.add(choiceItem); + } + public ExpandableChoicePromptBuilder name(String name) { + this.name = name; + if (message == null) { + message = name; + } + return this; + } + + public ExpandableChoicePromptBuilder message(String message) { + this.message = message; + if (name == null) { + name = message; + } + return this; + } + + public ExpandableChoiceItemBuilder newItem() { + return new ExpandableChoiceItemBuilder(this); + } + + public ExpandableChoiceItemBuilder newItem(String name) { + ExpandableChoiceItemBuilder expandableChoiceItemBuilder = new ExpandableChoiceItemBuilder(this); + return expandableChoiceItemBuilder.name(name); + } + + public PromptBuilder addPrompt() { + ExpandableChoice expandableChoice = new ExpandableChoice(message, name, itemList); + promptBuilder.addPrompt(expandableChoice); + return promptBuilder; + } + + public ExpandableChoiceSeparatorBuilder newSeparator(String text) { + ExpandableChoiceSeparatorBuilder expandableChoiceSeparatorBuilder = new ExpandableChoiceSeparatorBuilder(this); + return expandableChoiceSeparatorBuilder.text(text); + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java index 5a6409ee6..06f5ed742 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; import org.jline.consoleui.elements.items.impl.Separator; @@ -6,22 +14,22 @@ * Created by andy on 22.01.16. */ public class ExpandableChoiceSeparatorBuilder { - private final ExpandableChoicePromptBuilder expandableChoicePromptBuilder; - private String text; + private final ExpandableChoicePromptBuilder expandableChoicePromptBuilder; + private String text; - public ExpandableChoiceSeparatorBuilder(ExpandableChoicePromptBuilder expandableChoicePromptBuilder) { - this.expandableChoicePromptBuilder = expandableChoicePromptBuilder; - } + public ExpandableChoiceSeparatorBuilder(ExpandableChoicePromptBuilder expandableChoicePromptBuilder) { + this.expandableChoicePromptBuilder = expandableChoicePromptBuilder; + } - public ExpandableChoiceSeparatorBuilder text(String text) { - this.text = text; - return this; - } + public ExpandableChoiceSeparatorBuilder text(String text) { + this.text = text; + return this; + } - public ExpandableChoicePromptBuilder add() { - Separator separator = new Separator(text); - expandableChoicePromptBuilder.addItem(separator); + public ExpandableChoicePromptBuilder add() { + Separator separator = new Separator(text); + expandableChoicePromptBuilder.addItem(separator); - return expandableChoicePromptBuilder; - } + return expandableChoicePromptBuilder; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java index 7078c0c0f..80c00f787 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; import org.jline.consoleui.elements.InputValue; @@ -7,51 +15,51 @@ * Created by andy on 22.01.16. */ public class InputValueBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String defaultValue; - private String message; - private Character mask; - private Completer completer; - - public InputValueBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - } - - public InputValueBuilder name(String name) { - this.name = name; - return this; - } - - public InputValueBuilder defaultValue(String defaultValue) { - this.defaultValue = defaultValue; - return this; - } - - public InputValueBuilder message(String message) { - this.message = message; - return this; - } - - public InputValueBuilder mask(char mask) { - this.mask = mask; - return this; - } - - public PromptBuilder addPrompt() { - InputValue inputValue = new InputValue(name, message, null, defaultValue); - if (mask != null) { - inputValue.setMask(mask); + private final PromptBuilder promptBuilder; + private String name; + private String defaultValue; + private String message; + private Character mask; + private Completer completer; + + public InputValueBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + } + + public InputValueBuilder name(String name) { + this.name = name; + return this; } - if (completer != null) { - inputValue.setCompleter(completer); + + public InputValueBuilder defaultValue(String defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public InputValueBuilder message(String message) { + this.message = message; + return this; + } + + public InputValueBuilder mask(char mask) { + this.mask = mask; + return this; + } + + public PromptBuilder addPrompt() { + InputValue inputValue = new InputValue(name, message, null, defaultValue); + if (mask != null) { + inputValue.setMask(mask); + } + if (completer != null) { + inputValue.setCompleter(completer); + } + promptBuilder.addPrompt(inputValue); + return promptBuilder; + } + + public InputValueBuilder addCompleter(Completer completer) { + this.completer = completer; + return this; } - promptBuilder.addPrompt(inputValue); - return promptBuilder; - } - - public InputValueBuilder addCompleter(Completer completer) { - this.completer = completer; - return this; - } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java index 81b292995..cef7f4130 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; import org.jline.consoleui.elements.items.impl.ListItem; @@ -6,26 +14,26 @@ * Created by andy on 22.01.16. */ public class ListItemBuilder { - private final ListPromptBuilder listPromptBuilder; - private String text; - private String name; + private final ListPromptBuilder listPromptBuilder; + private String text; + private String name; - public ListItemBuilder(ListPromptBuilder listPromptBuilder) { - this.listPromptBuilder = listPromptBuilder; - } + public ListItemBuilder(ListPromptBuilder listPromptBuilder) { + this.listPromptBuilder = listPromptBuilder; + } - public ListItemBuilder text(String text) { - this.text = text; - return this; - } + public ListItemBuilder text(String text) { + this.text = text; + return this; + } - public ListItemBuilder name(String name) { - this.name = name; - return this; - } + public ListItemBuilder name(String name) { + this.name = name; + return this; + } - public ListPromptBuilder add() { - listPromptBuilder.addItem(new ListItem(text, name)); - return listPromptBuilder; - } + public ListPromptBuilder add() { + listPromptBuilder.addItem(new ListItem(text, name)); + return listPromptBuilder; + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java index 751d5b3fb..9c1ea352a 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java @@ -1,75 +1,82 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; +import java.util.ArrayList; +import java.util.List; + import org.jline.consoleui.elements.ListChoice; +import org.jline.consoleui.elements.PageSizeType; import org.jline.consoleui.elements.items.ListItemIF; import org.jline.consoleui.elements.items.impl.ListItem; -import org.jline.consoleui.elements.PageSizeType; - -import java.util.ArrayList; -import java.util.List; /** * Created by andy on 22.01.16. */ public class ListPromptBuilder { - private final PromptBuilder promptBuilder; - private String name; - private String message; - private int pageSize; - private PageSizeType pageSizeType; - private List itemList = new ArrayList<>(); + private final PromptBuilder promptBuilder; + private String name; + private String message; + private int pageSize; + private PageSizeType pageSizeType; + private final List itemList = new ArrayList<>(); - public ListPromptBuilder(PromptBuilder promptBuilder) { - this.promptBuilder = promptBuilder; - this.pageSize = 10; - this.pageSizeType = PageSizeType.ABSOLUTE; - } + public ListPromptBuilder(PromptBuilder promptBuilder) { + this.promptBuilder = promptBuilder; + this.pageSize = 10; + this.pageSizeType = PageSizeType.ABSOLUTE; + } - public ListPromptBuilder name(String name) { - this.name = name; - if (message != null) { - this.message = name; + public ListPromptBuilder name(String name) { + this.name = name; + if (message != null) { + this.message = name; + } + return this; } - return this; - } - public ListPromptBuilder message(String message) { - this.message = message; - if (name == null) { - name = message; + public ListPromptBuilder message(String message) { + this.message = message; + if (name == null) { + name = message; + } + return this; } - return this; - } - public ListPromptBuilder pageSize(int absoluteSize) { - this.pageSize = absoluteSize; - this.pageSizeType = PageSizeType.ABSOLUTE; - return this; - } + public ListPromptBuilder pageSize(int absoluteSize) { + this.pageSize = absoluteSize; + this.pageSizeType = PageSizeType.ABSOLUTE; + return this; + } - public ListPromptBuilder relativePageSize(int relativePageSize) { - this.pageSize = relativePageSize; - this.pageSizeType = PageSizeType.RELATIVE; - return this; - } - - public ListItemBuilder newItem() { - return new ListItemBuilder(this); - } + public ListPromptBuilder relativePageSize(int relativePageSize) { + this.pageSize = relativePageSize; + this.pageSizeType = PageSizeType.RELATIVE; + return this; + } - public ListItemBuilder newItem(String name) { - ListItemBuilder listItemBuilder = new ListItemBuilder(this); - return listItemBuilder.name(name).text(name); - } + public ListItemBuilder newItem() { + return new ListItemBuilder(this); + } - public PromptBuilder addPrompt() { - ListChoice listChoice = new ListChoice(message, name, pageSize, pageSizeType, itemList); - promptBuilder.addPrompt(listChoice); - return promptBuilder; - } + public ListItemBuilder newItem(String name) { + ListItemBuilder listItemBuilder = new ListItemBuilder(this); + return listItemBuilder.name(name).text(name); + } - void addItem(ListItem listItem) { - this.itemList.add(listItem); - } + public PromptBuilder addPrompt() { + ListChoice listChoice = new ListChoice(message, name, pageSize, pageSizeType, itemList); + promptBuilder.addPrompt(listChoice); + return promptBuilder; + } + void addItem(ListItem listItem) { + this.itemList.add(listItem); + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java index e7c51e26f..718b47a53 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java @@ -1,11 +1,18 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt.builder; -import de.codeshelf.consoleui.elements.*; -import org.jline.consoleui.elements.PromptableElementIF; - import java.util.ArrayList; import java.util.List; +import org.jline.consoleui.elements.PromptableElementIF; + /** * PromptBuilder is the builder class which creates * @@ -13,34 +20,33 @@ * on 20.01.16. */ public class PromptBuilder { - List promptList = new ArrayList(); - - public List build() { - return promptList; - } + List promptList = new ArrayList<>(); - public void addPrompt(PromptableElementIF promptableElement) { - promptList.add(promptableElement); - } + public List build() { + return promptList; + } - public InputValueBuilder createInputPrompt() { - return new InputValueBuilder(this); - } + public void addPrompt(PromptableElementIF promptableElement) { + promptList.add(promptableElement); + } - public ListPromptBuilder createListPrompt() { - return new ListPromptBuilder(this); - } + public InputValueBuilder createInputPrompt() { + return new InputValueBuilder(this); + } - public ExpandableChoicePromptBuilder createChoicePrompt() { - return new ExpandableChoicePromptBuilder(this); - } + public ListPromptBuilder createListPrompt() { + return new ListPromptBuilder(this); + } - public CheckboxPromptBuilder createCheckboxPrompt() { - return new CheckboxPromptBuilder(this); - } + public ExpandableChoicePromptBuilder createChoicePrompt() { + return new ExpandableChoicePromptBuilder(this); + } + public CheckboxPromptBuilder createCheckboxPrompt() { + return new CheckboxPromptBuilder(this); + } - public ConfirmPromptBuilder createConfirmPromp() { - return new ConfirmPromptBuilder(this); - } + public ConfirmPromptBuilder createConfirmPromp() { + return new ConfirmPromptBuilder(this); + } } diff --git a/console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java b/console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java deleted file mode 100644 index 873965782..000000000 --- a/console-ui/src/main/java/org/jline/consoleui/util/BuilderIF.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.jline.consoleui.util; - -/** - * User: Andreas Wegmann - * Date: 04.01.16 - */ -public interface BuilderIF { - T build(); -} diff --git a/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java b/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java new file mode 100644 index 000000000..ba8f2aa4f --- /dev/null +++ b/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package org.jline.consoleui.examples; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.jline.consoleui.elements.ConfirmChoice; +import org.jline.consoleui.prompt.ConfirmResult; +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.PromptBuilder; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.impl.completer.StringsCompleter; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; +import org.jline.utils.AttributedStyle; +import org.jline.utils.OSUtils; + +/** + * User: Andreas Wegmann + * Date: 29.11.15 + */ +public class Basic { + + private static void addInHeader(List header, String text) { + addInHeader(header, AttributedStyle.DEFAULT, text); + } + + private static void addInHeader(List header, AttributedStyle style, String text) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.style(style).append(text); + header.add(asb.toAttributedString()); + } + + public static void main(String[] args) { + List header = new ArrayList<>(); + AttributedStyle style = new AttributedStyle(); + addInHeader(header, style.italic().foreground(2), "Hello World!"); + addInHeader( + header, "This is a demonstration of ConsoleUI java library. It provides a simple console interface"); + addInHeader( + header, + "for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written"); + addInHeader(header, "in JavaScript."); + try (Terminal terminal = TerminalBuilder.builder().build()) { + ConsolePrompt.UiConfig config; + if (terminal.getType().equals(Terminal.TYPE_DUMB) + || terminal.getType().equals(Terminal.TYPE_DUMB_COLOR)) { + System.out.println(terminal.getName() + ": " + terminal.getType()); + throw new IllegalStateException("Dumb terminal detected.\nConsoleUi requires real terminal to work!\n" + + "Note: On Windows Jansi or JNA library must be included in classpath."); + } else if (OSUtils.IS_WINDOWS) { + config = new ConsolePrompt.UiConfig(">", "( )", "(x)", "( )"); + } else { + config = new ConsolePrompt.UiConfig("\u276F", "\u25EF ", "\u25C9 ", "\u25EF "); + } + // + // LineReader is needed only if you are adding JLine Completers in your prompts. + // If you are not using Completers you do not need to create LineReader. + // + LineReader reader = LineReaderBuilder.builder().terminal(terminal).build(); + ConsolePrompt prompt = new ConsolePrompt(reader, terminal, config); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder + .createInputPrompt() + .name("name") + .message("Please enter your name") + .defaultValue("John Doe") + // .mask('*') + .addCompleter( + // new Completers.FilesCompleter(() -> Paths.get(System.getProperty("user.dir")))) + new StringsCompleter("Jim", "Jack", "John", "Donald", "Dock")) + .addPrompt(); + + promptBuilder + .createListPrompt() + .name("pizzatype") + .message("Which pizza do you want?") + .newItem() + .text("Margherita") + .add() // without name (name defaults to text) + .newItem("veneziana") + .text("Veneziana") + .add() + .newItem("hawai") + .text("Hawai") + .add() + .newItem("quattro") + .text("Quattro Stagioni") + .add() + .addPrompt(); + + promptBuilder + .createCheckboxPrompt() + .name("topping") + .message("Please select additional toppings:") + .newSeparator("standard toppings") + .add() + .newItem() + .name("cheese") + .text("Cheese") + .add() + .newItem("bacon") + .text("Bacon") + .add() + .newItem("onions") + .text("Onions") + .disabledText("Sorry. Out of stock.") + .add() + .newSeparator() + .text("special toppings") + .add() + .newItem("salami") + .text("Very hot salami") + .check() + .add() + .newItem("salmon") + .text("Smoked Salmon") + .add() + .newSeparator("and our speciality...") + .add() + .newItem("special") + .text("Anchovies, and olives") + .checked(true) + .add() + .addPrompt(); + + promptBuilder + .createChoicePrompt() + .name("payment") + .message("How do you want to pay?") + .newItem() + .name("cash") + .message("Cash") + .key('c') + .asDefault() + .add() + .newItem("visa") + .message("Visa Card") + .key('v') + .add() + .newItem("master") + .message("Master Card") + .key('m') + .add() + .newSeparator("online payment") + .add() + .newItem("paypal") + .message("Paypal") + .key('p') + .add() + .addPrompt(); + + promptBuilder + .createConfirmPromp() + .name("delivery") + .message("Is this pizza for delivery?") + .defaultValue(ConfirmChoice.ConfirmationValue.YES) + .addPrompt(); + + Map result = prompt.prompt(header, promptBuilder.build()); + System.out.println("result = " + result); + + ConfirmResult delivery = (ConfirmResult) result.get("delivery"); + if (delivery.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) { + System.out.println("We will deliver the pizza in 5 minutes"); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java b/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java new file mode 100644 index 000000000..5096bed20 --- /dev/null +++ b/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package org.jline.consoleui.examples; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.CheckboxPromptBuilder; +import org.jline.consoleui.prompt.builder.ListPromptBuilder; +import org.jline.consoleui.prompt.builder.PromptBuilder; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; + +/** + * User: Andreas Wegmann + * Date: 29.11.15 + */ +public class LongList { + + public static void main(String[] args) { + List header = new ArrayList<>(); + header.add(new AttributedStringBuilder() + .append("This is a demonstration of ConsoleUI java library. It provides a simple console interface") + .toAttributedString()); + header.add(new AttributedStringBuilder() + .append("for querying information from the user. ConsoleUI is inspired by Inquirer.js which is written") + .toAttributedString()); + header.add(new AttributedStringBuilder().append("in JavaScript.").toAttributedString()); + + try (Terminal terminal = TerminalBuilder.builder().build()) { + ConsolePrompt.UiConfig config = new ConsolePrompt.UiConfig(">", "( )", "(x)", "( )"); + ConsolePrompt prompt = new ConsolePrompt(terminal, config); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + ListPromptBuilder listPrompt = promptBuilder.createListPrompt(); + listPrompt.name("longlist").message("What's your favourite Letter?").relativePageSize(66); + + for (char letter = 'A'; letter <= 'C'; letter++) + for (char letter2 = 'A'; letter2 <= 'Z'; letter2++) + listPrompt.newItem().text("" + letter + letter2).add(); + listPrompt.addPrompt(); + + CheckboxPromptBuilder checkboxPrompt = promptBuilder.createCheckboxPrompt(); + checkboxPrompt + .name("longcheckbox") + .message("What's your favourite Letter? Select all you want...") + .relativePageSize(66); + + for (char letter = 'A'; letter <= 'C'; letter++) + for (char letter2 = 'A'; letter2 <= 'Z'; letter2++) + checkboxPrompt.newItem().text("" + letter + letter2).add(); + checkboxPrompt.addPrompt(); + + Map result = prompt.prompt(header, promptBuilder.build()); + System.out.println("result = " + result); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java b/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java new file mode 100644 index 000000000..21c28bcdc --- /dev/null +++ b/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package org.jline.consoleui.examples; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.consoleui.prompt.PromptResultItemIF; +import org.jline.consoleui.prompt.builder.PromptBuilder; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; + +/** + * User: Andreas Wegmann + * Date: 12.08.2020 + */ +public class SimpleExample { + + public static void main(String[] args) { + List header = new ArrayList<>(); + header.add(new AttributedStringBuilder().append("Simple list example:").toAttributedString()); + + try (Terminal terminal = TerminalBuilder.builder().build()) { + ConsolePrompt prompt = new ConsolePrompt(terminal); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder + .createListPrompt() + .name("pizzatype") + .message("Which pizza do you want?") + .newItem() + .text("Margherita") + .add() // without name (name defaults to text) + .newItem("veneziana") + .text("Veneziana") + .add() + .newItem("hawai") + .text("Hawai") + .add() + .newItem("quattro") + .text("Quattro Stagioni") + .add() + .addPrompt(); + + Map result = prompt.prompt(header, promptBuilder.build()); + System.out.println("result = " + result); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java index 7b7bb70fc..d341e5dad 100644 --- a/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java @@ -1,32 +1,37 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; +import java.util.ArrayList; +import java.util.List; + import org.jline.consoleui.elements.items.CheckboxItemIF; import org.jline.consoleui.elements.items.impl.CheckboxItem; import org.jline.consoleui.elements.items.impl.Separator; -import org.junit.Test; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import org.junit.jupiter.api.Test; /** * User: Andreas Wegmann * Date: 07.12.15 */ public class CheckboxPromptTest { - @Test - public void renderSimpleList() throws IOException { - List list= new ArrayList<>(); - - list.add(new CheckboxItem("One")); - list.add(new CheckboxItem(true,"Two")); - CheckboxItem three = new CheckboxItem("Three"); - three.setDisabled("not available"); - list.add(three); - list.add(new Separator("some extra items")); - list.add(new CheckboxItem("Four")); - list.add(new CheckboxItem(true,"Five")); - - } + @Test + public void renderSimpleList() { + List list = new ArrayList<>(); -} \ No newline at end of file + list.add(new CheckboxItem("One")); + list.add(new CheckboxItem(true, "Two")); + CheckboxItem three = new CheckboxItem("Three"); + three.setDisabled("not available"); + list.add(three); + list.add(new Separator("some extra items")); + list.add(new CheckboxItem("Four")); + list.add(new CheckboxItem(true, "Five")); + } +} diff --git a/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java index 99840fc09..04f9c4c8d 100644 --- a/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java @@ -1,8 +1,14 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; -import org.junit.Test; - -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; /** * User: Andreas Wegmann @@ -10,9 +16,6 @@ */ public class ExpandableChoicePromptTest { - @Test - public void testPrompt() throws Exception { - - - } -} \ No newline at end of file + @Test + public void testPrompt() throws Exception {} +} diff --git a/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java index 0819381f7..584bb4a52 100644 --- a/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java @@ -1,16 +1,23 @@ +/* + * Copyright (c) 2024, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ package org.jline.consoleui.prompt; +import java.io.IOException; +import java.util.List; + import org.jline.consoleui.elements.ConfirmChoice; import org.jline.consoleui.elements.PromptableElementIF; -import org.jline.consoleui.prompt.ConsolePrompt; import org.jline.consoleui.prompt.builder.PromptBuilder; import org.jline.terminal.TerminalBuilder; -import org.junit.Test; - -import java.io.IOException; -import java.util.List; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * User: Andreas Wegmann @@ -18,73 +25,111 @@ */ public class PromptBuilderTest { - @Test - public void testBuilder() throws IOException { - ConsolePrompt prompt = new ConsolePrompt(TerminalBuilder.builder().build()); - PromptBuilder promptBuilder = prompt.getPromptBuilder(); - - promptBuilder.createConfirmPromp() - .name("wantapizza") - .message("Do you want to order a pizza?") - .defaultValue(ConfirmChoice.ConfirmationValue.YES) - .addPrompt(); - - promptBuilder.createInputPrompt() - .name("name") - .message("Please enter your name") - .defaultValue("John Doe") - .addPrompt(); - - promptBuilder.createListPrompt() - .name("pizzatype") - .message("Which pizza do you want?") - .newItem().text("Margherita").add() // without name (name defaults to text) - .newItem("veneziana").text("Veneziana").add() - .newItem("hawai").text("Hawai").add() - .newItem("quattro").text("Quattro Stagioni").add() - .addPrompt(); - - promptBuilder.createCheckboxPrompt() - .name("topping") - .message("Please select additional toppings:") - - .newSeparator("standard toppings") - .add() - - .newItem().name("cheese").text("Cheese").add() - .newItem("bacon").text("Bacon").add() - .newItem("onions").text("Onions").disabledText("Sorry. Out of stock.").add() - - .newSeparator().text("special toppings").add() - - .newItem("salami").text("Very hot salami").check().add() - .newItem("salmon").text("Smoked Salmon").add() - - .newSeparator("and our speciality...").add() - - .newItem("special").text("Anchovies, and olives").checked(true).add() - .addPrompt(); - - assertNotNull(promptBuilder); - promptBuilder.createChoicePrompt() - .name("payment") - .message("How do you want to pay?") - - .newItem().name("cash").message("Cash").key('c').asDefault().add() - .newItem("visa").message("Visa Card").key('v').add() - .newItem("master").message("Master Card").key('m').add() - .newSeparator("online payment").add() - .newItem("paypal").message("Paypal").key('p').add() - .addPrompt(); - - List promptableElementList = promptBuilder.build(); - - // only for test. reset the default reader to a test reader to automate the input - //promptableElementList.get(0) - - //HashMap result = prompt.prompt(promptableElementList); - - } - - -} \ No newline at end of file + @Test + public void testBuilder() throws IOException { + ConsolePrompt prompt = new ConsolePrompt(TerminalBuilder.builder().build()); + PromptBuilder promptBuilder = prompt.getPromptBuilder(); + + promptBuilder + .createConfirmPromp() + .name("wantapizza") + .message("Do you want to order a pizza?") + .defaultValue(ConfirmChoice.ConfirmationValue.YES) + .addPrompt(); + + promptBuilder + .createInputPrompt() + .name("name") + .message("Please enter your name") + .defaultValue("John Doe") + .addPrompt(); + + promptBuilder + .createListPrompt() + .name("pizzatype") + .message("Which pizza do you want?") + .newItem() + .text("Margherita") + .add() // without name (name defaults to text) + .newItem("veneziana") + .text("Veneziana") + .add() + .newItem("hawai") + .text("Hawai") + .add() + .newItem("quattro") + .text("Quattro Stagioni") + .add() + .addPrompt(); + + promptBuilder + .createCheckboxPrompt() + .name("topping") + .message("Please select additional toppings:") + .newSeparator("standard toppings") + .add() + .newItem() + .name("cheese") + .text("Cheese") + .add() + .newItem("bacon") + .text("Bacon") + .add() + .newItem("onions") + .text("Onions") + .disabledText("Sorry. Out of stock.") + .add() + .newSeparator() + .text("special toppings") + .add() + .newItem("salami") + .text("Very hot salami") + .check() + .add() + .newItem("salmon") + .text("Smoked Salmon") + .add() + .newSeparator("and our speciality...") + .add() + .newItem("special") + .text("Anchovies, and olives") + .checked(true) + .add() + .addPrompt(); + + assertNotNull(promptBuilder); + promptBuilder + .createChoicePrompt() + .name("payment") + .message("How do you want to pay?") + .newItem() + .name("cash") + .message("Cash") + .key('c') + .asDefault() + .add() + .newItem("visa") + .message("Visa Card") + .key('v') + .add() + .newItem("master") + .message("Master Card") + .key('m') + .add() + .newSeparator("online payment") + .add() + .newItem("paypal") + .message("Paypal") + .key('p') + .add() + .addPrompt(); + + List promptableElementList = promptBuilder.build(); + + // only for test. reset the default reader to a test reader to automate the input + // promptableElementList.get(0) + + // HashMap result = prompt.prompt(promptableElementList); + + } +} From dd4145bfdbe78939c190d0709d905fce2d169415 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 23 Jan 2024 13:58:36 +0100 Subject: [PATCH 115/115] Remove useless javadoc, rely on git history instead --- .../jline/consoleui/elements/AbstractPromptableElement.java | 4 ---- .../src/main/java/org/jline/consoleui/elements/Checkbox.java | 4 ---- .../java/org/jline/consoleui/elements/ConfirmChoice.java | 4 ---- .../java/org/jline/consoleui/elements/ExpandableChoice.java | 4 ---- .../main/java/org/jline/consoleui/elements/InputValue.java | 4 ---- .../main/java/org/jline/consoleui/elements/ListChoice.java | 4 ---- .../org/jline/consoleui/elements/PromptableElementIF.java | 4 ---- .../org/jline/consoleui/elements/items/CheckboxItemIF.java | 4 ---- .../org/jline/consoleui/elements/items/ChoiceItemIF.java | 4 ---- .../org/jline/consoleui/elements/items/ConsoleUIItemIF.java | 4 ---- .../java/org/jline/consoleui/elements/items/ListItemIF.java | 4 ---- .../jline/consoleui/elements/items/impl/CheckboxItem.java | 4 ---- .../org/jline/consoleui/elements/items/impl/ChoiceItem.java | 4 ---- .../org/jline/consoleui/elements/items/impl/ListItem.java | 4 ---- .../org/jline/consoleui/elements/items/impl/Separator.java | 4 ---- .../main/java/org/jline/consoleui/prompt/AbstractPrompt.java | 2 -- .../main/java/org/jline/consoleui/prompt/CheckboxResult.java | 3 --- .../main/java/org/jline/consoleui/prompt/ConfirmResult.java | 3 --- .../main/java/org/jline/consoleui/prompt/ConsolePrompt.java | 2 -- .../org/jline/consoleui/prompt/ExpandableChoiceResult.java | 3 --- .../main/java/org/jline/consoleui/prompt/InputResult.java | 5 ----- .../src/main/java/org/jline/consoleui/prompt/ListResult.java | 2 -- .../java/org/jline/consoleui/prompt/PromptResultItemIF.java | 3 --- .../jline/consoleui/prompt/builder/CheckboxItemBuilder.java | 3 --- .../consoleui/prompt/builder/CheckboxPromptBuilder.java | 3 --- .../consoleui/prompt/builder/CheckboxSeparatorBuilder.java | 3 --- .../jline/consoleui/prompt/builder/ConfirmPromptBuilder.java | 4 ---- .../prompt/builder/ExpandableChoiceItemBuilder.java | 3 --- .../prompt/builder/ExpandableChoicePromptBuilder.java | 3 --- .../prompt/builder/ExpandableChoiceSeparatorBuilder.java | 3 --- .../jline/consoleui/prompt/builder/InputValueBuilder.java | 3 --- .../org/jline/consoleui/prompt/builder/ListItemBuilder.java | 3 --- .../jline/consoleui/prompt/builder/ListPromptBuilder.java | 3 --- .../org/jline/consoleui/prompt/builder/PromptBuilder.java | 3 --- .../src/test/java/org/jline/consoleui/examples/Basic.java | 4 ---- .../src/test/java/org/jline/consoleui/examples/LongList.java | 4 ---- .../java/org/jline/consoleui/examples/SimpleExample.java | 4 ---- .../java/org/jline/consoleui/prompt/CheckboxPromptTest.java | 4 ---- .../jline/consoleui/prompt/ExpandableChoicePromptTest.java | 4 ---- .../java/org/jline/consoleui/prompt/PromptBuilderTest.java | 4 ---- 40 files changed, 141 deletions(-) diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java b/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java index 69b1e77f3..63779af87 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/AbstractPromptableElement.java @@ -8,10 +8,6 @@ */ package org.jline.consoleui.elements; -/** - * User: Andreas Wegmann - * Date: 06.01.16 - */ public class AbstractPromptableElement implements PromptableElementIF { protected String message; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java b/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java index 216860f92..3a75b449f 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/Checkbox.java @@ -12,10 +12,6 @@ import org.jline.consoleui.elements.items.CheckboxItemIF; -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ public class Checkbox extends AbstractPromptableElement { private final int pageSize; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java index b3834f06b..2d879c5e8 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ConfirmChoice.java @@ -8,10 +8,6 @@ */ package org.jline.consoleui.elements; -/** - * User: Andreas Wegmann - * Date: 07.01.16 - */ public class ConfirmChoice extends AbstractPromptableElement { public enum ConfirmationValue { diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java index 2c2729411..4efc3b531 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ExpandableChoice.java @@ -12,10 +12,6 @@ import org.jline.consoleui.elements.items.ChoiceItemIF; -/** - * User: Andreas Wegmann - * Date: 07.01.16 - */ public class ExpandableChoice extends AbstractPromptableElement { private final List choiceItems; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java b/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java index 1e0853b01..c4fa62ac4 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/InputValue.java @@ -10,10 +10,6 @@ import org.jline.reader.Completer; -/** - * User: Andreas Wegmann - * Date: 06.01.16 - */ public class InputValue extends AbstractPromptableElement { private String value; private final String defaultValue; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java b/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java index 65a4f1ead..8b637f66e 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/ListChoice.java @@ -12,10 +12,6 @@ import org.jline.consoleui.elements.items.ListItemIF; -/** - * User: Andreas Wegmann - * Date: 04.01.16 - */ public class ListChoice extends AbstractPromptableElement { private final int pageSize; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java index 6a1e4f498..4bb24fc12 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/PromptableElementIF.java @@ -8,10 +8,6 @@ */ package org.jline.consoleui.elements; -/** - * User: Andreas Wegmann - * Date: 04.01.16 - */ public interface PromptableElementIF { String getName(); diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java index 97ca42563..fe258d713 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/CheckboxItemIF.java @@ -8,10 +8,6 @@ */ package org.jline.consoleui.elements.items; -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ public interface CheckboxItemIF extends ConsoleUIItemIF { default boolean isChecked() { return false; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java index 3d2ed8030..984540786 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ChoiceItemIF.java @@ -8,10 +8,6 @@ */ package org.jline.consoleui.elements.items; -/** - * User: Andreas Wegmann - * Date: 13.01.16 - */ public interface ChoiceItemIF extends ConsoleUIItemIF, ListItemIF { default boolean isDefaultChoice() { return false; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java index a2513d709..2a737a592 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ConsoleUIItemIF.java @@ -8,10 +8,6 @@ */ package org.jline.consoleui.elements.items; -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ public interface ConsoleUIItemIF { boolean isSelectable(); diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java index d8f19b6a7..307c1eeb9 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/ListItemIF.java @@ -8,8 +8,4 @@ */ package org.jline.consoleui.elements.items; -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ public interface ListItemIF extends ConsoleUIItemIF {} diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java index ad2028a3c..418d2f2a6 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/CheckboxItem.java @@ -11,10 +11,6 @@ import org.jline.consoleui.elements.items.CheckboxItemIF; import org.jline.consoleui.elements.items.ConsoleUIItemIF; -/** - * User: Andreas Wegmann - * Date: 07.12.15 - */ public class CheckboxItem implements CheckboxItemIF, ConsoleUIItemIF { boolean checked; String text; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java index 3984762c5..5a9fb07bd 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ChoiceItem.java @@ -10,10 +10,6 @@ import org.jline.consoleui.elements.items.ChoiceItemIF; -/** - * User: Andreas Wegmann - * Date: 07.01.16 - */ public class ChoiceItem implements ChoiceItemIF { private final Character key; private final String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java index cb867f8d1..00030fd0c 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/ListItem.java @@ -10,10 +10,6 @@ import org.jline.consoleui.elements.items.ListItemIF; -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ public class ListItem implements ListItemIF { String text; String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java index cce29a3ff..c7371c68d 100644 --- a/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java +++ b/console-ui/src/main/java/org/jline/consoleui/elements/items/impl/Separator.java @@ -12,10 +12,6 @@ import org.jline.consoleui.elements.items.ChoiceItemIF; import org.jline.consoleui.elements.items.ListItemIF; -/** - * User: Andreas Wegmann - * Date: 01.01.16 - */ public class Separator implements CheckboxItemIF, ListItemIF, ChoiceItemIF { private String message; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java b/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java index fc1a883e5..fa3b69d3e 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/AbstractPrompt.java @@ -36,8 +36,6 @@ /** * Classes for all prompt implementations. - * - * @author Matti Rinta-Nikkola */ public abstract class AbstractPrompt { protected final Terminal terminal; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java index fd1b8046d..23938b87f 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/CheckboxResult.java @@ -13,9 +13,6 @@ /** * Result of a checkbox choice. CheckboxResult contains a {@link java.util.Set} with the * IDs of the selected checkbox items. - *

- * User: Andreas Wegmann - * Date: 03.02.16 */ public class CheckboxResult implements PromptResultItemIF { Set selectedIds; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java index c630832f4..a15bb73e9 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ConfirmResult.java @@ -13,9 +13,6 @@ /** * Result of a confirmation choice. Holds a single value of 'yes' or 'no' * from enum {@link ConfirmChoice.ConfirmationValue}. - *

- * User: Andreas Wegmann - * Date: 03.02.16 */ public class ConfirmResult implements PromptResultItemIF { ConfirmChoice.ConfirmationValue confirmed; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java index 7a740f5b6..f664c540f 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ConsolePrompt.java @@ -25,8 +25,6 @@ /** * ConsolePrompt encapsulates the prompting of a list of input questions for the user. - * - * @author Matti Rinta-Nikkola */ public class ConsolePrompt { private final LineReader reader; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java index 0f1423a87..9491af7e0 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ExpandableChoiceResult.java @@ -11,9 +11,6 @@ /** * Result of an expandable choice. ExpandableChoiceResult contains a String with the * IDs of the selected item. - *

- * User: Andreas Wegmann

- * Date: 03.02.16 */ public class ExpandableChoiceResult implements PromptResultItemIF { String selectedId; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java index d34a8ff3d..348326280 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/InputResult.java @@ -8,11 +8,6 @@ */ package org.jline.consoleui.prompt; -/** - * - * User: Andreas Wegmann - * Date: 03.02.16 - */ public class InputResult implements PromptResultItemIF { private final String input; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java b/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java index eabb2ebbe..a2609067e 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/ListResult.java @@ -10,8 +10,6 @@ /** * Result of a list choice. Holds the id of the selected item. - *

- * Created by Andreas Wegmann on 03.02.16. */ public class ListResult implements PromptResultItemIF { diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java index 26f85013c..73da56477 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/PromptResultItemIF.java @@ -8,9 +8,6 @@ */ package org.jline.consoleui.prompt; -/** - * Created by Andreas Wegmann on 03.02.16. - */ public interface PromptResultItemIF { String getResult(); } diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java index 99fee53ad..3b0dbffeb 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxItemBuilder.java @@ -11,9 +11,6 @@ import org.jline.consoleui.elements.items.CheckboxItemIF; import org.jline.consoleui.elements.items.impl.CheckboxItem; -/** - * Created by andy on 22.01.16. - */ public class CheckboxItemBuilder { private final CheckboxPromptBuilder checkboxPromptBuilder; private boolean checked; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java index 34ea8ffbd..de40baaf8 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxPromptBuilder.java @@ -15,9 +15,6 @@ import org.jline.consoleui.elements.PageSizeType; import org.jline.consoleui.elements.items.CheckboxItemIF; -/** - * Created by andy on 22.01.16. - */ public class CheckboxPromptBuilder { private final PromptBuilder promptBuilder; private String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java index f70617afe..dc1e6b055 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/CheckboxSeparatorBuilder.java @@ -10,9 +10,6 @@ import org.jline.consoleui.elements.items.impl.Separator; -/** - * Created by andy on 22.01.16. - */ public class CheckboxSeparatorBuilder { private final CheckboxPromptBuilder promptBuilder; private String text; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java index 3e753bccd..b574c6522 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ConfirmPromptBuilder.java @@ -10,10 +10,6 @@ import org.jline.consoleui.elements.ConfirmChoice; -/** - * User: Andreas Wegmann - * Date: 24.01.16 - */ public class ConfirmPromptBuilder { private final PromptBuilder promptBuilder; private String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java index 488bf9fb6..a053730ba 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceItemBuilder.java @@ -10,9 +10,6 @@ import org.jline.consoleui.elements.items.impl.ChoiceItem; -/** - * Created by andy on 22.01.16. - */ public class ExpandableChoiceItemBuilder { private final ExpandableChoicePromptBuilder choicePromptBuilder; private String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java index 208589411..84d7023ee 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoicePromptBuilder.java @@ -14,9 +14,6 @@ import org.jline.consoleui.elements.ExpandableChoice; import org.jline.consoleui.elements.items.ChoiceItemIF; -/** - * Created by andy on 22.01.16. - */ public class ExpandableChoicePromptBuilder { private final PromptBuilder promptBuilder; private String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java index 06f5ed742..f147c66a6 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ExpandableChoiceSeparatorBuilder.java @@ -10,9 +10,6 @@ import org.jline.consoleui.elements.items.impl.Separator; -/** - * Created by andy on 22.01.16. - */ public class ExpandableChoiceSeparatorBuilder { private final ExpandableChoicePromptBuilder expandableChoicePromptBuilder; private String text; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java index 80c00f787..cd9000311 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/InputValueBuilder.java @@ -11,9 +11,6 @@ import org.jline.consoleui.elements.InputValue; import org.jline.reader.Completer; -/** - * Created by andy on 22.01.16. - */ public class InputValueBuilder { private final PromptBuilder promptBuilder; private String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java index cef7f4130..3be5eecae 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListItemBuilder.java @@ -10,9 +10,6 @@ import org.jline.consoleui.elements.items.impl.ListItem; -/** - * Created by andy on 22.01.16. - */ public class ListItemBuilder { private final ListPromptBuilder listPromptBuilder; private String text; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java index 9c1ea352a..a767e88e5 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/ListPromptBuilder.java @@ -16,9 +16,6 @@ import org.jline.consoleui.elements.items.ListItemIF; import org.jline.consoleui.elements.items.impl.ListItem; -/** - * Created by andy on 22.01.16. - */ public class ListPromptBuilder { private final PromptBuilder promptBuilder; private String name; diff --git a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java index 718b47a53..4d3b2e555 100644 --- a/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java +++ b/console-ui/src/main/java/org/jline/consoleui/prompt/builder/PromptBuilder.java @@ -15,9 +15,6 @@ /** * PromptBuilder is the builder class which creates - * - * Created by Andreas Wegmann - * on 20.01.16. */ public class PromptBuilder { List promptList = new ArrayList<>(); diff --git a/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java b/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java index ba8f2aa4f..c532b5aa4 100644 --- a/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java +++ b/console-ui/src/test/java/org/jline/consoleui/examples/Basic.java @@ -27,10 +27,6 @@ import org.jline.utils.AttributedStyle; import org.jline.utils.OSUtils; -/** - * User: Andreas Wegmann - * Date: 29.11.15 - */ public class Basic { private static void addInHeader(List header, String text) { diff --git a/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java b/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java index 5096bed20..92ed5a386 100644 --- a/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java +++ b/console-ui/src/test/java/org/jline/consoleui/examples/LongList.java @@ -23,10 +23,6 @@ import org.jline.utils.AttributedString; import org.jline.utils.AttributedStringBuilder; -/** - * User: Andreas Wegmann - * Date: 29.11.15 - */ public class LongList { public static void main(String[] args) { diff --git a/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java b/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java index 21c28bcdc..6d9ef0dc7 100644 --- a/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java +++ b/console-ui/src/test/java/org/jline/consoleui/examples/SimpleExample.java @@ -21,10 +21,6 @@ import org.jline.utils.AttributedString; import org.jline.utils.AttributedStringBuilder; -/** - * User: Andreas Wegmann - * Date: 12.08.2020 - */ public class SimpleExample { public static void main(String[] args) { diff --git a/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java index d341e5dad..92975424d 100644 --- a/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/CheckboxPromptTest.java @@ -16,10 +16,6 @@ import org.jline.consoleui.elements.items.impl.Separator; import org.junit.jupiter.api.Test; -/** - * User: Andreas Wegmann - * Date: 07.12.15 - */ public class CheckboxPromptTest { @Test public void renderSimpleList() { diff --git a/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java index 04f9c4c8d..7e33d8e8e 100644 --- a/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/ExpandableChoicePromptTest.java @@ -10,10 +10,6 @@ import org.junit.jupiter.api.Test; -/** - * User: Andreas Wegmann - * Date: 08.01.16 - */ public class ExpandableChoicePromptTest { @Test diff --git a/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java b/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java index 584bb4a52..756ef72e4 100644 --- a/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java +++ b/console-ui/src/test/java/org/jline/consoleui/prompt/PromptBuilderTest.java @@ -19,10 +19,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; -/** - * User: Andreas Wegmann - * Date: 20.01.16 - */ public class PromptBuilderTest { @Test