Use value of buffer-local variable in another buffer - emacs

How can you process a buffer local variable in another buffer? I thought I could just bind it with let, but am having trouble passing the variable to another function that uses symbol-value. Here is a small example,
(defvar-local local-var nil)
(setq local-var "a")
(defun fun ()
(let ((local-var local-var))
(with-temp-buffer
(format-fun 'local-var)
(message (buffer-string)))))
(defun format-fun (name)
(insert (symbol-value name)))
How can I bind local-var in fun so format-fun can process it in another buffer?

There is an elisp function to get a buffer-local variable value from another buffer:
(buffer-local-value 'var (get-buffer "your-buffer-name"))

Binding the variable with let doesn't stop it from being reassigned when switching buffers.
Use a different variable to avoid this.
(defun fun ()
(let ((new-var local-var))
(with-temp-buffer
(format-fun 'new-var)
(message (buffer-string)))))

Related

Temporarily change a function variable in elisp

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

Substitute symbol name in macro

How can I substitute a symbol name into a function created in a macro? I think I am missing something obvious here. For example, I am trying to make a macro that defines some variables and functions similar to the following,
(cl-defmacro mac (pkg)
(let (
;; Define some variables
(sym (intern (concat pkg "-file")))
(sym-def "default-file.el")
(sym-doc (concat "A custom var from `" pkg "'."))
;; Define some functions
(symfn (intern (concat pkg "-fn")))
(symfn-doc (concat "A function for `" pkg "'.")))
`(list
(defcustom ,sym ,sym-def ,sym-doc
:group (quote ,(make-symbol pkg))
:type '(choice (const :tag "None" nil)
file))
(defun ,symfn ()
,symfn-doc
(interactive)
(fn ,sym)))))
The function returned makes a call out to another function (fn) with a signature like
(defun fn (var) (symbol-value var))
So, it is expecting a call like (fn 'some-var). And, I want to be able to use the macro like
(mac "pack")
And have the following work,
pack-file ; works: "default-file.el"
(pack-fn) ; error: not a symbol
I have tried things like (quote ,sym), symbol-name, and others... But can't seem to get it right.
You want the call to fn to be (fn ',sym) (which you mention you tried in the question, but I suspect got wrong somehow).
You probably also want the expansion of the macro to be (progn ...) instead of (list ...).
(This was originally a comment: I'm putting it here just so there's an answer.)

Result value of elisp code stored in a file?

Looking for a way how evaluate elisp code stored in an external file and pass its result as a function argument. Example demonstrating what I'd like to achieve follows:
;; content of my_template.el
'(this is a list)
;; content of .emacs where result of my_template.el has to be used
(define-auto-insert "\.ext$"
;; bellow is my attempt to retrieve resulting list object
;; but getting nil instead
(with-temp-buffer
(insert-file-contents ("my_template.el"))
(eval-buffer))))
Probably looking for an eval-like function which besides side-effect also returns result of the last expression.
Any idea ?
Using variable to share data is easier and more common, for example:
;; content of ~/my_template.el
(defvar my-template '(this is a list))
;; content of .emacs where result of my_template.el has to be used
(load-file "~/my_template.el")
(define-auto-insert "\.ext$"
my-template)
Update the function eval-file should do what you want:
;; content of ~/my_template.el
'(this is a list)
(defun eval-file (file)
"Execute FILE and return the result of the last expression."
(load-file file)
(with-temp-buffer
(insert-file-contents file)
(emacs-lisp-mode)
(goto-char (point-max))
(backward-sexp)
(eval (sexp-at-point))))
(eval-file "~/my_template.el")
=> (this is a list)
Update two: without evaluate the last expression twice
(defun eval-file (file)
"Execute FILE and return the result of the last expression."
(eval
(ignore-errors
(read-from-whole-string
(with-temp-buffer
(insert-file-contents file)
(buffer-string))))))
(eval-file "~/my_template.el")
=> (this is a list)
Don't read from a string. Read from a buffer.
(defun load&return (file &optional msgp)
"Load FILE. Return the value of the last sexp read."
(interactive "fFile: \np")
(let* ((sexp (with-current-buffer (find-file-noselect file)
(goto-char (point-min))
(read (current-buffer))))
(val (ignore-errors (eval sexp))))
(prog1 val (when msgp (message "Value: %S" val)))))

The mechanism iswtichb used to show completions

all.
I decided to hack iswitchb this morning, and found a confusing thing.
Usually,when we command iswitchb,we got someting in minibuffer like:
iswitch {buffer1,buffer2 ...}
What in braces is the completions, as we typing its number
is shrinking.
And I didn't find how iswitchb achieved this when hacking on
its code (sorry for my dullness ).
This is original iswitchb-read-buffer with doc-string ripped
off:
(defun iswitchb-read-buffer (prompt &optional default require-match
start matches-set)
(let
(
buf-sel
iswitchb-final-text
(icomplete-mode nil) ;; prevent icomplete starting up
)
(iswitchb-define-mode-map)
(setq iswitchb-exit nil)
(setq iswitchb-default
(if (bufferp default)
(buffer-name default)
default))
(setq iswitchb-text (or start ""))
(unless matches-set
(setq iswitchb-rescan t)
(iswitchb-make-buflist iswitchb-default)
(iswitchb-set-matches))
(let
((minibuffer-local-completion-map iswitchb-mode-map)
;; Record the minibuffer depth that we expect to find once
;; the minibuffer is set up and iswitchb-entryfn-p is called.
(iswitchb-minibuf-depth (1+ (minibuffer-depth)))
(iswitchb-require-match require-match))
;; prompt the user for the buffer name
(setq iswitchb-final-text (completing-read
prompt ;the prompt
'(("dummy" . 1)) ;table
nil ;predicate
nil ;require-match [handled elsewhere]
start ;initial-contents
'iswitchb-history)))
(if (and (not (eq iswitchb-exit 'usefirst))
(get-buffer iswitchb-final-text))
;; This happens for example if the buffer was chosen with the mouse.
(setq iswitchb-matches (list iswitchb-final-text)
iswitchb-virtual-buffers nil))
;; If no buffer matched, but a virtual buffer was selected, visit
;; that file now and act as though that buffer had been selected.
(if (and iswitchb-virtual-buffers
(not (iswitchb-existing-buffer-p)))
(let ((virt (car iswitchb-virtual-buffers))
(new-buf))
;; Keep the name of the buffer returned by find-file-noselect, as
;; the buffer 'virt' could be a symlink to a file of a different name.
(setq new-buf (buffer-name (find-file-noselect (cdr virt))))
(setq iswitchb-matches (list new-buf)
iswitchb-virtual-buffers nil)))
;; Handling the require-match must be done in a better way.
(if (and require-match
(not (iswitchb-existing-buffer-p)))
(error "Must specify valid buffer"))
(if (or (eq iswitchb-exit 'takeprompt)
(null iswitchb-matches))
(setq buf-sel iswitchb-final-text)
;; else take head of list
(setq buf-sel (car iswitchb-matches)))
;; Or possibly choose the default buffer
(if (equal iswitchb-final-text "")
(setq buf-sel (car iswitchb-matches)))
buf-sel))
And this is the part of iswitchb-read buffer,which I thought
is responsible for functioning completion mechanism.
(defun iswitchb-read-buffer (prompt &optional default require-match
start matches-set)
(let
(
(iswitchb-minibuf-depth (1+ (minibuffer-depth)))
)
;; prompt the user for the buffer name
(completing-read
prompt ;the prompt
'(("dummy" . 1)) ;table
nil ;predicate
nil ;require-match [handled elsewhere]
start ;initial-contents
'iswitchb-history)))
Eval
(iswitchb-read-buffer "Test: ")
resulting
Test: {buffer1,buffer2,...}
So, I think I'm right.
So,what confused me is how can sexp:
(iswitchb-minibuf-depth (1+ (minibuffer-depth)))
has effect on what echos in minibuffer. Comment this
sexp,or replace iswitchb-minibuffer-depth with another
variable, the completions will disappear.
Any advice?
This variable is used in iswitchb-entryfn-p which is called from iswitchb-minibuffer-setup
(defun iswitchb-minibuffer-setup ()
"Set up minibuffer for `iswitchb-buffer'.
Copied from `icomplete-minibuffer-setup-hook'."
(when (iswitchb-entryfn-p)
(set (make-local-variable 'iswitchb-use-mycompletion) t)
(add-hook 'pre-command-hook 'iswitchb-pre-command nil t)
(add-hook 'post-command-hook 'iswitchb-post-command nil t)
(run-hooks 'iswitchb-minibuffer-setup-hook)))
When iswitchb-minibuf-depth is null then iswitchb-entryfn-p is null and the setup is not done.
The iswitchb-minibuffer-setup is a hook which is added to the iswitchb-mode.
BTW, while this may not directly answer your question, this part of iswitchb's behavior is also provided by icomplete-mode (for the normal completion code).

How do I do closures in Emacs Lisp?

I'm trying to create a function on the fly that would return one constant value.
In JavaScript and other modern imperative languages I would use closures:
function id(a) {
return function() {return a;};
}
but Emacs lisp doesn't support those.
I can create mix of identity function and partial function application but it's not supported either.
So how do I do that?
Found another solution with lexical-let
(defun foo (n)
(lexical-let ((n n)) #'(lambda() n)))
(funcall (foo 10)) ;; => 10
Real (Not Fake) Closures in Emacs 24.
Although Emacs 24 has lexical scooping when the variable lexical-binding has value t, the defun special form doesn’t work properly in lexically bound contexts (at least not in Emacs 24.2.1.) This makes it difficult, but not impossible, to define real (not fake) closures. For example:
(let ((counter 0))
(defun counting ()
(setq counter (1+ counter))))
will not work as expected because the symbol counter in the defun will be bound to the global variable of that name, if there is one, and not the lexical variable define in the let. When the function counting is called, if the global variable doesn’t, exist then it will obviously fail. Hoever if there is such a global variable it be updated, which is probably not what was intended and could be a hard to trace bug since the function might appear to be working properly.
The byte compiler does give a warning if you use defun in this way and presumably the issue will be addressed in some future version of Emacs, but until then the following macro can be used:
(defmacro defun** (name args &rest body)
"Define NAME as a function in a lexically bound context.
Like normal `defun', except that it works correctly in lexically
bound contexts.
\(fn NAME ARGLIST [DOCSTRING] BODY...)"
(let ((bound-as-var (boundp `,name)))
(when (fboundp `,name)
(message "Redefining function/macro: %s" `,name))
(append
`(progn
(defvar ,name nil)
(fset (quote ,name) (lambda (,#args) ,#body)))
(if bound-as-var
'nil
`((makunbound `,name))))))
If you define counting as follows:
(let ((counter 0))
(defun** counting ()
(setq counter (1+ counter))))
it will work as expected and update the lexically bound variable count every time it is invoked, while returning the new value.
CAVEAT: The macro will not work properly if you try to defun** a function with the same name as one of the lexically bound variables. I.e if you do something like:
(let ((dont-do-this 10))
(defun** dont-do-this ()
.........
.........))
I can’t imagine anyone actually doing that but it was worth a mention.
Note: I have named the macro defun** so that it doesn’t clash with the macro defun* in the cl package, however it doesn’t depend in any way on that package.
Stupid idea: how about:
(defun foo (x)
`(lambda () ,x))
(funcall (foo 10)) ;; => 10
Emacs lisp only has dynamic scoping. There's a lexical-let macro that approximates lexical scoping through a rather terrible hack.
Emacs 24 has lexical binding.
http://www.emacswiki.org/emacs/LexicalBinding
;; -*- lexical-binding:t -*-
(defun create-counter ()
(let ((c 0))
(lambda ()
(setq c (+ c 1))
c)))
(setq counter (create-counter))
(funcall counter) ; => 1
(funcall counter) ; => 2
(funcall counter) ; => 3 ...
http://www.emacswiki.org/emacs/FakeClosures