Paraprogramming Dispatches


Deannoyifying SLIME


Lisp
Eugene Zaikonnikov

Over all these years I don’t think I ever wanted to close all existing SLIME connections when attaching to a remote host. Similarly, the version mismatch between SWANK and SLIME frontend has never stopped me following through with connection. I did however fumbled with y/n confirmations plenty of times. The snippet below removes these interactive checks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(defun slime-check-version (version conn)
  (or (equal version slime-protocol-version)
      (equal slime-protocol-version 'ignore)
      (message
       (format "Versions differ: %s (slime) vs. %s (swank)."
               slime-protocol-version version))
      (slime-net-close conn)
      (top-level)))

(defun slime-connect (host port &optional _coding-system interactive-p &rest parameters)
  "Connect to a running Swank server. Return the connection."
  (interactive (list (read-from-minibuffer
                      "Host: " (cl-first slime-connect-host-history)
                      nil nil '(slime-connect-host-history . 1))
                     (string-to-number
                      (read-from-minibuffer
                       "Port: " (cl-first slime-connect-port-history)
                       nil nil '(slime-connect-port-history . 1)))
                     nil t))
  (slime-setup)
  (message "Connecting to Swank on port %S.." port)
  (slime-setup-connection (apply 'slime-net-connect host port parameters)))

A useful feature for working on *nix backends is an ability to parse integers as epoch time in SLIME inspector. For this we need to minimally extend emacs-inspect found in swank-fancy-inspector.lisp:

1
2
3
4
5
6
7
8
9
10
11
12
13
(defmethod emacs-inspect ((i integer))
  (append
   `(,(format nil "Value: ~D = #x~8,'0X = #o~O = #b~,,' ,8:B~@[ = ~E~]"
	      i i i i (ignore-errors (coerce i 'float)))
     (:newline))
   (when (< -1 i char-code-limit)
     (label-value-line "Code-char" (code-char i)))
   (label-value-line "Integer-length" (integer-length i))
   (ignore-errors
     (label-value-line "Universal-time" (format-iso8601-time i t)))
   (ignore-errors
     (label-value-line "Epoch-time"
		       (format-iso8601-time (+ i 2208988800) t)))))

Tweaking SLIME Xref for Remote Images


Lisp
Eugene Zaikonnikov

By the nature of embedded development one spends a lot of time debugging on target devices. SLIME experience for the most part is as smooth as on local host with the exception of cross referencing. Swank backend on target is reporting local paths in xref records which the frontend on your host then tries to open.

The canonical workaround from the user manual is using slime-tramp contrib, allowing you to navigate the source tree on remote target over SSH. I however greatly prefer to work on the local copy of the source code, with much lower latency (SSH over VPN over cellular to a remote site is no fun) and ability to stage and commit changes immediately. A somehwat kludgy workflow that does the trick is using a hacked slime-postprocess-xref below to substitute $HOME in xref records. The source tree in remote home has to be placed in the same relative location as on your host. One should also remember copying their local tree to remote at the end of debugging session, in case the instance has to be restarted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
;;; A modified version that substitutes HOME in remote images with local ones
;;; enabling local code navigation with the usual SLIME xref tools
(defun slime-postprocess-xref (original-xref)
  "Process (for normalization purposes) an Xref comming directly
from SWANK before the rest of Slime sees it. In particular,
convert ETAGS based xrefs to actual file+position based
locations."
  (if (not (slime-xref-has-location-p original-xref))
      (list original-xref)
    (let ((loc (slime-xref.location original-xref)))
      (slime-dcase (slime-location.buffer loc)
        ((:etags-file tags-file)
         (slime-dcase (slime-location.position loc)
           ((:tag &rest tags)
            (visit-tags-table tags-file)
            (mapcar (lambda (xref)
                      (let ((old-dspec (slime-xref.dspec original-xref))
                            (new-dspec (slime-xref.dspec xref)))
                        (setf (slime-xref.dspec xref)
                              (format "%s: %s" old-dspec new-dspec))
                        xref))
                    (cl-mapcan #'slime-etags-definitions tags)))))
        (t
         ;; Find the /home/someuser/ path component and replace it
         ;; with our local $HOME, if any
         (setf (cadr (slime-location.buffer loc))
               (replace-regexp-in-string "^/[^/]+/[^/]+"
                                         (getenv "HOME")
                                         (cadr (slime-location.buffer loc))))
         (list original-xref))))))

Announcing deptree


Lisp
Eugene Zaikonnikov

Deptree is a tool to list and archive dependency snapshots of (ASDF-defined) projects. We at Norphonic use it in the product build pipeline, but it can be useful for integration workflows as well. The task sounds common enough so there’s little doubt am reinventing the wheel with this. Alas, I couldn’t find any readily available solutions nor good folks at #commonlisp could recall of any, so there.

Available in the latest Quicklisp.

Also ALSA gets Mixer API


Lisp
Eugene Zaikonnikov

Also ALSA now has a simple ALSA Mixer API support. See set-mixer-element-volume for sample use.

Available in the latest Quicklisp.

« Older Posts