user1311390
user1311390

Reputation:

Emacs / Elisp / Closure / Toggle

I currently have the following:

(defun my-hide-code ()                                                                                                                         
  (interactive)                                                                                                                                
  (set-selective-display 2))                                                                                                                   

(defvar my-keys-minor-mode-map (make-keymap) "my-keys-minor-mode keymap.")                                                                     
(define-key my-keys-minor-mode-map (kbd "<f2>") 'my-hide-code)                                                                                 
(define-minor-mode my-keys-minor-mode                                                                                                          
  "use"                                                                                                                                        
  t " my-keys" 'my-keys-minor-mode-map)                                                                                                        
(my-keys-minor-mode 1)    

Now, I want to toggle between (set-selective-display 2) and (set-selective-display 'nil)

Now, if I was in scheme, I would just create a s closure, and the closure would store a state variable, which would allow me to know which state I was in, and how to toggle.

However, Elisp is apparently a lisp-2 where variables and functions have different scope. Given this, how do I create closures / have be a toggle key?

Upvotes: 1

Views: 449

Answers (3)

Bernard Hurley
Bernard Hurley

Reputation: 366

Here is a link to an answer I gave elsewhere about how to create real (not fake) closures in Elisp:

https://stackoverflow.com/a/14088107/1857114

I use a macro I call defun****. It works in Emacs 24.2.1 but I'm not sure what earlier versions it works for. Presumably the **defun special form will be upgraded some time in the future and the macro will be unnecessary.

Upvotes: 0

Kyle Jones
Kyle Jones

Reputation: 5532

selective-display itself is the variable that contains the state you need to check, so you can write

(defun my-toggle-selective-display ()
  (interactive)
  (if selective-display
      (set-selective-display nil)
    (set-selective-display 2)))

As for closures in general, I had need of them for a project long ago and resorted to inserting uninterned symbols into a function definition using backquote substitution to avoid global variables. E.g.

(fset 'toggler
      (let ((toggle-var (make-symbol "toggle")))
        (set toggle-var nil)
        `(lambda () (interactive)
           (cond (,toggle-var
                  (setq ,toggle-var nil))
                 (t
                  (setq ,toggle-var t)))
           (message "toggle is %s" ,toggle-var))))

which when run produces

M-x toggler
toggle is t
M-x toggler
toggle is nil
M-x toggler
toggle is t
M-: (boundp 'toggle)
nil

I guess this qualifies as a kludge, but I know of no other way to get anything like a closure in Emacs-Lisp.

Upvotes: 2

phils
phils

Reputation: 73314

Emacs 24 supports lexical binding, so real closures can be written.

See: What are the new rules for variable scoping in Emacs 24?

Just be aware that dynamic binding is a very large part of what makes Emacs so customizable, so use lexical binding with due care if you are writing something which may be of use to others -- ensure that you defvar any variable which might potentially be useful for someone to override (ensuring, of course, that you think up all those potential use-cases that don't apply to you! :)

For Emacs < 24, see:

Upvotes: 3

Related Questions