
Controlling the terminal from Common Lisp (part 2) - jackdaniel
https://turtleware.eu/posts/Charming-CLIM-tutorial-part-2--Rethinking-The-Output.html
======
ngcc_hk
Interesting. Lisp is hard not because of the language. I read the source code
and unlike python etc it is straightforward.

but the setup is hard. Clojure setup is still a bit hard. But at least package
management is Easy. Asdf ...

The most difficult issue is it is more or less pure. Whilst the c external
interface seems easier. But it is not designed from ground up as one of the
language in a system. JavaScript sort of work with HTML and CSS and not
dealing with this. You do have canvas. But not for simple terminal io like
this.

Somehow it is kind of lost on space experience. Great language and great
ecosystem. Just out there, alone and for their own kind.

But nice to read. Still find it hard to read python after writing. Even there
is only one way to do so.

~~~
kazinator
TXR Lisp setup is easy. If you have to build from source (not a user of a
distro that has packaged it like Guix or Void, then:

    
    
      ./configure && make && sudo make install
    

Then there is a txr executable with some auto-loaded library files in
/usr/share, and that's it. The txr executable performs all the sysrooting
calculations so you can move an installation of it anywhere, as long as you
keep the relative locations of the files the same (the installation tree
shape). If you have a tarball of it, it will unpack and run from anywhere.

The documentation is all in a single man page, covering everything.

TXR is designed from the ground up as a system utility integrated well into a
POSIX environment.

TXR requires no package management or build system because the _load_ function
behaves sanely. If you load a file that is located in path/to/dir, and that
file itself does a (load "foo") at its own top level, then that top-level load
look for path/to/dir/foo.tlo (compiled file) or path/to/dir/foo.tl (source):
i.e relative to the same directory as the parent file that is being load-ed.

There is no need to mess around with irksome path schemes (look for stuff
here, look for stuff there, ...). You're in the driver's seat: put the pieces
you need where you want, load each of their main files, and that's it.

We can make a package just by putting some files into a directory, and
documenting which one is the main one that is to be loaded. That one loads the
others using relative paths, and that's that.

A module/program's main file can rebuild itself and the others like this:

    
    
       (defvarl myfiles '#"main foo bar baz xyzzy") ;; word list lit, same as '("main" "foo" ...)
    
       (each ((f myfiles))
         (or (compile-update-file `@f.tl` `@f.tlo`)
             (load f))
    

_compile-update-file_ checks the existence and time stamps, rebuilding the
.tlo if it is missing or older than the .tl file. Compilation usually has the
same effect as loading, so in that case we don't have to load. If compile-
update-file returns nil, then it means it did nothing; we load the existing
compiled file then.

> _But it is not designed from ground up as one of the language in a system._

I know exactly what you mean there; that is why I designed TXR from the ground
up in the form factor of a utility that fits into the surrounding OS
environment instead of being a kind of immigrant from a Lisp planet. It's
Lisp, for Unix and C people -- with a decent Windows port.

~~~
kazinator
Speaking of controlling the terminal, TXR Lisp has a built-in comprehensive
wrapper for termios.

[https://www.nongnu.org/txr/txr-
manpage.html#N-0260AE30](https://www.nongnu.org/txr/txr-
manpage.html#N-0260AE30)

It even supports the coreutils "stty -g" string format for saving and
restoring termios settings.

------
jxy
How does one go about unit testing those terminal controlling functions?

~~~
neilv
If you're not using much system calls, one simple way is to capture the byte
sequences that would be sent to the terminal, and simulate the byte sequences
that would be received.

(A terminal library I wrote, which doesn't do as much as this CL one, uses
byte stream I/O almost entirely.
[https://www.neilvandyke.org/racket/charterm/](https://www.neilvandyke.org/racket/charterm/)
)

Another option might be to connect it to `screen` or `tmux`, and scrape the
characters and attributes from there, or feed it to a terminal GUI program
like `xterm` and scrape the pixels from there. And synthesize the input to the
terminal emulator.

