8327476: Upgrade JLine to 3.26.1

Reviewed-by: ihse, vromero
This commit is contained in:
Jan Lahoda 2024-05-09 13:54:04 +00:00
parent 0a4eeeaa3c
commit aaa90b3005
143 changed files with 7616 additions and 7181 deletions

View File

@ -120,6 +120,7 @@ NATIVE_ACCESS_MODULES= \
jdk.dynalink \
jdk.httpserver \
jdk.incubator.vector \
jdk.internal.le \
jdk.internal.vm.ci \
jdk.jfr \
jdk.jsobject \

View File

@ -1,45 +0,0 @@
#
# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
include LibCommon.gmk
ifeq ($(call isTargetOs, aix), false)
##############################################################################
## Build lible
##############################################################################
$(eval $(call SetupJdkLibrary, BUILD_LIBLE, \
NAME := le, \
LINK_TYPE := C++, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := \
java.base:libjava \
java.base:libjvm, \
LD_SET_ORIGIN := false, \
LIBS_windows := user32.lib, \
))
TARGETS += $(BUILD_LIBLE)
endif

View File

@ -1,50 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna;
import java.io.IOException;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
class JDKNativePty {
static JnaNativePty current(TerminalProvider.Stream console) throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
static JnaNativePty open(Attributes attr, Size size) throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
static int isatty(int fd) {
throw new UnsupportedOperationException("Not supported.");
}
static String ttyname(int fd) {
throw new UnsupportedOperationException("Not supported.");
}
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna;
import java.io.IOException;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.jna.linux.LinuxNativePty;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
class JDKNativePty {
static JnaNativePty current(TerminalProvider.Stream console) throws IOException {
return LinuxNativePty.current(console);
}
static JnaNativePty open(Attributes attr, Size size) throws IOException {
return LinuxNativePty.open(attr, size);
}
static int isatty(int fd) {
return LinuxNativePty.isatty(fd);
}
static String ttyname(int fd) {
return LinuxNativePty.ttyname(fd);
}
}

View File

@ -1,389 +0,0 @@
/*
* Copyright (c) 2002-2020, 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.impl.jna.linux;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.List;
//import com.sun.jna.LastErrorException;
//import com.sun.jna.Platform;
//import com.sun.jna.Structure;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Attributes.ControlChar;
import jdk.internal.org.jline.terminal.Attributes.ControlFlag;
import jdk.internal.org.jline.terminal.Attributes.InputFlag;
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.jna.LastErrorException;
public interface CLibrary {//extends com.sun.jna.Library {
void tcgetattr(int fd, termios termios) throws LastErrorException;
void tcsetattr(int fd, int cmd, termios termios) throws LastErrorException;
void ioctl(int fd, int cmd, winsize data) throws LastErrorException;
int isatty(int fd);
void ttyname_r(int fd, byte[] buf, int len) throws LastErrorException;
class winsize { //extends Structure {
public short ws_row;
public short ws_col;
public short ws_xpixel;
public short ws_ypixel;
public winsize() {
}
public winsize(Size ws) {
ws_row = (short) ws.getRows();
ws_col = (short) ws.getColumns();
}
public Size toSize() {
return new Size(ws_col, ws_row);
}
// @Override
// protected List<String> getFieldOrder() {
// return Arrays.asList(//
// "ws_row",//
// "ws_col",//
// "ws_xpixel",//
// "ws_ypixel"//
// );
// }
}
class termios {// extends Structure {
public int c_iflag;
public int c_oflag;
public int c_cflag;
public int c_lflag;
public byte c_line;
public byte[] c_cc = new byte[32];
public int c_ispeed;
public int c_ospeed;
// @Override
// protected List<String> getFieldOrder() {
// return Arrays.asList(//
// "c_iflag",//
// "c_oflag",//
// "c_cflag",//
// "c_lflag",//
// "c_line",//
// "c_cc",//
// "c_ispeed",//
// "c_ospeed"//
// );
// }
public termios() {
}
public termios(Attributes t) {
// Input flags
c_iflag = setFlag(t.getInputFlag(InputFlag.IGNBRK), IGNBRK, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.BRKINT), BRKINT, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IGNPAR), IGNPAR, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.PARMRK), PARMRK, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.INPCK), INPCK, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.ISTRIP), ISTRIP, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.INLCR), INLCR, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IGNCR), IGNCR, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.ICRNL), ICRNL, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IXON), IXON, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IXOFF), IXOFF, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IXANY), IXANY, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IMAXBEL), IMAXBEL, c_iflag);
c_iflag = setFlag(t.getInputFlag(InputFlag.IUTF8), IUTF8, c_iflag);
// Output flags
c_oflag = setFlag(t.getOutputFlag(OutputFlag.OPOST), OPOST, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.ONLCR), ONLCR, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.OCRNL), OCRNL, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.ONOCR), ONOCR, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.ONLRET), ONLRET, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.OFILL), OFILL, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.NLDLY), NLDLY, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.TABDLY), TABDLY, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.CRDLY), CRDLY, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.FFDLY), FFDLY, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.BSDLY), BSDLY, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.VTDLY), VTDLY, c_oflag);
c_oflag = setFlag(t.getOutputFlag(OutputFlag.OFDEL), OFDEL, c_oflag);
// Control flags
c_cflag = setFlag(t.getControlFlag(ControlFlag.CS5), CS5, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.CS6), CS6, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.CS7), CS7, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.CS8), CS8, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.CSTOPB), CSTOPB, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.CREAD), CREAD, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.PARENB), PARENB, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.PARODD), PARODD, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.HUPCL), HUPCL, c_cflag);
c_cflag = setFlag(t.getControlFlag(ControlFlag.CLOCAL), CLOCAL, c_cflag);
// Local flags
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHOKE), ECHOKE, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHOE), ECHOE, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHOK), ECHOK, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHO), ECHO, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHONL), ECHONL, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHOPRT), ECHOPRT, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ECHOCTL), ECHOCTL, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ISIG), ISIG, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.ICANON), ICANON, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.EXTPROC), EXTPROC, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.TOSTOP), TOSTOP, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.FLUSHO), FLUSHO, c_lflag);
c_lflag = setFlag(t.getLocalFlag(LocalFlag.NOFLSH), NOFLSH, c_lflag);
// Control chars
c_cc[VEOF] = (byte) t.getControlChar(ControlChar.VEOF);
c_cc[VEOL] = (byte) t.getControlChar(ControlChar.VEOL);
c_cc[VEOL2] = (byte) t.getControlChar(ControlChar.VEOL2);
c_cc[VERASE] = (byte) t.getControlChar(ControlChar.VERASE);
c_cc[VWERASE] = (byte) t.getControlChar(ControlChar.VWERASE);
c_cc[VKILL] = (byte) t.getControlChar(ControlChar.VKILL);
c_cc[VREPRINT] = (byte) t.getControlChar(ControlChar.VREPRINT);
c_cc[VINTR] = (byte) t.getControlChar(ControlChar.VINTR);
c_cc[VQUIT] = (byte) t.getControlChar(ControlChar.VQUIT);
c_cc[VSUSP] = (byte) t.getControlChar(ControlChar.VSUSP);
c_cc[VSTART] = (byte) t.getControlChar(ControlChar.VSTART);
c_cc[VSTOP] = (byte) t.getControlChar(ControlChar.VSTOP);
c_cc[VLNEXT] = (byte) t.getControlChar(ControlChar.VLNEXT);
c_cc[VDISCARD] = (byte) t.getControlChar(ControlChar.VDISCARD);
c_cc[VMIN] = (byte) t.getControlChar(ControlChar.VMIN);
c_cc[VTIME] = (byte) t.getControlChar(ControlChar.VTIME);
}
private int setFlag(boolean flag, int value, int org) {
return flag ? (org | value) : org;
}
public Attributes toAttributes() {
Attributes attr = new Attributes();
// Input flags
EnumSet<InputFlag> iflag = attr.getInputFlags();
addFlag(c_iflag, iflag, InputFlag.IGNBRK, IGNBRK);
addFlag(c_iflag, iflag, InputFlag.IGNBRK, IGNBRK);
addFlag(c_iflag, iflag, InputFlag.BRKINT, BRKINT);
addFlag(c_iflag, iflag, InputFlag.IGNPAR, IGNPAR);
addFlag(c_iflag, iflag, InputFlag.PARMRK, PARMRK);
addFlag(c_iflag, iflag, InputFlag.INPCK, INPCK);
addFlag(c_iflag, iflag, InputFlag.ISTRIP, ISTRIP);
addFlag(c_iflag, iflag, InputFlag.INLCR, INLCR);
addFlag(c_iflag, iflag, InputFlag.IGNCR, IGNCR);
addFlag(c_iflag, iflag, InputFlag.ICRNL, ICRNL);
addFlag(c_iflag, iflag, InputFlag.IXON, IXON);
addFlag(c_iflag, iflag, InputFlag.IXOFF, IXOFF);
addFlag(c_iflag, iflag, InputFlag.IXANY, IXANY);
addFlag(c_iflag, iflag, InputFlag.IMAXBEL, IMAXBEL);
addFlag(c_iflag, iflag, InputFlag.IUTF8, IUTF8);
// Output flags
EnumSet<OutputFlag> oflag = attr.getOutputFlags();
addFlag(c_oflag, oflag, OutputFlag.OPOST, OPOST);
addFlag(c_oflag, oflag, OutputFlag.ONLCR, ONLCR);
addFlag(c_oflag, oflag, OutputFlag.OCRNL, OCRNL);
addFlag(c_oflag, oflag, OutputFlag.ONOCR, ONOCR);
addFlag(c_oflag, oflag, OutputFlag.ONLRET, ONLRET);
addFlag(c_oflag, oflag, OutputFlag.OFILL, OFILL);
addFlag(c_oflag, oflag, OutputFlag.NLDLY, NLDLY);
addFlag(c_oflag, oflag, OutputFlag.TABDLY, TABDLY);
addFlag(c_oflag, oflag, OutputFlag.CRDLY, CRDLY);
addFlag(c_oflag, oflag, OutputFlag.FFDLY, FFDLY);
addFlag(c_oflag, oflag, OutputFlag.BSDLY, BSDLY);
addFlag(c_oflag, oflag, OutputFlag.VTDLY, VTDLY);
addFlag(c_oflag, oflag, OutputFlag.OFDEL, OFDEL);
// Control flags
EnumSet<ControlFlag> cflag = attr.getControlFlags();
addFlag(c_cflag, cflag, ControlFlag.CS5, CS5);
addFlag(c_cflag, cflag, ControlFlag.CS6, CS6);
addFlag(c_cflag, cflag, ControlFlag.CS7, CS7);
addFlag(c_cflag, cflag, ControlFlag.CS8, CS8);
addFlag(c_cflag, cflag, ControlFlag.CSTOPB, CSTOPB);
addFlag(c_cflag, cflag, ControlFlag.CREAD, CREAD);
addFlag(c_cflag, cflag, ControlFlag.PARENB, PARENB);
addFlag(c_cflag, cflag, ControlFlag.PARODD, PARODD);
addFlag(c_cflag, cflag, ControlFlag.HUPCL, HUPCL);
addFlag(c_cflag, cflag, ControlFlag.CLOCAL, CLOCAL);
// Local flags
EnumSet<LocalFlag> lflag = attr.getLocalFlags();
addFlag(c_lflag, lflag, LocalFlag.ECHOKE, ECHOKE);
addFlag(c_lflag, lflag, LocalFlag.ECHOE, ECHOE);
addFlag(c_lflag, lflag, LocalFlag.ECHOK, ECHOK);
addFlag(c_lflag, lflag, LocalFlag.ECHO, ECHO);
addFlag(c_lflag, lflag, LocalFlag.ECHONL, ECHONL);
addFlag(c_lflag, lflag, LocalFlag.ECHOPRT, ECHOPRT);
addFlag(c_lflag, lflag, LocalFlag.ECHOCTL, ECHOCTL);
addFlag(c_lflag, lflag, LocalFlag.ISIG, ISIG);
addFlag(c_lflag, lflag, LocalFlag.ICANON, ICANON);
addFlag(c_lflag, lflag, LocalFlag.EXTPROC, EXTPROC);
addFlag(c_lflag, lflag, LocalFlag.TOSTOP, TOSTOP);
addFlag(c_lflag, lflag, LocalFlag.FLUSHO, FLUSHO);
addFlag(c_lflag, lflag, LocalFlag.NOFLSH, NOFLSH);
// Control chars
EnumMap<ControlChar, Integer> cc = attr.getControlChars();
cc.put(ControlChar.VEOF, (int) c_cc[VEOF]);
cc.put(ControlChar.VEOL, (int) c_cc[VEOL]);
cc.put(ControlChar.VEOL2, (int) c_cc[VEOL2]);
cc.put(ControlChar.VERASE, (int) c_cc[VERASE]);
cc.put(ControlChar.VWERASE, (int) c_cc[VWERASE]);
cc.put(ControlChar.VKILL, (int) c_cc[VKILL]);
cc.put(ControlChar.VREPRINT, (int) c_cc[VREPRINT]);
cc.put(ControlChar.VINTR, (int) c_cc[VINTR]);
cc.put(ControlChar.VQUIT, (int) c_cc[VQUIT]);
cc.put(ControlChar.VSUSP, (int) c_cc[VSUSP]);
cc.put(ControlChar.VSTART, (int) c_cc[VSTART]);
cc.put(ControlChar.VSTOP, (int) c_cc[VSTOP]);
cc.put(ControlChar.VLNEXT, (int) c_cc[VLNEXT]);
cc.put(ControlChar.VDISCARD, (int) c_cc[VDISCARD]);
cc.put(ControlChar.VMIN, (int) c_cc[VMIN]);
cc.put(ControlChar.VTIME, (int) c_cc[VTIME]);
// Return
return attr;
}
private <T extends Enum<T>> void addFlag(int value, EnumSet<T> flags, T flag, int v) {
if ((value & v) != 0) {
flags.add(flag);
}
}
}
// CONSTANTS
int TIOCGWINSZ = /*Platform.isMIPS() || Platform.isPPC() || Platform.isSPARC() ? 0x40087468 : */0x00005413;
int TIOCSWINSZ = /*Platform.isMIPS() || Platform.isPPC() || Platform.isSPARC() ? 0x80087467 : */0x00005414;
int VINTR = 0;
int VQUIT = 1;
int VERASE = 2;
int VKILL = 3;
int VEOF = 4;
int VTIME = 5;
int VMIN = 6;
int VSWTC = 7;
int VSTART = 8;
int VSTOP = 9;
int VSUSP = 10;
int VEOL = 11;
int VREPRINT = 12;
int VDISCARD = 13;
int VWERASE = 14;
int VLNEXT = 15;
int VEOL2 = 16;
int IGNBRK = 0x0000001;
int BRKINT = 0x0000002;
int IGNPAR = 0x0000004;
int PARMRK = 0x0000008;
int INPCK = 0x0000010;
int ISTRIP = 0x0000020;
int INLCR = 0x0000040;
int IGNCR = 0x0000080;
int ICRNL = 0x0000100;
int IUCLC = 0x0000200;
int IXON = 0x0000400;
int IXANY = 0x0000800;
int IXOFF = 0x0001000;
int IMAXBEL = 0x0002000;
int IUTF8 = 0x0004000;
int OPOST = 0x0000001;
int OLCUC = 0x0000002;
int ONLCR = 0x0000004;
int OCRNL = 0x0000008;
int ONOCR = 0x0000010;
int ONLRET = 0x0000020;
int OFILL = 0x0000040;
int OFDEL = 0x0000080;
int NLDLY = 0x0000100;
int NL0 = 0x0000000;
int NL1 = 0x0000100;
int CRDLY = 0x0000600;
int CR0 = 0x0000000;
int CR1 = 0x0000200;
int CR2 = 0x0000400;
int CR3 = 0x0000600;
int TABDLY = 0x0001800;
int TAB0 = 0x0000000;
int TAB1 = 0x0000800;
int TAB2 = 0x0001000;
int TAB3 = 0x0001800;
int XTABS = 0x0001800;
int BSDLY = 0x0002000;
int BS0 = 0x0000000;
int BS1 = 0x0002000;
int VTDLY = 0x0004000;
int VT0 = 0x0000000;
int VT1 = 0x0004000;
int FFDLY = 0x0008000;
int FF0 = 0x0000000;
int FF1 = 0x0008000;
int CBAUD = 0x000100f;
int B0 = 0x0000000;
int B50 = 0x0000001;
int B75 = 0x0000002;
int B110 = 0x0000003;
int B134 = 0x0000004;
int B150 = 0x0000005;
int B200 = 0x0000006;
int B300 = 0x0000007;
int B600 = 0x0000008;
int B1200 = 0x0000009;
int B1800 = 0x000000a;
int B2400 = 0x000000b;
int B4800 = 0x000000c;
int B9600 = 0x000000d;
int B19200 = 0x000000e;
int B38400 = 0x000000f;
int EXTA = B19200;
int EXTB = B38400;
int CSIZE = 0x0000030;
int CS5 = 0x0000000;
int CS6 = 0x0000010;
int CS7 = 0x0000020;
int CS8 = 0x0000030;
int CSTOPB = 0x0000040;
int CREAD = 0x0000080;
int PARENB = 0x0000100;
int PARODD = 0x0000200;
int HUPCL = 0x0000400;
int CLOCAL = 0x0000800;
int ISIG = 0x0000001;
int ICANON = 0x0000002;
int XCASE = 0x0000004;
int ECHO = 0x0000008;
int ECHOE = 0x0000010;
int ECHOK = 0x0000020;
int ECHONL = 0x0000040;
int NOFLSH = 0x0000080;
int TOSTOP = 0x0000100;
int ECHOCTL = 0x0000200;
int ECHOPRT = 0x0000400;
int ECHOKE = 0x0000800;
int FLUSHO = 0x0001000;
int PENDIN = 0x0002000;
int IEXTEN = 0x0008000;
int EXTPROC = 0x0010000;
int TCSANOW = 0x0;
int TCSADRAIN = 0x1;
int TCSAFLUSH = 0x2;
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna.linux;
import jdk.internal.org.jline.terminal.impl.jna.LastErrorException;
public final class CLibraryImpl implements CLibrary {
static {
System.loadLibrary("le");
initIDs();
}
private static native void initIDs();
@Override
public native void tcgetattr(int fd, termios termios) throws LastErrorException;
@Override
public native void tcsetattr(int fd, int cmd, termios termios) throws LastErrorException;
@Override
public void ioctl(int fd, int cmd, winsize data) throws LastErrorException {
if (cmd == CLibrary.TIOCGWINSZ || cmd == CLibrary.TIOCSWINSZ) {
ioctl0(fd, cmd, data);
} else {
throw new UnsupportedOperationException("Command: " + cmd + ", not supported.");
}
}
private native void ioctl0(int fd, int cmd, winsize data) throws LastErrorException;
@Override
public native int isatty(int fd);
@Override
public native void ttyname_r(int fd, byte[] buf, int len) throws LastErrorException;
}

View File

@ -1,122 +0,0 @@
/*
* Copyright (c) 2002-2020, 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.impl.jna.linux;
import java.io.FileDescriptor;
import java.io.IOException;
//import com.sun.jna.LastErrorException;
//import com.sun.jna.Native;
//import com.sun.jna.Platform;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.jna.JnaNativePty;
import jdk.internal.org.jline.terminal.impl.jna.LastErrorException;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import static jdk.internal.org.jline.terminal.impl.jna.linux.CLibrary.TCSADRAIN;
import static jdk.internal.org.jline.terminal.impl.jna.linux.CLibrary.TIOCGWINSZ;
import static jdk.internal.org.jline.terminal.impl.jna.linux.CLibrary.TIOCSWINSZ;
import static jdk.internal.org.jline.terminal.impl.jna.linux.CLibrary.termios;
import static jdk.internal.org.jline.terminal.impl.jna.linux.CLibrary.winsize;
public class LinuxNativePty extends JnaNativePty {
// private static final CLibrary C_LIBRARY = Native.load(Platform.C_LIBRARY_NAME, CLibrary.class);
private static final CLibrary C_LIBRARY = new CLibraryImpl();
public interface UtilLibrary {// extends com.sun.jna.Library {
void openpty(int[] master, int[] slave, byte[] name, CLibrary.termios t, CLibrary.winsize s) throws LastErrorException;
// UtilLibrary INSTANCE = Native.load("util", UtilLibrary.class);
UtilLibrary INSTANCE = new UtilLibraryImpl();
}
public static LinuxNativePty current(TerminalProvider.Stream consoleStream) throws IOException {
switch (consoleStream) {
case Output:
return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0));
case Error:
return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0));
default:
throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream);
}
}
public static LinuxNativePty open(Attributes attr, Size size) throws IOException {
int[] master = new int[1];
int[] slave = new int[1];
byte[] buf = new byte[64];
UtilLibrary.INSTANCE.openpty(master, slave, buf,
attr != null ? new termios(attr) : null,
size != null ? new winsize(size) : null);
int len = 0;
while (buf[len] != 0) {
len++;
}
String name = new String(buf, 0, len);
return new LinuxNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name);
}
public LinuxNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) {
super(master, masterFD, slave, slaveFD, name);
}
public LinuxNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, int slaveOut, FileDescriptor slaveOutFD, String name) {
super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name);
}
@Override
public Attributes getAttr() throws IOException {
termios termios = new termios();
C_LIBRARY.tcgetattr(getSlave(), termios);
return termios.toAttributes();
}
@Override
protected void doSetAttr(Attributes attr) throws IOException {
termios termios = new termios(attr);
termios org = new termios();
C_LIBRARY.tcgetattr(getSlave(), org);
org.c_iflag = termios.c_iflag;
org.c_oflag = termios.c_oflag;
org.c_lflag = termios.c_lflag;
System.arraycopy(termios.c_cc, 0, org.c_cc, 0, termios.c_cc.length);
C_LIBRARY.tcsetattr(getSlave(), TCSADRAIN, org);
}
@Override
public Size getSize() throws IOException {
winsize sz = new winsize();
C_LIBRARY.ioctl(getSlave(), TIOCGWINSZ, sz);
return sz.toSize();
}
@Override
public void setSize(Size size) throws IOException {
winsize sz = new winsize(size);
C_LIBRARY.ioctl(getSlave(), TIOCSWINSZ, sz);
}
public static int isatty(int fd) {
return C_LIBRARY.isatty(fd);
}
public static String ttyname(int slave) {
byte[] buf = new byte[64];
C_LIBRARY.ttyname_r(slave, buf, buf.length);
int len = 0;
while (buf[len] != 0) {
len++;
}
return new String(buf, 0, len);
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna.linux;
import jdk.internal.org.jline.terminal.impl.jna.LastErrorException;
import jdk.internal.org.jline.terminal.impl.jna.linux.LinuxNativePty.UtilLibrary;
public final class UtilLibraryImpl implements UtilLibrary {
@Override
public void openpty(int[] master, int[] slave, byte[] name, CLibrary.termios t, CLibrary.winsize s) throws LastErrorException {
throw new UnsupportedOperationException();
}
}

View File

@ -1,207 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl.h"
#include <errno.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
static jclass lastErrorExceptionClass;
static jmethodID lastErrorExceptionConstructor;
static jclass termios_j;
static jfieldID c_iflag;
static jfieldID c_oflag;
static jfieldID c_cflag;
static jfieldID c_lflag;
static jfieldID c_line;
static jfieldID c_cc;
static jfieldID c_ispeed;
static jfieldID c_ospeed;
static jclass winsize_j;
static jfieldID ws_row;
static jfieldID ws_col;
static jfieldID ws_xpixel;
static jfieldID ws_ypixel;
static void throw_errno(JNIEnv *env);
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl_initIDs
(JNIEnv *env, jclass unused) {
jclass cls;
cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/LastErrorException");
CHECK_NULL(cls);
lastErrorExceptionClass = (jclass) env->NewGlobalRef(cls);
lastErrorExceptionConstructor = env->GetMethodID(lastErrorExceptionClass, "<init>", "(J)V");
CHECK_NULL(lastErrorExceptionConstructor);
cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/linux/CLibrary$termios");
CHECK_NULL(cls);
termios_j = (jclass) env->NewGlobalRef(cls);
c_iflag = env->GetFieldID(termios_j, "c_iflag", "I");
CHECK_NULL(c_iflag);
c_oflag = env->GetFieldID(termios_j, "c_oflag", "I");
CHECK_NULL(c_oflag);
c_cflag = env->GetFieldID(termios_j, "c_cflag", "I");
CHECK_NULL(c_cflag);
c_lflag = env->GetFieldID(termios_j, "c_lflag", "I");
CHECK_NULL(c_lflag);
c_line = env->GetFieldID(termios_j, "c_line", "B");
CHECK_NULL(c_line);
c_cc = env->GetFieldID(termios_j, "c_cc", "[B");
CHECK_NULL(c_cc);
c_ispeed = env->GetFieldID(termios_j, "c_ispeed", "I");
CHECK_NULL(c_ispeed);
c_ospeed = env->GetFieldID(termios_j, "c_ospeed", "I");
CHECK_NULL(c_ospeed);
cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/linux/CLibrary$winsize");
CHECK_NULL(cls);
winsize_j = (jclass) env->NewGlobalRef(cls);
ws_row = env->GetFieldID(winsize_j, "ws_row", "S");
CHECK_NULL(ws_row);
ws_col = env->GetFieldID(winsize_j, "ws_col", "S");
CHECK_NULL(ws_col);
ws_xpixel= env->GetFieldID(winsize_j, "ws_xpixel", "S");
CHECK_NULL(ws_xpixel);
ws_ypixel= env->GetFieldID(winsize_j, "ws_ypixel", "S");
CHECK_NULL(ws_ypixel);
}
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl_tcgetattr
(JNIEnv *env, jobject, jint fd, jobject result) {
termios data;
if (tcgetattr(fd, &data) != 0) {
throw_errno(env);
return ;
}
env->SetIntField(result, c_iflag, data.c_iflag);
env->SetIntField(result, c_oflag, data.c_oflag);
env->SetIntField(result, c_cflag, data.c_cflag);
env->SetIntField(result, c_lflag, data.c_lflag);
env->SetIntField(result, c_line, data.c_line);
jbyteArray c_ccValue = (jbyteArray) env->GetObjectField(result, c_cc);
env->SetByteArrayRegion(c_ccValue, 0, NCCS, (signed char *) data.c_cc);//TODO: cast?
env->SetIntField(result, c_ispeed, cfgetispeed(&data));
env->SetIntField(result, c_ospeed, cfgetospeed(&data));
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl
* Method: tcsetattr
* Signature: (IILjdk/internal/org/jline/terminal/impl/jna/linux/CLibrary/termios;)V
*/
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl_tcsetattr
(JNIEnv *env, jobject, jint fd, jint cmd, jobject input) {
termios data;
data.c_iflag = env->GetIntField(input, c_iflag);
data.c_oflag = env->GetIntField(input, c_oflag);
data.c_cflag = env->GetIntField(input, c_cflag);
data.c_lflag = env->GetIntField(input, c_lflag);
data.c_line = env->GetIntField(input, c_line);
jbyteArray c_ccValue = (jbyteArray) env->GetObjectField(input, c_cc);
env->GetByteArrayRegion(c_ccValue, 0, NCCS, (jbyte *) data.c_cc);
cfsetispeed(&data, env->GetIntField(input, c_ispeed));
cfsetospeed(&data, env->GetIntField(input, c_ospeed));
if (tcsetattr(fd, cmd, &data) != 0) {
throw_errno(env);
}
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl
* Method: ioctl0
* Signature: (IILjdk/internal/org/jline/terminal/impl/jna/linux/CLibrary/winsize;)V
*/
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl_ioctl0
(JNIEnv *env, jobject, jint fd, jint cmd, jobject data) {
winsize ws;
ws.ws_row = env->GetShortField(data, ws_row);
ws.ws_col = env->GetShortField(data, ws_col);
ws.ws_xpixel = env->GetShortField(data, ws_xpixel);
ws.ws_ypixel = env->GetShortField(data, ws_ypixel);
if (ioctl(fd, cmd, &ws) != 0) {
throw_errno(env);
return ;
}
env->SetShortField(data, ws_row, ws.ws_row);
env->SetShortField(data, ws_col, ws.ws_col);
env->SetShortField(data, ws_xpixel, ws.ws_xpixel);
env->SetShortField(data, ws_ypixel, ws.ws_ypixel);
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl
* Method: isatty
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl_isatty
(JNIEnv *, jobject, jint fd) {
return isatty(fd);
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl
* Method: ttyname_r
* Signature: (I[BI)V
*/
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_linux_CLibraryImpl_ttyname_1r
(JNIEnv *env, jobject, jint fd, jbyteArray buf, jint len) {
char *data = new char[len];
int error = ttyname_r(fd, data, len);
if (error != 0) {
delete[] data;
throw_errno(env);
return ;
}
env->SetByteArrayRegion(buf, 0, len, (jbyte *) data);
delete[] data;
}
/*
* Throws LastErrorException based on the errno:
*/
static void throw_errno(JNIEnv *env) {
jobject exc = env->NewObject(lastErrorExceptionClass,
lastErrorExceptionConstructor,
errno);
env->Throw((jthrowable) exc);
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna;
import java.io.IOException;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.jna.osx.OsXNativePty;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
class JDKNativePty {
static JnaNativePty current(TerminalProvider.Stream console) throws IOException {
return OsXNativePty.current(console);
}
static JnaNativePty open(Attributes attr, Size size) throws IOException {
return OsXNativePty.open(attr, size);
}
static int isatty(int fd) {
return OsXNativePty.isatty(fd);
}
static String ttyname(int fd) {
return OsXNativePty.ttyname(fd);
}
}

View File

@ -1,394 +0,0 @@
/*
* Copyright (c) 2002-2020, 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.impl.jna.osx;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.List;
//import com.sun.jna.LastErrorException;
//import com.sun.jna.NativeLong;
//import com.sun.jna.Structure;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Attributes.ControlChar;
import jdk.internal.org.jline.terminal.Attributes.ControlFlag;
import jdk.internal.org.jline.terminal.Attributes.InputFlag;
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.jna.LastErrorException;
public interface CLibrary {//extends com.sun.jna.Library {
void tcgetattr(int fd, termios termios) throws LastErrorException;
void tcsetattr(int fd, int cmd, termios termios) throws LastErrorException;
void ioctl(int fd, NativeLong cmd, winsize data) throws LastErrorException;
int isatty(int fd);
void ttyname_r(int fd, byte[] buf, int len) throws LastErrorException;
void openpty(int[] master, int[] slave, byte[] name, termios t, winsize s) throws LastErrorException;
class winsize { //extends Structure {
public short ws_row;
public short ws_col;
public short ws_xpixel;
public short ws_ypixel;
public winsize() {
}
public winsize(Size ws) {
ws_row = (short) ws.getRows();
ws_col = (short) ws.getColumns();
}
public Size toSize() {
return new Size(ws_col, ws_row);
}
// @Override
// protected List<String> getFieldOrder() {
// return Arrays.asList(//
// "ws_row",//
// "ws_col",//
// "ws_xpixel",//
// "ws_ypixel"//
// );
// }
}
class termios { //extends Structure {
public NativeLong c_iflag;
public NativeLong c_oflag;
public NativeLong c_cflag;
public NativeLong c_lflag;
public byte[] c_cc = new byte[20];
public NativeLong c_ispeed;
public NativeLong c_ospeed;
// @Override
// protected List<String> getFieldOrder() {
// return Arrays.asList(//
// "c_iflag",//
// "c_oflag",//
// "c_cflag",//
// "c_lflag",//
// "c_cc",//
// "c_ispeed",//
// "c_ospeed"//
// );
// }
{
c_iflag = new NativeLong(0);
c_oflag = new NativeLong(0);
c_cflag = new NativeLong(0);
c_lflag = new NativeLong(0);
c_ispeed = new NativeLong(0);
c_ospeed = new NativeLong(0);
}
public termios() {
}
public termios(Attributes t) {
// Input flags
setFlag(t.getInputFlag(InputFlag.IGNBRK), IGNBRK, c_iflag);
setFlag(t.getInputFlag(InputFlag.BRKINT), BRKINT, c_iflag);
setFlag(t.getInputFlag(InputFlag.IGNPAR), IGNPAR, c_iflag);
setFlag(t.getInputFlag(InputFlag.PARMRK), PARMRK, c_iflag);
setFlag(t.getInputFlag(InputFlag.INPCK), INPCK, c_iflag);
setFlag(t.getInputFlag(InputFlag.ISTRIP), ISTRIP, c_iflag);
setFlag(t.getInputFlag(InputFlag.INLCR), INLCR, c_iflag);
setFlag(t.getInputFlag(InputFlag.IGNCR), IGNCR, c_iflag);
setFlag(t.getInputFlag(InputFlag.ICRNL), ICRNL, c_iflag);
setFlag(t.getInputFlag(InputFlag.IXON), IXON, c_iflag);
setFlag(t.getInputFlag(InputFlag.IXOFF), IXOFF, c_iflag);
setFlag(t.getInputFlag(InputFlag.IXANY), IXANY, c_iflag);
setFlag(t.getInputFlag(InputFlag.IMAXBEL), IMAXBEL, c_iflag);
setFlag(t.getInputFlag(InputFlag.IUTF8), IUTF8, c_iflag);
// Output flags
setFlag(t.getOutputFlag(OutputFlag.OPOST), OPOST, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.ONLCR), ONLCR, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.OXTABS), OXTABS, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.ONOEOT), ONOEOT, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.OCRNL), OCRNL, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.ONOCR), ONOCR, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.ONLRET), ONLRET, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.OFILL), OFILL, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.NLDLY), NLDLY, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.TABDLY), TABDLY, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.CRDLY), CRDLY, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.FFDLY), FFDLY, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.BSDLY), BSDLY, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.VTDLY), VTDLY, c_oflag);
setFlag(t.getOutputFlag(OutputFlag.OFDEL), OFDEL, c_oflag);
// Control flags
setFlag(t.getControlFlag(ControlFlag.CIGNORE), CIGNORE, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CS5), CS5, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CS6), CS6, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CS7), CS7, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CS8), CS8, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CSTOPB), CSTOPB, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CREAD), CREAD, c_cflag);
setFlag(t.getControlFlag(ControlFlag.PARENB), PARENB, c_cflag);
setFlag(t.getControlFlag(ControlFlag.PARODD), PARODD, c_cflag);
setFlag(t.getControlFlag(ControlFlag.HUPCL), HUPCL, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CLOCAL), CLOCAL, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CCTS_OFLOW), CCTS_OFLOW, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CRTS_IFLOW), CRTS_IFLOW, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CDTR_IFLOW), CDTR_IFLOW, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CDSR_OFLOW), CDSR_OFLOW, c_cflag);
setFlag(t.getControlFlag(ControlFlag.CCAR_OFLOW), CCAR_OFLOW, c_cflag);
// Local flags
setFlag(t.getLocalFlag(LocalFlag.ECHOKE), ECHOKE, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ECHOE), ECHOE, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ECHOK), ECHOK, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ECHO), ECHO, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ECHONL), ECHONL, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ECHOPRT), ECHOPRT, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ECHOCTL), ECHOCTL, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ISIG), ISIG, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ICANON), ICANON, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.ALTWERASE), ALTWERASE, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.IEXTEN), IEXTEN, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.EXTPROC), EXTPROC, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.TOSTOP), TOSTOP, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.FLUSHO), FLUSHO, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.NOKERNINFO), NOKERNINFO, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.PENDIN), PENDIN, c_lflag);
setFlag(t.getLocalFlag(LocalFlag.NOFLSH), NOFLSH, c_lflag);
// Control chars
c_cc[VEOF] = (byte) t.getControlChar(ControlChar.VEOF);
c_cc[VEOL] = (byte) t.getControlChar(ControlChar.VEOL);
c_cc[VEOL2] = (byte) t.getControlChar(ControlChar.VEOL2);
c_cc[VERASE] = (byte) t.getControlChar(ControlChar.VERASE);
c_cc[VWERASE] = (byte) t.getControlChar(ControlChar.VWERASE);
c_cc[VKILL] = (byte) t.getControlChar(ControlChar.VKILL);
c_cc[VREPRINT] = (byte) t.getControlChar(ControlChar.VREPRINT);
c_cc[VINTR] = (byte) t.getControlChar(ControlChar.VINTR);
c_cc[VQUIT] = (byte) t.getControlChar(ControlChar.VQUIT);
c_cc[VSUSP] = (byte) t.getControlChar(ControlChar.VSUSP);
c_cc[VDSUSP] = (byte) t.getControlChar(ControlChar.VDSUSP);
c_cc[VSTART] = (byte) t.getControlChar(ControlChar.VSTART);
c_cc[VSTOP] = (byte) t.getControlChar(ControlChar.VSTOP);
c_cc[VLNEXT] = (byte) t.getControlChar(ControlChar.VLNEXT);
c_cc[VDISCARD] = (byte) t.getControlChar(ControlChar.VDISCARD);
c_cc[VMIN] = (byte) t.getControlChar(ControlChar.VMIN);
c_cc[VTIME] = (byte) t.getControlChar(ControlChar.VTIME);
c_cc[VSTATUS] = (byte) t.getControlChar(ControlChar.VSTATUS);
}
private void setFlag(boolean flag, long value, NativeLong org) {
org.setValue(flag ? org.longValue() | value : org.longValue());
}
public Attributes toAttributes() {
Attributes attr = new Attributes();
// Input flags
EnumSet<InputFlag> iflag = attr.getInputFlags();
addFlag(c_iflag.longValue(), iflag, InputFlag.IGNBRK, IGNBRK);
addFlag(c_iflag.longValue(), iflag, InputFlag.IGNBRK, IGNBRK);
addFlag(c_iflag.longValue(), iflag, InputFlag.BRKINT, BRKINT);
addFlag(c_iflag.longValue(), iflag, InputFlag.IGNPAR, IGNPAR);
addFlag(c_iflag.longValue(), iflag, InputFlag.PARMRK, PARMRK);
addFlag(c_iflag.longValue(), iflag, InputFlag.INPCK, INPCK);
addFlag(c_iflag.longValue(), iflag, InputFlag.ISTRIP, ISTRIP);
addFlag(c_iflag.longValue(), iflag, InputFlag.INLCR, INLCR);
addFlag(c_iflag.longValue(), iflag, InputFlag.IGNCR, IGNCR);
addFlag(c_iflag.longValue(), iflag, InputFlag.ICRNL, ICRNL);
addFlag(c_iflag.longValue(), iflag, InputFlag.IXON, IXON);
addFlag(c_iflag.longValue(), iflag, InputFlag.IXOFF, IXOFF);
addFlag(c_iflag.longValue(), iflag, InputFlag.IXANY, IXANY);
addFlag(c_iflag.longValue(), iflag, InputFlag.IMAXBEL, IMAXBEL);
addFlag(c_iflag.longValue(), iflag, InputFlag.IUTF8, IUTF8);
// Output flags
EnumSet<OutputFlag> oflag = attr.getOutputFlags();
addFlag(c_oflag.longValue(), oflag, OutputFlag.OPOST, OPOST);
addFlag(c_oflag.longValue(), oflag, OutputFlag.ONLCR, ONLCR);
addFlag(c_oflag.longValue(), oflag, OutputFlag.OXTABS, OXTABS);
addFlag(c_oflag.longValue(), oflag, OutputFlag.ONOEOT, ONOEOT);
addFlag(c_oflag.longValue(), oflag, OutputFlag.OCRNL, OCRNL);
addFlag(c_oflag.longValue(), oflag, OutputFlag.ONOCR, ONOCR);
addFlag(c_oflag.longValue(), oflag, OutputFlag.ONLRET, ONLRET);
addFlag(c_oflag.longValue(), oflag, OutputFlag.OFILL, OFILL);
addFlag(c_oflag.longValue(), oflag, OutputFlag.NLDLY, NLDLY);
addFlag(c_oflag.longValue(), oflag, OutputFlag.TABDLY, TABDLY);
addFlag(c_oflag.longValue(), oflag, OutputFlag.CRDLY, CRDLY);
addFlag(c_oflag.longValue(), oflag, OutputFlag.FFDLY, FFDLY);
addFlag(c_oflag.longValue(), oflag, OutputFlag.BSDLY, BSDLY);
addFlag(c_oflag.longValue(), oflag, OutputFlag.VTDLY, VTDLY);
addFlag(c_oflag.longValue(), oflag, OutputFlag.OFDEL, OFDEL);
// Control flags
EnumSet<ControlFlag> cflag = attr.getControlFlags();
addFlag(c_cflag.longValue(), cflag, ControlFlag.CIGNORE, CIGNORE);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CS5, CS5);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CS6, CS6);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CS7, CS7);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CS8, CS8);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CSTOPB, CSTOPB);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CREAD, CREAD);
addFlag(c_cflag.longValue(), cflag, ControlFlag.PARENB, PARENB);
addFlag(c_cflag.longValue(), cflag, ControlFlag.PARODD, PARODD);
addFlag(c_cflag.longValue(), cflag, ControlFlag.HUPCL, HUPCL);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CLOCAL, CLOCAL);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CCTS_OFLOW, CCTS_OFLOW);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CRTS_IFLOW, CRTS_IFLOW);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CDSR_OFLOW, CDSR_OFLOW);
addFlag(c_cflag.longValue(), cflag, ControlFlag.CCAR_OFLOW, CCAR_OFLOW);
// Local flags
EnumSet<LocalFlag> lflag = attr.getLocalFlags();
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHOKE, ECHOKE);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHOE, ECHOE);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHOK, ECHOK);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHO, ECHO);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHONL, ECHONL);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHOPRT, ECHOPRT);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ECHOCTL, ECHOCTL);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ISIG, ISIG);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ICANON, ICANON);
addFlag(c_lflag.longValue(), lflag, LocalFlag.ALTWERASE, ALTWERASE);
addFlag(c_lflag.longValue(), lflag, LocalFlag.IEXTEN, IEXTEN);
addFlag(c_lflag.longValue(), lflag, LocalFlag.EXTPROC, EXTPROC);
addFlag(c_lflag.longValue(), lflag, LocalFlag.TOSTOP, TOSTOP);
addFlag(c_lflag.longValue(), lflag, LocalFlag.FLUSHO, FLUSHO);
addFlag(c_lflag.longValue(), lflag, LocalFlag.NOKERNINFO, NOKERNINFO);
addFlag(c_lflag.longValue(), lflag, LocalFlag.PENDIN, PENDIN);
addFlag(c_lflag.longValue(), lflag, LocalFlag.NOFLSH, NOFLSH);
// Control chars
EnumMap<ControlChar, Integer> cc = attr.getControlChars();
cc.put(ControlChar.VEOF, (int) c_cc[VEOF]);
cc.put(ControlChar.VEOL, (int) c_cc[VEOL]);
cc.put(ControlChar.VEOL2, (int) c_cc[VEOL2]);
cc.put(ControlChar.VERASE, (int) c_cc[VERASE]);
cc.put(ControlChar.VWERASE, (int) c_cc[VWERASE]);
cc.put(ControlChar.VKILL, (int) c_cc[VKILL]);
cc.put(ControlChar.VREPRINT, (int) c_cc[VREPRINT]);
cc.put(ControlChar.VINTR, (int) c_cc[VINTR]);
cc.put(ControlChar.VQUIT, (int) c_cc[VQUIT]);
cc.put(ControlChar.VSUSP, (int) c_cc[VSUSP]);
cc.put(ControlChar.VDSUSP, (int) c_cc[VDSUSP]);
cc.put(ControlChar.VSTART, (int) c_cc[VSTART]);
cc.put(ControlChar.VSTOP, (int) c_cc[VSTOP]);
cc.put(ControlChar.VLNEXT, (int) c_cc[VLNEXT]);
cc.put(ControlChar.VDISCARD, (int) c_cc[VDISCARD]);
cc.put(ControlChar.VMIN, (int) c_cc[VMIN]);
cc.put(ControlChar.VTIME, (int) c_cc[VTIME]);
cc.put(ControlChar.VSTATUS, (int) c_cc[VSTATUS]);
// Return
return attr;
}
private <T extends Enum<T>> void addFlag(long value, EnumSet<T> flags, T flag, int v) {
if ((value & v) != 0) {
flags.add(flag);
}
}
}
// CONSTANTS
long TIOCGWINSZ = 0x40087468L;
long TIOCSWINSZ = 0x80087467L;
int TCSANOW = 0x00000000;
int VEOF = 0;
int VEOL = 1;
int VEOL2 = 2;
int VERASE = 3;
int VWERASE = 4;
int VKILL = 5;
int VREPRINT = 6;
int VINTR = 8;
int VQUIT = 9;
int VSUSP = 10;
int VDSUSP = 11;
int VSTART = 12;
int VSTOP = 13;
int VLNEXT = 14;
int VDISCARD = 15;
int VMIN = 16;
int VTIME = 17;
int VSTATUS = 18;
int IGNBRK = 0x00000001;
int BRKINT = 0x00000002;
int IGNPAR = 0x00000004;
int PARMRK = 0x00000008;
int INPCK = 0x00000010;
int ISTRIP = 0x00000020;
int INLCR = 0x00000040;
int IGNCR = 0x00000080;
int ICRNL = 0x00000100;
int IXON = 0x00000200;
int IXOFF = 0x00000400;
int IXANY = 0x00000800;
int IMAXBEL = 0x00002000;
int IUTF8 = 0x00004000;
int OPOST = 0x00000001;
int ONLCR = 0x00000002;
int OXTABS = 0x00000004;
int ONOEOT = 0x00000008;
int OCRNL = 0x00000010;
int ONOCR = 0x00000020;
int ONLRET = 0x00000040;
int OFILL = 0x00000080;
int NLDLY = 0x00000300;
int TABDLY = 0x00000c04;
int CRDLY = 0x00003000;
int FFDLY = 0x00004000;
int BSDLY = 0x00008000;
int VTDLY = 0x00010000;
int OFDEL = 0x00020000;
int CIGNORE = 0x00000001;
int CS5 = 0x00000000;
int CS6 = 0x00000100;
int CS7 = 0x00000200;
int CS8 = 0x00000300;
int CSTOPB = 0x00000400;
int CREAD = 0x00000800;
int PARENB = 0x00001000;
int PARODD = 0x00002000;
int HUPCL = 0x00004000;
int CLOCAL = 0x00008000;
int CCTS_OFLOW = 0x00010000;
int CRTS_IFLOW = 0x00020000;
int CDTR_IFLOW = 0x00040000;
int CDSR_OFLOW = 0x00080000;
int CCAR_OFLOW = 0x00100000;
int ECHOKE = 0x00000001;
int ECHOE = 0x00000002;
int ECHOK = 0x00000004;
int ECHO = 0x00000008;
int ECHONL = 0x00000010;
int ECHOPRT = 0x00000020;
int ECHOCTL = 0x00000040;
int ISIG = 0x00000080;
int ICANON = 0x00000100;
int ALTWERASE = 0x00000200;
int IEXTEN = 0x00000400;
int EXTPROC = 0x00000800;
int TOSTOP = 0x00400000;
int FLUSHO = 0x00800000;
int NOKERNINFO = 0x02000000;
int PENDIN = 0x20000000;
int NOFLSH = 0x80000000;
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna.osx;
import jdk.internal.org.jline.terminal.impl.jna.LastErrorException;
public final class CLibraryImpl implements CLibrary {
static {
System.loadLibrary("le");
initIDs();
}
private static native void initIDs();
@Override
public native void tcgetattr(int fd, termios termios) throws LastErrorException;
@Override
public native void tcsetattr(int fd, int cmd, termios termios) throws LastErrorException;
@Override
public void ioctl(int fd, NativeLong cmd, winsize data) throws LastErrorException {
if (cmd.longValue() == CLibrary.TIOCGWINSZ || cmd.longValue() == CLibrary.TIOCSWINSZ) {
ioctl0(fd, cmd.longValue(), data);
} else {
throw new UnsupportedOperationException("Command: " + cmd + ", not supported.");
}
}
private native void ioctl0(int fd, long cmd, winsize data) throws LastErrorException;
@Override
public native int isatty(int fd);
@Override
public native void ttyname_r(int fd, byte[] buf, int len) throws LastErrorException;
@Override
public void openpty(int[] master, int[] slave, byte[] name, termios t, winsize s) throws LastErrorException {
throw new UnsupportedOperationException();
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna.osx;
class NativeLong {
public long value;
public NativeLong(long value) {
this.value = value;
}
public void setValue(long value) {
this.value = value;
}
public long longValue() {
return value;
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright (c) 2002-2020, 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.impl.jna.osx;
import java.io.FileDescriptor;
import java.io.IOException;
//import com.sun.jna.Native;
//import com.sun.jna.NativeLong;
//import com.sun.jna.Platform;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.jna.JnaNativePty;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import static jdk.internal.org.jline.terminal.impl.jna.osx.CLibrary.TCSANOW;
import static jdk.internal.org.jline.terminal.impl.jna.osx.CLibrary.TIOCGWINSZ;
import static jdk.internal.org.jline.terminal.impl.jna.osx.CLibrary.TIOCSWINSZ;
import static jdk.internal.org.jline.terminal.impl.jna.osx.CLibrary.termios;
import static jdk.internal.org.jline.terminal.impl.jna.osx.CLibrary.winsize;
public class OsXNativePty extends JnaNativePty {
// private static final CLibrary C_LIBRARY = Native.load(Platform.C_LIBRARY_NAME, CLibrary.class);
private static final CLibrary C_LIBRARY = new CLibraryImpl();//Native.load(Platform.C_LIBRARY_NAME, CLibrary.class);
public static OsXNativePty current(TerminalProvider.Stream consoleStream) throws IOException {
switch (consoleStream) {
case Output:
return new OsXNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0));
case Error:
return new OsXNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0));
default:
throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream);
}
}
public static OsXNativePty open(Attributes attr, Size size) throws IOException {
int[] master = new int[1];
int[] slave = new int[1];
byte[] buf = new byte[64];
C_LIBRARY.openpty(master, slave, buf,
attr != null ? new termios(attr) : null,
size != null ? new winsize(size) : null);
int len = 0;
while (buf[len] != 0) {
len++;
}
String name = new String(buf, 0, len);
return new OsXNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name);
}
public OsXNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) {
super(master, masterFD, slave, slaveFD, name);
}
public OsXNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, int slaveOut, FileDescriptor slaveOutFD, String name) {
super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name);
}
@Override
public Attributes getAttr() throws IOException {
termios termios = new termios();
C_LIBRARY.tcgetattr(getSlave(), termios);
return termios.toAttributes();
}
@Override
protected void doSetAttr(Attributes attr) throws IOException {
termios termios = new termios(attr);
C_LIBRARY.tcsetattr(getSlave(), TCSANOW, termios);
}
@Override
public Size getSize() throws IOException {
winsize sz = new winsize();
C_LIBRARY.ioctl(getSlave(), new NativeLong(TIOCGWINSZ), sz);
return sz.toSize();
}
@Override
public void setSize(Size size) throws IOException {
winsize sz = new winsize(size);
C_LIBRARY.ioctl(getSlave(), new NativeLong(TIOCSWINSZ), sz);
}
public static int isatty(int fd) {
return C_LIBRARY.isatty(fd);
}
public static String ttyname(int fd) {
byte[] buf = new byte[64];
C_LIBRARY.ttyname_r(fd, buf, buf.length);
int len = 0;
while (buf[len] != 0) {
len++;
}
return new String(buf, 0, len);
}
}

View File

@ -1,211 +0,0 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl.h"
#include <errno.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
static jclass lastErrorExceptionClass;
static jmethodID lastErrorExceptionConstructor;
static jclass termios_j;
static jfieldID c_iflag;
static jfieldID c_oflag;
static jfieldID c_cflag;
static jfieldID c_lflag;
static jfieldID c_cc;
static jfieldID c_ispeed;
static jfieldID c_ospeed;
static jclass winsize_j;
static jfieldID ws_row;
static jfieldID ws_col;
static jfieldID ws_xpixel;
static jfieldID ws_ypixel;
static jclass nativelong_j;
static jfieldID nativelong_value;
static void throw_errno(JNIEnv *env);
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl_initIDs
(JNIEnv *env, jclass) {
jclass cls;
cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/LastErrorException");
CHECK_NULL(cls);
lastErrorExceptionClass = (jclass) env->NewGlobalRef(cls);
lastErrorExceptionConstructor = env->GetMethodID(lastErrorExceptionClass, "<init>", "(J)V");
CHECK_NULL(lastErrorExceptionConstructor);
cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/osx/CLibrary$termios");
CHECK_NULL(cls);
termios_j = (jclass) env->NewGlobalRef(cls);
CHECK_NULL(termios_j);
c_iflag = env->GetFieldID(termios_j, "c_iflag", "Ljdk/internal/org/jline/terminal/impl/jna/osx/NativeLong;");
CHECK_NULL(c_iflag);
c_oflag = env->GetFieldID(termios_j, "c_oflag", "Ljdk/internal/org/jline/terminal/impl/jna/osx/NativeLong;");
CHECK_NULL(c_oflag);
c_cflag = env->GetFieldID(termios_j, "c_cflag", "Ljdk/internal/org/jline/terminal/impl/jna/osx/NativeLong;");
CHECK_NULL(c_cflag);
c_lflag = env->GetFieldID(termios_j, "c_lflag", "Ljdk/internal/org/jline/terminal/impl/jna/osx/NativeLong;");
CHECK_NULL(c_lflag);
c_cc = env->GetFieldID(termios_j, "c_cc", "[B");
CHECK_NULL(c_cc);
c_ispeed = env->GetFieldID(termios_j, "c_ispeed", "Ljdk/internal/org/jline/terminal/impl/jna/osx/NativeLong;");
CHECK_NULL(c_ispeed);
c_ospeed = env->GetFieldID(termios_j, "c_ospeed", "Ljdk/internal/org/jline/terminal/impl/jna/osx/NativeLong;");
CHECK_NULL(c_ospeed);
cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/osx/CLibrary$winsize");
CHECK_NULL(cls);
winsize_j = (jclass) env->NewGlobalRef(cls);
ws_row = env->GetFieldID(winsize_j, "ws_row", "S");
CHECK_NULL(ws_row);
ws_col = env->GetFieldID(winsize_j, "ws_col", "S");
CHECK_NULL(ws_col);
ws_xpixel= env->GetFieldID(winsize_j, "ws_xpixel", "S");
CHECK_NULL(ws_xpixel);
ws_ypixel= env->GetFieldID(winsize_j, "ws_ypixel", "S");
CHECK_NULL(ws_ypixel);
nativelong_j = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/osx/NativeLong");
CHECK_NULL(nativelong_j);
nativelong_value = env->GetFieldID(nativelong_j, "value", "J");
CHECK_NULL(nativelong_value);
}
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl_tcgetattr
(JNIEnv *env, jobject, jint fd, jobject result) {
termios data;
if (tcgetattr(fd, &data) != 0) {
throw_errno(env);
return ;
}
env->SetLongField(env->GetObjectField(result, c_iflag), nativelong_value, data.c_iflag);
env->SetLongField(env->GetObjectField(result, c_oflag), nativelong_value, data.c_oflag);
env->SetLongField(env->GetObjectField(result, c_cflag), nativelong_value, data.c_cflag);
env->SetLongField(env->GetObjectField(result, c_lflag), nativelong_value, data.c_lflag);
jbyteArray c_ccValue = (jbyteArray) env->GetObjectField(result, c_cc);
env->SetByteArrayRegion(c_ccValue, 0, NCCS, (signed char *) data.c_cc);
env->SetLongField(env->GetObjectField(result, c_ispeed), nativelong_value, data.c_ispeed);
env->SetLongField(env->GetObjectField(result, c_ospeed), nativelong_value, data.c_ospeed);
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl
* Method: tcsetattr
* Signature: (IILjdk/internal/org/jline/terminal/impl/jna/osx/CLibrary/termios;)V
*/
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl_tcsetattr
(JNIEnv *env, jobject, jint fd, jint cmd, jobject input) {
termios data;
data.c_iflag = env->GetLongField(env->GetObjectField(input, c_iflag), nativelong_value);
data.c_oflag = env->GetLongField(env->GetObjectField(input, c_oflag), nativelong_value);
data.c_cflag = env->GetLongField(env->GetObjectField(input, c_cflag), nativelong_value);
data.c_lflag = env->GetLongField(env->GetObjectField(input, c_lflag), nativelong_value);
jbyteArray c_ccValue = (jbyteArray) env->GetObjectField(input, c_cc);
env->GetByteArrayRegion(c_ccValue, 0, NCCS, (jbyte *) data.c_cc);
data.c_ispeed = env->GetLongField(env->GetObjectField(input, c_ispeed), nativelong_value);
data.c_ospeed = env->GetLongField(env->GetObjectField(input, c_ospeed), nativelong_value);
if (tcsetattr(fd, cmd, &data) != 0) {
throw_errno(env);
}
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl
* Method: ioctl0
* Signature: (IILjdk/internal/org/jline/terminal/impl/jna/osx/CLibrary/winsize;)V
*/
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl_ioctl0
(JNIEnv *env, jobject, jint fd, jlong cmd, jobject data) {
winsize ws;
ws.ws_row = env->GetShortField(data, ws_row);
ws.ws_col = env->GetShortField(data, ws_col);
ws.ws_xpixel = env->GetShortField(data, ws_xpixel);
ws.ws_ypixel = env->GetShortField(data, ws_ypixel);
if (ioctl(fd, cmd, &ws) != 0) {
throw_errno(env);
return ;
}
env->SetShortField(data, ws_row, ws.ws_row);
env->SetShortField(data, ws_col, ws.ws_col);
env->SetShortField(data, ws_xpixel, ws.ws_xpixel);
env->SetShortField(data, ws_ypixel, ws.ws_ypixel);
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl
* Method: isatty
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl_isatty
(JNIEnv *, jobject, jint fd) {
return isatty(fd);
}
/*
* Class: jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl
* Method: ttyname_r
* Signature: (I[BI)V
*/
JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_osx_CLibraryImpl_ttyname_1r
(JNIEnv *env, jobject, jint fd, jbyteArray buf, jint len) {
char *data = new char[len];
int error = ttyname_r(fd, data, len);
if (error != 0) {
delete[] data;
throw_errno(env);
return ;
}
env->SetByteArrayRegion(buf, 0, len, (jbyte *) data);
delete[] data;
}
/*
* Throws LastErrorException based on the errno:
*/
static void throw_errno(JNIEnv *env) {
jobject exc = env->NewObject(lastErrorExceptionClass,
lastErrorExceptionConstructor,
errno);
env->Throw((jthrowable) exc);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -66,7 +66,7 @@ public class BindingReader {
T o = null;
int[] remaining = new int[1];
boolean hasRead = false;
for (;;) {
for (; ; ) {
if (local != null) {
o = local.getBound(opBuffer, remaining);
}
@ -78,8 +78,7 @@ public class BindingReader {
if (remaining[0] >= 0) {
runMacro(opBuffer.substring(opBuffer.length() - remaining[0]));
opBuffer.setLength(opBuffer.length() - remaining[0]);
}
else {
} else {
long ambiguousTimeout = keys.getAmbiguousTimeout();
if (ambiguousTimeout > 0 && peekCharacter(ambiguousTimeout) != NonBlockingReader.READ_EXPIRED) {
o = null;
@ -234,5 +233,4 @@ public class BindingReader {
public String getLastBinding() {
return lastBinding;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -8,8 +8,6 @@
*/
package jdk.internal.org.jline.keymap;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@ -218,7 +216,6 @@ public class KeyMap<T> {
return seqs;
}
public static String esc() {
return "\033";
}
@ -264,7 +261,6 @@ public class KeyMap<T> {
// Methods
//
public T getUnicode() {
return unicode;
}
@ -306,9 +302,7 @@ public class KeyMap<T> {
}
for (int c = 0; c < keyMap.mapping.length; c++) {
if (keyMap.mapping[c] instanceof KeyMap) {
doGetBoundKeys((KeyMap<T>) keyMap.mapping[c],
prefix + (char) (c),
bound);
doGetBoundKeys((KeyMap<T>) keyMap.mapping[c], prefix + (char) (c), bound);
} else if (keyMap.mapping[c] != null) {
bound.put(prefix + (char) (c), (T) keyMap.mapping[c]);
}
@ -456,5 +450,4 @@ public class KeyMap<T> {
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -14,9 +14,8 @@ package jdk.internal.org.jline.reader;
* @see Macro
* @see Reference
* @see Widget
* @see jdk.internal.org.jline.keymap.KeyMap
* @see org.jline.keymap.KeyMap
*
* @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
*/
public interface Binding {
}
public interface Binding {}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2017, the original author or authors.
* Copyright (c) 2002-2017, 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.
@ -84,8 +84,8 @@ public interface Buffer {
void copyFrom(Buffer buffer);
// JDK specific modification
default void zeroOut() {
throw new UnsupportedOperationException();
}
/**
* Clear any internal buffer.
*/
void zeroOut();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019, the original author or authors.
* Copyright (c) 2002-2019, 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.
@ -47,7 +47,15 @@ public class Candidate implements Comparable<Candidate> {
* @param complete the complete flag
* @param sort the sort flag
*/
public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete, int sort) {
public Candidate(
String value,
String displ,
String group,
String descr,
String suffix,
String key,
boolean complete,
int sort) {
this.value = Objects.requireNonNull(value);
this.displ = Objects.requireNonNull(displ);
this.group = group;
@ -69,7 +77,8 @@ public class Candidate implements Comparable<Candidate> {
* @param key the key
* @param complete the complete flag
*/
public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete) {
public Candidate(
String value, String displ, String group, String descr, String suffix, String key, boolean complete) {
this(value, displ, group, descr, suffix, key, complete, 0);
}
@ -159,11 +168,10 @@ public class Candidate implements Comparable<Candidate> {
return sort;
}
@Override
public int compareTo(Candidate o) {
// If both candidates have same sort, use default behavior
if( sort == o.sort() ) {
if (sort == o.sort()) {
return value.compareTo(o.value);
} else {
return Integer.compare(sort, o.sort());
@ -180,7 +188,7 @@ public class Candidate implements Comparable<Candidate> {
@Override
public int hashCode() {
return Objects.hash(value);
return Objects.hashCode(value);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -18,8 +18,7 @@ import java.util.List;
* @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
* @since 2.3
*/
public interface Completer
{
public interface Completer {
/**
* Populates <i>candidates</i> with a list of possible completions for the <i>command line</i>.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -10,7 +10,7 @@ package jdk.internal.org.jline.reader;
/**
* An extension of {@link ParsedLine} that, being aware of the quoting and escaping rules
* of the {@link jdk.internal.org.jline.reader.Parser} that produced it, knows if and how a completion candidate
* of the {@link org.jline.reader.Parser} that produced it, knows if and how a completion candidate
* should be escaped/quoted.
*
* @author Eric Bottard
@ -22,5 +22,4 @@ public interface CompletingParsedLine extends ParsedLine {
int rawWordCursor();
int rawWordLength();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
* Copyright (c) 2002-2020, 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.
@ -23,8 +23,13 @@ public interface CompletionMatcher {
* @param errors number of errors accepted in matching
* @param originalGroupName value of JLineReader variable original-group-name
*/
void compile(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line
, boolean caseInsensitive, int errors, String originalGroupName);
void compile(
Map<LineReader.Option, Boolean> options,
boolean prefix,
CompletingParsedLine line,
boolean caseInsensitive,
int errors,
String originalGroupName);
/**
*
@ -44,5 +49,4 @@ public interface CompletionMatcher {
* @return a common prefix of matched candidates
*/
String getCommonPrefix();
}

View File

@ -1,20 +1,10 @@
/*
* 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
* Copyright (c) 2023, the original author(s).
*
* http://www.apache.org/licenses/LICENSE-2.0
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* 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.
* https://opensource.org/licenses/BSD-3-Clause
*/
package jdk.internal.org.jline.reader;
@ -45,7 +35,7 @@ public class EOFError extends SyntaxError {
return missing;
}
public int getOpenBrackets(){
public int getOpenBrackets() {
return openBrackets;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019, the original author or authors.
* Copyright (c) 2002-2019, 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.
@ -13,6 +13,8 @@ import java.util.List;
public interface Editor {
public void open(List<String> files) throws IOException;
public void run() throws IOException;
public void setRestricted(boolean restricted);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
* Copyright (c) 2002-2020, 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.
@ -17,8 +17,7 @@ public class EndOfFileException extends RuntimeException {
private static final long serialVersionUID = 528485360925144689L;
private String partialLine;
public EndOfFileException() {
}
public EndOfFileException() {}
public EndOfFileException(String message) {
super(message);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -13,5 +13,4 @@ public interface Expander {
String expandHistory(History history, String line);
String expandVar(String word);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -21,8 +21,7 @@ import java.util.ListIterator;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public interface History extends Iterable<History.Entry>
{
public interface History extends Iterable<History.Entry> {
/**
* Initialize the history for the given reader.
@ -75,7 +74,6 @@ public interface History extends Iterable<History.Entry>
*/
void purge() throws IOException;
int size();
default boolean isEmpty() {
@ -110,8 +108,7 @@ public interface History extends Iterable<History.Entry>
// Entries
//
interface Entry
{
interface Entry {
int index();
Instant time();
@ -132,14 +129,17 @@ public interface History extends Iterable<History.Entry>
default Iterator<Entry> reverseIterator(int index) {
return new Iterator<Entry>() {
private final ListIterator<Entry> it = iterator(index + 1);
@Override
public boolean hasNext() {
return it.hasPrevious();
}
@Override
public Entry next() {
return it.previous();
}
@Override
public void remove() {
it.remove();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2023, 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.
@ -21,7 +21,7 @@ import jdk.internal.org.jline.utils.AttributedString;
/** Read lines from the console, with input editing.
*
* <h3>Thread safety</h3>
* <h2>Thread safety</h2>
* The <code>LineReader</code> implementations are not thread safe,
* thus you should not attempt to use a single reader in several threads.
* Any attempt to call one of the <code>readLine</code> call while one is
@ -31,7 +31,7 @@ import jdk.internal.org.jline.utils.AttributedString;
* {@link #printAbove(String)} or {@link #printAbove(AttributedString)} at
* any time to allow text to be printed above the current prompt.
*
* <h3>Prompt strings</h3>
* <h2>Prompt strings</h2>
* It is traditional for an interactive console-based program
* to print a short prompt string to signal that the user is expected
* to type a command. JLine supports 3 kinds of prompt string:
@ -81,7 +81,6 @@ import jdk.internal.org.jline.utils.AttributedString;
* </dd>
* </dl>
*/
public interface LineReader {
/**
@ -284,6 +283,7 @@ public interface LineReader {
String MAIN = "main";
String EMACS = "emacs";
String SAFE = ".safe";
String DUMB = "dumb";
String MENU = "menu";
//
@ -301,6 +301,7 @@ public interface LineReader {
* they are displayed in a list below the field to be completed
*/
String MENU_LIST_MAX = "menu-list-max";
String DISABLE_HISTORY = "disable-history";
String DISABLE_COMPLETION = "disable-completion";
String EDITING_MODE = "editing-mode";
@ -317,18 +318,23 @@ public interface LineReader {
String ORIGINAL_GROUP_NAME = "ORIGINAL_GROUP_NAME";
/** Completion style for displaying groups name */
String COMPLETION_STYLE_GROUP = "COMPLETION_STYLE_GROUP";
String COMPLETION_STYLE_LIST_GROUP = "COMPLETION_STYLE_LIST_GROUP";
/** Completion style for displaying the current selected item */
String COMPLETION_STYLE_SELECTION = "COMPLETION_STYLE_SELECTION";
String COMPLETION_STYLE_LIST_SELECTION = "COMPLETION_STYLE_LIST_SELECTION";
/** Completion style for displaying the candidate description */
String COMPLETION_STYLE_DESCRIPTION = "COMPLETION_STYLE_DESCRIPTION";
String COMPLETION_STYLE_LIST_DESCRIPTION = "COMPLETION_STYLE_LIST_DESCRIPTION";
/** Completion style for displaying the matching part of candidates */
String COMPLETION_STYLE_STARTING = "COMPLETION_STYLE_STARTING";
String COMPLETION_STYLE_LIST_STARTING = "COMPLETION_STYLE_LIST_STARTING";
/** Completion style for displaying the list */
String COMPLETION_STYLE_BACKGROUND = "COMPLETION_STYLE_BACKGROUND";
String COMPLETION_STYLE_LIST_BACKGROUND = "COMPLETION_STYLE_LIST_BACKGROUND";
/**
* Set the template for prompts for secondary (continuation) lines.
@ -390,6 +396,26 @@ public interface LineReader {
*/
String SUGGESTIONS_MIN_BUFFER_SIZE = "suggestions-min-buffer-size";
/**
* Max number of times a command can be repeated.
*/
String MAX_REPEAT_COUNT = "max-repeat-count";
/**
* Number of spaces to display a tabulation, the default is 4.
*/
String TAB_WIDTH = "tab-width";
/**
* Name of inputrc to read at line reader creation time.
*/
String INPUT_RC_FILE_NAME = "input-rc-file-name";
/**
* Prefix to automatically delegate variables to system properties
*/
String SYSTEM_PROPERTY_PREFIX = "system-property-prefix";
Map<String, KeyMap<Binding>> defaultKeyMaps();
enum Option {
@ -469,8 +495,7 @@ public interface LineReader {
EMPTY_WORD_OPTIONS(true),
/** Disable the undo feature */
DISABLE_UNDO
;
DISABLE_UNDO;
private final boolean def;
@ -611,7 +636,8 @@ public interface LineReader {
* @throws EndOfFileException if an EOF has been found (using Ctrl-D for example)
* @throws java.io.IOError in case of other i/o errors
*/
String readLine(String prompt, String rightPrompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException;
String readLine(String prompt, String rightPrompt, Character mask, String buffer)
throws UserInterruptException, EndOfFileException;
/**
* Read a line from the <i>in</i> {@link InputStream}, and return the line
@ -631,7 +657,8 @@ public interface LineReader {
* @throws EndOfFileException if an EOF has been found (using Ctrl-D for example)
* @throws java.io.IOError in case of other i/o errors
*/
String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer) throws UserInterruptException, EndOfFileException;
String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer)
throws UserInterruptException, EndOfFileException;
/**
* Prints a line above the prompt and redraw everything.
@ -702,7 +729,7 @@ public interface LineReader {
void runMacro(String macro);
/**
* Read a mouse event when the {@link jdk.internal.org.jline.utils.InfoCmp.Capability#key_mouse} sequence
* Read a mouse event when the {@link org.jline.utils.InfoCmp.Capability#key_mouse} sequence
* has just been read on the input stream.
* Compared to {@link Terminal#readMouseEvent()}, this method takes into account keys
* that have been pushed back using {@link #runMacro(String)}.
@ -751,8 +778,8 @@ public interface LineReader {
SuggestionType getAutosuggestion();
// JDK specific modification
default void zeroOut() {
throw new UnsupportedOperationException();
}
/**
* Clear any internal buffers.
*/
void zeroOut();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
* Copyright (c) 2002-2020, 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.
@ -38,8 +38,7 @@ public final class LineReaderBuilder {
Expander expander;
CompletionMatcher completionMatcher;
private LineReaderBuilder() {
}
private LineReaderBuilder() {}
public LineReaderBuilder terminal(Terminal terminal) {
this.terminal = terminal;
@ -88,8 +87,9 @@ public final class LineReaderBuilder {
try {
if (!Boolean.getBoolean(LineReader.PROP_SUPPORT_PARSEDLINE)
&& !(parser.parse("", 0) instanceof CompletingParsedLine)) {
Log.warn("The Parser of class " + parser.getClass().getName() + " does not support the CompletingParsedLine interface. " +
"Completion with escaped or quoted words won't work correctly.");
Log.warn("The Parser of class " + parser.getClass().getName()
+ " does not support the CompletingParsedLine interface. "
+ "Completion with escaped or quoted words won't work correctly.");
}
} catch (Throwable t) {
// Ignore
@ -153,5 +153,4 @@ public final class LineReaderBuilder {
}
return reader;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -35,7 +35,6 @@ public class Macro implements Binding {
@Override
public String toString() {
return "Macro[" +
sequence + ']';
return "Macro[" + sequence + ']';
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -31,5 +31,4 @@ public interface MaskingCallback {
* @return the modified line
*/
String history(String line);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -64,5 +64,4 @@ public interface ParsedLine {
* @return the cursor position within the line
*/
int cursor();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -35,7 +35,7 @@ public interface Parser {
default String getCommand(final String line) {
String out;
Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+|$)");
Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+|$)");
Matcher matcher = patternCommand.matcher(line);
if (matcher.find()) {
out = matcher.group(1);
@ -50,7 +50,7 @@ public interface Parser {
default String getVariable(final String line) {
String out = null;
Pattern patternCommand = Pattern.compile("^\\s*(" + REGEX_VARIABLE + ")\\s*=[^=~].*");
Pattern patternCommand = Pattern.compile("^\\s*(" + REGEX_VARIABLE + ")\\s*=[^=~].*");
Matcher matcher = patternCommand.matcher(line);
if (matcher.find()) {
out = matcher.group(1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -38,7 +38,6 @@ public class Reference implements Binding {
@Override
public String toString() {
return "Reference[" +
name + ']';
return "Reference[" + name + ']';
}
}

View File

@ -1,20 +1,10 @@
/*
* 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
* Copyright (c) 2023, the original author(s).
*
* http://www.apache.org/licenses/LICENSE-2.0
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* 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.
* https://opensource.org/licenses/BSD-3-Clause
*/
package jdk.internal.org.jline.reader;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -14,23 +14,19 @@ package jdk.internal.org.jline.reader;
* interrupt character (ctrl-C). The partially entered line is
* available via the {@link #getPartialLine()} method.
*/
public class UserInterruptException
extends RuntimeException
{
public class UserInterruptException extends RuntimeException {
private static final long serialVersionUID = 6172232572140736750L;
private final String partialLine;
public UserInterruptException(String partialLine)
{
public UserInterruptException(String partialLine) {
this.partialLine = partialLine;
}
/**
* @return the partially entered line when ctrl-C was pressed
*/
public String getPartialLine()
{
public String getPartialLine() {
return partialLine;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -15,5 +15,4 @@ package jdk.internal.org.jline.reader;
public interface Widget extends Binding {
boolean apply();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2017, the original author or authors.
* Copyright (c) 2002-2017, 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.
@ -20,8 +20,7 @@ import jdk.internal.org.jline.reader.Buffer;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.0
*/
public class BufferImpl implements Buffer
{
public class BufferImpl implements Buffer {
private int cursor = 0;
private int cursorCol = -1;
private int[] buffer;
@ -46,7 +45,7 @@ public class BufferImpl implements Buffer
this.g1 = buffer.g1;
}
public BufferImpl copy () {
public BufferImpl copy() {
return new BufferImpl(this);
}
@ -107,7 +106,7 @@ public class BufferImpl implements Buffer
* @param c the character to insert
*/
public void write(int c) {
write(new int[] { c });
write(new int[] {c});
}
/**
@ -121,7 +120,7 @@ public class BufferImpl implements Buffer
if (overTyping) {
delete(1);
}
write(new int[] { c });
write(new int[] {c});
}
/**
@ -224,8 +223,7 @@ public class BufferImpl implements Buffer
if ((cursor + where) < 0) {
where = -cursor;
}
else if ((cursor + where) > length()) {
} else if ((cursor + where) > length()) {
where = length() - cursor;
}
@ -371,7 +369,6 @@ public class BufferImpl implements Buffer
}
}
// JDK specific modification
@Override
public void zeroOut() {
Arrays.fill(buffer, 0);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -8,26 +8,25 @@
*/
package jdk.internal.org.jline.reader.impl;
import jdk.internal.org.jline.reader.Candidate;
import jdk.internal.org.jline.reader.CompletingParsedLine;
import jdk.internal.org.jline.reader.CompletionMatcher;
import jdk.internal.org.jline.reader.LineReader;
import jdk.internal.org.jline.utils.AttributedString;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import jdk.internal.org.jline.reader.Candidate;
import jdk.internal.org.jline.reader.CompletingParsedLine;
import jdk.internal.org.jline.reader.CompletionMatcher;
import jdk.internal.org.jline.reader.LineReader;
import jdk.internal.org.jline.utils.AttributedString;
public class CompletionMatcherImpl implements CompletionMatcher {
protected Predicate<String> exact;
protected List<Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>>> matchers;
private Map<String, List<Candidate>> matching;
private boolean caseInsensitive;
public CompletionMatcherImpl() {
}
public CompletionMatcherImpl() {}
protected void reset(boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
@ -37,8 +36,13 @@ public class CompletionMatcherImpl implements CompletionMatcher {
}
@Override
public void compile(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line
, boolean caseInsensitive, int errors, String originalGroupName) {
public void compile(
Map<LineReader.Option, Boolean> options,
boolean prefix,
CompletingParsedLine line,
boolean caseInsensitive,
int errors,
String originalGroupName) {
reset(caseInsensitive);
defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName);
}
@ -47,15 +51,18 @@ public class CompletionMatcherImpl implements CompletionMatcher {
public List<Candidate> matches(List<Candidate> candidates) {
matching = Collections.emptyMap();
Map<String, List<Candidate>> sortedCandidates = sort(candidates);
for (Function<Map<String, List<Candidate>>,
Map<String, List<Candidate>>> matcher : matchers) {
for (Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> matcher : matchers) {
matching = matcher.apply(sortedCandidates);
if (!matching.isEmpty()) {
break;
}
}
return !matching.isEmpty() ? matching.entrySet().stream().flatMap(e -> e.getValue().stream()).distinct().collect(Collectors.toList())
: new ArrayList<>();
return !matching.isEmpty()
? matching.entrySet().stream()
.flatMap(e -> e.getValue().stream())
.distinct()
.collect(Collectors.toList())
: new ArrayList<>();
}
@Override
@ -63,10 +70,12 @@ public class CompletionMatcherImpl implements CompletionMatcher {
if (matching == null) {
throw new IllegalStateException();
}
return matching.values().stream().flatMap(Collection::stream)
return matching.values().stream()
.flatMap(Collection::stream)
.filter(Candidate::complete)
.filter(c -> exact.test(c.value()))
.findFirst().orElse(null);
.findFirst()
.orElse(null);
}
@Override
@ -84,8 +93,13 @@ public class CompletionMatcherImpl implements CompletionMatcher {
/**
* Default JLine matchers
*/
protected void defaultMatchers(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line
, boolean caseInsensitive, int errors, String originalGroupName) {
protected void defaultMatchers(
Map<LineReader.Option, Boolean> options,
boolean prefix,
CompletingParsedLine line,
boolean caseInsensitive,
int errors,
String originalGroupName) {
// Find matchers
// TODO: glob completion
String wd = line.word();
@ -94,8 +108,7 @@ public class CompletionMatcherImpl implements CompletionMatcher {
if (prefix) {
matchers = new ArrayList<>(Arrays.asList(
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wp)),
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp))
));
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp))));
if (LineReader.Option.COMPLETE_MATCHER_TYPO.isSet(options)) {
matchers.add(typoMatcher(wp, errors, caseInsensitive, originalGroupName));
}
@ -109,14 +122,14 @@ public class CompletionMatcherImpl implements CompletionMatcher {
Pattern p1 = Pattern.compile(Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
matchers = new ArrayList<>(Arrays.asList(
simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s).matches()),
simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s).matches())
));
simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s)
.matches()),
simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s)
.matches())));
} else {
matchers = new ArrayList<>(Arrays.asList(
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wdi)),
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi))
));
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi))));
}
if (LineReader.Option.COMPLETE_MATCHER_CAMELCASE.isSet(options)) {
matchers.add(simpleMatcher(s -> camelMatch(wd, 0, s, 0)));
@ -128,18 +141,20 @@ public class CompletionMatcherImpl implements CompletionMatcher {
}
}
protected Function<Map<String, List<Candidate>>,
Map<String, List<Candidate>>> simpleMatcher(Predicate<String> predicate) {
protected Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> simpleMatcher(
Predicate<String> predicate) {
return m -> m.entrySet().stream()
.filter(e -> predicate.test(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
protected Function<Map<String, List<Candidate>>,
Map<String, List<Candidate>>> typoMatcher(String word, int errors, boolean caseInsensitive, String originalGroupName) {
protected Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> typoMatcher(
String word, int errors, boolean caseInsensitive, String originalGroupName) {
return m -> {
Map<String, List<Candidate>> map = m.entrySet().stream()
.filter(e -> ReaderUtils.distance(word, caseInsensitive ? e.getKey().toLowerCase() : e.getKey()) < errors)
.filter(e -> ReaderUtils.distance(
word, caseInsensitive ? e.getKey().toLowerCase() : e.getKey())
< errors)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (map.size() > 1) {
map.computeIfAbsent(word, w -> new ArrayList<>())
@ -178,7 +193,8 @@ public class CompletionMatcherImpl implements CompletionMatcher {
Map<String, List<Candidate>> sortedCandidates = new HashMap<>();
for (Candidate candidate : candidates) {
sortedCandidates
.computeIfAbsent(AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>())
.computeIfAbsent(
AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>())
.add(candidate);
}
return sortedCandidates;
@ -206,5 +222,4 @@ public class CompletionMatcherImpl implements CompletionMatcher {
}
return new String(s1, 0, len);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -32,27 +32,25 @@ public class DefaultExpander implements Expander {
if (unicode > 0) {
escaped = (--unicode >= 0);
sb.append(c);
}
else if (escaped) {
} else if (escaped) {
if (c == 'u') {
unicode = 4;
} else {
escaped = false;
}
sb.append(c);
}
else if (c == '\'') {
} else if (c == '\'') {
inQuote = !inQuote;
sb.append(c);
}
else if (inQuote) {
} else if (inQuote) {
sb.append(c);
}
else {
} else {
switch (c) {
case '\\':
// any '\!' should be considered an expansion escape, so skip expansion and strip the escape character
// a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character
// any '\!' should be considered an expansion escape, so skip expansion and strip the escape
// character
// a leading '\^' should be considered an expansion escape, so skip expansion and strip the
// escape character
// otherwise, add the escape
escaped = true;
sb.append(c);
@ -91,7 +89,8 @@ public class DefaultExpander implements Expander {
if (history.size() == 0) {
throw new IllegalArgumentException("!$: event not found");
}
String previous = history.get(history.index() - 1).trim();
String previous =
history.get(history.index() - 1).trim();
int lastSpace = previous.lastIndexOf(' ');
if (lastSpace != -1) {
rep = previous.substring(lastSpace + 1);
@ -128,14 +127,18 @@ public class DefaultExpander implements Expander {
try {
idx = Integer.parseInt(line.substring(i1, i));
} catch (NumberFormatException e) {
throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
throw new IllegalArgumentException(
(neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
}
if (neg && idx > 0 && idx <= history.size()) {
rep = history.get(history.index() - idx);
} else if (!neg && idx > history.index() - history.size() && idx <= history.index()) {
} else if (!neg
&& idx > history.index() - history.size()
&& idx <= history.index()) {
rep = history.get(idx - 1);
} else {
throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
throw new IllegalArgumentException(
(neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
}
break;
default:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -10,9 +10,9 @@ package jdk.internal.org.jline.reader.impl;
import java.util.regex.Pattern;
import jdk.internal.org.jline.reader.Highlighter;
import jdk.internal.org.jline.reader.LineReader;
import jdk.internal.org.jline.reader.LineReader.RegionType;
import jdk.internal.org.jline.reader.Highlighter;
import jdk.internal.org.jline.utils.AttributedString;
import jdk.internal.org.jline.utils.AttributedStringBuilder;
import jdk.internal.org.jline.utils.AttributedStyle;
@ -57,7 +57,8 @@ public class DefaultHighlighter implements Highlighter {
while (negativeStart > 0 && reader.getBuffer().atChar(negativeStart - 1) != '\n') {
negativeStart--;
}
while (negativeEnd < reader.getBuffer().length() - 1 && reader.getBuffer().atChar(negativeEnd + 1) != '\n') {
while (negativeEnd < reader.getBuffer().length() - 1
&& reader.getBuffer().atChar(negativeEnd + 1) != '\n') {
negativeEnd++;
}
}
@ -104,5 +105,4 @@ public class DefaultHighlighter implements Highlighter {
}
return sb.toAttributedString();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
* Copyright (c) 2002-2020, 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.
@ -21,18 +21,18 @@ import jdk.internal.org.jline.reader.Parser;
public class DefaultParser implements Parser {
public enum Bracket {
ROUND, // ()
CURLY, // {}
SQUARE, // []
ANGLE // <>
ROUND, // ()
CURLY, // {}
SQUARE, // []
ANGLE // <>
}
public static class BlockCommentDelims {
private final String start;
private final String end;
public BlockCommentDelims(String start, String end) {
if (start == null || end == null
|| start.isEmpty() || end.isEmpty() || start.equals(end)) {
if (start == null || end == null || start.isEmpty() || end.isEmpty() || start.equals(end)) {
throw new IllegalArgumentException("Bad block comment delimiter!");
}
this.start = start;
@ -185,22 +185,22 @@ public class DefaultParser implements Parser {
int i = 0;
for (Bracket b : bs) {
switch (b) {
case ROUND:
openingBrackets[i] = '(';
closingBrackets[i] = ')';
break;
case CURLY:
openingBrackets[i] = '{';
closingBrackets[i] = '}';
break;
case SQUARE:
openingBrackets[i] = '[';
closingBrackets[i] = ']';
break;
case ANGLE:
openingBrackets[i] = '<';
closingBrackets[i] = '>';
break;
case ROUND:
openingBrackets[i] = '(';
closingBrackets[i] = ')';
break;
case CURLY:
openingBrackets[i] = '{';
closingBrackets[i] = '}';
break;
case SQUARE:
openingBrackets[i] = '[';
closingBrackets[i] = ']';
break;
case ANGLE:
openingBrackets[i] = '<';
closingBrackets[i] = '>';
break;
}
i++;
}
@ -229,7 +229,6 @@ public class DefaultParser implements Parser {
return name != null && regexVariable != null && name.matches(regexVariable);
}
@Override
public String getCommand(final String line) {
String out = "";
@ -296,7 +295,7 @@ public class DefaultParser implements Parser {
if (quoteStart < 0 && isQuoteChar(line, i) && !lineCommented && !blockCommented) {
// Start a quote block
quoteStart = i;
if (current.length()==0) {
if (current.length() == 0) {
quotedWord = true;
if (context == ParseContext.SPLIT_LINE) {
current.append(line.charAt(i));
@ -324,13 +323,15 @@ public class DefaultParser implements Parser {
}
} else {
// Delimiter
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i);
rawWordLength = handleDelimiterAndGetRawWordLength(
current, words, rawWordStart, rawWordCursor, rawWordLength, i);
rawWordStart = i + 1;
}
} else {
if (quoteStart < 0 && !blockCommented && (lineCommented || isLineCommentStarted(line, i))) {
lineCommented = true;
} else if (quoteStart < 0 && !lineCommented
} else if (quoteStart < 0
&& !lineCommented
&& (blockCommented || isCommentDelim(line, i, blockCommentStart))) {
if (blockCommented) {
if (blockCommentEnd != null && isCommentDelim(line, i, blockCommentEnd)) {
@ -339,12 +340,12 @@ public class DefaultParser implements Parser {
}
} else {
blockCommented = true;
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i);
rawWordLength = handleDelimiterAndGetRawWordLength(
current, words, rawWordStart, rawWordCursor, rawWordLength, i);
i += blockCommentStart == null ? 0 : blockCommentStart.length() - 1;
rawWordStart = i + 1;
}
} else if (quoteStart < 0 && !lineCommented
&& isCommentDelim(line, i, blockCommentEnd)) {
} else if (quoteStart < 0 && !lineCommented && isCommentDelim(line, i, blockCommentEnd)) {
current.append(line.charAt(i));
blockCommentInRightOrder = false;
} else if (!isEscapeChar(line, i)) {
@ -377,16 +378,14 @@ public class DefaultParser implements Parser {
throw new EOFError(-1, -1, "Escaped new line", "newline");
}
if (eofOnUnclosedQuote && quoteStart >= 0) {
throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\''
? "quote" : "dquote");
throw new EOFError(
-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\'' ? "quote" : "dquote");
}
if (blockCommented) {
throw new EOFError(-1, -1, "Missing closing block comment delimiter",
"add: " + blockCommentEnd);
throw new EOFError(-1, -1, "Missing closing block comment delimiter", "add: " + blockCommentEnd);
}
if (!blockCommentInRightOrder) {
throw new EOFError(-1, -1, "Missing opening block comment delimiter",
"missing: " + blockCommentStart);
throw new EOFError(-1, -1, "Missing opening block comment delimiter", "missing: " + blockCommentStart);
}
if (bracketChecker.isClosingBracketMissing() || bracketChecker.isOpeningBracketMissing()) {
String message = null;
@ -398,8 +397,13 @@ public class DefaultParser implements Parser {
message = "Missing opening bracket";
missing = "missing: " + bracketChecker.getMissingOpeningBracket();
}
throw new EOFError(-1, -1, message, missing,
bracketChecker.getOpenBrackets(), bracketChecker.getNextClosingBracket());
throw new EOFError(
-1,
-1,
message,
missing,
bracketChecker.getOpenBrackets(),
bracketChecker.getNextClosingBracket());
}
}
@ -420,7 +424,13 @@ public class DefaultParser implements Parser {
return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
}
private int handleDelimiterAndGetRawWordLength(StringBuilder current, List<String> words, int rawWordStart, int rawWordCursor, int rawWordLength, int pos) {
private int handleDelimiterAndGetRawWordLength(
StringBuilder current,
List<String> words,
int rawWordStart,
int rawWordCursor,
int rawWordLength,
int pos) {
if (current.length() > 0) {
words.add(current.toString());
current.setLength(0); // reset the arg
@ -470,7 +480,7 @@ public class DefaultParser implements Parser {
public boolean isLineCommentStarted(final CharSequence buffer, final int pos) {
if (lineCommentDelims != null) {
for (String comment: lineCommentDelims) {
for (String comment : lineCommentDelims) {
if (isCommentDelim(buffer, pos, comment)) {
return true;
}
@ -584,8 +594,8 @@ public class DefaultParser implements Parser {
} else {
bid = bracketId(closingBrackets, buffer, pos);
if (bid >= 0) {
if (!nested.isEmpty() && bid == nested.get(nested.size()-1)) {
nested.remove(nested.size()-1);
if (!nested.isEmpty() && bid == nested.get(nested.size() - 1)) {
nested.remove(nested.size() - 1);
} else {
missingOpeningBracket = bid;
}
@ -634,7 +644,7 @@ public class DefaultParser implements Parser {
}
private int bracketId(final char[] brackets, final CharSequence buffer, final int pos) {
for (int i=0; i < brackets.length; i++) {
for (int i = 0; i < brackets.length; i++) {
if (buffer.charAt(pos) == brackets[i]) {
return i;
}
@ -648,8 +658,7 @@ public class DefaultParser implements Parser {
*
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
*/
public class ArgumentList implements ParsedLine, CompletingParsedLine
{
public class ArgumentList implements ParsedLine, CompletingParsedLine {
private final String line;
private final List<String> words;
@ -667,11 +676,21 @@ public class DefaultParser implements Parser {
private final int rawWordLength;
@Deprecated
public ArgumentList(final String line, final List<String> words,
final int wordIndex, final int wordCursor,
final int cursor) {
this(line, words, wordIndex, wordCursor, cursor,
null, wordCursor, words.get(wordIndex).length());
public ArgumentList(
final String line,
final List<String> words,
final int wordIndex,
final int wordCursor,
final int cursor) {
this(
line,
words,
wordIndex,
wordCursor,
cursor,
null,
wordCursor,
words.get(wordIndex).length());
}
/**
@ -685,10 +704,15 @@ public class DefaultParser implements Parser {
* @param rawWordCursor the cursor position inside the raw word (i.e. including quotes and escape characters)
* @param rawWordLength the raw word length, including quotes and escape characters
*/
public ArgumentList(final String line, final List<String> words,
final int wordIndex, final int wordCursor,
final int cursor, final String openingQuote,
final int rawWordCursor, final int rawWordLength) {
public ArgumentList(
final String line,
final List<String> words,
final int wordIndex,
final int wordCursor,
final int cursor,
final String openingQuote,
final int rawWordCursor,
final int rawWordLength) {
this.line = line;
this.words = Collections.unmodifiableList(Objects.requireNonNull(words));
this.wordIndex = wordIndex;
@ -732,8 +756,8 @@ public class DefaultParser implements Parser {
Predicate<Integer> needToBeEscaped;
String quote = openingQuote;
boolean middleQuotes = false;
if (openingQuote==null) {
for (int i=0; i < sb.length(); i++) {
if (openingQuote == null) {
for (int i = 0; i < sb.length(); i++) {
if (isQuoteChar(sb, i)) {
middleQuotes = true;
break;
@ -746,7 +770,8 @@ public class DefaultParser implements Parser {
// Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does.
// Also, close the quote at the end
if (openingQuote != null) {
needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)) || String.valueOf(sb.charAt(i)).equals(openingQuote);
needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i))
|| String.valueOf(sb.charAt(i)).equals(openingQuote);
}
// Completion is protected by middle quotes:
// Delimiters (spaces) don't need to be escaped, nor do quotes, but everything else does.
@ -756,8 +781,8 @@ public class DefaultParser implements Parser {
// No quote protection, need to escape everything: delimiter chars (spaces), quote chars
// and escapes themselves
else {
needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i))
|| isRawQuoteChar(sb.charAt(i));
needToBeEscaped = i ->
isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) || isRawQuoteChar(sb.charAt(i));
}
for (int i = 0; i < sb.length(); i++) {
if (needToBeEscaped.test(i)) {
@ -792,5 +817,4 @@ public class DefaultParser implements Parser {
return rawWordLength;
}
}
}

View File

@ -0,0 +1,394 @@
/*
* Copyright (c) 2002-2023, 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 jdk.internal.org.jline.reader.impl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import jdk.internal.org.jline.reader.LineReader;
import jdk.internal.org.jline.reader.Macro;
import jdk.internal.org.jline.reader.Reference;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.utils.Log;
public final class InputRC {
public static void configure(LineReader reader, URL url) throws IOException {
try (InputStream is = url.openStream()) {
configure(reader, is);
}
}
public static void configure(LineReader reader, InputStream is) throws IOException {
try (InputStreamReader r = new InputStreamReader(is)) {
configure(reader, r);
}
}
public static void configure(LineReader reader, Reader r) throws IOException {
BufferedReader br;
if (r instanceof BufferedReader) {
br = (BufferedReader) r;
} else {
br = new BufferedReader(r);
}
Terminal terminal = reader.getTerminal();
if (Terminal.TYPE_DUMB.equals(terminal.getType()) || Terminal.TYPE_DUMB_COLOR.equals(terminal.getType())) {
reader.getVariables().putIfAbsent(LineReader.EDITING_MODE, "dumb");
} else {
reader.getVariables().putIfAbsent(LineReader.EDITING_MODE, "emacs");
}
reader.setKeyMap(LineReader.MAIN);
new InputRC(reader).parse(br);
if ("vi".equals(reader.getVariable(LineReader.EDITING_MODE))) {
reader.getKeyMaps().put(LineReader.MAIN, reader.getKeyMaps().get(LineReader.VIINS));
} else if ("emacs".equals(reader.getVariable(LineReader.EDITING_MODE))) {
reader.getKeyMaps().put(LineReader.MAIN, reader.getKeyMaps().get(LineReader.EMACS));
} else if ("dumb".equals(reader.getVariable(LineReader.EDITING_MODE))) {
reader.getKeyMaps().put(LineReader.MAIN, reader.getKeyMaps().get(LineReader.DUMB));
}
}
private final LineReader reader;
private InputRC(LineReader reader) {
this.reader = reader;
}
private void parse(BufferedReader br) throws IOException, IllegalArgumentException {
String line;
boolean parsing = true;
List<Boolean> ifsStack = new ArrayList<>();
while ((line = br.readLine()) != null) {
try {
line = line.trim();
if (line.length() == 0) {
continue;
}
if (line.charAt(0) == '#') {
continue;
}
int i = 0;
if (line.charAt(i) == '$') {
String cmd;
String args;
++i;
while (i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t')) {
i++;
}
int s = i;
while (i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t')) {
i++;
}
cmd = line.substring(s, i);
while (i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t')) {
i++;
}
s = i;
while (i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t')) {
i++;
}
args = line.substring(s, i);
if ("if".equalsIgnoreCase(cmd)) {
ifsStack.add(parsing);
if (!parsing) {
continue;
}
if (args.startsWith("term=")) {
// TODO
} else if (args.startsWith("mode=")) {
String mode = (String) reader.getVariable(LineReader.EDITING_MODE);
parsing = args.substring("mode=".length()).equalsIgnoreCase(mode);
} else {
parsing = args.equalsIgnoreCase(reader.getAppName());
}
} else if ("else".equalsIgnoreCase(cmd)) {
if (ifsStack.isEmpty()) {
throw new IllegalArgumentException("$else found without matching $if");
}
boolean invert = true;
for (boolean b : ifsStack) {
if (!b) {
invert = false;
break;
}
}
if (invert) {
parsing = !parsing;
}
} else if ("endif".equalsIgnoreCase(cmd)) {
if (ifsStack.isEmpty()) {
throw new IllegalArgumentException("endif found without matching $if");
}
parsing = ifsStack.remove(ifsStack.size() - 1);
} else if ("include".equalsIgnoreCase(cmd)) {
// TODO
}
continue;
}
if (!parsing) {
continue;
}
if (line.charAt(i++) == '"') {
boolean esc = false;
for (; ; i++) {
if (i >= line.length()) {
throw new IllegalArgumentException("Missing closing quote on line '" + line + "'");
}
if (esc) {
esc = false;
} else if (line.charAt(i) == '\\') {
esc = true;
} else if (line.charAt(i) == '"') {
break;
}
}
}
while (i < line.length() && line.charAt(i) != ':' && line.charAt(i) != ' ' && line.charAt(i) != '\t') {
i++;
}
String keySeq = line.substring(0, i);
boolean equivalency = i + 1 < line.length() && line.charAt(i) == ':' && line.charAt(i + 1) == '=';
i++;
if (equivalency) {
i++;
}
if (keySeq.equalsIgnoreCase("set")) {
String key;
String val;
while (i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t')) {
i++;
}
int s = i;
while (i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t')) {
i++;
}
key = line.substring(s, i);
while (i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t')) {
i++;
}
s = i;
while (i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t')) {
i++;
}
val = line.substring(s, i);
setVar(reader, key, val);
} else {
while (i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t')) {
i++;
}
int start = i;
if (i < line.length() && (line.charAt(i) == '\'' || line.charAt(i) == '\"')) {
char delim = line.charAt(i++);
boolean esc = false;
for (; ; i++) {
if (i >= line.length()) {
break;
}
if (esc) {
esc = false;
} else if (line.charAt(i) == '\\') {
esc = true;
} else if (line.charAt(i) == delim) {
break;
}
}
}
for (; i < line.length() && line.charAt(i) != ' ' && line.charAt(i) != '\t'; i++)
;
String val = line.substring(Math.min(start, line.length()), Math.min(i, line.length()));
if (keySeq.charAt(0) == '"') {
keySeq = translateQuoted(keySeq);
} else {
// Bind key name
String keyName =
keySeq.lastIndexOf('-') > 0 ? keySeq.substring(keySeq.lastIndexOf('-') + 1) : keySeq;
char key = getKeyFromName(keyName);
keyName = keySeq.toLowerCase();
keySeq = "";
if (keyName.contains("meta-") || keyName.contains("m-")) {
keySeq += "\u001b";
}
if (keyName.contains("control-") || keyName.contains("c-") || keyName.contains("ctrl-")) {
key = (char) (Character.toUpperCase(key) & 0x1f);
}
keySeq += key;
}
if (val.length() > 0 && (val.charAt(0) == '\'' || val.charAt(0) == '\"')) {
reader.getKeys().bind(new Macro(translateQuoted(val)), keySeq);
} else {
reader.getKeys().bind(new Reference(val), keySeq);
}
}
} catch (IllegalArgumentException e) {
Log.warn("Unable to parse user configuration: ", e);
}
}
}
private static String translateQuoted(String keySeq) {
int i;
String str = keySeq.substring(1, keySeq.length() - 1);
StringBuilder sb = new StringBuilder();
for (i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '\\') {
boolean ctrl = str.regionMatches(i, "\\C-", 0, 3) || str.regionMatches(i, "\\M-\\C-", 0, 6);
boolean meta = str.regionMatches(i, "\\M-", 0, 3) || str.regionMatches(i, "\\C-\\M-", 0, 6);
i += (meta ? 3 : 0) + (ctrl ? 3 : 0) + (!meta && !ctrl ? 1 : 0);
if (i >= str.length()) {
break;
}
c = str.charAt(i);
if (meta) {
sb.append("\u001b");
}
if (ctrl) {
c = c == '?' ? 0x7f : (char) (Character.toUpperCase(c) & 0x1f);
}
if (!meta && !ctrl) {
switch (c) {
case 'a':
c = 0x07;
break;
case 'b':
c = '\b';
break;
case 'd':
c = 0x7f;
break;
case 'e':
c = 0x1b;
break;
case 'f':
c = '\f';
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'v':
c = 0x0b;
break;
case '\\':
c = '\\';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = 0;
for (int j = 0; j < 3; j++, i++) {
if (i >= str.length()) {
break;
}
int k = Character.digit(str.charAt(i), 8);
if (k < 0) {
break;
}
c = (char) (c * 8 + k);
}
c &= 0xFF;
break;
case 'x':
i++;
c = 0;
for (int j = 0; j < 2; j++, i++) {
if (i >= str.length()) {
break;
}
int k = Character.digit(str.charAt(i), 16);
if (k < 0) {
break;
}
c = (char) (c * 16 + k);
}
c &= 0xFF;
break;
case 'u':
i++;
c = 0;
for (int j = 0; j < 4; j++, i++) {
if (i >= str.length()) {
break;
}
int k = Character.digit(str.charAt(i), 16);
if (k < 0) {
break;
}
c = (char) (c * 16 + k);
}
break;
}
}
sb.append(c);
} else {
sb.append(c);
}
}
return sb.toString();
}
private static char getKeyFromName(String name) {
if ("DEL".equalsIgnoreCase(name) || "Rubout".equalsIgnoreCase(name)) {
return 0x7f;
} else if ("ESC".equalsIgnoreCase(name) || "Escape".equalsIgnoreCase(name)) {
return '\033';
} else if ("LFD".equalsIgnoreCase(name) || "NewLine".equalsIgnoreCase(name)) {
return '\n';
} else if ("RET".equalsIgnoreCase(name) || "Return".equalsIgnoreCase(name)) {
return '\r';
} else if ("SPC".equalsIgnoreCase(name) || "Space".equalsIgnoreCase(name)) {
return ' ';
} else if ("Tab".equalsIgnoreCase(name)) {
return '\t';
} else {
return name.charAt(0);
}
}
static void setVar(LineReader reader, String key, String val) {
if (LineReader.KEYMAP.equalsIgnoreCase(key)) {
reader.setKeyMap(val);
return;
}
for (LineReader.Option option : LineReader.Option.values()) {
if (option.name().toLowerCase(Locale.ENGLISH).replace('_', '-').equals(val)) {
if ("on".equalsIgnoreCase(val)) {
reader.setOpt(option);
} else if ("off".equalsIgnoreCase(val)) {
reader.unsetOpt(option);
}
return;
}
}
reader.setVariable(key, val);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
* Copyright (c) 2002-2020, 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.
@ -13,7 +13,7 @@ import jdk.internal.org.jline.utils.Levenshtein;
public class ReaderUtils {
private ReaderUtils() { }
private ReaderUtils() {}
public static boolean isSet(LineReader reader, LineReader.Option option) {
return reader != null && reader.isSet(option);
@ -30,8 +30,7 @@ public class ReaderUtils {
return (Boolean) v;
} else if (v != null) {
String s = v.toString();
return s.isEmpty() || s.equalsIgnoreCase("on")
|| s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
return s.isEmpty() || s.equalsIgnoreCase("on") || s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
}
return def;
}
@ -77,5 +76,4 @@ public class ReaderUtils {
return Levenshtein.distance(word, cand);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2017, the original author or authors.
* Copyright (c) 2002-2017, 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.
@ -8,10 +8,10 @@
*/
package jdk.internal.org.jline.reader.impl;
import jdk.internal.org.jline.reader.MaskingCallback;
import java.util.Objects;
import jdk.internal.org.jline.reader.MaskingCallback;
/**
* Simple {@link MaskingCallback} that will replace all the characters in the line with the given mask.
* If the given mask is equal to {@link LineReaderImpl#NULL_MASK} then the line will be replaced with an empty String.
@ -29,7 +29,7 @@ public final class SimpleMaskingCallback implements MaskingCallback {
return "";
} else {
StringBuilder sb = new StringBuilder(line.length());
for (int i = line.length(); i-- > 0;) {
for (int i = line.length(); i-- > 0; ) {
sb.append((char) mask);
}
return sb.toString();
@ -40,5 +40,4 @@ public final class SimpleMaskingCallback implements MaskingCallback {
public String history(String line) {
return null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -20,6 +20,7 @@ public class UndoTree<T> {
private final Node parent;
private Node current;
@SuppressWarnings("this-escape")
public UndoTree(Consumer<T> s) {
state = s;
parent = new Node(null);
@ -71,5 +72,4 @@ public class UndoTree<T> {
state = s;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -24,9 +24,7 @@ import jdk.internal.org.jline.reader.ParsedLine;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public class AggregateCompleter
implements Completer
{
public class AggregateCompleter implements Completer {
private final Collection<Completer> completers;
/**
@ -78,9 +76,6 @@ public class AggregateCompleter
*/
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
"completers=" + completers +
'}';
return getClass().getSimpleName() + "{" + "completers=" + completers + '}';
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019, the original author or authors.
* Copyright (c) 2002-2019, 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.
@ -29,8 +29,7 @@ import jdk.internal.org.jline.reader.ParsedLine;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public class ArgumentCompleter implements Completer
{
public class ArgumentCompleter implements Completer {
private final List<Completer> completers = new ArrayList<>();
private boolean strict = true;
@ -108,12 +107,12 @@ public class ArgumentCompleter implements Completer
// if we are beyond the end of the completers, just use the last one
if (line.wordIndex() >= completers.size()) {
completer = completers.get(completers.size() - 1);
}
else {
} else {
completer = completers.get(line.wordIndex());
}
// ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
// ensure that all the previous completers are successful before allowing this completer to pass (only if
// strict).
for (int i = strictCommand ? 0 : 1; isStrict() && (i < line.wordIndex()); i++) {
int idx = i >= completers.size() ? (completers.size() - 1) : i;
if (idx == 0 && !strictCommand) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -19,8 +19,7 @@ import jdk.internal.org.jline.reader.Completer;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public class EnumCompleter extends StringsCompleter
{
public class EnumCompleter extends StringsCompleter {
public EnumCompleter(Class<? extends Enum<?>> source) {
Objects.requireNonNull(source);
for (Enum<?> n : source.getEnumConstants()) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -9,6 +9,7 @@
package jdk.internal.org.jline.reader.impl.completer;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -41,11 +42,10 @@ import jdk.internal.org.jline.utils.AttributedStyle;
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
* @deprecated use <code>jdk.internal.org.jline.builtins.Completers$FileNameCompleter</code> instead
* @deprecated use <code>org.jline.builtins.Completers$FileNameCompleter</code> instead
*/
@Deprecated
public class FileNameCompleter implements Completer
{
public class FileNameCompleter implements Completer {
public void complete(LineReader reader, ParsedLine commandLine, final List<Candidate> candidates) {
assert commandLine != null;
@ -72,20 +72,21 @@ public class FileNameCompleter implements Completer
curBuf = "";
current = getUserDir();
}
try {
Files.newDirectoryStream(current, this::accept).forEach(p -> {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(current, this::accept)) {
directoryStream.forEach(p -> {
String value = curBuf + p.getFileName().toString();
if (Files.isDirectory(p)) {
candidates.add(new Candidate(
value + (reader.isSet(Option.AUTO_PARAM_SLASH) ? sep : ""),
getDisplay(reader.getTerminal(), p),
null, null,
null,
null,
reader.isSet(Option.AUTO_REMOVE_SLASH) ? sep : null,
null,
false));
} else {
candidates.add(new Candidate(value, getDisplay(reader.getTerminal(), p),
null, null, null, null, true));
candidates.add(
new Candidate(value, getDisplay(reader.getTerminal(), p), null, null, null, null, true));
}
});
} catch (IOException e) {
@ -125,5 +126,4 @@ public class FileNameCompleter implements Completer
}
return name;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -22,11 +22,8 @@ import jdk.internal.org.jline.reader.ParsedLine;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public final class NullCompleter
implements Completer
{
public final class NullCompleter implements Completer {
public static final NullCompleter INSTANCE = new NullCompleter();
public void complete(LineReader reader, final ParsedLine line, final List<Candidate> candidates) {
}
public void complete(LineReader reader, final ParsedLine line, final List<Candidate> candidates) {}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019, the original author or authors.
* Copyright (c) 2002-2019, 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.
@ -27,8 +27,7 @@ import jdk.internal.org.jline.utils.AttributedString;
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public class StringsCompleter implements Completer
{
public class StringsCompleter implements Completer {
protected Collection<Candidate> candidates;
protected Supplier<Collection<String>> stringsSupplier;
@ -54,7 +53,7 @@ public class StringsCompleter implements Completer
}
}
public StringsCompleter(Candidate ... candidates) {
public StringsCompleter(Candidate... candidates) {
this(Arrays.asList(candidates));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
* Copyright (c) 2002-2020, 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.
@ -22,8 +22,8 @@ import jdk.internal.org.jline.utils.AttributedString;
* @author <a href="mailto:matti.rintanikkola@gmail.com">Matti Rinta-Nikkola</a>
*/
public class SystemCompleter implements Completer {
private Map<String,List<Completer>> completers = new HashMap<>();
private Map<String,String> aliasCommand = new HashMap<>();
private Map<String, List<Completer>> completers = new HashMap<>();
private Map<String, String> aliasCommand = new HashMap<>();
private StringsCompleter commands;
private boolean compiled = false;
@ -44,9 +44,9 @@ public class SystemCompleter implements Completer {
commands.complete(reader, commandLine, candidates);
} else if (reader.getParser().validVariableName(buffer.substring(0, eq))) {
String curBuf = buffer.substring(0, eq + 1);
for (String c: completers.keySet()) {
candidates.add(new Candidate(AttributedString.stripAnsi(curBuf+c)
, c, null, null, null, null, true));
for (String c : completers.keySet()) {
candidates.add(
new Candidate(AttributedString.stripAnsi(curBuf + c), c, null, null, null, null, true));
}
}
} else {
@ -81,7 +81,7 @@ public class SystemCompleter implements Completer {
}
public void add(List<String> commands, Completer completer) {
for (String c: commands) {
for (String c : commands) {
add(c, completer);
}
}
@ -104,22 +104,22 @@ public class SystemCompleter implements Completer {
if (other.isCompiled()) {
throw new IllegalStateException();
}
for (Map.Entry<String, List<Completer>> entry: other.getCompleters().entrySet()) {
for (Completer c: entry.getValue()) {
for (Map.Entry<String, List<Completer>> entry : other.getCompleters().entrySet()) {
for (Completer c : entry.getValue()) {
add(entry.getKey(), c);
}
}
addAliases(other.getAliases());
}
public void addAliases(Map<String,String> aliasCommand) {
public void addAliases(Map<String, String> aliasCommand) {
if (compiled) {
throw new IllegalStateException();
}
this.aliasCommand.putAll(aliasCommand);
}
private Map<String,String> getAliases() {
private Map<String, String> getAliases() {
return aliasCommand;
}
@ -128,7 +128,7 @@ public class SystemCompleter implements Completer {
return;
}
Map<String, List<Completer>> compiledCompleters = new HashMap<>();
for (Map.Entry<String, List<Completer>> entry: completers.entrySet()) {
for (Map.Entry<String, List<Completer>> entry : completers.entrySet()) {
if (entry.getValue().size() == 1) {
compiledCompleters.put(entry.getKey(), entry.getValue());
} else {
@ -143,8 +143,7 @@ public class SystemCompleter implements Completer {
compiled = true;
}
public Map<String,List<Completer>> getCompleters() {
public Map<String, List<Completer>> getCompleters() {
return completers;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -41,9 +41,9 @@ public class DefaultHistory implements History {
private int offset = 0;
private int index = 0;
public DefaultHistory() {
}
public DefaultHistory() {}
@SuppressWarnings("this-escape")
public DefaultHistory(LineReader reader) {
attach(reader);
}
@ -67,8 +67,7 @@ public class DefaultHistory implements History {
this.reader = reader;
try {
load();
}
catch (IllegalArgumentException | IOException e) {
} catch (IllegalArgumentException | IOException e) {
Log.warn("Failed to load history", e);
}
}
@ -117,13 +116,13 @@ public class DefaultHistory implements History {
}
}
private String doHistoryFileDataKey (Path path){
private String doHistoryFileDataKey(Path path) {
return path != null ? path.toAbsolutePath().toString() : null;
}
private HistoryFileData getHistoryFileData(Path path) {
String key = doHistoryFileDataKey(path);
if (!historyFiles.containsKey(key)){
if (!historyFiles.containsKey(key)) {
historyFiles.put(key, new HistoryFileData());
}
return historyFiles.get(key);
@ -133,7 +132,7 @@ public class DefaultHistory implements History {
historyFiles.put(doHistoryFileDataKey(path), historyFileData);
}
private boolean isLineReaderHistory (Path path) throws IOException {
private boolean isLineReaderHistory(Path path) throws IOException {
Path lrp = getPath();
if (lrp == null) {
return path == null;
@ -141,23 +140,23 @@ public class DefaultHistory implements History {
return Files.isSameFile(lrp, path);
}
private void setLastLoaded(Path path, int lastloaded){
private void setLastLoaded(Path path, int lastloaded) {
getHistoryFileData(path).setLastLoaded(lastloaded);
}
private void setEntriesInFile(Path path, int entriesInFile){
private void setEntriesInFile(Path path, int entriesInFile) {
getHistoryFileData(path).setEntriesInFile(entriesInFile);
}
private void incEntriesInFile(Path path, int amount){
private void incEntriesInFile(Path path, int amount) {
getHistoryFileData(path).incEntriesInFile(amount);
}
private int getLastLoaded(Path path){
private int getLastLoaded(Path path) {
return getHistoryFileData(path).getLastLoaded();
}
private int getEntriesInFile(Path path){
private int getEntriesInFile(Path path) {
return getHistoryFileData(path).getEntriesInFile();
}
@ -168,9 +167,8 @@ public class DefaultHistory implements History {
protected void addHistoryLine(Path path, String line, boolean checkDuplicates) {
if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
int idx = line.indexOf(':');
final String badHistoryFileSyntax = "Bad history file syntax! " +
"The history file `" + path + "` may be an older history: " +
"please remove it or use a different history file.";
final String badHistoryFileSyntax = "Bad history file syntax! " + "The history file `" + path
+ "` may be an older history: " + "please remove it or use a different history file.";
if (idx < 0) {
throw new IllegalArgumentException(badHistoryFileSyntax);
}
@ -183,8 +181,7 @@ public class DefaultHistory implements History {
String unescaped = unescape(line.substring(idx + 1));
internalAdd(time, unescaped, checkDuplicates);
}
else {
} else {
internalAdd(Instant.now(), unescape(line), checkDuplicates);
}
}
@ -210,8 +207,7 @@ public class DefaultHistory implements History {
@Override
public void append(Path file, boolean incremental) throws IOException {
internalWrite(file != null ? file : getPath(),
incremental ? getLastLoaded(file) : 0);
internalWrite(file != null ? file : getPath(), incremental ? getLastLoaded(file) : 0);
}
@Override
@ -227,8 +223,11 @@ public class DefaultHistory implements History {
Files.createDirectories(parent);
}
// Append new items to the history file
try (BufferedWriter writer = Files.newBufferedWriter(path.toAbsolutePath(),
StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
try (BufferedWriter writer = Files.newBufferedWriter(
path.toAbsolutePath(),
StandardOpenOption.WRITE,
StandardOpenOption.APPEND,
StandardOpenOption.CREATE)) {
for (Entry entry : items.subList(from, items.size())) {
if (isPersistable(entry)) {
writer.append(format(entry));
@ -248,18 +247,23 @@ public class DefaultHistory implements History {
Log.trace("Trimming history path: ", path);
// Load all history entries
LinkedList<Entry> allItems = new LinkedList<>();
try (BufferedReader reader = Files.newBufferedReader(path)) {
reader.lines().forEach(l -> {
int idx = l.indexOf(':');
Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx)));
String line = unescape(l.substring(idx + 1));
allItems.add(createEntry(allItems.size(), time, line));
try (BufferedReader historyFileReader = Files.newBufferedReader(path)) {
historyFileReader.lines().forEach(l -> {
if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
int idx = l.indexOf(':');
Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx)));
String line = unescape(l.substring(idx + 1));
allItems.add(createEntry(allItems.size(), time, line));
} else {
allItems.add(createEntry(allItems.size(), Instant.now(), unescape(l)));
}
});
}
// Remove duplicates
List<Entry> trimmedItems = doTrimHistory(allItems, max);
// Write history
Path temp = Files.createTempFile(path.toAbsolutePath().getParent(), path.getFileName().toString(), ".tmp");
Path temp = Files.createTempFile(
path.toAbsolutePath().getParent(), path.getFileName().toString(), ".tmp");
try (BufferedWriter writer = Files.newBufferedWriter(temp, StandardOpenOption.WRITE)) {
for (Entry entry : trimmedItems) {
writer.append(format(entry));
@ -351,7 +355,7 @@ public class DefaultHistory implements History {
public String get(final int index) {
int idx = index - offset;
if (idx >= items.size() || idx < 0) {
throw new IllegalArgumentException("IndexOutOfBounds: Index:" + idx +", Size:" + items.size());
throw new IllegalArgumentException("IndexOutOfBounds: Index:" + idx + ", Size:" + items.size());
}
return items.get(idx).line();
}
@ -382,8 +386,7 @@ public class DefaultHistory implements History {
if (isSet(reader, LineReader.Option.HISTORY_INCREMENTAL)) {
try {
save();
}
catch (IOException e) {
} catch (IOException e) {
Log.warn("Failed to save history", e);
}
}
@ -417,7 +420,7 @@ public class DefaultHistory implements History {
protected void internalAdd(Instant time, String line, boolean checkDuplicates) {
Entry entry = new EntryImpl(offset + items.size(), time, line);
if (checkDuplicates) {
for (Entry e: items) {
for (Entry e : items) {
if (e.line().trim().equals(line.trim())) {
return;
}
@ -430,7 +433,7 @@ public class DefaultHistory implements History {
private void maybeResize() {
while (size() > getInt(reader, LineReader.HISTORY_SIZE, DEFAULT_HISTORY_SIZE)) {
items.removeFirst();
for (HistoryFileData hfd: historyFiles.values()) {
for (HistoryFileData hfd : historyFiles.values()) {
hfd.decLastLoaded();
}
offset++;
@ -633,8 +636,7 @@ public class DefaultHistory implements History {
private int lastLoaded = 0;
private int entriesInFile = 0;
public HistoryFileData() {
}
public HistoryFileData() {}
public HistoryFileData(int lastLoaded, int entriesInFile) {
this.lastLoaded = lastLoaded;
@ -667,8 +669,5 @@ public class DefaultHistory implements History {
public void incEntriesInFile(int amount) {
entriesInFile = entriesInFile + amount;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -43,63 +43,65 @@ public class Attributes {
* 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 */
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 */
INORMEOL /* normalize end-of-line */
}
/*
* 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 */
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 */
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 */
}
/*
@ -110,23 +112,23 @@ public class Attributes {
* 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 */
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);
@ -135,9 +137,9 @@ public class Attributes {
final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class);
final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class);
public Attributes() {
}
public Attributes() {}
@SuppressWarnings("this-escape")
public Attributes(Attributes attr) {
copy(attr);
}
@ -310,13 +312,12 @@ public class Attributes {
@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) +
"]";
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) {
@ -345,5 +346,4 @@ public class Attributes {
private <T extends Enum<T>> String append(EnumSet<T> set, Function<T, String> toString) {
return set.stream().map(toString).collect(Collectors.joining(" "));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -71,12 +71,11 @@ public class MouseEvent {
@Override
public String toString() {
return "MouseEvent[" +
"type=" + type +
", button=" + button +
", modifiers=" + modifiers +
", x=" + x +
", y=" + y +
']';
return "MouseEvent[" + "type="
+ type + ", button="
+ button + ", modifiers="
+ modifiers + ", x="
+ x + ", y="
+ y + ']';
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -13,9 +13,9 @@ public class Size {
private int rows;
private int cols;
public Size() {
}
public Size() {}
@SuppressWarnings("this-escape")
public Size(int columns, int rows) {
this();
setColumns(columns);
@ -50,7 +50,7 @@ public class Size {
* @return the cursor position
*/
public int cursorPos(int row, int col) {
return row * (cols+1) + col;
return row * (cols + 1) + col;
}
public void copy(Size size) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -34,6 +34,7 @@ public interface Terminal extends Closeable, Flushable {
* Type used for dumb terminals.
*/
String TYPE_DUMB = "dumb";
String TYPE_DUMB_COLOR = "dumb-color";
String getName();
@ -42,6 +43,9 @@ public interface Terminal extends Closeable, Flushable {
// Signal support
//
/**
* Types of signals.
*/
enum Signal {
INT,
QUIT,
@ -51,16 +55,55 @@ public interface Terminal extends Closeable, Flushable {
WINCH
}
/**
* The SignalHandler defines the interface used to trap signals and perform specific behaviors.
* @see Terminal.Signal
* @see Terminal#handle(Signal, SignalHandler)
*/
interface SignalHandler {
/**
* The {@code SIG_DFL} value can be used to specify that the JVM default behavior
* should be used to handle this signal.
*/
SignalHandler SIG_DFL = NativeSignalHandler.SIG_DFL;
/**
* The {@code SIG_IGN} value can be used to ignore this signal and not perform
* any special processing.
*/
SignalHandler SIG_IGN = NativeSignalHandler.SIG_IGN;
/**
* Handle the signal.
* @param signal the signal
*/
void handle(Signal signal);
}
/**
* Registers a handler for the given {@link Signal}.
* <p>
* Note that the JVM does not easily allow catching the {@link Signal#QUIT} signal, which causes a thread dump
* to be displayed. This signal is mainly used when connecting through an SSH socket to a virtual terminal.
*
* @param signal the signal to register a handler for
* @param handler the handler
* @return the previous signal handler
*/
SignalHandler handle(Signal signal, SignalHandler handler);
/**
* Raise the specific signal.
* This is not method usually called by non system terminals.
* When accessing a terminal through a SSH or Telnet connection, signals may be
* conveyed by the protocol and thus need to be raised when reaching the terminal code.
* The terminals do that automatically when the terminal input stream has a character
* mapped to {@link Attributes.ControlChar#VINTR}, {@link Attributes.ControlChar#VQUIT},
* or {@link Attributes.ControlChar#VSUSP}.
*
* @param signal the signal to raise
*/
void raise(Signal signal);
//
@ -180,8 +223,21 @@ public interface Terminal extends Closeable, Flushable {
boolean echo(boolean echo);
/**
* Returns the terminal attributes.
* The returned object can be safely modified
* further used in a call to {@link #setAttributes(Attributes)}.
*
* @return the terminal attributes.
*/
Attributes getAttributes();
/**
* Set the terminal attributes.
* The terminal will perform a copy of the given attributes.
*
* @param attr the new attributes
*/
void setAttributes(Attributes attr);
/**
@ -334,5 +390,4 @@ public interface Terminal extends Closeable, Flushable {
* Color support
*/
ColorPalette getPalette();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -8,9 +8,6 @@
*/
package jdk.internal.org.jline.terminal;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -19,11 +16,16 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -31,8 +33,10 @@ import java.util.stream.Stream;
import jdk.internal.org.jline.terminal.impl.AbstractPosixTerminal;
import jdk.internal.org.jline.terminal.impl.AbstractTerminal;
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
import jdk.internal.org.jline.terminal.impl.DumbTerminal;
import jdk.internal.org.jline.terminal.impl.DumbTerminalProvider;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalExt;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.Log;
import jdk.internal.org.jline.utils.OSUtils;
@ -49,16 +53,30 @@ public final class TerminalBuilder {
public static final String PROP_ENCODING = "org.jline.terminal.encoding";
public static final String PROP_CODEPAGE = "org.jline.terminal.codepage";
public static final String PROP_TYPE = "org.jline.terminal.type";
public static final String PROP_JNA = "org.jline.terminal.jna";
public static final String PROP_JANSI = "org.jline.terminal.jansi";
public static final String PROP_EXEC = "org.jline.terminal.exec";
public static final String PROP_DUMB = "org.jline.terminal.dumb";
public static final String PROP_PROVIDER = "org.jline.terminal.provider";
public static final String PROP_PROVIDERS = "org.jline.terminal.providers";
public static final String PROP_PROVIDER_FFM = "ffm";
public static final String PROP_PROVIDER_JNI = "jni";
public static final String PROP_PROVIDER_JANSI = "jansi";
public static final String PROP_PROVIDER_JNA = "jna";
public static final String PROP_PROVIDER_EXEC = "exec";
public static final String PROP_PROVIDER_DUMB = "dumb";
public static final String PROP_PROVIDERS_DEFAULT = String.join(
",", PROP_PROVIDER_FFM, PROP_PROVIDER_JNI, PROP_PROVIDER_JANSI, PROP_PROVIDER_JNA, PROP_PROVIDER_EXEC);
public static final String PROP_FFM = "org.jline.terminal." + PROP_PROVIDER_FFM;
public static final String PROP_JNI = "org.jline.terminal." + PROP_PROVIDER_JNI;
public static final String PROP_JANSI = "org.jline.terminal." + PROP_PROVIDER_JANSI;
public static final String PROP_JNA = "org.jline.terminal." + PROP_PROVIDER_JNA;
public static final String PROP_EXEC = "org.jline.terminal." + PROP_PROVIDER_EXEC;
public static final String PROP_DUMB = "org.jline.terminal." + PROP_PROVIDER_DUMB;
public static final String PROP_DUMB_COLOR = "org.jline.terminal.dumb.color";
public static final String PROP_OUTPUT = "org.jline.terminal.output";
public static final String PROP_OUTPUT_OUT = "out";
public static final String PROP_OUTPUT_ERR = "err";
public static final String PROP_OUTPUT_OUT_ERR = "out-err";
public static final String PROP_OUTPUT_ERR_OUT = "err-out";
public static final String PROP_OUTPUT_FORCED_OUT = "forced-out";
public static final String PROP_OUTPUT_FORCED_ERR = "forced-err";
//
// Other system properties controlling various jline parts
@ -68,6 +86,32 @@ public final class TerminalBuilder {
public static final String PROP_COLOR_DISTANCE = "org.jline.utils.colorDistance";
public static final String PROP_DISABLE_ALTERNATE_CHARSET = "org.jline.utils.disableAlternateCharset";
//
// System properties controlling how FileDescriptor are create.
// The value can be a comma separated list of defined mechanisms.
//
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE = "org.jline.terminal.pty.fileDescriptorCreationMode";
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE = "native";
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION = "reflection";
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT =
String.join(",", PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION, PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE);
//
// System properties controlling how RedirectPipe are created.
// The value can be a comma separated list of defined mechanisms.
//
public static final String PROP_REDIRECT_PIPE_CREATION_MODE = "org.jline.terminal.exec.redirectPipeCreationMode";
public static final String PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE = "native";
public static final String PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION = "reflection";
public static final String PROP_REDIRECT_PIPE_CREATION_MODE_DEFAULT =
String.join(",", PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION, PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE);
public static final Set<String> DEPRECATED_PROVIDERS =
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(PROP_PROVIDER_JNA, PROP_PROVIDER_JANSI)));
public static final String PROP_DISABLE_DEPRECATED_PROVIDER_WARNING =
"org.jline.terminal.disableDeprecatedProviderWarning";
//
// Terminal output control
//
@ -75,7 +119,9 @@ public final class TerminalBuilder {
SysOut,
SysErr,
SysOutOrSysErr,
SysErrOrSysOut
SysErrOrSysOut,
ForcedSysOut,
ForcedSysErr
}
/**
@ -115,20 +161,23 @@ public final class TerminalBuilder {
private int codepage;
private Boolean system;
private SystemOutput systemOutput;
private String provider;
private String providers;
private Boolean jna;
private Boolean jansi;
private Boolean jni;
private Boolean exec;
private Boolean ffm;
private Boolean dumb;
private Boolean color;
private Attributes attributes;
private Size size;
private boolean nativeSignals = false;
private boolean nativeSignals = true;
private Function<InputStream, InputStream> inputStreamWrapper = in -> in;
private Terminal.SignalHandler signalHandler = Terminal.SignalHandler.SIG_DFL;
private boolean paused = false;
private TerminalBuilder() {
}
private TerminalBuilder() {}
public TerminalBuilder name(String name) {
this.name = name;
@ -160,6 +209,16 @@ public final class TerminalBuilder {
return this;
}
public TerminalBuilder provider(String provider) {
this.provider = provider;
return this;
}
public TerminalBuilder providers(String providers) {
this.providers = providers;
return this;
}
public TerminalBuilder jna(boolean jna) {
this.jna = jna;
return this;
@ -170,11 +229,21 @@ public final class TerminalBuilder {
return this;
}
public TerminalBuilder jni(boolean jni) {
this.jni = jni;
return this;
}
public TerminalBuilder exec(boolean exec) {
this.exec = exec;
return this;
}
public TerminalBuilder ffm(boolean ffm) {
this.ffm = ffm;
return this;
}
public TerminalBuilder dumb(boolean dumb) {
this.dumb = dumb;
return this;
@ -280,6 +349,12 @@ public final class TerminalBuilder {
return this;
}
/**
* Determines the default value for signal handlers.
* All signals will be mapped to the given handler.
* @param signalHandler the default signal handler
* @return The builder
*/
public TerminalBuilder signalHandler(Terminal.SignalHandler signalHandler) {
this.signalHandler = signalHandler;
return this;
@ -305,6 +380,11 @@ public final class TerminalBuilder {
return this;
}
/**
* Builds the terminal.
* @return the newly created terminal, never {@code null}
* @throws IOException if an error occurs
*/
public Terminal build() throws IOException {
Terminal override = TERMINAL_OVERRIDE.get();
Terminal terminal = override != null ? override : doBuild();
@ -313,7 +393,8 @@ public final class TerminalBuilder {
}
Log.debug(() -> "Using terminal " + terminal.getClass().getSimpleName());
if (terminal instanceof AbstractPosixTerminal) {
Log.debug(() -> "Using pty " + ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName());
Log.debug(() -> "Using pty "
+ ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName());
}
return terminal;
}
@ -323,6 +404,242 @@ public final class TerminalBuilder {
if (name == null) {
name = "JLine terminal";
}
Charset encoding = computeEncoding();
String type = computeType();
String provider = this.provider;
if (provider == null) {
provider = System.getProperty(PROP_PROVIDER, null);
}
boolean forceDumb =
(DumbTerminal.TYPE_DUMB.equals(type) || type != null && type.startsWith(DumbTerminal.TYPE_DUMB_COLOR))
|| (provider != null && provider.equals(PROP_PROVIDER_DUMB));
Boolean dumb = this.dumb;
if (dumb == null) {
dumb = getBoolean(PROP_DUMB, null);
}
IllegalStateException exception = new IllegalStateException("Unable to create a terminal");
List<TerminalProvider> providers = getProviders(provider, exception);
Terminal terminal = null;
if ((system != null && system) || (system == null && in == null && out == null)) {
if (system != null
&& ((in != null && !in.equals(System.in))
|| (out != null && !out.equals(System.out) && !out.equals(System.err)))) {
throw new IllegalArgumentException("Cannot create a system terminal using non System streams");
}
if (attributes != null || size != null) {
Log.warn("Attributes and size fields are ignored when creating a system terminal");
}
SystemOutput systemOutput = computeSystemOutput();
Map<SystemStream, Boolean> system = Stream.of(SystemStream.values())
.collect(Collectors.toMap(
stream -> stream, stream -> providers.stream().anyMatch(p -> p.isSystemStream(stream))));
SystemStream systemStream = select(system, systemOutput);
if (!forceDumb && system.get(SystemStream.Input) && systemStream != null) {
if (attributes != null || size != null) {
Log.warn("Attributes and size fields are ignored when creating a system terminal");
}
boolean ansiPassThrough = OSUtils.IS_CONEMU;
// Cygwin defaults to XTERM, but actually supports 256 colors,
// so if the value comes from the environment, change it to xterm-256color
if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM)
&& "xterm".equals(type)
&& this.type == null
&& System.getProperty(PROP_TYPE) == null) {
type = "xterm-256color";
}
for (TerminalProvider prov : providers) {
if (terminal == null) {
try {
terminal = prov.sysTerminal(
name,
type,
ansiPassThrough,
encoding,
nativeSignals,
signalHandler,
paused,
systemStream,
inputStreamWrapper);
} catch (Throwable t) {
Log.debug("Error creating " + prov.name() + " based terminal: ", t.getMessage(), t);
exception.addSuppressed(t);
}
}
}
if (terminal == null && OSUtils.IS_WINDOWS && providers.isEmpty() && (dumb == null || !dumb)) {
throw new IllegalStateException(
"Unable to create a system terminal. On Windows, either JLine's native libraries, JNA "
+ "or Jansi library is required. Make sure to add one of those in the classpath.",
exception);
}
}
if (terminal instanceof AbstractTerminal) {
AbstractTerminal t = (AbstractTerminal) terminal;
if (SYSTEM_TERMINAL.compareAndSet(null, t)) {
t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null));
} else {
exception.addSuppressed(new IllegalStateException("A system terminal is already running. "
+ "Make sure to use the created system Terminal on the LineReaderBuilder if you're using one "
+ "or that previously created system Terminals have been correctly closed."));
terminal.close();
terminal = null;
}
}
if (terminal == null && (forceDumb || dumb == null || dumb)) {
if (!forceDumb && dumb == null) {
if (Log.isDebugEnabled()) {
Log.warn("input is tty: " + system.get(SystemStream.Input));
Log.warn("output is tty: " + system.get(SystemStream.Output));
Log.warn("error is tty: " + system.get(SystemStream.Error));
Log.warn("Creating a dumb terminal", exception);
} else {
Log.warn(
"Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)");
}
}
type = getDumbTerminalType(dumb, systemStream);
terminal = new DumbTerminalProvider()
.sysTerminal(name, type, false, encoding, nativeSignals, signalHandler, paused, systemStream, inputStreamWrapper);
if (OSUtils.IS_WINDOWS) {
Attributes attr = terminal.getAttributes();
attr.setInputFlag(Attributes.InputFlag.IGNCR, true);
terminal.setAttributes(attr);
}
}
} else {
for (TerminalProvider prov : providers) {
if (terminal == null) {
try {
terminal = prov.newTerminal(
name, type, in, out, encoding, signalHandler, paused, attributes, size);
} catch (Throwable t) {
Log.debug("Error creating " + prov.name() + " based terminal: ", t.getMessage(), t);
exception.addSuppressed(t);
}
}
}
}
if (terminal == null) {
throw exception;
}
if (terminal instanceof TerminalExt) {
TerminalExt te = (TerminalExt) terminal;
if (DEPRECATED_PROVIDERS.contains(te.getProvider().name())
&& !getBoolean(PROP_DISABLE_DEPRECATED_PROVIDER_WARNING, false)) {
Log.warn("The terminal provider " + te.getProvider().name()
+ " has been deprecated, check your configuration. This warning can be disabled by setting the system property "
+ PROP_DISABLE_DEPRECATED_PROVIDER_WARNING + " to true.");
}
}
return terminal;
}
private String getDumbTerminalType(Boolean dumb, SystemStream systemStream) {
// forced colored dumb terminal
Boolean color = this.color;
if (color == null) {
color = getBoolean(PROP_DUMB_COLOR, null);
}
if (dumb == null) {
// detect emacs using the env variable
if (color == null) {
String emacs = System.getenv("INSIDE_EMACS");
if (emacs != null && emacs.contains("comint")) {
color = true;
}
}
// detect Intellij Idea
if (color == null) {
// using the env variable on windows
String ideHome = System.getenv("IDE_HOME");
if (ideHome != null) {
color = true;
} else {
// using the parent process command on unix/mac
String command = getParentProcessCommand();
if (command != null && command.endsWith("/idea")) {
color = true;
}
}
}
if (color == null) {
color = systemStream != null && System.getenv("TERM") != null;
}
} else {
if (color == null) {
color = false;
}
}
return color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB;
}
public SystemOutput computeSystemOutput() {
SystemOutput systemOutput = null;
if (out != null) {
if (out.equals(System.out)) {
systemOutput = SystemOutput.SysOut;
} else if (out.equals(System.err)) {
systemOutput = SystemOutput.SysErr;
}
}
if (systemOutput == null) {
systemOutput = this.systemOutput;
}
if (systemOutput == null) {
String str = System.getProperty(PROP_OUTPUT);
if (str != null) {
switch (str.trim().toLowerCase(Locale.ROOT)) {
case PROP_OUTPUT_OUT:
systemOutput = SystemOutput.SysOut;
break;
case PROP_OUTPUT_ERR:
systemOutput = SystemOutput.SysErr;
break;
case PROP_OUTPUT_OUT_ERR:
systemOutput = SystemOutput.SysOutOrSysErr;
break;
case PROP_OUTPUT_ERR_OUT:
systemOutput = SystemOutput.SysErrOrSysOut;
break;
case PROP_OUTPUT_FORCED_OUT:
systemOutput = SystemOutput.ForcedSysOut;
break;
case PROP_OUTPUT_FORCED_ERR:
systemOutput = SystemOutput.ForcedSysErr;
break;
default:
Log.debug("Unsupported value for " + PROP_OUTPUT + ": " + str + ". Supported values are: "
+ String.join(
", ",
PROP_OUTPUT_OUT,
PROP_OUTPUT_ERR,
PROP_OUTPUT_OUT_ERR,
PROP_OUTPUT_ERR_OUT)
+ ".");
}
}
}
if (systemOutput == null) {
systemOutput = SystemOutput.SysOutOrSysErr;
}
return systemOutput;
}
public String computeType() {
String type = this.type;
if (type == null) {
type = System.getProperty(PROP_TYPE);
}
if (type == null) {
type = System.getenv("TERM");
}
return type;
}
public Charset computeEncoding() {
Charset encoding = this.encoding;
if (encoding == null) {
String charsetName = System.getProperty(PROP_ENCODING);
@ -344,206 +661,84 @@ public final class TerminalBuilder {
encoding = StandardCharsets.UTF_8;
}
}
String type = this.type;
if (type == null) {
type = System.getProperty(PROP_TYPE);
}
if (type == null) {
type = System.getenv("TERM");
}
Boolean jna = this.jna;
if (jna == null) {
jna = getBoolean(PROP_JNA, true);
}
Boolean jansi = this.jansi;
if (jansi == null) {
jansi = getBoolean(PROP_JANSI, true);
}
Boolean exec = this.exec;
if (exec == null) {
exec = getBoolean(PROP_EXEC, true);
}
Boolean dumb = this.dumb;
if (dumb == null) {
dumb = getBoolean(PROP_DUMB, null);
}
IllegalStateException exception = new IllegalStateException("Unable to create a terminal");
List<TerminalProvider> providers = new ArrayList<>();
if (jna) {
try {
TerminalProvider provider = TerminalProvider.load("jna");
providers.add(provider);
} catch (Throwable t) {
Log.debug("Unable to load JNA support: ", t);
exception.addSuppressed(t);
}
}
if (jansi) {
try {
TerminalProvider provider = TerminalProvider.load("jansi");
providers.add(provider);
} catch (Throwable t) {
Log.debug("Unable to load JANSI support: ", t);
exception.addSuppressed(t);
}
}
if (exec)
{
try {
TerminalProvider provider = TerminalProvider.load("exec");
providers.add(provider);
} catch (Throwable t) {
Log.debug("Unable to load EXEC support: ", t);
exception.addSuppressed(t);
}
}
Terminal terminal = null;
if ((system != null && system) || (system == null && in == null && out == null)) {
if (system != null && ((in != null && !in.equals(System.in)) ||
(out != null && !out.equals(System.out) && !out.equals(System.err)))) {
throw new IllegalArgumentException("Cannot create a system terminal using non System streams");
}
if (attributes != null || size != null) {
Log.warn("Attributes and size fields are ignored when creating a system terminal");
}
if (out != null) {
if (out.equals(System.out)) {
systemOutput = SystemOutput.SysOut;
} else if (out.equals(System.err)) {
systemOutput = SystemOutput.SysErr;
}
}
if (systemOutput == null) {
String str = System.getProperty(PROP_OUTPUT);
if (str != null) {
switch (str.trim().toLowerCase(Locale.ROOT)) {
case PROP_OUTPUT_OUT: systemOutput = SystemOutput.SysOut; break;
case PROP_OUTPUT_ERR: systemOutput = SystemOutput.SysErr; break;
case PROP_OUTPUT_OUT_ERR: systemOutput = SystemOutput.SysOutOrSysErr; break;
case PROP_OUTPUT_ERR_OUT: systemOutput = SystemOutput.SysErrOrSysOut; break;
default:
Log.debug("Unsupported value for " + PROP_OUTPUT + ": " + str + ". Supported values are: "
+ String.join(", ", PROP_OUTPUT_OUT, PROP_OUTPUT_ERR, PROP_OUTPUT_OUT_ERR,PROP_OUTPUT_ERR_OUT)
+ ".");
}
}
}
if (systemOutput == null) {
systemOutput = SystemOutput.SysOutOrSysErr;
}
Map<TerminalProvider.Stream, Boolean> system = Stream.of(TerminalProvider.Stream.values())
.collect(Collectors.toMap(stream -> stream, stream -> providers.stream().anyMatch(p -> p.isSystemStream(stream))));
TerminalProvider.Stream console = select(system, systemOutput);
if (system.get(TerminalProvider.Stream.Input) && console != null) {
if (attributes != null || size != null) {
Log.warn("Attributes and size fields are ignored when creating a system terminal");
}
boolean ansiPassThrough = OSUtils.IS_CONEMU;
// Cygwin defaults to XTERM, but actually supports 256 colors,
// so if the value comes from the environment, change it to xterm-256color
if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) && "xterm".equals(type)
&& this.type == null && System.getProperty(PROP_TYPE) == null) {
type = "xterm-256color";
}
for ( TerminalProvider provider : providers) {
if (terminal == null) {
try {
terminal = provider.sysTerminal(name, type, ansiPassThrough, encoding,
nativeSignals, signalHandler, paused, console, inputStreamWrapper);
} catch (Throwable t) {
Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t);
exception.addSuppressed(t);
}
}
}
if (terminal == null && OSUtils.IS_WINDOWS && !jna && !jansi && (dumb == null || !dumb)) {
throw new IllegalStateException("Unable to create a system terminal. On windows, either "
+ "JNA or JANSI library is required. Make sure to add one of those in the classpath.");
}
}
if (terminal instanceof AbstractTerminal) {
AbstractTerminal t = (AbstractTerminal) terminal;
if (SYSTEM_TERMINAL.compareAndSet(null, t)) {
t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null));
} else {
exception.addSuppressed(new IllegalStateException("A system terminal is already running. " +
"Make sure to use the created system Terminal on the LineReaderBuilder if you're using one " +
"or that previously created system Terminals have been correctly closed."));
terminal.close();
terminal = null;
}
}
if (terminal == null && (dumb == null || dumb)) {
// forced colored dumb terminal
Boolean color = this.color;
if (color == null) {
color = getBoolean(PROP_DUMB_COLOR, false);
// detect emacs using the env variable
if (!color) {
String emacs = System.getenv("INSIDE_EMACS");
color = emacs != null && emacs.contains("comint");
}
// detect Intellij Idea
if (!color) {
String command = getParentProcessCommand();
color = command != null && command.contains("idea");
}
if (!color) {
color = system.get(TerminalProvider.Stream.Output) && System.getenv("TERM") != null;
}
if (!color && dumb == null) {
if (Log.isDebugEnabled()) {
Log.warn("input is tty: {}", system.get(TerminalProvider.Stream.Input));
Log.warn("output is tty: {}", system.get(TerminalProvider.Stream.Output));
Log.warn("error is tty: {}", system.get(TerminalProvider.Stream.Error));
Log.warn("Creating a dumb terminal", exception);
} else {
Log.warn("Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)");
}
}
}
terminal = new DumbTerminal(name, color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB,
new FileInputStream(FileDescriptor.in),
//JDK change: always write into stdout:
new FileOutputStream(FileDescriptor.out),
encoding, signalHandler);
}
} else {
for ( TerminalProvider provider : providers) {
if (terminal == null) {
try {
terminal = provider.newTerminal(name, type, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused, attributes, size);
} catch (Throwable t) {
Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t);
exception.addSuppressed(t);
}
}
}
}
if (terminal == null) {
throw exception;
}
return terminal;
return encoding;
}
private TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, SystemOutput systemOutput) {
/**
* Get the list of available terminal providers.
* This list is sorted according to the {@link #PROP_PROVIDERS} system property.
* @param provider if not {@code null}, only this provider will be checked
* @param exception if a provider throws an exception, it will be added to this exception as a suppressed exception
* @return a list of terminal providers
*/
public List<TerminalProvider> getProviders(String provider, IllegalStateException exception) {
List<TerminalProvider> providers = new ArrayList<>();
// Check ffm provider
checkProvider(provider, exception, providers, ffm, PROP_FFM, PROP_PROVIDER_FFM);
// Check jni provider
checkProvider(provider, exception, providers, jni, PROP_JNI, PROP_PROVIDER_JNI);
// Check jansi provider
checkProvider(provider, exception, providers, jansi, PROP_JANSI, PROP_PROVIDER_JANSI);
// Check jna provider
checkProvider(provider, exception, providers, jna, PROP_JNA, PROP_PROVIDER_JNA);
// Check exec provider
checkProvider(provider, exception, providers, exec, PROP_EXEC, PROP_PROVIDER_EXEC);
// Order providers
List<String> order = Arrays.asList(
(this.providers != null ? this.providers : System.getProperty(PROP_PROVIDERS, PROP_PROVIDERS_DEFAULT))
.split(","));
providers.sort(Comparator.comparing(l -> {
int idx = order.indexOf(l.name());
return idx >= 0 ? idx : Integer.MAX_VALUE;
}));
String names = providers.stream().map(TerminalProvider::name).collect(Collectors.joining(", "));
Log.debug("Available providers: " + names);
return providers;
}
private void checkProvider(
String provider,
IllegalStateException exception,
List<TerminalProvider> providers,
Boolean load,
String property,
String name) {
Boolean doLoad = provider != null ? (Boolean) name.equals(provider) : load;
if (doLoad == null) {
doLoad = getBoolean(property, true);
}
if (doLoad) {
try {
TerminalProvider prov = TerminalProvider.load(name);
prov.isSystemStream(SystemStream.Output);
providers.add(prov);
} catch (Throwable t) {
Log.debug("Unable to load " + name + " provider: ", t);
exception.addSuppressed(t);
}
}
}
private SystemStream select(Map<SystemStream, Boolean> system, SystemOutput systemOutput) {
switch (systemOutput) {
case SysOut:
return select(system, TerminalProvider.Stream.Output);
return select(system, SystemStream.Output);
case SysErr:
return select(system, TerminalProvider.Stream.Error);
return select(system, SystemStream.Error);
case SysOutOrSysErr:
return select(system, TerminalProvider.Stream.Output, TerminalProvider.Stream.Error);
return select(system, SystemStream.Output, SystemStream.Error);
case SysErrOrSysOut:
return select(system, TerminalProvider.Stream.Error, TerminalProvider.Stream.Output);
return select(system, SystemStream.Error, SystemStream.Output);
case ForcedSysOut:
return SystemStream.Output;
case ForcedSysErr:
return SystemStream.Error;
}
return null;
}
private static TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, TerminalProvider.Stream... streams) {
for (TerminalProvider.Stream s : streams) {
private static SystemStream select(Map<SystemStream, Boolean> system, SystemStream... streams) {
for (SystemStream s : streams) {
if (system.get(s)) {
return s;
}
@ -558,7 +753,9 @@ public final class TerminalBuilder {
Object parent = ((Optional<?>) phClass.getMethod("parent").invoke(current)).orElse(null);
Method infoMethod = phClass.getMethod("info");
Object info = infoMethod.invoke(parent);
Object command = ((Optional<?>) infoMethod.getReturnType().getMethod("command").invoke(info)).orElse(null);
Object command = ((Optional<?>)
infoMethod.getReturnType().getMethod("command").invoke(info))
.orElse(null);
return (String) command;
} catch (Throwable t) {
return null;
@ -583,7 +780,7 @@ public final class TerminalBuilder {
private static final int UTF8_CODE_PAGE = 65001;
private static Charset getCodepageCharset(int codepage) {
//http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
// http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
if (codepage == UTF8_CODE_PAGE) {
return StandardCharsets.UTF_8;
}
@ -630,5 +827,4 @@ public final class TerminalBuilder {
public static void setTerminalOverride(final Terminal terminal) {
TERMINAL_OVERRIDE.set(terminal);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -18,6 +18,8 @@ import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
public abstract class AbstractPosixTerminal extends AbstractTerminal {
@ -28,7 +30,8 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
this(name, type, pty, null, SignalHandler.SIG_DFL);
}
public AbstractPosixTerminal(String name, String type, Pty pty, Charset encoding, SignalHandler signalHandler) throws IOException {
public AbstractPosixTerminal(String name, String type, Pty pty, Charset encoding, SignalHandler signalHandler)
throws IOException {
super(name, type, encoding, signalHandler);
Objects.requireNonNull(pty);
this.pty = pty;
@ -82,4 +85,13 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
return CursorSupport.getCursorPosition(this, discarded);
}
@Override
public TerminalProvider getProvider() {
return getPty().getProvider();
}
@Override
public SystemStream getSystemStream() {
return getPty().getSystemStream();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019, the original author or authors.
* Copyright (c) 2002-2019, 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.
@ -8,20 +8,39 @@
*/
package jdk.internal.org.jline.terminal.impl;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.utils.NonBlockingInputStream;
import java.io.FileDescriptor;
import java.io.FilterInputStream;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.lang.reflect.Field;
//import jdk.internal.org.jline.nativ.JLineLibrary;
//import jdk.internal.org.jline.nativ.JLineNativeLoader;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.NonBlockingInputStream;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_NON_BLOCKING_READS;
public abstract class AbstractPty implements Pty {
protected final TerminalProvider provider;
protected final SystemStream systemStream;
private Attributes current;
private boolean skipNextLf;
public AbstractPty(TerminalProvider provider, SystemStream systemStream) {
this.provider = provider;
this.systemStream = systemStream;
}
@Override
public void setAttr(Attributes attr) throws IOException {
@ -32,10 +51,32 @@ public abstract class AbstractPty implements Pty {
@Override
public InputStream getSlaveInput() throws IOException {
InputStream si = doGetSlaveInput();
InputStream nsi = new FilterInputStream(si) {
@Override
public int read() throws IOException {
for (; ; ) {
int c = super.read();
if (current.getInputFlag(Attributes.InputFlag.INORMEOL)) {
if (c == '\r') {
skipNextLf = true;
c = '\n';
} else if (c == '\n') {
if (skipNextLf) {
skipNextLf = false;
continue;
}
} else {
skipNextLf = false;
}
}
return c;
}
}
};
if (Boolean.parseBoolean(System.getProperty(PROP_NON_BLOCKING_READS, "true"))) {
return new PtyInputStream(si);
return new PtyInputStream(nsi);
} else {
return si;
return nsi;
}
}
@ -49,6 +90,16 @@ public abstract class AbstractPty implements Pty {
}
}
@Override
public TerminalProvider getProvider() {
return provider;
}
@Override
public SystemStream getSystemStream() {
return systemStream;
}
class PtyInputStream extends NonBlockingInputStream {
final InputStream in;
int c = 0;
@ -102,4 +153,103 @@ public abstract class AbstractPty implements Pty {
}
}
private static FileDescriptorCreator fileDescriptorCreator;
protected static FileDescriptor newDescriptor(int fd) {
if (fileDescriptorCreator == null) {
String str =
System.getProperty(PROP_FILE_DESCRIPTOR_CREATION_MODE, PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT);
String[] modes = str.split(",");
IllegalStateException ise = new IllegalStateException("Unable to create FileDescriptor");
for (String mode : modes) {
try {
switch (mode) {
case PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE:
fileDescriptorCreator = null;//new NativeFileDescriptorCreator();
break;
case PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION:
fileDescriptorCreator = new ReflectionFileDescriptorCreator();
break;
}
} catch (Throwable t) {
// ignore
ise.addSuppressed(t);
}
if (fileDescriptorCreator != null) {
break;
}
}
if (fileDescriptorCreator == null) {
throw ise;
}
}
return fileDescriptorCreator.newDescriptor(fd);
}
interface FileDescriptorCreator {
FileDescriptor newDescriptor(int fd);
}
/*
* Class that could be used on OpenJDK 17. However, it requires the following JVM option
* --add-exports java.base/jdk.internal.access=ALL-UNNAMED
* so the benefit does not seem important enough to warrant the problems caused
* by access the jdk.internal.access package at compile time, which itself requires
* custom compiler options and a different maven module, or at least a different compile
* phase with a JDK 17 compiler.
* So, just keep the ReflectionFileDescriptorCreator for now.
*
static class Jdk17FileDescriptorCreator implements FileDescriptorCreator {
private final jdk.internal.access.JavaIOFileDescriptorAccess fdAccess;
Jdk17FileDescriptorCreator() {
fdAccess = jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess();
}
@Override
public FileDescriptor newDescriptor(int fd) {
FileDescriptor descriptor = new FileDescriptor();
fdAccess.set(descriptor, fd);
return descriptor;
}
}
*/
/**
* Reflection based file descriptor creator.
* This requires the following option
* --add-opens java.base/java.io=ALL-UNNAMED
*/
static class ReflectionFileDescriptorCreator implements FileDescriptorCreator {
private final Field fileDescriptorField;
ReflectionFileDescriptorCreator() throws Exception {
Field field = FileDescriptor.class.getDeclaredField("fd");
field.setAccessible(true);
fileDescriptorField = field;
}
@Override
public FileDescriptor newDescriptor(int fd) {
FileDescriptor descriptor = new FileDescriptor();
try {
fileDescriptorField.set(descriptor, fd);
} catch (IllegalAccessException e) {
// This should not happen as the field has been set accessible
throw new IllegalStateException(e);
}
return descriptor;
}
}
// static class NativeFileDescriptorCreator implements FileDescriptorCreator {
// NativeFileDescriptorCreator() {
// // Force load the library
// JLineNativeLoader.initialize();
// }
//
// @Override
// public FileDescriptor newDescriptor(int fd) {
// return JLineLibrary.newFileDescriptor(fd);
// }
// }
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -27,7 +27,7 @@ import jdk.internal.org.jline.terminal.Attributes.InputFlag;
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.MouseEvent;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.spi.TerminalExt;
import jdk.internal.org.jline.utils.ColorPalette;
import jdk.internal.org.jline.utils.Curses;
import jdk.internal.org.jline.utils.InfoCmp;
@ -35,7 +35,7 @@ import jdk.internal.org.jline.utils.InfoCmp.Capability;
import jdk.internal.org.jline.utils.Log;
import jdk.internal.org.jline.utils.Status;
public abstract class AbstractTerminal implements Terminal {
public abstract class AbstractTerminal implements TerminalExt {
protected final String name;
protected final String type;
@ -44,7 +44,7 @@ public abstract class AbstractTerminal implements Terminal {
protected final Set<Capability> bools = new HashSet<>();
protected final Map<Capability, Integer> ints = new HashMap<>();
protected final Map<Capability, String> strings = new HashMap<>();
protected final ColorPalette palette = new ColorPalette(this);
protected final ColorPalette palette;
protected Status status;
protected Runnable onClose;
@ -52,10 +52,13 @@ public abstract class AbstractTerminal implements Terminal {
this(name, type, null, SignalHandler.SIG_DFL);
}
public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler) throws IOException {
@SuppressWarnings("this-escape")
public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler)
throws IOException {
this.name = name;
this.type = type != null ? type : "ansi";
this.encoding = encoding != null ? encoding : System.out.charset();
this.palette = new ColorPalette(this);
for (Signal signal : Signal.values()) {
handlers.put(signal, signalHandler);
}
@ -85,12 +88,13 @@ public abstract class AbstractTerminal implements Terminal {
public void raise(Signal signal) {
Objects.requireNonNull(signal);
SignalHandler handler = handlers.get(signal);
if (handler != SignalHandler.SIG_DFL && handler != SignalHandler.SIG_IGN) {
if (handler == SignalHandler.SIG_DFL) {
if (status != null && signal == Signal.WINCH) {
status.resize();
}
} else if (handler != SignalHandler.SIG_IGN) {
handler.handle(signal);
}
if (status != null && signal == Signal.WINCH) {
status.resize();
}
}
public final void close() throws IOException {
@ -105,8 +109,7 @@ public abstract class AbstractTerminal implements Terminal {
protected void doClose() throws IOException {
if (status != null) {
status.update(null);
flush();
status.close();
}
}
@ -126,7 +129,7 @@ public abstract class AbstractTerminal implements Terminal {
if (cc != null) {
int vcc = getAttributes().getControlChar(cc);
if (vcc > 0 && vcc < 32) {
writer().write(new char[]{'^', (char) (vcc + '@')}, 0, 2);
writer().write(new char[] {'^', (char) (vcc + '@')}, 0, 2);
}
}
}
@ -217,8 +220,7 @@ public abstract class AbstractTerminal implements Terminal {
}
private MouseEvent lastMouseEvent = new MouseEvent(
MouseEvent.Type.Moved, MouseEvent.Button.NoButton,
EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
MouseEvent.Type.Moved, MouseEvent.Button.NoButton, EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
@Override
public boolean hasMouseSupport() {
@ -268,16 +270,13 @@ public abstract class AbstractTerminal implements Terminal {
}
@Override
public void pause() {
}
public void pause() {}
@Override
public void pause(boolean wait) throws InterruptedException {
}
public void pause(boolean wait) throws InterruptedException {}
@Override
public void resume() {
}
public void resume() {}
@Override
public boolean paused() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2017, the original author or authors.
* Copyright (c) 2002-2017, 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.
@ -29,11 +29,8 @@ public abstract class AbstractWindowsConsoleWriter extends Writer {
}
@Override
public void flush() {
}
public void flush() {}
@Override
public void close() {
}
public void close() {}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019, the original author or authors.
* Copyright (c) 2002-2023, 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.
@ -8,8 +8,20 @@
*/
package jdk.internal.org.jline.terminal.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.Curses;
import jdk.internal.org.jline.utils.InfoCmp;
import jdk.internal.org.jline.utils.Log;
@ -21,17 +33,6 @@ import jdk.internal.org.jline.utils.ShutdownHooks;
import jdk.internal.org.jline.utils.Signals;
import jdk.internal.org.jline.utils.WriterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* The AbstractWindowsTerminal is used as the base class for windows terminal.
* Due to windows limitations, mostly the missing support for ansi sequences,
@ -44,7 +45,7 @@ import java.util.function.Function;
* the writer() becomes the primary output, while the output() is bridged
* to the writer() using a WriterOutputStream wrapper.
*/
public abstract class AbstractWindowsTerminal extends AbstractTerminal {
public abstract class AbstractWindowsTerminal<Console> extends AbstractTerminal {
public static final String TYPE_WINDOWS = "windows";
public static final String TYPE_WINDOWS_256_COLOR = "windows-256color";
@ -56,12 +57,13 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
private static final int UTF8_CODE_PAGE = 65001;
protected static final int ENABLE_PROCESSED_INPUT = 0x0001;
protected static final int ENABLE_LINE_INPUT = 0x0002;
protected static final int ENABLE_ECHO_INPUT = 0x0004;
protected static final int ENABLE_WINDOW_INPUT = 0x0008;
protected static final int ENABLE_MOUSE_INPUT = 0x0010;
protected static final int ENABLE_INSERT_MODE = 0x0020;
protected static final int ENABLE_LINE_INPUT = 0x0002;
protected static final int ENABLE_ECHO_INPUT = 0x0004;
protected static final int ENABLE_WINDOW_INPUT = 0x0008;
protected static final int ENABLE_MOUSE_INPUT = 0x0010;
protected static final int ENABLE_INSERT_MODE = 0x0020;
protected static final int ENABLE_QUICK_EDIT_MODE = 0x0040;
protected static final int ENABLE_EXTENDED_FLAGS = 0x0080;
protected final Writer slaveInputPipe;
protected final InputStream input;
@ -71,7 +73,12 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
protected final ShutdownHooks.Task closer;
protected final Attributes attributes = new Attributes();
protected final int originalConsoleMode;
protected final Console inConsole;
protected final Console outConsole;
protected final int originalInConsoleMode;
protected final int originalOutConsoleMode;
private final TerminalProvider provider;
private final SystemStream systemStream;
protected final Object lock = new Object();
protected boolean paused = true;
@ -80,21 +87,42 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
protected MouseTracking tracking = MouseTracking.Off;
protected boolean focusTracking = false;
private volatile boolean closing;
protected boolean skipNextLf;
public AbstractWindowsTerminal(Writer writer, String name, String type, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
@SuppressWarnings("this-escape")
public AbstractWindowsTerminal(
TerminalProvider provider,
SystemStream systemStream,
Writer writer,
String name,
String type,
Charset encoding,
boolean nativeSignals,
SignalHandler signalHandler,
Console inConsole,
int inConsoleMode,
Console outConsole,
int outConsoleMode,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
super(name, type, encoding, signalHandler);
this.provider = provider;
this.systemStream = systemStream;
NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader();
this.slaveInputPipe = reader.getWriter();
this.input = inputStreamWrapper.apply(NonBlocking.nonBlockingStream(reader, encoding()));
this.reader = NonBlocking.nonBlocking(name, input, encoding());
this.writer = new PrintWriter(writer);
this.output = new WriterOutputStream(writer, encoding());
this.inConsole = inConsole;
this.outConsole = outConsole;
parseInfoCmp();
// Attributes
originalConsoleMode = getConsoleMode();
this.originalInConsoleMode = inConsoleMode;
this.originalOutConsoleMode = outConsoleMode;
attributes.setLocalFlag(Attributes.LocalFlag.ISIG, true);
attributes.setControlChar(Attributes.ControlChar.VINTR, ctrl('C'));
attributes.setControlChar(Attributes.ControlChar.VEOF, ctrl('D'));
attributes.setControlChar(Attributes.ControlChar.VEOF, ctrl('D'));
attributes.setControlChar(Attributes.ControlChar.VSUSP, ctrl('Z'));
// Handle signals
if (nativeSignals) {
@ -148,7 +176,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
}
public Attributes getAttributes() {
int mode = getConsoleMode();
int mode = getConsoleMode(inConsole);
if ((mode & ENABLE_ECHO_INPUT) != 0) {
attributes.setLocalFlag(Attributes.LocalFlag.ECHO, true);
}
@ -173,8 +201,11 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
}
if (tracking != MouseTracking.Off) {
mode |= ENABLE_MOUSE_INPUT;
// mouse events not send with quick edit mode
// to disable ENABLE_QUICK_EDIT_MODE just set extended flag
mode |= ENABLE_EXTENDED_FLAGS;
}
setConsoleMode(mode);
setConsoleMode(inConsole, mode);
}
protected int ctrl(char key) {
@ -197,23 +228,26 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
}
reader.close();
writer.close();
setConsoleMode(originalConsoleMode);
setConsoleMode(inConsole, originalInConsoleMode);
setConsoleMode(outConsole, originalOutConsoleMode);
}
static final int SHIFT_FLAG = 0x01;
static final int ALT_FLAG = 0x02;
static final int CTRL_FLAG = 0x04;
static final int ALT_FLAG = 0x02;
static final int CTRL_FLAG = 0x04;
static final int RIGHT_ALT_PRESSED = 0x0001;
static final int LEFT_ALT_PRESSED = 0x0002;
static final int RIGHT_CTRL_PRESSED = 0x0004;
static final int LEFT_CTRL_PRESSED = 0x0008;
static final int SHIFT_PRESSED = 0x0010;
static final int NUMLOCK_ON = 0x0020;
static final int SCROLLLOCK_ON = 0x0040;
static final int CAPSLOCK_ON = 0x0080;
static final int RIGHT_ALT_PRESSED = 0x0001;
static final int LEFT_ALT_PRESSED = 0x0002;
static final int RIGHT_CTRL_PRESSED = 0x0004;
static final int LEFT_CTRL_PRESSED = 0x0008;
static final int SHIFT_PRESSED = 0x0010;
static final int NUMLOCK_ON = 0x0020;
static final int SCROLLLOCK_ON = 0x0040;
static final int CAPSLOCK_ON = 0x0080;
protected void processKeyEvent(final boolean isKeyDown, final short virtualKeyCode, char ch, final int controlKeyState) throws IOException {
protected void processKeyEvent(
final boolean isKeyDown, final short virtualKeyCode, char ch, final int controlKeyState)
throws IOException {
final boolean isCtrl = (controlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) > 0;
final boolean isAlt = (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) > 0;
final boolean isShift = (controlKeyState & SHIFT_PRESSED) > 0;
@ -222,11 +256,13 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
// Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
// otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
if (ch != 0
&& (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED | SHIFT_PRESSED))
== (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
&& (controlKeyState
& (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
== (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
processInputChar(ch);
} else {
final String keySeq = getEscapeSequence(virtualKeyCode, (isCtrl ? CTRL_FLAG : 0) + (isAlt ? ALT_FLAG : 0) + (isShift ? SHIFT_FLAG : 0));
final String keySeq = getEscapeSequence(
virtualKeyCode, (isCtrl ? CTRL_FLAG : 0) + (isAlt ? ALT_FLAG : 0) + (isShift ? SHIFT_FLAG : 0));
if (keySeq != null) {
for (char c : keySeq.toCharArray()) {
processInputChar(c);
@ -240,7 +276,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
* 4). Ctrl + Space(0x20) : uchar=0x20
* 5). Ctrl + <Other key> : uchar=0
* 6). Ctrl + Alt + <Any key> : uchar=0
*/
*/
if (ch > 0) {
if (isAlt) {
processInputChar('\033');
@ -254,10 +290,10 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} else {
processInputChar(ch);
}
} else if (isCtrl) { //Handles the ctrl key events(uchar=0)
} else if (isCtrl) { // Handles the ctrl key events(uchar=0)
if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') {
ch = (char) (virtualKeyCode - 0x40);
} else if (virtualKeyCode == 191) { //?
} else if (virtualKeyCode == 191) { // ?
ch = 127;
}
if (ch > 0) {
@ -275,7 +311,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
else {
// support ALT+NumPad input method
if (virtualKeyCode == 0x12 /*VK_MENU ALT key*/ && ch > 0) {
processInputChar(ch); // no such combination in Windows
processInputChar(ch); // no such combination in Windows
}
}
}
@ -468,7 +504,19 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
raise(Signal.INFO);
}
}
if (c == '\r') {
if (attributes.getInputFlag(Attributes.InputFlag.INORMEOL)) {
if (c == '\r') {
skipNextLf = true;
c = '\n';
} else if (c == '\n') {
if (skipNextLf) {
skipNextLf = false;
return;
}
} else {
skipNextLf = false;
}
} else if (c == '\r') {
if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
return;
}
@ -478,10 +526,10 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} else if (c == '\n' && attributes.getInputFlag(Attributes.InputFlag.INLCR)) {
c = '\r';
}
// if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
// processOutputByte(c);
// masterOutput.flush();
// }
// if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
// processOutputByte(c);
// masterOutput.flush();
// }
slaveInputPipe.write(c);
}
@ -492,9 +540,9 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
return true;
}
protected abstract int getConsoleMode();
protected abstract int getConsoleMode(Console console);
protected abstract void setConsoleMode(int mode);
protected abstract void setConsoleMode(Console console, int mode);
/**
* Read a single input event from the input buffer and process it.
@ -504,5 +552,13 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
*/
protected abstract boolean processConsoleInput() throws IOException;
}
@Override
public TerminalProvider getProvider() {
return provider;
}
@Override
public SystemStream getSystemStream() {
return systemStream;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -8,17 +8,17 @@
*/
package jdk.internal.org.jline.terminal.impl;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.utils.Curses;
import jdk.internal.org.jline.utils.InfoCmp;
import java.io.IOError;
import java.io.IOException;
import java.util.function.IntConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.utils.Curses;
import jdk.internal.org.jline.utils.InfoCmp;
public class CursorSupport {
public static Cursor getCursorPosition(Terminal terminal, IntConsumer discarded) {
@ -105,5 +105,4 @@ public class CursorSupport {
throw new IOError(e);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, the original author or authors.
* Copyright (c) 2022, 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.
@ -17,6 +17,7 @@ import java.util.concurrent.TimeUnit;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.OSUtils;
@ -26,7 +27,7 @@ public class Diag {
diag(System.out);
}
static void diag(PrintStream out) {
public static void diag(PrintStream out) {
out.println("System properties");
out.println("=================");
out.println("os.name = " + System.getProperty("os.name"));
@ -50,6 +51,17 @@ public class Diag {
out.println("IS_OSX = " + OSUtils.IS_OSX);
out.println();
// FFM
out.println("FFM Support");
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("ffm");
testProvider(out, provider);
} catch (Throwable t) {
out.println("FFM support not available: " + t);
}
out.println();
out.println("JnaSupport");
out.println("=================");
try {
@ -60,13 +72,23 @@ public class Diag {
}
out.println();
out.println("JansiSupport");
out.println("Jansi2Support");
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("jansi");
testProvider(out, provider);
} catch (Throwable t) {
out.println("Jansi support not available: " + t);
out.println("Jansi 2 support not available: " + t);
}
out.println();
out.println("JniSupport");
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("jni");
testProvider(out, provider);
} catch (Throwable t) {
out.println("JNI support not available: " + t);
}
out.println();
@ -83,32 +105,45 @@ public class Diag {
private static void testProvider(PrintStream out, TerminalProvider provider) {
try {
out.println("StdIn stream = " + provider.isSystemStream(TerminalProvider.Stream.Input));
out.println("StdOut stream = " + provider.isSystemStream(TerminalProvider.Stream.Output));
out.println("StdErr stream = " + provider.isSystemStream(TerminalProvider.Stream.Error));
out.println("StdIn stream = " + provider.isSystemStream(SystemStream.Input));
out.println("StdOut stream = " + provider.isSystemStream(SystemStream.Output));
out.println("StdErr stream = " + provider.isSystemStream(SystemStream.Error));
} catch (Throwable t2) {
out.println("Unable to check stream: " + t2);
}
try {
out.println("StdIn stream name = " + provider.systemStreamName(TerminalProvider.Stream.Input));
out.println("StdOut stream name = " + provider.systemStreamName(TerminalProvider.Stream.Output));
out.println("StdErr stream name = " + provider.systemStreamName(TerminalProvider.Stream.Error));
out.println("StdIn stream name = " + provider.systemStreamName(SystemStream.Input));
out.println("StdOut stream name = " + provider.systemStreamName(SystemStream.Output));
out.println("StdErr stream name = " + provider.systemStreamName(SystemStream.Error));
} catch (Throwable t2) {
out.println("Unable to check stream names: " + t2);
}
try (Terminal terminal = provider.sysTerminal("diag", "xterm", false, StandardCharsets.UTF_8,
false, Terminal.SignalHandler.SIG_DFL, false, TerminalProvider.Stream.Output, input -> input) ) {
try (Terminal terminal = provider.sysTerminal(
"diag",
"xterm",
false,
StandardCharsets.UTF_8,
false,
Terminal.SignalHandler.SIG_DFL,
false,
SystemStream.Output,
input -> input)) {
if (terminal != null) {
Attributes attr = terminal.enterRawMode();
try {
out.println("Terminal size: " + terminal.getSize());
ForkJoinTask<Integer> t = new ForkJoinPool(1).submit(() -> terminal.reader().read(1) );
ForkJoinTask<Integer> t =
new ForkJoinPool(1).submit(() -> terminal.reader().read(1));
int r = t.get(1000, TimeUnit.MILLISECONDS);
StringBuilder sb = new StringBuilder();
sb.append("The terminal seems to work: ");
sb.append("terminal ").append(terminal.getClass().getName());
if (terminal instanceof AbstractPosixTerminal) {
sb.append(" with pty ").append(((AbstractPosixTerminal) terminal).getPty().getClass().getName());
sb.append(" with pty ")
.append(((AbstractPosixTerminal) terminal)
.getPty()
.getClass()
.getName());
}
out.println(sb);
} catch (Throwable t3) {
@ -129,5 +164,4 @@ public class Diag {
static <S> S load(Class<S> clazz) {
return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -14,38 +14,58 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Attributes.ControlChar;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.NonBlocking;
import jdk.internal.org.jline.utils.NonBlockingInputStream;
import jdk.internal.org.jline.utils.NonBlockingReader;
public class DumbTerminal extends AbstractTerminal {
private final TerminalProvider provider;
private final SystemStream systemStream;
private final NonBlockingInputStream input;
private final OutputStream output;
private final NonBlockingReader reader;
private final PrintWriter writer;
private final Attributes attributes;
private final Size size;
private boolean skipNextLf;
public DumbTerminal(InputStream in, OutputStream out) throws IOException {
this(TYPE_DUMB, TYPE_DUMB, in, out, null);
public DumbTerminal(InputStream in, OutputStream out, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
this(TYPE_DUMB, TYPE_DUMB, in, out, null, inputStreamWrapper);
}
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding) throws IOException {
this(name, type, in, out, encoding, SignalHandler.SIG_DFL);
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding, Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
this(null, null, name, type, in, out, encoding, SignalHandler.SIG_DFL, inputStreamWrapper);
}
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) throws IOException {
@SuppressWarnings("this-escape")
public DumbTerminal(
TerminalProvider provider,
SystemStream systemStream,
String name,
String type,
InputStream in,
OutputStream out,
Charset encoding,
SignalHandler signalHandler,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
super(name, type, encoding, signalHandler);
NonBlockingInputStream nbis = NonBlocking.nonBlocking(getName(), in);
this.provider = provider;
this.systemStream = systemStream;
NonBlockingInputStream nbis = NonBlocking.nonBlocking(getName(), inputStreamWrapper.apply(in));
this.input = new NonBlockingInputStream() {
@Override
public int read(long timeout, boolean isPeek) throws IOException {
for (;;) {
for (; ; ) {
int c = nbis.read(timeout, isPeek);
if (attributes.getLocalFlag(Attributes.LocalFlag.ISIG)) {
if (c == attributes.getControlChar(ControlChar.VINTR)) {
@ -62,7 +82,19 @@ public class DumbTerminal extends AbstractTerminal {
continue;
}
}
if (c == '\r') {
if (attributes.getInputFlag(Attributes.InputFlag.INORMEOL)) {
if (c == '\r') {
skipNextLf = true;
c = '\n';
} else if (c == '\n') {
if (skipNextLf) {
skipNextLf = false;
continue;
}
} else {
skipNextLf = false;
}
} else if (c == '\r') {
if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
continue;
}
@ -80,10 +112,10 @@ public class DumbTerminal extends AbstractTerminal {
this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
this.attributes = new Attributes();
this.attributes.setControlChar(ControlChar.VERASE, (char) 127);
this.attributes.setControlChar(ControlChar.VERASE, (char) 127);
this.attributes.setControlChar(ControlChar.VWERASE, (char) 23);
this.attributes.setControlChar(ControlChar.VKILL, (char) 21);
this.attributes.setControlChar(ControlChar.VLNEXT, (char) 22);
this.attributes.setControlChar(ControlChar.VKILL, (char) 21);
this.attributes.setControlChar(ControlChar.VLNEXT, (char) 22);
this.size = new Size();
parseInfoCmp();
}
@ -107,9 +139,7 @@ public class DumbTerminal extends AbstractTerminal {
}
public Attributes getAttributes() {
Attributes attr = new Attributes();
attr.copy(attributes);
return attr;
return new Attributes(attributes);
}
public void setAttributes(Attributes attr) {
@ -126,4 +156,13 @@ public class DumbTerminal extends AbstractTerminal {
size.copy(sz);
}
@Override
public TerminalProvider getProvider() {
return provider;
}
@Override
public SystemStream getSystemStream() {
return systemStream;
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2023, 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 jdk.internal.org.jline.terminal.impl;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.TerminalBuilder;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
public class DumbTerminalProvider implements TerminalProvider {
@Override
public String name() {
return TerminalBuilder.PROP_PROVIDER_DUMB;
}
@Override
public Terminal sysTerminal(
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
Terminal.SignalHandler signalHandler,
boolean paused,
SystemStream systemStream,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
return new DumbTerminal(
this,
systemStream,
name,
type,
new FileInputStream(FileDescriptor.in),
new FileOutputStream(systemStream == SystemStream.Error ? FileDescriptor.err : FileDescriptor.out),
encoding,
signalHandler,
inputStreamWrapper);
}
@Override
public Terminal newTerminal(
String name,
String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
Terminal.SignalHandler signalHandler,
boolean paused,
Attributes attributes,
Size size)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean isSystemStream(SystemStream stream) {
return false;
}
@Override
public String systemStreamName(SystemStream stream) {
return null;
}
@Override
public int systemStreamWidth(SystemStream stream) {
return 0;
}
@Override
public String toString() {
return "TerminalProvider[" + name() + "]";
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -8,10 +8,6 @@
*/
package jdk.internal.org.jline.terminal.impl;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.Size;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -19,6 +15,11 @@ import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.IntConsumer;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
/**
* Console implementation with embedded line disciplined.
*
@ -32,45 +33,59 @@ import java.util.function.IntConsumer;
*/
public class ExternalTerminal extends LineDisciplineTerminal {
private final TerminalProvider provider;
protected final AtomicBoolean closed = new AtomicBoolean();
protected final InputStream masterInput;
protected final Object lock = new Object();
protected boolean paused = true;
protected Thread pumpThread;
public ExternalTerminal(String name, String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding) throws IOException {
this(name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
public ExternalTerminal(
String name, String type, InputStream masterInput, OutputStream masterOutput, Charset encoding)
throws IOException {
this(null, name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
}
public ExternalTerminal(String name, String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler) throws IOException {
this(name, type, masterInput, masterOutput, encoding, signalHandler, false);
public ExternalTerminal(
TerminalProvider provider,
String name,
String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler)
throws IOException {
this(provider, name, type, masterInput, masterOutput, encoding, signalHandler, false);
}
public ExternalTerminal(String name, String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler,
boolean paused) throws IOException {
this(name, type, masterInput, masterOutput, encoding, signalHandler, paused, null, null);
public ExternalTerminal(
TerminalProvider provider,
String name,
String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler,
boolean paused)
throws IOException {
this(provider, name, type, masterInput, masterOutput, encoding, signalHandler, paused, null, null);
}
public ExternalTerminal(String name, String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler,
boolean paused,
Attributes attributes,
Size size) throws IOException {
@SuppressWarnings("this-escape")
public ExternalTerminal(
TerminalProvider provider,
String name,
String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler,
boolean paused,
Attributes attributes,
Size size)
throws IOException {
super(name, type, masterOutput, encoding, signalHandler);
this.provider = provider;
this.masterInput = masterInput;
if (attributes != null) {
setAttributes(attributes);
@ -171,4 +186,8 @@ public class ExternalTerminal extends LineDisciplineTerminal {
return CursorSupport.getCursorPosition(this, discarded);
}
@Override
public TerminalProvider getProvider() {
return provider;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -14,6 +14,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.EnumSet;
import java.util.Objects;
import jdk.internal.org.jline.terminal.Attributes;
@ -23,6 +24,8 @@ import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.NonBlocking;
import jdk.internal.org.jline.utils.NonBlockingPumpInputStream;
import jdk.internal.org.jline.utils.NonBlockingReader;
@ -45,21 +48,6 @@ import jdk.internal.org.jline.utils.NonBlockingReader;
*/
public class LineDisciplineTerminal extends AbstractTerminal {
private static final String DEFAULT_TERMINAL_ATTRIBUTES =
"speed 9600 baud; 24 rows; 80 columns;\n" +
"lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl\n" +
"\t-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
"\t-extproc\n" +
"iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8\n" +
"\t-ignbrk brkint -inpck -ignpar -parmrk\n" +
"oflags: opost onlcr -oxtabs -onocr -onlret\n" +
"cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
"\t-dtrflow -mdmbuf\n" +
"cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
"\teol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
"\tmin = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
"\tstop = ^S; susp = ^Z; time = 0; werase = ^W;\n";
private static final int PIPE_SIZE = 1024;
/*
@ -84,20 +72,20 @@ public class LineDisciplineTerminal extends AbstractTerminal {
* Console data
*/
protected final Attributes attributes;
protected final Size size;
public LineDisciplineTerminal(String name,
String type,
OutputStream masterOutput,
Charset encoding) throws IOException {
protected boolean skipNextLf;
public LineDisciplineTerminal(String name, String type, OutputStream masterOutput, Charset encoding)
throws IOException {
this(name, type, masterOutput, encoding, SignalHandler.SIG_DFL);
}
public LineDisciplineTerminal(String name,
String type,
OutputStream masterOutput,
Charset encoding,
SignalHandler signalHandler) throws IOException {
@SuppressWarnings("this-escape")
public LineDisciplineTerminal(
String name, String type, OutputStream masterOutput, Charset encoding, SignalHandler signalHandler)
throws IOException {
super(name, type, encoding, signalHandler);
NonBlockingPumpInputStream input = NonBlocking.nonBlockingPumpInputStream(PIPE_SIZE);
this.slaveInputPipe = input.getOutputStream();
@ -106,11 +94,66 @@ public class LineDisciplineTerminal extends AbstractTerminal {
this.slaveOutput = new FilteringOutputStream();
this.slaveWriter = new PrintWriter(new OutputStreamWriter(slaveOutput, encoding()));
this.masterOutput = masterOutput;
this.attributes = ExecPty.doGetAttr(DEFAULT_TERMINAL_ATTRIBUTES);
this.attributes = getDefaultTerminalAttributes();
this.size = new Size(160, 50);
parseInfoCmp();
}
private static Attributes getDefaultTerminalAttributes() {
// speed 9600 baud; 24 rows; 80 columns;
// lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
// -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
// -extproc
// iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8
// -ignbrk brkint -inpck -ignpar -parmrk
// oflags: opost onlcr -oxtabs -onocr -onlret
// cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
// -dtrflow -mdmbuf
// cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
// eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
// min = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;
// stop = ^S; susp = ^Z; time = 0; werase = ^W;
Attributes attr = new Attributes();
attr.setLocalFlags(EnumSet.of(
LocalFlag.ICANON,
LocalFlag.ISIG,
LocalFlag.IEXTEN,
LocalFlag.ECHO,
LocalFlag.ECHOE,
LocalFlag.ECHOKE,
LocalFlag.ECHOCTL,
LocalFlag.PENDIN));
attr.setInputFlags(EnumSet.of(
InputFlag.ICRNL,
InputFlag.IXON,
InputFlag.IXANY,
InputFlag.IMAXBEL,
InputFlag.IUTF8,
InputFlag.BRKINT));
attr.setOutputFlags(EnumSet.of(OutputFlag.OPOST, OutputFlag.ONLCR));
attr.setControlChar(ControlChar.VDISCARD, ctrl('O'));
attr.setControlChar(ControlChar.VDSUSP, ctrl('Y'));
attr.setControlChar(ControlChar.VEOF, ctrl('D'));
attr.setControlChar(ControlChar.VERASE, ctrl('?'));
attr.setControlChar(ControlChar.VINTR, ctrl('C'));
attr.setControlChar(ControlChar.VKILL, ctrl('U'));
attr.setControlChar(ControlChar.VLNEXT, ctrl('V'));
attr.setControlChar(ControlChar.VMIN, 1);
attr.setControlChar(ControlChar.VQUIT, ctrl('\\'));
attr.setControlChar(ControlChar.VREPRINT, ctrl('R'));
attr.setControlChar(ControlChar.VSTART, ctrl('Q'));
attr.setControlChar(ControlChar.VSTATUS, ctrl('T'));
attr.setControlChar(ControlChar.VSTOP, ctrl('S'));
attr.setControlChar(ControlChar.VSUSP, ctrl('Z'));
attr.setControlChar(ControlChar.VTIME, 0);
attr.setControlChar(ControlChar.VWERASE, ctrl('W'));
return attr;
}
private static int ctrl(char c) {
return c == '?' ? 177 : c - 64;
}
public NonBlockingReader reader() {
return slaveReader;
}
@ -130,9 +173,7 @@ public class LineDisciplineTerminal extends AbstractTerminal {
}
public Attributes getAttributes() {
Attributes attr = new Attributes();
attr.copy(attributes);
return attr;
return new Attributes(attributes);
}
public void setAttributes(Attributes attr) {
@ -149,9 +190,9 @@ public class LineDisciplineTerminal extends AbstractTerminal {
size.copy(sz);
}
@Override
@Override
public void raise(Signal signal) {
Objects.requireNonNull(signal);
Objects.requireNonNull(signal);
// Do not call clear() atm as this can cause
// deadlock between reading / writing threads
// TODO: any way to fix that ?
@ -214,7 +255,19 @@ public class LineDisciplineTerminal extends AbstractTerminal {
raise(Signal.INFO);
}
}
if (c == '\r') {
if (attributes.getInputFlag(InputFlag.INORMEOL)) {
if (c == '\r') {
skipNextLf = true;
c = '\n';
} else if (c == '\n') {
if (skipNextLf) {
skipNextLf = false;
return false;
}
} else {
skipNextLf = false;
}
} else if (c == '\r') {
if (attributes.getInputFlag(InputFlag.IGNCR)) {
return false;
}
@ -273,6 +326,16 @@ public class LineDisciplineTerminal extends AbstractTerminal {
}
}
@Override
public TerminalProvider getProvider() {
return null;
}
@Override
public SystemStream getSystemStream() {
return null;
}
private class FilteringOutputStream extends OutputStream {
@Override
public void write(int b) throws IOException {
@ -284,13 +347,12 @@ public class LineDisciplineTerminal extends AbstractTerminal {
public void write(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
} else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
for (int i = 0; i < len; i++) {
processOutputByte(b[off + i]);
}
flush();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -8,11 +8,6 @@
*/
package jdk.internal.org.jline.terminal.impl;
import jdk.internal.org.jline.terminal.MouseEvent;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.utils.InfoCmp;
import jdk.internal.org.jline.utils.InputStreamReader;
import java.io.EOFException;
import java.io.IOError;
import java.io.IOException;
@ -20,6 +15,11 @@ import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.function.IntSupplier;
import jdk.internal.org.jline.terminal.MouseEvent;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.utils.InfoCmp;
import jdk.internal.org.jline.utils.InputStreamReader;
public class MouseSupport {
public static boolean hasMouseSupport(Terminal terminal) {
@ -78,7 +78,8 @@ public class MouseSupport {
case 0:
button = MouseEvent.Button.Button1;
if (last.getButton() == button
&& (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
&& (last.getType() == MouseEvent.Type.Pressed
|| last.getType() == MouseEvent.Type.Dragged)) {
type = MouseEvent.Type.Dragged;
} else {
type = MouseEvent.Type.Pressed;
@ -87,7 +88,8 @@ public class MouseSupport {
case 1:
button = MouseEvent.Button.Button2;
if (last.getButton() == button
&& (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
&& (last.getType() == MouseEvent.Type.Pressed
|| last.getType() == MouseEvent.Type.Dragged)) {
type = MouseEvent.Type.Dragged;
} else {
type = MouseEvent.Type.Pressed;
@ -96,7 +98,8 @@ public class MouseSupport {
case 2:
button = MouseEvent.Button.Button3;
if (last.getButton() == button
&& (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
&& (last.getType() == MouseEvent.Type.Pressed
|| last.getType() == MouseEvent.Type.Dragged)) {
type = MouseEvent.Type.Dragged;
} else {
type = MouseEvent.Type.Pressed;
@ -134,5 +137,4 @@ public class MouseSupport {
throw new IOError(e);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -17,8 +17,7 @@ public final class NativeSignalHandler implements SignalHandler {
public static final NativeSignalHandler SIG_IGN = new NativeSignalHandler();
private NativeSignalHandler() {
}
private NativeSignalHandler() {}
public void handle(Signal signal) {
throw new UnsupportedOperationException();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -38,15 +38,34 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
private Thread outputPumpThread;
private boolean paused = true;
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding) throws IOException {
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding)
throws IOException {
this(name, type, pty, in, out, encoding, SignalHandler.SIG_DFL);
}
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) throws IOException {
public PosixPtyTerminal(
String name,
String type,
Pty pty,
InputStream in,
OutputStream out,
Charset encoding,
SignalHandler signalHandler)
throws IOException {
this(name, type, pty, in, out, encoding, signalHandler, false);
}
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler, boolean paused) throws IOException {
@SuppressWarnings("this-escape")
public PosixPtyTerminal(
String name,
String type,
Pty pty,
InputStream in,
OutputStream out,
Charset encoding,
SignalHandler signalHandler,
boolean paused)
throws IOException {
super(name, type, pty, encoding, signalHandler);
this.in = Objects.requireNonNull(in);
this.out = Objects.requireNonNull(out);
@ -113,7 +132,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
if (p1 != null) {
p1.join();
}
if (p2 !=null) {
if (p2 != null) {
p2.join();
}
}
@ -167,7 +186,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
private void pumpIn() {
try {
for (;;) {
for (; ; ) {
synchronized (lock) {
if (paused) {
inputPumpThread = null;
@ -193,7 +212,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
private void pumpOut() {
try {
for (;;) {
for (; ; ) {
synchronized (lock) {
if (paused) {
outputPumpThread = null;
@ -221,5 +240,4 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
// Ignore
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -18,8 +18,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import jdk.internal.org.jline.utils.NonBlocking;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.utils.FastBufferedOutputStream;
import jdk.internal.org.jline.utils.NonBlocking;
import jdk.internal.org.jline.utils.NonBlockingInputStream;
import jdk.internal.org.jline.utils.NonBlockingReader;
import jdk.internal.org.jline.utils.ShutdownHooks;
@ -35,12 +36,14 @@ public class PosixSysTerminal extends AbstractPosixTerminal {
protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
protected final Task closer;
public PosixSysTerminal(String name, String type, Pty pty, Charset encoding,
boolean nativeSignals, SignalHandler signalHandler,
Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
@SuppressWarnings("this-escape")
public PosixSysTerminal(
String name, String type, Pty pty, Charset encoding, boolean nativeSignals, SignalHandler signalHandler,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
super(name, type, pty, encoding, signalHandler);
this.input = NonBlocking.nonBlocking(getName(), inputStreamWrapper.apply(pty.getSlaveInput()));
this.output = pty.getSlaveOutput();
this.output = new FastBufferedOutputStream(pty.getSlaveOutput());
this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
parseInfoCmp();
@ -98,5 +101,4 @@ public class PosixSysTerminal extends AbstractPosixTerminal {
// Do not call reader.close()
reader.shutdown();
}
}

View File

@ -1,18 +1,18 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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 jdk.internal.org.jline.terminal.impl;
package jdk.internal.org.jline.terminal.impl.exec;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileDescriptor;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@ -26,8 +26,10 @@ import jdk.internal.org.jline.terminal.Attributes.InputFlag;
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.terminal.impl.AbstractPty;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.OSUtils;
import static jdk.internal.org.jline.utils.ExecHelper.exec;
@ -35,28 +37,26 @@ import static jdk.internal.org.jline.utils.ExecHelper.exec;
public class ExecPty extends AbstractPty implements Pty {
private final String name;
private final TerminalProvider.Stream console;
public static Pty current(TerminalProvider.Stream console) throws IOException {
public static Pty current(TerminalProvider provider, SystemStream systemStream) throws IOException {
try {
String result = exec(true, OSUtils.TTY_COMMAND);
if (console != TerminalProvider.Stream.Output && console != TerminalProvider.Stream.Error) {
throw new IllegalArgumentException("console should be Output or Error: " + console);
if (systemStream != SystemStream.Output && systemStream != SystemStream.Error) {
throw new IllegalArgumentException("systemStream should be Output or Error: " + systemStream);
}
return new ExecPty(result.trim(), console);
return new ExecPty(provider, systemStream, result.trim());
} catch (IOException e) {
throw new IOException("Not a tty", e);
}
}
protected ExecPty(String name, TerminalProvider.Stream console) {
protected ExecPty(TerminalProvider provider, SystemStream systemStream, String name) {
super(provider, systemStream);
this.name = name;
this.console = console;
}
@Override
public void close() throws IOException {
}
public void close() throws IOException {}
public String getName() {
return name;
@ -74,18 +74,16 @@ public class ExecPty extends AbstractPty implements Pty {
@Override
protected InputStream doGetSlaveInput() throws IOException {
return console != null
? new FileInputStream(FileDescriptor.in)
: new FileInputStream(getName());
return systemStream != null ? new FileInputStream(FileDescriptor.in) : new FileInputStream(getName());
}
@Override
public OutputStream getSlaveOutput() throws IOException {
return console == TerminalProvider.Stream.Output
return systemStream == SystemStream.Output
? new FileOutputStream(FileDescriptor.out)
: console == TerminalProvider.Stream.Error
? new FileOutputStream(FileDescriptor.err)
: new FileOutputStream(getName());
: systemStream == SystemStream.Error
? new FileOutputStream(FileDescriptor.err)
: new FileOutputStream(getName());
}
@Override
@ -99,18 +97,30 @@ public class ExecPty extends AbstractPty implements Pty {
List<String> commands = getFlagsToSet(attr, getAttr());
if (!commands.isEmpty()) {
commands.add(0, OSUtils.STTY_COMMAND);
if (console == null) {
if (systemStream == null) {
commands.add(1, OSUtils.STTY_F_OPTION);
commands.add(2, getName());
}
exec(console != null, commands.toArray(new String[0]));
try {
exec(systemStream != null, commands.toArray(new String[0]));
} catch (IOException e) {
// Handle partial failures with GNU stty, see #97
if (e.toString().contains("unable to perform all requested operations")) {
commands = getFlagsToSet(attr, getAttr());
if (!commands.isEmpty()) {
throw new IOException("Could not set the following flags: " + String.join(", ", commands), e);
}
} else {
throw e;
}
}
}
}
protected List<String> getFlagsToSet(Attributes attr, Attributes current) {
List<String> commands = new ArrayList<>();
for (InputFlag flag : InputFlag.values()) {
if (attr.getInputFlag(flag) != current.getInputFlag(flag)) {
if (attr.getInputFlag(flag) != current.getInputFlag(flag) && flag != InputFlag.INORMEOL) {
commands.add((attr.getInputFlag(flag) ? flag.name() : "-" + flag.name()).toLowerCase());
}
}
@ -137,11 +147,9 @@ public class ExecPty extends AbstractPty implements Pty {
commands.add(cchar.name().toLowerCase().substring(1));
if (cchar == ControlChar.VMIN || cchar == ControlChar.VTIME) {
commands.add(Integer.toString(v));
}
else if (v == 0) {
} else if (v == 0) {
commands.add(undef);
}
else {
} else {
if (v >= 128) {
v -= 128;
str += "M-";
@ -165,12 +173,12 @@ public class ExecPty extends AbstractPty implements Pty {
}
protected String doGetConfig() throws IOException {
return console != null
? exec(true, OSUtils.STTY_COMMAND, "-a")
return systemStream != null
? exec(true, OSUtils.STTY_COMMAND, "-a")
: exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, getName(), "-a");
}
static Attributes doGetAttr(String cfg) throws IOException {
public static Attributes doGetAttr(String cfg) throws IOException {
Attributes attributes = new Attributes();
for (InputFlag flag : InputFlag.values()) {
Boolean value = doGetFlag(cfg, flag);
@ -201,16 +209,19 @@ public class ExecPty extends AbstractPty implements Pty {
if ("reprint".endsWith(name)) {
name = "(?:reprint|rprnt)";
}
Matcher matcher = Pattern.compile("[\\s;]" + name + "\\s*=\\s*(.+?)[\\s;]").matcher(cfg);
Matcher matcher =
Pattern.compile("[\\s;]" + name + "\\s*=\\s*(.+?)[\\s;]").matcher(cfg);
if (matcher.find()) {
attributes.setControlChar(cchar, parseControlChar(matcher.group(1).toUpperCase()));
attributes.setControlChar(
cchar, parseControlChar(matcher.group(1).toUpperCase()));
}
}
return attributes;
}
private static Boolean doGetFlag(String cfg, Enum<?> flag) {
Matcher matcher = Pattern.compile("(?:^|[\\s;])(\\-?" + flag.name().toLowerCase() + ")(?:[\\s;]|$)").matcher(cfg);
Matcher matcher = Pattern.compile("(?:^|[\\s;])(\\-?" + flag.name().toLowerCase() + ")(?:[\\s;]|$)")
.matcher(cfg);
return matcher.find() ? !matcher.group(1).startsWith("-") : null;
}
@ -259,9 +270,7 @@ public class ExecPty extends AbstractPty implements Pty {
static int doGetInt(String name, String cfg) throws IOException {
String[] patterns = new String[] {
"\\b([0-9]+)\\s+" + name + "\\b",
"\\b" + name + "\\s+([0-9]+)\\b",
"\\b" + name + "\\s*=\\s*([0-9]+)\\b"
"\\b([0-9]+)\\s+" + name + "\\b", "\\b" + name + "\\s+([0-9]+)\\b", "\\b" + name + "\\s*=\\s*([0-9]+)\\b"
};
for (String pattern : patterns) {
Matcher matcher = Pattern.compile(pattern).matcher(cfg);
@ -274,23 +283,29 @@ public class ExecPty extends AbstractPty implements Pty {
@Override
public void setSize(Size size) throws IOException {
if (console != null) {
exec(true,
OSUtils.STTY_COMMAND,
"columns", Integer.toString(size.getColumns()),
"rows", Integer.toString(size.getRows()));
if (systemStream != null) {
exec(
true,
OSUtils.STTY_COMMAND,
"columns",
Integer.toString(size.getColumns()),
"rows",
Integer.toString(size.getRows()));
} else {
exec(false,
OSUtils.STTY_COMMAND,
OSUtils.STTY_F_OPTION, getName(),
"columns", Integer.toString(size.getColumns()),
"rows", Integer.toString(size.getRows()));
exec(
false,
OSUtils.STTY_COMMAND,
OSUtils.STTY_F_OPTION,
getName(),
"columns",
Integer.toString(size.getColumns()),
"rows",
Integer.toString(size.getRows()));
}
}
@Override
public String toString() {
return "ExecPty[" + getName() + (console != null ? ", system]" : "]");
return "ExecPty[" + getName() + (systemStream != null ? ", system]" : "]");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, the original author or authors.
* Copyright (c) 2022, 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.
@ -17,117 +17,249 @@ import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.function.Function;
//import jdk.internal.org.jline.nativ.JLineLibrary;
//import jdk.internal.org.jline.nativ.JLineNativeLoader;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.impl.ExecPty;
import jdk.internal.org.jline.terminal.TerminalBuilder;
import jdk.internal.org.jline.terminal.impl.ExternalTerminal;
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.ExecHelper;
import jdk.internal.org.jline.utils.Log;
import jdk.internal.org.jline.utils.OSUtils;
public class ExecTerminalProvider implements TerminalProvider
{
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE_DEFAULT;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION;
public class ExecTerminalProvider implements TerminalProvider {
private static boolean warned;
public String name() {
return "exec";
return TerminalBuilder.PROP_PROVIDER_EXEC;
}
public Pty current(Stream consoleStream) throws IOException {
return ExecPty.current(consoleStream);
public Pty current(SystemStream systemStream) throws IOException {
return ExecPty.current(this, systemStream);
}
@Override
public Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
public Terminal sysTerminal(
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
Terminal.SignalHandler signalHandler,
boolean paused,
SystemStream systemStream,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
if (OSUtils.IS_WINDOWS) {
return winSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
return winSysTerminal(
name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream, inputStreamWrapper);
} else {
return posixSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
return posixSysTerminal(
name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream, inputStreamWrapper);
}
}
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper ) throws IOException {
public Terminal winSysTerminal(
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
Terminal.SignalHandler signalHandler,
boolean paused,
SystemStream systemStream,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
Pty pty = current(consoleStream);
Pty pty = current(systemStream);
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
} else {
return null;
}
}
public Terminal posixSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
Pty pty = current(consoleStream);
public Terminal posixSysTerminal(
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
Terminal.SignalHandler signalHandler,
boolean paused,
SystemStream systemStream,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
Pty pty = current(systemStream);
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
}
@Override
public Terminal newTerminal(String name, String type, InputStream in, OutputStream out,
Charset encoding, Terminal.SignalHandler signalHandler, boolean paused,
Attributes attributes, Size size) throws IOException
{
return new ExternalTerminal(name, type, in, out, encoding, signalHandler, paused, attributes, size);
public Terminal newTerminal(
String name,
String type,
InputStream in,
OutputStream out,
Charset encoding,
Terminal.SignalHandler signalHandler,
boolean paused,
Attributes attributes,
Size size)
throws IOException {
return new ExternalTerminal(this, name, type, in, out, encoding, signalHandler, paused, attributes, size);
}
@Override
public boolean isSystemStream(Stream stream) {
public boolean isSystemStream(SystemStream stream) {
try {
return isWindowsSystemStream(stream) || isPosixSystemStream(stream);
return isPosixSystemStream(stream) || isWindowsSystemStream(stream);
} catch (Throwable t) {
return false;
}
}
public boolean isWindowsSystemStream(Stream stream) {
return systemStreamName( stream ) != null;
public boolean isWindowsSystemStream(SystemStream stream) {
return systemStreamName(stream) != null;
}
public boolean isPosixSystemStream(Stream stream) {
public boolean isPosixSystemStream(SystemStream stream) {
try {
Process p = new ProcessBuilder(OSUtils.TEST_COMMAND, "-t", Integer.toString(stream.ordinal()))
.inheritIO().start();
.inheritIO()
.start();
return p.waitFor() == 0;
} catch (Throwable t) {
Log.debug("ExecTerminalProvider failed 'test -t' for " + stream, t);
// ignore
}
return false;
}
@Override
public String systemStreamName(Stream stream) {
public String systemStreamName(SystemStream stream) {
try {
ProcessBuilder.Redirect input = stream == Stream.Input
? ProcessBuilder.Redirect.INHERIT
: getRedirect(stream == Stream.Output ? FileDescriptor.out : FileDescriptor.err);
Process p = new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start();
ProcessBuilder.Redirect input = stream == SystemStream.Input
? ProcessBuilder.Redirect.INHERIT
: newDescriptor(stream == SystemStream.Output ? FileDescriptor.out : FileDescriptor.err);
Process p =
new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start();
String result = ExecHelper.waitAndCapture(p);
if (p.exitValue() == 0) {
return result.trim();
}
} catch (Throwable t) {
if ("java.lang.reflect.InaccessibleObjectException"
.equals(t.getClass().getName())
&& !warned) {
Log.warn(
"The ExecTerminalProvider requires the JVM options: '--add-opens java.base/java.lang=ALL-UNNAMED'");
warned = true;
}
// ignore
}
return null;
}
private ProcessBuilder.Redirect getRedirect(FileDescriptor fd) throws ReflectiveOperationException {
// This is not really allowed, but this is the only way to redirect the output or error stream
// to the input. This is definitely not something you'd usually want to do, but in the case of
// the `tty` utility, it provides a way to get
Class<?> rpi = Class.forName("java.lang.ProcessBuilder$RedirectPipeImpl");
Constructor<?> cns = rpi.getDeclaredConstructor();
cns.setAccessible(true);
ProcessBuilder.Redirect input = (ProcessBuilder.Redirect) cns.newInstance();
Field f = rpi.getDeclaredField("fd");
f.setAccessible(true);
f.set(input, fd);
return input;
@Override
public int systemStreamWidth(SystemStream stream) {
try (ExecPty pty = new ExecPty(this, stream, null)) {
return pty.getSize().getColumns();
} catch (Throwable t) {
return -1;
}
}
private static RedirectPipeCreator redirectPipeCreator;
protected static ProcessBuilder.Redirect newDescriptor(FileDescriptor fd) {
if (redirectPipeCreator == null) {
String str = System.getProperty(PROP_REDIRECT_PIPE_CREATION_MODE, PROP_REDIRECT_PIPE_CREATION_MODE_DEFAULT);
String[] modes = str.split(",");
IllegalStateException ise = new IllegalStateException("Unable to create RedirectPipe");
for (String mode : modes) {
try {
switch (mode) {
case PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE:
redirectPipeCreator = null;//new NativeRedirectPipeCreator();
break;
case PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION:
redirectPipeCreator = new ReflectionRedirectPipeCreator();
break;
}
} catch (Throwable t) {
// ignore
ise.addSuppressed(t);
}
if (redirectPipeCreator != null) {
break;
}
}
if (redirectPipeCreator == null) {
throw ise;
}
}
return redirectPipeCreator.newRedirectPipe(fd);
}
interface RedirectPipeCreator {
ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd);
}
/**
* Reflection based file descriptor creator.
* This requires the following option
* --add-opens java.base/java.lang=ALL-UNNAMED
*/
static class ReflectionRedirectPipeCreator implements RedirectPipeCreator {
private final Constructor<ProcessBuilder.Redirect> constructor;
private final Field fdField;
@SuppressWarnings("unchecked")
ReflectionRedirectPipeCreator() throws Exception {
Class<?> rpi = Class.forName("java.lang.ProcessBuilder$RedirectPipeImpl");
constructor = (Constructor<ProcessBuilder.Redirect>) rpi.getDeclaredConstructor();
constructor.setAccessible(true);
fdField = rpi.getDeclaredField("fd");
fdField.setAccessible(true);
}
@Override
public ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd) {
try {
ProcessBuilder.Redirect input = constructor.newInstance();
fdField.set(input, fd);
return input;
} catch (ReflectiveOperationException e) {
// This should not happen as the field has been set accessible
throw new IllegalStateException(e);
}
}
}
// static class NativeRedirectPipeCreator implements RedirectPipeCreator {
// public NativeRedirectPipeCreator() {
// // Force load the library
// JLineNativeLoader.initialize();
// }
//
// @Override
// public ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd) {
// return JLineLibrary.newRedirectPipe(fd);
// }
// }
@Override
public String toString() {
return "TerminalProvider[" + name() + "]";
}
}

View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 2022-2023, 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 jdk.internal.org.jline.terminal.impl.ffm;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.AbstractPty;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
class FfmNativePty extends AbstractPty {
private final int master;
private final int slave;
private final int slaveOut;
private final String name;
private final FileDescriptor masterFD;
private final FileDescriptor slaveFD;
private final FileDescriptor slaveOutFD;
public FfmNativePty(TerminalProvider provider, SystemStream systemStream, int master, int slave, String name) {
this(
provider,
systemStream,
master,
newDescriptor(master),
slave,
newDescriptor(slave),
slave,
newDescriptor(slave),
name);
}
public FfmNativePty(
TerminalProvider provider,
SystemStream systemStream,
int master,
FileDescriptor masterFD,
int slave,
FileDescriptor slaveFD,
int slaveOut,
FileDescriptor slaveOutFD,
String name) {
super(provider, systemStream);
this.master = master;
this.slave = slave;
this.slaveOut = slaveOut;
this.name = name;
this.masterFD = masterFD;
this.slaveFD = slaveFD;
this.slaveOutFD = slaveOutFD;
}
@Override
public void close() throws IOException {
if (master > 0) {
getMasterInput().close();
}
if (slave > 0) {
getSlaveInput().close();
}
}
public int getMaster() {
return master;
}
public int getSlave() {
return slave;
}
public int getSlaveOut() {
return slaveOut;
}
public String getName() {
return name;
}
public FileDescriptor getMasterFD() {
return masterFD;
}
public FileDescriptor getSlaveFD() {
return slaveFD;
}
public FileDescriptor getSlaveOutFD() {
return slaveOutFD;
}
public InputStream getMasterInput() {
return new FileInputStream(getMasterFD());
}
public OutputStream getMasterOutput() {
return new FileOutputStream(getMasterFD());
}
protected InputStream doGetSlaveInput() {
return new FileInputStream(getSlaveFD());
}
public OutputStream getSlaveOutput() {
return new FileOutputStream(getSlaveOutFD());
}
@Override
public Attributes getAttr() throws IOException {
return CLibrary.getAttributes(slave);
}
@Override
protected void doSetAttr(Attributes attr) throws IOException {
CLibrary.setAttributes(slave, attr);
}
@Override
public Size getSize() throws IOException {
return CLibrary.getTerminalSize(slave);
}
@Override
public void setSize(Size size) throws IOException {
CLibrary.setTerminalSize(slave, size);
}
@Override
public String toString() {
return "FfmNativePty[" + getName() + "]";
}
public static boolean isPosixSystemStream(SystemStream stream) {
switch (stream) {
case Input:
return CLibrary.isTty(0);
case Output:
return CLibrary.isTty(1);
case Error:
return CLibrary.isTty(2);
default:
throw new IllegalArgumentException();
}
}
public static String posixSystemStreamName(SystemStream stream) {
switch (stream) {
case Input:
return CLibrary.ttyName(0);
case Output:
return CLibrary.ttyName(1);
case Error:
return CLibrary.ttyName(2);
default:
throw new IllegalArgumentException();
}
}
public static int systemStreamWidth(SystemStream systemStream) {
int fd = systemStream == SystemStream.Output ? 1 : 2;
return CLibrary.getTerminalSize(fd).getColumns();
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2022-2023, 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 jdk.internal.org.jline.terminal.impl.ffm;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemoryLayout.PathElement;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.charset.Charset;
import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.TerminalBuilder;
import jdk.internal.org.jline.terminal.impl.PosixPtyTerminal;
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
import jdk.internal.org.jline.terminal.spi.Pty;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.OSUtils;
public class FfmTerminalProvider implements TerminalProvider {
public FfmTerminalProvider() {
if (!FfmTerminalProvider.class.getModule().isNativeAccessEnabled()) {
throw new UnsupportedOperationException(
"Native access is not enabled for the current module: " + FfmTerminalProvider.class.getModule());
}
}
@Override
public String name() {
return TerminalBuilder.PROP_PROVIDER_FFM;
}
@Override
public Terminal sysTerminal(
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
Terminal.SignalHandler signalHandler,
boolean paused,
SystemStream systemStream,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
if (OSUtils.IS_WINDOWS) {
return NativeWinSysTerminal.createTerminal(
this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, inputStreamWrapper);
} else {
Pty pty = new FfmNativePty(
this,
systemStream,
-1,
null,
0,
FileDescriptor.in,
systemStream == SystemStream.Output ? 1 : 2,
systemStream == SystemStream.Output ? FileDescriptor.out : FileDescriptor.err,
CLibrary.ttyName(0));
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
}
}
@Override
public Terminal newTerminal(
String name,
String type,
InputStream in,
OutputStream out,
Charset encoding,
Terminal.SignalHandler signalHandler,
boolean paused,
Attributes attributes,
Size size)
throws IOException {
Pty pty = CLibrary.openpty(this, attributes, size);
return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused);
}
@Override
public boolean isSystemStream(SystemStream stream) {
if (OSUtils.IS_WINDOWS) {
return isWindowsSystemStream(stream);
} else {
return isPosixSystemStream(stream);
}
}
public boolean isWindowsSystemStream(SystemStream stream) {
return NativeWinSysTerminal.isWindowsSystemStream(stream);
}
public boolean isPosixSystemStream(SystemStream stream) {
return FfmNativePty.isPosixSystemStream(stream);
}
@Override
public String systemStreamName(SystemStream stream) {
return FfmNativePty.posixSystemStreamName(stream);
}
@Override
public int systemStreamWidth(SystemStream stream) {
return FfmNativePty.systemStreamWidth(stream);
}
@Override
public String toString() {
return "TerminalProvider[" + name() + "]";
}
static VarHandle lookupVarHandle(MemoryLayout layout, PathElement... element) {
VarHandle h = layout.varHandle(element);
// the last parameter of the VarHandle is additional offset, hardcode zero:
h = MethodHandles.insertCoordinates(h, h.coordinateTypes().size() - 1, 0L);
return h;
}
}

View File

@ -0,0 +1,927 @@
/*
* Copyright (c) 2009-2023, 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 jdk.internal.org.jline.terminal.impl.ffm;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.VarHandle;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
@SuppressWarnings({"unused", "restricted"})
final class Kernel32 {
public static final int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
public static final int INVALID_HANDLE_VALUE = -1;
public static final int STD_INPUT_HANDLE = -10;
public static final int STD_OUTPUT_HANDLE = -11;
public static final int STD_ERROR_HANDLE = -12;
public static final int ENABLE_PROCESSED_INPUT = 0x0001;
public static final int ENABLE_LINE_INPUT = 0x0002;
public static final int ENABLE_ECHO_INPUT = 0x0004;
public static final int ENABLE_WINDOW_INPUT = 0x0008;
public static final int ENABLE_MOUSE_INPUT = 0x0010;
public static final int ENABLE_INSERT_MODE = 0x0020;
public static final int ENABLE_QUICK_EDIT_MODE = 0x0040;
public static final int ENABLE_EXTENDED_FLAGS = 0x0080;
public static final int RIGHT_ALT_PRESSED = 0x0001;
public static final int LEFT_ALT_PRESSED = 0x0002;
public static final int RIGHT_CTRL_PRESSED = 0x0004;
public static final int LEFT_CTRL_PRESSED = 0x0008;
public static final int SHIFT_PRESSED = 0x0010;
public static final int FOREGROUND_BLUE = 0x0001;
public static final int FOREGROUND_GREEN = 0x0002;
public static final int FOREGROUND_RED = 0x0004;
public static final int FOREGROUND_INTENSITY = 0x0008;
public static final int BACKGROUND_BLUE = 0x0010;
public static final int BACKGROUND_GREEN = 0x0020;
public static final int BACKGROUND_RED = 0x0040;
public static final int BACKGROUND_INTENSITY = 0x0080;
// Button state
public static final int FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001;
public static final int RIGHTMOST_BUTTON_PRESSED = 0x0002;
public static final int FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004;
public static final int FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008;
public static final int FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010;
// Event flags
public static final int MOUSE_MOVED = 0x0001;
public static final int DOUBLE_CLICK = 0x0002;
public static final int MOUSE_WHEELED = 0x0004;
public static final int MOUSE_HWHEELED = 0x0008;
// Event types
public static final short KEY_EVENT = 0x0001;
public static final short MOUSE_EVENT = 0x0002;
public static final short WINDOW_BUFFER_SIZE_EVENT = 0x0004;
public static final short MENU_EVENT = 0x0008;
public static final short FOCUS_EVENT = 0x0010;
public static int WaitForSingleObject(java.lang.foreign.MemorySegment hHandle, int dwMilliseconds) {
MethodHandle mh$ = requireNonNull(WaitForSingleObject$MH, "WaitForSingleObject");
try {
return (int) mh$.invokeExact(hHandle, dwMilliseconds);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static java.lang.foreign.MemorySegment GetStdHandle(int nStdHandle) {
MethodHandle mh$ = requireNonNull(GetStdHandle$MH, "GetStdHandle");
try {
return (java.lang.foreign.MemorySegment) mh$.invokeExact(nStdHandle);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int FormatMessageW(
int dwFlags,
java.lang.foreign.MemorySegment lpSource,
int dwMessageId,
int dwLanguageId,
java.lang.foreign.MemorySegment lpBuffer,
int nSize,
java.lang.foreign.MemorySegment Arguments) {
MethodHandle mh$ = requireNonNull(FormatMessageW$MH, "FormatMessageW");
try {
return (int) mh$.invokeExact(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int SetConsoleTextAttribute(java.lang.foreign.MemorySegment hConsoleOutput, short wAttributes) {
MethodHandle mh$ = requireNonNull(SetConsoleTextAttribute$MH, "SetConsoleTextAttribute");
try {
return (int) mh$.invokeExact(hConsoleOutput, wAttributes);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int SetConsoleMode(java.lang.foreign.MemorySegment hConsoleHandle, int dwMode) {
MethodHandle mh$ = requireNonNull(SetConsoleMode$MH, "SetConsoleMode");
try {
return (int) mh$.invokeExact(hConsoleHandle, dwMode);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int GetConsoleMode(
java.lang.foreign.MemorySegment hConsoleHandle, java.lang.foreign.MemorySegment lpMode) {
MethodHandle mh$ = requireNonNull(GetConsoleMode$MH, "GetConsoleMode");
try {
return (int) mh$.invokeExact(hConsoleHandle, lpMode);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int SetConsoleTitleW(java.lang.foreign.MemorySegment lpConsoleTitle) {
MethodHandle mh$ = requireNonNull(SetConsoleTitleW$MH, "SetConsoleTitleW");
try {
return (int) mh$.invokeExact(lpConsoleTitle);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int SetConsoleCursorPosition(java.lang.foreign.MemorySegment hConsoleOutput, COORD dwCursorPosition) {
MethodHandle mh$ = requireNonNull(SetConsoleCursorPosition$MH, "SetConsoleCursorPosition");
try {
return (int) mh$.invokeExact(hConsoleOutput, dwCursorPosition.seg);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int FillConsoleOutputCharacterW(
java.lang.foreign.MemorySegment hConsoleOutput,
char cCharacter,
int nLength,
COORD dwWriteCoord,
java.lang.foreign.MemorySegment lpNumberOfCharsWritten) {
MethodHandle mh$ = requireNonNull(FillConsoleOutputCharacterW$MH, "FillConsoleOutputCharacterW");
try {
return (int) mh$.invokeExact(hConsoleOutput, cCharacter, nLength, dwWriteCoord.seg, lpNumberOfCharsWritten);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int FillConsoleOutputAttribute(
java.lang.foreign.MemorySegment hConsoleOutput,
short wAttribute,
int nLength,
COORD dwWriteCoord,
java.lang.foreign.MemorySegment lpNumberOfAttrsWritten) {
MethodHandle mh$ = requireNonNull(FillConsoleOutputAttribute$MH, "FillConsoleOutputAttribute");
try {
return (int) mh$.invokeExact(hConsoleOutput, wAttribute, nLength, dwWriteCoord.seg, lpNumberOfAttrsWritten);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int WriteConsoleW(
java.lang.foreign.MemorySegment hConsoleOutput,
java.lang.foreign.MemorySegment lpBuffer,
int nNumberOfCharsToWrite,
java.lang.foreign.MemorySegment lpNumberOfCharsWritten,
java.lang.foreign.MemorySegment lpReserved) {
MethodHandle mh$ = requireNonNull(WriteConsoleW$MH, "WriteConsoleW");
try {
return (int) mh$.invokeExact(
hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int ReadConsoleInputW(
java.lang.foreign.MemorySegment hConsoleInput,
java.lang.foreign.MemorySegment lpBuffer,
int nLength,
java.lang.foreign.MemorySegment lpNumberOfEventsRead) {
MethodHandle mh$ = requireNonNull(ReadConsoleInputW$MH, "ReadConsoleInputW");
try {
return (int) mh$.invokeExact(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int PeekConsoleInputW(
java.lang.foreign.MemorySegment hConsoleInput,
java.lang.foreign.MemorySegment lpBuffer,
int nLength,
java.lang.foreign.MemorySegment lpNumberOfEventsRead) {
MethodHandle mh$ = requireNonNull(PeekConsoleInputW$MH, "PeekConsoleInputW");
try {
return (int) mh$.invokeExact(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int GetConsoleScreenBufferInfo(
java.lang.foreign.MemorySegment hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo) {
MethodHandle mh$ = requireNonNull(GetConsoleScreenBufferInfo$MH, "GetConsoleScreenBufferInfo");
try {
return (int) mh$.invokeExact(hConsoleOutput, lpConsoleScreenBufferInfo.seg);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int ScrollConsoleScreenBuffer(
java.lang.foreign.MemorySegment hConsoleOutput,
SMALL_RECT lpScrollRectangle,
SMALL_RECT lpClipRectangle,
COORD dwDestinationOrigin,
CHAR_INFO lpFill) {
MethodHandle mh$ = requireNonNull(ScrollConsoleScreenBufferW$MH, "ScrollConsoleScreenBuffer");
try {
return (int)
mh$.invokeExact(hConsoleOutput, lpScrollRectangle, lpClipRectangle, dwDestinationOrigin, lpFill);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int GetLastError() {
MethodHandle mh$ = requireNonNull(GetLastError$MH, "GetLastError");
try {
return (int) mh$.invokeExact();
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static int GetFileType(java.lang.foreign.MemorySegment hFile) {
MethodHandle mh$ = requireNonNull(GetFileType$MH, "GetFileType");
try {
return (int) mh$.invokeExact(hFile);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static java.lang.foreign.MemorySegment _get_osfhandle(int fd) {
MethodHandle mh$ = requireNonNull(_get_osfhandle$MH, "_get_osfhandle");
try {
return (java.lang.foreign.MemorySegment) mh$.invokeExact(fd);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
public static INPUT_RECORD[] readConsoleInputHelper(java.lang.foreign.MemorySegment handle, int count, boolean peek)
throws IOException {
return readConsoleInputHelper(java.lang.foreign.Arena.ofAuto(), handle, count, peek);
}
public static INPUT_RECORD[] readConsoleInputHelper(
java.lang.foreign.Arena arena, java.lang.foreign.MemorySegment handle, int count, boolean peek)
throws IOException {
java.lang.foreign.MemorySegment inputRecordPtr = arena.allocate(INPUT_RECORD.LAYOUT, count);
java.lang.foreign.MemorySegment length = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT, 1);
int res = peek
? PeekConsoleInputW(handle, inputRecordPtr, count, length)
: ReadConsoleInputW(handle, inputRecordPtr, count, length);
if (res == 0) {
throw new IOException("ReadConsoleInputW failed: " + getLastErrorMessage());
}
int len = length.get(java.lang.foreign.ValueLayout.JAVA_INT, 0);
return inputRecordPtr
.elements(INPUT_RECORD.LAYOUT)
.map(INPUT_RECORD::new)
.limit(len)
.toArray(INPUT_RECORD[]::new);
}
public static String getLastErrorMessage() {
int errorCode = GetLastError();
return getErrorMessage(errorCode);
}
public static String getErrorMessage(int errorCode) {
int bufferSize = 160;
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment data = arena.allocate(bufferSize);
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM,
java.lang.foreign.MemorySegment.NULL,
errorCode,
0,
data,
bufferSize,
java.lang.foreign.MemorySegment.NULL);
return new String(data.toArray(java.lang.foreign.ValueLayout.JAVA_BYTE), StandardCharsets.UTF_16LE).trim();
}
}
private static final java.lang.foreign.SymbolLookup SYMBOL_LOOKUP;
static {
System.loadLibrary("msvcrt");
System.loadLibrary("Kernel32");
SYMBOL_LOOKUP = java.lang.foreign.SymbolLookup.loaderLookup();
}
static MethodHandle downcallHandle(String name, java.lang.foreign.FunctionDescriptor fdesc) {
return SYMBOL_LOOKUP
.find(name)
.map(addr -> java.lang.foreign.Linker.nativeLinker().downcallHandle(addr, fdesc))
.orElse(null);
}
static final java.lang.foreign.ValueLayout.OfBoolean C_BOOL$LAYOUT = java.lang.foreign.ValueLayout.JAVA_BOOLEAN;
static final java.lang.foreign.ValueLayout.OfByte C_CHAR$LAYOUT = java.lang.foreign.ValueLayout.JAVA_BYTE;
static final java.lang.foreign.ValueLayout.OfChar C_WCHAR$LAYOUT = java.lang.foreign.ValueLayout.JAVA_CHAR;
static final java.lang.foreign.ValueLayout.OfShort C_SHORT$LAYOUT = java.lang.foreign.ValueLayout.JAVA_SHORT;
static final java.lang.foreign.ValueLayout.OfShort C_WORD$LAYOUT = java.lang.foreign.ValueLayout.JAVA_SHORT;
static final java.lang.foreign.ValueLayout.OfInt C_DWORD$LAYOUT = java.lang.foreign.ValueLayout.JAVA_INT;
static final java.lang.foreign.ValueLayout.OfInt C_INT$LAYOUT = java.lang.foreign.ValueLayout.JAVA_INT;
static final java.lang.foreign.ValueLayout.OfLong C_LONG$LAYOUT = java.lang.foreign.ValueLayout.JAVA_LONG;
static final java.lang.foreign.ValueLayout.OfLong C_LONG_LONG$LAYOUT = java.lang.foreign.ValueLayout.JAVA_LONG;
static final java.lang.foreign.ValueLayout.OfFloat C_FLOAT$LAYOUT = java.lang.foreign.ValueLayout.JAVA_FLOAT;
static final java.lang.foreign.ValueLayout.OfDouble C_DOUBLE$LAYOUT = java.lang.foreign.ValueLayout.JAVA_DOUBLE;
static final java.lang.foreign.AddressLayout C_POINTER$LAYOUT = java.lang.foreign.ValueLayout.ADDRESS;
static final MethodHandle WaitForSingleObject$MH = downcallHandle(
"WaitForSingleObject",
java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT));
static final MethodHandle GetStdHandle$MH =
downcallHandle("GetStdHandle", java.lang.foreign.FunctionDescriptor.of(C_POINTER$LAYOUT, C_INT$LAYOUT));
static final MethodHandle FormatMessageW$MH = downcallHandle(
"FormatMessageW",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT,
C_INT$LAYOUT,
C_POINTER$LAYOUT,
C_INT$LAYOUT,
C_INT$LAYOUT,
C_POINTER$LAYOUT,
C_INT$LAYOUT,
C_POINTER$LAYOUT));
static final MethodHandle SetConsoleTextAttribute$MH = downcallHandle(
"SetConsoleTextAttribute",
java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT));
static final MethodHandle SetConsoleMode$MH = downcallHandle(
"SetConsoleMode", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT));
static final MethodHandle GetConsoleMode$MH = downcallHandle(
"GetConsoleMode",
java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle SetConsoleTitleW$MH =
downcallHandle("SetConsoleTitleW", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle SetConsoleCursorPosition$MH = downcallHandle(
"SetConsoleCursorPosition",
java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, COORD.LAYOUT));
static final MethodHandle FillConsoleOutputCharacterW$MH = downcallHandle(
"FillConsoleOutputCharacterW",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT, C_POINTER$LAYOUT, C_WCHAR$LAYOUT, C_INT$LAYOUT, COORD.LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle FillConsoleOutputAttribute$MH = downcallHandle(
"FillConsoleOutputAttribute",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT, C_INT$LAYOUT, COORD.LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle WriteConsoleW$MH = downcallHandle(
"WriteConsoleW",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT,
C_POINTER$LAYOUT,
C_POINTER$LAYOUT,
C_INT$LAYOUT,
C_POINTER$LAYOUT,
C_POINTER$LAYOUT));
static final MethodHandle ReadConsoleInputW$MH = downcallHandle(
"ReadConsoleInputW",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle PeekConsoleInputW$MH = downcallHandle(
"PeekConsoleInputW",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle GetConsoleScreenBufferInfo$MH = downcallHandle(
"GetConsoleScreenBufferInfo",
java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle ScrollConsoleScreenBufferW$MH = downcallHandle(
"ScrollConsoleScreenBufferW",
java.lang.foreign.FunctionDescriptor.of(
C_INT$LAYOUT,
C_POINTER$LAYOUT,
C_POINTER$LAYOUT,
C_POINTER$LAYOUT,
COORD.LAYOUT,
C_POINTER$LAYOUT));
static final MethodHandle GetLastError$MH =
downcallHandle("GetLastError", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT));
static final MethodHandle GetFileType$MH =
downcallHandle("GetFileType", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT));
static final MethodHandle _get_osfhandle$MH =
downcallHandle("_get_osfhandle", java.lang.foreign.FunctionDescriptor.of(C_POINTER$LAYOUT, C_INT$LAYOUT));
public static final class INPUT_RECORD {
static final java.lang.foreign.MemoryLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout(
java.lang.foreign.ValueLayout.JAVA_SHORT.withName("EventType"),
java.lang.foreign.ValueLayout.JAVA_SHORT, // padding
java.lang.foreign.MemoryLayout.unionLayout(
KEY_EVENT_RECORD.LAYOUT.withName("KeyEvent"),
MOUSE_EVENT_RECORD.LAYOUT.withName("MouseEvent"),
WINDOW_BUFFER_SIZE_RECORD.LAYOUT.withName("WindowBufferSizeEvent"),
MENU_EVENT_RECORD.LAYOUT.withName("MenuEvent"),
FOCUS_EVENT_RECORD.LAYOUT.withName("FocusEvent"))
.withName("Event"));
static final VarHandle EventType$VH = varHandle(LAYOUT, "EventType");
static final long Event$OFFSET = byteOffset(LAYOUT, "Event");
private final java.lang.foreign.MemorySegment seg;
public INPUT_RECORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public INPUT_RECORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public INPUT_RECORD(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public short eventType() {
return (short) EventType$VH.get(seg);
}
public KEY_EVENT_RECORD keyEvent() {
return new KEY_EVENT_RECORD(seg, Event$OFFSET);
}
public MOUSE_EVENT_RECORD mouseEvent() {
return new MOUSE_EVENT_RECORD(seg, Event$OFFSET);
}
public FOCUS_EVENT_RECORD focusEvent() {
return new FOCUS_EVENT_RECORD(seg, Event$OFFSET);
}
}
public static final class MENU_EVENT_RECORD {
static final java.lang.foreign.GroupLayout LAYOUT =
java.lang.foreign.MemoryLayout.structLayout(C_DWORD$LAYOUT.withName("dwCommandId"));
static final VarHandle COMMAND_ID = varHandle(LAYOUT, "dwCommandId");
private final java.lang.foreign.MemorySegment seg;
public MENU_EVENT_RECORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public MENU_EVENT_RECORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public MENU_EVENT_RECORD(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public int commandId() {
return (int) MENU_EVENT_RECORD.COMMAND_ID.get(seg);
}
public void commandId(int commandId) {
MENU_EVENT_RECORD.COMMAND_ID.set(seg, commandId);
}
}
public static final class FOCUS_EVENT_RECORD {
static final java.lang.foreign.GroupLayout LAYOUT =
java.lang.foreign.MemoryLayout.structLayout(C_INT$LAYOUT.withName("bSetFocus"));
static final VarHandle SET_FOCUS = varHandle(LAYOUT, "bSetFocus");
private final java.lang.foreign.MemorySegment seg;
public FOCUS_EVENT_RECORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public FOCUS_EVENT_RECORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public FOCUS_EVENT_RECORD(java.lang.foreign.MemorySegment seg) {
this.seg = Objects.requireNonNull(seg);
}
public FOCUS_EVENT_RECORD(java.lang.foreign.MemorySegment seg, long offset) {
this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize());
}
public boolean setFocus() {
return ((int) FOCUS_EVENT_RECORD.SET_FOCUS.get(seg) != 0);
}
public void setFocus(boolean setFocus) {
FOCUS_EVENT_RECORD.SET_FOCUS.set(seg, setFocus ? 1 : 0);
}
}
public static final class WINDOW_BUFFER_SIZE_RECORD {
static final java.lang.foreign.GroupLayout LAYOUT =
java.lang.foreign.MemoryLayout.structLayout(COORD.LAYOUT.withName("size"));
static final long SIZE_OFFSET = byteOffset(LAYOUT, "size");
private final java.lang.foreign.MemorySegment seg;
public WINDOW_BUFFER_SIZE_RECORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public WINDOW_BUFFER_SIZE_RECORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public WINDOW_BUFFER_SIZE_RECORD(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public COORD size() {
return new COORD(seg, SIZE_OFFSET);
}
public String toString() {
return "WINDOW_BUFFER_SIZE_RECORD{size=" + this.size() + '}';
}
}
public static final class MOUSE_EVENT_RECORD {
static final java.lang.foreign.MemoryLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout(
COORD.LAYOUT.withName("dwMousePosition"),
C_DWORD$LAYOUT.withName("dwButtonState"),
C_DWORD$LAYOUT.withName("dwControlKeyState"),
C_DWORD$LAYOUT.withName("dwEventFlags"));
static final long MOUSE_POSITION_OFFSET = byteOffset(LAYOUT, "dwMousePosition");
static final VarHandle BUTTON_STATE = varHandle(LAYOUT, "dwButtonState");
static final VarHandle CONTROL_KEY_STATE = varHandle(LAYOUT, "dwControlKeyState");
static final VarHandle EVENT_FLAGS = varHandle(LAYOUT, "dwEventFlags");
private final java.lang.foreign.MemorySegment seg;
public MOUSE_EVENT_RECORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public MOUSE_EVENT_RECORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public MOUSE_EVENT_RECORD(java.lang.foreign.MemorySegment seg) {
this.seg = Objects.requireNonNull(seg);
}
public MOUSE_EVENT_RECORD(java.lang.foreign.MemorySegment seg, long offset) {
this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize());
}
public COORD mousePosition() {
return new COORD(seg, MOUSE_POSITION_OFFSET);
}
public int buttonState() {
return (int) BUTTON_STATE.get(seg);
}
public int controlKeyState() {
return (int) CONTROL_KEY_STATE.get(seg);
}
public int eventFlags() {
return (int) EVENT_FLAGS.get(seg);
}
public String toString() {
return "MOUSE_EVENT_RECORD{mousePosition=" + mousePosition() + ", buttonState=" + buttonState()
+ ", controlKeyState=" + controlKeyState() + ", eventFlags=" + eventFlags() + '}';
}
}
public static final class KEY_EVENT_RECORD {
static final java.lang.foreign.MemoryLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout(
java.lang.foreign.ValueLayout.JAVA_INT.withName("bKeyDown"),
java.lang.foreign.ValueLayout.JAVA_SHORT.withName("wRepeatCount"),
java.lang.foreign.ValueLayout.JAVA_SHORT.withName("wVirtualKeyCode"),
java.lang.foreign.ValueLayout.JAVA_SHORT.withName("wVirtualScanCode"),
java.lang.foreign.MemoryLayout.unionLayout(
java.lang.foreign.ValueLayout.JAVA_CHAR.withName("UnicodeChar"),
java.lang.foreign.ValueLayout.JAVA_BYTE.withName("AsciiChar"))
.withName("uChar"),
java.lang.foreign.ValueLayout.JAVA_INT.withName("dwControlKeyState"));
static final VarHandle bKeyDown$VH = varHandle(LAYOUT, "bKeyDown");
static final VarHandle wRepeatCount$VH = varHandle(LAYOUT, "wRepeatCount");
static final VarHandle wVirtualKeyCode$VH = varHandle(LAYOUT, "wVirtualKeyCode");
static final VarHandle wVirtualScanCode$VH = varHandle(LAYOUT, "wVirtualScanCode");
static final VarHandle UnicodeChar$VH = varHandle(LAYOUT, "uChar", "UnicodeChar");
static final VarHandle AsciiChar$VH = varHandle(LAYOUT, "uChar", "AsciiChar");
static final VarHandle dwControlKeyState$VH = varHandle(LAYOUT, "dwControlKeyState");
final java.lang.foreign.MemorySegment seg;
public KEY_EVENT_RECORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public KEY_EVENT_RECORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public KEY_EVENT_RECORD(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public KEY_EVENT_RECORD(java.lang.foreign.MemorySegment seg, long offset) {
this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize());
}
public boolean keyDown() {
return ((int) bKeyDown$VH.get(seg)) != 0;
}
public int repeatCount() {
return (int) wRepeatCount$VH.get(seg);
}
public short keyCode() {
return (short) wVirtualKeyCode$VH.get(seg);
}
public short scanCode() {
return (short) wVirtualScanCode$VH.get(seg);
}
public char uchar() {
return (char) UnicodeChar$VH.get(seg);
}
public int controlKeyState() {
return (int) dwControlKeyState$VH.get(seg);
}
public String toString() {
return "KEY_EVENT_RECORD{keyDown=" + this.keyDown() + ", repeatCount=" + this.repeatCount() + ", keyCode="
+ this.keyCode() + ", scanCode=" + this.scanCode() + ", uchar=" + this.uchar()
+ ", controlKeyState="
+ this.controlKeyState() + '}';
}
}
public static final class CHAR_INFO {
static final java.lang.foreign.GroupLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout(
java.lang.foreign.MemoryLayout.unionLayout(
C_WCHAR$LAYOUT.withName("UnicodeChar"), C_CHAR$LAYOUT.withName("AsciiChar"))
.withName("Char"),
C_WORD$LAYOUT.withName("Attributes"));
static final VarHandle UnicodeChar$VH = varHandle(LAYOUT, "Char", "UnicodeChar");
static final VarHandle Attributes$VH = varHandle(LAYOUT, "Attributes");
final java.lang.foreign.MemorySegment seg;
public CHAR_INFO() {
this(java.lang.foreign.Arena.ofAuto());
}
public CHAR_INFO(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public CHAR_INFO(java.lang.foreign.Arena arena, char c, short a) {
this(arena);
UnicodeChar$VH.set(seg, c);
Attributes$VH.set(seg, a);
}
public CHAR_INFO(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public char unicodeChar() {
return (char) UnicodeChar$VH.get(seg);
}
}
public static final class CONSOLE_SCREEN_BUFFER_INFO {
static final java.lang.foreign.GroupLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout(
COORD.LAYOUT.withName("dwSize"),
COORD.LAYOUT.withName("dwCursorPosition"),
C_WORD$LAYOUT.withName("wAttributes"),
SMALL_RECT.LAYOUT.withName("srWindow"),
COORD.LAYOUT.withName("dwMaximumWindowSize"));
static final long dwSize$OFFSET = byteOffset(LAYOUT, "dwSize");
static final long dwCursorPosition$OFFSET = byteOffset(LAYOUT, "dwCursorPosition");
static final VarHandle wAttributes$VH = varHandle(LAYOUT, "wAttributes");
static final long srWindow$OFFSET = byteOffset(LAYOUT, "srWindow");
private final java.lang.foreign.MemorySegment seg;
public CONSOLE_SCREEN_BUFFER_INFO() {
this(java.lang.foreign.Arena.ofAuto());
}
public CONSOLE_SCREEN_BUFFER_INFO(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public CONSOLE_SCREEN_BUFFER_INFO(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public COORD size() {
return new COORD(seg, dwSize$OFFSET);
}
public COORD cursorPosition() {
return new COORD(seg, dwCursorPosition$OFFSET);
}
public short attributes() {
return (short) wAttributes$VH.get(seg);
}
public SMALL_RECT window() {
return new SMALL_RECT(seg, srWindow$OFFSET);
}
public int windowWidth() {
return this.window().width() + 1;
}
public int windowHeight() {
return this.window().height() + 1;
}
public void attributes(short attr) {
wAttributes$VH.set(seg, attr);
}
}
public static final class COORD {
static final java.lang.foreign.GroupLayout LAYOUT =
java.lang.foreign.MemoryLayout.structLayout(C_SHORT$LAYOUT.withName("x"), C_SHORT$LAYOUT.withName("y"));
static final VarHandle x$VH = varHandle(LAYOUT, "x");
static final VarHandle y$VH = varHandle(LAYOUT, "y");
private final java.lang.foreign.MemorySegment seg;
public COORD() {
this(java.lang.foreign.Arena.ofAuto());
}
public COORD(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public COORD(java.lang.foreign.Arena arena, short x, short y) {
this(arena.allocate(LAYOUT));
x(x);
y(y);
}
public COORD(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public COORD(java.lang.foreign.MemorySegment seg, long offset) {
this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize());
}
public short x() {
return (short) COORD.x$VH.get(seg);
}
public void x(short x) {
COORD.x$VH.set(seg, x);
}
public short y() {
return (short) COORD.y$VH.get(seg);
}
public void y(short y) {
COORD.y$VH.set(seg, y);
}
public COORD copy(java.lang.foreign.Arena arena) {
return new COORD(arena.allocate(LAYOUT).copyFrom(seg));
}
}
public static final class SMALL_RECT {
static final java.lang.foreign.GroupLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout(
C_SHORT$LAYOUT.withName("Left"),
C_SHORT$LAYOUT.withName("Top"),
C_SHORT$LAYOUT.withName("Right"),
C_SHORT$LAYOUT.withName("Bottom"));
static final VarHandle Left$VH = varHandle(LAYOUT, "Left");
static final VarHandle Top$VH = varHandle(LAYOUT, "Top");
static final VarHandle Right$VH = varHandle(LAYOUT, "Right");
static final VarHandle Bottom$VH = varHandle(LAYOUT, "Bottom");
private final java.lang.foreign.MemorySegment seg;
public SMALL_RECT() {
this(java.lang.foreign.Arena.ofAuto());
}
public SMALL_RECT(java.lang.foreign.Arena arena) {
this(arena.allocate(LAYOUT));
}
public SMALL_RECT(java.lang.foreign.Arena arena, SMALL_RECT rect) {
this(arena);
left(rect.left());
right(rect.right());
top(rect.top());
bottom(rect.bottom());
}
public SMALL_RECT(java.lang.foreign.MemorySegment seg, long offset) {
this(seg.asSlice(offset, LAYOUT.byteSize()));
}
public SMALL_RECT(java.lang.foreign.MemorySegment seg) {
this.seg = seg;
}
public short left() {
return (short) Left$VH.get(seg);
}
public short top() {
return (short) Top$VH.get(seg);
}
public short right() {
return (short) Right$VH.get(seg);
}
public short bottom() {
return (short) Bottom$VH.get(seg);
}
public short width() {
return (short) (this.right() - this.left());
}
public short height() {
return (short) (this.bottom() - this.top());
}
public void left(short l) {
Left$VH.set(seg, l);
}
public void top(short t) {
Top$VH.set(seg, t);
}
public void right(short r) {
Right$VH.set(seg, r);
}
public void bottom(short b) {
Bottom$VH.set(seg, b);
}
public SMALL_RECT copy(java.lang.foreign.Arena arena) {
return new SMALL_RECT(arena.allocate(LAYOUT).copyFrom(seg));
}
}
static <T> T requireNonNull(T obj, String symbolName) {
if (obj == null) {
throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName);
}
return obj;
}
static VarHandle varHandle(java.lang.foreign.MemoryLayout layout, String name) {
return FfmTerminalProvider.lookupVarHandle(
layout, java.lang.foreign.MemoryLayout.PathElement.groupElement(name));
}
static VarHandle varHandle(java.lang.foreign.MemoryLayout layout, String e1, String name) {
return FfmTerminalProvider.lookupVarHandle(
layout,
java.lang.foreign.MemoryLayout.PathElement.groupElement(e1),
java.lang.foreign.MemoryLayout.PathElement.groupElement(name));
}
static long byteOffset(java.lang.foreign.MemoryLayout layout, String name) {
return layout.byteOffset(java.lang.foreign.MemoryLayout.PathElement.groupElement(name));
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2022-2023, 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 jdk.internal.org.jline.terminal.impl.ffm;
import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import jdk.internal.org.jline.terminal.impl.AbstractWindowsConsoleWriter;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.GetStdHandle;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.STD_OUTPUT_HANDLE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.WriteConsoleW;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.getLastErrorMessage;
class NativeWinConsoleWriter extends AbstractWindowsConsoleWriter {
private final java.lang.foreign.MemorySegment console = GetStdHandle(STD_OUTPUT_HANDLE);
@Override
protected void writeConsole(char[] text, int len) throws IOException {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment txt = arena.allocateFrom(ValueLayout.JAVA_CHAR, text);
if (WriteConsoleW(console, txt, len, MemorySegment.NULL, MemorySegment.NULL) == 0) {
throw new IOException("Failed to write to console: " + getLastErrorMessage());
}
}
}
}

View File

@ -0,0 +1,302 @@
/*
* Copyright (c) 2022-2023, 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 jdk.internal.org.jline.terminal.impl.ffm;
import java.io.BufferedWriter;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.function.Function;
import java.util.function.IntConsumer;
import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
import jdk.internal.org.jline.terminal.spi.SystemStream;
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.OSUtils;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.*;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.GetConsoleMode;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.GetConsoleScreenBufferInfo;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.GetStdHandle;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.INPUT_RECORD;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.INVALID_HANDLE_VALUE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.KEY_EVENT_RECORD;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.MOUSE_EVENT_RECORD;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.STD_ERROR_HANDLE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.STD_INPUT_HANDLE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.STD_OUTPUT_HANDLE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.SetConsoleMode;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.WaitForSingleObject;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.getLastErrorMessage;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.readConsoleInputHelper;
public class NativeWinSysTerminal extends AbstractWindowsTerminal<java.lang.foreign.MemorySegment> {
public static NativeWinSysTerminal createTerminal(
TerminalProvider provider,
SystemStream systemStream,
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
SignalHandler signalHandler,
boolean paused,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
// Get input console mode
java.lang.foreign.MemorySegment consoleIn = GetStdHandle(STD_INPUT_HANDLE);
java.lang.foreign.MemorySegment inMode = allocateInt(arena);
if (GetConsoleMode(consoleIn, inMode) == 0) {
throw new IOException("Failed to get console mode: " + getLastErrorMessage());
}
// Get output console and mode
java.lang.foreign.MemorySegment console;
switch (systemStream) {
case Output:
console = GetStdHandle(STD_OUTPUT_HANDLE);
break;
case Error:
console = GetStdHandle(STD_ERROR_HANDLE);
break;
default:
throw new IllegalArgumentException("Unsupported stream for console: " + systemStream);
}
java.lang.foreign.MemorySegment outMode = allocateInt(arena);
if (GetConsoleMode(console, outMode) == 0) {
throw new IOException("Failed to get console mode: " + getLastErrorMessage());
}
// Create writer
Writer writer;
if (ansiPassThrough) {
type = type != null ? type : OSUtils.IS_CONEMU ? TYPE_WINDOWS_CONEMU : TYPE_WINDOWS;
writer = new NativeWinConsoleWriter();
} else {
int m = inMode.get(java.lang.foreign.ValueLayout.JAVA_INT, 0);
if (enableVtp(console, m)) {
type = type != null ? type : TYPE_WINDOWS_VTP;
writer = new NativeWinConsoleWriter();
} else if (OSUtils.IS_CONEMU) {
type = type != null ? type : TYPE_WINDOWS_CONEMU;
writer = new NativeWinConsoleWriter();
} else {
type = type != null ? type : TYPE_WINDOWS;
writer = new WindowsAnsiWriter(new BufferedWriter(new NativeWinConsoleWriter()));
}
}
// Create terminal
NativeWinSysTerminal terminal = new NativeWinSysTerminal(
provider,
systemStream,
writer,
name,
type,
encoding,
nativeSignals,
signalHandler,
consoleIn,
inMode.get(java.lang.foreign.ValueLayout.JAVA_INT, 0),
console,
outMode.get(java.lang.foreign.ValueLayout.JAVA_INT, 0),
inputStreamWrapper);
// Start input pump thread
if (!paused) {
terminal.resume();
}
return terminal;
}
}
private static boolean enableVtp(java.lang.foreign.MemorySegment console, int m) {
return SetConsoleMode(console, m | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
}
public static boolean isWindowsSystemStream(SystemStream stream) {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment console;
java.lang.foreign.MemorySegment mode = allocateInt(arena);
switch (stream) {
case Input:
console = GetStdHandle(STD_INPUT_HANDLE);
break;
case Output:
console = GetStdHandle(STD_OUTPUT_HANDLE);
break;
case Error:
console = GetStdHandle(STD_ERROR_HANDLE);
break;
default:
return false;
}
return GetConsoleMode(console, mode) != 0;
}
}
private static java.lang.foreign.MemorySegment allocateInt(java.lang.foreign.Arena arena) {
return arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT);
}
NativeWinSysTerminal(
TerminalProvider provider,
SystemStream systemStream,
Writer writer,
String name,
String type,
Charset encoding,
boolean nativeSignals,
SignalHandler signalHandler,
java.lang.foreign.MemorySegment inConsole,
int inConsoleMode,
java.lang.foreign.MemorySegment outConsole,
int outConsoleMode,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
super(
provider,
systemStream,
writer,
name,
type,
encoding,
nativeSignals,
signalHandler,
inConsole,
inConsoleMode,
outConsole,
outConsoleMode,
inputStreamWrapper);
}
@Override
protected int getConsoleMode(java.lang.foreign.MemorySegment console) {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment mode = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT);
if (GetConsoleMode(console, mode) == 0) {
return -1;
}
return mode.get(java.lang.foreign.ValueLayout.JAVA_INT, 0);
}
}
@Override
protected void setConsoleMode(java.lang.foreign.MemorySegment console, int mode) {
SetConsoleMode(console, mode);
}
public Size getSize() {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO(arena);
GetConsoleScreenBufferInfo(outConsole, info);
return new Size(info.windowWidth(), info.windowHeight());
}
}
@Override
public Size getBufferSize() {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO(arena);
GetConsoleScreenBufferInfo(outConsole, info);
return new Size(info.size().x(), info.size().y());
}
}
protected boolean processConsoleInput() throws IOException {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
INPUT_RECORD[] events;
if (inConsole != null
&& inConsole.address() != INVALID_HANDLE_VALUE
&& WaitForSingleObject(inConsole, 100) == 0) {
events = readConsoleInputHelper(arena, inConsole, 1, false);
} else {
return false;
}
boolean flush = false;
for (INPUT_RECORD event : events) {
int eventType = event.eventType();
if (eventType == KEY_EVENT) {
KEY_EVENT_RECORD keyEvent = event.keyEvent();
processKeyEvent(
keyEvent.keyDown(), keyEvent.keyCode(), keyEvent.uchar(), keyEvent.controlKeyState());
flush = true;
} else if (eventType == WINDOW_BUFFER_SIZE_EVENT) {
raise(Signal.WINCH);
} else if (eventType == MOUSE_EVENT) {
processMouseEvent(event.mouseEvent());
flush = true;
} else if (eventType == FOCUS_EVENT) {
processFocusEvent(event.focusEvent().setFocus());
}
}
return flush;
}
}
private final char[] focus = new char[] {'\033', '[', ' '};
private void processFocusEvent(boolean hasFocus) throws IOException {
if (focusTracking) {
focus[2] = hasFocus ? 'I' : 'O';
slaveInputPipe.write(focus);
}
}
private final char[] mouse = new char[] {'\033', '[', 'M', ' ', ' ', ' '};
private void processMouseEvent(MOUSE_EVENT_RECORD mouseEvent) throws IOException {
int dwEventFlags = mouseEvent.eventFlags();
int dwButtonState = mouseEvent.buttonState();
if (tracking == MouseTracking.Off
|| tracking == MouseTracking.Normal && dwEventFlags == MOUSE_MOVED
|| tracking == MouseTracking.Button && dwEventFlags == MOUSE_MOVED && dwButtonState == 0) {
return;
}
int cb = 0;
dwEventFlags &= ~DOUBLE_CLICK; // Treat double-clicks as normal
if (dwEventFlags == MOUSE_WHEELED) {
cb |= 64;
if ((dwButtonState >> 16) < 0) {
cb |= 1;
}
} else if (dwEventFlags == MOUSE_HWHEELED) {
return;
} else if ((dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) != 0) {
cb |= 0x00;
} else if ((dwButtonState & RIGHTMOST_BUTTON_PRESSED) != 0) {
cb |= 0x01;
} else if ((dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) != 0) {
cb |= 0x02;
} else {
cb |= 0x03;
}
int cx = mouseEvent.mousePosition().x();
int cy = mouseEvent.mousePosition().y();
mouse[3] = (char) (' ' + cb);
mouse[4] = (char) (' ' + cx + 1);
mouse[5] = (char) (' ' + cy + 1);
slaveInputPipe.write(mouse);
}
@Override
public Cursor getCursorPosition(IntConsumer discarded) {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO(arena);
if (GetConsoleScreenBufferInfo(outConsole, info) == 0) {
throw new IOError(new IOException("Could not get the cursor position: " + getLastErrorMessage()));
}
return new Cursor(info.cursorPosition().x(), info.cursorPosition().y());
}
}
}

View File

@ -0,0 +1,407 @@
/*
* Copyright (c) 2022-2023, 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 jdk.internal.org.jline.terminal.impl.ffm;
import java.io.IOException;
import java.io.Writer;
import jdk.internal.org.jline.utils.AnsiWriter;
import jdk.internal.org.jline.utils.Colors;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.BACKGROUND_BLUE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.BACKGROUND_GREEN;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.BACKGROUND_INTENSITY;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.BACKGROUND_RED;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.CHAR_INFO;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.CONSOLE_SCREEN_BUFFER_INFO;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.COORD;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.FOREGROUND_BLUE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.FOREGROUND_GREEN;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.FOREGROUND_INTENSITY;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.FOREGROUND_RED;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.FillConsoleOutputAttribute;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.FillConsoleOutputCharacterW;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.GetConsoleScreenBufferInfo;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.GetStdHandle;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.SMALL_RECT;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.STD_OUTPUT_HANDLE;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.ScrollConsoleScreenBuffer;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.SetConsoleCursorPosition;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.SetConsoleTextAttribute;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.SetConsoleTitleW;
import static jdk.internal.org.jline.terminal.impl.ffm.Kernel32.getLastErrorMessage;
class WindowsAnsiWriter extends AnsiWriter {
private static final java.lang.foreign.MemorySegment console = GetStdHandle(STD_OUTPUT_HANDLE);
private static final short FOREGROUND_BLACK = 0;
private static final short FOREGROUND_YELLOW = (short) (FOREGROUND_RED | FOREGROUND_GREEN);
private static final short FOREGROUND_MAGENTA = (short) (FOREGROUND_BLUE | FOREGROUND_RED);
private static final short FOREGROUND_CYAN = (short) (FOREGROUND_BLUE | FOREGROUND_GREEN);
private static final short FOREGROUND_WHITE = (short) (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
private static final short BACKGROUND_BLACK = 0;
private static final short BACKGROUND_YELLOW = (short) (BACKGROUND_RED | BACKGROUND_GREEN);
private static final short BACKGROUND_MAGENTA = (short) (BACKGROUND_BLUE | BACKGROUND_RED);
private static final short BACKGROUND_CYAN = (short) (BACKGROUND_BLUE | BACKGROUND_GREEN);
private static final short BACKGROUND_WHITE = (short) (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
private static final short[] ANSI_FOREGROUND_COLOR_MAP = {
FOREGROUND_BLACK,
FOREGROUND_RED,
FOREGROUND_GREEN,
FOREGROUND_YELLOW,
FOREGROUND_BLUE,
FOREGROUND_MAGENTA,
FOREGROUND_CYAN,
FOREGROUND_WHITE,
};
private static final short[] ANSI_BACKGROUND_COLOR_MAP = {
BACKGROUND_BLACK,
BACKGROUND_RED,
BACKGROUND_GREEN,
BACKGROUND_YELLOW,
BACKGROUND_BLUE,
BACKGROUND_MAGENTA,
BACKGROUND_CYAN,
BACKGROUND_WHITE,
};
private final CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO(java.lang.foreign.Arena.ofAuto());
private final short originalColors;
private boolean negative;
private boolean bold;
private boolean underline;
private short savedX = -1;
private short savedY = -1;
public WindowsAnsiWriter(Writer out) throws IOException {
super(out);
getConsoleInfo();
originalColors = info.attributes();
}
private void getConsoleInfo() throws IOException {
out.flush();
if (GetConsoleScreenBufferInfo(console, info) == 0) {
throw new IOException("Could not get the screen info: " + getLastErrorMessage());
}
if (negative) {
info.attributes(invertAttributeColors(info.attributes()));
}
}
private void applyAttribute() throws IOException {
out.flush();
short attributes = info.attributes();
// bold is simulated by high foreground intensity
if (bold) {
attributes |= FOREGROUND_INTENSITY;
}
// underline is simulated by high foreground intensity
if (underline) {
attributes |= BACKGROUND_INTENSITY;
}
if (negative) {
attributes = invertAttributeColors(attributes);
}
if (SetConsoleTextAttribute(console, attributes) == 0) {
throw new IOException(getLastErrorMessage());
}
}
private short invertAttributeColors(short attributes) {
// Swap the the Foreground and Background bits.
int fg = 0x000F & attributes;
fg <<= 4;
int bg = 0X00F0 & attributes;
bg >>= 4;
attributes = (short) ((attributes & 0xFF00) | fg | bg);
return attributes;
}
private void applyCursorPosition() throws IOException {
info.cursorPosition().x((short)
Math.max(0, Math.min(info.size().x() - 1, info.cursorPosition().x())));
info.cursorPosition().y((short)
Math.max(0, Math.min(info.size().y() - 1, info.cursorPosition().y())));
if (SetConsoleCursorPosition(console, info.cursorPosition()) == 0) {
throw new IOException(getLastErrorMessage());
}
}
@Override
protected void processEraseScreen(int eraseOption) throws IOException {
getConsoleInfo();
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment written = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT);
switch (eraseOption) {
case ERASE_SCREEN -> {
COORD topLeft = new COORD(arena, (short) 0, info.window().top());
int screenLength = info.window().height() * info.size().x();
FillConsoleOutputAttribute(console, originalColors, screenLength, topLeft, written);
FillConsoleOutputCharacterW(console, ' ', screenLength, topLeft, written);
}
case ERASE_SCREEN_TO_BEGINING -> {
COORD topLeft2 = new COORD(arena, (short) 0, info.window().top());
int lengthToCursor =
(info.cursorPosition().y() - info.window().top())
* info.size().x()
+ info.cursorPosition().x();
FillConsoleOutputAttribute(console, originalColors, lengthToCursor, topLeft2, written);
FillConsoleOutputCharacterW(console, ' ', lengthToCursor, topLeft2, written);
}
case ERASE_SCREEN_TO_END -> {
int lengthToEnd =
(info.window().bottom() - info.cursorPosition().y())
* info.size().x()
+ (info.size().x() - info.cursorPosition().x());
FillConsoleOutputAttribute(console, originalColors, lengthToEnd, info.cursorPosition(), written);
FillConsoleOutputCharacterW(console, ' ', lengthToEnd, info.cursorPosition(), written);
}
default -> {}
}
}
}
@Override
protected void processEraseLine(int eraseOption) throws IOException {
getConsoleInfo();
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment written = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT);
switch (eraseOption) {
case ERASE_LINE -> {
COORD leftColCurrRow =
new COORD(arena, (short) 0, info.cursorPosition().y());
FillConsoleOutputAttribute(
console, originalColors, info.size().x(), leftColCurrRow, written);
FillConsoleOutputCharacterW(console, ' ', info.size().x(), leftColCurrRow, written);
}
case ERASE_LINE_TO_BEGINING -> {
COORD leftColCurrRow2 =
new COORD(arena, (short) 0, info.cursorPosition().y());
FillConsoleOutputAttribute(
console, originalColors, info.cursorPosition().x(), leftColCurrRow2, written);
FillConsoleOutputCharacterW(
console, ' ', info.cursorPosition().x(), leftColCurrRow2, written);
}
case ERASE_LINE_TO_END -> {
int lengthToLastCol =
info.size().x() - info.cursorPosition().x();
FillConsoleOutputAttribute(
console, originalColors, lengthToLastCol, info.cursorPosition(), written);
FillConsoleOutputCharacterW(console, ' ', lengthToLastCol, info.cursorPosition(), written);
}
default -> {}
}
}
}
protected void processCursorUpLine(int count) throws IOException {
getConsoleInfo();
info.cursorPosition().x((short) 0);
info.cursorPosition().y((short) (info.cursorPosition().y() - count));
applyCursorPosition();
}
protected void processCursorDownLine(int count) throws IOException {
getConsoleInfo();
info.cursorPosition().x((short) 0);
info.cursorPosition().y((short) (info.cursorPosition().y() + count));
applyCursorPosition();
}
@Override
protected void processCursorLeft(int count) throws IOException {
getConsoleInfo();
info.cursorPosition().x((short) (info.cursorPosition().x() - count));
applyCursorPosition();
}
@Override
protected void processCursorRight(int count) throws IOException {
getConsoleInfo();
info.cursorPosition().x((short) (info.cursorPosition().x() + count));
applyCursorPosition();
}
@Override
protected void processCursorDown(int count) throws IOException {
getConsoleInfo();
int nb = Math.max(0, info.cursorPosition().y() + count - info.size().y() + 1);
if (nb != count) {
info.cursorPosition().y((short) (info.cursorPosition().y() + count));
applyCursorPosition();
}
if (nb > 0) {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
SMALL_RECT scroll = new SMALL_RECT(arena, info.window());
scroll.top((short) 0);
COORD org = new COORD(arena);
org.x((short) 0);
org.y((short) (-nb));
CHAR_INFO info = new CHAR_INFO(arena, ' ', originalColors);
ScrollConsoleScreenBuffer(console, scroll, scroll, org, info);
}
}
}
@Override
protected void processCursorUp(int count) throws IOException {
getConsoleInfo();
info.cursorPosition().y((short) (info.cursorPosition().y() - count));
applyCursorPosition();
}
@Override
protected void processCursorTo(int row, int col) throws IOException {
getConsoleInfo();
info.cursorPosition().y((short) (info.window().top() + row - 1));
info.cursorPosition().x((short) (col - 1));
applyCursorPosition();
}
@Override
protected void processCursorToColumn(int x) throws IOException {
getConsoleInfo();
info.cursorPosition().x((short) (x - 1));
applyCursorPosition();
}
@Override
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
int color = Colors.roundColor(paletteIndex, 16);
info.attributes((short) ((info.attributes() & ~0x0007) | ANSI_FOREGROUND_COLOR_MAP[color & 0x07]));
info.attributes(
(short) ((info.attributes() & ~FOREGROUND_INTENSITY) | (color >= 8 ? FOREGROUND_INTENSITY : 0)));
applyAttribute();
}
@Override
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
int color = Colors.roundColor(paletteIndex, 16);
info.attributes((short) ((info.attributes() & ~0x0070) | ANSI_BACKGROUND_COLOR_MAP[color & 0x07]));
info.attributes(
(short) ((info.attributes() & ~BACKGROUND_INTENSITY) | (color >= 8 ? BACKGROUND_INTENSITY : 0)));
applyAttribute();
}
@Override
protected void processDefaultTextColor() throws IOException {
info.attributes((short) ((info.attributes() & ~0x000F) | (originalColors & 0xF)));
info.attributes((short) (info.attributes() & ~FOREGROUND_INTENSITY));
applyAttribute();
}
@Override
protected void processDefaultBackgroundColor() throws IOException {
info.attributes((short) ((info.attributes() & ~0x00F0) | (originalColors & 0xF0)));
info.attributes((short) (info.attributes() & ~BACKGROUND_INTENSITY));
applyAttribute();
}
@Override
protected void processAttributeRest() throws IOException {
info.attributes((short) ((info.attributes() & ~0x00FF) | originalColors));
this.negative = false;
this.bold = false;
this.underline = false;
applyAttribute();
}
@Override
protected void processSetAttribute(int attribute) throws IOException {
switch (attribute) {
case ATTRIBUTE_INTENSITY_BOLD -> {
bold = true;
applyAttribute();
}
case ATTRIBUTE_INTENSITY_NORMAL -> {
bold = false;
applyAttribute();
}
case ATTRIBUTE_UNDERLINE -> {
underline = true;
applyAttribute();
}
case ATTRIBUTE_UNDERLINE_OFF -> {
underline = false;
applyAttribute();
}
case ATTRIBUTE_NEGATIVE_ON -> {
negative = true;
applyAttribute();
}
case ATTRIBUTE_NEGATIVE_OFF -> {
negative = false;
applyAttribute();
}
default -> {}
}
}
@Override
protected void processSaveCursorPosition() throws IOException {
getConsoleInfo();
savedX = info.cursorPosition().x();
savedY = info.cursorPosition().y();
}
@Override
protected void processRestoreCursorPosition() throws IOException {
// restore only if there was a save operation first
if (savedX != -1 && savedY != -1) {
out.flush();
info.cursorPosition().x(savedX);
info.cursorPosition().y(savedY);
applyCursorPosition();
}
}
@Override
protected void processInsertLine(int optionInt) throws IOException {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
getConsoleInfo();
SMALL_RECT scroll = info.window().copy(arena);
scroll.top(info.cursorPosition().y());
COORD org =
new COORD(arena, (short) 0, (short) (info.cursorPosition().y() + optionInt));
CHAR_INFO info = new CHAR_INFO(arena, ' ', originalColors);
if (ScrollConsoleScreenBuffer(console, scroll, scroll, org, info) == 0) {
throw new IOException(getLastErrorMessage());
}
}
}
@Override
protected void processDeleteLine(int optionInt) throws IOException {
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
getConsoleInfo();
SMALL_RECT scroll = info.window().copy(arena);
scroll.top(info.cursorPosition().y());
COORD org =
new COORD(arena, (short) 0, (short) (info.cursorPosition().y() - optionInt));
CHAR_INFO info = new CHAR_INFO(arena, ' ', originalColors);
if (ScrollConsoleScreenBuffer(console, scroll, scroll, org, info) == 0) {
throw new IOException(getLastErrorMessage());
}
}
}
@Override
protected void processChangeWindowTitle(String title) {
try (java.lang.foreign.Arena session = java.lang.foreign.Arena.ofConfined()) {
java.lang.foreign.MemorySegment str = session.allocateFrom(title);
SetConsoleTitleW(str);
}
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.org.jline.terminal.impl.jna;
@SuppressWarnings("serial")
public class LastErrorException extends RuntimeException{
public final long lastError;
public LastErrorException(long lastError) {
this.lastError = lastError;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -34,4 +34,7 @@ public interface Pty extends Closeable {
void setSize(Size size) throws IOException;
SystemStream getSystemStream();
TerminalProvider getProvider();
}

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2023, 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 jdk.internal.org.jline.terminal.spi;
public enum SystemStream {
Input,
Output,
Error
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023, 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 jdk.internal.org.jline.terminal.spi;
import jdk.internal.org.jline.terminal.Terminal;
/**
* The {@code TerminalExt} interface is implemented by {@code Terminal}s
* and provides access to the Terminal's internals.
*/
public interface TerminalExt extends Terminal {
/**
* Returns the {@code TerminalProvider} that created this terminal
* or {@code null} if the terminal was created with no provider.
*/
TerminalProvider getProvider();
/**
* The underlying system stream, may be {@link SystemStream#Output},
* {@link SystemStream#Error}, or {@code null} if this terminal is not bound
* to a system stream.
*/
SystemStream getSystemStream();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, the original author or authors.
* Copyright (c) 2022, 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.
@ -11,58 +11,60 @@ package jdk.internal.org.jline.terminal.spi;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.impl.exec.ExecTerminalProvider;
import jdk.internal.org.jline.terminal.impl.ffm.FfmTerminalProvider;
public interface TerminalProvider
{
enum Stream {
Input,
Output,
Error
}
public interface TerminalProvider {
String name();
Terminal sysTerminal(String name, String type, boolean ansiPassThrough,
Charset encoding, boolean nativeSignals,
Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException;
Terminal sysTerminal(
String name,
String type,
boolean ansiPassThrough,
Charset encoding,
boolean nativeSignals,
Terminal.SignalHandler signalHandler,
boolean paused,
SystemStream systemStream,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException;
Terminal newTerminal(String name, String type,
InputStream masterInput, OutputStream masterOutput,
Charset encoding, Terminal.SignalHandler signalHandler,
boolean paused, Attributes attributes, Size size) throws IOException;
Terminal newTerminal(
String name,
String type,
InputStream masterInput,
OutputStream masterOutput,
Charset encoding,
Terminal.SignalHandler signalHandler,
boolean paused,
Attributes attributes,
Size size)
throws IOException;
boolean isSystemStream(Stream stream);
boolean isSystemStream(SystemStream stream);
String systemStreamName(Stream stream);
String systemStreamName(SystemStream stream);
int systemStreamWidth(SystemStream stream);
static TerminalProvider load(String name) throws IOException {
switch (name) {
case "exec": return new ExecTerminalProvider();
case "jna": {
try {
return (TerminalProvider) Class.forName("jdk.internal.org.jline.terminal.impl.jna.JnaTerminalProvider").getConstructor().newInstance();
} catch (ReflectiveOperationException t) {
throw new IOException(t);
}
}
case "ffm": return new FfmTerminalProvider();
}
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
InputStream is = cl.getResourceAsStream( "META-INF/services/org/jline/terminal/provider/" + name);
InputStream is = cl.getResourceAsStream("META-INF/services/org/jline/terminal/provider/" + name);
if (is != null) {
Properties props = new Properties();
try {
@ -71,14 +73,13 @@ public interface TerminalProvider
if (className == null) {
throw new IOException("No class defined in terminal provider file " + name);
}
Class<?> clazz = cl.loadClass( className );
Class<?> clazz = cl.loadClass(className);
return (TerminalProvider) clazz.getConstructor().newInstance();
} catch ( Exception e ) {
throw new IOException("Unable to load terminal provider " + name, e);
} catch (Exception e) {
throw new IOException("Unable to load terminal provider " + name + ": " + e.getMessage(), e);
}
} else {
throw new IOException("Unable to find terminal provider " + name);
}
}
}

View File

@ -1,17 +1,10 @@
/*
* Copyright (C) 2009-2018 the original author(s).
* Copyright (c) 2009-2018, the original author(s).
*
* 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
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* 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.
* https://opensource.org/licenses/BSD-3-Clause
*/
package jdk.internal.org.jline.utils;
@ -252,12 +245,10 @@ public class AnsiWriter extends FilterWriter {
* @throws IOException if no more non-null values left
*/
private int getNextOptionInt(Iterator<Object> optionsIterator) throws IOException {
for (;;) {
if (!optionsIterator.hasNext())
throw new IllegalArgumentException();
for (; ; ) {
if (!optionsIterator.hasNext()) throw new IllegalArgumentException();
Object arg = optionsIterator.next();
if (arg != null)
return (Integer) arg;
if (arg != null) return (Integer) arg;
}
}
@ -346,27 +337,21 @@ public class AnsiWriter extends FilterWriter {
int g = getNextOptionInt(optionsIterator);
int b = getNextOptionInt(optionsIterator);
if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
if (value == 38)
processSetForegroundColorExt(r, g, b);
else
processSetBackgroundColorExt(r, g, b);
if (value == 38) processSetForegroundColorExt(r, g, b);
else processSetBackgroundColorExt(r, g, b);
} else {
throw new IllegalArgumentException();
}
}
else if (arg2or5 == 5) {
} else if (arg2or5 == 5) {
// 256 color style like `esc[38;5;<index>m`
int paletteIndex = getNextOptionInt(optionsIterator);
if (paletteIndex >= 0 && paletteIndex <= 255) {
if (value == 38)
processSetForegroundColorExt(paletteIndex);
else
processSetBackgroundColorExt(paletteIndex);
if (value == 38) processSetForegroundColorExt(paletteIndex);
else processSetBackgroundColorExt(paletteIndex);
} else {
throw new IllegalArgumentException();
}
}
else {
} else {
throw new IllegalArgumentException();
}
} else {
@ -449,47 +434,41 @@ public class AnsiWriter extends FilterWriter {
* Process <code>CSI u</code> ANSI code, corresponding to <code>RCP \u2013 Restore Cursor Position</code>
* @throws IOException if an error occurs
*/
protected void processRestoreCursorPosition() throws IOException {
}
protected void processRestoreCursorPosition() throws IOException {}
/**
* Process <code>CSI s</code> ANSI code, corresponding to <code>SCP \u2013 Save Cursor Position</code>
* @throws IOException if an error occurs
*/
protected void processSaveCursorPosition() throws IOException {
}
protected void processSaveCursorPosition() throws IOException {}
/**
* Process <code>CSI s</code> ANSI code, corresponding to <code>IL \u2013 Insert Line</code>
* @param optionInt the option
* @throws IOException if an error occurs
*/
protected void processInsertLine(int optionInt) throws IOException {
}
protected void processInsertLine(int optionInt) throws IOException {}
/**
* Process <code>CSI s</code> ANSI code, corresponding to <code>DL \u2013 Delete Line</code>
* @param optionInt the option
* @throws IOException if an error occurs
*/
protected void processDeleteLine(int optionInt) throws IOException {
}
protected void processDeleteLine(int optionInt) throws IOException {}
/**
* Process <code>CSI n T</code> ANSI code, corresponding to <code>SD \u2013 Scroll Down</code>
* @param optionInt the option
* @throws IOException if an error occurs
*/
protected void processScrollDown(int optionInt) throws IOException {
}
protected void processScrollDown(int optionInt) throws IOException {}
/**
* Process <code>CSI n U</code> ANSI code, corresponding to <code>SU \u2013 Scroll Up</code>
* @param optionInt the option
* @throws IOException if an error occurs
*/
protected void processScrollUp(int optionInt) throws IOException {
}
protected void processScrollUp(int optionInt) throws IOException {}
protected static final int ERASE_SCREEN_TO_END = 0;
protected static final int ERASE_SCREEN_TO_BEGINING = 1;
@ -500,8 +479,7 @@ public class AnsiWriter extends FilterWriter {
* @param eraseOption the erase option
* @throws IOException if an error occurs
*/
protected void processEraseScreen(int eraseOption) throws IOException {
}
protected void processEraseScreen(int eraseOption) throws IOException {}
protected static final int ERASE_LINE_TO_END = 0;
protected static final int ERASE_LINE_TO_BEGINING = 1;
@ -512,25 +490,27 @@ public class AnsiWriter extends FilterWriter {
* @param eraseOption the erase option
* @throws IOException if an error occurs
*/
protected void processEraseLine(int eraseOption) throws IOException {
}
protected void processEraseLine(int eraseOption) throws IOException {}
protected static final int ATTRIBUTE_INTENSITY_BOLD = 1; // Intensity: Bold
protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; // Intensity; Faint not widely supported
protected static final int ATTRIBUTE_ITALIC = 3; // Italic; on not widely supported. Sometimes treated as inverse.
protected static final int ATTRIBUTE_UNDERLINE = 4; // Underline; Single
protected static final int ATTRIBUTE_BLINK_SLOW = 5; // Blink; Slow less than 150 per minute
protected static final int ATTRIBUTE_BLINK_FAST = 6; // Blink; Rapid MS-DOS ANSI.SYS; 150 per minute or more
protected static final int ATTRIBUTE_NEGATIVE_ON =
7; // Image; Negative inverse or reverse; swap foreground and background
protected static final int ATTRIBUTE_CONCEAL_ON = 8; // Conceal on
protected static final int ATTRIBUTE_UNDERLINE_DOUBLE = 21; // Underline; Double not widely supported
protected static final int ATTRIBUTE_INTENSITY_NORMAL = 22; // Intensity; Normal not bold and not faint
protected static final int ATTRIBUTE_UNDERLINE_OFF = 24; // Underline; None
protected static final int ATTRIBUTE_BLINK_OFF = 25; // Blink; off
protected static final int ATTRIBUTE_INTENSITY_BOLD = 1; // Intensity: Bold
protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; // Intensity; Faint not widely supported
protected static final int ATTRIBUTE_ITALIC = 3; // Italic; on not widely supported. Sometimes treated as inverse.
protected static final int ATTRIBUTE_UNDERLINE = 4; // Underline; Single
protected static final int ATTRIBUTE_BLINK_SLOW = 5; // Blink; Slow less than 150 per minute
protected static final int ATTRIBUTE_BLINK_FAST = 6; // Blink; Rapid MS-DOS ANSI.SYS; 150 per minute or more
protected static final int ATTRIBUTE_NEGATIVE_ON = 7; // Image; Negative inverse or reverse; swap foreground and background
protected static final int ATTRIBUTE_CONCEAL_ON = 8; // Conceal on
protected static final int ATTRIBUTE_UNDERLINE_DOUBLE = 21; // Underline; Double not widely supported
protected static final int ATTRIBUTE_INTENSITY_NORMAL = 22; // Intensity; Normal not bold and not faint
protected static final int ATTRIBUTE_UNDERLINE_OFF = 24; // Underline; None
protected static final int ATTRIBUTE_BLINK_OFF = 25; // Blink; off
@Deprecated
protected static final int ATTRIBUTE_NEGATIVE_Off = 27; // Image; Positive
protected static final int ATTRIBUTE_NEGATIVE_OFF = 27; // Image; Positive
protected static final int ATTRIBUTE_CONCEAL_OFF = 28; // Reveal conceal off
protected static final int ATTRIBUTE_CONCEAL_OFF = 28; // Reveal conceal off
/**
* process <code>SGR</code> other than <code>0</code> (reset), <code>30-39</code> (foreground),
@ -546,8 +526,7 @@ public class AnsiWriter extends FilterWriter {
* @see #processDefaultTextColor()
* @see #processDefaultBackgroundColor()
*/
protected void processSetAttribute(int attribute) throws IOException {
}
protected void processSetAttribute(int attribute) throws IOException {}
protected static final int BLACK = 0;
protected static final int RED = 1;
@ -584,8 +563,7 @@ public class AnsiWriter extends FilterWriter {
* @param paletteIndex the text color in the palette
* @throws IOException if an error occurs
*/
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
}
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {}
/**
* process <code>SGR 38</code> corresponding to <code>extended set text color (foreground)</code>
@ -625,8 +603,7 @@ public class AnsiWriter extends FilterWriter {
* @param paletteIndex the background color in the palette
* @throws IOException if an error occurs
*/
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
}
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {}
/**
* process <code>SGR 48</code> corresponding to <code>extended set background color</code>
@ -644,22 +621,19 @@ public class AnsiWriter extends FilterWriter {
* process <code>SGR 39</code> corresponding to <code>Default text color (foreground)</code>
* @throws IOException if an error occurs
*/
protected void processDefaultTextColor() throws IOException {
}
protected void processDefaultTextColor() throws IOException {}
/**
* process <code>SGR 49</code> corresponding to <code>Default background color</code>
* @throws IOException if an error occurs
*/
protected void processDefaultBackgroundColor() throws IOException {
}
protected void processDefaultBackgroundColor() throws IOException {}
/**
* process <code>SGR 0</code> corresponding to <code>Reset / Normal</code>
* @throws IOException if an error occurs
*/
protected void processAttributeRest() throws IOException {
}
protected void processAttributeRest() throws IOException {}
/**
* process <code>CSI n ; m H</code> corresponding to <code>CUP \u2013 Cursor Position</code> or
@ -668,24 +642,21 @@ public class AnsiWriter extends FilterWriter {
* @param col the column
* @throws IOException if an error occurs
*/
protected void processCursorTo(int row, int col) throws IOException {
}
protected void processCursorTo(int row, int col) throws IOException {}
/**
* process <code>CSI n G</code> corresponding to <code>CHA \u2013 Cursor Horizontal Absolute</code>
* @param x the column
* @throws IOException if an error occurs
*/
protected void processCursorToColumn(int x) throws IOException {
}
protected void processCursorToColumn(int x) throws IOException {}
/**
* process <code>CSI n F</code> corresponding to <code>CPL \u2013 Cursor Previous Line</code>
* @param count line count
* @throws IOException if an error occurs
*/
protected void processCursorUpLine(int count) throws IOException {
}
protected void processCursorUpLine(int count) throws IOException {}
/**
* process <code>CSI n E</code> corresponding to <code>CNL \u2013 Cursor Next Line</code>
@ -704,8 +675,7 @@ public class AnsiWriter extends FilterWriter {
* @param count the count
* @throws IOException if an error occurs
*/
protected void processCursorLeft(int count) throws IOException {
}
protected void processCursorLeft(int count) throws IOException {}
/**
* process <code>CSI n C</code> corresponding to <code>CUF \u2013 Cursor Forward</code>
@ -724,19 +694,16 @@ public class AnsiWriter extends FilterWriter {
* @param count the count
* @throws IOException if an error occurs
*/
protected void processCursorDown(int count) throws IOException {
}
protected void processCursorDown(int count) throws IOException {}
/**
* process <code>CSI n A</code> corresponding to <code>CUU \u2013 Cursor Up</code>
* @param count the count
* @throws IOException if an error occurs
*/
protected void processCursorUp(int count) throws IOException {
}
protected void processCursorUp(int count) throws IOException {}
protected void processUnknownExtension(ArrayList<Object> options, int command) {
}
protected void processUnknownExtension(ArrayList<Object> options, int command) {}
/**
* process <code>OSC 0;text BEL</code> corresponding to <code>Change Window and Icon label</code>
@ -751,23 +718,20 @@ public class AnsiWriter extends FilterWriter {
* process <code>OSC 1;text BEL</code> corresponding to <code>Change Icon label</code>
* @param name the icon name
*/
protected void processChangeIconName(String name) {
}
protected void processChangeIconName(String name) {}
/**
* process <code>OSC 2;text BEL</code> corresponding to <code>Change Window title</code>
* @param title the title
*/
protected void processChangeWindowTitle(String title) {
}
protected void processChangeWindowTitle(String title) {}
/**
* Process unknown <code>OSC</code> command.
* @param command the command
* @param param the param
*/
protected void processUnknownOperatingSystemCommand(int command, String param) {
}
protected void processUnknownOperatingSystemCommand(int command, String param) {}
/**
* Process character set sequence.
@ -781,17 +745,13 @@ public class AnsiWriter extends FilterWriter {
return true;
}
protected void processCharsetSelect(int set, char seq) {
}
protected void processCharsetSelect(int set, char seq) {}
private int optionInt(ArrayList<Object> options, int index) {
if (options.size() <= index)
throw new IllegalArgumentException();
if (options.size() <= index) throw new IllegalArgumentException();
Object value = options.get(index);
if (value == null)
throw new IllegalArgumentException();
if (!value.getClass().equals(Integer.class))
throw new IllegalArgumentException();
if (value == null) throw new IllegalArgumentException();
if (!value.getClass().equals(Integer.class)) throw new IllegalArgumentException();
return (Integer) value;
}
@ -828,5 +788,4 @@ public class AnsiWriter extends FilterWriter {
flush();
super.close();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -15,6 +15,7 @@ import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
import jdk.internal.org.jline.utils.InfoCmp.Capability;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTERNATE_CHARSET;
import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR;
import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR_EXP;
import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR;
@ -30,12 +31,11 @@ import static jdk.internal.org.jline.utils.AttributedStyle.F_FAINT;
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND;
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_IND;
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_RGB;
import static jdk.internal.org.jline.utils.AttributedStyle.F_HIDDEN;
import static jdk.internal.org.jline.utils.AttributedStyle.F_INVERSE;
import static jdk.internal.org.jline.utils.AttributedStyle.F_ITALIC;
import static jdk.internal.org.jline.utils.AttributedStyle.F_UNDERLINE;
import static jdk.internal.org.jline.utils.AttributedStyle.F_HIDDEN;
import static jdk.internal.org.jline.utils.AttributedStyle.MASK;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTERNATE_CHARSET;
public abstract class AttributedCharSequence implements CharSequence {
@ -120,6 +120,7 @@ public abstract class AttributedCharSequence implements CharSequence {
char c = charAt(i);
if (altIn != null && altOut != null) {
char pc = c;
// @spotless:off
switch (c) {
case '\u2518': c = 'j'; break;
case '\u2510': c = 'k'; break;
@ -133,15 +134,16 @@ public abstract class AttributedCharSequence implements CharSequence {
case '\u252C': c = 'w'; break;
case '\u2502': c = 'x'; break;
}
// @spotless:on
boolean oldalt = alt;
alt = c != pc;
if (oldalt ^ alt) {
sb.append(alt ? altIn : altOut);
}
}
long s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles
long s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles
if (style != s) {
long d = (style ^ s) & MASK;
long d = (style ^ s) & MASK;
long fg = (s & F_FOREGROUND) != 0 ? s & (FG_COLOR | F_FOREGROUND) : 0;
long bg = (s & F_BACKGROUND) != 0 ? s & (BG_COLOR | F_BACKGROUND) : 0;
if (s == 0) {
@ -172,16 +174,16 @@ public abstract class AttributedCharSequence implements CharSequence {
if (fg > 0) {
int rounded = -1;
if ((fg & F_FOREGROUND_RGB) != 0) {
int r = (int)(fg >> (FG_COLOR_EXP + 16)) & 0xFF;
int g = (int)(fg >> (FG_COLOR_EXP + 8)) & 0xFF;
int b = (int)(fg >> FG_COLOR_EXP) & 0xFF;
int r = (int) (fg >> (FG_COLOR_EXP + 16)) & 0xFF;
int g = (int) (fg >> (FG_COLOR_EXP + 8)) & 0xFF;
int b = (int) (fg >> FG_COLOR_EXP) & 0xFF;
if (colors >= HIGH_COLORS) {
first = attr(sb, "38;2;" + r + ";" + g + ";" + b, first);
} else {
rounded = palette.round(r, g, b);
}
} else if ((fg & F_FOREGROUND_IND) != 0) {
rounded = palette.round((int)(fg >> FG_COLOR_EXP) & 0xFF);
rounded = palette.round((int) (fg >> FG_COLOR_EXP) & 0xFF);
}
if (rounded >= 0) {
if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) {
@ -211,16 +213,16 @@ public abstract class AttributedCharSequence implements CharSequence {
if (bg > 0) {
int rounded = -1;
if ((bg & F_BACKGROUND_RGB) != 0) {
int r = (int)(bg >> (BG_COLOR_EXP + 16)) & 0xFF;
int g = (int)(bg >> (BG_COLOR_EXP + 8)) & 0xFF;
int b = (int)(bg >> BG_COLOR_EXP) & 0xFF;
int r = (int) (bg >> (BG_COLOR_EXP + 16)) & 0xFF;
int g = (int) (bg >> (BG_COLOR_EXP + 8)) & 0xFF;
int b = (int) (bg >> BG_COLOR_EXP) & 0xFF;
if (colors >= HIGH_COLORS) {
first = attr(sb, "48;2;" + r + ";" + g + ";" + b, first);
} else {
rounded = palette.round(r, g, b);
}
} else if ((bg & F_BACKGROUND_IND) != 0) {
rounded = palette.round((int)(bg >> BG_COLOR_EXP) & 0xFF);
rounded = palette.round((int) (bg >> BG_COLOR_EXP) & 0xFF);
}
if (rounded >= 0) {
if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) {
@ -243,8 +245,7 @@ public abstract class AttributedCharSequence implements CharSequence {
background = bg;
}
if ((d & (F_BOLD | F_FAINT)) != 0) {
if ( (d & F_BOLD) != 0 && (s & F_BOLD) == 0
|| (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
if ((d & F_BOLD) != 0 && (s & F_BOLD) == 0 || (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
first = attr(sb, "22", first);
}
if ((d & F_BOLD) != 0 && (s & F_BOLD) != 0) {
@ -360,8 +361,7 @@ public abstract class AttributedCharSequence implements CharSequence {
int len = length();
for (int cur = 0; cur < len; ) {
int cp = codePointAt(cur);
if (!isHidden(cur))
cols += WCWidth.wcwidth(cp);
if (!isHidden(cur)) cols += WCWidth.wcwidth(cp);
cur += Character.charCount(cp);
}
return cols;
@ -382,8 +382,7 @@ public abstract class AttributedCharSequence implements CharSequence {
int end = begin;
while (end < this.length()) {
int cp = codePointAt(end);
if (cp == '\n')
break;
if (cp == '\n') break;
int w = isHidden(end) ? 0 : WCWidth.wcwidth(cp);
if (col + w > stop) {
break;
@ -407,7 +406,7 @@ public abstract class AttributedCharSequence implements CharSequence {
int cp = codePointAt(cur);
int w = isHidden(cur) ? 0 : WCWidth.wcwidth(cp);
if (cp == '\n') {
strings.add(subSequence(beg, includeNewlines ? cur+1 : cur));
strings.add(subSequence(beg, includeNewlines ? cur + 1 : cur));
beg = cur + 1;
col = 0;
} else if ((col += w) > columns) {
@ -429,5 +428,4 @@ public abstract class AttributedCharSequence implements CharSequence {
public AttributedString toAttributedString() {
return substring(0, length());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -15,6 +15,8 @@ import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jdk.internal.org.jline.terminal.Terminal;
/**
* Attributed string.
* Instances of this class are immutables.
@ -103,11 +105,28 @@ public class AttributedString extends AttributedCharSequence {
}
public static AttributedString fromAnsi(String ansi, List<Integer> tabs) {
return fromAnsi(ansi, tabs, null, null);
}
public static AttributedString fromAnsi(String ansi, Terminal terminal) {
String alternateIn, alternateOut;
if (!DISABLE_ALTERNATE_CHARSET) {
alternateIn = Curses.tputs(terminal.getStringCapability(InfoCmp.Capability.enter_alt_charset_mode));
alternateOut = Curses.tputs(terminal.getStringCapability(InfoCmp.Capability.exit_alt_charset_mode));
} else {
alternateIn = null;
alternateOut = null;
}
return fromAnsi(ansi, Arrays.asList(0), alternateIn, alternateOut);
}
public static AttributedString fromAnsi(String ansi, List<Integer> tabs, String altIn, String altOut) {
if (ansi == null) {
return null;
}
return new AttributedStringBuilder(ansi.length())
.tabs(tabs)
.altCharset(altIn, altOut)
.ansiAppend(ansi)
.toAttributedString();
}
@ -116,9 +135,7 @@ public class AttributedString extends AttributedCharSequence {
if (ansi == null) {
return null;
}
return new AttributedStringBuilder(ansi.length())
.ansiAppend(ansi)
.toString();
return new AttributedStringBuilder(ansi.length()).ansiAppend(ansi).toString();
}
@Override
@ -162,7 +179,7 @@ public class AttributedString extends AttributedCharSequence {
}
result = matcher.find();
} while (result);
return new AttributedString(buffer, newstyle, start , end);
return new AttributedString(buffer, newstyle, start, end);
}
return this;
}
@ -179,15 +196,16 @@ public class AttributedString extends AttributedCharSequence {
private boolean arrEq(char[] a1, char[] a2, int s1, int s2, int l) {
for (int i = 0; i < l; i++) {
if (a1[s1+i] != a2[s2+i]) {
if (a1[s1 + i] != a2[s2 + i]) {
return false;
}
}
return true;
}
private boolean arrEq(long[] a1, long[] a2, int s1, int s2, int l) {
for (int i = 0; i < l; i++) {
if (a1[s1+i] != a2[s2+i]) {
if (a1[s1 + i] != a2[s2 + i]) {
return false;
}
}
@ -221,5 +239,4 @@ public class AttributedString extends AttributedCharSequence {
}
return sb.toAttributedString();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2018, 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.
@ -27,6 +27,9 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
private long[] style;
private int length;
private TabStops tabs = new TabStops(0);
private char[] altIn;
private char[] altOut;
private boolean inAltCharset;
private int lastLineLength = 0;
private AttributedStyle current = AttributedStyle.DEFAULT;
@ -81,10 +84,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
@Override
public AttributedString subSequence(int start, int end) {
return new AttributedString(
Arrays.copyOfRange(buffer, start, end),
Arrays.copyOfRange(style, start, end),
0,
end - start);
Arrays.copyOfRange(buffer, start, end), Arrays.copyOfRange(style, start, end), 0, end - start);
}
@Override
@ -108,6 +108,14 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return append(Character.toString(c));
}
public AttributedStringBuilder append(char c, int repeat) {
AttributedString s = new AttributedString(Character.toString(c), current);
while (repeat-- > 0) {
append(s);
}
return this;
}
public AttributedStringBuilder append(CharSequence csq, AttributedStyle style) {
return append(new AttributedString(csq, style));
}
@ -117,12 +125,12 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return this;
}
public AttributedStringBuilder style(Function<AttributedStyle,AttributedStyle> style) {
public AttributedStringBuilder style(Function<AttributedStyle, AttributedStyle> style) {
current = style.apply(current);
return this;
}
public AttributedStringBuilder styled(Function<AttributedStyle,AttributedStyle> style, CharSequence cs) {
public AttributedStringBuilder styled(Function<AttributedStyle, AttributedStyle> style, CharSequence cs) {
return styled(style, sb -> sb.append(cs));
}
@ -130,7 +138,8 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return styled(s -> style, sb -> sb.append(cs));
}
public AttributedStringBuilder styled(Function<AttributedStyle,AttributedStyle> style, Consumer<AttributedStringBuilder> consumer) {
public AttributedStringBuilder styled(
Function<AttributedStyle, AttributedStyle> style, Consumer<AttributedStringBuilder> consumer) {
AttributedStyle prev = current;
current = style.apply(prev);
consumer.accept(this);
@ -338,23 +347,90 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
// This is not a SGR code, so ignore
ansiState = 0;
}
} else if (c == '\t' && tabs.defined()) {
insertTab(current);
} else {
ensureCapacity(length + 1);
buffer[length] = c;
style[length] = this.current.getStyle();
if (c == '\n') {
lastLineLength = 0;
} else {
lastLineLength++;
if (ansiState >= 1) {
ensureCapacity(length + 1);
buffer[length++] = 27;
if (ansiState >= 2) {
ensureCapacity(length + 1);
buffer[length++] = '[';
}
ansiState = 0;
}
if (c == '\t' && tabs.defined()) {
insertTab(current);
} else {
ensureCapacity(length + 1);
if (inAltCharset) {
switch (c) {
case 'j':
c = '\u2518';
break;
case 'k':
c = '\u2510';
break;
case 'l':
c = '\u250C';
break;
case 'm':
c = '\u2514';
break;
case 'n':
c = '\u253C';
break;
case 'q':
c = '\u2500';
break;
case 't':
c = '\u251C';
break;
case 'u':
c = '\u2524';
break;
case 'v':
c = '\u2534';
break;
case 'w':
c = '\u252C';
break;
case 'x':
c = '\u2502';
break;
}
}
buffer[length] = c;
style[length] = this.current.getStyle();
if (c == '\n') {
lastLineLength = 0;
} else {
lastLineLength++;
}
length++;
if (altIn != null && altOut != null) {
char[] alt = inAltCharset ? altOut : altIn;
if (equals(buffer, length - alt.length, alt, 0, alt.length)) {
inAltCharset = !inAltCharset;
length -= alt.length;
}
}
}
length++;
}
}
return this;
}
private static boolean equals(char[] a, int aFromIndex, char[] b, int bFromIndex, int length) {
if (aFromIndex < 0 || bFromIndex < 0 || aFromIndex + length > a.length || bFromIndex + length > b.length) {
return false;
}
for (int i = 0; i < length; i++) {
if (a[aFromIndex + i] != b[bFromIndex + i]) {
return false;
}
}
return true;
}
protected void insertTab(AttributedStyle s) {
int nb = tabs.spaces(lastLineLength);
ensureCapacity(length + nb);
@ -393,6 +469,15 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return this;
}
public AttributedStringBuilder altCharset(String altIn, String altOut) {
if (length > 0) {
throw new IllegalStateException("Cannot change alternative charset after appending text");
}
this.altIn = altIn != null ? altIn.toCharArray() : null;
this.altOut = altOut != null ? altOut.toCharArray() : null;
return this;
}
public AttributedStringBuilder styleMatches(Pattern pattern, AttributedStyle s) {
Matcher matcher = pattern.matcher(this);
while (matcher.find()) {
@ -416,7 +501,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return this;
}
private class TabStops {
private static class TabStops {
private List<Integer> tabs = new ArrayList<>();
private int lastStop = 0;
private int lastSize = 0;
@ -428,7 +513,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
public TabStops(List<Integer> tabs) {
this.tabs = tabs;
int p = 0;
for (int s: tabs) {
for (int s : tabs) {
if (s <= p) {
continue;
}
@ -447,7 +532,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
if (lastLineLength >= lastStop) {
out = lastSize - (lastLineLength - lastStop) % lastSize;
} else {
for (int s: tabs) {
for (int s : tabs) {
if (s > lastLineLength) {
out = s - lastLineLength;
break;
@ -456,7 +541,5 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
}
return out;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2021, the original author or authors.
* Copyright (c) 2002-2021, 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.
@ -15,39 +15,39 @@ package jdk.internal.org.jline.utils;
*/
public class AttributedStyle {
public static final int BLACK = 0;
public static final int RED = 1;
public static final int GREEN = 2;
public static final int YELLOW = 3;
public static final int BLUE = 4;
public static final int MAGENTA = 5;
public static final int CYAN = 6;
public static final int WHITE = 7;
public static final int BLACK = 0;
public static final int RED = 1;
public static final int GREEN = 2;
public static final int YELLOW = 3;
public static final int BLUE = 4;
public static final int MAGENTA = 5;
public static final int CYAN = 6;
public static final int WHITE = 7;
public static final int BRIGHT = 8;
public static final int BRIGHT = 8;
static final long F_BOLD = 0x00000001;
static final long F_FAINT = 0x00000002;
static final long F_ITALIC = 0x00000004;
static final long F_UNDERLINE = 0x00000008;
static final long F_BLINK = 0x00000010;
static final long F_INVERSE = 0x00000020;
static final long F_CONCEAL = 0x00000040;
static final long F_CROSSED_OUT = 0x00000080;
static final long F_FOREGROUND_IND = 0x00000100;
static final long F_FOREGROUND_RGB = 0x00000200;
static final long F_FOREGROUND = F_FOREGROUND_IND | F_FOREGROUND_RGB;
static final long F_BACKGROUND_IND = 0x00000400;
static final long F_BACKGROUND_RGB = 0x00000800;
static final long F_BACKGROUND = F_BACKGROUND_IND | F_BACKGROUND_RGB;
static final long F_HIDDEN = 0x00001000;
static final long F_BOLD = 0x00000001;
static final long F_FAINT = 0x00000002;
static final long F_ITALIC = 0x00000004;
static final long F_UNDERLINE = 0x00000008;
static final long F_BLINK = 0x00000010;
static final long F_INVERSE = 0x00000020;
static final long F_CONCEAL = 0x00000040;
static final long F_CROSSED_OUT = 0x00000080;
static final long F_FOREGROUND_IND = 0x00000100;
static final long F_FOREGROUND_RGB = 0x00000200;
static final long F_FOREGROUND = F_FOREGROUND_IND | F_FOREGROUND_RGB;
static final long F_BACKGROUND_IND = 0x00000400;
static final long F_BACKGROUND_RGB = 0x00000800;
static final long F_BACKGROUND = F_BACKGROUND_IND | F_BACKGROUND_RGB;
static final long F_HIDDEN = 0x00001000;
static final long MASK = 0x00001FFF;
static final long MASK = 0x00001FFF;
static final int FG_COLOR_EXP = 15;
static final int BG_COLOR_EXP = 39;
static final long FG_COLOR = 0xFFFFFFL << FG_COLOR_EXP;
static final long BG_COLOR = 0xFFFFFFL << BG_COLOR_EXP;
static final int FG_COLOR_EXP = 15;
static final int BG_COLOR_EXP = 39;
static final long FG_COLOR = 0xFFFFFFL << FG_COLOR_EXP;
static final long BG_COLOR = 0xFFFFFFL << BG_COLOR_EXP;
public static final AttributedStyle DEFAULT = new AttributedStyle();
public static final AttributedStyle BOLD = DEFAULT.bold();
@ -70,8 +70,9 @@ public class AttributedStyle {
public AttributedStyle(long style, long mask) {
this.style = style;
this.mask = mask & MASK | ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0)
| ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0);
this.mask = mask & MASK
| ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0)
| ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0);
}
public AttributedStyle bold() {
@ -176,7 +177,9 @@ public class AttributedStyle {
}
public AttributedStyle foreground(int color) {
return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND_IND | (((long) color << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND_IND);
return new AttributedStyle(
style & ~FG_COLOR | F_FOREGROUND_IND | (((long) color << FG_COLOR_EXP) & FG_COLOR),
mask | F_FOREGROUND_IND);
}
public AttributedStyle foreground(int r, int g, int b) {
@ -184,7 +187,9 @@ public class AttributedStyle {
}
public AttributedStyle foregroundRgb(int color) {
return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND_RGB | ((((long) color & 0xFFFFFF) << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND_RGB);
return new AttributedStyle(
style & ~FG_COLOR | F_FOREGROUND_RGB | ((((long) color & 0xFFFFFF) << FG_COLOR_EXP) & FG_COLOR),
mask | F_FOREGROUND_RGB);
}
public AttributedStyle foregroundOff() {
@ -196,7 +201,9 @@ public class AttributedStyle {
}
public AttributedStyle background(int color) {
return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND_IND | (((long) color << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND_IND);
return new AttributedStyle(
style & ~BG_COLOR | F_BACKGROUND_IND | (((long) color << BG_COLOR_EXP) & BG_COLOR),
mask | F_BACKGROUND_IND);
}
public AttributedStyle background(int r, int g, int b) {
@ -204,7 +211,9 @@ public class AttributedStyle {
}
public AttributedStyle backgroundRgb(int color) {
return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND_RGB | ((((long) color & 0xFFFFFF) << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND_RGB);
return new AttributedStyle(
style & ~BG_COLOR | F_BACKGROUND_RGB | ((((long) color & 0xFFFFFF) << BG_COLOR_EXP) & BG_COLOR),
mask | F_BACKGROUND_RGB);
}
public AttributedStyle backgroundOff() {
@ -249,7 +258,6 @@ public class AttributedStyle {
AttributedStyle that = (AttributedStyle) o;
if (style != that.style) return false;
return mask == that.mask;
}
@Override
@ -266,10 +274,6 @@ public class AttributedStyle {
@Override
public String toString() {
return "AttributedStyle{" +
"style=" + style +
", mask=" + mask +
", ansi=" + toAnsi() +
'}';
return "AttributedStyle{" + "style=" + style + ", mask=" + mask + ", ansi=" + toAnsi() + '}';
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2016, the original author or authors.
* Copyright (c) 2002-2016, 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.
@ -14,8 +14,7 @@ public class ClosedException extends IOException {
private static final long serialVersionUID = 3085420657077696L;
public ClosedException() {
}
public ClosedException() {}
public ClosedException(String message) {
super(message);

Some files were not shown because too many files have changed in this diff Show More