Linus Arver
Linus Arver

Reputation: 1378

How can I read a single character from STDIN in Clojure?

I'm writing a loop that only works on single-character inputs. Depending on what the user pressed (without pressing ENTER), I want to display what key the user typed in, and then repeat. If the user presses "q", then the loop must exit.

Constraints:

Can this be done? Some searching led me to jline2 which had ConsoleReader class but it seems to have disappeared in jline3.

Upvotes: 0

Views: 511

Answers (1)

Linus Arver
Linus Arver

Reputation: 1378

I saw https://gist.github.com/mikeananev/f5138eeee12144a3ca82136184e7a742 and using the linked duplicate answer, came up with this:

; Need `(:import [org.jline.terminal TerminalBuilder Terminal])`

(defn new-terminal
  "creates new JLine3 Terminal.
  returns terminal object"
  ^Terminal [term-name]
  (let [terminal (-> (TerminalBuilder/builder)
                     (.jna true)
                     (.system true)
                     (.name term-name)
                     (.build))]
    terminal))

(defn interactive-loop []
  (let [t (new-terminal "xxx")]
    (.enterRawMode t)
    (let [reader (.reader t)]
    (loop [char-int (.read reader)]
      (case (char char-int)
        \q (do
          (println "Bye!")
          (.close reader)
          (.close t))
        (do (println (char char-int))
            (recur (.read reader))))))))

I'm on NixOS and apparently the jline3 library depends on the infocmp binary being installed, which is part of the popular ncurses package. Unfortunately the Nixpkgs version I use currently does not package this binary so I put in a PR here: https://github.com/NixOS/nixpkgs/pull/72135

Upvotes: 2

Related Questions