Blog: 2024-02-12

From razwiki
Jump to navigation Jump to search

Started on this quest to have a scheme repl where the outputs are italicized, like the SICP book.

Printing italics is pretty easy:

In [1]: line = 'a'

In [2]: print(f'\x1B[3m{line}\x1B[0m')
a

It's italic, trust me!

But when it comes to spawning a scheme subprocess and interacting with its stdin and stdout, I took many turns, eventually trying nodejs since its asynchronous io model more closely fits this use case.

Here's what worked (or at least is a work in progress)

(basically just a copy from the docs of https://www.npmjs.com/package/node-pty which it uses)

var pty = require('node-pty');

var ptyProcess = pty.spawn('scheme')

ptyProcess.onData((data) => {
    process.stdout.write(data);
});

ptyProcess.write('(+ 3 3)\r');
hack $ node scheme_pty.js
(+ 3 3)
Could not open file init.scm
TinyScheme 1.41
ts> 6
ts>

This also sorta works, but right now only processes the stdin with it being ended:

var spawn = require('child_process').spawn

scheme = spawn('scheme')

scheme.stdout.on('data', data => {
  console.log('data')
  console.log(data.toString())
  console.log()
})

scheme.stderr.on('data', data => {
  console.log('err')
  console.log(data.toString())
  console.log()
})

// setTimeout(() => {
  scheme.stdin.write('(+ 3 3)\r')
  // scheme.stdin.write('3\r\n')
  scheme.stdin.end()
// }, 500)

// scheme

// setInterval(() => {}, 1000)

What a mess... I didn't even get python working.. though it has pty built in so it probably would work


Ok meanwhile back in python I got a repl working using a 3rd party tool https://pexpect.readthedocs.io/en/stable/api/replwrap.html that confusingly shadows the built in pexpect. Could incorporate the ideas from it to accomplish this with only the standard library expect. Anyway here's the code, nice and simple in the end


from subprocess import Popen, PIPE
from pexpect.replwrap import REPLWrapper


def safe_input(prompt):
    try:
        return input(prompt)
    except EOFError:
        return 'q'

def main():
    scheme = REPLWrapper('scheme', 'ts> ', prompt_change=None)

    while True:
        line = safe_input('> ')
        if line == 'q':
            return

        result = scheme.run_command(line)
        print(f'\x1B[3m{result}\x1B[0m')

main()