diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 8ae4fc00773..d8ba0439d47 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -172,6 +172,19 @@ public sealed class Console implements Flushable permits ProxyingConsole { throw newUnsupportedOperationException(); } + /** + * Terminates the current line in this console's output stream using + * {@link System#lineSeparator()} and then flushes the console. + * + * @return This console + * + * @since 24 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console println() { + return println(""); + } + /** * Writes a string representation of the specified object to this console's * output stream and then flushes the console. @@ -214,6 +227,24 @@ public sealed class Console implements Flushable permits ProxyingConsole { throw newUnsupportedOperationException(); } + /** + * Reads a single line of text from this console. + * + * @throws IOError + * If an I/O error occurs. + * + * @return A string containing the line read from the console, not + * including any line-termination characters, or {@code null} + * if an end of stream has been reached without having read + * any characters. + * + * @since 24 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public String readln() { + throw newUnsupportedOperationException(); + } + /** * Writes a formatted string to this console's output stream using * the specified format string and arguments with the diff --git a/src/java.base/share/classes/java/io/IO.java b/src/java.base/share/classes/java/io/IO.java index 7485f87f03f..a49a51041fc 100644 --- a/src/java.base/share/classes/java/io/IO.java +++ b/src/java.base/share/classes/java/io/IO.java @@ -63,6 +63,21 @@ public final class IO { con().println(obj); } + /** + * Terminates the current line on the system console and then flushes + * that console. + * + *
The effect is as if {@link Console#println() println()} + * had been called on {@code System.console()}. + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + * @since 24 + */ + public static void println() { + con().println(); + } + /** * Writes a string representation of the specified object to the system * console and then flushes that console. @@ -99,6 +114,24 @@ public final class IO { return con().readln(prompt); } + /** + * Reads a single line of text from the system console. + * + *
The effect is as if {@link Console#readln() readln()}
+ * had been called on {@code System.console()}.
+ *
+ * @return a string containing the line read from the system console, not
+ * including any line-termination characters. Returns {@code null} if an
+ * end of stream has been reached without having read any characters.
+ *
+ * @throws IOError if {@code System.console()} returns {@code null},
+ * or if an I/O error occurs
+ * @since 24
+ */
+ public static String readln() {
+ return con().readln();
+ }
+
private static Console con() {
var con = System.console();
if (con != null) {
diff --git a/src/java.base/share/classes/java/io/ProxyingConsole.java b/src/java.base/share/classes/java/io/ProxyingConsole.java
index 1babceb665f..cc5cd926264 100644
--- a/src/java.base/share/classes/java/io/ProxyingConsole.java
+++ b/src/java.base/share/classes/java/io/ProxyingConsole.java
@@ -117,6 +117,18 @@ final class ProxyingConsole extends Console {
}
}
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IOError {@inheritDoc}
+ */
+ @Override
+ public String readln() {
+ synchronized (readLock) {
+ return delegate.readln();
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java
index 6c911ed6fed..08bd840de37 100644
--- a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java
+++ b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java
@@ -41,6 +41,7 @@ public interface JdkConsole {
JdkConsole println(Object obj);
JdkConsole print(Object obj);
String readln(String prompt);
+ String readln();
JdkConsole format(Locale locale, String format, Object ... args);
String readLine(Locale locale, String format, Object ... args);
String readLine();
diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java
index a1086b245d1..3c0afd2005c 100644
--- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java
+++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java
@@ -90,6 +90,21 @@ public final class JdkConsoleImpl implements JdkConsole {
return line;
}
+ @Override
+ public String readln() {
+ String line = null;
+ synchronized(readLock) {
+ try {
+ char[] ca = readline(false);
+ if (ca != null)
+ line = new String(ca);
+ } catch (IOException x) {
+ throw new IOError(x);
+ }
+ }
+ return line;
+ }
+
@Override
public JdkConsole format(Locale locale, String format, Object ... args) {
formatter.format(locale, format, args).flush();
diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
index f40b9662625..11de96b7fc3 100644
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
@@ -98,6 +98,11 @@ public class JdkConsoleProviderImpl implements JdkConsoleProvider {
return getDelegate(true).readln(prompt);
}
+ @Override
+ public String readln() {
+ return getDelegate(true).readln();
+ }
+
@Override
public JdkConsole format(Locale locale, String format, Object... args) {
JdkConsole delegate = getDelegate(false);
@@ -224,6 +229,11 @@ public class JdkConsoleProviderImpl implements JdkConsoleProvider {
}
}
+ @Override
+ public String readln() {
+ return readLine();
+ }
+
@Override
public JdkConsole format(Locale locale, String format, Object ... args) {
writer().format(locale, format, args).flush();
@@ -242,7 +252,12 @@ public class JdkConsoleProviderImpl implements JdkConsoleProvider {
@Override
public String readLine() {
- return readLine(Locale.getDefault(Locale.Category.FORMAT), "");
+ try {
+ initJLineIfNeeded();
+ return jline.readLine();
+ } catch (EndOfFileException eofe) {
+ return null;
+ }
}
@Override
diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java
index 339a3005d7d..e22d927911c 100644
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java
@@ -67,6 +67,10 @@ abstract class IOContext implements AutoCloseable {
throw new UserInterruptException("");
}
+ public String readUserLine() throws IOException {
+ throw new UserInterruptException("");
+ }
+
public Writer userOutput() {
throw new UnsupportedOperationException();
}
diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
index 2d06ffc529d..d2d2ed10e63 100644
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
@@ -4112,6 +4112,15 @@ public class JShellTool implements MessageHandler {
}
}
+ @Override
+ public String readLine() throws IOError {
+ try {
+ return input.readUserLine();
+ } catch (IOException ex) {
+ throw new IOError(ex);
+ }
+ }
+
@Override
public char[] readPassword(String prompt) {
try {
diff --git a/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java b/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java
index fe73d6965cb..014766f9ff7 100644
--- a/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java
+++ b/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java
@@ -28,6 +28,7 @@ import java.io.IOError;
import java.io.PrintWriter;
import java.io.Reader;
import java.nio.charset.Charset;
+import jdk.internal.javac.PreviewFeature;
/**
* An interface providing functionality for {@link java.io.Console} in the user's snippet.
@@ -75,6 +76,21 @@ public interface JShellConsole {
*/
public String readLine(String prompt) throws IOError;
+ /**
+ * Reads a single line of text from the console.
+ *
+ * @throws IOError
+ * If an I/O error occurs.
+ *
+ * @return A string containing the line read from the console, not
+ * including any line-termination characters, or {@code null}
+ * if an end of stream has been reached.
+ * @see java.io.Console#readLine()
+ * @since 24
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.IMPLICIT_CLASSES)
+ public String readLine() throws IOError;
+
/**
* Provides a prompt, then reads a password or passphrase from
* the console with echoing disabled.
diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java
index b85b8c9ea0f..876f61ec856 100644
--- a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java
+++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java
@@ -233,6 +233,16 @@ public class ConsoleImpl {
}
}
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IOError {@inheritDoc}
+ */
+ @Override
+ public String readln() {
+ return readLine();
+ }
+
/**
* {@inheritDoc}
*/
@@ -269,7 +279,15 @@ public class ConsoleImpl {
*/
@Override
public String readLine() {
- return readLine(Locale.getDefault(Locale.Category.FORMAT), "");
+ try {
+ return sendAndReceive(() -> {
+ remoteInput.write(Task.READ_LINE_NO_PROMPT.ordinal());
+ char[] line = readChars();
+ return new String(line);
+ });
+ } catch (IOException ex) {
+ throw new IOError(ex);
+ }
}
/**
@@ -404,6 +422,12 @@ public class ConsoleImpl {
bp = 0;
}
}
+ case READ_LINE_NO_PROMPT -> {
+ String line = console.readLine();
+ char[] chars = line.toCharArray();
+ sendChars(sinkOutput, chars, 0, chars.length);
+ bp = 0;
+ }
case READ_PASSWORD -> {
char[] data = readCharsOrNull(1);
if (data != null) {
@@ -478,6 +502,7 @@ public class ConsoleImpl {
FLUSH_OUTPUT,
READ_CHARS,
READ_LINE,
+ READ_LINE_NO_PROMPT,
READ_PASSWORD,
FLUSH_CONSOLE,
CHARSET,
diff --git a/test/jdk/java/io/IO/IO.java b/test/jdk/java/io/IO/IO.java
index 328c189fb2f..e4da1742030 100644
--- a/test/jdk/java/io/IO/IO.java
+++ b/test/jdk/java/io/IO/IO.java
@@ -21,6 +21,7 @@
* questions.
*/
+import java.io.Writer;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -33,6 +34,7 @@ import jdk.test.lib.process.ProcessTools;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
@@ -48,7 +50,7 @@ import static org.junit.jupiter.api.Assertions.*;
/*
* @test
- * @bug 8305457
+ * @bug 8305457 8342936
* @summary java.io.IO tests
* @library /test/lib
* @run junit IO
@@ -131,22 +133,26 @@ public class IO {
var testSrc = System.getProperty("test.src", ".");
var command = new ArrayList