I have many handy functions which operate on the current word or region, and due to laziness etc. I've build them out of a template...
For example
(defun lower-camelcase-at-point-or-region ()
"lowerCamelCaseTheCurrent dashed or snake_case word or any words in text selection."
(interactive)
(let (pos1 pos2 meat)
(if (and transient-mark-mode mark-active)
(setq pos1 (region-beginning)
pos2 (region-end))
(setq pos1 (car (bounds-of-thing-at-point 'symbol))
pos2 (cdr (bounds-of-thing-at-point 'symbol))))
(setq meat (s-lower-camel-case (buffer-substring-no-properties pos1 pos2)))
(delete-region pos1 pos2)
(insert meat)))
Effectively this is all boiler plate, except for this line...
(setq meat (s-lower-camel-case (buffer-substring-no-properties pos1 pos2)))
Where I call the function s-lower-camel-case
on the buffer substring. I want to reuse the at point or region stuff, but without duplicating it everywhere, (because it's a headache to maintain.)
So what I really want to know is, can I pass functions as arguments in Emacs Lisp?
When I tried this...
(defun do-stuff-on-point-or-region ()
"Do stuff."
(interactive)
(operate-on-point-or-region 's-lower-camel-case))
With operate-on-point-or-region
defined as...:
(defun operate-on-point-or-region (fn)
"Pick the substring at point, or region
and replace it with the output of fn"
(let (pos1 pos2 meat)
(if (and transient-mark-mode mark-active)
(setq pos1 (region-beginning)
pos2 (region-end))
(setq pos1 (car (bounds-of-thing-at-point 'symbol))
pos2 (cdr (bounds-of-thing-at-point 'symbol))))
(setq meat (fn (buffer-substring-no-properties pos1 pos2)))
(delete-region pos1 pos2)
(insert meat)))
I get : Symbol's function definition is void: fn
Is it possible to use a function as an argument fn
in Emacs Lisp!? Or am I just doing it wrong?
UPDATE: The solution is to use funcall
e.g.
(defun replace-thing-at-point-with (fn)
"Get the current thing at point.
Replace with the return value of the function FN."
(let* ((pos1 (car (bounds-of-thing-at-point 'symbol)))
(pos2 (cdr (bounds-of-thing-at-point 'symbol)))
replacement
excerpt)
(when (> pos1 0)
(setq pos1 (- pos1 1)))
(setq excerpt (buffer-substring-no-properties pos1 pos2))
(setq replacement (funcall fn excerpt)) ;; <- here.
(delete-region pos1 pos2)
(insert replacement)))
First, emacs-lisp is, kinda, sorta, a 2-lisp, so the following is invalid:
(defun foo (fn)
(fn 3)) ;; DOES NOT WORK!
Instead, you have to do the following:
(defun foo (fn)
(funcall fn 3))
So if you replace (setq meat (fn
with (setq meat (funcall fn
the code ought to work.