InputConfirmation.java
/*
* Copyright (c) 2016, Stein Eldar Johnsen
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package net.morimekta.terminal.input;
import net.morimekta.strings.chr.Char;
import net.morimekta.strings.chr.Control;
import net.morimekta.terminal.Terminal;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.function.BooleanSupplier;
/**
*
*/
public class InputConfirmation implements BooleanSupplier {
/**
* Constructor for simple confirmation.
*
* @param terminal Terminal to use.
* @param confirmation Message to print.
*/
public InputConfirmation(Terminal terminal, String confirmation) {
this(terminal, confirmation, null);
}
/**
* Constructor for complete line-input.
*
* @param terminal Terminal to use.
* @param confirmation Message to print.
* @param defaultValue Default value to return on e.g. 'enter'.
*/
public InputConfirmation(Terminal terminal, String confirmation, Boolean defaultValue) {
this.terminal = terminal;
this.confirmation = confirmation;
this.defaultValue = defaultValue;
}
@Override
public boolean getAsBoolean() {
terminal.formatln("%s", confirmation);
try {
for (; ; ) {
Char c = terminal.read();
if (c == null) {
throw new IOException("End of stream.");
}
handleInterrupt(c);
if (isConfirmation(c)) {
printConfirmation(true);
return true;
} else if (isRejection(c)) {
printConfirmation(false);
return false;
} else if (isDefault(c)) {
if (defaultValue != null) {
printConfirmation(defaultValue);
return defaultValue;
} else {
// ignore this letter if no default value exists.
continue;
}
}
printMessage(String.format("'%s' is not valid input.", c.asString()));
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* Handle backspace. These are not control sequences, so must be handled separately
* from those.
*
* @param c The char instance.
* @return True if default value should be used.
*/
protected boolean isDefault(Char c) {
return c.codepoint() == '\n' || c.codepoint() == ' ';
}
/**
* @param c The char instance.
* @return True if confirmation is rejected.
*/
protected boolean isRejection(Char c) {
return c.codepoint() == 'n' || c.codepoint() == Char.DEL || c.codepoint() == Char.BS;
}
/**
* If the provided char indicates confirmation.
*
* @param c The char instance.
* @return True if confirmation is accepted.
*/
protected boolean isConfirmation(Char c) {
return c.codepoint() == 'y';
}
/**
* Handle user interrupts.
*
* @param c The char instance.
* @throws IOException If interrupted.
*/
protected void handleInterrupt(Char c) throws IOException {
if (c.codepoint() == Char.ESC || c.codepoint() == Char.ABR || c.codepoint() == Char.EOF) {
printMessage("User interrupted.");
throw new IOException("User interrupted: " + c.asString());
}
}
/**
* Print confirmation.
*
* @param result The result to be printed.
*/
protected void printConfirmation(boolean result) {
if (result) {
printMessage("Yes.");
} else {
printMessage("No.");
}
}
private void printMessage(String message) {
if (printedMessage == null) {
terminal.format(" %s", message);
} else {
terminal.format("\r%s%s %s", Control.CURSOR_ERASE, this.confirmation, message);
}
printedMessage = message;
}
private final Terminal terminal;
private final String confirmation;
private final Boolean defaultValue;
private String printedMessage;
}