How to change lambda content dynamically in Emacs Lisp? - lisp

I have two functions that return an anonymous function, and almost all the content in the functions are the same except for a few lines.
(defun foo ()
(interactive)
(lambda (arg)
(when (not (string-empty-p arg))
(message "foo")
(message arg))))
(defun bar ()
(interactive)
(lambda (arg)
(when (not (string-empty-p arg))
(message "bar")
(message arg))))
Therefore, I created a function that received lists as argument and returned an anonymous function as follows:
(defun make-anonymous-func (&rest body)
(interactive)
(lambda (arg)
`(when (not (string-empty-p arg))
,#body
(message arg))))
However, when I executed the function returned by make-anonymous-func, the list in lambda was recognized as list literal and wasn't properly evaluated.
(funcall (make-anonymous-func '(message "foo")) "bar")
; ===> (when (not (string-empty-p arg)) (message "foo") (message arg))
Are there some good ways to make it work?
Thanks.

A form like
`(when (not (string-empty-p arg))
,#body
(message arg))
is equivalent to something like this:
(append '(when (not (string-empty-p arg)))
body
((message arg))))
So your function can be rewritten like this:
(defun make-anonymous-func (&rest body)
(lambda (arg)
(append '(when (not (string-empty-p arg)))
body
`((message arg)))))
And I think it's now very clear why this can't work. More generally, backquote forms provide a concise way of describing ways of constructing s-expressions by filling in templates, which is useful in macros, since s-expressions represent Lisp source code and macros are essentially functions whose values are source code, ad well as in other places where you want to construct s-expressions from templates.
(One horrible approach to do what you want is eval which evaluates source code. There are many reasons why this is a very bad answer however, so I won't go into it here.)
The general way to do what you're after is to rely on lexical scope. Conveniently elisp now has lexical scope, so you actually can do this. The following two examples assume that lexical-binding is true.
First of all if you merely want to capture the value of some variable bindings then you can do this:
(defun make-anonymous-func (msg)
(lambda (arg)
(when (not (string-empty-p arg))
(message msg)
(message arg))))
The second approach is if you want the function to run some general code: the way to do this is to pass it a function to call:
(defun make-anonymous-func (f)
(lambda (arg)
(when (not (string-empty-p arg))
(funcall f arg)
(message arg))))
And now
(funcall (make-anonymous-func
(lambda (m)
(message "foo")
(sit-for 1)))
"x")
Will cause two messages to appear, but this time there will be a pause between them so you'll see the first.
A final possibility, if what you want to do is create a bunch of similar functions statically – at compile time or definition time rather than dynamically at runtime – is to use a macro.
(defmacro define-messaging-function (name args &rest forms)
;; elisp has no destructuring, so check
(unless (and (listp args) (= (length args) 1)
(symbolp (car args)))
(error "bad arguments"))
(let ((arg (car args)))
`(defun ,name (,arg)
(when (not (string-empty-p ,arg))
,#forms
(message ,arg)))))
And now
(define-messaging-function foo (x)
(message "foo"))
Defines foo as a function which, when called, will do what the function returned by your original foo did.

Related

How to make eshell-autojump case insensitive under Linux

Under Linux, eshell-autojump will do case sensitive matching which I just find a nuisance. I've tried to circumvent this by advising eshell/j with a eshell-under-windows-p that always returns t but to my chagrin eshell-under-windows-p invoked in eshell/j is unaffected by cl-letf. I've modified my eshell/j a bit to give me some debug info:
;; Modified eshell/j inside eshell-autojump.el to this
(defun eshell/j (&rest args) ; all but first ignored
"Jump to a directory you often cd to.
This compares the argument with the list of directories you usually jump to.
Without an argument, list the ten most common directories.
With a positive integer argument, list the n most common directories.
Otherwise, call `eshell/cd' with the result."
(setq args (eshell-flatten-list args))
(let ((path (car args))
(candidates (eshell-autojump-candidates))
(case-fold-search (eshell-under-windows-p))
result)
(when (not path)
(setq path 10))
(message "case-fold-search = %S" case-fold-search)
(message "eshell-under-windows-p returns %s from inside eshell/j" (eshell-under-windows-p))
(if (and (integerp path) (> path 0))
(progn
(let ((n (nthcdr (1- path) candidates)))
(when n
(setcdr n nil)))
(eshell-lisp-command (mapconcat 'identity candidates "\n")))
(while (and candidates (not result))
(if (string-match path (car candidates))
(setq result (car candidates))
(setq candidates (cdr candidates))))
(eshell/cd result))))
My init.el adds the advice to attempt to make eshell/j caseless by trying to trick it to think we are on Windows:
;; Added to init.el
(require 'eshell-autojump)
(advice-add 'eshell/j :around
(lambda (orig-fun &rest xs)
(cl-letf (((symbol-function 'eshell-under-windows-p) (lambda () t)))
(progn (message "eshell-under-windows-p returns %s from lambda" (eshell-under-windows-p)) (apply orig-fun xs)))))
But all I get in Messages buffer when I try to jump in eshell is:
;; I get in *Messages*
eshell-under-windows-p returns t from lambda
case-fold-search = nil
eshell-under-windows-p returns nil from inside eshell/j
My rookie knowledge of elisp is not enough to wrestle with probable scoping issues here. Can anyone decode why eshell-under-window-p is unaffected when called from eshell/j here?
I've found the answer. cl-letf does not work for byte compiled functions. As eshell-autojump is a package it gets byte compiled upon installation and cl-letf cannot be used to modify it's internal behavior. I had to resort to redefining the eshell/j which is a suboptimal solution.

Is there any way to see the implementations of built-in macros in Common Lisp?

Common Lisp built-in functions are probably implemented in C. But I imagine macros are implemented in lisp (sorry if I'm wrong about any of two sentences). Is there any way (through some function or some macro) to see the implementations of built-in macros in Common Lisp? I'm using CLisp.
The ability to inspect function and macro definitions is a feature of your development environment. These days it is typical to use SLIME or SLY with emacs as the basis of a Lisp development environment. I personally use SLIME, but I have heard good things about SLY, too.
In SLIME you can invoke slime-edit-definition (either by keying M-x slime-edit-definition or by using the keybinding M-.) to visit a definition for the symbol under the cursor in a source file. This works both when editing in a source file, or from the REPL. This feature is extremely useful when you want to inspect some library code you are working with, but you can also view a lot of built-in definitions this way. You can even jump to a new definition from a new symbol found in whatever definition you are currently inspecting.
After you are done looking at a definition, you can use M-x slime-pop-find-definition-stack, or the easier to remember keybinding M-, (M-* will also work), to back out through the previously viewed definitions, eventually returning to your starting point.
Here is an example, in SBCL:
CL-USER> with-open-file[press M-.]
(Note that the "[press M-.]" above is not typed, but only meant to remind what action is taken here). With the cursor on or right after the symbol with-open-file, press M-. to see the definition:
(sb-xc:defmacro with-open-file ((stream filespec &rest options)
&body body)
(multiple-value-bind (forms decls) (parse-body body nil)
(let ((abortp (gensym)))
`(let ((,stream (open ,filespec ,#options))
(,abortp t))
,#decls
(unwind-protect
(multiple-value-prog1
(progn ,#forms)
(setq ,abortp nil))
(when ,stream
(close ,stream :abort ,abortp)))))))
This time after keying M-. SLIME gives a choice of definitions to view:
CL-USER> and[press M-.]
Displayed in an emacs buffer:
/path-to-source/sbcl-2.0.4/src/code/macros.lisp
(DEFMACRO AND)
/path-to-source/sbcl-2.0.4/src/pcl/ctypes.lisp
(DEFINE-METHOD-COMBINATION AND)
We want to see the macro definition, so move the cursor to the line showing (DEFMACRO AND), and the following definition is displayed:
;; AND and OR are defined in terms of IF.
(sb-xc:defmacro and (&rest forms)
(named-let expand-forms ((nested nil) (forms forms) (ignore-last nil))
(cond ((endp forms) t)
((endp (rest forms))
(let ((car (car forms)))
(cond (nested
car)
(t
;; Preserve non-toplevelness of the form!
`(the t ,car)))))
((and ignore-last
(endp (cddr forms)))
(car forms))
;; Better code that way, since the result will only have two
;; values, NIL or the last form, and the precedeing tests
;; will only be used for jumps
((and (not nested) (cddr forms))
`(if ,(expand-forms t forms t)
,#(last forms)))
(t
`(if ,(first forms)
,(expand-forms t (rest forms) ignore-last))))))
There is more stuff here, since you are now actually in the source file that contains the definition for and; if you scroll down a bit you can also find the definition for or.
A lot of SBCL functions are written in Lisp; SBCL has a very high-quality compiler, so a lot of stuff that you might otherwise expect to be written in C can be written in Lisp without loss of performance. Here is the definition for the function list-length:
CL-USER> list-length[press M-.]
(defun list-length (list)
"Return the length of the given List, or Nil if the List is circular."
(do ((n 0 (+ n 2))
(y list (cddr y))
(z list (cdr z)))
(())
(declare (type fixnum n)
(type list y z))
(when (endp y) (return n))
(when (endp (cdr y)) (return (+ n 1)))
(when (and (eq y z) (> n 0)) (return nil))))
The same thing can be done when using CLISP with SLIME. Here is with-open-file as defined in CLISP:
CL-USER> with-open-file[press M-.]
(defmacro with-open-file ((stream &rest options) &body body)
(multiple-value-bind (body-rest declarations) (SYSTEM::PARSE-BODY body)
`(LET ((,stream (OPEN ,#options)))
(DECLARE (READ-ONLY ,stream) ,#declarations)
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1
(PROGN ,#body-rest)
;; Why do we do a first CLOSE invocation inside the protected form?
;; For reliability: Because the stream may be a buffered file stream,
;; therefore (CLOSE ,stream) may produce a disk-full error while
;; writing the last block of the file. In this case, we need to erase
;; the file again, through a (CLOSE ,stream :ABORT T) invocation.
(WHEN ,stream (CLOSE ,stream)))
(WHEN ,stream (CLOSE ,stream :ABORT T))))))
But, many CLISP functions are written in C, and those definitions are not available to inspect in the same way as before:
CL-USER> list-length[press M-.]
No known definition for: list-length (in COMMON-LISP-USER)

Use macroexpand-1 on Emacs-22

I am developing a package that works from Emacs-22 called leaf, and I'd like to use macroexpand-1 when testing it
But macroexpand-1 was not defined in Emacs-22 and Emacs-26's the code could not be defined because it depends on 'C - based' autoload-do-load function, even if I try to define it.
Is it impossible to use macroexpand-1 in Emacs-22? A hint to implement
macroexpand-1 another way by Elisp is fine.
(Emacs-22 is bundled with macOS at /usr/bin/emacs)
see PR. https://github.com/conao3/leaf.el/pull/36/commits/47cf0b7c8d6b83b21800d01c594cef8e8d531e57
(when (not (fboundp 'autoload-do-load))
(defun autoload-do-load (fundef &optional funname macro-only)
(if (or (not (consp fundef)) (not (eql 'autoload (car fundef))))
fundef
(let ((kind (nth 4 fundef)))
(if (and (eql macro-only 'macro)
(not (or (eql kind t)
(eql kind 'macro))))
fundef)
(if purify-flag
(error "Attempt to autoload %s while preparing to dump" (symbol-name funnname)))
(unwind-protect
(let ((ignore-errors (if (or (eql kind t) (eql kind 'macro)) nil macro_only)))
(load (cadr fundef) ignore-errors t nil t))
;; FIXME: revert partially performed defuns
())
(if (or (not funname) ignore-errors)
nil
(let ((fun (indirect-function funname, nil)))
(if (equal fun fundef)
(error "Autoloading file %s failed to define function %s"
(caar load-history)
(symbol-name funname))
fun)))))))

Adding comment-end character to Emacs-Lisp

Would it be possible to add a comment-end character to emacs?
I'll take the first code I have and apply what I would like as example:
(defun smart-tab ()
(interactive)
\1\ (if (minibufferp)
\1a\ (minibuffer-complete)
\2\ (if (eq major-mode 'emacs-lisp-mode)
(progn
(save-excursion
(search-backward "(def")
(while (not (looking-at "\\s-*)"))
(beginning-of-line 1)
(indent-for-tab-command)
(beginning-of-line 1)
(next-line)
(when (looking-at (concat ".*" comment-start))
(next-line))))
(indent-for-tab-command))
(yas-expand)))
)
I would like to add some information in the indentation area before the functions, indicating where the logical parts start.
Would this be possible for emacs-lisp, would there be an easy way to use some little trick to consider the evaluater to skip certain text?
Emacs Lisp doesn't have reader macros (or any other way of modifying the reader). But you can do something close to what you want by writing your own macro and using it instead of defun. For example, with this macro definition:
(defmacro mydefun (name args &rest body)
"Define NAME as a function.
Like normal `defun', except BODY may contain |comments|."
(labels ((uncomment (form)
(cond ((not (consp form)) form)
((and (symbolp (car form))
(string-match "|.*|$" (symbol-name (car form))))
(uncomment (cdr form)))
(t (cons (uncomment (car form))
(uncomment (cdr form)))))))
`(defun ,name ,args ,#(uncomment body))))
you can write:
(mydefun smart-tab ()
(interactive)
|1| (if (minibufferp)
|1a| (minibuffer-complete)
|2| (if (eq major-mode 'emacs-lisp-mode)
(progn
(indent-for-tab-command)))))
(It's not possible to use \ for this because that character already has a meaning for the Emacs Lisp reader.)
I have to say, though, that this doesn't seem like a particularly good idea to me. It would be much better to put your section headings in comments to the right of the source:
(defun smart-tab ()
(interactive)
(if (minibufferp) ; 1
(minibuffer-complete) ; 1a
(if (eq major-mode 'emacs-lisp-mode) ; 2
(progn
(indent-for-tab-command)))))
This seems just as clear as your proposal, and much easier for other Emacs Lisp programmers to understand.

Associate an object with a buffer

What I'm trying to do is very similar to what make-local-variable does except that I don't want variables to be declared for every buffer created (only for those which belong to a particular mode). This is mostly a performance concern, the objects created may be big. AND more importantly I'd need a function like (get-buffer-property buffer property-name) to figure out what is the state of the particular buffer.
Essentially, I'm after something similar to get-buffer-proccess except that I need something other than a process.
Will it make sense to create such objects in the declaration of the major mode and destructing them in a hook for when such buffer is killed, or is there a better way for that?
This is what I have so far:
(defun haxe-get-buffer-property (buffer property)
"Pops to BUFFER, reads the value of the PROPERTY and returns it."
(let ((result
(save-excursion
(pop-to-buffer buffer)
(symbol-value property))))
result))
(defmacro haxe-buffer-property (buffer property)
`(haxe-get-buffer-property ,buffer ',property))
(defmacro deflocal (var &rest body)
(let ((symb var)
(val (car body))
(doc (cadr body)))
`(progn
(defvar ,symb nil ,doc)
(unless ,symb (setq ,symb ,val))
(make-local-variable ',symb))))
But I don't like that I have to visit buffers because I'm not sure of side effects.
EDIT: Some more info.
What happens is like so, there are multiple buffers which can interact with a network connection process. This process can be shared by groups of buffers (it is important that buffers share this process), but it also may happen that there exist simultaneously multiple buffers that have different processes assigned to each other. Besides the process itself, there's a lot of info to store about the state of the process (how much data was received, what was sent, errors etc.) Similarly this data has to be shared by groups of buffers.
EDIT2:
This is what become of the code above, just in case anyone will need it.
(defmacro deflocal (var &rest body)
(let ((symb var)
(val (car body))
(doc (cadr body)))
`(progn
(set (make-local-variable ',symb) ,val)
(put ',symb 'variable-documentation ,doc))))
(defun haxe-get-buffer-property (buffer property)
"Pops to BUFFER, reads the value of the PROPERTY and returns it."
(let ((result
(with-current-buffer buffer
(symbol-value property))))
result))
(defun haxe-set-buffer-property (buffer &rest proplist)
"Pops to BUFFER and sets properties in parallel, similar to `pset'."
(let ((result
(with-current-buffer buffer
(loop for (property value) on proplist by #'cddr
do (set property value)
finally (return value)))))
result))
(defmacro haxe-buffer-pset-property (buffer &rest proplist)
`(haxe-set-buffer-property
,buffer
,#(loop for (key value) on proplist by #'cddr
nconc (list (list 'quote key) value))))
(defalias 'haxe-pbset #'haxe-buffer-pset-property)
(defmacro haxe-buffer-setf-property (buffer &rest proplist)
`(with-current-buffer ,buffer
,#(list (append '(setf) proplist))))
(defalias 'haxe-pbsetf #'haxe-buffer-setf-property)
On an emacs -q session I executed the following:
;; set up a hook to create buffer local variable
(add-hook 'html-mode-hook
(lambda ()
(set (make-local-variable 'my-var) "abcd")))
;; find two files, one html and another java
(find-file-noselect "X.java")
(find-file-noselect "X.html")
;; see the buffer value in html buffer
(progn
(set-buffer "X.html")
(message "html:%s" my-var))
;; in java buffer I get error for a void variable
(progn
(set-buffer "X.java")
(message "java:%s" my-var))