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.dynalink \
jdk.httpserver \ jdk.httpserver \
jdk.incubator.vector \ jdk.incubator.vector \
jdk.internal.le \
jdk.internal.vm.ci \ jdk.internal.vm.ci \
jdk.jfr \ jdk.jfr \
jdk.jsobject \ 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -66,7 +66,7 @@ public class BindingReader {
T o = null; T o = null;
int[] remaining = new int[1]; int[] remaining = new int[1];
boolean hasRead = false; boolean hasRead = false;
for (;;) { for (; ; ) {
if (local != null) { if (local != null) {
o = local.getBound(opBuffer, remaining); o = local.getBound(opBuffer, remaining);
} }
@ -78,8 +78,7 @@ public class BindingReader {
if (remaining[0] >= 0) { if (remaining[0] >= 0) {
runMacro(opBuffer.substring(opBuffer.length() - remaining[0])); runMacro(opBuffer.substring(opBuffer.length() - remaining[0]));
opBuffer.setLength(opBuffer.length() - remaining[0]); opBuffer.setLength(opBuffer.length() - remaining[0]);
} } else {
else {
long ambiguousTimeout = keys.getAmbiguousTimeout(); long ambiguousTimeout = keys.getAmbiguousTimeout();
if (ambiguousTimeout > 0 && peekCharacter(ambiguousTimeout) != NonBlockingReader.READ_EXPIRED) { if (ambiguousTimeout > 0 && peekCharacter(ambiguousTimeout) != NonBlockingReader.READ_EXPIRED) {
o = null; o = null;
@ -234,5 +233,4 @@ public class BindingReader {
public String getLastBinding() { public String getLastBinding() {
return lastBinding; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,8 +8,6 @@
*/ */
package jdk.internal.org.jline.keymap; package jdk.internal.org.jline.keymap;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator; import java.util.Comparator;
@ -218,7 +216,6 @@ public class KeyMap<T> {
return seqs; return seqs;
} }
public static String esc() { public static String esc() {
return "\033"; return "\033";
} }
@ -264,7 +261,6 @@ public class KeyMap<T> {
// Methods // Methods
// //
public T getUnicode() { public T getUnicode() {
return unicode; return unicode;
} }
@ -306,9 +302,7 @@ public class KeyMap<T> {
} }
for (int c = 0; c < keyMap.mapping.length; c++) { for (int c = 0; c < keyMap.mapping.length; c++) {
if (keyMap.mapping[c] instanceof KeyMap) { if (keyMap.mapping[c] instanceof KeyMap) {
doGetBoundKeys((KeyMap<T>) keyMap.mapping[c], doGetBoundKeys((KeyMap<T>) keyMap.mapping[c], prefix + (char) (c), bound);
prefix + (char) (c),
bound);
} else if (keyMap.mapping[c] != null) { } else if (keyMap.mapping[c] != null) {
bound.put(prefix + (char) (c), (T) keyMap.mapping[c]); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -14,9 +14,8 @@ package jdk.internal.org.jline.reader;
* @see Macro * @see Macro
* @see Reference * @see Reference
* @see Widget * @see Widget
* @see jdk.internal.org.jline.keymap.KeyMap * @see org.jline.keymap.KeyMap
* *
* @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a> * @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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -84,8 +84,8 @@ public interface Buffer {
void copyFrom(Buffer buffer); void copyFrom(Buffer buffer);
// JDK specific modification /**
default void zeroOut() { * Clear any internal buffer.
throw new UnsupportedOperationException(); */
} 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 complete the complete flag
* @param sort the sort 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.value = Objects.requireNonNull(value);
this.displ = Objects.requireNonNull(displ); this.displ = Objects.requireNonNull(displ);
this.group = group; this.group = group;
@ -69,7 +77,8 @@ public class Candidate implements Comparable<Candidate> {
* @param key the key * @param key the key
* @param complete the complete flag * @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); this(value, displ, group, descr, suffix, key, complete, 0);
} }
@ -159,11 +168,10 @@ public class Candidate implements Comparable<Candidate> {
return sort; return sort;
} }
@Override @Override
public int compareTo(Candidate o) { public int compareTo(Candidate o) {
// If both candidates have same sort, use default behavior // If both candidates have same sort, use default behavior
if( sort == o.sort() ) { if (sort == o.sort()) {
return value.compareTo(o.value); return value.compareTo(o.value);
} else { } else {
return Integer.compare(sort, o.sort()); return Integer.compare(sort, o.sort());
@ -180,7 +188,7 @@ public class Candidate implements Comparable<Candidate> {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(value); return Objects.hashCode(value);
} }
@Override @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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
* @since 2.3 * @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>. * 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 * 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. * should be escaped/quoted.
* *
* @author Eric Bottard * @author Eric Bottard
@ -22,5 +22,4 @@ public interface CompletingParsedLine extends ParsedLine {
int rawWordCursor(); int rawWordCursor();
int rawWordLength(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 errors number of errors accepted in matching
* @param originalGroupName value of JLineReader variable original-group-name * @param originalGroupName value of JLineReader variable original-group-name
*/ */
void compile(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line void compile(
, boolean caseInsensitive, int errors, String originalGroupName); 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 * @return a common prefix of matched candidates
*/ */
String getCommonPrefix(); String getCommonPrefix();
} }

View File

@ -1,20 +1,10 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one * Copyright (c) 2023, the original author(s).
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * 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, * https://opensource.org/licenses/BSD-3-Clause
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/ */
package jdk.internal.org.jline.reader; package jdk.internal.org.jline.reader;
@ -45,7 +35,7 @@ public class EOFError extends SyntaxError {
return missing; return missing;
} }
public int getOpenBrackets(){ public int getOpenBrackets() {
return openBrackets; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -13,6 +13,8 @@ import java.util.List;
public interface Editor { public interface Editor {
public void open(List<String> files) throws IOException; public void open(List<String> files) throws IOException;
public void run() throws IOException; public void run() throws IOException;
public void setRestricted(boolean restricted); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 static final long serialVersionUID = 528485360925144689L;
private String partialLine; private String partialLine;
public EndOfFileException() { public EndOfFileException() {}
}
public EndOfFileException(String message) { public EndOfFileException(String message) {
super(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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -13,5 +13,4 @@ public interface Expander {
String expandHistory(History history, String line); String expandHistory(History history, String line);
String expandVar(String word); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @since 2.3
*/ */
public interface History extends Iterable<History.Entry> public interface History extends Iterable<History.Entry> {
{
/** /**
* Initialize the history for the given reader. * Initialize the history for the given reader.
@ -75,7 +74,6 @@ public interface History extends Iterable<History.Entry>
*/ */
void purge() throws IOException; void purge() throws IOException;
int size(); int size();
default boolean isEmpty() { default boolean isEmpty() {
@ -110,8 +108,7 @@ public interface History extends Iterable<History.Entry>
// Entries // Entries
// //
interface Entry interface Entry {
{
int index(); int index();
Instant time(); Instant time();
@ -132,14 +129,17 @@ public interface History extends Iterable<History.Entry>
default Iterator<Entry> reverseIterator(int index) { default Iterator<Entry> reverseIterator(int index) {
return new Iterator<Entry>() { return new Iterator<Entry>() {
private final ListIterator<Entry> it = iterator(index + 1); private final ListIterator<Entry> it = iterator(index + 1);
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return it.hasPrevious(); return it.hasPrevious();
} }
@Override @Override
public Entry next() { public Entry next() {
return it.previous(); return it.previous();
} }
@Override @Override
public void remove() { public void remove() {
it.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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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. /** 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, * The <code>LineReader</code> implementations are not thread safe,
* thus you should not attempt to use a single reader in several threads. * 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 * 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 * {@link #printAbove(String)} or {@link #printAbove(AttributedString)} at
* any time to allow text to be printed above the current prompt. * 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 * It is traditional for an interactive console-based program
* to print a short prompt string to signal that the user is expected * to print a short prompt string to signal that the user is expected
* to type a command. JLine supports 3 kinds of prompt string: * to type a command. JLine supports 3 kinds of prompt string:
@ -81,7 +81,6 @@ import jdk.internal.org.jline.utils.AttributedString;
* </dd> * </dd>
* </dl> * </dl>
*/ */
public interface LineReader { public interface LineReader {
/** /**
@ -284,6 +283,7 @@ public interface LineReader {
String MAIN = "main"; String MAIN = "main";
String EMACS = "emacs"; String EMACS = "emacs";
String SAFE = ".safe"; String SAFE = ".safe";
String DUMB = "dumb";
String MENU = "menu"; String MENU = "menu";
// //
@ -301,6 +301,7 @@ public interface LineReader {
* they are displayed in a list below the field to be completed * they are displayed in a list below the field to be completed
*/ */
String MENU_LIST_MAX = "menu-list-max"; String MENU_LIST_MAX = "menu-list-max";
String DISABLE_HISTORY = "disable-history"; String DISABLE_HISTORY = "disable-history";
String DISABLE_COMPLETION = "disable-completion"; String DISABLE_COMPLETION = "disable-completion";
String EDITING_MODE = "editing-mode"; String EDITING_MODE = "editing-mode";
@ -317,18 +318,23 @@ public interface LineReader {
String ORIGINAL_GROUP_NAME = "ORIGINAL_GROUP_NAME"; String ORIGINAL_GROUP_NAME = "ORIGINAL_GROUP_NAME";
/** Completion style for displaying groups name */ /** Completion style for displaying groups name */
String COMPLETION_STYLE_GROUP = "COMPLETION_STYLE_GROUP"; String COMPLETION_STYLE_GROUP = "COMPLETION_STYLE_GROUP";
String COMPLETION_STYLE_LIST_GROUP = "COMPLETION_STYLE_LIST_GROUP"; String COMPLETION_STYLE_LIST_GROUP = "COMPLETION_STYLE_LIST_GROUP";
/** Completion style for displaying the current selected item */ /** Completion style for displaying the current selected item */
String COMPLETION_STYLE_SELECTION = "COMPLETION_STYLE_SELECTION"; String COMPLETION_STYLE_SELECTION = "COMPLETION_STYLE_SELECTION";
String COMPLETION_STYLE_LIST_SELECTION = "COMPLETION_STYLE_LIST_SELECTION"; String COMPLETION_STYLE_LIST_SELECTION = "COMPLETION_STYLE_LIST_SELECTION";
/** Completion style for displaying the candidate description */ /** Completion style for displaying the candidate description */
String COMPLETION_STYLE_DESCRIPTION = "COMPLETION_STYLE_DESCRIPTION"; String COMPLETION_STYLE_DESCRIPTION = "COMPLETION_STYLE_DESCRIPTION";
String COMPLETION_STYLE_LIST_DESCRIPTION = "COMPLETION_STYLE_LIST_DESCRIPTION"; String COMPLETION_STYLE_LIST_DESCRIPTION = "COMPLETION_STYLE_LIST_DESCRIPTION";
/** Completion style for displaying the matching part of candidates */ /** Completion style for displaying the matching part of candidates */
String COMPLETION_STYLE_STARTING = "COMPLETION_STYLE_STARTING"; String COMPLETION_STYLE_STARTING = "COMPLETION_STYLE_STARTING";
String COMPLETION_STYLE_LIST_STARTING = "COMPLETION_STYLE_LIST_STARTING"; String COMPLETION_STYLE_LIST_STARTING = "COMPLETION_STYLE_LIST_STARTING";
/** Completion style for displaying the list */ /** Completion style for displaying the list */
String COMPLETION_STYLE_BACKGROUND = "COMPLETION_STYLE_BACKGROUND"; String COMPLETION_STYLE_BACKGROUND = "COMPLETION_STYLE_BACKGROUND";
String COMPLETION_STYLE_LIST_BACKGROUND = "COMPLETION_STYLE_LIST_BACKGROUND"; String COMPLETION_STYLE_LIST_BACKGROUND = "COMPLETION_STYLE_LIST_BACKGROUND";
/** /**
* Set the template for prompts for secondary (continuation) lines. * 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"; 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(); Map<String, KeyMap<Binding>> defaultKeyMaps();
enum Option { enum Option {
@ -469,8 +495,7 @@ public interface LineReader {
EMPTY_WORD_OPTIONS(true), EMPTY_WORD_OPTIONS(true),
/** Disable the undo feature */ /** Disable the undo feature */
DISABLE_UNDO DISABLE_UNDO;
;
private final boolean def; 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 EndOfFileException if an EOF has been found (using Ctrl-D for example)
* @throws java.io.IOError in case of other i/o errors * @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 * 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 EndOfFileException if an EOF has been found (using Ctrl-D for example)
* @throws java.io.IOError in case of other i/o errors * @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. * Prints a line above the prompt and redraw everything.
@ -702,7 +729,7 @@ public interface LineReader {
void runMacro(String macro); 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. * has just been read on the input stream.
* Compared to {@link Terminal#readMouseEvent()}, this method takes into account keys * Compared to {@link Terminal#readMouseEvent()}, this method takes into account keys
* that have been pushed back using {@link #runMacro(String)}. * that have been pushed back using {@link #runMacro(String)}.
@ -751,8 +778,8 @@ public interface LineReader {
SuggestionType getAutosuggestion(); SuggestionType getAutosuggestion();
// JDK specific modification /**
default void zeroOut() { * Clear any internal buffers.
throw new UnsupportedOperationException(); */
} 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -38,8 +38,7 @@ public final class LineReaderBuilder {
Expander expander; Expander expander;
CompletionMatcher completionMatcher; CompletionMatcher completionMatcher;
private LineReaderBuilder() { private LineReaderBuilder() {}
}
public LineReaderBuilder terminal(Terminal terminal) { public LineReaderBuilder terminal(Terminal terminal) {
this.terminal = terminal; this.terminal = terminal;
@ -88,8 +87,9 @@ public final class LineReaderBuilder {
try { try {
if (!Boolean.getBoolean(LineReader.PROP_SUPPORT_PARSEDLINE) if (!Boolean.getBoolean(LineReader.PROP_SUPPORT_PARSEDLINE)
&& !(parser.parse("", 0) instanceof CompletingParsedLine)) { && !(parser.parse("", 0) instanceof CompletingParsedLine)) {
Log.warn("The Parser of class " + parser.getClass().getName() + " does not support the CompletingParsedLine interface. " + Log.warn("The Parser of class " + parser.getClass().getName()
"Completion with escaped or quoted words won't work correctly."); + " does not support the CompletingParsedLine interface. "
+ "Completion with escaped or quoted words won't work correctly.");
} }
} catch (Throwable t) { } catch (Throwable t) {
// Ignore // Ignore
@ -153,5 +153,4 @@ public final class LineReaderBuilder {
} }
return reader; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -35,7 +35,6 @@ public class Macro implements Binding {
@Override @Override
public String toString() { public String toString() {
return "Macro[" + return "Macro[" + sequence + ']';
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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -31,5 +31,4 @@ public interface MaskingCallback {
* @return the modified line * @return the modified line
*/ */
String history(String 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -64,5 +64,4 @@ public interface ParsedLine {
* @return the cursor position within the line * @return the cursor position within the line
*/ */
int cursor(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.

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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -38,7 +38,6 @@ public class Reference implements Binding {
@Override @Override
public String toString() { public String toString() {
return "Reference[" + return "Reference[" + name + ']';
name + ']';
} }
} }

View File

@ -1,20 +1,10 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one * Copyright (c) 2023, the original author(s).
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * 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, * https://opensource.org/licenses/BSD-3-Clause
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/ */
package jdk.internal.org.jline.reader; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 * interrupt character (ctrl-C). The partially entered line is
* available via the {@link #getPartialLine()} method. * available via the {@link #getPartialLine()} method.
*/ */
public class UserInterruptException public class UserInterruptException extends RuntimeException {
extends RuntimeException
{
private static final long serialVersionUID = 6172232572140736750L; private static final long serialVersionUID = 6172232572140736750L;
private final String partialLine; private final String partialLine;
public UserInterruptException(String partialLine) public UserInterruptException(String partialLine) {
{
this.partialLine = partialLine; this.partialLine = partialLine;
} }
/** /**
* @return the partially entered line when ctrl-C was pressed * @return the partially entered line when ctrl-C was pressed
*/ */
public String getPartialLine() public String getPartialLine() {
{
return partialLine; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -15,5 +15,4 @@ package jdk.internal.org.jline.reader;
public interface Widget extends Binding { public interface Widget extends Binding {
boolean apply(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.0 * @since 2.0
*/ */
public class BufferImpl implements Buffer public class BufferImpl implements Buffer {
{
private int cursor = 0; private int cursor = 0;
private int cursorCol = -1; private int cursorCol = -1;
private int[] buffer; private int[] buffer;
@ -46,7 +45,7 @@ public class BufferImpl implements Buffer
this.g1 = buffer.g1; this.g1 = buffer.g1;
} }
public BufferImpl copy () { public BufferImpl copy() {
return new BufferImpl(this); return new BufferImpl(this);
} }
@ -107,7 +106,7 @@ public class BufferImpl implements Buffer
* @param c the character to insert * @param c the character to insert
*/ */
public void write(int c) { public void write(int c) {
write(new int[] { c }); write(new int[] {c});
} }
/** /**
@ -121,7 +120,7 @@ public class BufferImpl implements Buffer
if (overTyping) { if (overTyping) {
delete(1); delete(1);
} }
write(new int[] { c }); write(new int[] {c});
} }
/** /**
@ -224,8 +223,7 @@ public class BufferImpl implements Buffer
if ((cursor + where) < 0) { if ((cursor + where) < 0) {
where = -cursor; where = -cursor;
} } else if ((cursor + where) > length()) {
else if ((cursor + where) > length()) {
where = length() - cursor; where = length() - cursor;
} }
@ -371,7 +369,6 @@ public class BufferImpl implements Buffer
} }
} }
// JDK specific modification
@Override @Override
public void zeroOut() { public void zeroOut() {
Arrays.fill(buffer, 0); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,26 +8,25 @@
*/ */
package jdk.internal.org.jline.reader.impl; 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.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; 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 { public class CompletionMatcherImpl implements CompletionMatcher {
protected Predicate<String> exact; protected Predicate<String> exact;
protected List<Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>>> matchers; protected List<Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>>> matchers;
private Map<String, List<Candidate>> matching; private Map<String, List<Candidate>> matching;
private boolean caseInsensitive; private boolean caseInsensitive;
public CompletionMatcherImpl() { public CompletionMatcherImpl() {}
}
protected void reset(boolean caseInsensitive) { protected void reset(boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive; this.caseInsensitive = caseInsensitive;
@ -37,8 +36,13 @@ public class CompletionMatcherImpl implements CompletionMatcher {
} }
@Override @Override
public void compile(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line public void compile(
, boolean caseInsensitive, int errors, String originalGroupName) { Map<LineReader.Option, Boolean> options,
boolean prefix,
CompletingParsedLine line,
boolean caseInsensitive,
int errors,
String originalGroupName) {
reset(caseInsensitive); reset(caseInsensitive);
defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName); defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName);
} }
@ -47,14 +51,17 @@ public class CompletionMatcherImpl implements CompletionMatcher {
public List<Candidate> matches(List<Candidate> candidates) { public List<Candidate> matches(List<Candidate> candidates) {
matching = Collections.emptyMap(); matching = Collections.emptyMap();
Map<String, List<Candidate>> sortedCandidates = sort(candidates); Map<String, List<Candidate>> sortedCandidates = sort(candidates);
for (Function<Map<String, List<Candidate>>, for (Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> matcher : matchers) {
Map<String, List<Candidate>>> matcher : matchers) {
matching = matcher.apply(sortedCandidates); matching = matcher.apply(sortedCandidates);
if (!matching.isEmpty()) { if (!matching.isEmpty()) {
break; break;
} }
} }
return !matching.isEmpty() ? matching.entrySet().stream().flatMap(e -> e.getValue().stream()).distinct().collect(Collectors.toList()) return !matching.isEmpty()
? matching.entrySet().stream()
.flatMap(e -> e.getValue().stream())
.distinct()
.collect(Collectors.toList())
: new ArrayList<>(); : new ArrayList<>();
} }
@ -63,10 +70,12 @@ public class CompletionMatcherImpl implements CompletionMatcher {
if (matching == null) { if (matching == null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return matching.values().stream().flatMap(Collection::stream) return matching.values().stream()
.flatMap(Collection::stream)
.filter(Candidate::complete) .filter(Candidate::complete)
.filter(c -> exact.test(c.value())) .filter(c -> exact.test(c.value()))
.findFirst().orElse(null); .findFirst()
.orElse(null);
} }
@Override @Override
@ -84,8 +93,13 @@ public class CompletionMatcherImpl implements CompletionMatcher {
/** /**
* Default JLine matchers * Default JLine matchers
*/ */
protected void defaultMatchers(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line protected void defaultMatchers(
, boolean caseInsensitive, int errors, String originalGroupName) { Map<LineReader.Option, Boolean> options,
boolean prefix,
CompletingParsedLine line,
boolean caseInsensitive,
int errors,
String originalGroupName) {
// Find matchers // Find matchers
// TODO: glob completion // TODO: glob completion
String wd = line.word(); String wd = line.word();
@ -94,8 +108,7 @@ public class CompletionMatcherImpl implements CompletionMatcher {
if (prefix) { if (prefix) {
matchers = new ArrayList<>(Arrays.asList( matchers = new ArrayList<>(Arrays.asList(
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wp)), 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)) { if (LineReader.Option.COMPLETE_MATCHER_TYPO.isSet(options)) {
matchers.add(typoMatcher(wp, errors, caseInsensitive, originalGroupName)); 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 p1 = Pattern.compile(Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*"); Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
matchers = new ArrayList<>(Arrays.asList( matchers = new ArrayList<>(Arrays.asList(
simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s).matches()), simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s)
simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s).matches()) .matches()),
)); simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s)
.matches())));
} else { } else {
matchers = new ArrayList<>(Arrays.asList( matchers = new ArrayList<>(Arrays.asList(
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wdi)), 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)) { if (LineReader.Option.COMPLETE_MATCHER_CAMELCASE.isSet(options)) {
matchers.add(simpleMatcher(s -> camelMatch(wd, 0, s, 0))); matchers.add(simpleMatcher(s -> camelMatch(wd, 0, s, 0)));
@ -128,18 +141,20 @@ public class CompletionMatcherImpl implements CompletionMatcher {
} }
} }
protected Function<Map<String, List<Candidate>>, protected Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> simpleMatcher(
Map<String, List<Candidate>>> simpleMatcher(Predicate<String> predicate) { Predicate<String> predicate) {
return m -> m.entrySet().stream() return m -> m.entrySet().stream()
.filter(e -> predicate.test(e.getKey())) .filter(e -> predicate.test(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
} }
protected Function<Map<String, List<Candidate>>, protected Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> typoMatcher(
Map<String, List<Candidate>>> typoMatcher(String word, int errors, boolean caseInsensitive, String originalGroupName) { String word, int errors, boolean caseInsensitive, String originalGroupName) {
return m -> { return m -> {
Map<String, List<Candidate>> map = m.entrySet().stream() 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)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (map.size() > 1) { if (map.size() > 1) {
map.computeIfAbsent(word, w -> new ArrayList<>()) map.computeIfAbsent(word, w -> new ArrayList<>())
@ -178,7 +193,8 @@ public class CompletionMatcherImpl implements CompletionMatcher {
Map<String, List<Candidate>> sortedCandidates = new HashMap<>(); Map<String, List<Candidate>> sortedCandidates = new HashMap<>();
for (Candidate candidate : candidates) { for (Candidate candidate : candidates) {
sortedCandidates sortedCandidates
.computeIfAbsent(AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>()) .computeIfAbsent(
AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>())
.add(candidate); .add(candidate);
} }
return sortedCandidates; return sortedCandidates;
@ -206,5 +222,4 @@ public class CompletionMatcherImpl implements CompletionMatcher {
} }
return new String(s1, 0, len); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -32,27 +32,25 @@ public class DefaultExpander implements Expander {
if (unicode > 0) { if (unicode > 0) {
escaped = (--unicode >= 0); escaped = (--unicode >= 0);
sb.append(c); sb.append(c);
} } else if (escaped) {
else if (escaped) {
if (c == 'u') { if (c == 'u') {
unicode = 4; unicode = 4;
} else { } else {
escaped = false; escaped = false;
} }
sb.append(c); sb.append(c);
} } else if (c == '\'') {
else if (c == '\'') {
inQuote = !inQuote; inQuote = !inQuote;
sb.append(c); sb.append(c);
} } else if (inQuote) {
else if (inQuote) {
sb.append(c); sb.append(c);
} } else {
else {
switch (c) { switch (c) {
case '\\': case '\\':
// any '\!' 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
// a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character // character
// a leading '\^' should be considered an expansion escape, so skip expansion and strip the
// escape character
// otherwise, add the escape // otherwise, add the escape
escaped = true; escaped = true;
sb.append(c); sb.append(c);
@ -91,7 +89,8 @@ public class DefaultExpander implements Expander {
if (history.size() == 0) { if (history.size() == 0) {
throw new IllegalArgumentException("!$: event not found"); 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(' '); int lastSpace = previous.lastIndexOf(' ');
if (lastSpace != -1) { if (lastSpace != -1) {
rep = previous.substring(lastSpace + 1); rep = previous.substring(lastSpace + 1);
@ -128,14 +127,18 @@ public class DefaultExpander implements Expander {
try { try {
idx = Integer.parseInt(line.substring(i1, i)); idx = Integer.parseInt(line.substring(i1, i));
} catch (NumberFormatException e) { } 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()) { if (neg && idx > 0 && idx <= history.size()) {
rep = history.get(history.index() - idx); 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); rep = history.get(idx - 1);
} else { } else {
throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found"); throw new IllegalArgumentException(
(neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
} }
break; break;
default: 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 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;
import jdk.internal.org.jline.reader.LineReader.RegionType; 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.AttributedString;
import jdk.internal.org.jline.utils.AttributedStringBuilder; import jdk.internal.org.jline.utils.AttributedStringBuilder;
import jdk.internal.org.jline.utils.AttributedStyle; 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') { while (negativeStart > 0 && reader.getBuffer().atChar(negativeStart - 1) != '\n') {
negativeStart--; 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++; negativeEnd++;
} }
} }
@ -104,5 +105,4 @@ public class DefaultHighlighter implements Highlighter {
} }
return sb.toAttributedString(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -30,9 +30,9 @@ public class DefaultParser implements Parser {
public static class BlockCommentDelims { public static class BlockCommentDelims {
private final String start; private final String start;
private final String end; private final String end;
public BlockCommentDelims(String start, String end) { public BlockCommentDelims(String start, String end) {
if (start == null || end == null if (start == null || end == null || start.isEmpty() || end.isEmpty() || start.equals(end)) {
|| start.isEmpty() || end.isEmpty() || start.equals(end)) {
throw new IllegalArgumentException("Bad block comment delimiter!"); throw new IllegalArgumentException("Bad block comment delimiter!");
} }
this.start = start; this.start = start;
@ -229,7 +229,6 @@ public class DefaultParser implements Parser {
return name != null && regexVariable != null && name.matches(regexVariable); return name != null && regexVariable != null && name.matches(regexVariable);
} }
@Override @Override
public String getCommand(final String line) { public String getCommand(final String line) {
String out = ""; String out = "";
@ -296,7 +295,7 @@ public class DefaultParser implements Parser {
if (quoteStart < 0 && isQuoteChar(line, i) && !lineCommented && !blockCommented) { if (quoteStart < 0 && isQuoteChar(line, i) && !lineCommented && !blockCommented) {
// Start a quote block // Start a quote block
quoteStart = i; quoteStart = i;
if (current.length()==0) { if (current.length() == 0) {
quotedWord = true; quotedWord = true;
if (context == ParseContext.SPLIT_LINE) { if (context == ParseContext.SPLIT_LINE) {
current.append(line.charAt(i)); current.append(line.charAt(i));
@ -324,13 +323,15 @@ public class DefaultParser implements Parser {
} }
} else { } else {
// Delimiter // Delimiter
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i); rawWordLength = handleDelimiterAndGetRawWordLength(
current, words, rawWordStart, rawWordCursor, rawWordLength, i);
rawWordStart = i + 1; rawWordStart = i + 1;
} }
} else { } else {
if (quoteStart < 0 && !blockCommented && (lineCommented || isLineCommentStarted(line, i))) { if (quoteStart < 0 && !blockCommented && (lineCommented || isLineCommentStarted(line, i))) {
lineCommented = true; lineCommented = true;
} else if (quoteStart < 0 && !lineCommented } else if (quoteStart < 0
&& !lineCommented
&& (blockCommented || isCommentDelim(line, i, blockCommentStart))) { && (blockCommented || isCommentDelim(line, i, blockCommentStart))) {
if (blockCommented) { if (blockCommented) {
if (blockCommentEnd != null && isCommentDelim(line, i, blockCommentEnd)) { if (blockCommentEnd != null && isCommentDelim(line, i, blockCommentEnd)) {
@ -339,12 +340,12 @@ public class DefaultParser implements Parser {
} }
} else { } else {
blockCommented = true; 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; i += blockCommentStart == null ? 0 : blockCommentStart.length() - 1;
rawWordStart = i + 1; rawWordStart = i + 1;
} }
} else if (quoteStart < 0 && !lineCommented } else if (quoteStart < 0 && !lineCommented && isCommentDelim(line, i, blockCommentEnd)) {
&& isCommentDelim(line, i, blockCommentEnd)) {
current.append(line.charAt(i)); current.append(line.charAt(i));
blockCommentInRightOrder = false; blockCommentInRightOrder = false;
} else if (!isEscapeChar(line, i)) { } else if (!isEscapeChar(line, i)) {
@ -377,16 +378,14 @@ public class DefaultParser implements Parser {
throw new EOFError(-1, -1, "Escaped new line", "newline"); throw new EOFError(-1, -1, "Escaped new line", "newline");
} }
if (eofOnUnclosedQuote && quoteStart >= 0) { if (eofOnUnclosedQuote && quoteStart >= 0) {
throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\'' throw new EOFError(
? "quote" : "dquote"); -1, -1, "Missing closing quote", line.charAt(quoteStart) == '\'' ? "quote" : "dquote");
} }
if (blockCommented) { if (blockCommented) {
throw new EOFError(-1, -1, "Missing closing block comment delimiter", throw new EOFError(-1, -1, "Missing closing block comment delimiter", "add: " + blockCommentEnd);
"add: " + blockCommentEnd);
} }
if (!blockCommentInRightOrder) { if (!blockCommentInRightOrder) {
throw new EOFError(-1, -1, "Missing opening block comment delimiter", throw new EOFError(-1, -1, "Missing opening block comment delimiter", "missing: " + blockCommentStart);
"missing: " + blockCommentStart);
} }
if (bracketChecker.isClosingBracketMissing() || bracketChecker.isOpeningBracketMissing()) { if (bracketChecker.isClosingBracketMissing() || bracketChecker.isOpeningBracketMissing()) {
String message = null; String message = null;
@ -398,8 +397,13 @@ public class DefaultParser implements Parser {
message = "Missing opening bracket"; message = "Missing opening bracket";
missing = "missing: " + bracketChecker.getMissingOpeningBracket(); missing = "missing: " + bracketChecker.getMissingOpeningBracket();
} }
throw new EOFError(-1, -1, message, missing, throw new EOFError(
bracketChecker.getOpenBrackets(), bracketChecker.getNextClosingBracket()); -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); 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) { if (current.length() > 0) {
words.add(current.toString()); words.add(current.toString());
current.setLength(0); // reset the arg current.setLength(0); // reset the arg
@ -470,7 +480,7 @@ public class DefaultParser implements Parser {
public boolean isLineCommentStarted(final CharSequence buffer, final int pos) { public boolean isLineCommentStarted(final CharSequence buffer, final int pos) {
if (lineCommentDelims != null) { if (lineCommentDelims != null) {
for (String comment: lineCommentDelims) { for (String comment : lineCommentDelims) {
if (isCommentDelim(buffer, pos, comment)) { if (isCommentDelim(buffer, pos, comment)) {
return true; return true;
} }
@ -584,8 +594,8 @@ public class DefaultParser implements Parser {
} else { } else {
bid = bracketId(closingBrackets, buffer, pos); bid = bracketId(closingBrackets, buffer, pos);
if (bid >= 0) { if (bid >= 0) {
if (!nested.isEmpty() && bid == nested.get(nested.size()-1)) { if (!nested.isEmpty() && bid == nested.get(nested.size() - 1)) {
nested.remove(nested.size()-1); nested.remove(nested.size() - 1);
} else { } else {
missingOpeningBracket = bid; missingOpeningBracket = bid;
} }
@ -634,7 +644,7 @@ public class DefaultParser implements Parser {
} }
private int bracketId(final char[] brackets, final CharSequence buffer, final int pos) { 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]) { if (buffer.charAt(pos) == brackets[i]) {
return i; return i;
} }
@ -648,8 +658,7 @@ public class DefaultParser implements Parser {
* *
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a> * @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 String line;
private final List<String> words; private final List<String> words;
@ -667,11 +676,21 @@ public class DefaultParser implements Parser {
private final int rawWordLength; private final int rawWordLength;
@Deprecated @Deprecated
public ArgumentList(final String line, final List<String> words, public ArgumentList(
final int wordIndex, final int wordCursor, final String line,
final List<String> words,
final int wordIndex,
final int wordCursor,
final int cursor) { final int cursor) {
this(line, words, wordIndex, wordCursor, cursor, this(
null, wordCursor, words.get(wordIndex).length()); 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 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 * @param rawWordLength the raw word length, including quotes and escape characters
*/ */
public ArgumentList(final String line, final List<String> words, public ArgumentList(
final int wordIndex, final int wordCursor, final String line,
final int cursor, final String openingQuote, final List<String> words,
final int rawWordCursor, final int rawWordLength) { final int wordIndex,
final int wordCursor,
final int cursor,
final String openingQuote,
final int rawWordCursor,
final int rawWordLength) {
this.line = line; this.line = line;
this.words = Collections.unmodifiableList(Objects.requireNonNull(words)); this.words = Collections.unmodifiableList(Objects.requireNonNull(words));
this.wordIndex = wordIndex; this.wordIndex = wordIndex;
@ -732,8 +756,8 @@ public class DefaultParser implements Parser {
Predicate<Integer> needToBeEscaped; Predicate<Integer> needToBeEscaped;
String quote = openingQuote; String quote = openingQuote;
boolean middleQuotes = false; boolean middleQuotes = false;
if (openingQuote==null) { if (openingQuote == null) {
for (int i=0; i < sb.length(); i++) { for (int i = 0; i < sb.length(); i++) {
if (isQuoteChar(sb, i)) { if (isQuoteChar(sb, i)) {
middleQuotes = true; middleQuotes = true;
break; 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. // Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does.
// Also, close the quote at the end // Also, close the quote at the end
if (openingQuote != null) { 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: // Completion is protected by middle quotes:
// Delimiters (spaces) don't need to be escaped, nor do quotes, but everything else does. // 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 // No quote protection, need to escape everything: delimiter chars (spaces), quote chars
// and escapes themselves // and escapes themselves
else { else {
needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) needToBeEscaped = i ->
|| isRawQuoteChar(sb.charAt(i)); isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) || isRawQuoteChar(sb.charAt(i));
} }
for (int i = 0; i < sb.length(); i++) { for (int i = 0; i < sb.length(); i++) {
if (needToBeEscaped.test(i)) { if (needToBeEscaped.test(i)) {
@ -792,5 +817,4 @@ public class DefaultParser implements Parser {
return rawWordLength; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -13,7 +13,7 @@ import jdk.internal.org.jline.utils.Levenshtein;
public class ReaderUtils { public class ReaderUtils {
private ReaderUtils() { } private ReaderUtils() {}
public static boolean isSet(LineReader reader, LineReader.Option option) { public static boolean isSet(LineReader reader, LineReader.Option option) {
return reader != null && reader.isSet(option); return reader != null && reader.isSet(option);
@ -30,8 +30,7 @@ public class ReaderUtils {
return (Boolean) v; return (Boolean) v;
} else if (v != null) { } else if (v != null) {
String s = v.toString(); String s = v.toString();
return s.isEmpty() || s.equalsIgnoreCase("on") return s.isEmpty() || s.equalsIgnoreCase("on") || s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
|| s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
} }
return def; return def;
} }
@ -77,5 +76,4 @@ public class ReaderUtils {
return Levenshtein.distance(word, cand); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,10 +8,10 @@
*/ */
package jdk.internal.org.jline.reader.impl; package jdk.internal.org.jline.reader.impl;
import jdk.internal.org.jline.reader.MaskingCallback;
import java.util.Objects; 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. * 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. * 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 ""; return "";
} else { } else {
StringBuilder sb = new StringBuilder(line.length()); StringBuilder sb = new StringBuilder(line.length());
for (int i = line.length(); i-- > 0;) { for (int i = line.length(); i-- > 0; ) {
sb.append((char) mask); sb.append((char) mask);
} }
return sb.toString(); return sb.toString();
@ -40,5 +40,4 @@ public final class SimpleMaskingCallback implements MaskingCallback {
public String history(String line) { public String history(String line) {
return null; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -20,6 +20,7 @@ public class UndoTree<T> {
private final Node parent; private final Node parent;
private Node current; private Node current;
@SuppressWarnings("this-escape")
public UndoTree(Consumer<T> s) { public UndoTree(Consumer<T> s) {
state = s; state = s;
parent = new Node(null); parent = new Node(null);
@ -71,5 +72,4 @@ public class UndoTree<T> {
state = s; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @since 2.3
*/ */
public class AggregateCompleter public class AggregateCompleter implements Completer {
implements Completer
{
private final Collection<Completer> completers; private final Collection<Completer> completers;
/** /**
@ -78,9 +76,6 @@ public class AggregateCompleter
*/ */
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + "{" + return getClass().getSimpleName() + "{" + "completers=" + completers + '}';
"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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @since 2.3
*/ */
public class ArgumentCompleter implements Completer public class ArgumentCompleter implements Completer {
{
private final List<Completer> completers = new ArrayList<>(); private final List<Completer> completers = new ArrayList<>();
private boolean strict = true; 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 we are beyond the end of the completers, just use the last one
if (line.wordIndex() >= completers.size()) { if (line.wordIndex() >= completers.size()) {
completer = completers.get(completers.size() - 1); completer = completers.get(completers.size() - 1);
} } else {
else {
completer = completers.get(line.wordIndex()); 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++) { for (int i = strictCommand ? 0 : 1; isStrict() && (i < line.wordIndex()); i++) {
int idx = i >= completers.size() ? (completers.size() - 1) : i; int idx = i >= completers.size() ? (completers.size() - 1) : i;
if (idx == 0 && !strictCommand) { 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @since 2.3
*/ */
public class EnumCompleter extends StringsCompleter public class EnumCompleter extends StringsCompleter {
{
public EnumCompleter(Class<? extends Enum<?>> source) { public EnumCompleter(Class<? extends Enum<?>> source) {
Objects.requireNonNull(source); Objects.requireNonNull(source);
for (Enum<?> n : source.getEnumConstants()) { 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -9,6 +9,7 @@
package jdk.internal.org.jline.reader.impl.completer; package jdk.internal.org.jline.reader.impl.completer;
import java.io.IOException; import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; 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:mwp1@cornell.edu">Marc Prud'hommeaux</a>
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @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 @Deprecated
public class FileNameCompleter implements Completer public class FileNameCompleter implements Completer {
{
public void complete(LineReader reader, ParsedLine commandLine, final List<Candidate> candidates) { public void complete(LineReader reader, ParsedLine commandLine, final List<Candidate> candidates) {
assert commandLine != null; assert commandLine != null;
@ -72,20 +72,21 @@ public class FileNameCompleter implements Completer
curBuf = ""; curBuf = "";
current = getUserDir(); current = getUserDir();
} }
try { try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(current, this::accept)) {
Files.newDirectoryStream(current, this::accept).forEach(p -> { directoryStream.forEach(p -> {
String value = curBuf + p.getFileName().toString(); String value = curBuf + p.getFileName().toString();
if (Files.isDirectory(p)) { if (Files.isDirectory(p)) {
candidates.add(new Candidate( candidates.add(new Candidate(
value + (reader.isSet(Option.AUTO_PARAM_SLASH) ? sep : ""), value + (reader.isSet(Option.AUTO_PARAM_SLASH) ? sep : ""),
getDisplay(reader.getTerminal(), p), getDisplay(reader.getTerminal(), p),
null, null, null,
null,
reader.isSet(Option.AUTO_REMOVE_SLASH) ? sep : null, reader.isSet(Option.AUTO_REMOVE_SLASH) ? sep : null,
null, null,
false)); false));
} else { } else {
candidates.add(new Candidate(value, getDisplay(reader.getTerminal(), p), candidates.add(
null, null, null, null, true)); new Candidate(value, getDisplay(reader.getTerminal(), p), null, null, null, null, true));
} }
}); });
} catch (IOException e) { } catch (IOException e) {
@ -125,5 +126,4 @@ public class FileNameCompleter implements Completer
} }
return name; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @since 2.3
*/ */
public final class NullCompleter public final class NullCompleter implements Completer {
implements Completer
{
public static final NullCompleter INSTANCE = new NullCompleter(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3 * @since 2.3
*/ */
public class StringsCompleter implements Completer public class StringsCompleter implements Completer {
{
protected Collection<Candidate> candidates; protected Collection<Candidate> candidates;
protected Supplier<Collection<String>> stringsSupplier; 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)); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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> * @author <a href="mailto:matti.rintanikkola@gmail.com">Matti Rinta-Nikkola</a>
*/ */
public class SystemCompleter implements Completer { public class SystemCompleter implements Completer {
private Map<String,List<Completer>> completers = new HashMap<>(); private Map<String, List<Completer>> completers = new HashMap<>();
private Map<String,String> aliasCommand = new HashMap<>(); private Map<String, String> aliasCommand = new HashMap<>();
private StringsCompleter commands; private StringsCompleter commands;
private boolean compiled = false; private boolean compiled = false;
@ -44,9 +44,9 @@ public class SystemCompleter implements Completer {
commands.complete(reader, commandLine, candidates); commands.complete(reader, commandLine, candidates);
} else if (reader.getParser().validVariableName(buffer.substring(0, eq))) { } else if (reader.getParser().validVariableName(buffer.substring(0, eq))) {
String curBuf = buffer.substring(0, eq + 1); String curBuf = buffer.substring(0, eq + 1);
for (String c: completers.keySet()) { for (String c : completers.keySet()) {
candidates.add(new Candidate(AttributedString.stripAnsi(curBuf+c) candidates.add(
, c, null, null, null, null, true)); new Candidate(AttributedString.stripAnsi(curBuf + c), c, null, null, null, null, true));
} }
} }
} else { } else {
@ -81,7 +81,7 @@ public class SystemCompleter implements Completer {
} }
public void add(List<String> commands, Completer completer) { public void add(List<String> commands, Completer completer) {
for (String c: commands) { for (String c : commands) {
add(c, completer); add(c, completer);
} }
} }
@ -104,22 +104,22 @@ public class SystemCompleter implements Completer {
if (other.isCompiled()) { if (other.isCompiled()) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
for (Map.Entry<String, List<Completer>> entry: other.getCompleters().entrySet()) { for (Map.Entry<String, List<Completer>> entry : other.getCompleters().entrySet()) {
for (Completer c: entry.getValue()) { for (Completer c : entry.getValue()) {
add(entry.getKey(), c); add(entry.getKey(), c);
} }
} }
addAliases(other.getAliases()); addAliases(other.getAliases());
} }
public void addAliases(Map<String,String> aliasCommand) { public void addAliases(Map<String, String> aliasCommand) {
if (compiled) { if (compiled) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
this.aliasCommand.putAll(aliasCommand); this.aliasCommand.putAll(aliasCommand);
} }
private Map<String,String> getAliases() { private Map<String, String> getAliases() {
return aliasCommand; return aliasCommand;
} }
@ -128,7 +128,7 @@ public class SystemCompleter implements Completer {
return; return;
} }
Map<String, List<Completer>> compiledCompleters = new HashMap<>(); 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) { if (entry.getValue().size() == 1) {
compiledCompleters.put(entry.getKey(), entry.getValue()); compiledCompleters.put(entry.getKey(), entry.getValue());
} else { } else {
@ -143,8 +143,7 @@ public class SystemCompleter implements Completer {
compiled = true; compiled = true;
} }
public Map<String,List<Completer>> getCompleters() { public Map<String, List<Completer>> getCompleters() {
return completers; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -41,9 +41,9 @@ public class DefaultHistory implements History {
private int offset = 0; private int offset = 0;
private int index = 0; private int index = 0;
public DefaultHistory() { public DefaultHistory() {}
}
@SuppressWarnings("this-escape")
public DefaultHistory(LineReader reader) { public DefaultHistory(LineReader reader) {
attach(reader); attach(reader);
} }
@ -67,8 +67,7 @@ public class DefaultHistory implements History {
this.reader = reader; this.reader = reader;
try { try {
load(); load();
} } catch (IllegalArgumentException | IOException e) {
catch (IllegalArgumentException | IOException e) {
Log.warn("Failed to load history", 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; return path != null ? path.toAbsolutePath().toString() : null;
} }
private HistoryFileData getHistoryFileData(Path path) { private HistoryFileData getHistoryFileData(Path path) {
String key = doHistoryFileDataKey(path); String key = doHistoryFileDataKey(path);
if (!historyFiles.containsKey(key)){ if (!historyFiles.containsKey(key)) {
historyFiles.put(key, new HistoryFileData()); historyFiles.put(key, new HistoryFileData());
} }
return historyFiles.get(key); return historyFiles.get(key);
@ -133,7 +132,7 @@ public class DefaultHistory implements History {
historyFiles.put(doHistoryFileDataKey(path), historyFileData); historyFiles.put(doHistoryFileDataKey(path), historyFileData);
} }
private boolean isLineReaderHistory (Path path) throws IOException { private boolean isLineReaderHistory(Path path) throws IOException {
Path lrp = getPath(); Path lrp = getPath();
if (lrp == null) { if (lrp == null) {
return path == null; return path == null;
@ -141,23 +140,23 @@ public class DefaultHistory implements History {
return Files.isSameFile(lrp, path); return Files.isSameFile(lrp, path);
} }
private void setLastLoaded(Path path, int lastloaded){ private void setLastLoaded(Path path, int lastloaded) {
getHistoryFileData(path).setLastLoaded(lastloaded); getHistoryFileData(path).setLastLoaded(lastloaded);
} }
private void setEntriesInFile(Path path, int entriesInFile){ private void setEntriesInFile(Path path, int entriesInFile) {
getHistoryFileData(path).setEntriesInFile(entriesInFile); getHistoryFileData(path).setEntriesInFile(entriesInFile);
} }
private void incEntriesInFile(Path path, int amount){ private void incEntriesInFile(Path path, int amount) {
getHistoryFileData(path).incEntriesInFile(amount); getHistoryFileData(path).incEntriesInFile(amount);
} }
private int getLastLoaded(Path path){ private int getLastLoaded(Path path) {
return getHistoryFileData(path).getLastLoaded(); return getHistoryFileData(path).getLastLoaded();
} }
private int getEntriesInFile(Path path){ private int getEntriesInFile(Path path) {
return getHistoryFileData(path).getEntriesInFile(); return getHistoryFileData(path).getEntriesInFile();
} }
@ -168,9 +167,8 @@ public class DefaultHistory implements History {
protected void addHistoryLine(Path path, String line, boolean checkDuplicates) { protected void addHistoryLine(Path path, String line, boolean checkDuplicates) {
if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) { if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
int idx = line.indexOf(':'); int idx = line.indexOf(':');
final String badHistoryFileSyntax = "Bad history file syntax! " + final String badHistoryFileSyntax = "Bad history file syntax! " + "The history file `" + path
"The history file `" + path + "` may be an older history: " + + "` may be an older history: " + "please remove it or use a different history file.";
"please remove it or use a different history file.";
if (idx < 0) { if (idx < 0) {
throw new IllegalArgumentException(badHistoryFileSyntax); throw new IllegalArgumentException(badHistoryFileSyntax);
} }
@ -183,8 +181,7 @@ public class DefaultHistory implements History {
String unescaped = unescape(line.substring(idx + 1)); String unescaped = unescape(line.substring(idx + 1));
internalAdd(time, unescaped, checkDuplicates); internalAdd(time, unescaped, checkDuplicates);
} } else {
else {
internalAdd(Instant.now(), unescape(line), checkDuplicates); internalAdd(Instant.now(), unescape(line), checkDuplicates);
} }
} }
@ -210,8 +207,7 @@ public class DefaultHistory implements History {
@Override @Override
public void append(Path file, boolean incremental) throws IOException { public void append(Path file, boolean incremental) throws IOException {
internalWrite(file != null ? file : getPath(), internalWrite(file != null ? file : getPath(), incremental ? getLastLoaded(file) : 0);
incremental ? getLastLoaded(file) : 0);
} }
@Override @Override
@ -227,8 +223,11 @@ public class DefaultHistory implements History {
Files.createDirectories(parent); Files.createDirectories(parent);
} }
// Append new items to the history file // Append new items to the history file
try (BufferedWriter writer = Files.newBufferedWriter(path.toAbsolutePath(), try (BufferedWriter writer = Files.newBufferedWriter(
StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) { path.toAbsolutePath(),
StandardOpenOption.WRITE,
StandardOpenOption.APPEND,
StandardOpenOption.CREATE)) {
for (Entry entry : items.subList(from, items.size())) { for (Entry entry : items.subList(from, items.size())) {
if (isPersistable(entry)) { if (isPersistable(entry)) {
writer.append(format(entry)); writer.append(format(entry));
@ -248,18 +247,23 @@ public class DefaultHistory implements History {
Log.trace("Trimming history path: ", path); Log.trace("Trimming history path: ", path);
// Load all history entries // Load all history entries
LinkedList<Entry> allItems = new LinkedList<>(); LinkedList<Entry> allItems = new LinkedList<>();
try (BufferedReader reader = Files.newBufferedReader(path)) { try (BufferedReader historyFileReader = Files.newBufferedReader(path)) {
reader.lines().forEach(l -> { historyFileReader.lines().forEach(l -> {
if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
int idx = l.indexOf(':'); int idx = l.indexOf(':');
Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx))); Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx)));
String line = unescape(l.substring(idx + 1)); String line = unescape(l.substring(idx + 1));
allItems.add(createEntry(allItems.size(), time, line)); allItems.add(createEntry(allItems.size(), time, line));
} else {
allItems.add(createEntry(allItems.size(), Instant.now(), unescape(l)));
}
}); });
} }
// Remove duplicates // Remove duplicates
List<Entry> trimmedItems = doTrimHistory(allItems, max); List<Entry> trimmedItems = doTrimHistory(allItems, max);
// Write history // 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)) { try (BufferedWriter writer = Files.newBufferedWriter(temp, StandardOpenOption.WRITE)) {
for (Entry entry : trimmedItems) { for (Entry entry : trimmedItems) {
writer.append(format(entry)); writer.append(format(entry));
@ -351,7 +355,7 @@ public class DefaultHistory implements History {
public String get(final int index) { public String get(final int index) {
int idx = index - offset; int idx = index - offset;
if (idx >= items.size() || idx < 0) { 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(); return items.get(idx).line();
} }
@ -382,8 +386,7 @@ public class DefaultHistory implements History {
if (isSet(reader, LineReader.Option.HISTORY_INCREMENTAL)) { if (isSet(reader, LineReader.Option.HISTORY_INCREMENTAL)) {
try { try {
save(); save();
} } catch (IOException e) {
catch (IOException e) {
Log.warn("Failed to save history", 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) { protected void internalAdd(Instant time, String line, boolean checkDuplicates) {
Entry entry = new EntryImpl(offset + items.size(), time, line); Entry entry = new EntryImpl(offset + items.size(), time, line);
if (checkDuplicates) { if (checkDuplicates) {
for (Entry e: items) { for (Entry e : items) {
if (e.line().trim().equals(line.trim())) { if (e.line().trim().equals(line.trim())) {
return; return;
} }
@ -430,7 +433,7 @@ public class DefaultHistory implements History {
private void maybeResize() { private void maybeResize() {
while (size() > getInt(reader, LineReader.HISTORY_SIZE, DEFAULT_HISTORY_SIZE)) { while (size() > getInt(reader, LineReader.HISTORY_SIZE, DEFAULT_HISTORY_SIZE)) {
items.removeFirst(); items.removeFirst();
for (HistoryFileData hfd: historyFiles.values()) { for (HistoryFileData hfd : historyFiles.values()) {
hfd.decLastLoaded(); hfd.decLastLoaded();
} }
offset++; offset++;
@ -633,8 +636,7 @@ public class DefaultHistory implements History {
private int lastLoaded = 0; private int lastLoaded = 0;
private int entriesInFile = 0; private int entriesInFile = 0;
public HistoryFileData() { public HistoryFileData() {}
}
public HistoryFileData(int lastLoaded, int entriesInFile) { public HistoryFileData(int lastLoaded, int entriesInFile) {
this.lastLoaded = lastLoaded; this.lastLoaded = lastLoaded;
@ -667,8 +669,5 @@ public class DefaultHistory implements History {
public void incEntriesInFile(int amount) { public void incEntriesInFile(int amount) {
entriesInFile = entriesInFile + 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -56,7 +56,9 @@ public class Attributes {
IXOFF, /* enable input flow control */ IXOFF, /* enable input flow control */
IXANY, /* any char will restart after stop */ IXANY, /* any char will restart after stop */
IMAXBEL, /* ring bell on input queue full */ IMAXBEL, /* ring bell on input queue full */
IUTF8 /* maintain state for UTF-8 VERASE */ IUTF8, /* maintain state for UTF-8 VERASE */
INORMEOL /* normalize end-of-line */
} }
/* /*
@ -135,9 +137,9 @@ public class Attributes {
final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class); final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class);
final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class); final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class);
public Attributes() { public Attributes() {}
}
@SuppressWarnings("this-escape")
public Attributes(Attributes attr) { public Attributes(Attributes attr) {
copy(attr); copy(attr);
} }
@ -310,13 +312,12 @@ public class Attributes {
@Override @Override
public String toString() { public String toString() {
return "Attributes[" + return "Attributes[" + "lflags: "
"lflags: " + append(lflag) + ", " + + append(lflag) + ", " + "iflags: "
"iflags: " + append(iflag) + ", " + + append(iflag) + ", " + "oflags: "
"oflags: " + append(oflag) + ", " + + append(oflag) + ", " + "cflags: "
"cflags: " + append(cflag) + ", " + + append(cflag) + ", " + "cchars: "
"cchars: " + append(EnumSet.allOf(ControlChar.class), this::display) + + append(EnumSet.allOf(ControlChar.class), this::display) + "]";
"]";
} }
private String display(ControlChar c) { 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) { private <T extends Enum<T>> String append(EnumSet<T> set, Function<T, String> toString) {
return set.stream().map(toString).collect(Collectors.joining(" ")); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -71,12 +71,11 @@ public class MouseEvent {
@Override @Override
public String toString() { public String toString() {
return "MouseEvent[" + return "MouseEvent[" + "type="
"type=" + type + + type + ", button="
", button=" + button + + button + ", modifiers="
", modifiers=" + modifiers + + modifiers + ", x="
", x=" + x + + x + ", y="
", y=" + 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -13,9 +13,9 @@ public class Size {
private int rows; private int rows;
private int cols; private int cols;
public Size() { public Size() {}
}
@SuppressWarnings("this-escape")
public Size(int columns, int rows) { public Size(int columns, int rows) {
this(); this();
setColumns(columns); setColumns(columns);
@ -50,7 +50,7 @@ public class Size {
* @return the cursor position * @return the cursor position
*/ */
public int cursorPos(int row, int col) { public int cursorPos(int row, int col) {
return row * (cols+1) + col; return row * (cols + 1) + col;
} }
public void copy(Size size) { 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -34,6 +34,7 @@ public interface Terminal extends Closeable, Flushable {
* Type used for dumb terminals. * Type used for dumb terminals.
*/ */
String TYPE_DUMB = "dumb"; String TYPE_DUMB = "dumb";
String TYPE_DUMB_COLOR = "dumb-color"; String TYPE_DUMB_COLOR = "dumb-color";
String getName(); String getName();
@ -42,6 +43,9 @@ public interface Terminal extends Closeable, Flushable {
// Signal support // Signal support
// //
/**
* Types of signals.
*/
enum Signal { enum Signal {
INT, INT,
QUIT, QUIT,
@ -51,16 +55,55 @@ public interface Terminal extends Closeable, Flushable {
WINCH WINCH
} }
/**
* The SignalHandler defines the interface used to trap signals and perform specific behaviors.
* @see Terminal.Signal
* @see Terminal#handle(Signal, SignalHandler)
*/
interface 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; 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; SignalHandler SIG_IGN = NativeSignalHandler.SIG_IGN;
/**
* Handle the signal.
* @param signal the signal
*/
void handle(Signal 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); 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); void raise(Signal signal);
// //
@ -180,8 +223,21 @@ public interface Terminal extends Closeable, Flushable {
boolean echo(boolean echo); 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(); 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); void setAttributes(Attributes attr);
/** /**
@ -334,5 +390,4 @@ public interface Terminal extends Closeable, Flushable {
* Color support * Color support
*/ */
ColorPalette getPalette(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,9 +8,6 @@
*/ */
package jdk.internal.org.jline.terminal; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -19,11 +16,16 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList; 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.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; 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.AbstractPosixTerminal;
import jdk.internal.org.jline.terminal.impl.AbstractTerminal; 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.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.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.Log; import jdk.internal.org.jline.utils.Log;
import jdk.internal.org.jline.utils.OSUtils; 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_ENCODING = "org.jline.terminal.encoding";
public static final String PROP_CODEPAGE = "org.jline.terminal.codepage"; 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_TYPE = "org.jline.terminal.type";
public static final String PROP_JNA = "org.jline.terminal.jna"; public static final String PROP_PROVIDER = "org.jline.terminal.provider";
public static final String PROP_JANSI = "org.jline.terminal.jansi"; public static final String PROP_PROVIDERS = "org.jline.terminal.providers";
public static final String PROP_EXEC = "org.jline.terminal.exec"; public static final String PROP_PROVIDER_FFM = "ffm";
public static final String PROP_DUMB = "org.jline.terminal.dumb"; 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_DUMB_COLOR = "org.jline.terminal.dumb.color";
public static final String PROP_OUTPUT = "org.jline.terminal.output"; public static final String PROP_OUTPUT = "org.jline.terminal.output";
public static final String PROP_OUTPUT_OUT = "out"; public static final String PROP_OUTPUT_OUT = "out";
public static final String PROP_OUTPUT_ERR = "err"; public static final String PROP_OUTPUT_ERR = "err";
public static final String PROP_OUTPUT_OUT_ERR = "out-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_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 // 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_COLOR_DISTANCE = "org.jline.utils.colorDistance";
public static final String PROP_DISABLE_ALTERNATE_CHARSET = "org.jline.utils.disableAlternateCharset"; 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 // Terminal output control
// //
@ -75,7 +119,9 @@ public final class TerminalBuilder {
SysOut, SysOut,
SysErr, SysErr,
SysOutOrSysErr, SysOutOrSysErr,
SysErrOrSysOut SysErrOrSysOut,
ForcedSysOut,
ForcedSysErr
} }
/** /**
@ -115,20 +161,23 @@ public final class TerminalBuilder {
private int codepage; private int codepage;
private Boolean system; private Boolean system;
private SystemOutput systemOutput; private SystemOutput systemOutput;
private String provider;
private String providers;
private Boolean jna; private Boolean jna;
private Boolean jansi; private Boolean jansi;
private Boolean jni;
private Boolean exec; private Boolean exec;
private Boolean ffm;
private Boolean dumb; private Boolean dumb;
private Boolean color; private Boolean color;
private Attributes attributes; private Attributes attributes;
private Size size; private Size size;
private boolean nativeSignals = false; private boolean nativeSignals = true;
private Function<InputStream, InputStream> inputStreamWrapper = in -> in; private Function<InputStream, InputStream> inputStreamWrapper = in -> in;
private Terminal.SignalHandler signalHandler = Terminal.SignalHandler.SIG_DFL; private Terminal.SignalHandler signalHandler = Terminal.SignalHandler.SIG_DFL;
private boolean paused = false; private boolean paused = false;
private TerminalBuilder() { private TerminalBuilder() {}
}
public TerminalBuilder name(String name) { public TerminalBuilder name(String name) {
this.name = name; this.name = name;
@ -160,6 +209,16 @@ public final class TerminalBuilder {
return this; 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) { public TerminalBuilder jna(boolean jna) {
this.jna = jna; this.jna = jna;
return this; return this;
@ -170,11 +229,21 @@ public final class TerminalBuilder {
return this; return this;
} }
public TerminalBuilder jni(boolean jni) {
this.jni = jni;
return this;
}
public TerminalBuilder exec(boolean exec) { public TerminalBuilder exec(boolean exec) {
this.exec = exec; this.exec = exec;
return this; return this;
} }
public TerminalBuilder ffm(boolean ffm) {
this.ffm = ffm;
return this;
}
public TerminalBuilder dumb(boolean dumb) { public TerminalBuilder dumb(boolean dumb) {
this.dumb = dumb; this.dumb = dumb;
return this; return this;
@ -280,6 +349,12 @@ public final class TerminalBuilder {
return this; 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) { public TerminalBuilder signalHandler(Terminal.SignalHandler signalHandler) {
this.signalHandler = signalHandler; this.signalHandler = signalHandler;
return this; return this;
@ -305,6 +380,11 @@ public final class TerminalBuilder {
return this; return this;
} }
/**
* Builds the terminal.
* @return the newly created terminal, never {@code null}
* @throws IOException if an error occurs
*/
public Terminal build() throws IOException { public Terminal build() throws IOException {
Terminal override = TERMINAL_OVERRIDE.get(); Terminal override = TERMINAL_OVERRIDE.get();
Terminal terminal = override != null ? override : doBuild(); Terminal terminal = override != null ? override : doBuild();
@ -313,7 +393,8 @@ public final class TerminalBuilder {
} }
Log.debug(() -> "Using terminal " + terminal.getClass().getSimpleName()); Log.debug(() -> "Using terminal " + terminal.getClass().getSimpleName());
if (terminal instanceof AbstractPosixTerminal) { if (terminal instanceof AbstractPosixTerminal) {
Log.debug(() -> "Using pty " + ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName()); Log.debug(() -> "Using pty "
+ ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName());
} }
return terminal; return terminal;
} }
@ -323,6 +404,242 @@ public final class TerminalBuilder {
if (name == null) { if (name == null) {
name = "JLine terminal"; 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; Charset encoding = this.encoding;
if (encoding == null) { if (encoding == null) {
String charsetName = System.getProperty(PROP_ENCODING); String charsetName = System.getProperty(PROP_ENCODING);
@ -344,206 +661,84 @@ public final class TerminalBuilder {
encoding = StandardCharsets.UTF_8; encoding = StandardCharsets.UTF_8;
} }
} }
String type = this.type; return encoding;
if (type == null) {
type = System.getProperty(PROP_TYPE);
} }
if (type == null) {
type = System.getenv("TERM"); /**
} * Get the list of available terminal providers.
Boolean jna = this.jna; * This list is sorted according to the {@link #PROP_PROVIDERS} system property.
if (jna == null) { * @param provider if not {@code null}, only this provider will be checked
jna = getBoolean(PROP_JNA, true); * @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
Boolean jansi = this.jansi; */
if (jansi == null) { public List<TerminalProvider> getProviders(String provider, IllegalStateException exception) {
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<>(); List<TerminalProvider> providers = new ArrayList<>();
if (jna) { // 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 { try {
TerminalProvider provider = TerminalProvider.load("jna"); TerminalProvider prov = TerminalProvider.load(name);
providers.add(provider); prov.isSystemStream(SystemStream.Output);
providers.add(prov);
} catch (Throwable t) { } catch (Throwable t) {
Log.debug("Unable to load JNA support: ", t); Log.debug("Unable to load " + name + " provider: ", t);
exception.addSuppressed(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; private SystemStream select(Map<SystemStream, Boolean> system, SystemOutput systemOutput) {
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;
}
private TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, SystemOutput systemOutput) {
switch (systemOutput) { switch (systemOutput) {
case SysOut: case SysOut:
return select(system, TerminalProvider.Stream.Output); return select(system, SystemStream.Output);
case SysErr: case SysErr:
return select(system, TerminalProvider.Stream.Error); return select(system, SystemStream.Error);
case SysOutOrSysErr: case SysOutOrSysErr:
return select(system, TerminalProvider.Stream.Output, TerminalProvider.Stream.Error); return select(system, SystemStream.Output, SystemStream.Error);
case SysErrOrSysOut: 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; return null;
} }
private static TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, TerminalProvider.Stream... streams) { private static SystemStream select(Map<SystemStream, Boolean> system, SystemStream... streams) {
for (TerminalProvider.Stream s : streams) { for (SystemStream s : streams) {
if (system.get(s)) { if (system.get(s)) {
return s; return s;
} }
@ -558,7 +753,9 @@ public final class TerminalBuilder {
Object parent = ((Optional<?>) phClass.getMethod("parent").invoke(current)).orElse(null); Object parent = ((Optional<?>) phClass.getMethod("parent").invoke(current)).orElse(null);
Method infoMethod = phClass.getMethod("info"); Method infoMethod = phClass.getMethod("info");
Object info = infoMethod.invoke(parent); 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; return (String) command;
} catch (Throwable t) { } catch (Throwable t) {
return null; return null;
@ -583,7 +780,7 @@ public final class TerminalBuilder {
private static final int UTF8_CODE_PAGE = 65001; private static final int UTF8_CODE_PAGE = 65001;
private static Charset getCodepageCharset(int codepage) { 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) { if (codepage == UTF8_CODE_PAGE) {
return StandardCharsets.UTF_8; return StandardCharsets.UTF_8;
} }
@ -630,5 +827,4 @@ public final class TerminalBuilder {
public static void setTerminalOverride(final Terminal terminal) { public static void setTerminalOverride(final Terminal terminal) {
TERMINAL_OVERRIDE.set(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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.Cursor;
import jdk.internal.org.jline.terminal.Size; import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.spi.Pty; 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 { public abstract class AbstractPosixTerminal extends AbstractTerminal {
@ -28,7 +30,8 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
this(name, type, pty, null, SignalHandler.SIG_DFL); 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); super(name, type, encoding, signalHandler);
Objects.requireNonNull(pty); Objects.requireNonNull(pty);
this.pty = pty; this.pty = pty;
@ -82,4 +85,13 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
return CursorSupport.getCursorPosition(this, discarded); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,20 +8,39 @@
*/ */
package jdk.internal.org.jline.terminal.impl; package jdk.internal.org.jline.terminal.impl;
import jdk.internal.org.jline.terminal.Attributes; import java.io.FileDescriptor;
import jdk.internal.org.jline.terminal.spi.Pty; import java.io.FilterInputStream;
import jdk.internal.org.jline.utils.NonBlockingInputStream;
import java.io.IOError; import java.io.IOError;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InterruptedIOException; 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; import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_NON_BLOCKING_READS;
public abstract class AbstractPty implements Pty { public abstract class AbstractPty implements Pty {
protected final TerminalProvider provider;
protected final SystemStream systemStream;
private Attributes current; private Attributes current;
private boolean skipNextLf;
public AbstractPty(TerminalProvider provider, SystemStream systemStream) {
this.provider = provider;
this.systemStream = systemStream;
}
@Override @Override
public void setAttr(Attributes attr) throws IOException { public void setAttr(Attributes attr) throws IOException {
@ -32,10 +51,32 @@ public abstract class AbstractPty implements Pty {
@Override @Override
public InputStream getSlaveInput() throws IOException { public InputStream getSlaveInput() throws IOException {
InputStream si = doGetSlaveInput(); InputStream si = doGetSlaveInput();
if (Boolean.parseBoolean(System.getProperty(PROP_NON_BLOCKING_READS, "true"))) { InputStream nsi = new FilterInputStream(si) {
return new PtyInputStream(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 { } else {
return si; skipNextLf = false;
}
}
return c;
}
}
};
if (Boolean.parseBoolean(System.getProperty(PROP_NON_BLOCKING_READS, "true"))) {
return new PtyInputStream(nsi);
} else {
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 { class PtyInputStream extends NonBlockingInputStream {
final InputStream in; final InputStream in;
int c = 0; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.Attributes.LocalFlag;
import jdk.internal.org.jline.terminal.Cursor; import jdk.internal.org.jline.terminal.Cursor;
import jdk.internal.org.jline.terminal.MouseEvent; 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.ColorPalette;
import jdk.internal.org.jline.utils.Curses; import jdk.internal.org.jline.utils.Curses;
import jdk.internal.org.jline.utils.InfoCmp; 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.Log;
import jdk.internal.org.jline.utils.Status; 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 name;
protected final String type; protected final String type;
@ -44,7 +44,7 @@ public abstract class AbstractTerminal implements Terminal {
protected final Set<Capability> bools = new HashSet<>(); protected final Set<Capability> bools = new HashSet<>();
protected final Map<Capability, Integer> ints = new HashMap<>(); protected final Map<Capability, Integer> ints = new HashMap<>();
protected final Map<Capability, String> strings = 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 Status status;
protected Runnable onClose; protected Runnable onClose;
@ -52,10 +52,13 @@ public abstract class AbstractTerminal implements Terminal {
this(name, type, null, SignalHandler.SIG_DFL); 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.name = name;
this.type = type != null ? type : "ansi"; this.type = type != null ? type : "ansi";
this.encoding = encoding != null ? encoding : System.out.charset(); this.encoding = encoding != null ? encoding : System.out.charset();
this.palette = new ColorPalette(this);
for (Signal signal : Signal.values()) { for (Signal signal : Signal.values()) {
handlers.put(signal, signalHandler); handlers.put(signal, signalHandler);
} }
@ -85,12 +88,13 @@ public abstract class AbstractTerminal implements Terminal {
public void raise(Signal signal) { public void raise(Signal signal) {
Objects.requireNonNull(signal); Objects.requireNonNull(signal);
SignalHandler handler = handlers.get(signal); SignalHandler handler = handlers.get(signal);
if (handler != SignalHandler.SIG_DFL && handler != SignalHandler.SIG_IGN) { if (handler == SignalHandler.SIG_DFL) {
handler.handle(signal);
}
if (status != null && signal == Signal.WINCH) { if (status != null && signal == Signal.WINCH) {
status.resize(); status.resize();
} }
} else if (handler != SignalHandler.SIG_IGN) {
handler.handle(signal);
}
} }
public final void close() throws IOException { public final void close() throws IOException {
@ -105,8 +109,7 @@ public abstract class AbstractTerminal implements Terminal {
protected void doClose() throws IOException { protected void doClose() throws IOException {
if (status != null) { if (status != null) {
status.update(null); status.close();
flush();
} }
} }
@ -126,7 +129,7 @@ public abstract class AbstractTerminal implements Terminal {
if (cc != null) { if (cc != null) {
int vcc = getAttributes().getControlChar(cc); int vcc = getAttributes().getControlChar(cc);
if (vcc > 0 && vcc < 32) { 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( private MouseEvent lastMouseEvent = new MouseEvent(
MouseEvent.Type.Moved, MouseEvent.Button.NoButton, MouseEvent.Type.Moved, MouseEvent.Button.NoButton, EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
@Override @Override
public boolean hasMouseSupport() { public boolean hasMouseSupport() {
@ -268,16 +270,13 @@ public abstract class AbstractTerminal implements Terminal {
} }
@Override @Override
public void pause() { public void pause() {}
}
@Override @Override
public void pause(boolean wait) throws InterruptedException { public void pause(boolean wait) throws InterruptedException {}
}
@Override @Override
public void resume() { public void resume() {}
}
@Override @Override
public boolean paused() { 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -29,11 +29,8 @@ public abstract class AbstractWindowsConsoleWriter extends Writer {
} }
@Override @Override
public void flush() { public void flush() {}
}
@Override @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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,8 +8,20 @@
*/ */
package jdk.internal.org.jline.terminal.impl; 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.Attributes;
import jdk.internal.org.jline.terminal.Size; 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.Curses;
import jdk.internal.org.jline.utils.InfoCmp; import jdk.internal.org.jline.utils.InfoCmp;
import jdk.internal.org.jline.utils.Log; 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.Signals;
import jdk.internal.org.jline.utils.WriterOutputStream; 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. * The AbstractWindowsTerminal is used as the base class for windows terminal.
* Due to windows limitations, mostly the missing support for ansi sequences, * 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 * the writer() becomes the primary output, while the output() is bridged
* to the writer() using a WriterOutputStream wrapper. * 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 = "windows";
public static final String TYPE_WINDOWS_256_COLOR = "windows-256color"; public static final String TYPE_WINDOWS_256_COLOR = "windows-256color";
@ -62,6 +63,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
protected static final int ENABLE_MOUSE_INPUT = 0x0010; protected static final int ENABLE_MOUSE_INPUT = 0x0010;
protected static final int ENABLE_INSERT_MODE = 0x0020; protected static final int ENABLE_INSERT_MODE = 0x0020;
protected static final int ENABLE_QUICK_EDIT_MODE = 0x0040; protected static final int ENABLE_QUICK_EDIT_MODE = 0x0040;
protected static final int ENABLE_EXTENDED_FLAGS = 0x0080;
protected final Writer slaveInputPipe; protected final Writer slaveInputPipe;
protected final InputStream input; protected final InputStream input;
@ -71,7 +73,12 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
protected final Map<Signal, Object> nativeHandlers = new HashMap<>(); protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
protected final ShutdownHooks.Task closer; protected final ShutdownHooks.Task closer;
protected final Attributes attributes = new Attributes(); 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 final Object lock = new Object();
protected boolean paused = true; protected boolean paused = true;
@ -80,18 +87,39 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
protected MouseTracking tracking = MouseTracking.Off; protected MouseTracking tracking = MouseTracking.Off;
protected boolean focusTracking = false; protected boolean focusTracking = false;
private volatile boolean closing; 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); super(name, type, encoding, signalHandler);
this.provider = provider;
this.systemStream = systemStream;
NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader(); NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader();
this.slaveInputPipe = reader.getWriter(); this.slaveInputPipe = reader.getWriter();
this.input = inputStreamWrapper.apply(NonBlocking.nonBlockingStream(reader, encoding())); this.input = inputStreamWrapper.apply(NonBlocking.nonBlockingStream(reader, encoding()));
this.reader = NonBlocking.nonBlocking(name, input, encoding()); this.reader = NonBlocking.nonBlocking(name, input, encoding());
this.writer = new PrintWriter(writer); this.writer = new PrintWriter(writer);
this.output = new WriterOutputStream(writer, encoding()); this.output = new WriterOutputStream(writer, encoding());
this.inConsole = inConsole;
this.outConsole = outConsole;
parseInfoCmp(); parseInfoCmp();
// Attributes // Attributes
originalConsoleMode = getConsoleMode(); this.originalInConsoleMode = inConsoleMode;
this.originalOutConsoleMode = outConsoleMode;
attributes.setLocalFlag(Attributes.LocalFlag.ISIG, true); attributes.setLocalFlag(Attributes.LocalFlag.ISIG, true);
attributes.setControlChar(Attributes.ControlChar.VINTR, ctrl('C')); attributes.setControlChar(Attributes.ControlChar.VINTR, ctrl('C'));
attributes.setControlChar(Attributes.ControlChar.VEOF, ctrl('D')); attributes.setControlChar(Attributes.ControlChar.VEOF, ctrl('D'));
@ -148,7 +176,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} }
public Attributes getAttributes() { public Attributes getAttributes() {
int mode = getConsoleMode(); int mode = getConsoleMode(inConsole);
if ((mode & ENABLE_ECHO_INPUT) != 0) { if ((mode & ENABLE_ECHO_INPUT) != 0) {
attributes.setLocalFlag(Attributes.LocalFlag.ECHO, true); attributes.setLocalFlag(Attributes.LocalFlag.ECHO, true);
} }
@ -173,8 +201,11 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} }
if (tracking != MouseTracking.Off) { if (tracking != MouseTracking.Off) {
mode |= ENABLE_MOUSE_INPUT; 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) { protected int ctrl(char key) {
@ -197,7 +228,8 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} }
reader.close(); reader.close();
writer.close(); writer.close();
setConsoleMode(originalConsoleMode); setConsoleMode(inConsole, originalInConsoleMode);
setConsoleMode(outConsole, originalOutConsoleMode);
} }
static final int SHIFT_FLAG = 0x01; static final int SHIFT_FLAG = 0x01;
@ -213,7 +245,9 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
static final int SCROLLLOCK_ON = 0x0040; static final int SCROLLLOCK_ON = 0x0040;
static final int CAPSLOCK_ON = 0x0080; 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 isCtrl = (controlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) > 0;
final boolean isAlt = (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) > 0; final boolean isAlt = (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) > 0;
final boolean isShift = (controlKeyState & SHIFT_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, // 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 // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
if (ch != 0 if (ch != 0
&& (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED | SHIFT_PRESSED)) && (controlKeyState
& (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
== (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) { == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
processInputChar(ch); processInputChar(ch);
} else { } 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) { if (keySeq != null) {
for (char c : keySeq.toCharArray()) { for (char c : keySeq.toCharArray()) {
processInputChar(c); processInputChar(c);
@ -254,10 +290,10 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} else { } else {
processInputChar(ch); 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') { if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') {
ch = (char) (virtualKeyCode - 0x40); ch = (char) (virtualKeyCode - 0x40);
} else if (virtualKeyCode == 191) { //? } else if (virtualKeyCode == 191) { // ?
ch = 127; ch = 127;
} }
if (ch > 0) { if (ch > 0) {
@ -468,7 +504,19 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
raise(Signal.INFO); raise(Signal.INFO);
} }
} }
if (attributes.getInputFlag(Attributes.InputFlag.INORMEOL)) {
if (c == '\r') { 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)) { if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
return; return;
} }
@ -478,10 +526,10 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
} else if (c == '\n' && attributes.getInputFlag(Attributes.InputFlag.INLCR)) { } else if (c == '\n' && attributes.getInputFlag(Attributes.InputFlag.INLCR)) {
c = '\r'; c = '\r';
} }
// if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) { // if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
// processOutputByte(c); // processOutputByte(c);
// masterOutput.flush(); // masterOutput.flush();
// } // }
slaveInputPipe.write(c); slaveInputPipe.write(c);
} }
@ -492,9 +540,9 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
return true; 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. * 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; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,17 +8,17 @@
*/ */
package jdk.internal.org.jline.terminal.impl; 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.IOError;
import java.io.IOException; import java.io.IOException;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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 class CursorSupport {
public static Cursor getCursorPosition(Terminal terminal, IntConsumer discarded) { public static Cursor getCursorPosition(Terminal terminal, IntConsumer discarded) {
@ -105,5 +105,4 @@ public class CursorSupport {
throw new IOError(e); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.Attributes;
import jdk.internal.org.jline.terminal.Terminal; 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.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.OSUtils; import jdk.internal.org.jline.utils.OSUtils;
@ -26,7 +27,7 @@ public class Diag {
diag(System.out); diag(System.out);
} }
static void diag(PrintStream out) { public static void diag(PrintStream out) {
out.println("System properties"); out.println("System properties");
out.println("================="); out.println("=================");
out.println("os.name = " + System.getProperty("os.name")); out.println("os.name = " + System.getProperty("os.name"));
@ -50,6 +51,17 @@ public class Diag {
out.println("IS_OSX = " + OSUtils.IS_OSX); out.println("IS_OSX = " + OSUtils.IS_OSX);
out.println(); 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("JnaSupport");
out.println("================="); out.println("=================");
try { try {
@ -60,13 +72,23 @@ public class Diag {
} }
out.println(); out.println();
out.println("JansiSupport"); out.println("Jansi2Support");
out.println("================="); out.println("=================");
try { try {
TerminalProvider provider = TerminalProvider.load("jansi"); TerminalProvider provider = TerminalProvider.load("jansi");
testProvider(out, provider); testProvider(out, provider);
} catch (Throwable t) { } 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(); out.println();
@ -83,32 +105,45 @@ public class Diag {
private static void testProvider(PrintStream out, TerminalProvider provider) { private static void testProvider(PrintStream out, TerminalProvider provider) {
try { try {
out.println("StdIn stream = " + provider.isSystemStream(TerminalProvider.Stream.Input)); out.println("StdIn stream = " + provider.isSystemStream(SystemStream.Input));
out.println("StdOut stream = " + provider.isSystemStream(TerminalProvider.Stream.Output)); out.println("StdOut stream = " + provider.isSystemStream(SystemStream.Output));
out.println("StdErr stream = " + provider.isSystemStream(TerminalProvider.Stream.Error)); out.println("StdErr stream = " + provider.isSystemStream(SystemStream.Error));
} catch (Throwable t2) { } catch (Throwable t2) {
out.println("Unable to check stream: " + t2); out.println("Unable to check stream: " + t2);
} }
try { try {
out.println("StdIn stream name = " + provider.systemStreamName(TerminalProvider.Stream.Input)); out.println("StdIn stream name = " + provider.systemStreamName(SystemStream.Input));
out.println("StdOut stream name = " + provider.systemStreamName(TerminalProvider.Stream.Output)); out.println("StdOut stream name = " + provider.systemStreamName(SystemStream.Output));
out.println("StdErr stream name = " + provider.systemStreamName(TerminalProvider.Stream.Error)); out.println("StdErr stream name = " + provider.systemStreamName(SystemStream.Error));
} catch (Throwable t2) { } catch (Throwable t2) {
out.println("Unable to check stream names: " + t2); out.println("Unable to check stream names: " + t2);
} }
try (Terminal terminal = provider.sysTerminal("diag", "xterm", false, StandardCharsets.UTF_8, try (Terminal terminal = provider.sysTerminal(
false, Terminal.SignalHandler.SIG_DFL, false, TerminalProvider.Stream.Output, input -> input) ) { "diag",
"xterm",
false,
StandardCharsets.UTF_8,
false,
Terminal.SignalHandler.SIG_DFL,
false,
SystemStream.Output,
input -> input)) {
if (terminal != null) { if (terminal != null) {
Attributes attr = terminal.enterRawMode(); Attributes attr = terminal.enterRawMode();
try { try {
out.println("Terminal size: " + terminal.getSize()); 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); int r = t.get(1000, TimeUnit.MILLISECONDS);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("The terminal seems to work: "); sb.append("The terminal seems to work: ");
sb.append("terminal ").append(terminal.getClass().getName()); sb.append("terminal ").append(terminal.getClass().getName());
if (terminal instanceof AbstractPosixTerminal) { 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); out.println(sb);
} catch (Throwable t3) { } catch (Throwable t3) {
@ -129,5 +164,4 @@ public class Diag {
static <S> S load(Class<S> clazz) { static <S> S load(Class<S> clazz) {
return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -14,38 +14,58 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes; import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Attributes.ControlChar; import jdk.internal.org.jline.terminal.Attributes.ControlChar;
import jdk.internal.org.jline.terminal.Size; 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.NonBlocking;
import jdk.internal.org.jline.utils.NonBlockingInputStream; import jdk.internal.org.jline.utils.NonBlockingInputStream;
import jdk.internal.org.jline.utils.NonBlockingReader; import jdk.internal.org.jline.utils.NonBlockingReader;
public class DumbTerminal extends AbstractTerminal { public class DumbTerminal extends AbstractTerminal {
private final TerminalProvider provider;
private final SystemStream systemStream;
private final NonBlockingInputStream input; private final NonBlockingInputStream input;
private final OutputStream output; private final OutputStream output;
private final NonBlockingReader reader; private final NonBlockingReader reader;
private final PrintWriter writer; private final PrintWriter writer;
private final Attributes attributes; private final Attributes attributes;
private final Size size; private final Size size;
private boolean skipNextLf;
public DumbTerminal(InputStream in, OutputStream out) throws IOException { public DumbTerminal(InputStream in, OutputStream out, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
this(TYPE_DUMB, TYPE_DUMB, in, out, null); this(TYPE_DUMB, TYPE_DUMB, in, out, null, inputStreamWrapper);
} }
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding) throws IOException { public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding, Function<InputStream, InputStream> inputStreamWrapper)
this(name, type, in, out, encoding, SignalHandler.SIG_DFL); 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); 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() { this.input = new NonBlockingInputStream() {
@Override @Override
public int read(long timeout, boolean isPeek) throws IOException { public int read(long timeout, boolean isPeek) throws IOException {
for (;;) { for (; ; ) {
int c = nbis.read(timeout, isPeek); int c = nbis.read(timeout, isPeek);
if (attributes.getLocalFlag(Attributes.LocalFlag.ISIG)) { if (attributes.getLocalFlag(Attributes.LocalFlag.ISIG)) {
if (c == attributes.getControlChar(ControlChar.VINTR)) { if (c == attributes.getControlChar(ControlChar.VINTR)) {
@ -62,7 +82,19 @@ public class DumbTerminal extends AbstractTerminal {
continue; continue;
} }
} }
if (attributes.getInputFlag(Attributes.InputFlag.INORMEOL)) {
if (c == '\r') { 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)) { if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
continue; continue;
} }
@ -107,9 +139,7 @@ public class DumbTerminal extends AbstractTerminal {
} }
public Attributes getAttributes() { public Attributes getAttributes() {
Attributes attr = new Attributes(); return new Attributes(attributes);
attr.copy(attributes);
return attr;
} }
public void setAttributes(Attributes attr) { public void setAttributes(Attributes attr) {
@ -126,4 +156,13 @@ public class DumbTerminal extends AbstractTerminal {
size.copy(sz); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,10 +8,6 @@
*/ */
package jdk.internal.org.jline.terminal.impl; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -19,6 +15,11 @@ import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.IntConsumer; 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. * Console implementation with embedded line disciplined.
* *
@ -32,45 +33,59 @@ import java.util.function.IntConsumer;
*/ */
public class ExternalTerminal extends LineDisciplineTerminal { public class ExternalTerminal extends LineDisciplineTerminal {
private final TerminalProvider provider;
protected final AtomicBoolean closed = new AtomicBoolean(); protected final AtomicBoolean closed = new AtomicBoolean();
protected final InputStream masterInput; protected final InputStream masterInput;
protected final Object lock = new Object(); protected final Object lock = new Object();
protected boolean paused = true; protected boolean paused = true;
protected Thread pumpThread; protected Thread pumpThread;
public ExternalTerminal(String name, String type, public ExternalTerminal(
InputStream masterInput, String name, String type, InputStream masterInput, OutputStream masterOutput, Charset encoding)
OutputStream masterOutput, throws IOException {
Charset encoding) throws IOException { this(null, name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
this(name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
} }
public ExternalTerminal(String name, String type, public ExternalTerminal(
TerminalProvider provider,
String name,
String type,
InputStream masterInput, InputStream masterInput,
OutputStream masterOutput, OutputStream masterOutput,
Charset encoding, Charset encoding,
SignalHandler signalHandler) throws IOException { SignalHandler signalHandler)
this(name, type, masterInput, masterOutput, encoding, signalHandler, false); throws IOException {
this(provider, name, type, masterInput, masterOutput, encoding, signalHandler, false);
} }
public ExternalTerminal(String name, String type, public ExternalTerminal(
TerminalProvider provider,
String name,
String type,
InputStream masterInput, InputStream masterInput,
OutputStream masterOutput, OutputStream masterOutput,
Charset encoding, Charset encoding,
SignalHandler signalHandler, SignalHandler signalHandler,
boolean paused) throws IOException { boolean paused)
this(name, type, masterInput, masterOutput, encoding, signalHandler, paused, null, null); throws IOException {
this(provider, name, type, masterInput, masterOutput, encoding, signalHandler, paused, null, null);
} }
public ExternalTerminal(String name, String type, @SuppressWarnings("this-escape")
public ExternalTerminal(
TerminalProvider provider,
String name,
String type,
InputStream masterInput, InputStream masterInput,
OutputStream masterOutput, OutputStream masterOutput,
Charset encoding, Charset encoding,
SignalHandler signalHandler, SignalHandler signalHandler,
boolean paused, boolean paused,
Attributes attributes, Attributes attributes,
Size size) throws IOException { Size size)
throws IOException {
super(name, type, masterOutput, encoding, signalHandler); super(name, type, masterOutput, encoding, signalHandler);
this.provider = provider;
this.masterInput = masterInput; this.masterInput = masterInput;
if (attributes != null) { if (attributes != null) {
setAttributes(attributes); setAttributes(attributes);
@ -171,4 +186,8 @@ public class ExternalTerminal extends LineDisciplineTerminal {
return CursorSupport.getCursorPosition(this, discarded); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -14,6 +14,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.EnumSet;
import java.util.Objects; import java.util.Objects;
import jdk.internal.org.jline.terminal.Attributes; 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.Attributes.OutputFlag;
import jdk.internal.org.jline.terminal.Size; import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal; 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.NonBlocking;
import jdk.internal.org.jline.utils.NonBlockingPumpInputStream; import jdk.internal.org.jline.utils.NonBlockingPumpInputStream;
import jdk.internal.org.jline.utils.NonBlockingReader; import jdk.internal.org.jline.utils.NonBlockingReader;
@ -45,21 +48,6 @@ import jdk.internal.org.jline.utils.NonBlockingReader;
*/ */
public class LineDisciplineTerminal extends AbstractTerminal { 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; private static final int PIPE_SIZE = 1024;
/* /*
@ -84,20 +72,20 @@ public class LineDisciplineTerminal extends AbstractTerminal {
* Console data * Console data
*/ */
protected final Attributes attributes; protected final Attributes attributes;
protected final Size size; protected final Size size;
public LineDisciplineTerminal(String name, protected boolean skipNextLf;
String type,
OutputStream masterOutput, public LineDisciplineTerminal(String name, String type, OutputStream masterOutput, Charset encoding)
Charset encoding) throws IOException { throws IOException {
this(name, type, masterOutput, encoding, SignalHandler.SIG_DFL); this(name, type, masterOutput, encoding, SignalHandler.SIG_DFL);
} }
public LineDisciplineTerminal(String name, @SuppressWarnings("this-escape")
String type, public LineDisciplineTerminal(
OutputStream masterOutput, String name, String type, OutputStream masterOutput, Charset encoding, SignalHandler signalHandler)
Charset encoding, throws IOException {
SignalHandler signalHandler) throws IOException {
super(name, type, encoding, signalHandler); super(name, type, encoding, signalHandler);
NonBlockingPumpInputStream input = NonBlocking.nonBlockingPumpInputStream(PIPE_SIZE); NonBlockingPumpInputStream input = NonBlocking.nonBlockingPumpInputStream(PIPE_SIZE);
this.slaveInputPipe = input.getOutputStream(); this.slaveInputPipe = input.getOutputStream();
@ -106,11 +94,66 @@ public class LineDisciplineTerminal extends AbstractTerminal {
this.slaveOutput = new FilteringOutputStream(); this.slaveOutput = new FilteringOutputStream();
this.slaveWriter = new PrintWriter(new OutputStreamWriter(slaveOutput, encoding())); this.slaveWriter = new PrintWriter(new OutputStreamWriter(slaveOutput, encoding()));
this.masterOutput = masterOutput; this.masterOutput = masterOutput;
this.attributes = ExecPty.doGetAttr(DEFAULT_TERMINAL_ATTRIBUTES); this.attributes = getDefaultTerminalAttributes();
this.size = new Size(160, 50); this.size = new Size(160, 50);
parseInfoCmp(); 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() { public NonBlockingReader reader() {
return slaveReader; return slaveReader;
} }
@ -130,9 +173,7 @@ public class LineDisciplineTerminal extends AbstractTerminal {
} }
public Attributes getAttributes() { public Attributes getAttributes() {
Attributes attr = new Attributes(); return new Attributes(attributes);
attr.copy(attributes);
return attr;
} }
public void setAttributes(Attributes attr) { public void setAttributes(Attributes attr) {
@ -214,7 +255,19 @@ public class LineDisciplineTerminal extends AbstractTerminal {
raise(Signal.INFO); raise(Signal.INFO);
} }
} }
if (attributes.getInputFlag(InputFlag.INORMEOL)) {
if (c == '\r') { 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)) { if (attributes.getInputFlag(InputFlag.IGNCR)) {
return false; 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 { private class FilteringOutputStream extends OutputStream {
@Override @Override
public void write(int b) throws IOException { 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 { public void write(byte[] b, int off, int len) throws IOException {
if (b == null) { if (b == null) {
throw new NullPointerException(); throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) || } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} else if (len == 0) { } else if (len == 0) {
return; return;
} }
for (int i = 0 ; i < len ; i++) { for (int i = 0; i < len; i++) {
processOutputByte(b[off + i]); processOutputByte(b[off + i]);
} }
flush(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -8,11 +8,6 @@
*/ */
package jdk.internal.org.jline.terminal.impl; 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.EOFException;
import java.io.IOError; import java.io.IOError;
import java.io.IOException; import java.io.IOException;
@ -20,6 +15,11 @@ import java.nio.charset.StandardCharsets;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.function.IntSupplier; 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 class MouseSupport {
public static boolean hasMouseSupport(Terminal terminal) { public static boolean hasMouseSupport(Terminal terminal) {
@ -78,7 +78,8 @@ public class MouseSupport {
case 0: case 0:
button = MouseEvent.Button.Button1; button = MouseEvent.Button.Button1;
if (last.getButton() == button 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; type = MouseEvent.Type.Dragged;
} else { } else {
type = MouseEvent.Type.Pressed; type = MouseEvent.Type.Pressed;
@ -87,7 +88,8 @@ public class MouseSupport {
case 1: case 1:
button = MouseEvent.Button.Button2; button = MouseEvent.Button.Button2;
if (last.getButton() == button 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; type = MouseEvent.Type.Dragged;
} else { } else {
type = MouseEvent.Type.Pressed; type = MouseEvent.Type.Pressed;
@ -96,7 +98,8 @@ public class MouseSupport {
case 2: case 2:
button = MouseEvent.Button.Button3; button = MouseEvent.Button.Button3;
if (last.getButton() == button 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; type = MouseEvent.Type.Dragged;
} else { } else {
type = MouseEvent.Type.Pressed; type = MouseEvent.Type.Pressed;
@ -134,5 +137,4 @@ public class MouseSupport {
throw new IOError(e); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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(); public static final NativeSignalHandler SIG_IGN = new NativeSignalHandler();
private NativeSignalHandler() { private NativeSignalHandler() {}
}
public void handle(Signal signal) { public void handle(Signal signal) {
throw new UnsupportedOperationException(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -38,15 +38,34 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
private Thread outputPumpThread; private Thread outputPumpThread;
private boolean paused = true; 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); 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); 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); super(name, type, pty, encoding, signalHandler);
this.in = Objects.requireNonNull(in); this.in = Objects.requireNonNull(in);
this.out = Objects.requireNonNull(out); this.out = Objects.requireNonNull(out);
@ -113,7 +132,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
if (p1 != null) { if (p1 != null) {
p1.join(); p1.join();
} }
if (p2 !=null) { if (p2 != null) {
p2.join(); p2.join();
} }
} }
@ -167,7 +186,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
private void pumpIn() { private void pumpIn() {
try { try {
for (;;) { for (; ; ) {
synchronized (lock) { synchronized (lock) {
if (paused) { if (paused) {
inputPumpThread = null; inputPumpThread = null;
@ -193,7 +212,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
private void pumpOut() { private void pumpOut() {
try { try {
for (;;) { for (; ; ) {
synchronized (lock) { synchronized (lock) {
if (paused) { if (paused) {
outputPumpThread = null; outputPumpThread = null;
@ -221,5 +240,4 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
// Ignore // 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -18,8 +18,9 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; 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.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.NonBlockingInputStream;
import jdk.internal.org.jline.utils.NonBlockingReader; import jdk.internal.org.jline.utils.NonBlockingReader;
import jdk.internal.org.jline.utils.ShutdownHooks; 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 Map<Signal, Object> nativeHandlers = new HashMap<>();
protected final Task closer; protected final Task closer;
public PosixSysTerminal(String name, String type, Pty pty, Charset encoding, @SuppressWarnings("this-escape")
boolean nativeSignals, SignalHandler signalHandler, public PosixSysTerminal(
Function<InputStream, InputStream> inputStreamWrapper) throws IOException { String name, String type, Pty pty, Charset encoding, boolean nativeSignals, SignalHandler signalHandler,
Function<InputStream, InputStream> inputStreamWrapper)
throws IOException {
super(name, type, pty, encoding, signalHandler); super(name, type, pty, encoding, signalHandler);
this.input = NonBlocking.nonBlocking(getName(), inputStreamWrapper.apply(pty.getSlaveInput())); 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.reader = NonBlocking.nonBlocking(getName(), input, encoding());
this.writer = new PrintWriter(new OutputStreamWriter(output, encoding())); this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
parseInfoCmp(); parseInfoCmp();
@ -98,5 +101,4 @@ public class PosixSysTerminal extends AbstractPosixTerminal {
// Do not call reader.close() // Do not call reader.close()
reader.shutdown(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
* *
* https://opensource.org/licenses/BSD-3-Clause * 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.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.FileDescriptor;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.LocalFlag;
import jdk.internal.org.jline.terminal.Attributes.OutputFlag; import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
import jdk.internal.org.jline.terminal.Size; 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.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 jdk.internal.org.jline.utils.OSUtils;
import static jdk.internal.org.jline.utils.ExecHelper.exec; 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 { public class ExecPty extends AbstractPty implements Pty {
private final String name; 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 { try {
String result = exec(true, OSUtils.TTY_COMMAND); String result = exec(true, OSUtils.TTY_COMMAND);
if (console != TerminalProvider.Stream.Output && console != TerminalProvider.Stream.Error) { if (systemStream != SystemStream.Output && systemStream != SystemStream.Error) {
throw new IllegalArgumentException("console should be Output or Error: " + console); 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) { } catch (IOException e) {
throw new IOException("Not a tty", 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.name = name;
this.console = console;
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {}
}
public String getName() { public String getName() {
return name; return name;
@ -74,16 +74,14 @@ public class ExecPty extends AbstractPty implements Pty {
@Override @Override
protected InputStream doGetSlaveInput() throws IOException { protected InputStream doGetSlaveInput() throws IOException {
return console != null return systemStream != null ? new FileInputStream(FileDescriptor.in) : new FileInputStream(getName());
? new FileInputStream(FileDescriptor.in)
: new FileInputStream(getName());
} }
@Override @Override
public OutputStream getSlaveOutput() throws IOException { public OutputStream getSlaveOutput() throws IOException {
return console == TerminalProvider.Stream.Output return systemStream == SystemStream.Output
? new FileOutputStream(FileDescriptor.out) ? new FileOutputStream(FileDescriptor.out)
: console == TerminalProvider.Stream.Error : systemStream == SystemStream.Error
? new FileOutputStream(FileDescriptor.err) ? new FileOutputStream(FileDescriptor.err)
: new FileOutputStream(getName()); : new FileOutputStream(getName());
} }
@ -99,18 +97,30 @@ public class ExecPty extends AbstractPty implements Pty {
List<String> commands = getFlagsToSet(attr, getAttr()); List<String> commands = getFlagsToSet(attr, getAttr());
if (!commands.isEmpty()) { if (!commands.isEmpty()) {
commands.add(0, OSUtils.STTY_COMMAND); commands.add(0, OSUtils.STTY_COMMAND);
if (console == null) { if (systemStream == null) {
commands.add(1, OSUtils.STTY_F_OPTION); commands.add(1, OSUtils.STTY_F_OPTION);
commands.add(2, getName()); 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) { protected List<String> getFlagsToSet(Attributes attr, Attributes current) {
List<String> commands = new ArrayList<>(); List<String> commands = new ArrayList<>();
for (InputFlag flag : InputFlag.values()) { 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()); 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)); commands.add(cchar.name().toLowerCase().substring(1));
if (cchar == ControlChar.VMIN || cchar == ControlChar.VTIME) { if (cchar == ControlChar.VMIN || cchar == ControlChar.VTIME) {
commands.add(Integer.toString(v)); commands.add(Integer.toString(v));
} } else if (v == 0) {
else if (v == 0) {
commands.add(undef); commands.add(undef);
} } else {
else {
if (v >= 128) { if (v >= 128) {
v -= 128; v -= 128;
str += "M-"; str += "M-";
@ -165,12 +173,12 @@ public class ExecPty extends AbstractPty implements Pty {
} }
protected String doGetConfig() throws IOException { protected String doGetConfig() throws IOException {
return console != null return systemStream != null
? exec(true, OSUtils.STTY_COMMAND, "-a") ? exec(true, OSUtils.STTY_COMMAND, "-a")
: exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, getName(), "-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(); Attributes attributes = new Attributes();
for (InputFlag flag : InputFlag.values()) { for (InputFlag flag : InputFlag.values()) {
Boolean value = doGetFlag(cfg, flag); Boolean value = doGetFlag(cfg, flag);
@ -201,16 +209,19 @@ public class ExecPty extends AbstractPty implements Pty {
if ("reprint".endsWith(name)) { if ("reprint".endsWith(name)) {
name = "(?:reprint|rprnt)"; 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()) { if (matcher.find()) {
attributes.setControlChar(cchar, parseControlChar(matcher.group(1).toUpperCase())); attributes.setControlChar(
cchar, parseControlChar(matcher.group(1).toUpperCase()));
} }
} }
return attributes; return attributes;
} }
private static Boolean doGetFlag(String cfg, Enum<?> flag) { 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; 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 { static int doGetInt(String name, String cfg) throws IOException {
String[] patterns = new String[] { String[] patterns = new String[] {
"\\b([0-9]+)\\s+" + name + "\\b", "\\b([0-9]+)\\s+" + name + "\\b", "\\b" + name + "\\s+([0-9]+)\\b", "\\b" + name + "\\s*=\\s*([0-9]+)\\b"
"\\b" + name + "\\s+([0-9]+)\\b",
"\\b" + name + "\\s*=\\s*([0-9]+)\\b"
}; };
for (String pattern : patterns) { for (String pattern : patterns) {
Matcher matcher = Pattern.compile(pattern).matcher(cfg); Matcher matcher = Pattern.compile(pattern).matcher(cfg);
@ -274,23 +283,29 @@ public class ExecPty extends AbstractPty implements Pty {
@Override @Override
public void setSize(Size size) throws IOException { public void setSize(Size size) throws IOException {
if (console != null) { if (systemStream != null) {
exec(true, exec(
true,
OSUtils.STTY_COMMAND, OSUtils.STTY_COMMAND,
"columns", Integer.toString(size.getColumns()), "columns",
"rows", Integer.toString(size.getRows())); Integer.toString(size.getColumns()),
"rows",
Integer.toString(size.getRows()));
} else { } else {
exec(false, exec(
false,
OSUtils.STTY_COMMAND, OSUtils.STTY_COMMAND,
OSUtils.STTY_F_OPTION, getName(), OSUtils.STTY_F_OPTION,
"columns", Integer.toString(size.getColumns()), getName(),
"rows", Integer.toString(size.getRows())); "columns",
Integer.toString(size.getColumns()),
"rows",
Integer.toString(size.getRows()));
} }
} }
@Override @Override
public String toString() { 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.nio.charset.Charset;
import java.util.function.Function; 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.Attributes;
import jdk.internal.org.jline.terminal.Size; import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal; 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.ExternalTerminal;
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal; import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
import jdk.internal.org.jline.terminal.spi.Pty; 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.terminal.spi.TerminalProvider;
import jdk.internal.org.jline.utils.ExecHelper; import jdk.internal.org.jline.utils.ExecHelper;
import jdk.internal.org.jline.utils.Log;
import jdk.internal.org.jline.utils.OSUtils; 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() { public String name() {
return "exec"; return TerminalBuilder.PROP_PROVIDER_EXEC;
} }
public Pty current(Stream consoleStream) throws IOException { public Pty current(SystemStream systemStream) throws IOException {
return ExecPty.current(consoleStream); return ExecPty.current(this, systemStream);
} }
@Override @Override
public Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, public Terminal sysTerminal(
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, String name,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException { 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) { 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 { } 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, public Terminal winSysTerminal(
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, String name,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper ) throws IOException { 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) { 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); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
} else { } else {
return null; return null;
} }
} }
public Terminal posixSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, public Terminal posixSysTerminal(
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, String name,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException { String type,
Pty pty = current(consoleStream); 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); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
} }
@Override @Override
public Terminal newTerminal(String name, String type, InputStream in, OutputStream out, public Terminal newTerminal(
Charset encoding, Terminal.SignalHandler signalHandler, boolean paused, String name,
Attributes attributes, Size size) throws IOException String type,
{ InputStream in,
return new ExternalTerminal(name, type, in, out, encoding, signalHandler, paused, attributes, size); 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 @Override
public boolean isSystemStream(Stream stream) { public boolean isSystemStream(SystemStream stream) {
try { try {
return isWindowsSystemStream(stream) || isPosixSystemStream(stream); return isPosixSystemStream(stream) || isWindowsSystemStream(stream);
} catch (Throwable t) { } catch (Throwable t) {
return false; return false;
} }
} }
public boolean isWindowsSystemStream(Stream stream) { public boolean isWindowsSystemStream(SystemStream stream) {
return systemStreamName( stream ) != null; return systemStreamName(stream) != null;
} }
public boolean isPosixSystemStream(Stream stream) { public boolean isPosixSystemStream(SystemStream stream) {
try { try {
Process p = new ProcessBuilder(OSUtils.TEST_COMMAND, "-t", Integer.toString(stream.ordinal())) Process p = new ProcessBuilder(OSUtils.TEST_COMMAND, "-t", Integer.toString(stream.ordinal()))
.inheritIO().start(); .inheritIO()
.start();
return p.waitFor() == 0; return p.waitFor() == 0;
} catch (Throwable t) { } catch (Throwable t) {
Log.debug("ExecTerminalProvider failed 'test -t' for " + stream, t);
// ignore // ignore
} }
return false; return false;
} }
@Override @Override
public String systemStreamName(Stream stream) { public String systemStreamName(SystemStream stream) {
try { try {
ProcessBuilder.Redirect input = stream == Stream.Input ProcessBuilder.Redirect input = stream == SystemStream.Input
? ProcessBuilder.Redirect.INHERIT ? ProcessBuilder.Redirect.INHERIT
: getRedirect(stream == Stream.Output ? FileDescriptor.out : FileDescriptor.err); : newDescriptor(stream == SystemStream.Output ? FileDescriptor.out : FileDescriptor.err);
Process p = new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start(); Process p =
new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start();
String result = ExecHelper.waitAndCapture(p); String result = ExecHelper.waitAndCapture(p);
if (p.exitValue() == 0) { if (p.exitValue() == 0) {
return result.trim(); return result.trim();
} }
} catch (Throwable t) { } 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 // ignore
} }
return null; return null;
} }
private ProcessBuilder.Redirect getRedirect(FileDescriptor fd) throws ReflectiveOperationException { @Override
// This is not really allowed, but this is the only way to redirect the output or error stream public int systemStreamWidth(SystemStream stream) {
// to the input. This is definitely not something you'd usually want to do, but in the case of try (ExecPty pty = new ExecPty(this, stream, null)) {
// the `tty` utility, it provides a way to get 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"); Class<?> rpi = Class.forName("java.lang.ProcessBuilder$RedirectPipeImpl");
Constructor<?> cns = rpi.getDeclaredConstructor(); constructor = (Constructor<ProcessBuilder.Redirect>) rpi.getDeclaredConstructor();
cns.setAccessible(true); constructor.setAccessible(true);
ProcessBuilder.Redirect input = (ProcessBuilder.Redirect) cns.newInstance(); fdField = rpi.getDeclaredField("fd");
Field f = rpi.getDeclaredField("fd"); fdField.setAccessible(true);
f.setAccessible(true); }
f.set(input, fd);
@Override
public ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd) {
try {
ProcessBuilder.Redirect input = constructor.newInstance();
fdField.set(input, fd);
return input; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -34,4 +34,7 @@ public interface Pty extends Closeable {
void setSize(Size size) throws IOException; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Properties; import java.util.Properties;
import java.util.ServiceLoader;
import java.util.function.Function; import java.util.function.Function;
import jdk.internal.org.jline.terminal.Attributes; import jdk.internal.org.jline.terminal.Attributes;
import jdk.internal.org.jline.terminal.Size; import jdk.internal.org.jline.terminal.Size;
import jdk.internal.org.jline.terminal.Terminal; import jdk.internal.org.jline.terminal.Terminal;
import jdk.internal.org.jline.terminal.impl.exec.ExecTerminalProvider; import jdk.internal.org.jline.terminal.impl.exec.ExecTerminalProvider;
import jdk.internal.org.jline.terminal.impl.ffm.FfmTerminalProvider;
public interface TerminalProvider public interface TerminalProvider {
{
enum Stream {
Input,
Output,
Error
}
String name(); String name();
Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Terminal sysTerminal(
Charset encoding, boolean nativeSignals, String name,
Terminal.SignalHandler signalHandler, boolean paused, String type,
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException; 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, Terminal newTerminal(
InputStream masterInput, OutputStream masterOutput, String name,
Charset encoding, Terminal.SignalHandler signalHandler, String type,
boolean paused, Attributes attributes, Size size) throws IOException; 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 { static TerminalProvider load(String name) throws IOException {
switch (name) { switch (name) {
case "exec": return new ExecTerminalProvider(); case "exec": return new ExecTerminalProvider();
case "jna": { case "ffm": return new FfmTerminalProvider();
try {
return (TerminalProvider) Class.forName("jdk.internal.org.jline.terminal.impl.jna.JnaTerminalProvider").getConstructor().newInstance();
} catch (ReflectiveOperationException t) {
throw new IOException(t);
}
}
} }
ClassLoader cl = Thread.currentThread().getContextClassLoader(); ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) { if (cl == null) {
cl = ClassLoader.getSystemClassLoader(); 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) { if (is != null) {
Properties props = new Properties(); Properties props = new Properties();
try { try {
@ -71,14 +73,13 @@ public interface TerminalProvider
if (className == null) { if (className == null) {
throw new IOException("No class defined in terminal provider file " + name); 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(); return (TerminalProvider) clazz.getConstructor().newInstance();
} catch ( Exception e ) { } catch (Exception e) {
throw new IOException("Unable to load terminal provider " + name, e); throw new IOException("Unable to load terminal provider " + name + ": " + e.getMessage(), e);
} }
} else { } else {
throw new IOException("Unable to find terminal provider " + name); 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"); * This software is distributable under the BSD license. See the terms of the
* you may not use this file except in compliance with the License. * BSD license in the documentation provided with this software.
* You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
package jdk.internal.org.jline.utils; package jdk.internal.org.jline.utils;
@ -252,12 +245,10 @@ public class AnsiWriter extends FilterWriter {
* @throws IOException if no more non-null values left * @throws IOException if no more non-null values left
*/ */
private int getNextOptionInt(Iterator<Object> optionsIterator) throws IOException { private int getNextOptionInt(Iterator<Object> optionsIterator) throws IOException {
for (;;) { for (; ; ) {
if (!optionsIterator.hasNext()) if (!optionsIterator.hasNext()) throw new IllegalArgumentException();
throw new IllegalArgumentException();
Object arg = optionsIterator.next(); Object arg = optionsIterator.next();
if (arg != null) if (arg != null) return (Integer) arg;
return (Integer) arg;
} }
} }
@ -346,27 +337,21 @@ public class AnsiWriter extends FilterWriter {
int g = getNextOptionInt(optionsIterator); int g = getNextOptionInt(optionsIterator);
int b = getNextOptionInt(optionsIterator); int b = getNextOptionInt(optionsIterator);
if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) { if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
if (value == 38) if (value == 38) processSetForegroundColorExt(r, g, b);
processSetForegroundColorExt(r, g, b); else processSetBackgroundColorExt(r, g, b);
else
processSetBackgroundColorExt(r, g, b);
} else { } else {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} } else if (arg2or5 == 5) {
else if (arg2or5 == 5) {
// 256 color style like `esc[38;5;<index>m` // 256 color style like `esc[38;5;<index>m`
int paletteIndex = getNextOptionInt(optionsIterator); int paletteIndex = getNextOptionInt(optionsIterator);
if (paletteIndex >= 0 && paletteIndex <= 255) { if (paletteIndex >= 0 && paletteIndex <= 255) {
if (value == 38) if (value == 38) processSetForegroundColorExt(paletteIndex);
processSetForegroundColorExt(paletteIndex); else processSetBackgroundColorExt(paletteIndex);
else
processSetBackgroundColorExt(paletteIndex);
} else { } else {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} } else {
else {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} else { } 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> * Process <code>CSI u</code> ANSI code, corresponding to <code>RCP \u2013 Restore Cursor Position</code>
* @throws IOException if an error occurs * @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> * Process <code>CSI s</code> ANSI code, corresponding to <code>SCP \u2013 Save Cursor Position</code>
* @throws IOException if an error occurs * @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> * Process <code>CSI s</code> ANSI code, corresponding to <code>IL \u2013 Insert Line</code>
* @param optionInt the option * @param optionInt the option
* @throws IOException if an error occurs * @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> * Process <code>CSI s</code> ANSI code, corresponding to <code>DL \u2013 Delete Line</code>
* @param optionInt the option * @param optionInt the option
* @throws IOException if an error occurs * @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> * Process <code>CSI n T</code> ANSI code, corresponding to <code>SD \u2013 Scroll Down</code>
* @param optionInt the option * @param optionInt the option
* @throws IOException if an error occurs * @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> * Process <code>CSI n U</code> ANSI code, corresponding to <code>SU \u2013 Scroll Up</code>
* @param optionInt the option * @param optionInt the option
* @throws IOException if an error occurs * @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_END = 0;
protected static final int ERASE_SCREEN_TO_BEGINING = 1; protected static final int ERASE_SCREEN_TO_BEGINING = 1;
@ -500,8 +479,7 @@ public class AnsiWriter extends FilterWriter {
* @param eraseOption the erase option * @param eraseOption the erase option
* @throws IOException if an error occurs * @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_END = 0;
protected static final int ERASE_LINE_TO_BEGINING = 1; protected static final int ERASE_LINE_TO_BEGINING = 1;
@ -512,8 +490,7 @@ public class AnsiWriter extends FilterWriter {
* @param eraseOption the erase option * @param eraseOption the erase option
* @throws IOException if an error occurs * @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_BOLD = 1; // Intensity: Bold
protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; // Intensity; Faint not widely supported protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; // Intensity; Faint not widely supported
@ -521,14 +498,17 @@ public class AnsiWriter extends FilterWriter {
protected static final int ATTRIBUTE_UNDERLINE = 4; // Underline; Single 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_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_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_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_CONCEAL_ON = 8; // Conceal on
protected static final int ATTRIBUTE_UNDERLINE_DOUBLE = 21; // Underline; Double not widely supported 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_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_UNDERLINE_OFF = 24; // Underline; None
protected static final int ATTRIBUTE_BLINK_OFF = 25; // Blink; off protected static final int ATTRIBUTE_BLINK_OFF = 25; // Blink; off
@Deprecated @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_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
@ -546,8 +526,7 @@ public class AnsiWriter extends FilterWriter {
* @see #processDefaultTextColor() * @see #processDefaultTextColor()
* @see #processDefaultBackgroundColor() * @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 BLACK = 0;
protected static final int RED = 1; protected static final int RED = 1;
@ -584,8 +563,7 @@ public class AnsiWriter extends FilterWriter {
* @param paletteIndex the text color in the palette * @param paletteIndex the text color in the palette
* @throws IOException if an error occurs * @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> * 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 * @param paletteIndex the background color in the palette
* @throws IOException if an error occurs * @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> * 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> * process <code>SGR 39</code> corresponding to <code>Default text color (foreground)</code>
* @throws IOException if an error occurs * @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> * process <code>SGR 49</code> corresponding to <code>Default background color</code>
* @throws IOException if an error occurs * @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> * process <code>SGR 0</code> corresponding to <code>Reset / Normal</code>
* @throws IOException if an error occurs * @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 * 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 * @param col the column
* @throws IOException if an error occurs * @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> * process <code>CSI n G</code> corresponding to <code>CHA \u2013 Cursor Horizontal Absolute</code>
* @param x the column * @param x the column
* @throws IOException if an error occurs * @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> * process <code>CSI n F</code> corresponding to <code>CPL \u2013 Cursor Previous Line</code>
* @param count line count * @param count line count
* @throws IOException if an error occurs * @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> * 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 * @param count the count
* @throws IOException if an error occurs * @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> * 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 * @param count the count
* @throws IOException if an error occurs * @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> * process <code>CSI n A</code> corresponding to <code>CUU \u2013 Cursor Up</code>
* @param count the count * @param count the count
* @throws IOException if an error occurs * @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> * 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> * process <code>OSC 1;text BEL</code> corresponding to <code>Change Icon label</code>
* @param name the icon name * @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> * process <code>OSC 2;text BEL</code> corresponding to <code>Change Window title</code>
* @param title the title * @param title the title
*/ */
protected void processChangeWindowTitle(String title) { protected void processChangeWindowTitle(String title) {}
}
/** /**
* Process unknown <code>OSC</code> command. * Process unknown <code>OSC</code> command.
* @param command the command * @param command the command
* @param param the param * @param param the param
*/ */
protected void processUnknownOperatingSystemCommand(int command, String param) { protected void processUnknownOperatingSystemCommand(int command, String param) {}
}
/** /**
* Process character set sequence. * Process character set sequence.
@ -781,17 +745,13 @@ public class AnsiWriter extends FilterWriter {
return true; return true;
} }
protected void processCharsetSelect(int set, char seq) { protected void processCharsetSelect(int set, char seq) {}
}
private int optionInt(ArrayList<Object> options, int index) { private int optionInt(ArrayList<Object> options, int index) {
if (options.size() <= index) if (options.size() <= index) throw new IllegalArgumentException();
throw new IllegalArgumentException();
Object value = options.get(index); Object value = options.get(index);
if (value == null) if (value == null) throw new IllegalArgumentException();
throw new IllegalArgumentException(); if (!value.getClass().equals(Integer.class)) throw new IllegalArgumentException();
if (!value.getClass().equals(Integer.class))
throw new IllegalArgumentException();
return (Integer) value; return (Integer) value;
} }
@ -828,5 +788,4 @@ public class AnsiWriter extends FilterWriter {
flush(); flush();
super.close(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.terminal.impl.AbstractWindowsTerminal;
import jdk.internal.org.jline.utils.InfoCmp.Capability; 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;
import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR_EXP; import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR_EXP;
import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR; 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;
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_IND; 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_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_INVERSE;
import static jdk.internal.org.jline.utils.AttributedStyle.F_ITALIC; 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_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.utils.AttributedStyle.MASK;
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTERNATE_CHARSET;
public abstract class AttributedCharSequence implements CharSequence { public abstract class AttributedCharSequence implements CharSequence {
@ -120,6 +120,7 @@ public abstract class AttributedCharSequence implements CharSequence {
char c = charAt(i); char c = charAt(i);
if (altIn != null && altOut != null) { if (altIn != null && altOut != null) {
char pc = c; char pc = c;
// @spotless:off
switch (c) { switch (c) {
case '\u2518': c = 'j'; break; case '\u2518': c = 'j'; break;
case '\u2510': c = 'k'; break; case '\u2510': c = 'k'; break;
@ -133,6 +134,7 @@ public abstract class AttributedCharSequence implements CharSequence {
case '\u252C': c = 'w'; break; case '\u252C': c = 'w'; break;
case '\u2502': c = 'x'; break; case '\u2502': c = 'x'; break;
} }
// @spotless:on
boolean oldalt = alt; boolean oldalt = alt;
alt = c != pc; alt = c != pc;
if (oldalt ^ alt) { if (oldalt ^ alt) {
@ -172,16 +174,16 @@ public abstract class AttributedCharSequence implements CharSequence {
if (fg > 0) { if (fg > 0) {
int rounded = -1; int rounded = -1;
if ((fg & F_FOREGROUND_RGB) != 0) { if ((fg & F_FOREGROUND_RGB) != 0) {
int r = (int)(fg >> (FG_COLOR_EXP + 16)) & 0xFF; int r = (int) (fg >> (FG_COLOR_EXP + 16)) & 0xFF;
int g = (int)(fg >> (FG_COLOR_EXP + 8)) & 0xFF; int g = (int) (fg >> (FG_COLOR_EXP + 8)) & 0xFF;
int b = (int)(fg >> FG_COLOR_EXP) & 0xFF; int b = (int) (fg >> FG_COLOR_EXP) & 0xFF;
if (colors >= HIGH_COLORS) { if (colors >= HIGH_COLORS) {
first = attr(sb, "38;2;" + r + ";" + g + ";" + b, first); first = attr(sb, "38;2;" + r + ";" + g + ";" + b, first);
} else { } else {
rounded = palette.round(r, g, b); rounded = palette.round(r, g, b);
} }
} else if ((fg & F_FOREGROUND_IND) != 0) { } 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 (rounded >= 0) {
if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) { if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) {
@ -211,16 +213,16 @@ public abstract class AttributedCharSequence implements CharSequence {
if (bg > 0) { if (bg > 0) {
int rounded = -1; int rounded = -1;
if ((bg & F_BACKGROUND_RGB) != 0) { if ((bg & F_BACKGROUND_RGB) != 0) {
int r = (int)(bg >> (BG_COLOR_EXP + 16)) & 0xFF; int r = (int) (bg >> (BG_COLOR_EXP + 16)) & 0xFF;
int g = (int)(bg >> (BG_COLOR_EXP + 8)) & 0xFF; int g = (int) (bg >> (BG_COLOR_EXP + 8)) & 0xFF;
int b = (int)(bg >> BG_COLOR_EXP) & 0xFF; int b = (int) (bg >> BG_COLOR_EXP) & 0xFF;
if (colors >= HIGH_COLORS) { if (colors >= HIGH_COLORS) {
first = attr(sb, "48;2;" + r + ";" + g + ";" + b, first); first = attr(sb, "48;2;" + r + ";" + g + ";" + b, first);
} else { } else {
rounded = palette.round(r, g, b); rounded = palette.round(r, g, b);
} }
} else if ((bg & F_BACKGROUND_IND) != 0) { } 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 (rounded >= 0) {
if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) { if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) {
@ -243,8 +245,7 @@ public abstract class AttributedCharSequence implements CharSequence {
background = bg; background = bg;
} }
if ((d & (F_BOLD | F_FAINT)) != 0) { if ((d & (F_BOLD | F_FAINT)) != 0) {
if ( (d & F_BOLD) != 0 && (s & F_BOLD) == 0 if ((d & F_BOLD) != 0 && (s & F_BOLD) == 0 || (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
|| (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
first = attr(sb, "22", first); first = attr(sb, "22", first);
} }
if ((d & F_BOLD) != 0 && (s & F_BOLD) != 0) { if ((d & F_BOLD) != 0 && (s & F_BOLD) != 0) {
@ -360,8 +361,7 @@ public abstract class AttributedCharSequence implements CharSequence {
int len = length(); int len = length();
for (int cur = 0; cur < len; ) { for (int cur = 0; cur < len; ) {
int cp = codePointAt(cur); int cp = codePointAt(cur);
if (!isHidden(cur)) if (!isHidden(cur)) cols += WCWidth.wcwidth(cp);
cols += WCWidth.wcwidth(cp);
cur += Character.charCount(cp); cur += Character.charCount(cp);
} }
return cols; return cols;
@ -382,8 +382,7 @@ public abstract class AttributedCharSequence implements CharSequence {
int end = begin; int end = begin;
while (end < this.length()) { while (end < this.length()) {
int cp = codePointAt(end); int cp = codePointAt(end);
if (cp == '\n') if (cp == '\n') break;
break;
int w = isHidden(end) ? 0 : WCWidth.wcwidth(cp); int w = isHidden(end) ? 0 : WCWidth.wcwidth(cp);
if (col + w > stop) { if (col + w > stop) {
break; break;
@ -407,7 +406,7 @@ public abstract class AttributedCharSequence implements CharSequence {
int cp = codePointAt(cur); int cp = codePointAt(cur);
int w = isHidden(cur) ? 0 : WCWidth.wcwidth(cp); int w = isHidden(cur) ? 0 : WCWidth.wcwidth(cp);
if (cp == '\n') { if (cp == '\n') {
strings.add(subSequence(beg, includeNewlines ? cur+1 : cur)); strings.add(subSequence(beg, includeNewlines ? cur + 1 : cur));
beg = cur + 1; beg = cur + 1;
col = 0; col = 0;
} else if ((col += w) > columns) { } else if ((col += w) > columns) {
@ -429,5 +428,4 @@ public abstract class AttributedCharSequence implements CharSequence {
public AttributedString toAttributedString() { public AttributedString toAttributedString() {
return substring(0, length()); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * 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.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jdk.internal.org.jline.terminal.Terminal;
/** /**
* Attributed string. * Attributed string.
* Instances of this class are immutables. * Instances of this class are immutables.
@ -103,11 +105,28 @@ public class AttributedString extends AttributedCharSequence {
} }
public static AttributedString fromAnsi(String ansi, List<Integer> tabs) { 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) { if (ansi == null) {
return null; return null;
} }
return new AttributedStringBuilder(ansi.length()) return new AttributedStringBuilder(ansi.length())
.tabs(tabs) .tabs(tabs)
.altCharset(altIn, altOut)
.ansiAppend(ansi) .ansiAppend(ansi)
.toAttributedString(); .toAttributedString();
} }
@ -116,9 +135,7 @@ public class AttributedString extends AttributedCharSequence {
if (ansi == null) { if (ansi == null) {
return null; return null;
} }
return new AttributedStringBuilder(ansi.length()) return new AttributedStringBuilder(ansi.length()).ansiAppend(ansi).toString();
.ansiAppend(ansi)
.toString();
} }
@Override @Override
@ -162,7 +179,7 @@ public class AttributedString extends AttributedCharSequence {
} }
result = matcher.find(); result = matcher.find();
} while (result); } while (result);
return new AttributedString(buffer, newstyle, start , end); return new AttributedString(buffer, newstyle, start, end);
} }
return this; return this;
} }
@ -179,15 +196,16 @@ public class AttributedString extends AttributedCharSequence {
private boolean arrEq(char[] a1, char[] a2, int s1, int s2, int l) { private boolean arrEq(char[] a1, char[] a2, int s1, int s2, int l) {
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
if (a1[s1+i] != a2[s2+i]) { if (a1[s1 + i] != a2[s2 + i]) {
return false; return false;
} }
} }
return true; return true;
} }
private boolean arrEq(long[] a1, long[] a2, int s1, int s2, int l) { private boolean arrEq(long[] a1, long[] a2, int s1, int s2, int l) {
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
if (a1[s1+i] != a2[s2+i]) { if (a1[s1 + i] != a2[s2 + i]) {
return false; return false;
} }
} }
@ -221,5 +239,4 @@ public class AttributedString extends AttributedCharSequence {
} }
return sb.toAttributedString(); 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -27,6 +27,9 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
private long[] style; private long[] style;
private int length; private int length;
private TabStops tabs = new TabStops(0); private TabStops tabs = new TabStops(0);
private char[] altIn;
private char[] altOut;
private boolean inAltCharset;
private int lastLineLength = 0; private int lastLineLength = 0;
private AttributedStyle current = AttributedStyle.DEFAULT; private AttributedStyle current = AttributedStyle.DEFAULT;
@ -81,10 +84,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
@Override @Override
public AttributedString subSequence(int start, int end) { public AttributedString subSequence(int start, int end) {
return new AttributedString( return new AttributedString(
Arrays.copyOfRange(buffer, start, end), Arrays.copyOfRange(buffer, start, end), Arrays.copyOfRange(style, start, end), 0, end - start);
Arrays.copyOfRange(style, start, end),
0,
end - start);
} }
@Override @Override
@ -108,6 +108,14 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return append(Character.toString(c)); 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) { public AttributedStringBuilder append(CharSequence csq, AttributedStyle style) {
return append(new AttributedString(csq, style)); return append(new AttributedString(csq, style));
} }
@ -117,12 +125,12 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return this; return this;
} }
public AttributedStringBuilder style(Function<AttributedStyle,AttributedStyle> style) { public AttributedStringBuilder style(Function<AttributedStyle, AttributedStyle> style) {
current = style.apply(current); current = style.apply(current);
return this; 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)); 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)); 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; AttributedStyle prev = current;
current = style.apply(prev); current = style.apply(prev);
consumer.accept(this); consumer.accept(this);
@ -338,10 +347,57 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
// This is not a SGR code, so ignore // This is not a SGR code, so ignore
ansiState = 0; ansiState = 0;
} }
} else if (c == '\t' && tabs.defined()) { } else {
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); insertTab(current);
} else { } else {
ensureCapacity(length + 1); 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; buffer[length] = c;
style[length] = this.current.getStyle(); style[length] = this.current.getStyle();
if (c == '\n') { if (c == '\n') {
@ -350,11 +406,31 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
lastLineLength++; lastLineLength++;
} }
length++; 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;
}
}
}
} }
} }
return this; 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) { protected void insertTab(AttributedStyle s) {
int nb = tabs.spaces(lastLineLength); int nb = tabs.spaces(lastLineLength);
ensureCapacity(length + nb); ensureCapacity(length + nb);
@ -393,6 +469,15 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return this; 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) { public AttributedStringBuilder styleMatches(Pattern pattern, AttributedStyle s) {
Matcher matcher = pattern.matcher(this); Matcher matcher = pattern.matcher(this);
while (matcher.find()) { while (matcher.find()) {
@ -416,7 +501,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
return this; return this;
} }
private class TabStops { private static class TabStops {
private List<Integer> tabs = new ArrayList<>(); private List<Integer> tabs = new ArrayList<>();
private int lastStop = 0; private int lastStop = 0;
private int lastSize = 0; private int lastSize = 0;
@ -428,7 +513,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
public TabStops(List<Integer> tabs) { public TabStops(List<Integer> tabs) {
this.tabs = tabs; this.tabs = tabs;
int p = 0; int p = 0;
for (int s: tabs) { for (int s : tabs) {
if (s <= p) { if (s <= p) {
continue; continue;
} }
@ -447,7 +532,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
if (lastLineLength >= lastStop) { if (lastLineLength >= lastStop) {
out = lastSize - (lastLineLength - lastStop) % lastSize; out = lastSize - (lastLineLength - lastStop) % lastSize;
} else { } else {
for (int s: tabs) { for (int s : tabs) {
if (s > lastLineLength) { if (s > lastLineLength) {
out = s - lastLineLength; out = s - lastLineLength;
break; break;
@ -456,7 +541,5 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
} }
return out; 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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -70,7 +70,8 @@ public class AttributedStyle {
public AttributedStyle(long style, long mask) { public AttributedStyle(long style, long mask) {
this.style = style; this.style = style;
this.mask = mask & MASK | ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0) this.mask = mask & MASK
| ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0)
| ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0); | ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0);
} }
@ -176,7 +177,9 @@ public class AttributedStyle {
} }
public AttributedStyle foreground(int color) { 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) { public AttributedStyle foreground(int r, int g, int b) {
@ -184,7 +187,9 @@ public class AttributedStyle {
} }
public AttributedStyle foregroundRgb(int color) { 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() { public AttributedStyle foregroundOff() {
@ -196,7 +201,9 @@ public class AttributedStyle {
} }
public AttributedStyle background(int color) { 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) { public AttributedStyle background(int r, int g, int b) {
@ -204,7 +211,9 @@ public class AttributedStyle {
} }
public AttributedStyle backgroundRgb(int color) { 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() { public AttributedStyle backgroundOff() {
@ -249,7 +258,6 @@ public class AttributedStyle {
AttributedStyle that = (AttributedStyle) o; AttributedStyle that = (AttributedStyle) o;
if (style != that.style) return false; if (style != that.style) return false;
return mask == that.mask; return mask == that.mask;
} }
@Override @Override
@ -266,10 +274,6 @@ public class AttributedStyle {
@Override @Override
public String toString() { public String toString() {
return "AttributedStyle{" + return "AttributedStyle{" + "style=" + style + ", mask=" + mask + ", ansi=" + toAnsi() + '}';
"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 * This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software. * BSD license in the documentation provided with this software.
@ -14,8 +14,7 @@ public class ClosedException extends IOException {
private static final long serialVersionUID = 3085420657077696L; private static final long serialVersionUID = 3085420657077696L;
public ClosedException() { public ClosedException() {}
}
public ClosedException(String message) { public ClosedException(String message) {
super(message); super(message);

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