RSS Feed

Lisp Project of the Day

cl-charms

You can support this project by donating at:

Donate using PatreonDonate using Liberapay

cl-charmsconsoleui

Documentation🥺
Docstrings🤨
Tests 🥺
Examples😀
RepositoryActivity🤨
CI 🤨

Two days ago I reviewed the cl-ncurses. CL-Charms is also a binding to ncurses, but uses more universal and portable CFFI instead of UFFI.

By the way, LEM (Common Lisp Emacs) uses cl-charms for it's console backend.

CL-Charms provides a high-level API besides a low level. I've ported my previous echo program to it:

(defun main (&rest argv)
  (declare (ignorable argv))
  (with-curses ()
    (enable-raw-input)
    (enable-extra-keys *standard-window*)
    (disable-echoing)

    (write-string-at-cursor *standard-window*
                            "Type any character to see it in bold:
")

    (let ((ch (get-char *standard-window*)))

      (cond
        ((eql ch (code-char 265))
         (write-string-at-cursor *standard-window*
                                 "F1 Key pressed"))
        (t
         (write-string-at-cursor *standard-window*
                                 "The pressed key is ")

         (cl-charms/low-level:attron cl-charms/low-level:a_bold)
         (write-string-at-cursor *standard-window*
                                 (format nil "~A~%" ch))
         (cl-charms/low-level:attroff cl-charms/low-level:a_bold)))
      

      (get-char *standard-window*))))

Interesting that cl-charms/low-level package can be used as a drop-in replacement for cl-ncurses and my second example worked without any changes except a change in the use clause.

A few words about portability

CL-NCURSES

I must admit, that working with such kind of bindings can be problematic. For example, I haven't any problems using neither cl-ncurses nor cl-charms on OSX, but there was a problem with starting an example program on Ubuntu Bionic.

On Ubuntu cl-ncurses is unable to find libncurses.so and you have to load it manually like that:

;; These paths are harcoded in the cl-ncurses:
(defvar *ncurses-search-paths*
  #-win32'("/usr/local/lib64/" "/usr/local/lib/" "/lib64/" "/lib/" "/usr/lib64/" "/usr/lib/")
  #+win32'("/users/jacob/src/pdc31dll/"))

;; On Ubuntu Bionic you have to add this
;; before cl-ncurses initscr call:
(uffi:load-foreign-library "/lib/x86_64-linux-gnu/libncurses.so.5.9"
                           :module "cl-ncurses")

CL-CHARMS

CL-Charms has another problem. It requires the libncurses5-dev package to be installed on Ubuntu. Without that, it has problem when compiling the CFFI Grovel's files:

; cc -o /root/.cache/common-lisp/sbcl-1.5.6-linux-x64/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cl-charms-20200218-git/src/low-level/curses-grovel__grovel-tmpBF3HHBTQ.o -c -g -Wall -Wundef -Wsign-compare -Wpointer-arith -O3 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wunused-parameter -fno-omit-frame-pointer -momit-leaf-frame-pointer -fno-pie -fPIC -I/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.21.0/ /root/.cache/common-lisp/sbcl-1.5.6-linux-x64/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cl-charms-20200218-git/src/low-level/curses-grovel__grovel.c
/root/.cache/common-lisp/sbcl-1.5.6-linux-x64/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cl-charms-20200218-git/src/low-level/curses-grovel__grovel.c:6:10: fatal error: ncurses.h: No such file or directory
 #include <ncurses.h>
          ^~~~~~~~~~~
compilation terminated.
Unhandled CFFI-GROVEL:GROVEL-ERROR in thread #<error printing a SB-THREAD:THREAD: #<PRINT-NOT-READABLE {10042938A3}>>: Subprocess #<UIOP/LAUNCH-PROGRAM::PROCESS-INFO {100428DCF3}>
 with command ("cc" "-o" "/root/.cache/common-lisp/sbcl-1.5.6-linux-x64/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cl-charms-20200218-git/src/low-level/curses-grovel__grovel-tmpBF3HHBTQ.o" "-c" "-g" "-Wall" "-Wundef" "-Wsign-compare" "-Wpointer-arith" "-O3" "-D_LARGEFILE_SOURCE" "-D_LARGEFILE64_SOURCE" "-D_FILE_OFFSET_BITS=64" "-Wunused-parameter" "-fno-omit-frame-pointer" "-momit-leaf-frame-pointer" "-fno-pie" "-fPIC" "-I/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.21.0/" "/root/.cache/common-lisp/sbcl-1.5.6-linux-x64/root/.roswell/lisp/quicklisp/dists/quicklisp/software/cl-charms-20200218-git/src/low-level/curses-grovel__grovel.c")
 exited with error code 1

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10004F04C3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<CFFI-GROVEL:GROVEL-ERROR "~a" {1004291F73}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<CFFI-GROVEL:GROVEL-ERROR "~a" {1004291F73}>)
2: (INVOKE-DEBUGGER #<CFFI-GROVEL:GROVEL-ERROR "~a" {1004291F73}>)
3: (ERROR CFFI-GROVEL:GROVEL-ERROR :FORMAT-CONTROL "~a" :FORMAT-ARGUMENTS (#<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {10042917F3}>))
4: (CFFI-GROVEL:GROVEL-ERROR "~a" #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {10042917F3}>)
5: ((FLET "THUNK" :IN CFFI-GROVEL:PROCESS-GROVEL-FILE))

Possible Solution?

Probably, @borodust's claw and bodge-blobs-support can solve these issues?


Brought to you by 40Ants under Creative Commons License