Friday 17 May 2024

Getting the terminal size in Clisp on FreeBSD
=============================================

Recently I have been fooling around with lisp and ncurses. 
This is part of my quest to learn Lisp, I don't have much
experience with Common Lisp, so this is one big adventure for me.

Clisp and ncurses
-----------------
Clisp, at least on FreeBSD, doesn't like cl-charms or croatoan, two
more "modern" Common Lisp packages created for using ncurses.

I read somewhere about a file "curses.lisp", and started looking for
that. This is how I discovered "The Sewer Massacre" [1], which is
available under the GPL license. The Git repo contains indeed a file
`curses.lisp'. This file uses the `CFFI' package, "The Common Foreign
Function Interface" to talk with the ncurses library.

Swank
-----
Emacs gives a Common Lisp REPL through SLIME. This works wonderful.
However, using ncurses to interact with the terminal screen
is not possible this way.

In order to let Clisp interact with the terminal and still have
a REPL, one has to use Swank. This is used to create a running
Lisp that listens to a port (default 4005). The command
`M-x slime-connect' starts an interface in Emacs to this port
to provide a REPL, 

It turned out it wasn't that difficult to get a running Clisp
that listens to port 4005.

Hello world
-----------
Using my fresh Swank daemon, I started playing with the `curses.lisp'
file.

After loading the lisp packages `CFFI' and `trivial-gray-streams', and
changing the library name into `libncurses.so.6' in the code, Clisp
printed the famous "hello world" message using ncurses.

And There Was Much Rejoicing...

LINES and COLS
--------------
In the (very) past, I have toyed with ncurses from C and Perl.
I remembered using `LINES' and `COLS' to get the actual screen size.

Unfortunately, the `curses.lisp' file doesn't export some function
to retrieve these two variables. I tried to add a Lisp function,
using CFFI, to request these values from ncurses. Which resulted
in a crashing Swank session :)

Next, I created a Lisp function to use the getmaxyx ncurses function.
This resulted in the values 0 and 14. Searching the internet I ran
into posts from people running in these same values, using different
languages to interface with ncurses, which gave me an excuse not to
blame it on my Lisp function, and concluded that using getmaxyx was
perhaps not the best path.

Terminal size
-------------
Trying to discover more, I ran into a small Common lisp project called
"terminal-size" [2]. This is available under the MIT license.

`terminal-size' also uses CFFI, but it doesn't use ncurses.

terminal-size depends on the Common Lisp `osicat' package.

After loading CFFI and osicat, the function `(size)' reports a
terminal width and height of 182 and 60.

Mission accomplished :)

Final words
-----------
Learning Lisp is a hobby project that only allows for brief sessions.
A seemingly trivial task --to get the terminal dimensions-- as a start
for a small Clisp application, took me several days.

It has not been a waste of time, I learned a lot along the road. From
this perspective, attempting to get things functioning with Clisp
rather than SBCL was beneficial. The additional challenges I had to
tackle as a result created numerous learning opportunities.

Happy Lisping!

[1]: http://common-lisp.net/project/lifp/sewers-src.zip
[2]: https://github.com/eudoxia0/terminal-size.git


Last edited: $Date: 2024/05/17 13:29:37 $