jline2 print "^J" when it should print "\n" on a telnet console
Asked Answered
T

1

8

I am using JLine 2 (v2.13) in conjunction with a Socket IO to create an admin console for my app which can be accessed via an ordinary telnet client. However I found it prints out strange symbols when it should print out a line break:

act.app.restart  restart app^Jact.job.list  List jobs

The correct output should be:

act.app.restart  restart app
act.job.list     List jobs

I traced into the code and found the following line of code that caused the trouble:

enter image description here

Another weird thing is when I press the up arrow to get the history, the console prints out ^[[A and nothing else happens.

Does anyone have any idea?

Update: added relevant source code

  1. The code accepting the incoming telnet connection:

enter image description here

  1. The code that creates the ConsoleReader and dispatches the command:

enter image description here

Update 2

Sorry I've disappeared for a while. Just come back as my project gives me a breath of fresh air. So here is what happened: I've created a PrintWriter and use it as a workaround for the ^J issue:

enter image description here

However there are many other issues when jline2 is used along with telnet session:

  1. Type <TAB> displays tab instead of activate complete list. However after I hit enter key it gives me a complete list plus an error message: enter image description here
  2. Type <UP> arrow, displays ^[[A, hit enter key it will execute my last command. However I lost the command line editing

The issue is still there and I believe there should be a way to solve it just need some guide...

Tipi answered 25/12, 2015 at 23:46 Comment(10)
Do you have the terminal configured for the client you are using? The characters you are seeing are probably escape sequences used to position the cursor, which should make sense to the client you are using unless there is a mismatch, e.g., ANSI instead of vt-100 or windows instead of unix. Make sure you are configuring the terminal application properly. Look into TerminalType AUTO for example.Salesin
I am on linux mint 17.3, use the plain telnet to connect to the Java server. And the code to respond the telnet connection request is github.com/actframework/actframework/blob/master/src/main/java/….Tipi
BTW, I couldn't find the class TerminalType in jline2 source code. Can you put a link here?Tipi
I just looked at the Javadoc's. The TerminalFactory has the enum: jline.github.io/jline2/apidocs/reference/jline/…Salesin
It's not obvious without setting up the program locally what's going on. The problem you are describing seems like terminal configuration mismatch. Beyond that, it's difficult to say. github.com/actframework/actframework/blob/master/src/main/java/…Salesin
The TelnetTerminal is someone I want to implement, however it's not finished because I don't have the ideal how to deal with it. I didn't pass my Terminal to the ConsoleReader constructor and it just use the TerminalFactory.get() to get an arbitrary terminal. In my system it will be the jline.UnixTerminal. I just don't know how to configure it to make it work. I will create a simple project to demonstrate itTipi
It should be straight forward to write a quick and dirty program that instantiates TelnetTerminal so you can get a better understanding. You might also try stty --all in the terminal window on the unix client to see what the configuration is. For sockets you should probably make sure you are in 8 bit raw mode.Salesin
You might have to set the telnet session's terminal type using option 24 (see pcmicro.com/netfoss/telnet.html for more info).Blackhead
thanks @LodewijkBogaards, how can I set the terminal type with 24 option? I mean which API should I use?Tipi
@green it seems to me from looking at the RFC it is just a matter of sending a few of the right bytes. There might be some libraries out there that could help you. You might want to use wireshark or some other sniffing tool to see what other proper telnet connections use.Blackhead
R
0

Edit: My bad, the method I showed is private. Still, it's not a bug -it's code doing what it should be doing. The two public methods that use rawPrint (I put them at the end) use it only for masked output and apparently for printing completions, so ConsoleReader probably doesn't support your use case -it might be a design bug, but I think its meant to be that way. The arrow key problems are mentioned in the docs in passing as a terminal configuration issue.

ConsoleReader.java is here: https://github.com/jline/jline2/blob/master/src/main/java/jline/console/ConsoleReader.java

I think it's the last version, etc.

What you are doing is creating a ConsoleReader the calling println() on it. LF is shown as ^J. This is not a bug in the sense that the method is doing what it's supposed to do:

/*3478*/ public void println(final CharSequence s) throws IOException {
    print(s);
    println();
}

which eventually calls

/*3445*/private int print(final CharSequence buff, int start, int end, int cursorPos) throws IOException {
        checkNotNull(buff);
        for (int i = start; i < end; i++) {
            char c = buff.charAt(i);
            if (c == '\t') {
                int nb = nextTabStop(cursorPos);
                cursorPos += nb;
                while (nb-- > 0) {
                    out.write(' ');
                }
            } else if (c < 32) {
                out.write('^');
                out.write((char) (c + '@')); //LF -> ^J

This function does what you want but is private:

/*3510*/ private void rawPrintln(final String s) throws IOException {
    rawPrint(s); //
    println();
}

/*3499*/ final void rawPrint(final String str) throws IOException {
    out.write(str);
    cursorOk = false;
}

It can be called through the public methods putString(final CharSequence str) at line 895 and printColumns(final Collection items) at line 3715. putString only calls it when using masked output so it's useless to you, and printColumns seems to be meant for completions.

Maybe you are supposed to print lines separately and let ConsoleReader add newlines to them? Technically, LF is a control code and it makes sense to forbid ConsoleReader to print control codes as is. Just split your input in lines, print them one by one.

Radiobroadcast answered 3/1, 2016 at 11:1 Comment(1)
I've already used an external PrintWriter to workaround the ^J issue temporarily. However there are more weird things than ^J. I type in a <TAB> to activate Completer however it displays the tab, and when I hit enter, it shows the complete list, and then says "Command not recognized: xxx". I type <UP> arrow to get my last command, it shows ^[[A, when I hit <ENTER>, it does execute my last command, however I lost my command line editingTipi

© 2022 - 2024 — McMap. All rights reserved.