-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8352693: Use a simpler console reader instead of JLine for System.console() #24242
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
Conversation
|
👋 Welcome back jlahoda! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
Webrevs
|
|
Can you coordinate with Naoto on this? There is a CSR in progress to switch Console back to using the java.base implementation by default. |
| } | ||
| } | ||
|
|
||
| private static void doReadImpl(Reader reader, Writer out, boolean password, int firstLineOffset, IntSupplier terminalWidthSupplier, CleanableBuffer result) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These overly long lines make it really hard to see the changes going forward so I think trim back some of these to make it easy to look at diffs in the future.
| java.management, | ||
| java.rmi, | ||
| jdk.charsets, | ||
| jdk.internal.le, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What code in JLine is using shared secrets? I wonder what we need to change to avoid this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, sorry. I forgot to remove these (qualified export of jdk.internal.access and sun.nio.cs) after a refactoring. Will remove them in a next update.
| exports sun.nio.cs to | ||
| jdk.charsets; | ||
| jdk.charsets, | ||
| jdk.internal.le; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing here.
Right - but that still keeps the existing JLine-based provider, and so the problems it has still exist (albeit with a lower severity). This proposal is not the only sole possibility, of course. Other possibilities include removing the JLine-based provider, or fixing the problems in the JLine provider one-by-one. I don't object to any of these possibilities, although I didn't want to offer them in the first step. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not very familiar with those escape sequences/modes in the native console, but looks good to me. Sharing the common part as the base looks reasonable.
| case 127: | ||
| //backspace: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it delete?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. Delete is an escape sequence (\033[3~).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that's interesting. In ASCII control codes, 127 is defined as Delete and 08 is defined as Backspace
| } | ||
|
|
||
| if (it.hasNext()) { | ||
| out.append("\n\r"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand this is a simple console, but do we want to CR/LF/CRLF based on the platform?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line.seprator system property can be used here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the terminal is in the raw/unprocessed mode, I believe \n is only moving the cursor to the next line (without changing the column), and \r is doing carriage return. So, to move the cursor to the first character of the next line, both are needed.
|
|
||
| #include <stdlib.h> | ||
| #include <Windows.h> | ||
| //#include <wincon.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you really check in new files with commented-out code?
make/modules/jdk.internal.le/Lib.gmk
Outdated
| NAME := le, \ | ||
| TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ | ||
| OPTIMIZATION := LOW, \ | ||
| JDK_LIBS := java.base:libjava, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick glance through the native code revealed no obvious calls to libjava functions. Are you sure this dependency is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHECK_NULL is used by the native code, originating in jni_util.h. But, looking at other libraries, seems that
EXTRA_HEADER_DIRS := java.base:libjava,
should be enough (i.e. replacing JDK_LIBS with EXTRA_HEADER_DIRS). Is there some even better way?
make/modules/jdk.internal.le/Lib.gmk
Outdated
| LIBS_unix := $(JDKLIB_LIBS) $(LIBCXX), \ | ||
| LIBS_windows := $(JDKLIB_LIBS) user32.lib, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JDKLIB_LIBS is not used anymore.
make/modules/jdk.internal.le/Lib.gmk
Outdated
| TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ | ||
| OPTIMIZATION := LOW, \ | ||
| JDK_LIBS := java.base:libjava, \ | ||
| LIBS_unix := $(JDKLIB_LIBS) $(LIBCXX), \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LIBCXX is added automatically nowadays, so you can remove this entire line.
make/modules/jdk.internal.le/Lib.gmk
Outdated
| $(eval $(call SetupJdkLibrary, BUILD_LIBLE, \ | ||
| NAME := le, \ | ||
| TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ | ||
| OPTIMIZATION := LOW, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are trying to move away from using LOW as a default optimization level. If you believe this library is not performance critical, please use SIZE as the new default. Or, use HIGHEST if that gives performance benefits with no significant impact on library size.
|
|
||
| ################################################################################ | ||
|
|
||
| ifeq ($(call isTargetOs, linux macosx windows), true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to sync with the AIX guys to see if this should be enabled there as well. The unix version seems quite portable, so I assume it will work with very few adjustments, if any. @MBaesken
Otherwise, what will happen if you try to run this on a platform without the corresponding native library?
| caret--; | ||
| } | ||
| continue READ; | ||
| case '\033': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is meant to be platform-agnostic, is it really safe to make these assumptions about the ability to produce or interpret escape codes and to make assumptions about their behavior on the user's terminal? I don't think it would even be safe to assume a single terminal type or interpretation on POSIX-type OSes; that's what things like terminfo/termcap are supposed to be for, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory, yes, that's what terminfo is supposed to do. But terminfo has its own set of problems, and what we get from a terminal and what we send to the terminal is so simple and generally supported, that it should be possible to make it work on all realistic terminals(*). Or is there a particular terminal you have in mind?
(*) I admit I've forgot that \E[7~/\E[8~ is Home/End as well. I'll fix that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose I don't have a particular terminal in mind. But at the very least, maybe some documentation somewhere should reference e.g. ECMA-48 as the basis for the behaviors of the console?
|
@lahodaj this pull request can not be integrated into git checkout JDK-8352693
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
|
I have updated the PR based on most of the review comments so far:
|
| ################################################################################ | ||
|
|
||
| ifeq ($(call isTargetOs, linux macosx windows), true) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please insert the standardized header we use for native libraries? (These are extremely helpful to find/locate where certain libraries are built, since there is no existing proper IDE support for makefiles.)
| ############################################################################## | |
| ## Build lible | |
| ############################################################################## | |
|
|
||
| protected final Charset charset; | ||
| protected final Object readLock; | ||
| protected final Object writeLock; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recommend mentioning that when both locks must be acquired, the writeLock must be acquired first. Unfortunately we cannot just use a ReentrantReadWriteLock.
| protected abstract char[] readline(boolean password) throws IOException; | ||
|
|
||
| @SuppressWarnings("this-escape") | ||
| public BaseJdkConsoleImpl(Charset charset) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public BaseJdkConsoleImpl(Charset charset) { | |
| protected BaseJdkConsoleImpl(Charset charset) { |
| protected final PrintWriter pw; | ||
| protected final Formatter formatter; | ||
|
|
||
| protected abstract char[] readline(boolean password) throws IOException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend a more distinct method name, like nextLine or implReadLine; using readline to distinguish from readLine is weird.
| return charset; | ||
| } | ||
|
|
||
| protected char[] readline(boolean password) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Override
| package jdk.internal.console; | ||
|
|
||
| @SuppressWarnings("serial") | ||
| public class LastErrorException extends RuntimeException{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public class LastErrorException extends RuntimeException{ | |
| public class LastErrorException extends RuntimeException { |
| /** | ||
| * JdkConsole implementation based on the platform's TTY, with basic keyboard navigation. | ||
| */ | ||
| public final class JdkConsoleImpl extends BaseJdkConsoleImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should choose a different simple name for this class, especially when we are importing classes from jdk.internal.io package.
|
@lahodaj This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a |
|
@lahodaj This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
The
java.io.Consolehas several backends: a simple on injava.base, a more convenient one injdk.internal.le(with line-reading based on JLine) and one for JShell.The backend based on JLine is proving to be a somewhat problematic - JLine is very powerful, possibly too powerful and complex for the simple task of editing a line with no completion, no history, no variables, no commands, etc. As a consequence, there are inevitable sharp edges in this backend.
The idea in this PR is to replace the use of JLine in the
jdk.internal.lebackend with a simple escape code interpreter, that only handles a handful of keys/codes (left/right arrow, home, end, delete, backspace, enter), and ignores the rest. The goal is to have something simple with less surprising behavior.Progress
Warnings
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/24242/head:pull/24242$ git checkout pull/24242Update a local copy of the PR:
$ git checkout pull/24242$ git pull https://git.openjdk.org/jdk.git pull/24242/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 24242View PR using the GUI difftool:
$ git pr show -t 24242Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/24242.diff
Using Webrev
Link to Webrev Comment