Skip to content

Writing a lambda printer function

You can write a printer function with a lambda expression taking one argument in two cases:

  • when you configure the printer function applying to a cell or column, or
  • when you define a local printer function with command ses-define-local-printer.

When doing so, please take care that the returned value is a string, or a list containing a string, even when the input argument has an unexpected value. Here is an example:

emacs-lisp
(lambda (val)
   (cond
      ((null val) "")
      ((and (numberp val) (>= val 0)) (format "%.1f" val))
      (t (ses-center-span val ?# 'ses-prin1))))

This example will:

  • When the cell is empty (ie. when val is nil), print an empty string ""
  • When the cell value is a non negative number, format the value in fixed-point notation with one decimal after point
  • Otherwise, handle the value as erroneous by printing it as an s-expression (using ses-prin1), centered and surrounded by # filling.

Another precaution to take is to avoid stack overflow due to a printer function calling itself indefinitely. This mistake can happen when you use a local printer as a column printer, and this local printer implicitly calls the current column printer, so it will call itself recursively. Imagine for instance that you want to create some local printer =fill that would center the content of a cell and surround it by equal signs =, and you do it (errounously) this way:

emacs-lisp
;; ERRONEOUS CODE
(lambda (x)
  (cond
   ((null x) "")
   (t (ses-center x 0 ?=))))

Because =fill uses the standard printer ses-center without explicitly passing any printer to it, ses-center will call the current column printer if any, or the spreadsheet default printer otherwise. So using =fill as a column printer will result in a stack overflow in this column on any non empty cell as ses-center will recursively recall the function that has called it. SES does not check for that; you just have to be careful. For instance, re-write =fill like this:

emacs-lisp
(lambda (x)
  (cond
   ((null x) "")
   ((stringp x) (ses-center x 0 ?= " %s "))
   (t (ses-center-span x ?# 'ses-prin1))))

The code above is fixed as ses-center and ses-center-span are both called with an explicit last printer argument, respectively " %s " and 'ses-prin1.

The code above applies the = filling only to strings; it also surrounds the string by one space on each side before filling with = signs. So the string ‘Foo’ will be displayed like ‘=== Foo ===’ in an 11 character wide column. Any value that is neither nil (ie. an empty cell) nor a string is displayed as an error by using # filling.