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

Dynamically detect terminal size #634

Closed
remkop opened this issue Feb 19, 2019 · 9 comments
Closed

Dynamically detect terminal size #634

remkop opened this issue Feb 19, 2019 · 9 comments

Comments

@remkop
Copy link
Owner

remkop commented Feb 19, 2019

The simplest solution is to rely on the LINES and COLUMNS environment variables. (Update: these are bash variables and may not be available as env variables unless explicitly exported...)

  • In bash, these are set if shopt -s checkwinsize is set. Apparently this is enabled by default.
  • In zsh, apparently these are set automatically

Alternatively (more advanced), the Lantern project (#633) shows how this can be done with ANSI escape sequences.

Example implementation to get the terminal size:

import java.io.IOException;

public class WinSize {
    /*
      /bin/stty -echo; /bin/stty -icanon; /bin/stty min 1; java WinSize; /bin/stty echo; /bin/stty icanon;
     */
    public static void main(String... args) throws IOException {
        String[] signals = new String[] {
                "\u001b[s",            // save cursor position
                "\u001b[5000;5000H",   // move to col 5000 row 5000
                "\u001b[6n",           // request cursor position
                "\u001b[u",            // restore cursor position
        };
        for (String s : signals) {
            System.out.print(s);
        }
        int read = -1;
        StringBuilder sb = new StringBuilder();
        byte[] buff = new byte[1];
        while ((read = System.in.read(buff, 0, 1)) != -1) {
            sb.append((char) buff[0]);
            //System.err.printf("Read %s chars, buf size=%s%n", read, sb.length());
            if ('R' == buff[0]) {
                break;
            }
        }
        String size = sb.toString();
        int rows = Integer.parseInt(size.substring(size.indexOf("\u001b[") + 2, size.indexOf(';')));
        int cols = Integer.parseInt(size.substring(size.indexOf(';') + 1, size.indexOf('R')));
        System.err.printf("rows = %s, cols = %s%n", rows, cols);
    }
}
@remkop remkop added this to the 4.0 milestone Feb 19, 2019
@remkop remkop modified the milestones: 4.0, 4.0-beta-1 May 13, 2019
@remkop remkop modified the milestones: 4.0-beta-1, 4.0 May 28, 2019
@remkop
Copy link
Owner Author

remkop commented Jun 14, 2019

API to enable this:

  • Command: usageHelpAutoWidth: boolean
  • UsageMessageSpec: autoWidth: boolean
  • If system property "picocli.usage.width" has value AUTO or TERM or TERMINAL, then autoWidth becomes true
  • CommandLine: get/setUsageHelpAutoWidth : boolean

@yschimke
Copy link

FWIW I've done this with https://github.com/yschimke/oksocial-output/blob/master/src/main/kotlin/com/baulsupp/oksocial/output/ConsoleHandler.kt#L179

I'd love to switch to whatever you come up with particularly if it doesn't require launching commands etc.

@remkop
Copy link
Owner Author

remkop commented Jun 16, 2019

Thanks for the link, just saw that. (Wasn't aware of the -f vs -F difference for MacOS, that's a good catch!)
I am working on this right now, once I get it to work I'm planning to release 4.0.0-beta-2.

My current approach is similar to what you did in ConsoleHandler, but still experimenting with various approaches to find something that also works in Cygwin. What the Lantern project is doing with the ANSI escape sequences may work, but also depends on executing (a number of) commands: bin/stty -echo; /bin/stty -icanon; /bin/stty min 1; for setup, then /bin/stty echo; /bin/stty icanon; for teardown...

@charphi
Copy link
Contributor

charphi commented Jun 20, 2019

FYI, here are two other ways to get the console width:

  • Powershell: powershell -command (Get-Host).ui.rawui.windowsize.width
  • MingwXterm: tput cols

@remkop
Copy link
Owner Author

remkop commented Jun 20, 2019

@charphi picocli 4.0.0-beta-2 should work (be able to detect the terminal width) with Powershell and MINGW. Is this not working correctly?

@charphi
Copy link
Contributor

charphi commented Jun 20, 2019

I've not tested it yet.
My comment was just alternatives in case of problem.

@remkop
Copy link
Owner Author

remkop commented Jun 20, 2019

I see! That’s good. :-)
I tested MINGW so that should be fine.
I think that the command for Windows will work from Powershell too but I didn’t test.

@garretwilson
Copy link

What a coincidence that I found this after I was looking for a way to detect the console width. Can I find the console width with Java? mentions some of the same techniques mentioned here. fusesource/jansi#24 says to use jline, although I didn't understand why if jline3 used Jansi then why I couldn't use Jansi myself to find the console width. (I'm using Jansi already.)

But it sounds like you've implemented something in this ticket to detect the console width. So how can I access the value picocli detected so that I can use it in my application?

@garretwilson
Copy link

Oh, I see. 😭 You hid all that useful code deep in some private method. I'll open a ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants