Temporarily change a function variable in elisp - emacs

Update
This question is no longer feasible.
Turned out ivy-read doesn't return immediately as I expected. I used C-g to cancel completion which skips the restoring ivy-format-function part.
I'm writing an ivy extension with dynamic collection. I'd like to return a list of list of strings instead of a list of strings as candidates. The default value of ivy-format-function only supports list of strings so I decide to change it to my own function while calling ivy-read then change it back.
I defined the following macro and function:
(defun ivy-foo ()
(interactive)
(with--ivy-foo-format-function
(ivy-read "Foo: "
#'ivy-foo-function
:dynamic-collection t
:require-match t
:action #'ivy-foo--action
:unwind #'ivy-foo--unwind
:history 'ivy-foo-history
:caller 'ivy-foo)))
(defmacro with--ivy-foo-format-function (&rest body)
`(let ((original-function ivy-format-function))
(setq ivy-format-function (lambda (candidates) (ivy-foo--format-function candidates original-function)))
,#body
(setq ivy-format-function original-function)))
(defun ivy-foo--format-function (candidates original-format-function)
(funcall original-format-function
(mapcar
(lambda (cand)
(if (listp cand)
(car cand)
cand))
candidates)))
(defun ivy-foo-function (str)
(list (list "cand1" str) (list "cand2" str)))
with--ivy-foo-format-function doesn't set ivy-format-function to the original value. I got error "Symbol's value as a variable is void: original-function". What's wrong?
Update: ivy-format-function is a defvar. Its default value is #'ivy--format-function-default

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))))))))

How to make describe-function "C-h f" case-insensitive by default

When searching for a function whose name I partly remember, I use C-h f to call describe-function, enter *part-of-function-name, and hit TAB. But I now realize that this search is not case-insensitive.
For example:
C-h f info TAB
lists all functions starting with info, but doesn't include those starting with Info, whereas
C-h f Info TAB
lists all functions starting with Info, but doesn't include those starting with info.
Another example:
C-h f *nfc TAB
gives me *nfc [No match], whereas
C-h f *NFC TAB
gives me ucs-normalize-HFS-NFC-region.
How can I make describe-function case-insensitive by default, using some configuration in my init.el file?
Add a binding of completion-ignore-case to t in the interactive spec of the command. This has the advantages that (a) it affects only describe-function (C-h f) and (b) you can easily toggle it on/off (as with any Emacs advice).
(defadvice describe-function (before ignore-case activate)
"Make it case-insensitive."
(interactive
(let ((completion-ignore-case t) ; <============= ADDED BINDING
(fn (function-called-at-point))
(enable-recursive-minibuffers t)
val)
(setq val (completing-read
(if fn
(format "Describe function (default %s): " fn)
"Describe function: ")
obarray 'fboundp t nil nil (and fn (symbol-name fn))))
(list (if (equal val "") fn (intern val))))))
(setq completion-ignore-case t) should do what you want, tho globally rather than only for C-h f.
Here's a custom function that I use in place of describe-function.
It uses ido completion.
(defvar functions-cache nil)
;;;###autoload
(defun refresh-functions-cache ()
(interactive)
(setq functions-cache nil)
(mapatoms (lambda (symbol)
(when (fboundp symbol)
(push (symbol-name symbol) functions-cache))))
(setq functions-cache (sort functions-cache #'string<)))
;;;###autoload
(defun describe-function-ex (function)
"Display the full documentation of FUNCTION (a symbol)."
(interactive
(let ((fn (function-called-at-point))
(enable-recursive-minibuffers t)
val)
(unless functions-cache
(refresh-functions-cache))
(setq val (ido-completing-read
(if fn
(format "Describe function (default %s): " fn)
"Describe function: ")
functions-cache
nil t nil nil
(and fn (symbol-name fn))))
(list (if (equal val "")
fn (intern val)))))
(if (null function)
(message "You didn't specify a function")
(help-setup-xref (list #'describe-function function)
(called-interactively-p 'interactive))
(save-excursion
(with-help-window (help-buffer)
(prin1 function)
(princ " is ")
(describe-function-1 function)
(with-current-buffer standard-output
;; Return the text we displayed.
(buffer-string))))))

Why doesn't this quoted form evaluate as expected

I have a simple function that works:
(defun ifelse (the-test)
(cond (the-test (format t "passed test, true!"))
(t (format t "failed test, boo hoo"))))
If I do this, I get what you'd expect:
(ifelse (funcall (lambda () nil)))
failed test, boo hoo
NIL
I'm curious why this doesn't also result in a "failure" :
CL-USER> (ifelse '(funcall (lambda () nil)))
passed test, true!
NIL
My thinking is that, rather than evaluating the funcall in place and then passing the return value into ifelse, the entire funcall is being passed unevaluated into the ifelse -- however, how is a quoted form treated within the function? Wouldn't it be essentially copied in-place and then treated as a true Lisp form?
Let's see what you actually get:
(defun return-argument (element) element)
[9]> (defun return-argument (element) element)
RETURN-ARGUMENT
[10]> (return-argument (funcall (lambda () nil)))
NIL
Ok, this is as expected. Now your second function call, which results in a failure.
[11]> (return-argument '(funcall (lambda () nil)))
(FUNCALL (LAMBDA NIL NIL))
Aha, this gives us a clue. We're not evaluating argument, because it's quoted. In fact, we can see we're getting it back as a list:
[19]> (listp (return-argument '(funcall (lambda () nil))))
T
Remember, when you quote something, you prevent it from being evaluated.
Note: return-argument is the same function as the built-in identity. I wrote a new one so you could see what it's doing under the hood.
In the example , you pass a list as argument (because of the quote).
You need to use eval to evaluate the quoted list to have the 'failure'.
like this
(ifelse (eval '(funcall (lambda () nil))))
or remove the quote
(ifelse (funcall (lambda () nil)))

In Elisp how to dynamically assign value to a variable which also selected dynamically (in let form.)

I have a alist of known variables and corresponding functions with nil parameter list, inside body it use that known non-parameter (or global) variable.
for e.g.
(defun funA ()
(message "%s" varA))
(defun funB ()
(message "%s" varB))
...
(setq alist
'((varA . funA)
(varB . funB)
...
))
Similar element in alist can be added / deleted dynamically.
I want to run all these function in another function where the value of known variable assigned dynamically in LET form.
(defun call-each-fun-of-alist ()
(dolist (e alist)
(let (( (car e) (read-from-minibuffer "value: ") ))
(funcall (cdr e)))))
(Yes it will throw error, but I wanted to similar thing, possible without EVAL)
For known element of alist (like first I could do
(let ((varA (read-from-minibuffer "value: ")))
(funcall (cdr (assoc 'varA alist))))
But alist is dynamically updated and I what to run all functions in alist
and the value for corresponding variable will come dynamically.
Please let me know how I can define
call-each-fun-of-alist
(not necessarily but without calling EVAL inside call-each-fun-of-alist, if not possible without EVAL than I like to know it also.)
You could do this with letf (cl-letf in recent Emacs). It binds values like let but allows 'places' or 'generalized variables' as well as simple variable names.
(defun call-each-fun-of-alist ()
(cl-dolist (e alist)
(cl-destructuring-bind (variable . function) e
(cl-letf (((symbol-value variable)
(read-from-minibuffer
(format "value for %s: "
variable))))
(funcall function)))))
Note that this will fail with an error unless the variables named in alist have previously been declared as dynamic variables using defvar. Look up 'generalized variables' in the Elisp manual for more information.
Another solution would be to use cl-progv, which takes parallel lists of variable names and values to bind dynamically:
(defun call-each-fun-of-alist ()
(cl-dolist (e alist)
(cl-destructuring-bind (variable . function) e
(cl-progv
(list variable)
(list (read-from-minibuffer
(format "value for %s: "
variable)))
(funcall function)))))
In Common Lisp this is provided by PROGV - dynamic binding of a variable given the symbol of the variable.
GNU Emacs should have PROGV in its Common Lisp emulation.
This is all you need -- no need for progv or destructing bind stuff:
(defun call-each-fun-of-alist (alist)
(dolist (e alist)
(set (car e) (read-from-minibuffer "value: "))
(funcall (cdr e))))
(defvar my-alist '((varA . funA) (varB . funB)))
(call-each-fun-of-alist my-alist)
Or if you really want to see a let binding for some reason:
(defun call-each-fun-of-alist (alist)
(dolist (e alist)
(eval `(let ((,(car e) (read-from-minibuffer "value: ")))
(funcall (cdr e))))))

Debugging code with a mix of functions, macros, and bash calls in elisp

I am trying to call a bash program herbstclient from Emacs via process-lines. I created a macro hc-call which actually calls herbstclient that is invoked by the function hc which is supposed to convert its numeric arguments into strings via stringify-numbers.
Needless to say it's not working. Calling hc with "keybind" "Mod4-Shift-r" "reload" gives the error:
*** Eval error *** Wrong type argument: listp, stringified-args
I tried using edebug on hc and the output suggested stringify-numbers was working properly. The function errored immediately on the hc-call. Yet, when I run:
(hc-call ("keybind" "Mod4-Shift-r" "reload"))
it works as expected. I then tried:
(setq sargs (list "keybind" "Mod4-Shift-r" "reload"))
(hc-call sargs)
and I got the same error. I don't know how to approach debugging this further. Below is all the code:
(defmacro hc-call (args)
"Call herbstclient to with the given arguments."
`(process-lines "herbstclient" ,#args))
(defun stringify-numbers (args)
"Take a list of random arguments with a mix of numbers and
strings and convert just the numbers to strings."
(let (stringified-args)
(dolist (arg args)
(if (numberp arg)
(setq stringified-args (cons (number-to-string arg) stringified-args))
(setq stringified-args (cons arg stringified-args))))
(nreverse stringified-args)))
(defun hc (&rest args)
"Pass arguments to herbstclient in a bash process."
(let ((stringified-args (stringify-numbers args)))
(hc-call stringified-args)))
Why would it complain stringified-args isn't a list?
Your hc-call should be a function, along the lines of
(defun hc-call (args)
"Call herbstclient to with the given arguments."
(apply #'process-lines "herbstclient" args))
BTW, while I'm here:
(if (numberp arg)
(setq stringified-args (cons (number-to-string arg) stringified-args))
(setq stringified-args (cons arg stringified-args))))
is better written
(setq stringified-args (cons (if (numberp arg) (number-to-string arg) arg) stringified-args))))
or
(push (if (numberp arg) (number-to-string arg) arg) stringified-args)))
Unlike most expressions, macro arguments are passed unevaluated.
This is why (hc-call ("keybind" "Mod4-Shift-r" "reload")) does not result in an error!
It therefore follows that (hc-call sargs) is passing the symbol sargs to the macro, rather than the list to which it would otherwise evaluate.
If you wish your macro to process a variable in this way, you could change ,#args to ,#(eval args), or else conditionally process args either way, depending on what it turns out to actually be.