Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a new Terminal InputFlag INORMEOL to normalize end of lines (fixes #899) #900

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
*/
package org.jline.terminal.impl;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -51,6 +53,43 @@ public void tearDown() {
System.clearProperty(TerminalBuilder.PROP_PROVIDERS);
}

@Test
void testEOL() throws IOException {
{
PipedInputStream in = new PipedInputStream();
PipedOutputStream outIn = new PipedOutputStream(in);
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
outIn.write("abc\rdef\nghi\r\njkl\r".getBytes());

assertEquals("abc", reader.readLine());
assertEquals("def", reader.readLine());
assertEquals("ghi", reader.readLine());
assertEquals("jkl", reader.readLine());
}
{
PipedInputStream in = new PipedInputStream();
PipedOutputStream outIn = new PipedOutputStream(in);
ByteArrayOutputStream out = new ByteArrayOutputStream();
outIn.write("abc\rdef\nghi\r\njkl\n".getBytes());

Terminal terminal = TerminalBuilder.builder()
.type("ansi")
.streams(in, out)
.paused(true)
.build();
LineReader reader = LineReaderBuilder.builder().terminal(terminal).build();
Attributes attributes = terminal.getAttributes();
attributes.setInputFlag(InputFlag.INORMEOL, true);
terminal.setAttributes(attributes);
terminal.resume();

assertEquals("abc", reader.readLine());
assertEquals("def", reader.readLine());
assertEquals("ghi", reader.readLine());
assertEquals("jkl", reader.readLine());
}
}

@Test
public void testInput() throws IOException, InterruptedException {
PipedInputStream in = new PipedInputStream();
Expand Down
4 changes: 3 additions & 1 deletion terminal/src/main/java/org/jline/terminal/Attributes.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public enum InputFlag {
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 */
IUTF8, /* maintain state for UTF-8 VERASE */

INORMEOL /* normalize end-of-line */
}

/*
Expand Down
28 changes: 26 additions & 2 deletions terminal/src/main/java/org/jline/terminal/impl/AbstractPty.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.jline.terminal.impl;

import java.io.FileDescriptor;
import java.io.FilterInputStream;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -34,6 +35,7 @@ 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;
Expand All @@ -49,10 +51,32 @@ public void setAttr(Attributes attr) throws IOException {
@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;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public abstract class AbstractWindowsTerminal<Console> extends AbstractTerminal
protected MouseTracking tracking = MouseTracking.Off;
protected boolean focusTracking = false;
private volatile boolean closing;
protected boolean skipNextLf;

@SuppressWarnings("this-escape")
public AbstractWindowsTerminal(
Expand Down Expand Up @@ -496,7 +497,19 @@ public void processInputChar(char c) throws IOException {
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;
}
Expand Down
15 changes: 14 additions & 1 deletion terminal/src/main/java/org/jline/terminal/impl/DumbTerminal.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class DumbTerminal extends AbstractTerminal {
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);
Expand Down Expand Up @@ -79,7 +80,19 @@ public int read(long timeout, boolean isPeek) throws IOException {
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ public class LineDisciplineTerminal extends AbstractTerminal {

protected final Size size;

protected boolean skipNextLf;

public LineDisciplineTerminal(String name, String type, OutputStream masterOutput, Charset encoding)
throws IOException {
this(name, type, masterOutput, encoding, SignalHandler.SIG_DFL);
Expand Down Expand Up @@ -253,7 +255,19 @@ protected boolean doProcessInputByte(int c) throws IOException {
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ protected void doSetAttr(Attributes attr) throws IOException {
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());
}
}
Expand Down
Loading