Skip to content

Commit

Permalink
Provide a new Terminal InputFlag INORMEOL to normalize end of lines (#…
Browse files Browse the repository at this point in the history
…900, fixes #899)
  • Loading branch information
gnodet authored Dec 21, 2023
1 parent af7777d commit d733739
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 7 deletions.
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

0 comments on commit d733739

Please sign in to comment.