0

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:

  • I don't care about Unicode (only supporting US ASCII character set is desirable).
  • I only care about Unixy systems (only Linux is fine).
  • I am using Leiningen.

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

Linus Arver
  • 1,331
  • 1
  • 13
  • 18
  • Clojure question, but I think a Java answer is applicable here. – Carcigenicate Oct 26 '19 at 15:00
  • 2
    Possible duplicate of [How to read a single char from the console in Java (as the user types it)?](https://stackoverflow.com/questions/1066318/how-to-read-a-single-char-from-the-console-in-java-as-the-user-types-it) – Carcigenicate Oct 26 '19 at 15:01
  • 1
    Thank you so much. I will update that other question with a Clojure MWE and then click on the "That solved my problem!" button, if that's ok? – Linus Arver Oct 26 '19 at 20:05
  • 1
    I don't think the other question should be modified. If it answers your question though, yes, you can accept the duplicate suggestion. – Carcigenicate Oct 26 '19 at 20:57
  • 1
    Well I posted an answer here that solves it for me in Clojure. It will probably help other Clojurists. The other question did help a bit, but I still had to tweak things a little based on another gist. Given this, this question and answer probably has enough originality to leave it as-is. I'm happy with my solution so feel free to moderate at will. *shrug* – Linus Arver Oct 28 '19 at 04:14

1 Answers1

2

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

Linus Arver
  • 1,331
  • 1
  • 13
  • 18