/*
* Copyright (c) 2002-2016, the original author or authors.
*
* 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 jdk.internal.org.jline.terminal;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Attributes {
Control characters
/**
* Control characters
*/
public enum ControlChar {
VEOF,
VEOL,
VEOL2,
VERASE,
VWERASE,
VKILL,
VREPRINT,
VINTR,
VQUIT,
VSUSP,
VDSUSP,
VSTART,
VSTOP,
VLNEXT,
VDISCARD,
VMIN,
VTIME,
VSTATUS
}
Input flags - software input processing
/**
* Input flags - software input processing
*/
public enum InputFlag {
IGNBRK, /* ignore BREAK condition */
BRKINT, /* map BREAK to SIGINTR */
IGNPAR, /* ignore (discard) parity errors */
PARMRK, /* mark parity and framing errors */
INPCK, /* enable checking of parity errors */
ISTRIP, /* strip 8th bit off chars */
INLCR, /* map NL into CR */
IGNCR, /* ignore CR */
ICRNL, /* map CR to NL (ala CRMOD) */
IXON, /* enable output flow control */
IXOFF, /* enable input flow control */
IXANY, /* any char will restart after stop */
IMAXBEL, /* ring bell on input queue full */
IUTF8 /* maintain state for UTF-8 VERASE */
}
/*
* Output flags - software output processing
*/
public enum OutputFlag {
OPOST, /* enable following output processing */
ONLCR, /* map NL to CR-NL (ala CRMOD) */
OXTABS, /* expand tabs to spaces */
ONOEOT, /* discard EOT's (^D) on output) */
OCRNL, /* map CR to NL on output */
ONOCR, /* no CR output at column 0 */
ONLRET, /* NL performs CR function */
OFILL, /* use fill characters for delay */
NLDLY, /* \n delay */
TABDLY, /* horizontal tab delay */
CRDLY, /* \r delay */
FFDLY, /* form feed delay */
BSDLY, /* \b delay */
VTDLY, /* vertical tab delay */
OFDEL /* fill is DEL, else NUL */
}
/*
* Control flags - hardware control of terminal
*/
public enum ControlFlag {
CIGNORE, /* ignore control flags */
CS5, /* 5 bits (pseudo) */
CS6, /* 6 bits */
CS7, /* 7 bits */
CS8, /* 8 bits */
CSTOPB, /* send 2 stop bits */
CREAD, /* enable receiver */
PARENB, /* parity enable */
PARODD, /* odd parity, else even */
HUPCL, /* hang up on last close */
CLOCAL, /* ignore modem status lines */
CCTS_OFLOW, /* CTS flow control of output */
CRTS_IFLOW, /* RTS flow control of input */
CDTR_IFLOW, /* DTR flow control of input */
CDSR_OFLOW, /* DSR flow control of output */
CCAR_OFLOW /* DCD flow control of output */
}
/*
* "Local" flags - dumping ground for other state
*
* Warning: some flags in this structure begin with
* the letter "I" and look like they belong in the
* input flag.
*/
public enum LocalFlag {
ECHOKE, /* visual erase for line kill */
ECHOE, /* visually erase chars */
ECHOK, /* echo NL after line kill */
ECHO, /* enable echoing */
ECHONL, /* echo NL even if ECHO is off */
ECHOPRT, /* visual erase mode for hardcopy */
ECHOCTL, /* echo control chars as ^(Char) */
ISIG, /* enable signals INTR, QUIT, [D]SUSP */
ICANON, /* canonicalize input lines */
ALTWERASE, /* use alternate WERASE algorithm */
IEXTEN, /* enable DISCARD and LNEXT */
EXTPROC, /* external processing */
TOSTOP, /* stop background jobs from output */
FLUSHO, /* output being flushed (state) */
NOKERNINFO, /* no kernel output from VSTATUS */
PENDIN, /* XXX retype pending input (state) */
NOFLSH /* don't flush after interrupt */
}
final EnumSet<InputFlag> iflag = EnumSet.noneOf(InputFlag.class);
final EnumSet<OutputFlag> oflag = EnumSet.noneOf(OutputFlag.class);
final EnumSet<ControlFlag> cflag = EnumSet.noneOf(ControlFlag.class);
final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class);
final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class);
public Attributes() {
}
public Attributes(Attributes attr) {
copy(attr);
}
//
// Input flags
//
public EnumSet<InputFlag> getInputFlags() {
return iflag;
}
public void setInputFlags(EnumSet<InputFlag> flags) {
iflag.clear();
iflag.addAll(flags);
}
public boolean getInputFlag(InputFlag flag) {
return iflag.contains(flag);
}
public void setInputFlags(EnumSet<InputFlag> flags, boolean value) {
if (value) {
iflag.addAll(flags);
} else {
iflag.removeAll(flags);
}
}
public void setInputFlag(InputFlag flag, boolean value) {
if (value) {
iflag.add(flag);
} else {
iflag.remove(flag);
}
}
//
// Output flags
//
public EnumSet<OutputFlag> getOutputFlags() {
return oflag;
}
public void setOutputFlags(EnumSet<OutputFlag> flags) {
oflag.clear();
oflag.addAll(flags);
}
public boolean getOutputFlag(OutputFlag flag) {
return oflag.contains(flag);
}
public void setOutputFlags(EnumSet<OutputFlag> flags, boolean value) {
if (value) {
oflag.addAll(flags);
} else {
oflag.removeAll(flags);
}
}
public void setOutputFlag(OutputFlag flag, boolean value) {
if (value) {
oflag.add(flag);
} else {
oflag.remove(flag);
}
}
//
// Control flags
//
public EnumSet<ControlFlag> getControlFlags() {
return cflag;
}
public void setControlFlags(EnumSet<ControlFlag> flags) {
cflag.clear();
cflag.addAll(flags);
}
public boolean getControlFlag(ControlFlag flag) {
return cflag.contains(flag);
}
public void setControlFlags(EnumSet<ControlFlag> flags, boolean value) {
if (value) {
cflag.addAll(flags);
} else {
cflag.removeAll(flags);
}
}
public void setControlFlag(ControlFlag flag, boolean value) {
if (value) {
cflag.add(flag);
} else {
cflag.remove(flag);
}
}
//
// Local flags
//
public EnumSet<LocalFlag> getLocalFlags() {
return lflag;
}
public void setLocalFlags(EnumSet<LocalFlag> flags) {
lflag.clear();
lflag.addAll(flags);
}
public boolean getLocalFlag(LocalFlag flag) {
return lflag.contains(flag);
}
public void setLocalFlags(EnumSet<LocalFlag> flags, boolean value) {
if (value) {
lflag.addAll(flags);
} else {
lflag.removeAll(flags);
}
}
public void setLocalFlag(LocalFlag flag, boolean value) {
if (value) {
lflag.add(flag);
} else {
lflag.remove(flag);
}
}
//
// Control chars
//
public EnumMap<ControlChar, Integer> getControlChars() {
return cchars;
}
public void setControlChars(EnumMap<ControlChar, Integer> chars) {
cchars.clear();
cchars.putAll(chars);
}
public int getControlChar(ControlChar c) {
Integer v = cchars.get(c);
return v != null ? v : -1;
}
public void setControlChar(ControlChar c, int value) {
cchars.put(c, value);
}
//
// Miscellaneous methods
//
public void copy(Attributes attributes) {
setControlFlags(attributes.getControlFlags());
setInputFlags(attributes.getInputFlags());
setLocalFlags(attributes.getLocalFlags());
setOutputFlags(attributes.getOutputFlags());
setControlChars(attributes.getControlChars());
}
@Override
public String toString() {
return "Attributes[" +
"lflags: " + append(lflag) + ", " +
"iflags: " + append(iflag) + ", " +
"oflags: " + append(oflag) + ", " +
"cflags: " + append(cflag) + ", " +
"cchars: " + append(EnumSet.allOf(ControlChar.class), this::display) +
"]";
}
private String display(ControlChar c) {
String value;
int ch = getControlChar(c);
if (c == ControlChar.VMIN || c == ControlChar.VTIME) {
value = Integer.toString(ch);
} else if (ch < 0) {
value = "<undef>";
} else if (ch < 32) {
value = "^" + (char) (ch + 'A' - 1);
} else if (ch == 127) {
value = "^?";
} else if (ch >= 128) {
value = String.format("\\u%04x", ch);
} else {
value = String.valueOf((char) ch);
}
return c.name().toLowerCase().substring(1) + "=" + value;
}
private <T extends Enum<T>> String append(EnumSet<T> set) {
return append(set, e -> e.name().toLowerCase());
}
private <T extends Enum<T>> String append(EnumSet<T> set, Function<T, String> toString) {
return set.stream().map(toString).collect(Collectors.joining(" "));
}
}