8327476: Upgrade JLine to 3.26.1
Reviewed-by: ihse, vromero
This commit is contained in:
parent
0a4eeeaa3c
commit
aaa90b3005
@ -120,6 +120,7 @@ NATIVE_ACCESS_MODULES= \
|
||||
jdk.dynalink \
|
||||
jdk.httpserver \
|
||||
jdk.incubator.vector \
|
||||
jdk.internal.le \
|
||||
jdk.internal.vm.ci \
|
||||
jdk.jfr \
|
||||
jdk.jsobject \
|
||||
|
@ -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
|
@ -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.");
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -66,7 +66,7 @@ public class BindingReader {
|
||||
T o = null;
|
||||
int[] remaining = new int[1];
|
||||
boolean hasRead = false;
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
if (local != null) {
|
||||
o = local.getBound(opBuffer, remaining);
|
||||
}
|
||||
@ -78,8 +78,7 @@ public class BindingReader {
|
||||
if (remaining[0] >= 0) {
|
||||
runMacro(opBuffer.substring(opBuffer.length() - remaining[0]));
|
||||
opBuffer.setLength(opBuffer.length() - remaining[0]);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
long ambiguousTimeout = keys.getAmbiguousTimeout();
|
||||
if (ambiguousTimeout > 0 && peekCharacter(ambiguousTimeout) != NonBlockingReader.READ_EXPIRED) {
|
||||
o = null;
|
||||
@ -234,5 +233,4 @@ public class BindingReader {
|
||||
public String getLastBinding() {
|
||||
return lastBinding;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,8 +8,6 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.keymap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@ -218,7 +216,6 @@ public class KeyMap<T> {
|
||||
return seqs;
|
||||
}
|
||||
|
||||
|
||||
public static String esc() {
|
||||
return "\033";
|
||||
}
|
||||
@ -264,7 +261,6 @@ public class KeyMap<T> {
|
||||
// Methods
|
||||
//
|
||||
|
||||
|
||||
public T getUnicode() {
|
||||
return unicode;
|
||||
}
|
||||
@ -306,9 +302,7 @@ public class KeyMap<T> {
|
||||
}
|
||||
for (int c = 0; c < keyMap.mapping.length; c++) {
|
||||
if (keyMap.mapping[c] instanceof KeyMap) {
|
||||
doGetBoundKeys((KeyMap<T>) keyMap.mapping[c],
|
||||
prefix + (char) (c),
|
||||
bound);
|
||||
doGetBoundKeys((KeyMap<T>) keyMap.mapping[c], prefix + (char) (c), bound);
|
||||
} else if (keyMap.mapping[c] != null) {
|
||||
bound.put(prefix + (char) (c), (T) keyMap.mapping[c]);
|
||||
}
|
||||
@ -456,5 +450,4 @@ public class KeyMap<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -14,9 +14,8 @@ package jdk.internal.org.jline.reader;
|
||||
* @see Macro
|
||||
* @see Reference
|
||||
* @see Widget
|
||||
* @see jdk.internal.org.jline.keymap.KeyMap
|
||||
* @see org.jline.keymap.KeyMap
|
||||
*
|
||||
* @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
|
||||
*/
|
||||
public interface Binding {
|
||||
}
|
||||
public interface Binding {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2017, the original author or authors.
|
||||
* Copyright (c) 2002-2017, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -84,8 +84,8 @@ public interface Buffer {
|
||||
|
||||
void copyFrom(Buffer buffer);
|
||||
|
||||
// JDK specific modification
|
||||
default void zeroOut() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
/**
|
||||
* Clear any internal buffer.
|
||||
*/
|
||||
void zeroOut();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2019, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -47,7 +47,15 @@ public class Candidate implements Comparable<Candidate> {
|
||||
* @param complete the complete flag
|
||||
* @param sort the sort flag
|
||||
*/
|
||||
public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete, int sort) {
|
||||
public Candidate(
|
||||
String value,
|
||||
String displ,
|
||||
String group,
|
||||
String descr,
|
||||
String suffix,
|
||||
String key,
|
||||
boolean complete,
|
||||
int sort) {
|
||||
this.value = Objects.requireNonNull(value);
|
||||
this.displ = Objects.requireNonNull(displ);
|
||||
this.group = group;
|
||||
@ -69,7 +77,8 @@ public class Candidate implements Comparable<Candidate> {
|
||||
* @param key the key
|
||||
* @param complete the complete flag
|
||||
*/
|
||||
public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete) {
|
||||
public Candidate(
|
||||
String value, String displ, String group, String descr, String suffix, String key, boolean complete) {
|
||||
this(value, displ, group, descr, suffix, key, complete, 0);
|
||||
}
|
||||
|
||||
@ -159,11 +168,10 @@ public class Candidate implements Comparable<Candidate> {
|
||||
return sort;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(Candidate o) {
|
||||
// If both candidates have same sort, use default behavior
|
||||
if( sort == o.sort() ) {
|
||||
if (sort == o.sort()) {
|
||||
return value.compareTo(o.value);
|
||||
} else {
|
||||
return Integer.compare(sort, o.sort());
|
||||
@ -180,7 +188,7 @@ public class Candidate implements Comparable<Candidate> {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
return Objects.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -18,8 +18,7 @@ import java.util.List;
|
||||
* @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public interface Completer
|
||||
{
|
||||
public interface Completer {
|
||||
/**
|
||||
* Populates <i>candidates</i> with a list of possible completions for the <i>command line</i>.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -10,7 +10,7 @@ package jdk.internal.org.jline.reader;
|
||||
|
||||
/**
|
||||
* An extension of {@link ParsedLine} that, being aware of the quoting and escaping rules
|
||||
* of the {@link jdk.internal.org.jline.reader.Parser} that produced it, knows if and how a completion candidate
|
||||
* of the {@link org.jline.reader.Parser} that produced it, knows if and how a completion candidate
|
||||
* should be escaped/quoted.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
@ -22,5 +22,4 @@ public interface CompletingParsedLine extends ParsedLine {
|
||||
int rawWordCursor();
|
||||
|
||||
int rawWordLength();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -23,8 +23,13 @@ public interface CompletionMatcher {
|
||||
* @param errors number of errors accepted in matching
|
||||
* @param originalGroupName value of JLineReader variable original-group-name
|
||||
*/
|
||||
void compile(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line
|
||||
, boolean caseInsensitive, int errors, String originalGroupName);
|
||||
void compile(
|
||||
Map<LineReader.Option, Boolean> options,
|
||||
boolean prefix,
|
||||
CompletingParsedLine line,
|
||||
boolean caseInsensitive,
|
||||
int errors,
|
||||
String originalGroupName);
|
||||
|
||||
/**
|
||||
*
|
||||
@ -44,5 +49,4 @@ public interface CompletionMatcher {
|
||||
* @return a common prefix of matched candidates
|
||||
*/
|
||||
String getCommonPrefix();
|
||||
|
||||
}
|
||||
|
@ -1,20 +1,10 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
* Copyright (c) 2023, the original author(s).
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
package jdk.internal.org.jline.reader;
|
||||
|
||||
@ -45,7 +35,7 @@ public class EOFError extends SyntaxError {
|
||||
return missing;
|
||||
}
|
||||
|
||||
public int getOpenBrackets(){
|
||||
public int getOpenBrackets() {
|
||||
return openBrackets;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2019, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -13,6 +13,8 @@ import java.util.List;
|
||||
|
||||
public interface Editor {
|
||||
public void open(List<String> files) throws IOException;
|
||||
|
||||
public void run() throws IOException;
|
||||
|
||||
public void setRestricted(boolean restricted);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -17,8 +17,7 @@ public class EndOfFileException extends RuntimeException {
|
||||
private static final long serialVersionUID = 528485360925144689L;
|
||||
private String partialLine;
|
||||
|
||||
public EndOfFileException() {
|
||||
}
|
||||
public EndOfFileException() {}
|
||||
|
||||
public EndOfFileException(String message) {
|
||||
super(message);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -13,5 +13,4 @@ public interface Expander {
|
||||
String expandHistory(History history, String line);
|
||||
|
||||
String expandVar(String word);
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -21,8 +21,7 @@ import java.util.ListIterator;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public interface History extends Iterable<History.Entry>
|
||||
{
|
||||
public interface History extends Iterable<History.Entry> {
|
||||
|
||||
/**
|
||||
* Initialize the history for the given reader.
|
||||
@ -75,7 +74,6 @@ public interface History extends Iterable<History.Entry>
|
||||
*/
|
||||
void purge() throws IOException;
|
||||
|
||||
|
||||
int size();
|
||||
|
||||
default boolean isEmpty() {
|
||||
@ -110,8 +108,7 @@ public interface History extends Iterable<History.Entry>
|
||||
// Entries
|
||||
//
|
||||
|
||||
interface Entry
|
||||
{
|
||||
interface Entry {
|
||||
int index();
|
||||
|
||||
Instant time();
|
||||
@ -132,14 +129,17 @@ public interface History extends Iterable<History.Entry>
|
||||
default Iterator<Entry> reverseIterator(int index) {
|
||||
return new Iterator<Entry>() {
|
||||
private final ListIterator<Entry> it = iterator(index + 1);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return it.hasPrevious();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry next() {
|
||||
return it.previous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
it.remove();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2023, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -21,7 +21,7 @@ import jdk.internal.org.jline.utils.AttributedString;
|
||||
|
||||
/** Read lines from the console, with input editing.
|
||||
*
|
||||
* <h3>Thread safety</h3>
|
||||
* <h2>Thread safety</h2>
|
||||
* The <code>LineReader</code> implementations are not thread safe,
|
||||
* thus you should not attempt to use a single reader in several threads.
|
||||
* Any attempt to call one of the <code>readLine</code> call while one is
|
||||
@ -31,7 +31,7 @@ import jdk.internal.org.jline.utils.AttributedString;
|
||||
* {@link #printAbove(String)} or {@link #printAbove(AttributedString)} at
|
||||
* any time to allow text to be printed above the current prompt.
|
||||
*
|
||||
* <h3>Prompt strings</h3>
|
||||
* <h2>Prompt strings</h2>
|
||||
* It is traditional for an interactive console-based program
|
||||
* to print a short prompt string to signal that the user is expected
|
||||
* to type a command. JLine supports 3 kinds of prompt string:
|
||||
@ -81,7 +81,6 @@ import jdk.internal.org.jline.utils.AttributedString;
|
||||
* </dd>
|
||||
* </dl>
|
||||
*/
|
||||
|
||||
public interface LineReader {
|
||||
|
||||
/**
|
||||
@ -284,6 +283,7 @@ public interface LineReader {
|
||||
String MAIN = "main";
|
||||
String EMACS = "emacs";
|
||||
String SAFE = ".safe";
|
||||
String DUMB = "dumb";
|
||||
String MENU = "menu";
|
||||
|
||||
//
|
||||
@ -301,6 +301,7 @@ public interface LineReader {
|
||||
* they are displayed in a list below the field to be completed
|
||||
*/
|
||||
String MENU_LIST_MAX = "menu-list-max";
|
||||
|
||||
String DISABLE_HISTORY = "disable-history";
|
||||
String DISABLE_COMPLETION = "disable-completion";
|
||||
String EDITING_MODE = "editing-mode";
|
||||
@ -317,18 +318,23 @@ public interface LineReader {
|
||||
String ORIGINAL_GROUP_NAME = "ORIGINAL_GROUP_NAME";
|
||||
/** Completion style for displaying groups name */
|
||||
String COMPLETION_STYLE_GROUP = "COMPLETION_STYLE_GROUP";
|
||||
|
||||
String COMPLETION_STYLE_LIST_GROUP = "COMPLETION_STYLE_LIST_GROUP";
|
||||
/** Completion style for displaying the current selected item */
|
||||
String COMPLETION_STYLE_SELECTION = "COMPLETION_STYLE_SELECTION";
|
||||
|
||||
String COMPLETION_STYLE_LIST_SELECTION = "COMPLETION_STYLE_LIST_SELECTION";
|
||||
/** Completion style for displaying the candidate description */
|
||||
String COMPLETION_STYLE_DESCRIPTION = "COMPLETION_STYLE_DESCRIPTION";
|
||||
|
||||
String COMPLETION_STYLE_LIST_DESCRIPTION = "COMPLETION_STYLE_LIST_DESCRIPTION";
|
||||
/** Completion style for displaying the matching part of candidates */
|
||||
String COMPLETION_STYLE_STARTING = "COMPLETION_STYLE_STARTING";
|
||||
|
||||
String COMPLETION_STYLE_LIST_STARTING = "COMPLETION_STYLE_LIST_STARTING";
|
||||
/** Completion style for displaying the list */
|
||||
String COMPLETION_STYLE_BACKGROUND = "COMPLETION_STYLE_BACKGROUND";
|
||||
|
||||
String COMPLETION_STYLE_LIST_BACKGROUND = "COMPLETION_STYLE_LIST_BACKGROUND";
|
||||
/**
|
||||
* Set the template for prompts for secondary (continuation) lines.
|
||||
@ -390,6 +396,26 @@ public interface LineReader {
|
||||
*/
|
||||
String SUGGESTIONS_MIN_BUFFER_SIZE = "suggestions-min-buffer-size";
|
||||
|
||||
/**
|
||||
* Max number of times a command can be repeated.
|
||||
*/
|
||||
String MAX_REPEAT_COUNT = "max-repeat-count";
|
||||
|
||||
/**
|
||||
* Number of spaces to display a tabulation, the default is 4.
|
||||
*/
|
||||
String TAB_WIDTH = "tab-width";
|
||||
|
||||
/**
|
||||
* Name of inputrc to read at line reader creation time.
|
||||
*/
|
||||
String INPUT_RC_FILE_NAME = "input-rc-file-name";
|
||||
|
||||
/**
|
||||
* Prefix to automatically delegate variables to system properties
|
||||
*/
|
||||
String SYSTEM_PROPERTY_PREFIX = "system-property-prefix";
|
||||
|
||||
Map<String, KeyMap<Binding>> defaultKeyMaps();
|
||||
|
||||
enum Option {
|
||||
@ -469,8 +495,7 @@ public interface LineReader {
|
||||
EMPTY_WORD_OPTIONS(true),
|
||||
|
||||
/** Disable the undo feature */
|
||||
DISABLE_UNDO
|
||||
;
|
||||
DISABLE_UNDO;
|
||||
|
||||
private final boolean def;
|
||||
|
||||
@ -611,7 +636,8 @@ public interface LineReader {
|
||||
* @throws EndOfFileException if an EOF has been found (using Ctrl-D for example)
|
||||
* @throws java.io.IOError in case of other i/o errors
|
||||
*/
|
||||
String readLine(String prompt, String rightPrompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException;
|
||||
String readLine(String prompt, String rightPrompt, Character mask, String buffer)
|
||||
throws UserInterruptException, EndOfFileException;
|
||||
|
||||
/**
|
||||
* Read a line from the <i>in</i> {@link InputStream}, and return the line
|
||||
@ -631,7 +657,8 @@ public interface LineReader {
|
||||
* @throws EndOfFileException if an EOF has been found (using Ctrl-D for example)
|
||||
* @throws java.io.IOError in case of other i/o errors
|
||||
*/
|
||||
String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer) throws UserInterruptException, EndOfFileException;
|
||||
String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer)
|
||||
throws UserInterruptException, EndOfFileException;
|
||||
|
||||
/**
|
||||
* Prints a line above the prompt and redraw everything.
|
||||
@ -702,7 +729,7 @@ public interface LineReader {
|
||||
void runMacro(String macro);
|
||||
|
||||
/**
|
||||
* Read a mouse event when the {@link jdk.internal.org.jline.utils.InfoCmp.Capability#key_mouse} sequence
|
||||
* Read a mouse event when the {@link org.jline.utils.InfoCmp.Capability#key_mouse} sequence
|
||||
* has just been read on the input stream.
|
||||
* Compared to {@link Terminal#readMouseEvent()}, this method takes into account keys
|
||||
* that have been pushed back using {@link #runMacro(String)}.
|
||||
@ -751,8 +778,8 @@ public interface LineReader {
|
||||
|
||||
SuggestionType getAutosuggestion();
|
||||
|
||||
// JDK specific modification
|
||||
default void zeroOut() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
/**
|
||||
* Clear any internal buffers.
|
||||
*/
|
||||
void zeroOut();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -38,8 +38,7 @@ public final class LineReaderBuilder {
|
||||
Expander expander;
|
||||
CompletionMatcher completionMatcher;
|
||||
|
||||
private LineReaderBuilder() {
|
||||
}
|
||||
private LineReaderBuilder() {}
|
||||
|
||||
public LineReaderBuilder terminal(Terminal terminal) {
|
||||
this.terminal = terminal;
|
||||
@ -88,8 +87,9 @@ public final class LineReaderBuilder {
|
||||
try {
|
||||
if (!Boolean.getBoolean(LineReader.PROP_SUPPORT_PARSEDLINE)
|
||||
&& !(parser.parse("", 0) instanceof CompletingParsedLine)) {
|
||||
Log.warn("The Parser of class " + parser.getClass().getName() + " does not support the CompletingParsedLine interface. " +
|
||||
"Completion with escaped or quoted words won't work correctly.");
|
||||
Log.warn("The Parser of class " + parser.getClass().getName()
|
||||
+ " does not support the CompletingParsedLine interface. "
|
||||
+ "Completion with escaped or quoted words won't work correctly.");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Ignore
|
||||
@ -153,5 +153,4 @@ public final class LineReaderBuilder {
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -35,7 +35,6 @@ public class Macro implements Binding {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Macro[" +
|
||||
sequence + ']';
|
||||
return "Macro[" + sequence + ']';
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -31,5 +31,4 @@ public interface MaskingCallback {
|
||||
* @return the modified line
|
||||
*/
|
||||
String history(String line);
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -64,5 +64,4 @@ public interface ParsedLine {
|
||||
* @return the cursor position within the line
|
||||
*/
|
||||
int cursor();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -35,7 +35,7 @@ public interface Parser {
|
||||
|
||||
default String getCommand(final String line) {
|
||||
String out;
|
||||
Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+|$)");
|
||||
Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+|$)");
|
||||
Matcher matcher = patternCommand.matcher(line);
|
||||
if (matcher.find()) {
|
||||
out = matcher.group(1);
|
||||
@ -50,7 +50,7 @@ public interface Parser {
|
||||
|
||||
default String getVariable(final String line) {
|
||||
String out = null;
|
||||
Pattern patternCommand = Pattern.compile("^\\s*(" + REGEX_VARIABLE + ")\\s*=[^=~].*");
|
||||
Pattern patternCommand = Pattern.compile("^\\s*(" + REGEX_VARIABLE + ")\\s*=[^=~].*");
|
||||
Matcher matcher = patternCommand.matcher(line);
|
||||
if (matcher.find()) {
|
||||
out = matcher.group(1);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -38,7 +38,6 @@ public class Reference implements Binding {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Reference[" +
|
||||
name + ']';
|
||||
return "Reference[" + name + ']';
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,10 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
* Copyright (c) 2023, the original author(s).
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
package jdk.internal.org.jline.reader;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -14,23 +14,19 @@ package jdk.internal.org.jline.reader;
|
||||
* interrupt character (ctrl-C). The partially entered line is
|
||||
* available via the {@link #getPartialLine()} method.
|
||||
*/
|
||||
public class UserInterruptException
|
||||
extends RuntimeException
|
||||
{
|
||||
public class UserInterruptException extends RuntimeException {
|
||||
private static final long serialVersionUID = 6172232572140736750L;
|
||||
|
||||
private final String partialLine;
|
||||
|
||||
public UserInterruptException(String partialLine)
|
||||
{
|
||||
public UserInterruptException(String partialLine) {
|
||||
this.partialLine = partialLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the partially entered line when ctrl-C was pressed
|
||||
*/
|
||||
public String getPartialLine()
|
||||
{
|
||||
public String getPartialLine() {
|
||||
return partialLine;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -15,5 +15,4 @@ package jdk.internal.org.jline.reader;
|
||||
public interface Widget extends Binding {
|
||||
|
||||
boolean apply();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2017, the original author or authors.
|
||||
* Copyright (c) 2002-2017, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -20,8 +20,7 @@ import jdk.internal.org.jline.reader.Buffer;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.0
|
||||
*/
|
||||
public class BufferImpl implements Buffer
|
||||
{
|
||||
public class BufferImpl implements Buffer {
|
||||
private int cursor = 0;
|
||||
private int cursorCol = -1;
|
||||
private int[] buffer;
|
||||
@ -46,7 +45,7 @@ public class BufferImpl implements Buffer
|
||||
this.g1 = buffer.g1;
|
||||
}
|
||||
|
||||
public BufferImpl copy () {
|
||||
public BufferImpl copy() {
|
||||
return new BufferImpl(this);
|
||||
}
|
||||
|
||||
@ -107,7 +106,7 @@ public class BufferImpl implements Buffer
|
||||
* @param c the character to insert
|
||||
*/
|
||||
public void write(int c) {
|
||||
write(new int[] { c });
|
||||
write(new int[] {c});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,7 +120,7 @@ public class BufferImpl implements Buffer
|
||||
if (overTyping) {
|
||||
delete(1);
|
||||
}
|
||||
write(new int[] { c });
|
||||
write(new int[] {c});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -224,8 +223,7 @@ public class BufferImpl implements Buffer
|
||||
|
||||
if ((cursor + where) < 0) {
|
||||
where = -cursor;
|
||||
}
|
||||
else if ((cursor + where) > length()) {
|
||||
} else if ((cursor + where) > length()) {
|
||||
where = length() - cursor;
|
||||
}
|
||||
|
||||
@ -371,7 +369,6 @@ public class BufferImpl implements Buffer
|
||||
}
|
||||
}
|
||||
|
||||
// JDK specific modification
|
||||
@Override
|
||||
public void zeroOut() {
|
||||
Arrays.fill(buffer, 0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,26 +8,25 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.reader.impl;
|
||||
|
||||
import jdk.internal.org.jline.reader.Candidate;
|
||||
import jdk.internal.org.jline.reader.CompletingParsedLine;
|
||||
import jdk.internal.org.jline.reader.CompletionMatcher;
|
||||
import jdk.internal.org.jline.reader.LineReader;
|
||||
import jdk.internal.org.jline.utils.AttributedString;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.org.jline.reader.Candidate;
|
||||
import jdk.internal.org.jline.reader.CompletingParsedLine;
|
||||
import jdk.internal.org.jline.reader.CompletionMatcher;
|
||||
import jdk.internal.org.jline.reader.LineReader;
|
||||
import jdk.internal.org.jline.utils.AttributedString;
|
||||
|
||||
public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
protected Predicate<String> exact;
|
||||
protected List<Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>>> matchers;
|
||||
private Map<String, List<Candidate>> matching;
|
||||
private boolean caseInsensitive;
|
||||
|
||||
public CompletionMatcherImpl() {
|
||||
}
|
||||
public CompletionMatcherImpl() {}
|
||||
|
||||
protected void reset(boolean caseInsensitive) {
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
@ -37,8 +36,13 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line
|
||||
, boolean caseInsensitive, int errors, String originalGroupName) {
|
||||
public void compile(
|
||||
Map<LineReader.Option, Boolean> options,
|
||||
boolean prefix,
|
||||
CompletingParsedLine line,
|
||||
boolean caseInsensitive,
|
||||
int errors,
|
||||
String originalGroupName) {
|
||||
reset(caseInsensitive);
|
||||
defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName);
|
||||
}
|
||||
@ -47,15 +51,18 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
public List<Candidate> matches(List<Candidate> candidates) {
|
||||
matching = Collections.emptyMap();
|
||||
Map<String, List<Candidate>> sortedCandidates = sort(candidates);
|
||||
for (Function<Map<String, List<Candidate>>,
|
||||
Map<String, List<Candidate>>> matcher : matchers) {
|
||||
for (Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> matcher : matchers) {
|
||||
matching = matcher.apply(sortedCandidates);
|
||||
if (!matching.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !matching.isEmpty() ? matching.entrySet().stream().flatMap(e -> e.getValue().stream()).distinct().collect(Collectors.toList())
|
||||
: new ArrayList<>();
|
||||
return !matching.isEmpty()
|
||||
? matching.entrySet().stream()
|
||||
.flatMap(e -> e.getValue().stream())
|
||||
.distinct()
|
||||
.collect(Collectors.toList())
|
||||
: new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,10 +70,12 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
if (matching == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return matching.values().stream().flatMap(Collection::stream)
|
||||
return matching.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
.filter(Candidate::complete)
|
||||
.filter(c -> exact.test(c.value()))
|
||||
.findFirst().orElse(null);
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,8 +93,13 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
/**
|
||||
* Default JLine matchers
|
||||
*/
|
||||
protected void defaultMatchers(Map<LineReader.Option, Boolean> options, boolean prefix, CompletingParsedLine line
|
||||
, boolean caseInsensitive, int errors, String originalGroupName) {
|
||||
protected void defaultMatchers(
|
||||
Map<LineReader.Option, Boolean> options,
|
||||
boolean prefix,
|
||||
CompletingParsedLine line,
|
||||
boolean caseInsensitive,
|
||||
int errors,
|
||||
String originalGroupName) {
|
||||
// Find matchers
|
||||
// TODO: glob completion
|
||||
String wd = line.word();
|
||||
@ -94,8 +108,7 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
if (prefix) {
|
||||
matchers = new ArrayList<>(Arrays.asList(
|
||||
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wp)),
|
||||
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp))
|
||||
));
|
||||
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp))));
|
||||
if (LineReader.Option.COMPLETE_MATCHER_TYPO.isSet(options)) {
|
||||
matchers.add(typoMatcher(wp, errors, caseInsensitive, originalGroupName));
|
||||
}
|
||||
@ -109,14 +122,14 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
Pattern p1 = Pattern.compile(Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
|
||||
Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
|
||||
matchers = new ArrayList<>(Arrays.asList(
|
||||
simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s).matches()),
|
||||
simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s).matches())
|
||||
));
|
||||
simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s)
|
||||
.matches()),
|
||||
simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s)
|
||||
.matches())));
|
||||
} else {
|
||||
matchers = new ArrayList<>(Arrays.asList(
|
||||
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wdi)),
|
||||
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi))
|
||||
));
|
||||
simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi))));
|
||||
}
|
||||
if (LineReader.Option.COMPLETE_MATCHER_CAMELCASE.isSet(options)) {
|
||||
matchers.add(simpleMatcher(s -> camelMatch(wd, 0, s, 0)));
|
||||
@ -128,18 +141,20 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
protected Function<Map<String, List<Candidate>>,
|
||||
Map<String, List<Candidate>>> simpleMatcher(Predicate<String> predicate) {
|
||||
protected Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> simpleMatcher(
|
||||
Predicate<String> predicate) {
|
||||
return m -> m.entrySet().stream()
|
||||
.filter(e -> predicate.test(e.getKey()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
protected Function<Map<String, List<Candidate>>,
|
||||
Map<String, List<Candidate>>> typoMatcher(String word, int errors, boolean caseInsensitive, String originalGroupName) {
|
||||
protected Function<Map<String, List<Candidate>>, Map<String, List<Candidate>>> typoMatcher(
|
||||
String word, int errors, boolean caseInsensitive, String originalGroupName) {
|
||||
return m -> {
|
||||
Map<String, List<Candidate>> map = m.entrySet().stream()
|
||||
.filter(e -> ReaderUtils.distance(word, caseInsensitive ? e.getKey().toLowerCase() : e.getKey()) < errors)
|
||||
.filter(e -> ReaderUtils.distance(
|
||||
word, caseInsensitive ? e.getKey().toLowerCase() : e.getKey())
|
||||
< errors)
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
if (map.size() > 1) {
|
||||
map.computeIfAbsent(word, w -> new ArrayList<>())
|
||||
@ -178,7 +193,8 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
Map<String, List<Candidate>> sortedCandidates = new HashMap<>();
|
||||
for (Candidate candidate : candidates) {
|
||||
sortedCandidates
|
||||
.computeIfAbsent(AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>())
|
||||
.computeIfAbsent(
|
||||
AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>())
|
||||
.add(candidate);
|
||||
}
|
||||
return sortedCandidates;
|
||||
@ -206,5 +222,4 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
}
|
||||
return new String(s1, 0, len);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -32,27 +32,25 @@ public class DefaultExpander implements Expander {
|
||||
if (unicode > 0) {
|
||||
escaped = (--unicode >= 0);
|
||||
sb.append(c);
|
||||
}
|
||||
else if (escaped) {
|
||||
} else if (escaped) {
|
||||
if (c == 'u') {
|
||||
unicode = 4;
|
||||
} else {
|
||||
escaped = false;
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
else if (c == '\'') {
|
||||
} else if (c == '\'') {
|
||||
inQuote = !inQuote;
|
||||
sb.append(c);
|
||||
}
|
||||
else if (inQuote) {
|
||||
} else if (inQuote) {
|
||||
sb.append(c);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
// any '\!' should be considered an expansion escape, so skip expansion and strip the escape character
|
||||
// a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character
|
||||
// any '\!' should be considered an expansion escape, so skip expansion and strip the escape
|
||||
// character
|
||||
// a leading '\^' should be considered an expansion escape, so skip expansion and strip the
|
||||
// escape character
|
||||
// otherwise, add the escape
|
||||
escaped = true;
|
||||
sb.append(c);
|
||||
@ -91,7 +89,8 @@ public class DefaultExpander implements Expander {
|
||||
if (history.size() == 0) {
|
||||
throw new IllegalArgumentException("!$: event not found");
|
||||
}
|
||||
String previous = history.get(history.index() - 1).trim();
|
||||
String previous =
|
||||
history.get(history.index() - 1).trim();
|
||||
int lastSpace = previous.lastIndexOf(' ');
|
||||
if (lastSpace != -1) {
|
||||
rep = previous.substring(lastSpace + 1);
|
||||
@ -128,14 +127,18 @@ public class DefaultExpander implements Expander {
|
||||
try {
|
||||
idx = Integer.parseInt(line.substring(i1, i));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
|
||||
throw new IllegalArgumentException(
|
||||
(neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
|
||||
}
|
||||
if (neg && idx > 0 && idx <= history.size()) {
|
||||
rep = history.get(history.index() - idx);
|
||||
} else if (!neg && idx > history.index() - history.size() && idx <= history.index()) {
|
||||
} else if (!neg
|
||||
&& idx > history.index() - history.size()
|
||||
&& idx <= history.index()) {
|
||||
rep = history.get(idx - 1);
|
||||
} else {
|
||||
throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
|
||||
throw new IllegalArgumentException(
|
||||
(neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -10,9 +10,9 @@ package jdk.internal.org.jline.reader.impl;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.internal.org.jline.reader.Highlighter;
|
||||
import jdk.internal.org.jline.reader.LineReader;
|
||||
import jdk.internal.org.jline.reader.LineReader.RegionType;
|
||||
import jdk.internal.org.jline.reader.Highlighter;
|
||||
import jdk.internal.org.jline.utils.AttributedString;
|
||||
import jdk.internal.org.jline.utils.AttributedStringBuilder;
|
||||
import jdk.internal.org.jline.utils.AttributedStyle;
|
||||
@ -57,7 +57,8 @@ public class DefaultHighlighter implements Highlighter {
|
||||
while (negativeStart > 0 && reader.getBuffer().atChar(negativeStart - 1) != '\n') {
|
||||
negativeStart--;
|
||||
}
|
||||
while (negativeEnd < reader.getBuffer().length() - 1 && reader.getBuffer().atChar(negativeEnd + 1) != '\n') {
|
||||
while (negativeEnd < reader.getBuffer().length() - 1
|
||||
&& reader.getBuffer().atChar(negativeEnd + 1) != '\n') {
|
||||
negativeEnd++;
|
||||
}
|
||||
}
|
||||
@ -104,5 +105,4 @@ public class DefaultHighlighter implements Highlighter {
|
||||
}
|
||||
return sb.toAttributedString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -21,18 +21,18 @@ import jdk.internal.org.jline.reader.Parser;
|
||||
public class DefaultParser implements Parser {
|
||||
|
||||
public enum Bracket {
|
||||
ROUND, // ()
|
||||
CURLY, // {}
|
||||
SQUARE, // []
|
||||
ANGLE // <>
|
||||
ROUND, // ()
|
||||
CURLY, // {}
|
||||
SQUARE, // []
|
||||
ANGLE // <>
|
||||
}
|
||||
|
||||
public static class BlockCommentDelims {
|
||||
private final String start;
|
||||
private final String end;
|
||||
|
||||
public BlockCommentDelims(String start, String end) {
|
||||
if (start == null || end == null
|
||||
|| start.isEmpty() || end.isEmpty() || start.equals(end)) {
|
||||
if (start == null || end == null || start.isEmpty() || end.isEmpty() || start.equals(end)) {
|
||||
throw new IllegalArgumentException("Bad block comment delimiter!");
|
||||
}
|
||||
this.start = start;
|
||||
@ -185,22 +185,22 @@ public class DefaultParser implements Parser {
|
||||
int i = 0;
|
||||
for (Bracket b : bs) {
|
||||
switch (b) {
|
||||
case ROUND:
|
||||
openingBrackets[i] = '(';
|
||||
closingBrackets[i] = ')';
|
||||
break;
|
||||
case CURLY:
|
||||
openingBrackets[i] = '{';
|
||||
closingBrackets[i] = '}';
|
||||
break;
|
||||
case SQUARE:
|
||||
openingBrackets[i] = '[';
|
||||
closingBrackets[i] = ']';
|
||||
break;
|
||||
case ANGLE:
|
||||
openingBrackets[i] = '<';
|
||||
closingBrackets[i] = '>';
|
||||
break;
|
||||
case ROUND:
|
||||
openingBrackets[i] = '(';
|
||||
closingBrackets[i] = ')';
|
||||
break;
|
||||
case CURLY:
|
||||
openingBrackets[i] = '{';
|
||||
closingBrackets[i] = '}';
|
||||
break;
|
||||
case SQUARE:
|
||||
openingBrackets[i] = '[';
|
||||
closingBrackets[i] = ']';
|
||||
break;
|
||||
case ANGLE:
|
||||
openingBrackets[i] = '<';
|
||||
closingBrackets[i] = '>';
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -229,7 +229,6 @@ public class DefaultParser implements Parser {
|
||||
return name != null && regexVariable != null && name.matches(regexVariable);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCommand(final String line) {
|
||||
String out = "";
|
||||
@ -296,7 +295,7 @@ public class DefaultParser implements Parser {
|
||||
if (quoteStart < 0 && isQuoteChar(line, i) && !lineCommented && !blockCommented) {
|
||||
// Start a quote block
|
||||
quoteStart = i;
|
||||
if (current.length()==0) {
|
||||
if (current.length() == 0) {
|
||||
quotedWord = true;
|
||||
if (context == ParseContext.SPLIT_LINE) {
|
||||
current.append(line.charAt(i));
|
||||
@ -324,13 +323,15 @@ public class DefaultParser implements Parser {
|
||||
}
|
||||
} else {
|
||||
// Delimiter
|
||||
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i);
|
||||
rawWordLength = handleDelimiterAndGetRawWordLength(
|
||||
current, words, rawWordStart, rawWordCursor, rawWordLength, i);
|
||||
rawWordStart = i + 1;
|
||||
}
|
||||
} else {
|
||||
if (quoteStart < 0 && !blockCommented && (lineCommented || isLineCommentStarted(line, i))) {
|
||||
lineCommented = true;
|
||||
} else if (quoteStart < 0 && !lineCommented
|
||||
} else if (quoteStart < 0
|
||||
&& !lineCommented
|
||||
&& (blockCommented || isCommentDelim(line, i, blockCommentStart))) {
|
||||
if (blockCommented) {
|
||||
if (blockCommentEnd != null && isCommentDelim(line, i, blockCommentEnd)) {
|
||||
@ -339,12 +340,12 @@ public class DefaultParser implements Parser {
|
||||
}
|
||||
} else {
|
||||
blockCommented = true;
|
||||
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i);
|
||||
rawWordLength = handleDelimiterAndGetRawWordLength(
|
||||
current, words, rawWordStart, rawWordCursor, rawWordLength, i);
|
||||
i += blockCommentStart == null ? 0 : blockCommentStart.length() - 1;
|
||||
rawWordStart = i + 1;
|
||||
}
|
||||
} else if (quoteStart < 0 && !lineCommented
|
||||
&& isCommentDelim(line, i, blockCommentEnd)) {
|
||||
} else if (quoteStart < 0 && !lineCommented && isCommentDelim(line, i, blockCommentEnd)) {
|
||||
current.append(line.charAt(i));
|
||||
blockCommentInRightOrder = false;
|
||||
} else if (!isEscapeChar(line, i)) {
|
||||
@ -377,16 +378,14 @@ public class DefaultParser implements Parser {
|
||||
throw new EOFError(-1, -1, "Escaped new line", "newline");
|
||||
}
|
||||
if (eofOnUnclosedQuote && quoteStart >= 0) {
|
||||
throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\''
|
||||
? "quote" : "dquote");
|
||||
throw new EOFError(
|
||||
-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\'' ? "quote" : "dquote");
|
||||
}
|
||||
if (blockCommented) {
|
||||
throw new EOFError(-1, -1, "Missing closing block comment delimiter",
|
||||
"add: " + blockCommentEnd);
|
||||
throw new EOFError(-1, -1, "Missing closing block comment delimiter", "add: " + blockCommentEnd);
|
||||
}
|
||||
if (!blockCommentInRightOrder) {
|
||||
throw new EOFError(-1, -1, "Missing opening block comment delimiter",
|
||||
"missing: " + blockCommentStart);
|
||||
throw new EOFError(-1, -1, "Missing opening block comment delimiter", "missing: " + blockCommentStart);
|
||||
}
|
||||
if (bracketChecker.isClosingBracketMissing() || bracketChecker.isOpeningBracketMissing()) {
|
||||
String message = null;
|
||||
@ -398,8 +397,13 @@ public class DefaultParser implements Parser {
|
||||
message = "Missing opening bracket";
|
||||
missing = "missing: " + bracketChecker.getMissingOpeningBracket();
|
||||
}
|
||||
throw new EOFError(-1, -1, message, missing,
|
||||
bracketChecker.getOpenBrackets(), bracketChecker.getNextClosingBracket());
|
||||
throw new EOFError(
|
||||
-1,
|
||||
-1,
|
||||
message,
|
||||
missing,
|
||||
bracketChecker.getOpenBrackets(),
|
||||
bracketChecker.getNextClosingBracket());
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,7 +424,13 @@ public class DefaultParser implements Parser {
|
||||
return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
|
||||
}
|
||||
|
||||
private int handleDelimiterAndGetRawWordLength(StringBuilder current, List<String> words, int rawWordStart, int rawWordCursor, int rawWordLength, int pos) {
|
||||
private int handleDelimiterAndGetRawWordLength(
|
||||
StringBuilder current,
|
||||
List<String> words,
|
||||
int rawWordStart,
|
||||
int rawWordCursor,
|
||||
int rawWordLength,
|
||||
int pos) {
|
||||
if (current.length() > 0) {
|
||||
words.add(current.toString());
|
||||
current.setLength(0); // reset the arg
|
||||
@ -470,7 +480,7 @@ public class DefaultParser implements Parser {
|
||||
|
||||
public boolean isLineCommentStarted(final CharSequence buffer, final int pos) {
|
||||
if (lineCommentDelims != null) {
|
||||
for (String comment: lineCommentDelims) {
|
||||
for (String comment : lineCommentDelims) {
|
||||
if (isCommentDelim(buffer, pos, comment)) {
|
||||
return true;
|
||||
}
|
||||
@ -584,8 +594,8 @@ public class DefaultParser implements Parser {
|
||||
} else {
|
||||
bid = bracketId(closingBrackets, buffer, pos);
|
||||
if (bid >= 0) {
|
||||
if (!nested.isEmpty() && bid == nested.get(nested.size()-1)) {
|
||||
nested.remove(nested.size()-1);
|
||||
if (!nested.isEmpty() && bid == nested.get(nested.size() - 1)) {
|
||||
nested.remove(nested.size() - 1);
|
||||
} else {
|
||||
missingOpeningBracket = bid;
|
||||
}
|
||||
@ -634,7 +644,7 @@ public class DefaultParser implements Parser {
|
||||
}
|
||||
|
||||
private int bracketId(final char[] brackets, final CharSequence buffer, final int pos) {
|
||||
for (int i=0; i < brackets.length; i++) {
|
||||
for (int i = 0; i < brackets.length; i++) {
|
||||
if (buffer.charAt(pos) == brackets[i]) {
|
||||
return i;
|
||||
}
|
||||
@ -648,8 +658,7 @@ public class DefaultParser implements Parser {
|
||||
*
|
||||
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
|
||||
*/
|
||||
public class ArgumentList implements ParsedLine, CompletingParsedLine
|
||||
{
|
||||
public class ArgumentList implements ParsedLine, CompletingParsedLine {
|
||||
private final String line;
|
||||
|
||||
private final List<String> words;
|
||||
@ -667,11 +676,21 @@ public class DefaultParser implements Parser {
|
||||
private final int rawWordLength;
|
||||
|
||||
@Deprecated
|
||||
public ArgumentList(final String line, final List<String> words,
|
||||
final int wordIndex, final int wordCursor,
|
||||
final int cursor) {
|
||||
this(line, words, wordIndex, wordCursor, cursor,
|
||||
null, wordCursor, words.get(wordIndex).length());
|
||||
public ArgumentList(
|
||||
final String line,
|
||||
final List<String> words,
|
||||
final int wordIndex,
|
||||
final int wordCursor,
|
||||
final int cursor) {
|
||||
this(
|
||||
line,
|
||||
words,
|
||||
wordIndex,
|
||||
wordCursor,
|
||||
cursor,
|
||||
null,
|
||||
wordCursor,
|
||||
words.get(wordIndex).length());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -685,10 +704,15 @@ public class DefaultParser implements Parser {
|
||||
* @param rawWordCursor the cursor position inside the raw word (i.e. including quotes and escape characters)
|
||||
* @param rawWordLength the raw word length, including quotes and escape characters
|
||||
*/
|
||||
public ArgumentList(final String line, final List<String> words,
|
||||
final int wordIndex, final int wordCursor,
|
||||
final int cursor, final String openingQuote,
|
||||
final int rawWordCursor, final int rawWordLength) {
|
||||
public ArgumentList(
|
||||
final String line,
|
||||
final List<String> words,
|
||||
final int wordIndex,
|
||||
final int wordCursor,
|
||||
final int cursor,
|
||||
final String openingQuote,
|
||||
final int rawWordCursor,
|
||||
final int rawWordLength) {
|
||||
this.line = line;
|
||||
this.words = Collections.unmodifiableList(Objects.requireNonNull(words));
|
||||
this.wordIndex = wordIndex;
|
||||
@ -732,8 +756,8 @@ public class DefaultParser implements Parser {
|
||||
Predicate<Integer> needToBeEscaped;
|
||||
String quote = openingQuote;
|
||||
boolean middleQuotes = false;
|
||||
if (openingQuote==null) {
|
||||
for (int i=0; i < sb.length(); i++) {
|
||||
if (openingQuote == null) {
|
||||
for (int i = 0; i < sb.length(); i++) {
|
||||
if (isQuoteChar(sb, i)) {
|
||||
middleQuotes = true;
|
||||
break;
|
||||
@ -746,7 +770,8 @@ public class DefaultParser implements Parser {
|
||||
// Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does.
|
||||
// Also, close the quote at the end
|
||||
if (openingQuote != null) {
|
||||
needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)) || String.valueOf(sb.charAt(i)).equals(openingQuote);
|
||||
needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i))
|
||||
|| String.valueOf(sb.charAt(i)).equals(openingQuote);
|
||||
}
|
||||
// Completion is protected by middle quotes:
|
||||
// Delimiters (spaces) don't need to be escaped, nor do quotes, but everything else does.
|
||||
@ -756,8 +781,8 @@ public class DefaultParser implements Parser {
|
||||
// No quote protection, need to escape everything: delimiter chars (spaces), quote chars
|
||||
// and escapes themselves
|
||||
else {
|
||||
needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i))
|
||||
|| isRawQuoteChar(sb.charAt(i));
|
||||
needToBeEscaped = i ->
|
||||
isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) || isRawQuoteChar(sb.charAt(i));
|
||||
}
|
||||
for (int i = 0; i < sb.length(); i++) {
|
||||
if (needToBeEscaped.test(i)) {
|
||||
@ -792,5 +817,4 @@ public class DefaultParser implements Parser {
|
||||
return rawWordLength;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -13,7 +13,7 @@ import jdk.internal.org.jline.utils.Levenshtein;
|
||||
|
||||
public class ReaderUtils {
|
||||
|
||||
private ReaderUtils() { }
|
||||
private ReaderUtils() {}
|
||||
|
||||
public static boolean isSet(LineReader reader, LineReader.Option option) {
|
||||
return reader != null && reader.isSet(option);
|
||||
@ -30,8 +30,7 @@ public class ReaderUtils {
|
||||
return (Boolean) v;
|
||||
} else if (v != null) {
|
||||
String s = v.toString();
|
||||
return s.isEmpty() || s.equalsIgnoreCase("on")
|
||||
|| s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
|
||||
return s.isEmpty() || s.equalsIgnoreCase("on") || s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
|
||||
}
|
||||
return def;
|
||||
}
|
||||
@ -77,5 +76,4 @@ public class ReaderUtils {
|
||||
return Levenshtein.distance(word, cand);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2017, the original author or authors.
|
||||
* Copyright (c) 2002-2017, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,10 +8,10 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.reader.impl;
|
||||
|
||||
import jdk.internal.org.jline.reader.MaskingCallback;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.org.jline.reader.MaskingCallback;
|
||||
|
||||
/**
|
||||
* Simple {@link MaskingCallback} that will replace all the characters in the line with the given mask.
|
||||
* If the given mask is equal to {@link LineReaderImpl#NULL_MASK} then the line will be replaced with an empty String.
|
||||
@ -29,7 +29,7 @@ public final class SimpleMaskingCallback implements MaskingCallback {
|
||||
return "";
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder(line.length());
|
||||
for (int i = line.length(); i-- > 0;) {
|
||||
for (int i = line.length(); i-- > 0; ) {
|
||||
sb.append((char) mask);
|
||||
}
|
||||
return sb.toString();
|
||||
@ -40,5 +40,4 @@ public final class SimpleMaskingCallback implements MaskingCallback {
|
||||
public String history(String line) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -20,6 +20,7 @@ public class UndoTree<T> {
|
||||
private final Node parent;
|
||||
private Node current;
|
||||
|
||||
@SuppressWarnings("this-escape")
|
||||
public UndoTree(Consumer<T> s) {
|
||||
state = s;
|
||||
parent = new Node(null);
|
||||
@ -71,5 +72,4 @@ public class UndoTree<T> {
|
||||
state = s;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -24,9 +24,7 @@ import jdk.internal.org.jline.reader.ParsedLine;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public class AggregateCompleter
|
||||
implements Completer
|
||||
{
|
||||
public class AggregateCompleter implements Completer {
|
||||
private final Collection<Completer> completers;
|
||||
|
||||
/**
|
||||
@ -78,9 +76,6 @@ public class AggregateCompleter
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "{" +
|
||||
"completers=" + completers +
|
||||
'}';
|
||||
return getClass().getSimpleName() + "{" + "completers=" + completers + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2019, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -29,8 +29,7 @@ import jdk.internal.org.jline.reader.ParsedLine;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public class ArgumentCompleter implements Completer
|
||||
{
|
||||
public class ArgumentCompleter implements Completer {
|
||||
private final List<Completer> completers = new ArrayList<>();
|
||||
|
||||
private boolean strict = true;
|
||||
@ -108,12 +107,12 @@ public class ArgumentCompleter implements Completer
|
||||
// if we are beyond the end of the completers, just use the last one
|
||||
if (line.wordIndex() >= completers.size()) {
|
||||
completer = completers.get(completers.size() - 1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
completer = completers.get(line.wordIndex());
|
||||
}
|
||||
|
||||
// ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
|
||||
// ensure that all the previous completers are successful before allowing this completer to pass (only if
|
||||
// strict).
|
||||
for (int i = strictCommand ? 0 : 1; isStrict() && (i < line.wordIndex()); i++) {
|
||||
int idx = i >= completers.size() ? (completers.size() - 1) : i;
|
||||
if (idx == 0 && !strictCommand) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -19,8 +19,7 @@ import jdk.internal.org.jline.reader.Completer;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public class EnumCompleter extends StringsCompleter
|
||||
{
|
||||
public class EnumCompleter extends StringsCompleter {
|
||||
public EnumCompleter(Class<? extends Enum<?>> source) {
|
||||
Objects.requireNonNull(source);
|
||||
for (Enum<?> n : source.getEnumConstants()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -9,6 +9,7 @@
|
||||
package jdk.internal.org.jline.reader.impl.completer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@ -41,11 +42,10 @@ import jdk.internal.org.jline.utils.AttributedStyle;
|
||||
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
* @deprecated use <code>jdk.internal.org.jline.builtins.Completers$FileNameCompleter</code> instead
|
||||
* @deprecated use <code>org.jline.builtins.Completers$FileNameCompleter</code> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class FileNameCompleter implements Completer
|
||||
{
|
||||
public class FileNameCompleter implements Completer {
|
||||
|
||||
public void complete(LineReader reader, ParsedLine commandLine, final List<Candidate> candidates) {
|
||||
assert commandLine != null;
|
||||
@ -72,20 +72,21 @@ public class FileNameCompleter implements Completer
|
||||
curBuf = "";
|
||||
current = getUserDir();
|
||||
}
|
||||
try {
|
||||
Files.newDirectoryStream(current, this::accept).forEach(p -> {
|
||||
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(current, this::accept)) {
|
||||
directoryStream.forEach(p -> {
|
||||
String value = curBuf + p.getFileName().toString();
|
||||
if (Files.isDirectory(p)) {
|
||||
candidates.add(new Candidate(
|
||||
value + (reader.isSet(Option.AUTO_PARAM_SLASH) ? sep : ""),
|
||||
getDisplay(reader.getTerminal(), p),
|
||||
null, null,
|
||||
null,
|
||||
null,
|
||||
reader.isSet(Option.AUTO_REMOVE_SLASH) ? sep : null,
|
||||
null,
|
||||
false));
|
||||
} else {
|
||||
candidates.add(new Candidate(value, getDisplay(reader.getTerminal(), p),
|
||||
null, null, null, null, true));
|
||||
candidates.add(
|
||||
new Candidate(value, getDisplay(reader.getTerminal(), p), null, null, null, null, true));
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
@ -125,5 +126,4 @@ public class FileNameCompleter implements Completer
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -22,11 +22,8 @@ import jdk.internal.org.jline.reader.ParsedLine;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public final class NullCompleter
|
||||
implements Completer
|
||||
{
|
||||
public final class NullCompleter implements Completer {
|
||||
public static final NullCompleter INSTANCE = new NullCompleter();
|
||||
|
||||
public void complete(LineReader reader, final ParsedLine line, final List<Candidate> candidates) {
|
||||
}
|
||||
public void complete(LineReader reader, final ParsedLine line, final List<Candidate> candidates) {}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2019, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -27,8 +27,7 @@ import jdk.internal.org.jline.utils.AttributedString;
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
*/
|
||||
public class StringsCompleter implements Completer
|
||||
{
|
||||
public class StringsCompleter implements Completer {
|
||||
protected Collection<Candidate> candidates;
|
||||
protected Supplier<Collection<String>> stringsSupplier;
|
||||
|
||||
@ -54,7 +53,7 @@ public class StringsCompleter implements Completer
|
||||
}
|
||||
}
|
||||
|
||||
public StringsCompleter(Candidate ... candidates) {
|
||||
public StringsCompleter(Candidate... candidates) {
|
||||
this(Arrays.asList(candidates));
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -22,8 +22,8 @@ import jdk.internal.org.jline.utils.AttributedString;
|
||||
* @author <a href="mailto:matti.rintanikkola@gmail.com">Matti Rinta-Nikkola</a>
|
||||
*/
|
||||
public class SystemCompleter implements Completer {
|
||||
private Map<String,List<Completer>> completers = new HashMap<>();
|
||||
private Map<String,String> aliasCommand = new HashMap<>();
|
||||
private Map<String, List<Completer>> completers = new HashMap<>();
|
||||
private Map<String, String> aliasCommand = new HashMap<>();
|
||||
private StringsCompleter commands;
|
||||
private boolean compiled = false;
|
||||
|
||||
@ -44,9 +44,9 @@ public class SystemCompleter implements Completer {
|
||||
commands.complete(reader, commandLine, candidates);
|
||||
} else if (reader.getParser().validVariableName(buffer.substring(0, eq))) {
|
||||
String curBuf = buffer.substring(0, eq + 1);
|
||||
for (String c: completers.keySet()) {
|
||||
candidates.add(new Candidate(AttributedString.stripAnsi(curBuf+c)
|
||||
, c, null, null, null, null, true));
|
||||
for (String c : completers.keySet()) {
|
||||
candidates.add(
|
||||
new Candidate(AttributedString.stripAnsi(curBuf + c), c, null, null, null, null, true));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -81,7 +81,7 @@ public class SystemCompleter implements Completer {
|
||||
}
|
||||
|
||||
public void add(List<String> commands, Completer completer) {
|
||||
for (String c: commands) {
|
||||
for (String c : commands) {
|
||||
add(c, completer);
|
||||
}
|
||||
}
|
||||
@ -104,22 +104,22 @@ public class SystemCompleter implements Completer {
|
||||
if (other.isCompiled()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
for (Map.Entry<String, List<Completer>> entry: other.getCompleters().entrySet()) {
|
||||
for (Completer c: entry.getValue()) {
|
||||
for (Map.Entry<String, List<Completer>> entry : other.getCompleters().entrySet()) {
|
||||
for (Completer c : entry.getValue()) {
|
||||
add(entry.getKey(), c);
|
||||
}
|
||||
}
|
||||
addAliases(other.getAliases());
|
||||
}
|
||||
|
||||
public void addAliases(Map<String,String> aliasCommand) {
|
||||
public void addAliases(Map<String, String> aliasCommand) {
|
||||
if (compiled) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.aliasCommand.putAll(aliasCommand);
|
||||
}
|
||||
|
||||
private Map<String,String> getAliases() {
|
||||
private Map<String, String> getAliases() {
|
||||
return aliasCommand;
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ public class SystemCompleter implements Completer {
|
||||
return;
|
||||
}
|
||||
Map<String, List<Completer>> compiledCompleters = new HashMap<>();
|
||||
for (Map.Entry<String, List<Completer>> entry: completers.entrySet()) {
|
||||
for (Map.Entry<String, List<Completer>> entry : completers.entrySet()) {
|
||||
if (entry.getValue().size() == 1) {
|
||||
compiledCompleters.put(entry.getKey(), entry.getValue());
|
||||
} else {
|
||||
@ -143,8 +143,7 @@ public class SystemCompleter implements Completer {
|
||||
compiled = true;
|
||||
}
|
||||
|
||||
public Map<String,List<Completer>> getCompleters() {
|
||||
public Map<String, List<Completer>> getCompleters() {
|
||||
return completers;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -41,9 +41,9 @@ public class DefaultHistory implements History {
|
||||
private int offset = 0;
|
||||
private int index = 0;
|
||||
|
||||
public DefaultHistory() {
|
||||
}
|
||||
public DefaultHistory() {}
|
||||
|
||||
@SuppressWarnings("this-escape")
|
||||
public DefaultHistory(LineReader reader) {
|
||||
attach(reader);
|
||||
}
|
||||
@ -67,8 +67,7 @@ public class DefaultHistory implements History {
|
||||
this.reader = reader;
|
||||
try {
|
||||
load();
|
||||
}
|
||||
catch (IllegalArgumentException | IOException e) {
|
||||
} catch (IllegalArgumentException | IOException e) {
|
||||
Log.warn("Failed to load history", e);
|
||||
}
|
||||
}
|
||||
@ -117,13 +116,13 @@ public class DefaultHistory implements History {
|
||||
}
|
||||
}
|
||||
|
||||
private String doHistoryFileDataKey (Path path){
|
||||
private String doHistoryFileDataKey(Path path) {
|
||||
return path != null ? path.toAbsolutePath().toString() : null;
|
||||
}
|
||||
|
||||
private HistoryFileData getHistoryFileData(Path path) {
|
||||
String key = doHistoryFileDataKey(path);
|
||||
if (!historyFiles.containsKey(key)){
|
||||
if (!historyFiles.containsKey(key)) {
|
||||
historyFiles.put(key, new HistoryFileData());
|
||||
}
|
||||
return historyFiles.get(key);
|
||||
@ -133,7 +132,7 @@ public class DefaultHistory implements History {
|
||||
historyFiles.put(doHistoryFileDataKey(path), historyFileData);
|
||||
}
|
||||
|
||||
private boolean isLineReaderHistory (Path path) throws IOException {
|
||||
private boolean isLineReaderHistory(Path path) throws IOException {
|
||||
Path lrp = getPath();
|
||||
if (lrp == null) {
|
||||
return path == null;
|
||||
@ -141,23 +140,23 @@ public class DefaultHistory implements History {
|
||||
return Files.isSameFile(lrp, path);
|
||||
}
|
||||
|
||||
private void setLastLoaded(Path path, int lastloaded){
|
||||
private void setLastLoaded(Path path, int lastloaded) {
|
||||
getHistoryFileData(path).setLastLoaded(lastloaded);
|
||||
}
|
||||
|
||||
private void setEntriesInFile(Path path, int entriesInFile){
|
||||
private void setEntriesInFile(Path path, int entriesInFile) {
|
||||
getHistoryFileData(path).setEntriesInFile(entriesInFile);
|
||||
}
|
||||
|
||||
private void incEntriesInFile(Path path, int amount){
|
||||
private void incEntriesInFile(Path path, int amount) {
|
||||
getHistoryFileData(path).incEntriesInFile(amount);
|
||||
}
|
||||
|
||||
private int getLastLoaded(Path path){
|
||||
private int getLastLoaded(Path path) {
|
||||
return getHistoryFileData(path).getLastLoaded();
|
||||
}
|
||||
|
||||
private int getEntriesInFile(Path path){
|
||||
private int getEntriesInFile(Path path) {
|
||||
return getHistoryFileData(path).getEntriesInFile();
|
||||
}
|
||||
|
||||
@ -168,9 +167,8 @@ public class DefaultHistory implements History {
|
||||
protected void addHistoryLine(Path path, String line, boolean checkDuplicates) {
|
||||
if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
|
||||
int idx = line.indexOf(':');
|
||||
final String badHistoryFileSyntax = "Bad history file syntax! " +
|
||||
"The history file `" + path + "` may be an older history: " +
|
||||
"please remove it or use a different history file.";
|
||||
final String badHistoryFileSyntax = "Bad history file syntax! " + "The history file `" + path
|
||||
+ "` may be an older history: " + "please remove it or use a different history file.";
|
||||
if (idx < 0) {
|
||||
throw new IllegalArgumentException(badHistoryFileSyntax);
|
||||
}
|
||||
@ -183,8 +181,7 @@ public class DefaultHistory implements History {
|
||||
|
||||
String unescaped = unescape(line.substring(idx + 1));
|
||||
internalAdd(time, unescaped, checkDuplicates);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
internalAdd(Instant.now(), unescape(line), checkDuplicates);
|
||||
}
|
||||
}
|
||||
@ -210,8 +207,7 @@ public class DefaultHistory implements History {
|
||||
|
||||
@Override
|
||||
public void append(Path file, boolean incremental) throws IOException {
|
||||
internalWrite(file != null ? file : getPath(),
|
||||
incremental ? getLastLoaded(file) : 0);
|
||||
internalWrite(file != null ? file : getPath(), incremental ? getLastLoaded(file) : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -227,8 +223,11 @@ public class DefaultHistory implements History {
|
||||
Files.createDirectories(parent);
|
||||
}
|
||||
// Append new items to the history file
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(path.toAbsolutePath(),
|
||||
StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(
|
||||
path.toAbsolutePath(),
|
||||
StandardOpenOption.WRITE,
|
||||
StandardOpenOption.APPEND,
|
||||
StandardOpenOption.CREATE)) {
|
||||
for (Entry entry : items.subList(from, items.size())) {
|
||||
if (isPersistable(entry)) {
|
||||
writer.append(format(entry));
|
||||
@ -248,18 +247,23 @@ public class DefaultHistory implements History {
|
||||
Log.trace("Trimming history path: ", path);
|
||||
// Load all history entries
|
||||
LinkedList<Entry> allItems = new LinkedList<>();
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
reader.lines().forEach(l -> {
|
||||
int idx = l.indexOf(':');
|
||||
Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx)));
|
||||
String line = unescape(l.substring(idx + 1));
|
||||
allItems.add(createEntry(allItems.size(), time, line));
|
||||
try (BufferedReader historyFileReader = Files.newBufferedReader(path)) {
|
||||
historyFileReader.lines().forEach(l -> {
|
||||
if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
|
||||
int idx = l.indexOf(':');
|
||||
Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx)));
|
||||
String line = unescape(l.substring(idx + 1));
|
||||
allItems.add(createEntry(allItems.size(), time, line));
|
||||
} else {
|
||||
allItems.add(createEntry(allItems.size(), Instant.now(), unescape(l)));
|
||||
}
|
||||
});
|
||||
}
|
||||
// Remove duplicates
|
||||
List<Entry> trimmedItems = doTrimHistory(allItems, max);
|
||||
// Write history
|
||||
Path temp = Files.createTempFile(path.toAbsolutePath().getParent(), path.getFileName().toString(), ".tmp");
|
||||
Path temp = Files.createTempFile(
|
||||
path.toAbsolutePath().getParent(), path.getFileName().toString(), ".tmp");
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(temp, StandardOpenOption.WRITE)) {
|
||||
for (Entry entry : trimmedItems) {
|
||||
writer.append(format(entry));
|
||||
@ -351,7 +355,7 @@ public class DefaultHistory implements History {
|
||||
public String get(final int index) {
|
||||
int idx = index - offset;
|
||||
if (idx >= items.size() || idx < 0) {
|
||||
throw new IllegalArgumentException("IndexOutOfBounds: Index:" + idx +", Size:" + items.size());
|
||||
throw new IllegalArgumentException("IndexOutOfBounds: Index:" + idx + ", Size:" + items.size());
|
||||
}
|
||||
return items.get(idx).line();
|
||||
}
|
||||
@ -382,8 +386,7 @@ public class DefaultHistory implements History {
|
||||
if (isSet(reader, LineReader.Option.HISTORY_INCREMENTAL)) {
|
||||
try {
|
||||
save();
|
||||
}
|
||||
catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
Log.warn("Failed to save history", e);
|
||||
}
|
||||
}
|
||||
@ -417,7 +420,7 @@ public class DefaultHistory implements History {
|
||||
protected void internalAdd(Instant time, String line, boolean checkDuplicates) {
|
||||
Entry entry = new EntryImpl(offset + items.size(), time, line);
|
||||
if (checkDuplicates) {
|
||||
for (Entry e: items) {
|
||||
for (Entry e : items) {
|
||||
if (e.line().trim().equals(line.trim())) {
|
||||
return;
|
||||
}
|
||||
@ -430,7 +433,7 @@ public class DefaultHistory implements History {
|
||||
private void maybeResize() {
|
||||
while (size() > getInt(reader, LineReader.HISTORY_SIZE, DEFAULT_HISTORY_SIZE)) {
|
||||
items.removeFirst();
|
||||
for (HistoryFileData hfd: historyFiles.values()) {
|
||||
for (HistoryFileData hfd : historyFiles.values()) {
|
||||
hfd.decLastLoaded();
|
||||
}
|
||||
offset++;
|
||||
@ -633,8 +636,7 @@ public class DefaultHistory implements History {
|
||||
private int lastLoaded = 0;
|
||||
private int entriesInFile = 0;
|
||||
|
||||
public HistoryFileData() {
|
||||
}
|
||||
public HistoryFileData() {}
|
||||
|
||||
public HistoryFileData(int lastLoaded, int entriesInFile) {
|
||||
this.lastLoaded = lastLoaded;
|
||||
@ -667,8 +669,5 @@ public class DefaultHistory implements History {
|
||||
public void incEntriesInFile(int amount) {
|
||||
entriesInFile = entriesInFile + amount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -43,63 +43,65 @@ public class Attributes {
|
||||
* Input flags - software input processing
|
||||
*/
|
||||
public enum InputFlag {
|
||||
IGNBRK, /* ignore BREAK condition */
|
||||
BRKINT, /* map BREAK to SIGINTR */
|
||||
IGNPAR, /* ignore (discard) parity errors */
|
||||
PARMRK, /* mark parity and framing errors */
|
||||
INPCK, /* enable checking of parity errors */
|
||||
ISTRIP, /* strip 8th bit off chars */
|
||||
INLCR, /* map NL into CR */
|
||||
IGNCR, /* ignore CR */
|
||||
ICRNL, /* map CR to NL (ala CRMOD) */
|
||||
IXON, /* enable output flow control */
|
||||
IXOFF, /* enable input flow control */
|
||||
IXANY, /* any char will restart after stop */
|
||||
IMAXBEL, /* ring bell on input queue full */
|
||||
IUTF8 /* maintain state for UTF-8 VERASE */
|
||||
IGNBRK, /* ignore BREAK condition */
|
||||
BRKINT, /* map BREAK to SIGINTR */
|
||||
IGNPAR, /* ignore (discard) parity errors */
|
||||
PARMRK, /* mark parity and framing errors */
|
||||
INPCK, /* enable checking of parity errors */
|
||||
ISTRIP, /* strip 8th bit off chars */
|
||||
INLCR, /* map NL into CR */
|
||||
IGNCR, /* ignore CR */
|
||||
ICRNL, /* map CR to NL (ala CRMOD) */
|
||||
IXON, /* enable output flow control */
|
||||
IXOFF, /* enable input flow control */
|
||||
IXANY, /* any char will restart after stop */
|
||||
IMAXBEL, /* ring bell on input queue full */
|
||||
IUTF8, /* maintain state for UTF-8 VERASE */
|
||||
|
||||
INORMEOL /* normalize end-of-line */
|
||||
}
|
||||
|
||||
/*
|
||||
* Output flags - software output processing
|
||||
*/
|
||||
public enum OutputFlag {
|
||||
OPOST, /* enable following output processing */
|
||||
ONLCR, /* map NL to CR-NL (ala CRMOD) */
|
||||
OXTABS, /* expand tabs to spaces */
|
||||
ONOEOT, /* discard EOT's (^D) on output) */
|
||||
OCRNL, /* map CR to NL on output */
|
||||
ONOCR, /* no CR output at column 0 */
|
||||
ONLRET, /* NL performs CR function */
|
||||
OFILL, /* use fill characters for delay */
|
||||
NLDLY, /* \n delay */
|
||||
TABDLY, /* horizontal tab delay */
|
||||
CRDLY, /* \r delay */
|
||||
FFDLY, /* form feed delay */
|
||||
BSDLY, /* \b delay */
|
||||
VTDLY, /* vertical tab delay */
|
||||
OFDEL /* fill is DEL, else NUL */
|
||||
OPOST, /* enable following output processing */
|
||||
ONLCR, /* map NL to CR-NL (ala CRMOD) */
|
||||
OXTABS, /* expand tabs to spaces */
|
||||
ONOEOT, /* discard EOT's (^D) on output) */
|
||||
OCRNL, /* map CR to NL on output */
|
||||
ONOCR, /* no CR output at column 0 */
|
||||
ONLRET, /* NL performs CR function */
|
||||
OFILL, /* use fill characters for delay */
|
||||
NLDLY, /* \n delay */
|
||||
TABDLY, /* horizontal tab delay */
|
||||
CRDLY, /* \r delay */
|
||||
FFDLY, /* form feed delay */
|
||||
BSDLY, /* \b delay */
|
||||
VTDLY, /* vertical tab delay */
|
||||
OFDEL /* fill is DEL, else NUL */
|
||||
}
|
||||
|
||||
/*
|
||||
* Control flags - hardware control of terminal
|
||||
*/
|
||||
public enum ControlFlag {
|
||||
CIGNORE, /* ignore control flags */
|
||||
CS5, /* 5 bits (pseudo) */
|
||||
CS6, /* 6 bits */
|
||||
CS7, /* 7 bits */
|
||||
CS8, /* 8 bits */
|
||||
CSTOPB, /* send 2 stop bits */
|
||||
CREAD, /* enable receiver */
|
||||
PARENB, /* parity enable */
|
||||
PARODD, /* odd parity, else even */
|
||||
HUPCL, /* hang up on last close */
|
||||
CLOCAL, /* ignore modem status lines */
|
||||
CCTS_OFLOW, /* CTS flow control of output */
|
||||
CRTS_IFLOW, /* RTS flow control of input */
|
||||
CDTR_IFLOW, /* DTR flow control of input */
|
||||
CDSR_OFLOW, /* DSR flow control of output */
|
||||
CCAR_OFLOW /* DCD flow control of output */
|
||||
CIGNORE, /* ignore control flags */
|
||||
CS5, /* 5 bits (pseudo) */
|
||||
CS6, /* 6 bits */
|
||||
CS7, /* 7 bits */
|
||||
CS8, /* 8 bits */
|
||||
CSTOPB, /* send 2 stop bits */
|
||||
CREAD, /* enable receiver */
|
||||
PARENB, /* parity enable */
|
||||
PARODD, /* odd parity, else even */
|
||||
HUPCL, /* hang up on last close */
|
||||
CLOCAL, /* ignore modem status lines */
|
||||
CCTS_OFLOW, /* CTS flow control of output */
|
||||
CRTS_IFLOW, /* RTS flow control of input */
|
||||
CDTR_IFLOW, /* DTR flow control of input */
|
||||
CDSR_OFLOW, /* DSR flow control of output */
|
||||
CCAR_OFLOW /* DCD flow control of output */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -110,23 +112,23 @@ public class Attributes {
|
||||
* input flag.
|
||||
*/
|
||||
public enum LocalFlag {
|
||||
ECHOKE, /* visual erase for line kill */
|
||||
ECHOE, /* visually erase chars */
|
||||
ECHOK, /* echo NL after line kill */
|
||||
ECHO, /* enable echoing */
|
||||
ECHONL, /* echo NL even if ECHO is off */
|
||||
ECHOPRT, /* visual erase mode for hardcopy */
|
||||
ECHOCTL, /* echo control chars as ^(Char) */
|
||||
ISIG, /* enable signals INTR, QUIT, [D]SUSP */
|
||||
ICANON, /* canonicalize input lines */
|
||||
ALTWERASE, /* use alternate WERASE algorithm */
|
||||
IEXTEN, /* enable DISCARD and LNEXT */
|
||||
EXTPROC, /* external processing */
|
||||
TOSTOP, /* stop background jobs from output */
|
||||
FLUSHO, /* output being flushed (state) */
|
||||
NOKERNINFO, /* no kernel output from VSTATUS */
|
||||
PENDIN, /* XXX retype pending input (state) */
|
||||
NOFLSH /* don't flush after interrupt */
|
||||
ECHOKE, /* visual erase for line kill */
|
||||
ECHOE, /* visually erase chars */
|
||||
ECHOK, /* echo NL after line kill */
|
||||
ECHO, /* enable echoing */
|
||||
ECHONL, /* echo NL even if ECHO is off */
|
||||
ECHOPRT, /* visual erase mode for hardcopy */
|
||||
ECHOCTL, /* echo control chars as ^(Char) */
|
||||
ISIG, /* enable signals INTR, QUIT, [D]SUSP */
|
||||
ICANON, /* canonicalize input lines */
|
||||
ALTWERASE, /* use alternate WERASE algorithm */
|
||||
IEXTEN, /* enable DISCARD and LNEXT */
|
||||
EXTPROC, /* external processing */
|
||||
TOSTOP, /* stop background jobs from output */
|
||||
FLUSHO, /* output being flushed (state) */
|
||||
NOKERNINFO, /* no kernel output from VSTATUS */
|
||||
PENDIN, /* XXX retype pending input (state) */
|
||||
NOFLSH /* don't flush after interrupt */
|
||||
}
|
||||
|
||||
final EnumSet<InputFlag> iflag = EnumSet.noneOf(InputFlag.class);
|
||||
@ -135,9 +137,9 @@ public class Attributes {
|
||||
final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class);
|
||||
final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class);
|
||||
|
||||
public Attributes() {
|
||||
}
|
||||
public Attributes() {}
|
||||
|
||||
@SuppressWarnings("this-escape")
|
||||
public Attributes(Attributes attr) {
|
||||
copy(attr);
|
||||
}
|
||||
@ -310,13 +312,12 @@ public class Attributes {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Attributes[" +
|
||||
"lflags: " + append(lflag) + ", " +
|
||||
"iflags: " + append(iflag) + ", " +
|
||||
"oflags: " + append(oflag) + ", " +
|
||||
"cflags: " + append(cflag) + ", " +
|
||||
"cchars: " + append(EnumSet.allOf(ControlChar.class), this::display) +
|
||||
"]";
|
||||
return "Attributes[" + "lflags: "
|
||||
+ append(lflag) + ", " + "iflags: "
|
||||
+ append(iflag) + ", " + "oflags: "
|
||||
+ append(oflag) + ", " + "cflags: "
|
||||
+ append(cflag) + ", " + "cchars: "
|
||||
+ append(EnumSet.allOf(ControlChar.class), this::display) + "]";
|
||||
}
|
||||
|
||||
private String display(ControlChar c) {
|
||||
@ -345,5 +346,4 @@ public class Attributes {
|
||||
private <T extends Enum<T>> String append(EnumSet<T> set, Function<T, String> toString) {
|
||||
return set.stream().map(toString).collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -71,12 +71,11 @@ public class MouseEvent {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MouseEvent[" +
|
||||
"type=" + type +
|
||||
", button=" + button +
|
||||
", modifiers=" + modifiers +
|
||||
", x=" + x +
|
||||
", y=" + y +
|
||||
']';
|
||||
return "MouseEvent[" + "type="
|
||||
+ type + ", button="
|
||||
+ button + ", modifiers="
|
||||
+ modifiers + ", x="
|
||||
+ x + ", y="
|
||||
+ y + ']';
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -13,9 +13,9 @@ public class Size {
|
||||
private int rows;
|
||||
private int cols;
|
||||
|
||||
public Size() {
|
||||
}
|
||||
public Size() {}
|
||||
|
||||
@SuppressWarnings("this-escape")
|
||||
public Size(int columns, int rows) {
|
||||
this();
|
||||
setColumns(columns);
|
||||
@ -50,7 +50,7 @@ public class Size {
|
||||
* @return the cursor position
|
||||
*/
|
||||
public int cursorPos(int row, int col) {
|
||||
return row * (cols+1) + col;
|
||||
return row * (cols + 1) + col;
|
||||
}
|
||||
|
||||
public void copy(Size size) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -34,6 +34,7 @@ public interface Terminal extends Closeable, Flushable {
|
||||
* Type used for dumb terminals.
|
||||
*/
|
||||
String TYPE_DUMB = "dumb";
|
||||
|
||||
String TYPE_DUMB_COLOR = "dumb-color";
|
||||
|
||||
String getName();
|
||||
@ -42,6 +43,9 @@ public interface Terminal extends Closeable, Flushable {
|
||||
// Signal support
|
||||
//
|
||||
|
||||
/**
|
||||
* Types of signals.
|
||||
*/
|
||||
enum Signal {
|
||||
INT,
|
||||
QUIT,
|
||||
@ -51,16 +55,55 @@ public interface Terminal extends Closeable, Flushable {
|
||||
WINCH
|
||||
}
|
||||
|
||||
/**
|
||||
* The SignalHandler defines the interface used to trap signals and perform specific behaviors.
|
||||
* @see Terminal.Signal
|
||||
* @see Terminal#handle(Signal, SignalHandler)
|
||||
*/
|
||||
interface SignalHandler {
|
||||
|
||||
/**
|
||||
* The {@code SIG_DFL} value can be used to specify that the JVM default behavior
|
||||
* should be used to handle this signal.
|
||||
*/
|
||||
SignalHandler SIG_DFL = NativeSignalHandler.SIG_DFL;
|
||||
|
||||
/**
|
||||
* The {@code SIG_IGN} value can be used to ignore this signal and not perform
|
||||
* any special processing.
|
||||
*/
|
||||
SignalHandler SIG_IGN = NativeSignalHandler.SIG_IGN;
|
||||
|
||||
/**
|
||||
* Handle the signal.
|
||||
* @param signal the signal
|
||||
*/
|
||||
void handle(Signal signal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler for the given {@link Signal}.
|
||||
* <p>
|
||||
* Note that the JVM does not easily allow catching the {@link Signal#QUIT} signal, which causes a thread dump
|
||||
* to be displayed. This signal is mainly used when connecting through an SSH socket to a virtual terminal.
|
||||
*
|
||||
* @param signal the signal to register a handler for
|
||||
* @param handler the handler
|
||||
* @return the previous signal handler
|
||||
*/
|
||||
SignalHandler handle(Signal signal, SignalHandler handler);
|
||||
|
||||
/**
|
||||
* Raise the specific signal.
|
||||
* This is not method usually called by non system terminals.
|
||||
* When accessing a terminal through a SSH or Telnet connection, signals may be
|
||||
* conveyed by the protocol and thus need to be raised when reaching the terminal code.
|
||||
* The terminals do that automatically when the terminal input stream has a character
|
||||
* mapped to {@link Attributes.ControlChar#VINTR}, {@link Attributes.ControlChar#VQUIT},
|
||||
* or {@link Attributes.ControlChar#VSUSP}.
|
||||
*
|
||||
* @param signal the signal to raise
|
||||
*/
|
||||
void raise(Signal signal);
|
||||
|
||||
//
|
||||
@ -180,8 +223,21 @@ public interface Terminal extends Closeable, Flushable {
|
||||
|
||||
boolean echo(boolean echo);
|
||||
|
||||
/**
|
||||
* Returns the terminal attributes.
|
||||
* The returned object can be safely modified
|
||||
* further used in a call to {@link #setAttributes(Attributes)}.
|
||||
*
|
||||
* @return the terminal attributes.
|
||||
*/
|
||||
Attributes getAttributes();
|
||||
|
||||
/**
|
||||
* Set the terminal attributes.
|
||||
* The terminal will perform a copy of the given attributes.
|
||||
*
|
||||
* @param attr the new attributes
|
||||
*/
|
||||
void setAttributes(Attributes attr);
|
||||
|
||||
/**
|
||||
@ -334,5 +390,4 @@ public interface Terminal extends Closeable, Flushable {
|
||||
* Color support
|
||||
*/
|
||||
ColorPalette getPalette();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,9 +8,6 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -19,11 +16,16 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@ -31,8 +33,10 @@ import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractPosixTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.DumbTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.DumbTerminalProvider;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalExt;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.Log;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
@ -49,16 +53,30 @@ public final class TerminalBuilder {
|
||||
public static final String PROP_ENCODING = "org.jline.terminal.encoding";
|
||||
public static final String PROP_CODEPAGE = "org.jline.terminal.codepage";
|
||||
public static final String PROP_TYPE = "org.jline.terminal.type";
|
||||
public static final String PROP_JNA = "org.jline.terminal.jna";
|
||||
public static final String PROP_JANSI = "org.jline.terminal.jansi";
|
||||
public static final String PROP_EXEC = "org.jline.terminal.exec";
|
||||
public static final String PROP_DUMB = "org.jline.terminal.dumb";
|
||||
public static final String PROP_PROVIDER = "org.jline.terminal.provider";
|
||||
public static final String PROP_PROVIDERS = "org.jline.terminal.providers";
|
||||
public static final String PROP_PROVIDER_FFM = "ffm";
|
||||
public static final String PROP_PROVIDER_JNI = "jni";
|
||||
public static final String PROP_PROVIDER_JANSI = "jansi";
|
||||
public static final String PROP_PROVIDER_JNA = "jna";
|
||||
public static final String PROP_PROVIDER_EXEC = "exec";
|
||||
public static final String PROP_PROVIDER_DUMB = "dumb";
|
||||
public static final String PROP_PROVIDERS_DEFAULT = String.join(
|
||||
",", PROP_PROVIDER_FFM, PROP_PROVIDER_JNI, PROP_PROVIDER_JANSI, PROP_PROVIDER_JNA, PROP_PROVIDER_EXEC);
|
||||
public static final String PROP_FFM = "org.jline.terminal." + PROP_PROVIDER_FFM;
|
||||
public static final String PROP_JNI = "org.jline.terminal." + PROP_PROVIDER_JNI;
|
||||
public static final String PROP_JANSI = "org.jline.terminal." + PROP_PROVIDER_JANSI;
|
||||
public static final String PROP_JNA = "org.jline.terminal." + PROP_PROVIDER_JNA;
|
||||
public static final String PROP_EXEC = "org.jline.terminal." + PROP_PROVIDER_EXEC;
|
||||
public static final String PROP_DUMB = "org.jline.terminal." + PROP_PROVIDER_DUMB;
|
||||
public static final String PROP_DUMB_COLOR = "org.jline.terminal.dumb.color";
|
||||
public static final String PROP_OUTPUT = "org.jline.terminal.output";
|
||||
public static final String PROP_OUTPUT_OUT = "out";
|
||||
public static final String PROP_OUTPUT_ERR = "err";
|
||||
public static final String PROP_OUTPUT_OUT_ERR = "out-err";
|
||||
public static final String PROP_OUTPUT_ERR_OUT = "err-out";
|
||||
public static final String PROP_OUTPUT_FORCED_OUT = "forced-out";
|
||||
public static final String PROP_OUTPUT_FORCED_ERR = "forced-err";
|
||||
|
||||
//
|
||||
// Other system properties controlling various jline parts
|
||||
@ -68,6 +86,32 @@ public final class TerminalBuilder {
|
||||
public static final String PROP_COLOR_DISTANCE = "org.jline.utils.colorDistance";
|
||||
public static final String PROP_DISABLE_ALTERNATE_CHARSET = "org.jline.utils.disableAlternateCharset";
|
||||
|
||||
//
|
||||
// System properties controlling how FileDescriptor are create.
|
||||
// The value can be a comma separated list of defined mechanisms.
|
||||
//
|
||||
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE = "org.jline.terminal.pty.fileDescriptorCreationMode";
|
||||
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE = "native";
|
||||
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION = "reflection";
|
||||
public static final String PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT =
|
||||
String.join(",", PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION, PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE);
|
||||
|
||||
//
|
||||
// System properties controlling how RedirectPipe are created.
|
||||
// The value can be a comma separated list of defined mechanisms.
|
||||
//
|
||||
public static final String PROP_REDIRECT_PIPE_CREATION_MODE = "org.jline.terminal.exec.redirectPipeCreationMode";
|
||||
public static final String PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE = "native";
|
||||
public static final String PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION = "reflection";
|
||||
public static final String PROP_REDIRECT_PIPE_CREATION_MODE_DEFAULT =
|
||||
String.join(",", PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION, PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE);
|
||||
|
||||
public static final Set<String> DEPRECATED_PROVIDERS =
|
||||
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(PROP_PROVIDER_JNA, PROP_PROVIDER_JANSI)));
|
||||
|
||||
public static final String PROP_DISABLE_DEPRECATED_PROVIDER_WARNING =
|
||||
"org.jline.terminal.disableDeprecatedProviderWarning";
|
||||
|
||||
//
|
||||
// Terminal output control
|
||||
//
|
||||
@ -75,7 +119,9 @@ public final class TerminalBuilder {
|
||||
SysOut,
|
||||
SysErr,
|
||||
SysOutOrSysErr,
|
||||
SysErrOrSysOut
|
||||
SysErrOrSysOut,
|
||||
ForcedSysOut,
|
||||
ForcedSysErr
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,20 +161,23 @@ public final class TerminalBuilder {
|
||||
private int codepage;
|
||||
private Boolean system;
|
||||
private SystemOutput systemOutput;
|
||||
private String provider;
|
||||
private String providers;
|
||||
private Boolean jna;
|
||||
private Boolean jansi;
|
||||
private Boolean jni;
|
||||
private Boolean exec;
|
||||
private Boolean ffm;
|
||||
private Boolean dumb;
|
||||
private Boolean color;
|
||||
private Attributes attributes;
|
||||
private Size size;
|
||||
private boolean nativeSignals = false;
|
||||
private boolean nativeSignals = true;
|
||||
private Function<InputStream, InputStream> inputStreamWrapper = in -> in;
|
||||
private Terminal.SignalHandler signalHandler = Terminal.SignalHandler.SIG_DFL;
|
||||
private boolean paused = false;
|
||||
|
||||
private TerminalBuilder() {
|
||||
}
|
||||
private TerminalBuilder() {}
|
||||
|
||||
public TerminalBuilder name(String name) {
|
||||
this.name = name;
|
||||
@ -160,6 +209,16 @@ public final class TerminalBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder provider(String provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder providers(String providers) {
|
||||
this.providers = providers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder jna(boolean jna) {
|
||||
this.jna = jna;
|
||||
return this;
|
||||
@ -170,11 +229,21 @@ public final class TerminalBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder jni(boolean jni) {
|
||||
this.jni = jni;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder exec(boolean exec) {
|
||||
this.exec = exec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder ffm(boolean ffm) {
|
||||
this.ffm = ffm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder dumb(boolean dumb) {
|
||||
this.dumb = dumb;
|
||||
return this;
|
||||
@ -280,6 +349,12 @@ public final class TerminalBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the default value for signal handlers.
|
||||
* All signals will be mapped to the given handler.
|
||||
* @param signalHandler the default signal handler
|
||||
* @return The builder
|
||||
*/
|
||||
public TerminalBuilder signalHandler(Terminal.SignalHandler signalHandler) {
|
||||
this.signalHandler = signalHandler;
|
||||
return this;
|
||||
@ -305,6 +380,11 @@ public final class TerminalBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the terminal.
|
||||
* @return the newly created terminal, never {@code null}
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
public Terminal build() throws IOException {
|
||||
Terminal override = TERMINAL_OVERRIDE.get();
|
||||
Terminal terminal = override != null ? override : doBuild();
|
||||
@ -313,7 +393,8 @@ public final class TerminalBuilder {
|
||||
}
|
||||
Log.debug(() -> "Using terminal " + terminal.getClass().getSimpleName());
|
||||
if (terminal instanceof AbstractPosixTerminal) {
|
||||
Log.debug(() -> "Using pty " + ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName());
|
||||
Log.debug(() -> "Using pty "
|
||||
+ ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName());
|
||||
}
|
||||
return terminal;
|
||||
}
|
||||
@ -323,6 +404,242 @@ public final class TerminalBuilder {
|
||||
if (name == null) {
|
||||
name = "JLine terminal";
|
||||
}
|
||||
Charset encoding = computeEncoding();
|
||||
String type = computeType();
|
||||
|
||||
String provider = this.provider;
|
||||
if (provider == null) {
|
||||
provider = System.getProperty(PROP_PROVIDER, null);
|
||||
}
|
||||
|
||||
boolean forceDumb =
|
||||
(DumbTerminal.TYPE_DUMB.equals(type) || type != null && type.startsWith(DumbTerminal.TYPE_DUMB_COLOR))
|
||||
|| (provider != null && provider.equals(PROP_PROVIDER_DUMB));
|
||||
Boolean dumb = this.dumb;
|
||||
if (dumb == null) {
|
||||
dumb = getBoolean(PROP_DUMB, null);
|
||||
}
|
||||
IllegalStateException exception = new IllegalStateException("Unable to create a terminal");
|
||||
List<TerminalProvider> providers = getProviders(provider, exception);
|
||||
Terminal terminal = null;
|
||||
if ((system != null && system) || (system == null && in == null && out == null)) {
|
||||
if (system != null
|
||||
&& ((in != null && !in.equals(System.in))
|
||||
|| (out != null && !out.equals(System.out) && !out.equals(System.err)))) {
|
||||
throw new IllegalArgumentException("Cannot create a system terminal using non System streams");
|
||||
}
|
||||
if (attributes != null || size != null) {
|
||||
Log.warn("Attributes and size fields are ignored when creating a system terminal");
|
||||
}
|
||||
SystemOutput systemOutput = computeSystemOutput();
|
||||
Map<SystemStream, Boolean> system = Stream.of(SystemStream.values())
|
||||
.collect(Collectors.toMap(
|
||||
stream -> stream, stream -> providers.stream().anyMatch(p -> p.isSystemStream(stream))));
|
||||
SystemStream systemStream = select(system, systemOutput);
|
||||
|
||||
if (!forceDumb && system.get(SystemStream.Input) && systemStream != null) {
|
||||
if (attributes != null || size != null) {
|
||||
Log.warn("Attributes and size fields are ignored when creating a system terminal");
|
||||
}
|
||||
boolean ansiPassThrough = OSUtils.IS_CONEMU;
|
||||
// Cygwin defaults to XTERM, but actually supports 256 colors,
|
||||
// so if the value comes from the environment, change it to xterm-256color
|
||||
if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM)
|
||||
&& "xterm".equals(type)
|
||||
&& this.type == null
|
||||
&& System.getProperty(PROP_TYPE) == null) {
|
||||
type = "xterm-256color";
|
||||
}
|
||||
for (TerminalProvider prov : providers) {
|
||||
if (terminal == null) {
|
||||
try {
|
||||
terminal = prov.sysTerminal(
|
||||
name,
|
||||
type,
|
||||
ansiPassThrough,
|
||||
encoding,
|
||||
nativeSignals,
|
||||
signalHandler,
|
||||
paused,
|
||||
systemStream,
|
||||
inputStreamWrapper);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating " + prov.name() + " based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (terminal == null && OSUtils.IS_WINDOWS && providers.isEmpty() && (dumb == null || !dumb)) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to create a system terminal. On Windows, either JLine's native libraries, JNA "
|
||||
+ "or Jansi library is required. Make sure to add one of those in the classpath.",
|
||||
exception);
|
||||
}
|
||||
}
|
||||
if (terminal instanceof AbstractTerminal) {
|
||||
AbstractTerminal t = (AbstractTerminal) terminal;
|
||||
if (SYSTEM_TERMINAL.compareAndSet(null, t)) {
|
||||
t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null));
|
||||
} else {
|
||||
exception.addSuppressed(new IllegalStateException("A system terminal is already running. "
|
||||
+ "Make sure to use the created system Terminal on the LineReaderBuilder if you're using one "
|
||||
+ "or that previously created system Terminals have been correctly closed."));
|
||||
terminal.close();
|
||||
terminal = null;
|
||||
}
|
||||
}
|
||||
if (terminal == null && (forceDumb || dumb == null || dumb)) {
|
||||
if (!forceDumb && dumb == null) {
|
||||
if (Log.isDebugEnabled()) {
|
||||
Log.warn("input is tty: " + system.get(SystemStream.Input));
|
||||
Log.warn("output is tty: " + system.get(SystemStream.Output));
|
||||
Log.warn("error is tty: " + system.get(SystemStream.Error));
|
||||
Log.warn("Creating a dumb terminal", exception);
|
||||
} else {
|
||||
Log.warn(
|
||||
"Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)");
|
||||
}
|
||||
}
|
||||
type = getDumbTerminalType(dumb, systemStream);
|
||||
terminal = new DumbTerminalProvider()
|
||||
.sysTerminal(name, type, false, encoding, nativeSignals, signalHandler, paused, systemStream, inputStreamWrapper);
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
Attributes attr = terminal.getAttributes();
|
||||
attr.setInputFlag(Attributes.InputFlag.IGNCR, true);
|
||||
terminal.setAttributes(attr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (TerminalProvider prov : providers) {
|
||||
if (terminal == null) {
|
||||
try {
|
||||
terminal = prov.newTerminal(
|
||||
name, type, in, out, encoding, signalHandler, paused, attributes, size);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating " + prov.name() + " based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (terminal == null) {
|
||||
throw exception;
|
||||
}
|
||||
if (terminal instanceof TerminalExt) {
|
||||
TerminalExt te = (TerminalExt) terminal;
|
||||
if (DEPRECATED_PROVIDERS.contains(te.getProvider().name())
|
||||
&& !getBoolean(PROP_DISABLE_DEPRECATED_PROVIDER_WARNING, false)) {
|
||||
Log.warn("The terminal provider " + te.getProvider().name()
|
||||
+ " has been deprecated, check your configuration. This warning can be disabled by setting the system property "
|
||||
+ PROP_DISABLE_DEPRECATED_PROVIDER_WARNING + " to true.");
|
||||
}
|
||||
}
|
||||
return terminal;
|
||||
}
|
||||
|
||||
private String getDumbTerminalType(Boolean dumb, SystemStream systemStream) {
|
||||
// forced colored dumb terminal
|
||||
Boolean color = this.color;
|
||||
if (color == null) {
|
||||
color = getBoolean(PROP_DUMB_COLOR, null);
|
||||
}
|
||||
if (dumb == null) {
|
||||
// detect emacs using the env variable
|
||||
if (color == null) {
|
||||
String emacs = System.getenv("INSIDE_EMACS");
|
||||
if (emacs != null && emacs.contains("comint")) {
|
||||
color = true;
|
||||
}
|
||||
}
|
||||
// detect Intellij Idea
|
||||
if (color == null) {
|
||||
// using the env variable on windows
|
||||
String ideHome = System.getenv("IDE_HOME");
|
||||
if (ideHome != null) {
|
||||
color = true;
|
||||
} else {
|
||||
// using the parent process command on unix/mac
|
||||
String command = getParentProcessCommand();
|
||||
if (command != null && command.endsWith("/idea")) {
|
||||
color = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (color == null) {
|
||||
color = systemStream != null && System.getenv("TERM") != null;
|
||||
}
|
||||
} else {
|
||||
if (color == null) {
|
||||
color = false;
|
||||
}
|
||||
}
|
||||
return color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB;
|
||||
}
|
||||
|
||||
public SystemOutput computeSystemOutput() {
|
||||
SystemOutput systemOutput = null;
|
||||
if (out != null) {
|
||||
if (out.equals(System.out)) {
|
||||
systemOutput = SystemOutput.SysOut;
|
||||
} else if (out.equals(System.err)) {
|
||||
systemOutput = SystemOutput.SysErr;
|
||||
}
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
systemOutput = this.systemOutput;
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
String str = System.getProperty(PROP_OUTPUT);
|
||||
if (str != null) {
|
||||
switch (str.trim().toLowerCase(Locale.ROOT)) {
|
||||
case PROP_OUTPUT_OUT:
|
||||
systemOutput = SystemOutput.SysOut;
|
||||
break;
|
||||
case PROP_OUTPUT_ERR:
|
||||
systemOutput = SystemOutput.SysErr;
|
||||
break;
|
||||
case PROP_OUTPUT_OUT_ERR:
|
||||
systemOutput = SystemOutput.SysOutOrSysErr;
|
||||
break;
|
||||
case PROP_OUTPUT_ERR_OUT:
|
||||
systemOutput = SystemOutput.SysErrOrSysOut;
|
||||
break;
|
||||
case PROP_OUTPUT_FORCED_OUT:
|
||||
systemOutput = SystemOutput.ForcedSysOut;
|
||||
break;
|
||||
case PROP_OUTPUT_FORCED_ERR:
|
||||
systemOutput = SystemOutput.ForcedSysErr;
|
||||
break;
|
||||
default:
|
||||
Log.debug("Unsupported value for " + PROP_OUTPUT + ": " + str + ". Supported values are: "
|
||||
+ String.join(
|
||||
", ",
|
||||
PROP_OUTPUT_OUT,
|
||||
PROP_OUTPUT_ERR,
|
||||
PROP_OUTPUT_OUT_ERR,
|
||||
PROP_OUTPUT_ERR_OUT)
|
||||
+ ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
systemOutput = SystemOutput.SysOutOrSysErr;
|
||||
}
|
||||
return systemOutput;
|
||||
}
|
||||
|
||||
public String computeType() {
|
||||
String type = this.type;
|
||||
if (type == null) {
|
||||
type = System.getProperty(PROP_TYPE);
|
||||
}
|
||||
if (type == null) {
|
||||
type = System.getenv("TERM");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public Charset computeEncoding() {
|
||||
Charset encoding = this.encoding;
|
||||
if (encoding == null) {
|
||||
String charsetName = System.getProperty(PROP_ENCODING);
|
||||
@ -344,206 +661,84 @@ public final class TerminalBuilder {
|
||||
encoding = StandardCharsets.UTF_8;
|
||||
}
|
||||
}
|
||||
String type = this.type;
|
||||
if (type == null) {
|
||||
type = System.getProperty(PROP_TYPE);
|
||||
}
|
||||
if (type == null) {
|
||||
type = System.getenv("TERM");
|
||||
}
|
||||
Boolean jna = this.jna;
|
||||
if (jna == null) {
|
||||
jna = getBoolean(PROP_JNA, true);
|
||||
}
|
||||
Boolean jansi = this.jansi;
|
||||
if (jansi == null) {
|
||||
jansi = getBoolean(PROP_JANSI, true);
|
||||
}
|
||||
Boolean exec = this.exec;
|
||||
if (exec == null) {
|
||||
exec = getBoolean(PROP_EXEC, true);
|
||||
}
|
||||
Boolean dumb = this.dumb;
|
||||
if (dumb == null) {
|
||||
dumb = getBoolean(PROP_DUMB, null);
|
||||
}
|
||||
IllegalStateException exception = new IllegalStateException("Unable to create a terminal");
|
||||
List<TerminalProvider> providers = new ArrayList<>();
|
||||
if (jna) {
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jna");
|
||||
providers.add(provider);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load JNA support: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (jansi) {
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jansi");
|
||||
providers.add(provider);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load JANSI support: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (exec)
|
||||
{
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("exec");
|
||||
providers.add(provider);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load EXEC support: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
|
||||
Terminal terminal = null;
|
||||
if ((system != null && system) || (system == null && in == null && out == null)) {
|
||||
if (system != null && ((in != null && !in.equals(System.in)) ||
|
||||
(out != null && !out.equals(System.out) && !out.equals(System.err)))) {
|
||||
throw new IllegalArgumentException("Cannot create a system terminal using non System streams");
|
||||
}
|
||||
if (attributes != null || size != null) {
|
||||
Log.warn("Attributes and size fields are ignored when creating a system terminal");
|
||||
}
|
||||
if (out != null) {
|
||||
if (out.equals(System.out)) {
|
||||
systemOutput = SystemOutput.SysOut;
|
||||
} else if (out.equals(System.err)) {
|
||||
systemOutput = SystemOutput.SysErr;
|
||||
}
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
String str = System.getProperty(PROP_OUTPUT);
|
||||
if (str != null) {
|
||||
switch (str.trim().toLowerCase(Locale.ROOT)) {
|
||||
case PROP_OUTPUT_OUT: systemOutput = SystemOutput.SysOut; break;
|
||||
case PROP_OUTPUT_ERR: systemOutput = SystemOutput.SysErr; break;
|
||||
case PROP_OUTPUT_OUT_ERR: systemOutput = SystemOutput.SysOutOrSysErr; break;
|
||||
case PROP_OUTPUT_ERR_OUT: systemOutput = SystemOutput.SysErrOrSysOut; break;
|
||||
default:
|
||||
Log.debug("Unsupported value for " + PROP_OUTPUT + ": " + str + ". Supported values are: "
|
||||
+ String.join(", ", PROP_OUTPUT_OUT, PROP_OUTPUT_ERR, PROP_OUTPUT_OUT_ERR,PROP_OUTPUT_ERR_OUT)
|
||||
+ ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
systemOutput = SystemOutput.SysOutOrSysErr;
|
||||
}
|
||||
Map<TerminalProvider.Stream, Boolean> system = Stream.of(TerminalProvider.Stream.values())
|
||||
.collect(Collectors.toMap(stream -> stream, stream -> providers.stream().anyMatch(p -> p.isSystemStream(stream))));
|
||||
TerminalProvider.Stream console = select(system, systemOutput);
|
||||
|
||||
if (system.get(TerminalProvider.Stream.Input) && console != null) {
|
||||
if (attributes != null || size != null) {
|
||||
Log.warn("Attributes and size fields are ignored when creating a system terminal");
|
||||
}
|
||||
boolean ansiPassThrough = OSUtils.IS_CONEMU;
|
||||
// Cygwin defaults to XTERM, but actually supports 256 colors,
|
||||
// so if the value comes from the environment, change it to xterm-256color
|
||||
if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) && "xterm".equals(type)
|
||||
&& this.type == null && System.getProperty(PROP_TYPE) == null) {
|
||||
type = "xterm-256color";
|
||||
}
|
||||
for ( TerminalProvider provider : providers) {
|
||||
if (terminal == null) {
|
||||
try {
|
||||
terminal = provider.sysTerminal(name, type, ansiPassThrough, encoding,
|
||||
nativeSignals, signalHandler, paused, console, inputStreamWrapper);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (terminal == null && OSUtils.IS_WINDOWS && !jna && !jansi && (dumb == null || !dumb)) {
|
||||
throw new IllegalStateException("Unable to create a system terminal. On windows, either "
|
||||
+ "JNA or JANSI library is required. Make sure to add one of those in the classpath.");
|
||||
}
|
||||
}
|
||||
if (terminal instanceof AbstractTerminal) {
|
||||
AbstractTerminal t = (AbstractTerminal) terminal;
|
||||
if (SYSTEM_TERMINAL.compareAndSet(null, t)) {
|
||||
t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null));
|
||||
} else {
|
||||
exception.addSuppressed(new IllegalStateException("A system terminal is already running. " +
|
||||
"Make sure to use the created system Terminal on the LineReaderBuilder if you're using one " +
|
||||
"or that previously created system Terminals have been correctly closed."));
|
||||
terminal.close();
|
||||
terminal = null;
|
||||
}
|
||||
}
|
||||
if (terminal == null && (dumb == null || dumb)) {
|
||||
// forced colored dumb terminal
|
||||
Boolean color = this.color;
|
||||
if (color == null) {
|
||||
color = getBoolean(PROP_DUMB_COLOR, false);
|
||||
// detect emacs using the env variable
|
||||
if (!color) {
|
||||
String emacs = System.getenv("INSIDE_EMACS");
|
||||
color = emacs != null && emacs.contains("comint");
|
||||
}
|
||||
// detect Intellij Idea
|
||||
if (!color) {
|
||||
String command = getParentProcessCommand();
|
||||
color = command != null && command.contains("idea");
|
||||
}
|
||||
if (!color) {
|
||||
color = system.get(TerminalProvider.Stream.Output) && System.getenv("TERM") != null;
|
||||
}
|
||||
if (!color && dumb == null) {
|
||||
if (Log.isDebugEnabled()) {
|
||||
Log.warn("input is tty: {}", system.get(TerminalProvider.Stream.Input));
|
||||
Log.warn("output is tty: {}", system.get(TerminalProvider.Stream.Output));
|
||||
Log.warn("error is tty: {}", system.get(TerminalProvider.Stream.Error));
|
||||
Log.warn("Creating a dumb terminal", exception);
|
||||
} else {
|
||||
Log.warn("Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)");
|
||||
}
|
||||
}
|
||||
}
|
||||
terminal = new DumbTerminal(name, color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB,
|
||||
new FileInputStream(FileDescriptor.in),
|
||||
//JDK change: always write into stdout:
|
||||
new FileOutputStream(FileDescriptor.out),
|
||||
encoding, signalHandler);
|
||||
}
|
||||
} else {
|
||||
for ( TerminalProvider provider : providers) {
|
||||
if (terminal == null) {
|
||||
try {
|
||||
terminal = provider.newTerminal(name, type, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused, attributes, size);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (terminal == null) {
|
||||
throw exception;
|
||||
}
|
||||
return terminal;
|
||||
return encoding;
|
||||
}
|
||||
|
||||
private TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, SystemOutput systemOutput) {
|
||||
/**
|
||||
* Get the list of available terminal providers.
|
||||
* This list is sorted according to the {@link #PROP_PROVIDERS} system property.
|
||||
* @param provider if not {@code null}, only this provider will be checked
|
||||
* @param exception if a provider throws an exception, it will be added to this exception as a suppressed exception
|
||||
* @return a list of terminal providers
|
||||
*/
|
||||
public List<TerminalProvider> getProviders(String provider, IllegalStateException exception) {
|
||||
List<TerminalProvider> providers = new ArrayList<>();
|
||||
// Check ffm provider
|
||||
checkProvider(provider, exception, providers, ffm, PROP_FFM, PROP_PROVIDER_FFM);
|
||||
// Check jni provider
|
||||
checkProvider(provider, exception, providers, jni, PROP_JNI, PROP_PROVIDER_JNI);
|
||||
// Check jansi provider
|
||||
checkProvider(provider, exception, providers, jansi, PROP_JANSI, PROP_PROVIDER_JANSI);
|
||||
// Check jna provider
|
||||
checkProvider(provider, exception, providers, jna, PROP_JNA, PROP_PROVIDER_JNA);
|
||||
// Check exec provider
|
||||
checkProvider(provider, exception, providers, exec, PROP_EXEC, PROP_PROVIDER_EXEC);
|
||||
// Order providers
|
||||
List<String> order = Arrays.asList(
|
||||
(this.providers != null ? this.providers : System.getProperty(PROP_PROVIDERS, PROP_PROVIDERS_DEFAULT))
|
||||
.split(","));
|
||||
providers.sort(Comparator.comparing(l -> {
|
||||
int idx = order.indexOf(l.name());
|
||||
return idx >= 0 ? idx : Integer.MAX_VALUE;
|
||||
}));
|
||||
String names = providers.stream().map(TerminalProvider::name).collect(Collectors.joining(", "));
|
||||
Log.debug("Available providers: " + names);
|
||||
return providers;
|
||||
}
|
||||
|
||||
private void checkProvider(
|
||||
String provider,
|
||||
IllegalStateException exception,
|
||||
List<TerminalProvider> providers,
|
||||
Boolean load,
|
||||
String property,
|
||||
String name) {
|
||||
Boolean doLoad = provider != null ? (Boolean) name.equals(provider) : load;
|
||||
if (doLoad == null) {
|
||||
doLoad = getBoolean(property, true);
|
||||
}
|
||||
if (doLoad) {
|
||||
try {
|
||||
TerminalProvider prov = TerminalProvider.load(name);
|
||||
prov.isSystemStream(SystemStream.Output);
|
||||
providers.add(prov);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load " + name + " provider: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SystemStream select(Map<SystemStream, Boolean> system, SystemOutput systemOutput) {
|
||||
switch (systemOutput) {
|
||||
case SysOut:
|
||||
return select(system, TerminalProvider.Stream.Output);
|
||||
return select(system, SystemStream.Output);
|
||||
case SysErr:
|
||||
return select(system, TerminalProvider.Stream.Error);
|
||||
return select(system, SystemStream.Error);
|
||||
case SysOutOrSysErr:
|
||||
return select(system, TerminalProvider.Stream.Output, TerminalProvider.Stream.Error);
|
||||
return select(system, SystemStream.Output, SystemStream.Error);
|
||||
case SysErrOrSysOut:
|
||||
return select(system, TerminalProvider.Stream.Error, TerminalProvider.Stream.Output);
|
||||
return select(system, SystemStream.Error, SystemStream.Output);
|
||||
case ForcedSysOut:
|
||||
return SystemStream.Output;
|
||||
case ForcedSysErr:
|
||||
return SystemStream.Error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, TerminalProvider.Stream... streams) {
|
||||
for (TerminalProvider.Stream s : streams) {
|
||||
private static SystemStream select(Map<SystemStream, Boolean> system, SystemStream... streams) {
|
||||
for (SystemStream s : streams) {
|
||||
if (system.get(s)) {
|
||||
return s;
|
||||
}
|
||||
@ -558,7 +753,9 @@ public final class TerminalBuilder {
|
||||
Object parent = ((Optional<?>) phClass.getMethod("parent").invoke(current)).orElse(null);
|
||||
Method infoMethod = phClass.getMethod("info");
|
||||
Object info = infoMethod.invoke(parent);
|
||||
Object command = ((Optional<?>) infoMethod.getReturnType().getMethod("command").invoke(info)).orElse(null);
|
||||
Object command = ((Optional<?>)
|
||||
infoMethod.getReturnType().getMethod("command").invoke(info))
|
||||
.orElse(null);
|
||||
return (String) command;
|
||||
} catch (Throwable t) {
|
||||
return null;
|
||||
@ -583,7 +780,7 @@ public final class TerminalBuilder {
|
||||
private static final int UTF8_CODE_PAGE = 65001;
|
||||
|
||||
private static Charset getCodepageCharset(int codepage) {
|
||||
//http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
|
||||
// http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
|
||||
if (codepage == UTF8_CODE_PAGE) {
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
@ -630,5 +827,4 @@ public final class TerminalBuilder {
|
||||
public static void setTerminalOverride(final Terminal terminal) {
|
||||
TERMINAL_OVERRIDE.set(terminal);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -18,6 +18,8 @@ import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
|
||||
public abstract class AbstractPosixTerminal extends AbstractTerminal {
|
||||
|
||||
@ -28,7 +30,8 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
|
||||
this(name, type, pty, null, SignalHandler.SIG_DFL);
|
||||
}
|
||||
|
||||
public AbstractPosixTerminal(String name, String type, Pty pty, Charset encoding, SignalHandler signalHandler) throws IOException {
|
||||
public AbstractPosixTerminal(String name, String type, Pty pty, Charset encoding, SignalHandler signalHandler)
|
||||
throws IOException {
|
||||
super(name, type, encoding, signalHandler);
|
||||
Objects.requireNonNull(pty);
|
||||
this.pty = pty;
|
||||
@ -82,4 +85,13 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
|
||||
return CursorSupport.getCursorPosition(this, discarded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminalProvider getProvider() {
|
||||
return getPty().getProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemStream getSystemStream() {
|
||||
return getPty().getSystemStream();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2019, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,20 +8,39 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal.impl;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.utils.NonBlockingInputStream;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
//import jdk.internal.org.jline.nativ.JLineLibrary;
|
||||
//import jdk.internal.org.jline.nativ.JLineNativeLoader;
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.NonBlockingInputStream;
|
||||
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_NON_BLOCKING_READS;
|
||||
|
||||
public abstract class AbstractPty implements Pty {
|
||||
|
||||
protected final TerminalProvider provider;
|
||||
protected final SystemStream systemStream;
|
||||
private Attributes current;
|
||||
private boolean skipNextLf;
|
||||
|
||||
public AbstractPty(TerminalProvider provider, SystemStream systemStream) {
|
||||
this.provider = provider;
|
||||
this.systemStream = systemStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttr(Attributes attr) throws IOException {
|
||||
@ -32,10 +51,32 @@ public abstract class AbstractPty implements Pty {
|
||||
@Override
|
||||
public InputStream getSlaveInput() throws IOException {
|
||||
InputStream si = doGetSlaveInput();
|
||||
InputStream nsi = new FilterInputStream(si) {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
for (; ; ) {
|
||||
int c = super.read();
|
||||
if (current.getInputFlag(Attributes.InputFlag.INORMEOL)) {
|
||||
if (c == '\r') {
|
||||
skipNextLf = true;
|
||||
c = '\n';
|
||||
} else if (c == '\n') {
|
||||
if (skipNextLf) {
|
||||
skipNextLf = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
skipNextLf = false;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Boolean.parseBoolean(System.getProperty(PROP_NON_BLOCKING_READS, "true"))) {
|
||||
return new PtyInputStream(si);
|
||||
return new PtyInputStream(nsi);
|
||||
} else {
|
||||
return si;
|
||||
return nsi;
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +90,16 @@ public abstract class AbstractPty implements Pty {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminalProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemStream getSystemStream() {
|
||||
return systemStream;
|
||||
}
|
||||
|
||||
class PtyInputStream extends NonBlockingInputStream {
|
||||
final InputStream in;
|
||||
int c = 0;
|
||||
@ -102,4 +153,103 @@ public abstract class AbstractPty implements Pty {
|
||||
}
|
||||
}
|
||||
|
||||
private static FileDescriptorCreator fileDescriptorCreator;
|
||||
|
||||
protected static FileDescriptor newDescriptor(int fd) {
|
||||
if (fileDescriptorCreator == null) {
|
||||
String str =
|
||||
System.getProperty(PROP_FILE_DESCRIPTOR_CREATION_MODE, PROP_FILE_DESCRIPTOR_CREATION_MODE_DEFAULT);
|
||||
String[] modes = str.split(",");
|
||||
IllegalStateException ise = new IllegalStateException("Unable to create FileDescriptor");
|
||||
for (String mode : modes) {
|
||||
try {
|
||||
switch (mode) {
|
||||
case PROP_FILE_DESCRIPTOR_CREATION_MODE_NATIVE:
|
||||
fileDescriptorCreator = null;//new NativeFileDescriptorCreator();
|
||||
break;
|
||||
case PROP_FILE_DESCRIPTOR_CREATION_MODE_REFLECTION:
|
||||
fileDescriptorCreator = new ReflectionFileDescriptorCreator();
|
||||
break;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
ise.addSuppressed(t);
|
||||
}
|
||||
if (fileDescriptorCreator != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fileDescriptorCreator == null) {
|
||||
throw ise;
|
||||
}
|
||||
}
|
||||
return fileDescriptorCreator.newDescriptor(fd);
|
||||
}
|
||||
|
||||
interface FileDescriptorCreator {
|
||||
FileDescriptor newDescriptor(int fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class that could be used on OpenJDK 17. However, it requires the following JVM option
|
||||
* --add-exports java.base/jdk.internal.access=ALL-UNNAMED
|
||||
* so the benefit does not seem important enough to warrant the problems caused
|
||||
* by access the jdk.internal.access package at compile time, which itself requires
|
||||
* custom compiler options and a different maven module, or at least a different compile
|
||||
* phase with a JDK 17 compiler.
|
||||
* So, just keep the ReflectionFileDescriptorCreator for now.
|
||||
*
|
||||
static class Jdk17FileDescriptorCreator implements FileDescriptorCreator {
|
||||
private final jdk.internal.access.JavaIOFileDescriptorAccess fdAccess;
|
||||
Jdk17FileDescriptorCreator() {
|
||||
fdAccess = jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileDescriptor newDescriptor(int fd) {
|
||||
FileDescriptor descriptor = new FileDescriptor();
|
||||
fdAccess.set(descriptor, fd);
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reflection based file descriptor creator.
|
||||
* This requires the following option
|
||||
* --add-opens java.base/java.io=ALL-UNNAMED
|
||||
*/
|
||||
static class ReflectionFileDescriptorCreator implements FileDescriptorCreator {
|
||||
private final Field fileDescriptorField;
|
||||
|
||||
ReflectionFileDescriptorCreator() throws Exception {
|
||||
Field field = FileDescriptor.class.getDeclaredField("fd");
|
||||
field.setAccessible(true);
|
||||
fileDescriptorField = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileDescriptor newDescriptor(int fd) {
|
||||
FileDescriptor descriptor = new FileDescriptor();
|
||||
try {
|
||||
fileDescriptorField.set(descriptor, fd);
|
||||
} catch (IllegalAccessException e) {
|
||||
// This should not happen as the field has been set accessible
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
// static class NativeFileDescriptorCreator implements FileDescriptorCreator {
|
||||
// NativeFileDescriptorCreator() {
|
||||
// // Force load the library
|
||||
// JLineNativeLoader.initialize();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public FileDescriptor newDescriptor(int fd) {
|
||||
// return JLineLibrary.newFileDescriptor(fd);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -27,7 +27,7 @@ import jdk.internal.org.jline.terminal.Attributes.InputFlag;
|
||||
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.MouseEvent;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalExt;
|
||||
import jdk.internal.org.jline.utils.ColorPalette;
|
||||
import jdk.internal.org.jline.utils.Curses;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
@ -35,7 +35,7 @@ import jdk.internal.org.jline.utils.InfoCmp.Capability;
|
||||
import jdk.internal.org.jline.utils.Log;
|
||||
import jdk.internal.org.jline.utils.Status;
|
||||
|
||||
public abstract class AbstractTerminal implements Terminal {
|
||||
public abstract class AbstractTerminal implements TerminalExt {
|
||||
|
||||
protected final String name;
|
||||
protected final String type;
|
||||
@ -44,7 +44,7 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
protected final Set<Capability> bools = new HashSet<>();
|
||||
protected final Map<Capability, Integer> ints = new HashMap<>();
|
||||
protected final Map<Capability, String> strings = new HashMap<>();
|
||||
protected final ColorPalette palette = new ColorPalette(this);
|
||||
protected final ColorPalette palette;
|
||||
protected Status status;
|
||||
protected Runnable onClose;
|
||||
|
||||
@ -52,10 +52,13 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
this(name, type, null, SignalHandler.SIG_DFL);
|
||||
}
|
||||
|
||||
public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler)
|
||||
throws IOException {
|
||||
this.name = name;
|
||||
this.type = type != null ? type : "ansi";
|
||||
this.encoding = encoding != null ? encoding : System.out.charset();
|
||||
this.palette = new ColorPalette(this);
|
||||
for (Signal signal : Signal.values()) {
|
||||
handlers.put(signal, signalHandler);
|
||||
}
|
||||
@ -85,12 +88,13 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
public void raise(Signal signal) {
|
||||
Objects.requireNonNull(signal);
|
||||
SignalHandler handler = handlers.get(signal);
|
||||
if (handler != SignalHandler.SIG_DFL && handler != SignalHandler.SIG_IGN) {
|
||||
if (handler == SignalHandler.SIG_DFL) {
|
||||
if (status != null && signal == Signal.WINCH) {
|
||||
status.resize();
|
||||
}
|
||||
} else if (handler != SignalHandler.SIG_IGN) {
|
||||
handler.handle(signal);
|
||||
}
|
||||
if (status != null && signal == Signal.WINCH) {
|
||||
status.resize();
|
||||
}
|
||||
}
|
||||
|
||||
public final void close() throws IOException {
|
||||
@ -105,8 +109,7 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
|
||||
protected void doClose() throws IOException {
|
||||
if (status != null) {
|
||||
status.update(null);
|
||||
flush();
|
||||
status.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +129,7 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
if (cc != null) {
|
||||
int vcc = getAttributes().getControlChar(cc);
|
||||
if (vcc > 0 && vcc < 32) {
|
||||
writer().write(new char[]{'^', (char) (vcc + '@')}, 0, 2);
|
||||
writer().write(new char[] {'^', (char) (vcc + '@')}, 0, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,8 +220,7 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
}
|
||||
|
||||
private MouseEvent lastMouseEvent = new MouseEvent(
|
||||
MouseEvent.Type.Moved, MouseEvent.Button.NoButton,
|
||||
EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
|
||||
MouseEvent.Type.Moved, MouseEvent.Button.NoButton, EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
|
||||
|
||||
@Override
|
||||
public boolean hasMouseSupport() {
|
||||
@ -268,16 +270,13 @@ public abstract class AbstractTerminal implements Terminal {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
}
|
||||
public void pause() {}
|
||||
|
||||
@Override
|
||||
public void pause(boolean wait) throws InterruptedException {
|
||||
}
|
||||
public void pause(boolean wait) throws InterruptedException {}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
}
|
||||
public void resume() {}
|
||||
|
||||
@Override
|
||||
public boolean paused() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2017, the original author or authors.
|
||||
* Copyright (c) 2002-2017, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -29,11 +29,8 @@ public abstract class AbstractWindowsConsoleWriter extends Writer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
public void flush() {}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void close() {}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2023, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,8 +8,20 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.Curses;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
import jdk.internal.org.jline.utils.Log;
|
||||
@ -21,17 +33,6 @@ import jdk.internal.org.jline.utils.ShutdownHooks;
|
||||
import jdk.internal.org.jline.utils.Signals;
|
||||
import jdk.internal.org.jline.utils.WriterOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The AbstractWindowsTerminal is used as the base class for windows terminal.
|
||||
* Due to windows limitations, mostly the missing support for ansi sequences,
|
||||
@ -44,7 +45,7 @@ import java.util.function.Function;
|
||||
* the writer() becomes the primary output, while the output() is bridged
|
||||
* to the writer() using a WriterOutputStream wrapper.
|
||||
*/
|
||||
public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
public abstract class AbstractWindowsTerminal<Console> extends AbstractTerminal {
|
||||
|
||||
public static final String TYPE_WINDOWS = "windows";
|
||||
public static final String TYPE_WINDOWS_256_COLOR = "windows-256color";
|
||||
@ -56,12 +57,13 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
private static final int UTF8_CODE_PAGE = 65001;
|
||||
|
||||
protected static final int ENABLE_PROCESSED_INPUT = 0x0001;
|
||||
protected static final int ENABLE_LINE_INPUT = 0x0002;
|
||||
protected static final int ENABLE_ECHO_INPUT = 0x0004;
|
||||
protected static final int ENABLE_WINDOW_INPUT = 0x0008;
|
||||
protected static final int ENABLE_MOUSE_INPUT = 0x0010;
|
||||
protected static final int ENABLE_INSERT_MODE = 0x0020;
|
||||
protected static final int ENABLE_LINE_INPUT = 0x0002;
|
||||
protected static final int ENABLE_ECHO_INPUT = 0x0004;
|
||||
protected static final int ENABLE_WINDOW_INPUT = 0x0008;
|
||||
protected static final int ENABLE_MOUSE_INPUT = 0x0010;
|
||||
protected static final int ENABLE_INSERT_MODE = 0x0020;
|
||||
protected static final int ENABLE_QUICK_EDIT_MODE = 0x0040;
|
||||
protected static final int ENABLE_EXTENDED_FLAGS = 0x0080;
|
||||
|
||||
protected final Writer slaveInputPipe;
|
||||
protected final InputStream input;
|
||||
@ -71,7 +73,12 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
|
||||
protected final ShutdownHooks.Task closer;
|
||||
protected final Attributes attributes = new Attributes();
|
||||
protected final int originalConsoleMode;
|
||||
protected final Console inConsole;
|
||||
protected final Console outConsole;
|
||||
protected final int originalInConsoleMode;
|
||||
protected final int originalOutConsoleMode;
|
||||
private final TerminalProvider provider;
|
||||
private final SystemStream systemStream;
|
||||
|
||||
protected final Object lock = new Object();
|
||||
protected boolean paused = true;
|
||||
@ -80,21 +87,42 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
protected MouseTracking tracking = MouseTracking.Off;
|
||||
protected boolean focusTracking = false;
|
||||
private volatile boolean closing;
|
||||
protected boolean skipNextLf;
|
||||
|
||||
public AbstractWindowsTerminal(Writer writer, String name, String type, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public AbstractWindowsTerminal(
|
||||
TerminalProvider provider,
|
||||
SystemStream systemStream,
|
||||
Writer writer,
|
||||
String name,
|
||||
String type,
|
||||
Charset encoding,
|
||||
boolean nativeSignals,
|
||||
SignalHandler signalHandler,
|
||||
Console inConsole,
|
||||
int inConsoleMode,
|
||||
Console outConsole,
|
||||
int outConsoleMode,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
super(name, type, encoding, signalHandler);
|
||||
this.provider = provider;
|
||||
this.systemStream = systemStream;
|
||||
NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader();
|
||||
this.slaveInputPipe = reader.getWriter();
|
||||
this.input = inputStreamWrapper.apply(NonBlocking.nonBlockingStream(reader, encoding()));
|
||||
this.reader = NonBlocking.nonBlocking(name, input, encoding());
|
||||
this.writer = new PrintWriter(writer);
|
||||
this.output = new WriterOutputStream(writer, encoding());
|
||||
this.inConsole = inConsole;
|
||||
this.outConsole = outConsole;
|
||||
parseInfoCmp();
|
||||
// Attributes
|
||||
originalConsoleMode = getConsoleMode();
|
||||
this.originalInConsoleMode = inConsoleMode;
|
||||
this.originalOutConsoleMode = outConsoleMode;
|
||||
attributes.setLocalFlag(Attributes.LocalFlag.ISIG, true);
|
||||
attributes.setControlChar(Attributes.ControlChar.VINTR, ctrl('C'));
|
||||
attributes.setControlChar(Attributes.ControlChar.VEOF, ctrl('D'));
|
||||
attributes.setControlChar(Attributes.ControlChar.VEOF, ctrl('D'));
|
||||
attributes.setControlChar(Attributes.ControlChar.VSUSP, ctrl('Z'));
|
||||
// Handle signals
|
||||
if (nativeSignals) {
|
||||
@ -148,7 +176,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
}
|
||||
|
||||
public Attributes getAttributes() {
|
||||
int mode = getConsoleMode();
|
||||
int mode = getConsoleMode(inConsole);
|
||||
if ((mode & ENABLE_ECHO_INPUT) != 0) {
|
||||
attributes.setLocalFlag(Attributes.LocalFlag.ECHO, true);
|
||||
}
|
||||
@ -173,8 +201,11 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
}
|
||||
if (tracking != MouseTracking.Off) {
|
||||
mode |= ENABLE_MOUSE_INPUT;
|
||||
// mouse events not send with quick edit mode
|
||||
// to disable ENABLE_QUICK_EDIT_MODE just set extended flag
|
||||
mode |= ENABLE_EXTENDED_FLAGS;
|
||||
}
|
||||
setConsoleMode(mode);
|
||||
setConsoleMode(inConsole, mode);
|
||||
}
|
||||
|
||||
protected int ctrl(char key) {
|
||||
@ -197,23 +228,26 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
}
|
||||
reader.close();
|
||||
writer.close();
|
||||
setConsoleMode(originalConsoleMode);
|
||||
setConsoleMode(inConsole, originalInConsoleMode);
|
||||
setConsoleMode(outConsole, originalOutConsoleMode);
|
||||
}
|
||||
|
||||
static final int SHIFT_FLAG = 0x01;
|
||||
static final int ALT_FLAG = 0x02;
|
||||
static final int CTRL_FLAG = 0x04;
|
||||
static final int ALT_FLAG = 0x02;
|
||||
static final int CTRL_FLAG = 0x04;
|
||||
|
||||
static final int RIGHT_ALT_PRESSED = 0x0001;
|
||||
static final int LEFT_ALT_PRESSED = 0x0002;
|
||||
static final int RIGHT_CTRL_PRESSED = 0x0004;
|
||||
static final int LEFT_CTRL_PRESSED = 0x0008;
|
||||
static final int SHIFT_PRESSED = 0x0010;
|
||||
static final int NUMLOCK_ON = 0x0020;
|
||||
static final int SCROLLLOCK_ON = 0x0040;
|
||||
static final int CAPSLOCK_ON = 0x0080;
|
||||
static final int RIGHT_ALT_PRESSED = 0x0001;
|
||||
static final int LEFT_ALT_PRESSED = 0x0002;
|
||||
static final int RIGHT_CTRL_PRESSED = 0x0004;
|
||||
static final int LEFT_CTRL_PRESSED = 0x0008;
|
||||
static final int SHIFT_PRESSED = 0x0010;
|
||||
static final int NUMLOCK_ON = 0x0020;
|
||||
static final int SCROLLLOCK_ON = 0x0040;
|
||||
static final int CAPSLOCK_ON = 0x0080;
|
||||
|
||||
protected void processKeyEvent(final boolean isKeyDown, final short virtualKeyCode, char ch, final int controlKeyState) throws IOException {
|
||||
protected void processKeyEvent(
|
||||
final boolean isKeyDown, final short virtualKeyCode, char ch, final int controlKeyState)
|
||||
throws IOException {
|
||||
final boolean isCtrl = (controlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) > 0;
|
||||
final boolean isAlt = (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) > 0;
|
||||
final boolean isShift = (controlKeyState & SHIFT_PRESSED) > 0;
|
||||
@ -222,11 +256,13 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
// Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
|
||||
// otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
|
||||
if (ch != 0
|
||||
&& (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED | SHIFT_PRESSED))
|
||||
== (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
|
||||
&& (controlKeyState
|
||||
& (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
|
||||
== (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
|
||||
processInputChar(ch);
|
||||
} else {
|
||||
final String keySeq = getEscapeSequence(virtualKeyCode, (isCtrl ? CTRL_FLAG : 0) + (isAlt ? ALT_FLAG : 0) + (isShift ? SHIFT_FLAG : 0));
|
||||
final String keySeq = getEscapeSequence(
|
||||
virtualKeyCode, (isCtrl ? CTRL_FLAG : 0) + (isAlt ? ALT_FLAG : 0) + (isShift ? SHIFT_FLAG : 0));
|
||||
if (keySeq != null) {
|
||||
for (char c : keySeq.toCharArray()) {
|
||||
processInputChar(c);
|
||||
@ -240,7 +276,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
* 4). Ctrl + Space(0x20) : uchar=0x20
|
||||
* 5). Ctrl + <Other key> : uchar=0
|
||||
* 6). Ctrl + Alt + <Any key> : uchar=0
|
||||
*/
|
||||
*/
|
||||
if (ch > 0) {
|
||||
if (isAlt) {
|
||||
processInputChar('\033');
|
||||
@ -254,10 +290,10 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
} else {
|
||||
processInputChar(ch);
|
||||
}
|
||||
} else if (isCtrl) { //Handles the ctrl key events(uchar=0)
|
||||
} else if (isCtrl) { // Handles the ctrl key events(uchar=0)
|
||||
if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') {
|
||||
ch = (char) (virtualKeyCode - 0x40);
|
||||
} else if (virtualKeyCode == 191) { //?
|
||||
} else if (virtualKeyCode == 191) { // ?
|
||||
ch = 127;
|
||||
}
|
||||
if (ch > 0) {
|
||||
@ -275,7 +311,7 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
else {
|
||||
// support ALT+NumPad input method
|
||||
if (virtualKeyCode == 0x12 /*VK_MENU ALT key*/ && ch > 0) {
|
||||
processInputChar(ch); // no such combination in Windows
|
||||
processInputChar(ch); // no such combination in Windows
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -468,7 +504,19 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
raise(Signal.INFO);
|
||||
}
|
||||
}
|
||||
if (c == '\r') {
|
||||
if (attributes.getInputFlag(Attributes.InputFlag.INORMEOL)) {
|
||||
if (c == '\r') {
|
||||
skipNextLf = true;
|
||||
c = '\n';
|
||||
} else if (c == '\n') {
|
||||
if (skipNextLf) {
|
||||
skipNextLf = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
skipNextLf = false;
|
||||
}
|
||||
} else if (c == '\r') {
|
||||
if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
|
||||
return;
|
||||
}
|
||||
@ -478,10 +526,10 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
} else if (c == '\n' && attributes.getInputFlag(Attributes.InputFlag.INLCR)) {
|
||||
c = '\r';
|
||||
}
|
||||
// if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
|
||||
// processOutputByte(c);
|
||||
// masterOutput.flush();
|
||||
// }
|
||||
// if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
|
||||
// processOutputByte(c);
|
||||
// masterOutput.flush();
|
||||
// }
|
||||
slaveInputPipe.write(c);
|
||||
}
|
||||
|
||||
@ -492,9 +540,9 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract int getConsoleMode();
|
||||
protected abstract int getConsoleMode(Console console);
|
||||
|
||||
protected abstract void setConsoleMode(int mode);
|
||||
protected abstract void setConsoleMode(Console console, int mode);
|
||||
|
||||
/**
|
||||
* Read a single input event from the input buffer and process it.
|
||||
@ -504,5 +552,13 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
*/
|
||||
protected abstract boolean processConsoleInput() throws IOException;
|
||||
|
||||
}
|
||||
@Override
|
||||
public TerminalProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemStream getSystemStream() {
|
||||
return systemStream;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,17 +8,17 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal.impl;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.utils.Curses;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.utils.Curses;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
|
||||
public class CursorSupport {
|
||||
|
||||
public static Cursor getCursorPosition(Terminal terminal, IntConsumer discarded) {
|
||||
@ -105,5 +105,4 @@ public class CursorSupport {
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, the original author or authors.
|
||||
* Copyright (c) 2022, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -17,6 +17,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
@ -26,7 +27,7 @@ public class Diag {
|
||||
diag(System.out);
|
||||
}
|
||||
|
||||
static void diag(PrintStream out) {
|
||||
public static void diag(PrintStream out) {
|
||||
out.println("System properties");
|
||||
out.println("=================");
|
||||
out.println("os.name = " + System.getProperty("os.name"));
|
||||
@ -50,6 +51,17 @@ public class Diag {
|
||||
out.println("IS_OSX = " + OSUtils.IS_OSX);
|
||||
out.println();
|
||||
|
||||
// FFM
|
||||
out.println("FFM Support");
|
||||
out.println("=================");
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("ffm");
|
||||
testProvider(out, provider);
|
||||
} catch (Throwable t) {
|
||||
out.println("FFM support not available: " + t);
|
||||
}
|
||||
out.println();
|
||||
|
||||
out.println("JnaSupport");
|
||||
out.println("=================");
|
||||
try {
|
||||
@ -60,13 +72,23 @@ public class Diag {
|
||||
}
|
||||
out.println();
|
||||
|
||||
out.println("JansiSupport");
|
||||
out.println("Jansi2Support");
|
||||
out.println("=================");
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jansi");
|
||||
testProvider(out, provider);
|
||||
} catch (Throwable t) {
|
||||
out.println("Jansi support not available: " + t);
|
||||
out.println("Jansi 2 support not available: " + t);
|
||||
}
|
||||
out.println();
|
||||
|
||||
out.println("JniSupport");
|
||||
out.println("=================");
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jni");
|
||||
testProvider(out, provider);
|
||||
} catch (Throwable t) {
|
||||
out.println("JNI support not available: " + t);
|
||||
}
|
||||
out.println();
|
||||
|
||||
@ -83,32 +105,45 @@ public class Diag {
|
||||
|
||||
private static void testProvider(PrintStream out, TerminalProvider provider) {
|
||||
try {
|
||||
out.println("StdIn stream = " + provider.isSystemStream(TerminalProvider.Stream.Input));
|
||||
out.println("StdOut stream = " + provider.isSystemStream(TerminalProvider.Stream.Output));
|
||||
out.println("StdErr stream = " + provider.isSystemStream(TerminalProvider.Stream.Error));
|
||||
out.println("StdIn stream = " + provider.isSystemStream(SystemStream.Input));
|
||||
out.println("StdOut stream = " + provider.isSystemStream(SystemStream.Output));
|
||||
out.println("StdErr stream = " + provider.isSystemStream(SystemStream.Error));
|
||||
} catch (Throwable t2) {
|
||||
out.println("Unable to check stream: " + t2);
|
||||
}
|
||||
try {
|
||||
out.println("StdIn stream name = " + provider.systemStreamName(TerminalProvider.Stream.Input));
|
||||
out.println("StdOut stream name = " + provider.systemStreamName(TerminalProvider.Stream.Output));
|
||||
out.println("StdErr stream name = " + provider.systemStreamName(TerminalProvider.Stream.Error));
|
||||
out.println("StdIn stream name = " + provider.systemStreamName(SystemStream.Input));
|
||||
out.println("StdOut stream name = " + provider.systemStreamName(SystemStream.Output));
|
||||
out.println("StdErr stream name = " + provider.systemStreamName(SystemStream.Error));
|
||||
} catch (Throwable t2) {
|
||||
out.println("Unable to check stream names: " + t2);
|
||||
}
|
||||
try (Terminal terminal = provider.sysTerminal("diag", "xterm", false, StandardCharsets.UTF_8,
|
||||
false, Terminal.SignalHandler.SIG_DFL, false, TerminalProvider.Stream.Output, input -> input) ) {
|
||||
try (Terminal terminal = provider.sysTerminal(
|
||||
"diag",
|
||||
"xterm",
|
||||
false,
|
||||
StandardCharsets.UTF_8,
|
||||
false,
|
||||
Terminal.SignalHandler.SIG_DFL,
|
||||
false,
|
||||
SystemStream.Output,
|
||||
input -> input)) {
|
||||
if (terminal != null) {
|
||||
Attributes attr = terminal.enterRawMode();
|
||||
try {
|
||||
out.println("Terminal size: " + terminal.getSize());
|
||||
ForkJoinTask<Integer> t = new ForkJoinPool(1).submit(() -> terminal.reader().read(1) );
|
||||
ForkJoinTask<Integer> t =
|
||||
new ForkJoinPool(1).submit(() -> terminal.reader().read(1));
|
||||
int r = t.get(1000, TimeUnit.MILLISECONDS);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("The terminal seems to work: ");
|
||||
sb.append("terminal ").append(terminal.getClass().getName());
|
||||
if (terminal instanceof AbstractPosixTerminal) {
|
||||
sb.append(" with pty ").append(((AbstractPosixTerminal) terminal).getPty().getClass().getName());
|
||||
sb.append(" with pty ")
|
||||
.append(((AbstractPosixTerminal) terminal)
|
||||
.getPty()
|
||||
.getClass()
|
||||
.getName());
|
||||
}
|
||||
out.println(sb);
|
||||
} catch (Throwable t3) {
|
||||
@ -129,5 +164,4 @@ public class Diag {
|
||||
static <S> S load(Class<S> clazz) {
|
||||
return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -14,38 +14,58 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Attributes.ControlChar;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.NonBlocking;
|
||||
import jdk.internal.org.jline.utils.NonBlockingInputStream;
|
||||
import jdk.internal.org.jline.utils.NonBlockingReader;
|
||||
|
||||
public class DumbTerminal extends AbstractTerminal {
|
||||
|
||||
private final TerminalProvider provider;
|
||||
private final SystemStream systemStream;
|
||||
private final NonBlockingInputStream input;
|
||||
private final OutputStream output;
|
||||
private final NonBlockingReader reader;
|
||||
private final PrintWriter writer;
|
||||
private final Attributes attributes;
|
||||
private final Size size;
|
||||
private boolean skipNextLf;
|
||||
|
||||
public DumbTerminal(InputStream in, OutputStream out) throws IOException {
|
||||
this(TYPE_DUMB, TYPE_DUMB, in, out, null);
|
||||
public DumbTerminal(InputStream in, OutputStream out, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
this(TYPE_DUMB, TYPE_DUMB, in, out, null, inputStreamWrapper);
|
||||
}
|
||||
|
||||
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding) throws IOException {
|
||||
this(name, type, in, out, encoding, SignalHandler.SIG_DFL);
|
||||
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding, Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
this(null, null, name, type, in, out, encoding, SignalHandler.SIG_DFL, inputStreamWrapper);
|
||||
}
|
||||
|
||||
public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public DumbTerminal(
|
||||
TerminalProvider provider,
|
||||
SystemStream systemStream,
|
||||
String name,
|
||||
String type,
|
||||
InputStream in,
|
||||
OutputStream out,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
super(name, type, encoding, signalHandler);
|
||||
NonBlockingInputStream nbis = NonBlocking.nonBlocking(getName(), in);
|
||||
this.provider = provider;
|
||||
this.systemStream = systemStream;
|
||||
NonBlockingInputStream nbis = NonBlocking.nonBlocking(getName(), inputStreamWrapper.apply(in));
|
||||
this.input = new NonBlockingInputStream() {
|
||||
@Override
|
||||
public int read(long timeout, boolean isPeek) throws IOException {
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
int c = nbis.read(timeout, isPeek);
|
||||
if (attributes.getLocalFlag(Attributes.LocalFlag.ISIG)) {
|
||||
if (c == attributes.getControlChar(ControlChar.VINTR)) {
|
||||
@ -62,7 +82,19 @@ public class DumbTerminal extends AbstractTerminal {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c == '\r') {
|
||||
if (attributes.getInputFlag(Attributes.InputFlag.INORMEOL)) {
|
||||
if (c == '\r') {
|
||||
skipNextLf = true;
|
||||
c = '\n';
|
||||
} else if (c == '\n') {
|
||||
if (skipNextLf) {
|
||||
skipNextLf = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
skipNextLf = false;
|
||||
}
|
||||
} else if (c == '\r') {
|
||||
if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
|
||||
continue;
|
||||
}
|
||||
@ -80,10 +112,10 @@ public class DumbTerminal extends AbstractTerminal {
|
||||
this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
|
||||
this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
|
||||
this.attributes = new Attributes();
|
||||
this.attributes.setControlChar(ControlChar.VERASE, (char) 127);
|
||||
this.attributes.setControlChar(ControlChar.VERASE, (char) 127);
|
||||
this.attributes.setControlChar(ControlChar.VWERASE, (char) 23);
|
||||
this.attributes.setControlChar(ControlChar.VKILL, (char) 21);
|
||||
this.attributes.setControlChar(ControlChar.VLNEXT, (char) 22);
|
||||
this.attributes.setControlChar(ControlChar.VKILL, (char) 21);
|
||||
this.attributes.setControlChar(ControlChar.VLNEXT, (char) 22);
|
||||
this.size = new Size();
|
||||
parseInfoCmp();
|
||||
}
|
||||
@ -107,9 +139,7 @@ public class DumbTerminal extends AbstractTerminal {
|
||||
}
|
||||
|
||||
public Attributes getAttributes() {
|
||||
Attributes attr = new Attributes();
|
||||
attr.copy(attributes);
|
||||
return attr;
|
||||
return new Attributes(attributes);
|
||||
}
|
||||
|
||||
public void setAttributes(Attributes attr) {
|
||||
@ -126,4 +156,13 @@ public class DumbTerminal extends AbstractTerminal {
|
||||
size.copy(sz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminalProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemStream getSystemStream() {
|
||||
return systemStream;
|
||||
}
|
||||
}
|
||||
|
@ -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() + "]";
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,10 +8,6 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal.impl;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -19,6 +15,11 @@ import java.nio.charset.Charset;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
|
||||
/**
|
||||
* Console implementation with embedded line disciplined.
|
||||
*
|
||||
@ -32,45 +33,59 @@ import java.util.function.IntConsumer;
|
||||
*/
|
||||
public class ExternalTerminal extends LineDisciplineTerminal {
|
||||
|
||||
private final TerminalProvider provider;
|
||||
protected final AtomicBoolean closed = new AtomicBoolean();
|
||||
protected final InputStream masterInput;
|
||||
protected final Object lock = new Object();
|
||||
protected boolean paused = true;
|
||||
protected Thread pumpThread;
|
||||
|
||||
public ExternalTerminal(String name, String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding) throws IOException {
|
||||
this(name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
|
||||
public ExternalTerminal(
|
||||
String name, String type, InputStream masterInput, OutputStream masterOutput, Charset encoding)
|
||||
throws IOException {
|
||||
this(null, name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
|
||||
}
|
||||
|
||||
public ExternalTerminal(String name, String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler) throws IOException {
|
||||
this(name, type, masterInput, masterOutput, encoding, signalHandler, false);
|
||||
public ExternalTerminal(
|
||||
TerminalProvider provider,
|
||||
String name,
|
||||
String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler)
|
||||
throws IOException {
|
||||
this(provider, name, type, masterInput, masterOutput, encoding, signalHandler, false);
|
||||
}
|
||||
|
||||
public ExternalTerminal(String name, String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler,
|
||||
boolean paused) throws IOException {
|
||||
this(name, type, masterInput, masterOutput, encoding, signalHandler, paused, null, null);
|
||||
public ExternalTerminal(
|
||||
TerminalProvider provider,
|
||||
String name,
|
||||
String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler,
|
||||
boolean paused)
|
||||
throws IOException {
|
||||
this(provider, name, type, masterInput, masterOutput, encoding, signalHandler, paused, null, null);
|
||||
}
|
||||
|
||||
public ExternalTerminal(String name, String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
Attributes attributes,
|
||||
Size size) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public ExternalTerminal(
|
||||
TerminalProvider provider,
|
||||
String name,
|
||||
String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
Attributes attributes,
|
||||
Size size)
|
||||
throws IOException {
|
||||
super(name, type, masterOutput, encoding, signalHandler);
|
||||
this.provider = provider;
|
||||
this.masterInput = masterInput;
|
||||
if (attributes != null) {
|
||||
setAttributes(attributes);
|
||||
@ -171,4 +186,8 @@ public class ExternalTerminal extends LineDisciplineTerminal {
|
||||
return CursorSupport.getCursorPosition(this, discarded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminalProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -14,6 +14,7 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
@ -23,6 +24,8 @@ import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
|
||||
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.NonBlocking;
|
||||
import jdk.internal.org.jline.utils.NonBlockingPumpInputStream;
|
||||
import jdk.internal.org.jline.utils.NonBlockingReader;
|
||||
@ -45,21 +48,6 @@ import jdk.internal.org.jline.utils.NonBlockingReader;
|
||||
*/
|
||||
public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
|
||||
private static final String DEFAULT_TERMINAL_ATTRIBUTES =
|
||||
"speed 9600 baud; 24 rows; 80 columns;\n" +
|
||||
"lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl\n" +
|
||||
"\t-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
|
||||
"\t-extproc\n" +
|
||||
"iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8\n" +
|
||||
"\t-ignbrk brkint -inpck -ignpar -parmrk\n" +
|
||||
"oflags: opost onlcr -oxtabs -onocr -onlret\n" +
|
||||
"cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
|
||||
"\t-dtrflow -mdmbuf\n" +
|
||||
"cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
|
||||
"\teol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
|
||||
"\tmin = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
|
||||
"\tstop = ^S; susp = ^Z; time = 0; werase = ^W;\n";
|
||||
|
||||
private static final int PIPE_SIZE = 1024;
|
||||
|
||||
/*
|
||||
@ -84,20 +72,20 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
* Console data
|
||||
*/
|
||||
protected final Attributes attributes;
|
||||
|
||||
protected final Size size;
|
||||
|
||||
public LineDisciplineTerminal(String name,
|
||||
String type,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding) throws IOException {
|
||||
protected boolean skipNextLf;
|
||||
|
||||
public LineDisciplineTerminal(String name, String type, OutputStream masterOutput, Charset encoding)
|
||||
throws IOException {
|
||||
this(name, type, masterOutput, encoding, SignalHandler.SIG_DFL);
|
||||
}
|
||||
|
||||
public LineDisciplineTerminal(String name,
|
||||
String type,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public LineDisciplineTerminal(
|
||||
String name, String type, OutputStream masterOutput, Charset encoding, SignalHandler signalHandler)
|
||||
throws IOException {
|
||||
super(name, type, encoding, signalHandler);
|
||||
NonBlockingPumpInputStream input = NonBlocking.nonBlockingPumpInputStream(PIPE_SIZE);
|
||||
this.slaveInputPipe = input.getOutputStream();
|
||||
@ -106,11 +94,66 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
this.slaveOutput = new FilteringOutputStream();
|
||||
this.slaveWriter = new PrintWriter(new OutputStreamWriter(slaveOutput, encoding()));
|
||||
this.masterOutput = masterOutput;
|
||||
this.attributes = ExecPty.doGetAttr(DEFAULT_TERMINAL_ATTRIBUTES);
|
||||
this.attributes = getDefaultTerminalAttributes();
|
||||
this.size = new Size(160, 50);
|
||||
parseInfoCmp();
|
||||
}
|
||||
|
||||
private static Attributes getDefaultTerminalAttributes() {
|
||||
// speed 9600 baud; 24 rows; 80 columns;
|
||||
// lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
|
||||
// -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
|
||||
// -extproc
|
||||
// iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8
|
||||
// -ignbrk brkint -inpck -ignpar -parmrk
|
||||
// oflags: opost onlcr -oxtabs -onocr -onlret
|
||||
// cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
|
||||
// -dtrflow -mdmbuf
|
||||
// cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
|
||||
// eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
|
||||
// min = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;
|
||||
// stop = ^S; susp = ^Z; time = 0; werase = ^W;
|
||||
Attributes attr = new Attributes();
|
||||
attr.setLocalFlags(EnumSet.of(
|
||||
LocalFlag.ICANON,
|
||||
LocalFlag.ISIG,
|
||||
LocalFlag.IEXTEN,
|
||||
LocalFlag.ECHO,
|
||||
LocalFlag.ECHOE,
|
||||
LocalFlag.ECHOKE,
|
||||
LocalFlag.ECHOCTL,
|
||||
LocalFlag.PENDIN));
|
||||
attr.setInputFlags(EnumSet.of(
|
||||
InputFlag.ICRNL,
|
||||
InputFlag.IXON,
|
||||
InputFlag.IXANY,
|
||||
InputFlag.IMAXBEL,
|
||||
InputFlag.IUTF8,
|
||||
InputFlag.BRKINT));
|
||||
attr.setOutputFlags(EnumSet.of(OutputFlag.OPOST, OutputFlag.ONLCR));
|
||||
attr.setControlChar(ControlChar.VDISCARD, ctrl('O'));
|
||||
attr.setControlChar(ControlChar.VDSUSP, ctrl('Y'));
|
||||
attr.setControlChar(ControlChar.VEOF, ctrl('D'));
|
||||
attr.setControlChar(ControlChar.VERASE, ctrl('?'));
|
||||
attr.setControlChar(ControlChar.VINTR, ctrl('C'));
|
||||
attr.setControlChar(ControlChar.VKILL, ctrl('U'));
|
||||
attr.setControlChar(ControlChar.VLNEXT, ctrl('V'));
|
||||
attr.setControlChar(ControlChar.VMIN, 1);
|
||||
attr.setControlChar(ControlChar.VQUIT, ctrl('\\'));
|
||||
attr.setControlChar(ControlChar.VREPRINT, ctrl('R'));
|
||||
attr.setControlChar(ControlChar.VSTART, ctrl('Q'));
|
||||
attr.setControlChar(ControlChar.VSTATUS, ctrl('T'));
|
||||
attr.setControlChar(ControlChar.VSTOP, ctrl('S'));
|
||||
attr.setControlChar(ControlChar.VSUSP, ctrl('Z'));
|
||||
attr.setControlChar(ControlChar.VTIME, 0);
|
||||
attr.setControlChar(ControlChar.VWERASE, ctrl('W'));
|
||||
return attr;
|
||||
}
|
||||
|
||||
private static int ctrl(char c) {
|
||||
return c == '?' ? 177 : c - 64;
|
||||
}
|
||||
|
||||
public NonBlockingReader reader() {
|
||||
return slaveReader;
|
||||
}
|
||||
@ -130,9 +173,7 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
}
|
||||
|
||||
public Attributes getAttributes() {
|
||||
Attributes attr = new Attributes();
|
||||
attr.copy(attributes);
|
||||
return attr;
|
||||
return new Attributes(attributes);
|
||||
}
|
||||
|
||||
public void setAttributes(Attributes attr) {
|
||||
@ -149,9 +190,9 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
size.copy(sz);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void raise(Signal signal) {
|
||||
Objects.requireNonNull(signal);
|
||||
Objects.requireNonNull(signal);
|
||||
// Do not call clear() atm as this can cause
|
||||
// deadlock between reading / writing threads
|
||||
// TODO: any way to fix that ?
|
||||
@ -214,7 +255,19 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
raise(Signal.INFO);
|
||||
}
|
||||
}
|
||||
if (c == '\r') {
|
||||
if (attributes.getInputFlag(InputFlag.INORMEOL)) {
|
||||
if (c == '\r') {
|
||||
skipNextLf = true;
|
||||
c = '\n';
|
||||
} else if (c == '\n') {
|
||||
if (skipNextLf) {
|
||||
skipNextLf = false;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
skipNextLf = false;
|
||||
}
|
||||
} else if (c == '\r') {
|
||||
if (attributes.getInputFlag(InputFlag.IGNCR)) {
|
||||
return false;
|
||||
}
|
||||
@ -273,6 +326,16 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminalProvider getProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemStream getSystemStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class FilteringOutputStream extends OutputStream {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
@ -284,13 +347,12 @@ public class LineDisciplineTerminal extends AbstractTerminal {
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length) || ((off + len) < 0)) {
|
||||
} else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0 ; i < len ; i++) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
processOutputByte(b[off + i]);
|
||||
}
|
||||
flush();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -8,11 +8,6 @@
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal.impl;
|
||||
|
||||
import jdk.internal.org.jline.terminal.MouseEvent;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
import jdk.internal.org.jline.utils.InputStreamReader;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
@ -20,6 +15,11 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.EnumSet;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import jdk.internal.org.jline.terminal.MouseEvent;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
import jdk.internal.org.jline.utils.InputStreamReader;
|
||||
|
||||
public class MouseSupport {
|
||||
|
||||
public static boolean hasMouseSupport(Terminal terminal) {
|
||||
@ -78,7 +78,8 @@ public class MouseSupport {
|
||||
case 0:
|
||||
button = MouseEvent.Button.Button1;
|
||||
if (last.getButton() == button
|
||||
&& (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
|
||||
&& (last.getType() == MouseEvent.Type.Pressed
|
||||
|| last.getType() == MouseEvent.Type.Dragged)) {
|
||||
type = MouseEvent.Type.Dragged;
|
||||
} else {
|
||||
type = MouseEvent.Type.Pressed;
|
||||
@ -87,7 +88,8 @@ public class MouseSupport {
|
||||
case 1:
|
||||
button = MouseEvent.Button.Button2;
|
||||
if (last.getButton() == button
|
||||
&& (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
|
||||
&& (last.getType() == MouseEvent.Type.Pressed
|
||||
|| last.getType() == MouseEvent.Type.Dragged)) {
|
||||
type = MouseEvent.Type.Dragged;
|
||||
} else {
|
||||
type = MouseEvent.Type.Pressed;
|
||||
@ -96,7 +98,8 @@ public class MouseSupport {
|
||||
case 2:
|
||||
button = MouseEvent.Button.Button3;
|
||||
if (last.getButton() == button
|
||||
&& (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
|
||||
&& (last.getType() == MouseEvent.Type.Pressed
|
||||
|| last.getType() == MouseEvent.Type.Dragged)) {
|
||||
type = MouseEvent.Type.Dragged;
|
||||
} else {
|
||||
type = MouseEvent.Type.Pressed;
|
||||
@ -134,5 +137,4 @@ public class MouseSupport {
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -17,8 +17,7 @@ public final class NativeSignalHandler implements SignalHandler {
|
||||
|
||||
public static final NativeSignalHandler SIG_IGN = new NativeSignalHandler();
|
||||
|
||||
private NativeSignalHandler() {
|
||||
}
|
||||
private NativeSignalHandler() {}
|
||||
|
||||
public void handle(Signal signal) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -38,15 +38,34 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
private Thread outputPumpThread;
|
||||
private boolean paused = true;
|
||||
|
||||
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding) throws IOException {
|
||||
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding)
|
||||
throws IOException {
|
||||
this(name, type, pty, in, out, encoding, SignalHandler.SIG_DFL);
|
||||
}
|
||||
|
||||
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) throws IOException {
|
||||
public PosixPtyTerminal(
|
||||
String name,
|
||||
String type,
|
||||
Pty pty,
|
||||
InputStream in,
|
||||
OutputStream out,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler)
|
||||
throws IOException {
|
||||
this(name, type, pty, in, out, encoding, signalHandler, false);
|
||||
}
|
||||
|
||||
public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler, boolean paused) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public PosixPtyTerminal(
|
||||
String name,
|
||||
String type,
|
||||
Pty pty,
|
||||
InputStream in,
|
||||
OutputStream out,
|
||||
Charset encoding,
|
||||
SignalHandler signalHandler,
|
||||
boolean paused)
|
||||
throws IOException {
|
||||
super(name, type, pty, encoding, signalHandler);
|
||||
this.in = Objects.requireNonNull(in);
|
||||
this.out = Objects.requireNonNull(out);
|
||||
@ -113,7 +132,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
if (p1 != null) {
|
||||
p1.join();
|
||||
}
|
||||
if (p2 !=null) {
|
||||
if (p2 != null) {
|
||||
p2.join();
|
||||
}
|
||||
}
|
||||
@ -167,7 +186,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
|
||||
private void pumpIn() {
|
||||
try {
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
synchronized (lock) {
|
||||
if (paused) {
|
||||
inputPumpThread = null;
|
||||
@ -193,7 +212,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
|
||||
private void pumpOut() {
|
||||
try {
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
synchronized (lock) {
|
||||
if (paused) {
|
||||
outputPumpThread = null;
|
||||
@ -221,5 +240,4 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -18,8 +18,9 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.utils.NonBlocking;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.utils.FastBufferedOutputStream;
|
||||
import jdk.internal.org.jline.utils.NonBlocking;
|
||||
import jdk.internal.org.jline.utils.NonBlockingInputStream;
|
||||
import jdk.internal.org.jline.utils.NonBlockingReader;
|
||||
import jdk.internal.org.jline.utils.ShutdownHooks;
|
||||
@ -35,12 +36,14 @@ public class PosixSysTerminal extends AbstractPosixTerminal {
|
||||
protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
|
||||
protected final Task closer;
|
||||
|
||||
public PosixSysTerminal(String name, String type, Pty pty, Charset encoding,
|
||||
boolean nativeSignals, SignalHandler signalHandler,
|
||||
Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
@SuppressWarnings("this-escape")
|
||||
public PosixSysTerminal(
|
||||
String name, String type, Pty pty, Charset encoding, boolean nativeSignals, SignalHandler signalHandler,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
super(name, type, pty, encoding, signalHandler);
|
||||
this.input = NonBlocking.nonBlocking(getName(), inputStreamWrapper.apply(pty.getSlaveInput()));
|
||||
this.output = pty.getSlaveOutput();
|
||||
this.output = new FastBufferedOutputStream(pty.getSlaveOutput());
|
||||
this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
|
||||
this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
|
||||
parseInfoCmp();
|
||||
@ -98,5 +101,4 @@ public class PosixSysTerminal extends AbstractPosixTerminal {
|
||||
// Do not call reader.close()
|
||||
reader.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
package jdk.internal.org.jline.terminal.impl;
|
||||
package jdk.internal.org.jline.terminal.impl.exec;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -26,8 +26,10 @@ import jdk.internal.org.jline.terminal.Attributes.InputFlag;
|
||||
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
|
||||
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractPty;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
import static jdk.internal.org.jline.utils.ExecHelper.exec;
|
||||
@ -35,28 +37,26 @@ import static jdk.internal.org.jline.utils.ExecHelper.exec;
|
||||
public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
private final String name;
|
||||
private final TerminalProvider.Stream console;
|
||||
|
||||
public static Pty current(TerminalProvider.Stream console) throws IOException {
|
||||
public static Pty current(TerminalProvider provider, SystemStream systemStream) throws IOException {
|
||||
try {
|
||||
String result = exec(true, OSUtils.TTY_COMMAND);
|
||||
if (console != TerminalProvider.Stream.Output && console != TerminalProvider.Stream.Error) {
|
||||
throw new IllegalArgumentException("console should be Output or Error: " + console);
|
||||
if (systemStream != SystemStream.Output && systemStream != SystemStream.Error) {
|
||||
throw new IllegalArgumentException("systemStream should be Output or Error: " + systemStream);
|
||||
}
|
||||
return new ExecPty(result.trim(), console);
|
||||
return new ExecPty(provider, systemStream, result.trim());
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Not a tty", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected ExecPty(String name, TerminalProvider.Stream console) {
|
||||
protected ExecPty(TerminalProvider provider, SystemStream systemStream, String name) {
|
||||
super(provider, systemStream);
|
||||
this.name = name;
|
||||
this.console = console;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
public void close() throws IOException {}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
@ -74,18 +74,16 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
@Override
|
||||
protected InputStream doGetSlaveInput() throws IOException {
|
||||
return console != null
|
||||
? new FileInputStream(FileDescriptor.in)
|
||||
: new FileInputStream(getName());
|
||||
return systemStream != null ? new FileInputStream(FileDescriptor.in) : new FileInputStream(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getSlaveOutput() throws IOException {
|
||||
return console == TerminalProvider.Stream.Output
|
||||
return systemStream == SystemStream.Output
|
||||
? new FileOutputStream(FileDescriptor.out)
|
||||
: console == TerminalProvider.Stream.Error
|
||||
? new FileOutputStream(FileDescriptor.err)
|
||||
: new FileOutputStream(getName());
|
||||
: systemStream == SystemStream.Error
|
||||
? new FileOutputStream(FileDescriptor.err)
|
||||
: new FileOutputStream(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -99,18 +97,30 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
List<String> commands = getFlagsToSet(attr, getAttr());
|
||||
if (!commands.isEmpty()) {
|
||||
commands.add(0, OSUtils.STTY_COMMAND);
|
||||
if (console == null) {
|
||||
if (systemStream == null) {
|
||||
commands.add(1, OSUtils.STTY_F_OPTION);
|
||||
commands.add(2, getName());
|
||||
}
|
||||
exec(console != null, commands.toArray(new String[0]));
|
||||
try {
|
||||
exec(systemStream != null, commands.toArray(new String[0]));
|
||||
} catch (IOException e) {
|
||||
// Handle partial failures with GNU stty, see #97
|
||||
if (e.toString().contains("unable to perform all requested operations")) {
|
||||
commands = getFlagsToSet(attr, getAttr());
|
||||
if (!commands.isEmpty()) {
|
||||
throw new IOException("Could not set the following flags: " + String.join(", ", commands), e);
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> getFlagsToSet(Attributes attr, Attributes current) {
|
||||
List<String> commands = new ArrayList<>();
|
||||
for (InputFlag flag : InputFlag.values()) {
|
||||
if (attr.getInputFlag(flag) != current.getInputFlag(flag)) {
|
||||
if (attr.getInputFlag(flag) != current.getInputFlag(flag) && flag != InputFlag.INORMEOL) {
|
||||
commands.add((attr.getInputFlag(flag) ? flag.name() : "-" + flag.name()).toLowerCase());
|
||||
}
|
||||
}
|
||||
@ -137,11 +147,9 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
commands.add(cchar.name().toLowerCase().substring(1));
|
||||
if (cchar == ControlChar.VMIN || cchar == ControlChar.VTIME) {
|
||||
commands.add(Integer.toString(v));
|
||||
}
|
||||
else if (v == 0) {
|
||||
} else if (v == 0) {
|
||||
commands.add(undef);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (v >= 128) {
|
||||
v -= 128;
|
||||
str += "M-";
|
||||
@ -165,12 +173,12 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
}
|
||||
|
||||
protected String doGetConfig() throws IOException {
|
||||
return console != null
|
||||
? exec(true, OSUtils.STTY_COMMAND, "-a")
|
||||
return systemStream != null
|
||||
? exec(true, OSUtils.STTY_COMMAND, "-a")
|
||||
: exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, getName(), "-a");
|
||||
}
|
||||
|
||||
static Attributes doGetAttr(String cfg) throws IOException {
|
||||
public static Attributes doGetAttr(String cfg) throws IOException {
|
||||
Attributes attributes = new Attributes();
|
||||
for (InputFlag flag : InputFlag.values()) {
|
||||
Boolean value = doGetFlag(cfg, flag);
|
||||
@ -201,16 +209,19 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
if ("reprint".endsWith(name)) {
|
||||
name = "(?:reprint|rprnt)";
|
||||
}
|
||||
Matcher matcher = Pattern.compile("[\\s;]" + name + "\\s*=\\s*(.+?)[\\s;]").matcher(cfg);
|
||||
Matcher matcher =
|
||||
Pattern.compile("[\\s;]" + name + "\\s*=\\s*(.+?)[\\s;]").matcher(cfg);
|
||||
if (matcher.find()) {
|
||||
attributes.setControlChar(cchar, parseControlChar(matcher.group(1).toUpperCase()));
|
||||
attributes.setControlChar(
|
||||
cchar, parseControlChar(matcher.group(1).toUpperCase()));
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static Boolean doGetFlag(String cfg, Enum<?> flag) {
|
||||
Matcher matcher = Pattern.compile("(?:^|[\\s;])(\\-?" + flag.name().toLowerCase() + ")(?:[\\s;]|$)").matcher(cfg);
|
||||
Matcher matcher = Pattern.compile("(?:^|[\\s;])(\\-?" + flag.name().toLowerCase() + ")(?:[\\s;]|$)")
|
||||
.matcher(cfg);
|
||||
return matcher.find() ? !matcher.group(1).startsWith("-") : null;
|
||||
}
|
||||
|
||||
@ -259,9 +270,7 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
static int doGetInt(String name, String cfg) throws IOException {
|
||||
String[] patterns = new String[] {
|
||||
"\\b([0-9]+)\\s+" + name + "\\b",
|
||||
"\\b" + name + "\\s+([0-9]+)\\b",
|
||||
"\\b" + name + "\\s*=\\s*([0-9]+)\\b"
|
||||
"\\b([0-9]+)\\s+" + name + "\\b", "\\b" + name + "\\s+([0-9]+)\\b", "\\b" + name + "\\s*=\\s*([0-9]+)\\b"
|
||||
};
|
||||
for (String pattern : patterns) {
|
||||
Matcher matcher = Pattern.compile(pattern).matcher(cfg);
|
||||
@ -274,23 +283,29 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
@Override
|
||||
public void setSize(Size size) throws IOException {
|
||||
if (console != null) {
|
||||
exec(true,
|
||||
OSUtils.STTY_COMMAND,
|
||||
"columns", Integer.toString(size.getColumns()),
|
||||
"rows", Integer.toString(size.getRows()));
|
||||
if (systemStream != null) {
|
||||
exec(
|
||||
true,
|
||||
OSUtils.STTY_COMMAND,
|
||||
"columns",
|
||||
Integer.toString(size.getColumns()),
|
||||
"rows",
|
||||
Integer.toString(size.getRows()));
|
||||
} else {
|
||||
exec(false,
|
||||
OSUtils.STTY_COMMAND,
|
||||
OSUtils.STTY_F_OPTION, getName(),
|
||||
"columns", Integer.toString(size.getColumns()),
|
||||
"rows", Integer.toString(size.getRows()));
|
||||
exec(
|
||||
false,
|
||||
OSUtils.STTY_COMMAND,
|
||||
OSUtils.STTY_F_OPTION,
|
||||
getName(),
|
||||
"columns",
|
||||
Integer.toString(size.getColumns()),
|
||||
"rows",
|
||||
Integer.toString(size.getRows()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExecPty[" + getName() + (console != null ? ", system]" : "]");
|
||||
return "ExecPty[" + getName() + (systemStream != null ? ", system]" : "]");
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, the original author or authors.
|
||||
* Copyright (c) 2022, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -17,117 +17,249 @@ import java.lang.reflect.Field;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.function.Function;
|
||||
|
||||
//import jdk.internal.org.jline.nativ.JLineLibrary;
|
||||
//import jdk.internal.org.jline.nativ.JLineNativeLoader;
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.ExecPty;
|
||||
import jdk.internal.org.jline.terminal.TerminalBuilder;
|
||||
import jdk.internal.org.jline.terminal.impl.ExternalTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.terminal.spi.SystemStream;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.ExecHelper;
|
||||
import jdk.internal.org.jline.utils.Log;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
public class ExecTerminalProvider implements TerminalProvider
|
||||
{
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE_DEFAULT;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION;
|
||||
|
||||
public class ExecTerminalProvider implements TerminalProvider {
|
||||
|
||||
private static boolean warned;
|
||||
|
||||
public String name() {
|
||||
return "exec";
|
||||
return TerminalBuilder.PROP_PROVIDER_EXEC;
|
||||
}
|
||||
|
||||
public Pty current(Stream consoleStream) throws IOException {
|
||||
return ExecPty.current(consoleStream);
|
||||
public Pty current(SystemStream systemStream) throws IOException {
|
||||
return ExecPty.current(this, systemStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
public Terminal sysTerminal(
|
||||
String name,
|
||||
String type,
|
||||
boolean ansiPassThrough,
|
||||
Charset encoding,
|
||||
boolean nativeSignals,
|
||||
Terminal.SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
SystemStream systemStream,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
return winSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
|
||||
return winSysTerminal(
|
||||
name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream, inputStreamWrapper);
|
||||
} else {
|
||||
return posixSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
|
||||
return posixSysTerminal(
|
||||
name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream, inputStreamWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper ) throws IOException {
|
||||
public Terminal winSysTerminal(
|
||||
String name,
|
||||
String type,
|
||||
boolean ansiPassThrough,
|
||||
Charset encoding,
|
||||
boolean nativeSignals,
|
||||
Terminal.SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
SystemStream systemStream,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
|
||||
Pty pty = current(consoleStream);
|
||||
Pty pty = current(systemStream);
|
||||
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Terminal posixSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
Pty pty = current(consoleStream);
|
||||
public Terminal posixSysTerminal(
|
||||
String name,
|
||||
String type,
|
||||
boolean ansiPassThrough,
|
||||
Charset encoding,
|
||||
boolean nativeSignals,
|
||||
Terminal.SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
SystemStream systemStream,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException {
|
||||
Pty pty = current(systemStream);
|
||||
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal newTerminal(String name, String type, InputStream in, OutputStream out,
|
||||
Charset encoding, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Attributes attributes, Size size) throws IOException
|
||||
{
|
||||
return new ExternalTerminal(name, type, in, out, encoding, signalHandler, paused, attributes, size);
|
||||
public Terminal newTerminal(
|
||||
String name,
|
||||
String type,
|
||||
InputStream in,
|
||||
OutputStream out,
|
||||
Charset encoding,
|
||||
Terminal.SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
Attributes attributes,
|
||||
Size size)
|
||||
throws IOException {
|
||||
return new ExternalTerminal(this, name, type, in, out, encoding, signalHandler, paused, attributes, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSystemStream(Stream stream) {
|
||||
public boolean isSystemStream(SystemStream stream) {
|
||||
try {
|
||||
return isWindowsSystemStream(stream) || isPosixSystemStream(stream);
|
||||
return isPosixSystemStream(stream) || isWindowsSystemStream(stream);
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWindowsSystemStream(Stream stream) {
|
||||
return systemStreamName( stream ) != null;
|
||||
public boolean isWindowsSystemStream(SystemStream stream) {
|
||||
return systemStreamName(stream) != null;
|
||||
}
|
||||
|
||||
public boolean isPosixSystemStream(Stream stream) {
|
||||
public boolean isPosixSystemStream(SystemStream stream) {
|
||||
try {
|
||||
Process p = new ProcessBuilder(OSUtils.TEST_COMMAND, "-t", Integer.toString(stream.ordinal()))
|
||||
.inheritIO().start();
|
||||
.inheritIO()
|
||||
.start();
|
||||
return p.waitFor() == 0;
|
||||
} catch (Throwable t) {
|
||||
Log.debug("ExecTerminalProvider failed 'test -t' for " + stream, t);
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String systemStreamName(Stream stream) {
|
||||
public String systemStreamName(SystemStream stream) {
|
||||
try {
|
||||
ProcessBuilder.Redirect input = stream == Stream.Input
|
||||
? ProcessBuilder.Redirect.INHERIT
|
||||
: getRedirect(stream == Stream.Output ? FileDescriptor.out : FileDescriptor.err);
|
||||
Process p = new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start();
|
||||
ProcessBuilder.Redirect input = stream == SystemStream.Input
|
||||
? ProcessBuilder.Redirect.INHERIT
|
||||
: newDescriptor(stream == SystemStream.Output ? FileDescriptor.out : FileDescriptor.err);
|
||||
Process p =
|
||||
new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start();
|
||||
String result = ExecHelper.waitAndCapture(p);
|
||||
if (p.exitValue() == 0) {
|
||||
return result.trim();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if ("java.lang.reflect.InaccessibleObjectException"
|
||||
.equals(t.getClass().getName())
|
||||
&& !warned) {
|
||||
Log.warn(
|
||||
"The ExecTerminalProvider requires the JVM options: '--add-opens java.base/java.lang=ALL-UNNAMED'");
|
||||
warned = true;
|
||||
}
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ProcessBuilder.Redirect getRedirect(FileDescriptor fd) throws ReflectiveOperationException {
|
||||
// This is not really allowed, but this is the only way to redirect the output or error stream
|
||||
// to the input. This is definitely not something you'd usually want to do, but in the case of
|
||||
// the `tty` utility, it provides a way to get
|
||||
Class<?> rpi = Class.forName("java.lang.ProcessBuilder$RedirectPipeImpl");
|
||||
Constructor<?> cns = rpi.getDeclaredConstructor();
|
||||
cns.setAccessible(true);
|
||||
ProcessBuilder.Redirect input = (ProcessBuilder.Redirect) cns.newInstance();
|
||||
Field f = rpi.getDeclaredField("fd");
|
||||
f.setAccessible(true);
|
||||
f.set(input, fd);
|
||||
return input;
|
||||
@Override
|
||||
public int systemStreamWidth(SystemStream stream) {
|
||||
try (ExecPty pty = new ExecPty(this, stream, null)) {
|
||||
return pty.getSize().getColumns();
|
||||
} catch (Throwable t) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static RedirectPipeCreator redirectPipeCreator;
|
||||
|
||||
protected static ProcessBuilder.Redirect newDescriptor(FileDescriptor fd) {
|
||||
if (redirectPipeCreator == null) {
|
||||
String str = System.getProperty(PROP_REDIRECT_PIPE_CREATION_MODE, PROP_REDIRECT_PIPE_CREATION_MODE_DEFAULT);
|
||||
String[] modes = str.split(",");
|
||||
IllegalStateException ise = new IllegalStateException("Unable to create RedirectPipe");
|
||||
for (String mode : modes) {
|
||||
try {
|
||||
switch (mode) {
|
||||
case PROP_REDIRECT_PIPE_CREATION_MODE_NATIVE:
|
||||
redirectPipeCreator = null;//new NativeRedirectPipeCreator();
|
||||
break;
|
||||
case PROP_REDIRECT_PIPE_CREATION_MODE_REFLECTION:
|
||||
redirectPipeCreator = new ReflectionRedirectPipeCreator();
|
||||
break;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
ise.addSuppressed(t);
|
||||
}
|
||||
if (redirectPipeCreator != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (redirectPipeCreator == null) {
|
||||
throw ise;
|
||||
}
|
||||
}
|
||||
return redirectPipeCreator.newRedirectPipe(fd);
|
||||
}
|
||||
|
||||
interface RedirectPipeCreator {
|
||||
ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflection based file descriptor creator.
|
||||
* This requires the following option
|
||||
* --add-opens java.base/java.lang=ALL-UNNAMED
|
||||
*/
|
||||
static class ReflectionRedirectPipeCreator implements RedirectPipeCreator {
|
||||
private final Constructor<ProcessBuilder.Redirect> constructor;
|
||||
private final Field fdField;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ReflectionRedirectPipeCreator() throws Exception {
|
||||
Class<?> rpi = Class.forName("java.lang.ProcessBuilder$RedirectPipeImpl");
|
||||
constructor = (Constructor<ProcessBuilder.Redirect>) rpi.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
fdField = rpi.getDeclaredField("fd");
|
||||
fdField.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd) {
|
||||
try {
|
||||
ProcessBuilder.Redirect input = constructor.newInstance();
|
||||
fdField.set(input, fd);
|
||||
return input;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
// This should not happen as the field has been set accessible
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static class NativeRedirectPipeCreator implements RedirectPipeCreator {
|
||||
// public NativeRedirectPipeCreator() {
|
||||
// // Force load the library
|
||||
// JLineNativeLoader.initialize();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd) {
|
||||
// return JLineLibrary.newRedirectPipe(fd);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TerminalProvider[" + name() + "]";
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -34,4 +34,7 @@ public interface Pty extends Closeable {
|
||||
|
||||
void setSize(Size size) throws IOException;
|
||||
|
||||
SystemStream getSystemStream();
|
||||
|
||||
TerminalProvider getProvider();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, the original author or authors.
|
||||
* Copyright (c) 2022, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -11,58 +11,60 @@ package jdk.internal.org.jline.terminal.spi;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.exec.ExecTerminalProvider;
|
||||
import jdk.internal.org.jline.terminal.impl.ffm.FfmTerminalProvider;
|
||||
|
||||
public interface TerminalProvider
|
||||
{
|
||||
|
||||
enum Stream {
|
||||
Input,
|
||||
Output,
|
||||
Error
|
||||
}
|
||||
public interface TerminalProvider {
|
||||
|
||||
String name();
|
||||
|
||||
Terminal sysTerminal(String name, String type, boolean ansiPassThrough,
|
||||
Charset encoding, boolean nativeSignals,
|
||||
Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException;
|
||||
Terminal sysTerminal(
|
||||
String name,
|
||||
String type,
|
||||
boolean ansiPassThrough,
|
||||
Charset encoding,
|
||||
boolean nativeSignals,
|
||||
Terminal.SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
SystemStream systemStream,
|
||||
Function<InputStream, InputStream> inputStreamWrapper)
|
||||
throws IOException;
|
||||
|
||||
Terminal newTerminal(String name, String type,
|
||||
InputStream masterInput, OutputStream masterOutput,
|
||||
Charset encoding, Terminal.SignalHandler signalHandler,
|
||||
boolean paused, Attributes attributes, Size size) throws IOException;
|
||||
Terminal newTerminal(
|
||||
String name,
|
||||
String type,
|
||||
InputStream masterInput,
|
||||
OutputStream masterOutput,
|
||||
Charset encoding,
|
||||
Terminal.SignalHandler signalHandler,
|
||||
boolean paused,
|
||||
Attributes attributes,
|
||||
Size size)
|
||||
throws IOException;
|
||||
|
||||
boolean isSystemStream(Stream stream);
|
||||
boolean isSystemStream(SystemStream stream);
|
||||
|
||||
String systemStreamName(Stream stream);
|
||||
String systemStreamName(SystemStream stream);
|
||||
|
||||
int systemStreamWidth(SystemStream stream);
|
||||
|
||||
static TerminalProvider load(String name) throws IOException {
|
||||
switch (name) {
|
||||
case "exec": return new ExecTerminalProvider();
|
||||
case "jna": {
|
||||
try {
|
||||
return (TerminalProvider) Class.forName("jdk.internal.org.jline.terminal.impl.jna.JnaTerminalProvider").getConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException t) {
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
case "ffm": return new FfmTerminalProvider();
|
||||
}
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl == null) {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
InputStream is = cl.getResourceAsStream( "META-INF/services/org/jline/terminal/provider/" + name);
|
||||
InputStream is = cl.getResourceAsStream("META-INF/services/org/jline/terminal/provider/" + name);
|
||||
if (is != null) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
@ -71,14 +73,13 @@ public interface TerminalProvider
|
||||
if (className == null) {
|
||||
throw new IOException("No class defined in terminal provider file " + name);
|
||||
}
|
||||
Class<?> clazz = cl.loadClass( className );
|
||||
Class<?> clazz = cl.loadClass(className);
|
||||
return (TerminalProvider) clazz.getConstructor().newInstance();
|
||||
} catch ( Exception e ) {
|
||||
throw new IOException("Unable to load terminal provider " + name, e);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Unable to load terminal provider " + name + ": " + e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unable to find terminal provider " + name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,17 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2018 the original author(s).
|
||||
* Copyright (c) 2009-2018, the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
package jdk.internal.org.jline.utils;
|
||||
|
||||
@ -252,12 +245,10 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @throws IOException if no more non-null values left
|
||||
*/
|
||||
private int getNextOptionInt(Iterator<Object> optionsIterator) throws IOException {
|
||||
for (;;) {
|
||||
if (!optionsIterator.hasNext())
|
||||
throw new IllegalArgumentException();
|
||||
for (; ; ) {
|
||||
if (!optionsIterator.hasNext()) throw new IllegalArgumentException();
|
||||
Object arg = optionsIterator.next();
|
||||
if (arg != null)
|
||||
return (Integer) arg;
|
||||
if (arg != null) return (Integer) arg;
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,27 +337,21 @@ public class AnsiWriter extends FilterWriter {
|
||||
int g = getNextOptionInt(optionsIterator);
|
||||
int b = getNextOptionInt(optionsIterator);
|
||||
if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
|
||||
if (value == 38)
|
||||
processSetForegroundColorExt(r, g, b);
|
||||
else
|
||||
processSetBackgroundColorExt(r, g, b);
|
||||
if (value == 38) processSetForegroundColorExt(r, g, b);
|
||||
else processSetBackgroundColorExt(r, g, b);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
else if (arg2or5 == 5) {
|
||||
} else if (arg2or5 == 5) {
|
||||
// 256 color style like `esc[38;5;<index>m`
|
||||
int paletteIndex = getNextOptionInt(optionsIterator);
|
||||
if (paletteIndex >= 0 && paletteIndex <= 255) {
|
||||
if (value == 38)
|
||||
processSetForegroundColorExt(paletteIndex);
|
||||
else
|
||||
processSetBackgroundColorExt(paletteIndex);
|
||||
if (value == 38) processSetForegroundColorExt(paletteIndex);
|
||||
else processSetBackgroundColorExt(paletteIndex);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else {
|
||||
@ -449,47 +434,41 @@ public class AnsiWriter extends FilterWriter {
|
||||
* Process <code>CSI u</code> ANSI code, corresponding to <code>RCP \u2013 Restore Cursor Position</code>
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processRestoreCursorPosition() throws IOException {
|
||||
}
|
||||
protected void processRestoreCursorPosition() throws IOException {}
|
||||
|
||||
/**
|
||||
* Process <code>CSI s</code> ANSI code, corresponding to <code>SCP \u2013 Save Cursor Position</code>
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processSaveCursorPosition() throws IOException {
|
||||
}
|
||||
protected void processSaveCursorPosition() throws IOException {}
|
||||
|
||||
/**
|
||||
* Process <code>CSI s</code> ANSI code, corresponding to <code>IL \u2013 Insert Line</code>
|
||||
* @param optionInt the option
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processInsertLine(int optionInt) throws IOException {
|
||||
}
|
||||
protected void processInsertLine(int optionInt) throws IOException {}
|
||||
|
||||
/**
|
||||
* Process <code>CSI s</code> ANSI code, corresponding to <code>DL \u2013 Delete Line</code>
|
||||
* @param optionInt the option
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processDeleteLine(int optionInt) throws IOException {
|
||||
}
|
||||
protected void processDeleteLine(int optionInt) throws IOException {}
|
||||
|
||||
/**
|
||||
* Process <code>CSI n T</code> ANSI code, corresponding to <code>SD \u2013 Scroll Down</code>
|
||||
* @param optionInt the option
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processScrollDown(int optionInt) throws IOException {
|
||||
}
|
||||
protected void processScrollDown(int optionInt) throws IOException {}
|
||||
|
||||
/**
|
||||
* Process <code>CSI n U</code> ANSI code, corresponding to <code>SU \u2013 Scroll Up</code>
|
||||
* @param optionInt the option
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processScrollUp(int optionInt) throws IOException {
|
||||
}
|
||||
protected void processScrollUp(int optionInt) throws IOException {}
|
||||
|
||||
protected static final int ERASE_SCREEN_TO_END = 0;
|
||||
protected static final int ERASE_SCREEN_TO_BEGINING = 1;
|
||||
@ -500,8 +479,7 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param eraseOption the erase option
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processEraseScreen(int eraseOption) throws IOException {
|
||||
}
|
||||
protected void processEraseScreen(int eraseOption) throws IOException {}
|
||||
|
||||
protected static final int ERASE_LINE_TO_END = 0;
|
||||
protected static final int ERASE_LINE_TO_BEGINING = 1;
|
||||
@ -512,25 +490,27 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param eraseOption the erase option
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processEraseLine(int eraseOption) throws IOException {
|
||||
}
|
||||
protected void processEraseLine(int eraseOption) throws IOException {}
|
||||
|
||||
protected static final int ATTRIBUTE_INTENSITY_BOLD = 1; // Intensity: Bold
|
||||
protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; // Intensity; Faint not widely supported
|
||||
protected static final int ATTRIBUTE_ITALIC = 3; // Italic; on not widely supported. Sometimes treated as inverse.
|
||||
protected static final int ATTRIBUTE_UNDERLINE = 4; // Underline; Single
|
||||
protected static final int ATTRIBUTE_BLINK_SLOW = 5; // Blink; Slow less than 150 per minute
|
||||
protected static final int ATTRIBUTE_BLINK_FAST = 6; // Blink; Rapid MS-DOS ANSI.SYS; 150 per minute or more
|
||||
protected static final int ATTRIBUTE_NEGATIVE_ON =
|
||||
7; // Image; Negative inverse or reverse; swap foreground and background
|
||||
protected static final int ATTRIBUTE_CONCEAL_ON = 8; // Conceal on
|
||||
protected static final int ATTRIBUTE_UNDERLINE_DOUBLE = 21; // Underline; Double not widely supported
|
||||
protected static final int ATTRIBUTE_INTENSITY_NORMAL = 22; // Intensity; Normal not bold and not faint
|
||||
protected static final int ATTRIBUTE_UNDERLINE_OFF = 24; // Underline; None
|
||||
protected static final int ATTRIBUTE_BLINK_OFF = 25; // Blink; off
|
||||
|
||||
protected static final int ATTRIBUTE_INTENSITY_BOLD = 1; // Intensity: Bold
|
||||
protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; // Intensity; Faint not widely supported
|
||||
protected static final int ATTRIBUTE_ITALIC = 3; // Italic; on not widely supported. Sometimes treated as inverse.
|
||||
protected static final int ATTRIBUTE_UNDERLINE = 4; // Underline; Single
|
||||
protected static final int ATTRIBUTE_BLINK_SLOW = 5; // Blink; Slow less than 150 per minute
|
||||
protected static final int ATTRIBUTE_BLINK_FAST = 6; // Blink; Rapid MS-DOS ANSI.SYS; 150 per minute or more
|
||||
protected static final int ATTRIBUTE_NEGATIVE_ON = 7; // Image; Negative inverse or reverse; swap foreground and background
|
||||
protected static final int ATTRIBUTE_CONCEAL_ON = 8; // Conceal on
|
||||
protected static final int ATTRIBUTE_UNDERLINE_DOUBLE = 21; // Underline; Double not widely supported
|
||||
protected static final int ATTRIBUTE_INTENSITY_NORMAL = 22; // Intensity; Normal not bold and not faint
|
||||
protected static final int ATTRIBUTE_UNDERLINE_OFF = 24; // Underline; None
|
||||
protected static final int ATTRIBUTE_BLINK_OFF = 25; // Blink; off
|
||||
@Deprecated
|
||||
protected static final int ATTRIBUTE_NEGATIVE_Off = 27; // Image; Positive
|
||||
|
||||
protected static final int ATTRIBUTE_NEGATIVE_OFF = 27; // Image; Positive
|
||||
protected static final int ATTRIBUTE_CONCEAL_OFF = 28; // Reveal conceal off
|
||||
protected static final int ATTRIBUTE_CONCEAL_OFF = 28; // Reveal conceal off
|
||||
|
||||
/**
|
||||
* process <code>SGR</code> other than <code>0</code> (reset), <code>30-39</code> (foreground),
|
||||
@ -546,8 +526,7 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @see #processDefaultTextColor()
|
||||
* @see #processDefaultBackgroundColor()
|
||||
*/
|
||||
protected void processSetAttribute(int attribute) throws IOException {
|
||||
}
|
||||
protected void processSetAttribute(int attribute) throws IOException {}
|
||||
|
||||
protected static final int BLACK = 0;
|
||||
protected static final int RED = 1;
|
||||
@ -584,8 +563,7 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param paletteIndex the text color in the palette
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
|
||||
}
|
||||
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>SGR 38</code> corresponding to <code>extended set text color (foreground)</code>
|
||||
@ -625,8 +603,7 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param paletteIndex the background color in the palette
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
|
||||
}
|
||||
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>SGR 48</code> corresponding to <code>extended set background color</code>
|
||||
@ -644,22 +621,19 @@ public class AnsiWriter extends FilterWriter {
|
||||
* process <code>SGR 39</code> corresponding to <code>Default text color (foreground)</code>
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processDefaultTextColor() throws IOException {
|
||||
}
|
||||
protected void processDefaultTextColor() throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>SGR 49</code> corresponding to <code>Default background color</code>
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processDefaultBackgroundColor() throws IOException {
|
||||
}
|
||||
protected void processDefaultBackgroundColor() throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>SGR 0</code> corresponding to <code>Reset / Normal</code>
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processAttributeRest() throws IOException {
|
||||
}
|
||||
protected void processAttributeRest() throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>CSI n ; m H</code> corresponding to <code>CUP \u2013 Cursor Position</code> or
|
||||
@ -668,24 +642,21 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param col the column
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processCursorTo(int row, int col) throws IOException {
|
||||
}
|
||||
protected void processCursorTo(int row, int col) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>CSI n G</code> corresponding to <code>CHA \u2013 Cursor Horizontal Absolute</code>
|
||||
* @param x the column
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processCursorToColumn(int x) throws IOException {
|
||||
}
|
||||
protected void processCursorToColumn(int x) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>CSI n F</code> corresponding to <code>CPL \u2013 Cursor Previous Line</code>
|
||||
* @param count line count
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processCursorUpLine(int count) throws IOException {
|
||||
}
|
||||
protected void processCursorUpLine(int count) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>CSI n E</code> corresponding to <code>CNL \u2013 Cursor Next Line</code>
|
||||
@ -704,8 +675,7 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param count the count
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processCursorLeft(int count) throws IOException {
|
||||
}
|
||||
protected void processCursorLeft(int count) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>CSI n C</code> corresponding to <code>CUF \u2013 Cursor Forward</code>
|
||||
@ -724,19 +694,16 @@ public class AnsiWriter extends FilterWriter {
|
||||
* @param count the count
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processCursorDown(int count) throws IOException {
|
||||
}
|
||||
protected void processCursorDown(int count) throws IOException {}
|
||||
|
||||
/**
|
||||
* process <code>CSI n A</code> corresponding to <code>CUU \u2013 Cursor Up</code>
|
||||
* @param count the count
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
protected void processCursorUp(int count) throws IOException {
|
||||
}
|
||||
protected void processCursorUp(int count) throws IOException {}
|
||||
|
||||
protected void processUnknownExtension(ArrayList<Object> options, int command) {
|
||||
}
|
||||
protected void processUnknownExtension(ArrayList<Object> options, int command) {}
|
||||
|
||||
/**
|
||||
* process <code>OSC 0;text BEL</code> corresponding to <code>Change Window and Icon label</code>
|
||||
@ -751,23 +718,20 @@ public class AnsiWriter extends FilterWriter {
|
||||
* process <code>OSC 1;text BEL</code> corresponding to <code>Change Icon label</code>
|
||||
* @param name the icon name
|
||||
*/
|
||||
protected void processChangeIconName(String name) {
|
||||
}
|
||||
protected void processChangeIconName(String name) {}
|
||||
|
||||
/**
|
||||
* process <code>OSC 2;text BEL</code> corresponding to <code>Change Window title</code>
|
||||
* @param title the title
|
||||
*/
|
||||
protected void processChangeWindowTitle(String title) {
|
||||
}
|
||||
protected void processChangeWindowTitle(String title) {}
|
||||
|
||||
/**
|
||||
* Process unknown <code>OSC</code> command.
|
||||
* @param command the command
|
||||
* @param param the param
|
||||
*/
|
||||
protected void processUnknownOperatingSystemCommand(int command, String param) {
|
||||
}
|
||||
protected void processUnknownOperatingSystemCommand(int command, String param) {}
|
||||
|
||||
/**
|
||||
* Process character set sequence.
|
||||
@ -781,17 +745,13 @@ public class AnsiWriter extends FilterWriter {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void processCharsetSelect(int set, char seq) {
|
||||
}
|
||||
protected void processCharsetSelect(int set, char seq) {}
|
||||
|
||||
private int optionInt(ArrayList<Object> options, int index) {
|
||||
if (options.size() <= index)
|
||||
throw new IllegalArgumentException();
|
||||
if (options.size() <= index) throw new IllegalArgumentException();
|
||||
Object value = options.get(index);
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!value.getClass().equals(Integer.class))
|
||||
throw new IllegalArgumentException();
|
||||
if (value == null) throw new IllegalArgumentException();
|
||||
if (!value.getClass().equals(Integer.class)) throw new IllegalArgumentException();
|
||||
return (Integer) value;
|
||||
}
|
||||
|
||||
@ -828,5 +788,4 @@ public class AnsiWriter extends FilterWriter {
|
||||
flush();
|
||||
super.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -15,6 +15,7 @@ import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
|
||||
import jdk.internal.org.jline.utils.InfoCmp.Capability;
|
||||
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTERNATE_CHARSET;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR_EXP;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR;
|
||||
@ -30,12 +31,11 @@ import static jdk.internal.org.jline.utils.AttributedStyle.F_FAINT;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_IND;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_RGB;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_HIDDEN;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_INVERSE;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_ITALIC;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_UNDERLINE;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.F_HIDDEN;
|
||||
import static jdk.internal.org.jline.utils.AttributedStyle.MASK;
|
||||
import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTERNATE_CHARSET;
|
||||
|
||||
public abstract class AttributedCharSequence implements CharSequence {
|
||||
|
||||
@ -120,6 +120,7 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
char c = charAt(i);
|
||||
if (altIn != null && altOut != null) {
|
||||
char pc = c;
|
||||
// @spotless:off
|
||||
switch (c) {
|
||||
case '\u2518': c = 'j'; break;
|
||||
case '\u2510': c = 'k'; break;
|
||||
@ -133,15 +134,16 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
case '\u252C': c = 'w'; break;
|
||||
case '\u2502': c = 'x'; break;
|
||||
}
|
||||
// @spotless:on
|
||||
boolean oldalt = alt;
|
||||
alt = c != pc;
|
||||
if (oldalt ^ alt) {
|
||||
sb.append(alt ? altIn : altOut);
|
||||
}
|
||||
}
|
||||
long s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles
|
||||
long s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles
|
||||
if (style != s) {
|
||||
long d = (style ^ s) & MASK;
|
||||
long d = (style ^ s) & MASK;
|
||||
long fg = (s & F_FOREGROUND) != 0 ? s & (FG_COLOR | F_FOREGROUND) : 0;
|
||||
long bg = (s & F_BACKGROUND) != 0 ? s & (BG_COLOR | F_BACKGROUND) : 0;
|
||||
if (s == 0) {
|
||||
@ -172,16 +174,16 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
if (fg > 0) {
|
||||
int rounded = -1;
|
||||
if ((fg & F_FOREGROUND_RGB) != 0) {
|
||||
int r = (int)(fg >> (FG_COLOR_EXP + 16)) & 0xFF;
|
||||
int g = (int)(fg >> (FG_COLOR_EXP + 8)) & 0xFF;
|
||||
int b = (int)(fg >> FG_COLOR_EXP) & 0xFF;
|
||||
int r = (int) (fg >> (FG_COLOR_EXP + 16)) & 0xFF;
|
||||
int g = (int) (fg >> (FG_COLOR_EXP + 8)) & 0xFF;
|
||||
int b = (int) (fg >> FG_COLOR_EXP) & 0xFF;
|
||||
if (colors >= HIGH_COLORS) {
|
||||
first = attr(sb, "38;2;" + r + ";" + g + ";" + b, first);
|
||||
} else {
|
||||
rounded = palette.round(r, g, b);
|
||||
}
|
||||
} else if ((fg & F_FOREGROUND_IND) != 0) {
|
||||
rounded = palette.round((int)(fg >> FG_COLOR_EXP) & 0xFF);
|
||||
rounded = palette.round((int) (fg >> FG_COLOR_EXP) & 0xFF);
|
||||
}
|
||||
if (rounded >= 0) {
|
||||
if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) {
|
||||
@ -211,16 +213,16 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
if (bg > 0) {
|
||||
int rounded = -1;
|
||||
if ((bg & F_BACKGROUND_RGB) != 0) {
|
||||
int r = (int)(bg >> (BG_COLOR_EXP + 16)) & 0xFF;
|
||||
int g = (int)(bg >> (BG_COLOR_EXP + 8)) & 0xFF;
|
||||
int b = (int)(bg >> BG_COLOR_EXP) & 0xFF;
|
||||
int r = (int) (bg >> (BG_COLOR_EXP + 16)) & 0xFF;
|
||||
int g = (int) (bg >> (BG_COLOR_EXP + 8)) & 0xFF;
|
||||
int b = (int) (bg >> BG_COLOR_EXP) & 0xFF;
|
||||
if (colors >= HIGH_COLORS) {
|
||||
first = attr(sb, "48;2;" + r + ";" + g + ";" + b, first);
|
||||
} else {
|
||||
rounded = palette.round(r, g, b);
|
||||
}
|
||||
} else if ((bg & F_BACKGROUND_IND) != 0) {
|
||||
rounded = palette.round((int)(bg >> BG_COLOR_EXP) & 0xFF);
|
||||
rounded = palette.round((int) (bg >> BG_COLOR_EXP) & 0xFF);
|
||||
}
|
||||
if (rounded >= 0) {
|
||||
if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) {
|
||||
@ -243,8 +245,7 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
background = bg;
|
||||
}
|
||||
if ((d & (F_BOLD | F_FAINT)) != 0) {
|
||||
if ( (d & F_BOLD) != 0 && (s & F_BOLD) == 0
|
||||
|| (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
|
||||
if ((d & F_BOLD) != 0 && (s & F_BOLD) == 0 || (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
|
||||
first = attr(sb, "22", first);
|
||||
}
|
||||
if ((d & F_BOLD) != 0 && (s & F_BOLD) != 0) {
|
||||
@ -360,8 +361,7 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
int len = length();
|
||||
for (int cur = 0; cur < len; ) {
|
||||
int cp = codePointAt(cur);
|
||||
if (!isHidden(cur))
|
||||
cols += WCWidth.wcwidth(cp);
|
||||
if (!isHidden(cur)) cols += WCWidth.wcwidth(cp);
|
||||
cur += Character.charCount(cp);
|
||||
}
|
||||
return cols;
|
||||
@ -382,8 +382,7 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
int end = begin;
|
||||
while (end < this.length()) {
|
||||
int cp = codePointAt(end);
|
||||
if (cp == '\n')
|
||||
break;
|
||||
if (cp == '\n') break;
|
||||
int w = isHidden(end) ? 0 : WCWidth.wcwidth(cp);
|
||||
if (col + w > stop) {
|
||||
break;
|
||||
@ -407,7 +406,7 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
int cp = codePointAt(cur);
|
||||
int w = isHidden(cur) ? 0 : WCWidth.wcwidth(cp);
|
||||
if (cp == '\n') {
|
||||
strings.add(subSequence(beg, includeNewlines ? cur+1 : cur));
|
||||
strings.add(subSequence(beg, includeNewlines ? cur + 1 : cur));
|
||||
beg = cur + 1;
|
||||
col = 0;
|
||||
} else if ((col += w) > columns) {
|
||||
@ -429,5 +428,4 @@ public abstract class AttributedCharSequence implements CharSequence {
|
||||
public AttributedString toAttributedString() {
|
||||
return substring(0, length());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -15,6 +15,8 @@ import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
|
||||
/**
|
||||
* Attributed string.
|
||||
* Instances of this class are immutables.
|
||||
@ -103,11 +105,28 @@ public class AttributedString extends AttributedCharSequence {
|
||||
}
|
||||
|
||||
public static AttributedString fromAnsi(String ansi, List<Integer> tabs) {
|
||||
return fromAnsi(ansi, tabs, null, null);
|
||||
}
|
||||
|
||||
public static AttributedString fromAnsi(String ansi, Terminal terminal) {
|
||||
String alternateIn, alternateOut;
|
||||
if (!DISABLE_ALTERNATE_CHARSET) {
|
||||
alternateIn = Curses.tputs(terminal.getStringCapability(InfoCmp.Capability.enter_alt_charset_mode));
|
||||
alternateOut = Curses.tputs(terminal.getStringCapability(InfoCmp.Capability.exit_alt_charset_mode));
|
||||
} else {
|
||||
alternateIn = null;
|
||||
alternateOut = null;
|
||||
}
|
||||
return fromAnsi(ansi, Arrays.asList(0), alternateIn, alternateOut);
|
||||
}
|
||||
|
||||
public static AttributedString fromAnsi(String ansi, List<Integer> tabs, String altIn, String altOut) {
|
||||
if (ansi == null) {
|
||||
return null;
|
||||
}
|
||||
return new AttributedStringBuilder(ansi.length())
|
||||
.tabs(tabs)
|
||||
.altCharset(altIn, altOut)
|
||||
.ansiAppend(ansi)
|
||||
.toAttributedString();
|
||||
}
|
||||
@ -116,9 +135,7 @@ public class AttributedString extends AttributedCharSequence {
|
||||
if (ansi == null) {
|
||||
return null;
|
||||
}
|
||||
return new AttributedStringBuilder(ansi.length())
|
||||
.ansiAppend(ansi)
|
||||
.toString();
|
||||
return new AttributedStringBuilder(ansi.length()).ansiAppend(ansi).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -162,7 +179,7 @@ public class AttributedString extends AttributedCharSequence {
|
||||
}
|
||||
result = matcher.find();
|
||||
} while (result);
|
||||
return new AttributedString(buffer, newstyle, start , end);
|
||||
return new AttributedString(buffer, newstyle, start, end);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -179,15 +196,16 @@ public class AttributedString extends AttributedCharSequence {
|
||||
|
||||
private boolean arrEq(char[] a1, char[] a2, int s1, int s2, int l) {
|
||||
for (int i = 0; i < l; i++) {
|
||||
if (a1[s1+i] != a2[s2+i]) {
|
||||
if (a1[s1 + i] != a2[s2 + i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean arrEq(long[] a1, long[] a2, int s1, int s2, int l) {
|
||||
for (int i = 0; i < l; i++) {
|
||||
if (a1[s1+i] != a2[s2+i]) {
|
||||
if (a1[s1 + i] != a2[s2 + i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -221,5 +239,4 @@ public class AttributedString extends AttributedCharSequence {
|
||||
}
|
||||
return sb.toAttributedString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
* Copyright (c) 2002-2018, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -27,6 +27,9 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
private long[] style;
|
||||
private int length;
|
||||
private TabStops tabs = new TabStops(0);
|
||||
private char[] altIn;
|
||||
private char[] altOut;
|
||||
private boolean inAltCharset;
|
||||
private int lastLineLength = 0;
|
||||
private AttributedStyle current = AttributedStyle.DEFAULT;
|
||||
|
||||
@ -81,10 +84,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
@Override
|
||||
public AttributedString subSequence(int start, int end) {
|
||||
return new AttributedString(
|
||||
Arrays.copyOfRange(buffer, start, end),
|
||||
Arrays.copyOfRange(style, start, end),
|
||||
0,
|
||||
end - start);
|
||||
Arrays.copyOfRange(buffer, start, end), Arrays.copyOfRange(style, start, end), 0, end - start);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,6 +108,14 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
return append(Character.toString(c));
|
||||
}
|
||||
|
||||
public AttributedStringBuilder append(char c, int repeat) {
|
||||
AttributedString s = new AttributedString(Character.toString(c), current);
|
||||
while (repeat-- > 0) {
|
||||
append(s);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttributedStringBuilder append(CharSequence csq, AttributedStyle style) {
|
||||
return append(new AttributedString(csq, style));
|
||||
}
|
||||
@ -117,12 +125,12 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttributedStringBuilder style(Function<AttributedStyle,AttributedStyle> style) {
|
||||
public AttributedStringBuilder style(Function<AttributedStyle, AttributedStyle> style) {
|
||||
current = style.apply(current);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttributedStringBuilder styled(Function<AttributedStyle,AttributedStyle> style, CharSequence cs) {
|
||||
public AttributedStringBuilder styled(Function<AttributedStyle, AttributedStyle> style, CharSequence cs) {
|
||||
return styled(style, sb -> sb.append(cs));
|
||||
}
|
||||
|
||||
@ -130,7 +138,8 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
return styled(s -> style, sb -> sb.append(cs));
|
||||
}
|
||||
|
||||
public AttributedStringBuilder styled(Function<AttributedStyle,AttributedStyle> style, Consumer<AttributedStringBuilder> consumer) {
|
||||
public AttributedStringBuilder styled(
|
||||
Function<AttributedStyle, AttributedStyle> style, Consumer<AttributedStringBuilder> consumer) {
|
||||
AttributedStyle prev = current;
|
||||
current = style.apply(prev);
|
||||
consumer.accept(this);
|
||||
@ -338,23 +347,90 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
// This is not a SGR code, so ignore
|
||||
ansiState = 0;
|
||||
}
|
||||
} else if (c == '\t' && tabs.defined()) {
|
||||
insertTab(current);
|
||||
} else {
|
||||
ensureCapacity(length + 1);
|
||||
buffer[length] = c;
|
||||
style[length] = this.current.getStyle();
|
||||
if (c == '\n') {
|
||||
lastLineLength = 0;
|
||||
} else {
|
||||
lastLineLength++;
|
||||
if (ansiState >= 1) {
|
||||
ensureCapacity(length + 1);
|
||||
buffer[length++] = 27;
|
||||
if (ansiState >= 2) {
|
||||
ensureCapacity(length + 1);
|
||||
buffer[length++] = '[';
|
||||
}
|
||||
ansiState = 0;
|
||||
}
|
||||
if (c == '\t' && tabs.defined()) {
|
||||
insertTab(current);
|
||||
} else {
|
||||
ensureCapacity(length + 1);
|
||||
if (inAltCharset) {
|
||||
switch (c) {
|
||||
case 'j':
|
||||
c = '\u2518';
|
||||
break;
|
||||
case 'k':
|
||||
c = '\u2510';
|
||||
break;
|
||||
case 'l':
|
||||
c = '\u250C';
|
||||
break;
|
||||
case 'm':
|
||||
c = '\u2514';
|
||||
break;
|
||||
case 'n':
|
||||
c = '\u253C';
|
||||
break;
|
||||
case 'q':
|
||||
c = '\u2500';
|
||||
break;
|
||||
case 't':
|
||||
c = '\u251C';
|
||||
break;
|
||||
case 'u':
|
||||
c = '\u2524';
|
||||
break;
|
||||
case 'v':
|
||||
c = '\u2534';
|
||||
break;
|
||||
case 'w':
|
||||
c = '\u252C';
|
||||
break;
|
||||
case 'x':
|
||||
c = '\u2502';
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer[length] = c;
|
||||
style[length] = this.current.getStyle();
|
||||
if (c == '\n') {
|
||||
lastLineLength = 0;
|
||||
} else {
|
||||
lastLineLength++;
|
||||
}
|
||||
length++;
|
||||
if (altIn != null && altOut != null) {
|
||||
char[] alt = inAltCharset ? altOut : altIn;
|
||||
if (equals(buffer, length - alt.length, alt, 0, alt.length)) {
|
||||
inAltCharset = !inAltCharset;
|
||||
length -= alt.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
length++;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static boolean equals(char[] a, int aFromIndex, char[] b, int bFromIndex, int length) {
|
||||
if (aFromIndex < 0 || bFromIndex < 0 || aFromIndex + length > a.length || bFromIndex + length > b.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (a[aFromIndex + i] != b[bFromIndex + i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void insertTab(AttributedStyle s) {
|
||||
int nb = tabs.spaces(lastLineLength);
|
||||
ensureCapacity(length + nb);
|
||||
@ -393,6 +469,15 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttributedStringBuilder altCharset(String altIn, String altOut) {
|
||||
if (length > 0) {
|
||||
throw new IllegalStateException("Cannot change alternative charset after appending text");
|
||||
}
|
||||
this.altIn = altIn != null ? altIn.toCharArray() : null;
|
||||
this.altOut = altOut != null ? altOut.toCharArray() : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttributedStringBuilder styleMatches(Pattern pattern, AttributedStyle s) {
|
||||
Matcher matcher = pattern.matcher(this);
|
||||
while (matcher.find()) {
|
||||
@ -416,7 +501,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
return this;
|
||||
}
|
||||
|
||||
private class TabStops {
|
||||
private static class TabStops {
|
||||
private List<Integer> tabs = new ArrayList<>();
|
||||
private int lastStop = 0;
|
||||
private int lastSize = 0;
|
||||
@ -428,7 +513,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
public TabStops(List<Integer> tabs) {
|
||||
this.tabs = tabs;
|
||||
int p = 0;
|
||||
for (int s: tabs) {
|
||||
for (int s : tabs) {
|
||||
if (s <= p) {
|
||||
continue;
|
||||
}
|
||||
@ -447,7 +532,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
if (lastLineLength >= lastStop) {
|
||||
out = lastSize - (lastLineLength - lastStop) % lastSize;
|
||||
} else {
|
||||
for (int s: tabs) {
|
||||
for (int s : tabs) {
|
||||
if (s > lastLineLength) {
|
||||
out = s - lastLineLength;
|
||||
break;
|
||||
@ -456,7 +541,5 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -15,39 +15,39 @@ package jdk.internal.org.jline.utils;
|
||||
*/
|
||||
public class AttributedStyle {
|
||||
|
||||
public static final int BLACK = 0;
|
||||
public static final int RED = 1;
|
||||
public static final int GREEN = 2;
|
||||
public static final int YELLOW = 3;
|
||||
public static final int BLUE = 4;
|
||||
public static final int MAGENTA = 5;
|
||||
public static final int CYAN = 6;
|
||||
public static final int WHITE = 7;
|
||||
public static final int BLACK = 0;
|
||||
public static final int RED = 1;
|
||||
public static final int GREEN = 2;
|
||||
public static final int YELLOW = 3;
|
||||
public static final int BLUE = 4;
|
||||
public static final int MAGENTA = 5;
|
||||
public static final int CYAN = 6;
|
||||
public static final int WHITE = 7;
|
||||
|
||||
public static final int BRIGHT = 8;
|
||||
public static final int BRIGHT = 8;
|
||||
|
||||
static final long F_BOLD = 0x00000001;
|
||||
static final long F_FAINT = 0x00000002;
|
||||
static final long F_ITALIC = 0x00000004;
|
||||
static final long F_UNDERLINE = 0x00000008;
|
||||
static final long F_BLINK = 0x00000010;
|
||||
static final long F_INVERSE = 0x00000020;
|
||||
static final long F_CONCEAL = 0x00000040;
|
||||
static final long F_CROSSED_OUT = 0x00000080;
|
||||
static final long F_FOREGROUND_IND = 0x00000100;
|
||||
static final long F_FOREGROUND_RGB = 0x00000200;
|
||||
static final long F_FOREGROUND = F_FOREGROUND_IND | F_FOREGROUND_RGB;
|
||||
static final long F_BACKGROUND_IND = 0x00000400;
|
||||
static final long F_BACKGROUND_RGB = 0x00000800;
|
||||
static final long F_BACKGROUND = F_BACKGROUND_IND | F_BACKGROUND_RGB;
|
||||
static final long F_HIDDEN = 0x00001000;
|
||||
static final long F_BOLD = 0x00000001;
|
||||
static final long F_FAINT = 0x00000002;
|
||||
static final long F_ITALIC = 0x00000004;
|
||||
static final long F_UNDERLINE = 0x00000008;
|
||||
static final long F_BLINK = 0x00000010;
|
||||
static final long F_INVERSE = 0x00000020;
|
||||
static final long F_CONCEAL = 0x00000040;
|
||||
static final long F_CROSSED_OUT = 0x00000080;
|
||||
static final long F_FOREGROUND_IND = 0x00000100;
|
||||
static final long F_FOREGROUND_RGB = 0x00000200;
|
||||
static final long F_FOREGROUND = F_FOREGROUND_IND | F_FOREGROUND_RGB;
|
||||
static final long F_BACKGROUND_IND = 0x00000400;
|
||||
static final long F_BACKGROUND_RGB = 0x00000800;
|
||||
static final long F_BACKGROUND = F_BACKGROUND_IND | F_BACKGROUND_RGB;
|
||||
static final long F_HIDDEN = 0x00001000;
|
||||
|
||||
static final long MASK = 0x00001FFF;
|
||||
static final long MASK = 0x00001FFF;
|
||||
|
||||
static final int FG_COLOR_EXP = 15;
|
||||
static final int BG_COLOR_EXP = 39;
|
||||
static final long FG_COLOR = 0xFFFFFFL << FG_COLOR_EXP;
|
||||
static final long BG_COLOR = 0xFFFFFFL << BG_COLOR_EXP;
|
||||
static final int FG_COLOR_EXP = 15;
|
||||
static final int BG_COLOR_EXP = 39;
|
||||
static final long FG_COLOR = 0xFFFFFFL << FG_COLOR_EXP;
|
||||
static final long BG_COLOR = 0xFFFFFFL << BG_COLOR_EXP;
|
||||
|
||||
public static final AttributedStyle DEFAULT = new AttributedStyle();
|
||||
public static final AttributedStyle BOLD = DEFAULT.bold();
|
||||
@ -70,8 +70,9 @@ public class AttributedStyle {
|
||||
|
||||
public AttributedStyle(long style, long mask) {
|
||||
this.style = style;
|
||||
this.mask = mask & MASK | ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0)
|
||||
| ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0);
|
||||
this.mask = mask & MASK
|
||||
| ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0)
|
||||
| ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0);
|
||||
}
|
||||
|
||||
public AttributedStyle bold() {
|
||||
@ -176,7 +177,9 @@ public class AttributedStyle {
|
||||
}
|
||||
|
||||
public AttributedStyle foreground(int color) {
|
||||
return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND_IND | (((long) color << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND_IND);
|
||||
return new AttributedStyle(
|
||||
style & ~FG_COLOR | F_FOREGROUND_IND | (((long) color << FG_COLOR_EXP) & FG_COLOR),
|
||||
mask | F_FOREGROUND_IND);
|
||||
}
|
||||
|
||||
public AttributedStyle foreground(int r, int g, int b) {
|
||||
@ -184,7 +187,9 @@ public class AttributedStyle {
|
||||
}
|
||||
|
||||
public AttributedStyle foregroundRgb(int color) {
|
||||
return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND_RGB | ((((long) color & 0xFFFFFF) << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND_RGB);
|
||||
return new AttributedStyle(
|
||||
style & ~FG_COLOR | F_FOREGROUND_RGB | ((((long) color & 0xFFFFFF) << FG_COLOR_EXP) & FG_COLOR),
|
||||
mask | F_FOREGROUND_RGB);
|
||||
}
|
||||
|
||||
public AttributedStyle foregroundOff() {
|
||||
@ -196,7 +201,9 @@ public class AttributedStyle {
|
||||
}
|
||||
|
||||
public AttributedStyle background(int color) {
|
||||
return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND_IND | (((long) color << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND_IND);
|
||||
return new AttributedStyle(
|
||||
style & ~BG_COLOR | F_BACKGROUND_IND | (((long) color << BG_COLOR_EXP) & BG_COLOR),
|
||||
mask | F_BACKGROUND_IND);
|
||||
}
|
||||
|
||||
public AttributedStyle background(int r, int g, int b) {
|
||||
@ -204,7 +211,9 @@ public class AttributedStyle {
|
||||
}
|
||||
|
||||
public AttributedStyle backgroundRgb(int color) {
|
||||
return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND_RGB | ((((long) color & 0xFFFFFF) << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND_RGB);
|
||||
return new AttributedStyle(
|
||||
style & ~BG_COLOR | F_BACKGROUND_RGB | ((((long) color & 0xFFFFFF) << BG_COLOR_EXP) & BG_COLOR),
|
||||
mask | F_BACKGROUND_RGB);
|
||||
}
|
||||
|
||||
public AttributedStyle backgroundOff() {
|
||||
@ -249,7 +258,6 @@ public class AttributedStyle {
|
||||
AttributedStyle that = (AttributedStyle) o;
|
||||
if (style != that.style) return false;
|
||||
return mask == that.mask;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -266,10 +274,6 @@ public class AttributedStyle {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AttributedStyle{" +
|
||||
"style=" + style +
|
||||
", mask=" + mask +
|
||||
", ansi=" + toAnsi() +
|
||||
'}';
|
||||
return "AttributedStyle{" + "style=" + style + ", mask=" + mask + ", ansi=" + toAnsi() + '}';
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2016, the original author or authors.
|
||||
* Copyright (c) 2002-2016, the original author(s).
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -14,8 +14,7 @@ public class ClosedException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 3085420657077696L;
|
||||
|
||||
public ClosedException() {
|
||||
}
|
||||
public ClosedException() {}
|
||||
|
||||
public ClosedException(String message) {
|
||||
super(message);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user