How to call describe-function for current-word in Emacs? - emacs

I want to write an Emacs function that calls describe-function for current-word. And if there is no function named current-word then it calls describe-variable.
I tried to write it, but I couldn't even call describe-function for current-word...
(defun describe-function-or-variable ()
(interactive)
(describe-function `(current-word)))
How can I write it?

Something like this should work:
(defun describe-function-or-variable ()
(interactive)
(let ((sym (intern-soft (current-word))))
(cond ((null sym)
"nothing")
((functionp sym)
(describe-function sym))
(t
(describe-variable sym)))))

Here's a more general function:
(defun describe-function-or-variable ()
(interactive)
(let ((sym (intern-soft (current-word))))
(unless
(cond ((null sym))
((not (eq t (help-function-arglist sym)))
(describe-function sym))
((boundp sym)
(describe-variable sym)))
(message "nothing"))))
It works for special forms, e.g. and, as well as for macros, e.g. case.
It also makes sure that the varible is bound, before trying to describe it.

Related

Emacs jump to next annotated words or phrases

When using Emacs, I notice that words or phrases in a buffer can be annotated or highlighted by many minor modes like hi-lock-mode, flyspell-mode, flycheck-mode...
Is there any uniform way to jump to the highlighted words or phrases created by all these minor modes? Specifically, is there any package or function support jumping to the next and previous highlighted phrases?
When using Eclipse, I can do it by pressing Ctrl-. and Ctrl-,. However, when switching to Emacs, so far, I haven't found an equivalent feature.
Developing a mode which aims to tackle that kind of tasks
https://github.com/andreas-roehler/werkstatt/tree/master/general-key
Facilitates the setting of a general command.
Than this command gets different bindings according to modes - which needs to be edited by hand once. Afterwards it allows to set/change a key at one place for all related/bound commands.
See for example inside
https://github.com/andreas-roehler/werkstatt/blob/master/general-key/general-key-python-mode.el
It's alpha still notably for the install process. Bug reports resp. feature requests welcome.
Not surprisingly, #Drew has answered something related to this.
You can programmatically use isearch with something like:
(defun foo (regexp)
(interactive (list (read-regexp "Regexp: ")))
(isearch-mode t t)
(let ((isearch-regexp nil))
(isearch-yank-string regexp)))
This will pull your previous regexp history, including those from hi-lock. I imagine it would be a fun exercise to modify this to use hi-lock-regexp-history.
If you use swiper, you can restrict the search candidates to lines with highlighted patterns by hi-lock-mode.
Here is a simple wrapper of swiper:
(require 'cl-lib)
(defun swiper-over-highlights-simple ()
(interactive)
(let ((original-swiper--candidates (symbol-function 'swiper--candidates)))
(cl-letf (((symbol-function 'swiper--candidates)
(lambda ()
(let ((pattern (mapconcat #'car hi-lock-interactive-patterns "\\|")))
(cl-remove-if-not (lambda (x) (string-match-p pattern x))
(funcall original-swiper--candidates))))))
(swiper))))
In addition, you can change ivy-read's preselect argument, which initializes the first matched line inside swiper.
The following fuction, modified from swiper, finds the closest next line with a highlighted pattern:
(defun swiper-over-highlights (&optional initial-input)
(interactive)
(let ((original-swiper--candidates (symbol-function 'swiper--candidates))
(pattern (mapconcat #'car hi-lock-interactive-patterns "\\|")))
(cl-letf (((symbol-function 'swiper--candidates)
(lambda ()
(cl-remove-if-not (lambda (x) (string-match-p pattern x))
(funcall original-swiper--candidates)))))
(let ((candidates (swiper--candidates)))
(swiper--init)
(setq swiper-invocation-face
(plist-get (text-properties-at (point)) 'face))
(let ((preselect
(save-excursion
(search-forward-regexp pattern nil t)
(let* ((current-line-value (current-line))
(candidate-line-numbers (mapcar (lambda (x) (cadr (text-properties-at 0 x)))
candidates))
(preselect-line-num (cl-find-if (lambda (x) (<= current-line-value x))
candidate-line-numbers)))
(- (length candidate-line-numbers)
(length (member preselect-line-num candidate-line-numbers))))))
(minibuffer-allow-text-properties t)
res)
(unwind-protect
(and
(setq res
(ivy-read
"Swiper: "
candidates
:initial-input initial-input
:keymap swiper-map
:preselect preselect
:require-match t
:action #'swiper--action
:re-builder #'swiper--re-builder
:history 'swiper-history
:extra-props (list :fname (buffer-file-name))
:caller 'swiper))
(point))
(unless (or res swiper-stay-on-quit)
(goto-char swiper--opoint))
(isearch-clean-overlays)
(unless (or res (string= ivy-text ""))
(cl-pushnew ivy-text swiper-history))
(setq swiper--current-window-start nil)
(when swiper--reveal-mode
(reveal-mode 1))))))))

Is there a `flet` for commands in Emacs?

I want to dynamically redirect one command to another one within a
certain function using around advice, something like this:
(defun f1 (arg)
(interactive (list (read-from-minibuffer "F1: ")))
(message "f1: %S" arg)
arg)
(defun f2 (arg)
(interactive (list (read-from-minibuffer "F2: ")))
(message "f2: %S" arg)
arg)
;; Function that invokes the f1 command
(defun myfunc ()
(call-interactively 'f1))
;; I want myfunc to invoke f2 instead whenever it would invoke f1
(defadvice myfunc (around f1-to-f2 activate)
(flet ((f1 (&rest args) (interactive) (call-interactively 'f2)))
ad-do-it))
(myfunc)
However, this gives an error (wrong-type-argument commandp f1),
indicating that when flet redefined the f1 function, it didn't
process the interactive form and treat it like a command, so it can't
be invoked by call-interactively.
Is there a variant of flet that will work for commands in this way?
(Here are the actual redefinitions I want to do:)
(defadvice org-metaleft (around osx-command activate)
(flet ((backward-word (&rest args)
(interactive)
(call-interactively #'move-beginning-of-line)))
ad-do-it))
(defadvice org-metaright (around osx-command activate)
(flet ((forward-word (&rest args)
(interactive)
(call-interactively #'move-end-of-line)))
ad-do-it))
You're bumping into a silly bug in flet: the macroexpansion of flet will have: (lambda (&rest args) (progn (interactive) (call-interactively 'f2))). Notice the spurious progn added in there, which "hides" the interactive.
To get more control (and avoid cl.el at the same time), you can do:
(defadvice myfunc (around f1-to-f2 activate)
(cl-letf (((symbol-function 'f1)
(lambda (&rest args)
(interactive) (call-interactively 'f2))))
ad-do-it))
(Edit: The cl-letf macro can do this natively in modern emacs. The answer below might still be useful for old versions.)
Well, if there wasn't before, there is now:
(require 'cl)
(require 'cl-lib)
(defmacro command-let (bindings &rest body)
"Like `flet', but works for interactive commands.
In addition to the standard `(FUNC ARGLIST BODY...)' syntax from
`flet', this also supports `(FUNC NEW-FUNC)' as a shorthand for
remapping command FUNC to another command NEW-FUNC, like this:
(defun FUNC (&rest ignored)
(interactive)
(call-interactively NEW-FUNC))
\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
(declare (indent 1))
(cl-loop for binding in bindings
collect (list (car binding) nil) into empty-bindings
collect (if (symbolp (cadr binding))
;; Remap one command to another
`(defun ,(car binding) (&rest args)
(interactive)
(call-interactively ',(cadr binding)))
;; Define command on the fly
(cons 'defun binding))
into defun-forms
finally return
`(flet (,#empty-bindings)
,#defun-forms
,#body)))
In action:
(defadvice myfunc (around f1-to-f2 activate)
(command-let ((f1 f2))
ad-do-it))
(myfunc)
That code now invokes the f2 command using call-interactively, as desired.

Generate quoted symbol in Emacs Lisp macro

I am creating a simple macro to disable show trailing whitespace in certain major modes (I will loop this macro in a dolist loop later):
(defmacro non-trailing-whitespaces-modes (mode)
(let ((hook (intern (concat mode "-mode-hook"))))
`(add-hook ,hook (lambda () (setq show-trailing-whitespace nil)))))
After this macroexpand: (macroexpand '(non-trailing-whitespaces-modes "eshell")), the result is
(add-hook eshell-mode-hook
(lambda nil
(setq show-trailing-whitespace nil)))
I want eshell-mode-hook to be 'eshell-mode-hook, otherwise it will cause error.
Simply change the body of the macro to begin (add-hook ',hook ...)
No need for a macro, here:
(defun non-trailing-whitespaces-modes (mode)
(let ((hook (intern (concat mode "-mode-hook"))))
(add-hook hook (lambda () (setq show-trailing-whitespace nil)))))

flet works, but with obsolete message; cl-flet does not work

I'm trying to temporarily turn off the yes-or-no-p within a function that is defined elsewhere and then restore things to the way they were. Using flet works, but creates a *compile-log* buffer telling me that it is obsolete and to use cl-flet instead. However, cl-flet doesn't seem to work with this attempt at defadvice -- i.e., nothing happens and the yes-or-no-p remains active. Any ideas on how to avoid the error message and make this work also?
(defun function-without-confirmation ()
(defadvice elmo-dop-queue-flush (around stfu activate)
(flet ((yes-or-no-p (&rest args) t)
(y-or-n-p (&rest args) t))
ad-do-it))
. . . .
(ad-unadvise 'elmo-dop-queue-flush)
)
I cannot take credit for the answer, because that was solved by wvxvw, so I'll put the relevant fix underneath the original question. The new macro is called lawlist-flet instad of flet, and the obsolete line has been commented out:
(defmacro lawlist-flet (bindings &rest body)
"Make temporary overriding function definitions.
This is an analogue of a dynamically scoped `let' that operates on the function
cell of FUNCs rather than their value cell.
If you want the Common-Lisp style of `flet', you should use `cl-flet'.
The FORMs are evaluated with the specified function definitions in place,
then the definitions are undone (the FUNCs go back to their previous
definitions, or lack thereof).
\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
(declare (indent 1) (debug cl-flet)
;; (obsolete "use either `cl-flet' or `cl-letf'." "24.3")
)
`(letf ,(mapcar
(lambda (x)
(if (or (and (fboundp (car x))
(eq (car-safe (symbol-function (car x))) 'macro))
(cdr (assq (car x) macroexpand-all-environment)))
(error "Use `labels', not `flet', to rebind macro names"))
(let ((func `(cl-function
(lambda ,(cadr x)
(cl-block ,(car x) ,#(cddr x))))))
(when (cl--compiling-file)
;; Bug#411. It would be nice to fix this.
(and (get (car x) 'byte-compile)
(error "Byte-compiling a redefinition of `%s' \
will not work - use `labels' instead" (symbol-name (car x))))
;; FIXME This affects the rest of the file, when it
;; should be restricted to the flet body.
(and (boundp 'byte-compile-function-environment)
(push (cons (car x) (eval func))
byte-compile-function-environment)))
(list `(symbol-function ',(car x)) func)))
bindings)
,#body))
And, here is the modified function that eliminates the error message relating to flet being obsolete.
(defun function-without-confirmation ()
(defadvice elmo-dop-queue-flush (around stfu activate)
(lawlist-flet ((yes-or-no-p (&rest args) t)
(y-or-n-p (&rest args) t))
ad-do-it))
. . . .
(ad-unadvise 'elmo-dop-queue-flush)
Here's how I'd recommend you do it:
(defvar stfu-inhibit-yonp nil)
(defadvice yes-or-no-p (around stfu activate)
(if stfu-inhibit-yonp (setq ad-return t) ad-do-it))
(defadvice y-or-n-p (around stfu activate)
(if stfu-inhibit-yonp (setq ad-return t) ad-do-it))
(defadvice elmo-dop-queue-flush (around stfu activate)
(let ((stfu-inhibit-yonp t))
ad-do-it))
Contrary to CL's flet this will make it clear (e.g. in C-h f yes-or-no-p) that something's going on with yes-or-no-p.

Emacs lisp - can a defun reference itself somehow? [duplicate]

(defun foo ()
(send-to-debug-log "Error. Function terminated." (get-current-function-name)))
I currently do this:
(defun foo ()
(send-to-debug-log "Error. Function terminated." 'foo)))
Hard coding the function name seems not to be a good practice.
Any suggestion to implement the get-current-function-name or get-function-name-that-call-me.
(defun foo ()
(send-to-debug-log "Error. Function terminated." (nth 1 (backtrace-frame 2))))
You could try something like:
(defconst my-defun-macros '(defun cl-defun defmacro cl-defmacro))
(defun my-add-defun-name (orig-fun name &rest args)
(let* ((my-current-defun-name (if (consp name) (cadr name) name))
(macroexpand-all-environment
(cons (cons 'my-get-current-function-name
(lambda () my-current-defun-name))
macroexpand-all-environment))
(code (apply orig-fun name args)))
(macroexpand-all code macroexpand-all-environment)))
(defmacro my-get-current-function-name ()
"Return current defun's name.
Only works within the advised macros in `my-defun-macros'."
(error "my-get-current-function-name used outside of a defun"))
(dolist (m my-defun-macros)
(advice-add m :around #'my-add-defun-name))
Here's something that seems to work pretty well:
(defun calling-function ()
(let ((n 6) ;; nestings in this function + 1 to get out of it
func
bt)
(while (and (setq bt (backtrace-frame n))
(not func))
(setq n (1+ n)
func (and bt
(nth 0 bt)
(nth 1 bt))))
func))
If you call it in a lambda, you get the whole lambda. It works with apply, funcall, and eval.
I think the most simple, robust way is to just explicitly write the function name, as you're doing now.
With the package which-function-mode (in melpa), you can programmatically call the function
(Which-function)
more info:
https://www.masteringemacs.org/article/which-function-mode
http://emacsredux.com/blog/2014/04/05/which-function-mode/