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

no correct information about terminal width/height available #75

Closed
cldwalker opened this issue Jul 24, 2012 · 5 comments
Closed

no correct information about terminal width/height available #75

cldwalker opened this issue Jul 24, 2012 · 5 comments

Comments

@cldwalker
Copy link

Hi,
I'm writing a clojar that needs to detect a user's terminal width. I've tried all the following ways which work fine in a ruby repl but none of them work in reply:

$ lein repl
user=> (System/getenv "COLUMNS")
nil

user=> (clojure.java.shell/sh "tput" "cols")
{:exit 0, :out "80\n", :err ""}
; This is incorrect as my terminal width is 238

user=> (clojure.java.shell/sh "stty" "size")
{:exit 1, :out "", :err "stty: stdin isn't a terminal\n"}

$COLUMNS not being picked up is particularly strange since other lein tasks do pick it up. Any pointers on where/how I could patch this up in reply?

@trptcolin
Copy link
Owner

Cool, I like that project idea.

Unfortunately, I think it's a very low-level thing that I'm not following at the moment: even JRuby doesn't handle this transparently for me locally:

colin:/tmp/ $ irb
jruby-1.6.7.2 :001 > `stty -a`
stty: stdin isn't a terminal
 => "" 
jruby-1.6.7.2 :002 > `tput cols`
 => "80\n" 
jruby-1.6.7.2 :003 > `echo $COLUMNS`
 => "\n" 

On my local setup, I found that I was able to get ahold of this info, but I had to export COLUMNS beforehand - almost certainly not good enough for your use case. But it definitely appears not to be reply-specific - it happens with java -jar clojure.jar as well as the JRuby stuff above. How can you tell that other lein tasks are picking it up?

Interestingly, we use stty -a and friends heavily in JLine2 (e.g. https://github.com/jline/jline2/blob/master/src/main/java/jline/internal/TerminalLineSettings.java), but I'm not immediately seeing what makes that work fine via Runtime exec when it doesn't work via Clojure/JRuby REPLs (also tried using Runtime exec directly).

colin:tmp/ $ lein repl
nREPL server started on port 61667
REPL-y 0.1.0-beta8
Clojure 1.4.0
    Exit: Control+D or (exit) or (quit)
Commands: (user/help)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
          (user/sourcery function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
          (user/clojuredocs name-here)
          (user/clojuredocs "ns-here" "name-here")

user=> (System/getenv "COLUMNS")
nil
user=> Bye for now!

colin:tmp/ $ java -jar ~/.m2/repository/org/clojure/clojure/1.4.0/clojure-1.4.0.jar
Clojure 1.4.0
user=> (System/getenv "COLUMNS")
nil
colin:tmp/ $ echo $COLUMNS
203
colin:tmp/ $ export COLUMNS
colin:tmp/ $ lein repl     
nREPL server started on port 61674
REPL-y 0.1.0-beta8
Clojure 1.4.0
    Exit: Control+D or (exit) or (quit)
Commands: (user/help)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
          (user/sourcery function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
          (user/clojuredocs name-here)
          (user/clojuredocs "ns-here" "name-here")

user=> (System/getenv "COLUMNS")
"203"
colin:tmp/ $ java -jar ~/.m2/repository/org/clojure/clojure/1.4.0/clojure-1.4.0.jar
Clojure 1.4.0
user=> (System/getenv "COLUMNS")
"203"

I can imagine a hack where we export COLUMNS and LINES, but it seems like hazy territory for Leiningen and/or REPLy to be getting into - presumably there could be other environment variables like this as well. I also googled for the stty: stdin isn't a terminal\n message a little - which brought this interesting JRuby issue up: https://jira.codehaus.org/browse/JRUBY-6693

It's really too bad that support isn't better, but I must say I'm baffled as to how JLine2 can possibly be getting away with this! Even calling its APIs through a Clojure repl seems to work, so if you're willing to explicitly depend on jline2, you could get away with using it directly:

user=> (import 'jline.TerminalFactory)
jline.TerminalFactory  
user=> (TerminalFactory/get)
#<UnixTerminal jline.UnixTerminal@5576b9ea>
user=> (.getWidth *1)
203

Hopefully that helps. But it certainly seems to be an upstream issue of one sort or another, so I'll close this. Would still definitely like to hear what you settle on.

@cldwalker
Copy link
Author

Thanks for pointing me in the direction of jline! I looked around and found this which allowed me to construct this:

user=> (->> (clojure.java.shell/sh "/bin/sh" "-c" "stty -a < /dev/tty") :out (re-find #"(\d+) columns") second)
"238"

As for the $COLUMNS dilemma, it seems that's a java-specific issue as mentioned here. I've confirmed this for ruby as mri ruby gives me ENV["COLUMNS"] fine while jruby doesn't. As for other lein contexts that work with $COLUMNS, I was wrong. I had checked that in a shell where I had already exported COLUMNS.

@cldwalker
Copy link
Author

Also, thanks for your hard work on reply. Having autocompletion and clojuredocs have been helpful :)

@trptcolin
Copy link
Owner

Cool, glad to hear it!

@johanatan
Copy link

This is the solution that works on my machine (Mac OS X Snow Leopard) [re-jiggered the regex]:

(->> (clojure.java.shell/sh "/bin/sh" "-c" "stty -a < /dev/tty") :out
     (re-find #"columns (\d+)") second)

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

No branches or pull requests

3 participants