6

I am writing a text game in Clojure. I want the player to type lines at the console, and the game to respond on a line-by-line basis.

Research showed me that (read-line) is the way one is meant to get text lines from standard input in Clojure, but it is not working for me.

I am in a fresh Leiningen project, and I have added a :main clause to the project.clj pointing to the only source file:

(ns textgame.core)

(defn -main [& args]
  (println "Entering -main")
;  (flush)                      ;makes no difference if flush are commented out
  (let [input (read-line)]
    (println "ECHO:" input))
;  (flush)
  (println "Exiting -main"))

using lein run yields:

Entering -main
ECHO: nil
Exiting -main

In other words, there is no opportunity to enter text at the console for (read-line) to read.

How should I get Clojure to wait for characters and newline to be entered and return the corresponding string?

(I am using GNOME Terminal 2.32.1 on Linux Mint 11, Leiningen 1.6.1.1 on Java 1.6.0_26 Java HotSpot(TM) 64-Bit Server VM, Clojure version 1.2.1.)

Update: If I run lein repl, I can (println (read-line)), but not when I have a -main function and run using lein run.

liwp
  • 6,746
  • 1
  • 27
  • 39
dukereg
  • 722
  • 5
  • 16
  • possible duplicate of [Clojure's (read-line) returns nil; does not prompt](http://stackoverflow.com/questions/5861373/clojures-read-line-returns-nil-does-not-prompt) – amalloy Oct 10 '11 at 01:13
  • @amalloy The best guess in the answer you linked to was that it was a problem with swank-clojure/SLIME. I am not using either of those. – dukereg Oct 10 '11 at 05:23
  • 1
    have you tried to run the script directly with java -cp clojure.jar clojure.main /path/to/myscript.clj to discard other problems and focus on lein run issues? – jneira Oct 10 '11 at 05:50
  • @jneira It does seem to be a problem with lein run. Thanks for the suggestion. – dukereg Oct 10 '11 at 22:28

5 Answers5

6

Try "lein trampoline run". See http://groups.google.com/group/leiningen/browse_thread/thread/a07a7f10edb77c9b for more details also from https://github.com/technomancy/leiningen:

Q: I don't have access to stdin inside my project.

A: There's a problem in the library that Leiningen uses to spawn new processes that blocks access to console input. This means that functions like read-line will not work as expected in most contexts, though the repl task necessarily includes a workaround. You can also use the trampoline task to launch your project's JVM after Leiningen's has exited rather than launching it as a subprocess.

Community
  • 1
  • 1
DanLebrero
  • 8,545
  • 1
  • 29
  • 30
2

I have had similar problems and resorted to building a jar file and then running that.

lein uberjar
java -jar project-standalone.jar

It's a bit slower, though it got me unstuck. An answer that works from the repl would be better

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • You're right; this is slow, but it works. It seems that lein run has something wrong with it. – dukereg Oct 10 '11 at 22:26
  • 2
    People with the same problem should note that they need (:gen-class) in their namespace declaration before running the standalone jar in this manner. – dukereg Oct 10 '11 at 22:34
1

Wrap your read-line calls with the macro with-read-line-support which is now in ns swank.core [since swank-clojure 1.4+ I believe]:

(use 'swank.core)
(with-read-line-support 
  (println "a line from Emacs:" (read-line)))

Thanks to Tavis Judd for the fix.

Don
  • 1,151
  • 9
  • 19
0

You can use read and use a string as input.

efraimmgon
  • 31
  • 1
  • 4
-1

Not sure about the lein aspects of the problem, but definitely in emacs it is impossible to make stdin work. However, if you want to get text from the user, you can easily do it using a JOptionPane like this code from my little tic-tac-toe program:

(defn get-input []
  (let [input (JOptionPane/showInputDialog "Enter your next move (row/column)")]
    (map #(Integer/valueOf %) (.split input "/"))))
yiny
  • 1