1

§12 Skeleton Language lists, as an element of a skeleton input list,

skeleton

  Subskeletons are inserted recursively, not once, but as often as
  the user enters something at the subskeletons interactor. Thus there
  must be a `str` in the subskeleton. They can also be used
  non-interactively, when prompt is a lisp-expression that returns
  successive list-elements.

As seems to be common in the skeleton documentation, the terminology is obscure and self-contradictory. I've tried various ways to realise the structure described, but none of my attempts have worked. Here is one of them:

(define-skeleton _skel
  "Test skeleton"
  nil
  ('("Seventeen" "Nineteen") "Should be two values, 17 and 19:" str \n))

Invoking _skell results in "Should be two values, 17 and 19:" appearing in the buffer, and an error of setq: Wrong type argument: stringp, ("Seventeen" "Nineteen") appearing in the message buffer.

What am I missing to make this use of subskeletons non-interactively, with either static values or a dynamic lisp-expression returning the values?

Thanks!

Drew
  • 75,699
  • 9
  • 109
  • 225
RoUS
  • 111
  • 3
  • https://emacs.stackexchange.com/tags/elisp/info – Drew Dec 04 '20 at 00:16
  • Reading the documentation what I do understand is that the interactor (set to `nil` in your example) should be what returns the list elements and not trying to pass a list to str which expects an atom. – Muihlinn Dec 05 '20 at 09:19
  • I've tried that, too. Of course, AFAIUI, subskeletons need an interactor, too. Hence the confusion. Every combo I've tried has resulted in the same error. :-( – RoUS Dec 06 '20 at 18:50
  • Even an example here would be a big help. The code in `skeleton.el` contains a lot of Deep Magic. – RoUS Dec 11 '20 at 22:18

1 Answers1

1

It's a long time since the question was asked but I figured I would answer since it took me hours to figure this out. This section from emacswiki tipped me off.

The first item of a subskeleton has to be either a string (used as a prompt) or an s-expression that returns a string when evaluated. This string can be produced interactively (using skeleton-read) or non interactively. That means your example needs a function that returns a different string for each call. Iterating over a list like this can be done with a helper function that tracks the state of the iteration with a closure.

(defun make-list-iterator (list)
  (let ((ls (cons 'discard list))) ; provide item to discard on first call
    (lambda ()
      (setf ls (cdr ls))
      (car ls))))

You can then make your example work as you expect like so:

(define-skeleton _skel
  "Test skeleton"
  nil
  ;; Save function doing the iteration in a skeleton-local variable
  '(fset 'v1 (make-list-iterator '("Seventeen" "Nineteen")))
  ((v1) "Should be two values, 17 and 19:" str \n))
mmarshall540
  • 131
  • 4
cowile
  • 11
  • 1