In GNU Emacs, I want to run a program, figlet, on the currently selected text. I then want to comment the region which is produced.
I have figured out how to do it using the standard Emacs commands:
- set mark with C-<space> at the start of the word
- move cursor to the end of the word
- C-u M-x shell-command-on-region RET figlet RET
- M-x comment-region RET
However, I have failed to work out how to write an Emacs lisp program to do all this. Here is my attempt:
(defun figlet-region ()
(interactive)
(push-mark)
(shell-command-on-region "figlet")
(comment-region (mark) (point))
(pop-mark)
)
(global-set-key "\C-c\C-f" 'figlet-region)
Then C-<space>; M-x figlet-region
produces garbage:
figlet-region: Wrong number of arguments: #[(start end command &optional output-buffer replace error-buffer display-error-buffer) "ÆÇÈ \"!É 'jÊ!j;j 0Wb ?Ë`Ì\"Í ÎQÎDRÎÉ!\"& ffÏ )ãÐqÑ!#Ò#p=¬É$]d|e^|Íed Î ÎD¡ÎÉ!\"&â%qÉ$Á&%Ó *Í ÉØ#DÚ#É!\"&*#Ô!#ÕÖ×!8WrÐ!qd`Z'o ØcÙÉ\"d'Zb)(Úp!)Û!*" [error-buffer small-temporary-file-directory temporary-file-directory exit-status error-file replace make-temp-file expand-file-name "scor" nil ...] 9 1945557 (let (string) (unless (mark) (error "The mark is not set now, so there is no region")) (setq string (read-from-minibuffer "Shell command on region: " nil nil nil (quote shell-command-history))) (list (region-beginning) (region-end) string current-prefix-arg current-prefix-arg shell-command-default-error-buffer t))], 1
Answer
(defun figlet-region (&optional b e)
(interactive "r")
(shell-command-on-region b e "figlet" (current-buffer) t)
(comment-region (mark) (point)))
(This is based on Trey Jackson's answer.)
Example (Lisp Interaction mode)
;; _ _ _
;; | |_| |__ __ _ _ __ | | _____
;; | __| '_ \ / _` | '_ \| |/ / __|
;; | |_| | | | (_| | | | | <\__ \
;; \__|_| |_|\__,_|_| |_|_|\_\___/
Example (CPerl mode)
# _ _ _
# | |_| |__ __ _ _ __ | | _____
# | __| '_ \ / _` | '_ \| |/ / __|
# | |_| | | | (_| | | | | <\__ \
# \__|_| |_|\__,_|_| |_|_|\_\___/
It is not a very good idea to use an interactive command like
shell-command-on-region
in a lisp program. You should usecall-process-region
instead:It should be more resilient against various user options.
Well, I'm not sure where the garbage is coming from, but the error itself is coming from
shell-command-region
. When used inelisp
, it expects at least 3 arguments,START
END
andCOMMAND
.Also, in general, it is bad practice to mess with the mark in functions. Here is what the doc of push-mark has to say on the subject:
I'm unsure what you're trying to accomplish with the pushing and popping of the marks, I believe you'd get the same functionality by doing this:
The argument to interactive tells Emacs to pass the region (point and mark) in as the first two arguments to the command.