Files
terminal-ui/src/main/java/dev/jakub/terminal/interactive/Prompt.java

90 lines
2.5 KiB
Java

package dev.jakub.terminal.interactive;
import dev.jakub.terminal.Terminal;
import dev.jakub.terminal.core.TerminalSupport;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Scanner;
/**
* Input prompt for reading user input. Use via {@link Terminal#prompt(String)}.
* Supports masked input for passwords. Injectable input/output for tests.
*/
public final class Prompt {
private final String message;
private final TerminalSupport support;
private boolean masked;
private PrintStream out = System.out;
private InputStream in = System.in;
public Prompt(String message, TerminalSupport support) {
this.message = message != null ? message : "";
this.support = support;
}
/**
* Hides input (e.g. for passwords). Shows * per character or blank.
*/
public Prompt masked() {
this.masked = true;
return this;
}
/**
* Sets the output stream (default: stdout).
*/
public Prompt output(PrintStream out) {
this.out = out != null ? out : System.out;
return this;
}
/**
* Sets the input stream (default: stdin). Useful for tests.
*/
public Prompt input(InputStream in) {
this.in = in != null ? in : System.in;
return this;
}
/**
* Prompts and returns the entered string. Blocks until a line is read.
*/
public String ask() {
out.print(message);
out.flush();
if (masked) {
return readMasked();
}
try (Scanner scan = new Scanner(in)) {
return scan.hasNextLine() ? scan.nextLine() : "";
}
}
/**
* Prompts and returns the next line from the given scanner. Use this when
* sharing one scanner (e.g. in an interactive app) so input blocks correctly.
*/
public String ask(Scanner sharedScanner) {
if (sharedScanner == null) return ask();
out.print(message);
out.flush();
if (masked && System.console() != null) {
char[] chars = System.console().readPassword();
return chars != null ? new String(chars) : "";
}
return sharedScanner.hasNextLine() ? sharedScanner.nextLine() : "";
}
private String readMasked() {
if (System.console() != null) {
char[] chars = System.console().readPassword();
return chars != null ? new String(chars) : "";
}
try (Scanner scan = new Scanner(in)) {
return scan.hasNextLine() ? scan.nextLine() : "";
}
}
}