Search code examples
emacselisp

Can't assign keys programmatically to bookmarks in a loop


Suppose, we have n bookmarks in the list (n <= 9)

% Bookmark
- --------
1  mark-1                     ~/work/file-1.txt
2  mark-2                     ~/work/file-2.txt
  ...
9  mark-9                     ~/work/file-9.txt

I wanted to programmatically attach key <n> to jump to n-th bookmark.

Code

;get a sorted list of bookmarks
(let ((bookmarks (sort (bookmark-all-names) 'string<))
      (i 1))
  (while bookmarks
    (setq key (number-to-string i))
    ;try to assign key i -> jump-to-bookmark(bookmarks[i])
    (define-key bookmark-bmenu-mode-map
      (kbd key)
      (lambda () (interactive) (bookmark-jump (car bookmarks))))
    ;next bookmark
    (setq bookmarks (cdr bookmarks))
    (setq i (+ i 1))
              ))

Unfortunately, it gives an error:

(wrong-type-argument integer-or-marker-p key)


Solution

  • The issue here is related to the fact that you are using dynamic binding, but trying to access from a lambda a variable that is not in scope anymore (bookmarks). You can fix it by defining the lambda this way:

    `(lambda () (interactive) (bookmark-jump (car ',bookmarks))))
    

    You can see an explanation here.

    (btw, code will fail when you have more than 9 bookmarks)

    This is the modified code that works fine for me:

    (let ((bookmarks (sort (bookmark-all-names) 'string<))
          (i 1)
          key)
      (while bookmarks
        (setq key (number-to-string i))
        (define-key bookmark-bmenu-mode-map
          (kbd key)
          `(lambda () (interactive) (bookmark-jump (car ',bookmarks))))
        (setq bookmarks (cdr bookmarks))
        (setq i (+ i 1))))