Cider repl and minibuffer stdin

Hi there Clojurians,

I am in the process of making a switch from vim to emacs to take advantage of cider. Everything is going pretty well so far, but I have one nagging issue I would like to be able to solve.

I am working on an interactive text adventure that takes input from stdin (read-line) every turn. When I use lein directly, I enter text directly into the repl and hit enter. In emacs, however, the minibuffer becomes “Stdin:” and I have to enter text there; any text entered directly into the repl is not evaluated. This is a little disconcerting when I am live-coding as 1) the prompt is not where I have the repl and 2) while the minibuffer is occupied other commands do not often work (for instance C-x o does not switch buffers).

Is there a way to enter input directly into the repl and leave the minibuffer free? Am I just handling the whole situation incorrectly?

Thanks,
Matt

2 Likes

I did something similar to this a while back for the halite challenge. I ended up making a pure function that took in the current state of the game, a single line of text, and returned a new game state and maybe something to print out. I developed all that using the repl.

All of the I/O stuff I did separately and was just a loop. I used bash’s nc command to help with that.

I don’t know of a good way of working with stdin from inside the repl. I’m interested to hear how others might do this differently though!

2 Likes

Thanks bmaddy, that sounds like something I could try. Is your source code available so that I could take a look? I’ve never used nc, but it sounds interesting.

Matt

Honestly, the code is hard to follow because I’m coordinating multiple sockets of conversations between a game server and many players. As I remember more about this I realize I probably shouldn’t have mentioned nc–I only needed that because I had to communicate over sockets. I don’t think you’ll need that. Here’s the general gist of what I would do:

  (defn game
    [{:keys [turn] :as state} in]
    {:state (update state :turn inc)
     :out (str "turn " turn ": " in)})

  (defn main
    []
    (println "Welcome!")
    (loop [prev-state {:turn 0}] ; initial game state
      (let [{:keys [state out]} (game prev-state (read-line))]
        (println out)
        (recur state))))

in the repl you can play with game directly:

> (game 4 "hello")
{:state 5, :out "turn 4: hello"}

Then run main when you actually run your app.

The key thing here is that you’re essentially making a repl. I never looked into it much, but there might be a way to use some of Clojure’s repl tooling to make this simpler.

2 Likes

That’s a really good example of the value of separating pure functions and external state! Now you can essentially test each game step in islolation. And when you run it “in production”, there’s just some external actions driving the state.

2 Likes

Thank you Brian! I see now, and I think this will be very helpful. Not much refactoring of my current code, either.

Regards,
Matt

2 Likes