Emacs list file buffers in clickable text - emacs

I am new to emacs lisp. Today I want to write a emacs lisp function to list my opening files
(that is buffer related to a file) and make them clickable, but i get question in understanding insert-button function.
Here is my code.
(require 'dash)
(require 'button)
(defun insert-button-for-buffer (buf)
(insert-button (buffer-name buf)
'action (lambda (x) (display-buffer (get-buffer buf)))))
(-map 'insert-button-for-buffer
(-filter (lambda (buf) (buffer-file-name buf))
(buffer-list)))
this piece of code just don't work. I guess (display-buffer (get-buffer buf)). The variable in an lambda function just don't get the right value. I know the x argument in lambda in a Overlay.But how could I get buffer-name from x variable? Or is there a better way to achieve this goal? This quetion may seem silly. I hope you guys could help.

You fell for the good ol' lexical binding trap.
Here's a fix:
(require 'button)
(defun insert-button-for-buffer (buf)
(insert-button
(buffer-name buf)
'action
`(lambda (x) (display-buffer ,(get-buffer buf))))
(insert "\n"))
(mapc #'insert-button-for-buffer
(cl-remove-if-not
#'buffer-file-name
(buffer-list)))

Related

How to change the behaviour of org-agenda-goto to open org-file in a new frame?

When pressing TAB (org-agenda-goto) in org-agenda I want to open the related org-file in a new frame instead of splitting the existing frame.
I could create a modified function of org-agenda-goto replacing switch-to-buffer-other-window with switch-to-buffer-other-frame and rebinding the TAB-key but I assume there is a more elegant way to do so?
The quick solution would be as below modifying line 8:
(defun sk/org-agenda-goto (&optional highlight)
"Go to the entry at point in the corresponding Org file."
(interactive)
(let* ((marker (or (org-get-at-bol 'org-marker)
(org-agenda-error)))
(buffer (marker-buffer marker))
(pos (marker-position marker)))
(switch-to-buffer-other-frame buffer)
(widen)
(push-mark)
(goto-char pos)
(when (derived-mode-p 'org-mode)
(org-show-context 'agenda)
(recenter (/ (window-height) 2))
(org-back-to-heading t)
(let ((case-fold-search nil))
(when (re-search-forward org-complex-heading-regexp nil t)
(goto-char (match-beginning 4)))))
(run-hooks 'org-agenda-after-show-hook)
(and highlight (org-highlight (point-at-bol) (point-at-eol)))))
I assume it may be done more elegantly with advice but I'm not so experienced in emacs-lisp and would not know how exactly this could be achived or if using advice would be the right approach.
I found out in override prefered method are hints for using advice-add like this in order to replace the original function with my own:
(advice-add 'org-agenda-goto :override #'sk/org-agenda-goto)
You can use advice to temporarily redefine switch-to-buffer-other-window using cl-letf. Assuming your on at least emacs 25.1 you can use define-advice, eg.
(define-advice org-agenda-goto (:around (orig-fn &rest args) "new-frame")
(cl-letf (((symbol-function 'switch-to-buffer-other-window)
(symbol-function 'switch-to-buffer-other-frame)))
(apply orig-fn args)))
In the advice orig-fn is a placeholder to org-agenda-goto. Alternatively, you could temporarily override display-buffer's function (there are a number of options you could use here -- see help for display-buffer), eg.
(define-advice org-agenda-goto (:around (orig-fn &rest args) "new-frame")
(let ((display-buffer-overriding-action '(display-buffer-pop-up-frame)))
(apply orig-fn args)))

A Simple 'copy-form Command

I want a command that copies a form to the kill ring. In emacs-live, the closest thing I could find was this command / key-binding
(global-set-key (kbd "M-]") 'kill-ring-save)
However kill-ring-save has some wonky behaviour. Ii copies more than 1 form, past the cursor. Ultimately, I want a simple function along the lines of what's below (this doesn't quite work).
(defun copy-form ()
(kill-ring-save (line-beginning-position) (live-paredit-forward)))
(global-set-key (kbd "M-]") 'copy-form)
I've searched high and low ( SO question and Google search), but can't seem to find a simple, working command to copy a balanced expression. Has someone already done this?
Thanks
Tim
Function sexp-at-point gives you the sexp ("form") at the cursor. Just copy that to the kill-ring, using kill-ring-save. E.g.:
(defun copy-sexp-at-point ()
(interactive)
(let ((bnds (bounds-of-thing-at-point 'sexp)))
(kill-ring-save (car bnds) (cdr bnds))))
Alternatively, just use kill-new:
(defun copy-sexp-at-point ()
(interactive)
(kill-new (thing-at-point 'sexp)))
The reason your copy-form cannot be bound to a key is that it is a function, not a command - it is missing an interactive form.
However, in your case you don't even need to write a new function.
Try a combination of
mark-sexp is an interactive compiled Lisp function in `lisp.el'.
It is bound to C-M-#, C-M-SPC.
and
M-w runs the command kill-ring-save, which is an interactive compiled
Lisp function in `simple.el'.
It is bound to <C-insertchar>, M-w, <menu-bar> <edit> <copy>.
I'm not sure I understand the question, but when I need to do what I consider as "copy a balanced form", I do: M-C-SPC M-w. If I want to cut it instead, I do M-C-SPC C-w.
Here's what I generally use. Somehow it's more useful for me
to kill the balanced expression instead of copying. If I want a
copy instead, I first kill, then undo.
This function kills a string, if the point is inside string,
otherwise the balanced expression, i.e. (),[],{},<>
or whatever is defined by the syntax.
(defun kill-at-point ()
"Kill the quoted string or the list that includes the point"
(interactive)
(let ((p (nth 8 (syntax-ppss))))
(cond
;; string
((eq (char-after p) ?\")
(goto-char p)
(kill-sexp))
;; list
((ignore-errors (when (eq (char-after) ?\()
(forward-char))
(up-list)
t)
(let ((beg (point)))
(backward-list)
(kill-region beg (point)))))))
I've also tried to add a special case for when the point is
inside the comment, but I couldn't find a generic
way to determine bounds of comment at point. If anyone knows,
please tell me.
This other function can be relevant as well. It marks instead
of killing, like the previous one. The nice thing that it
extends the region each time it's called.
I bind the first one to C-, and the second to
C-M-,.
(defun mark-at-point ()
"Mark the quoted string or the list that includes the point"
(interactive)
(let ((p (nth 8 (syntax-ppss))))
(if (eq (char-after p) ?\")
(progn
(goto-char p)
(set-mark (point))
(forward-sexp))
(progn
(when (eq (char-after) 40)
(forward-char))
(condition-case nil
(progn
(up-list)
(set-mark (point))
(let ((beg (point)))
(backward-list)
(exchange-point-and-mark)))
(error
(when (looking-back "}")
(exchange-point-and-mark)
;; assumes functions are separated by one empty line
(re-search-backward "^[^A-Z-a-z]" nil t)
(forward-char))))))))

Check if major mode is equal one of several emacs

I found a snippet to close all dired buffers, which I want to use in sunrise commander:
(defun er/kill-all-dired-buffers()
"Kill all dired buffers."
(interactive)
(save-excursion
(let((count 0))
(dolist(buffer (buffer-list))
(set-buffer buffer)
(when (equal major-mode 'sr-mode)
(or (equal major-mode 'dired-mode))
(setq count (1+ count))
(kill-buffer buffer)))
(message "Killed %i dired buffer(s)." count ))))
(setq sr-quit-hook 'er/kill-all-dired-buffers)
Issue being, I can't make it work both for sr-mode and dired-mode together.
How do I check "if major mode is sr-mode OR dired-mode"?
EDIT:
Just a syntax error.
Should be
(when (or (equal major-mode 'dired-mode) (equal major-mode 'sr-mode))
Have to admit it's not too intuitive.
The canonical way would be (when (derived-mode-p 'sr-mode 'dired-mode) ...).
I tried some things and found this to work on my emacs-ielm - perhaps it might help also:
(if (member major-mode '(fsharp-mode c-mode java-mode inferior-emacs-lisp-mode))
(message "yeah right"))
Maybe the correct check function is:
(derived-mode-p &rest MODES)
See 'subr.el'.

elisp dealing with closure

I'm trying to write a macro that can generate a set of functions that I can use to access project directories in a more efficient fashion. If you look at the following macro, you should have a good idea what I'm trying to do.
(defmacro create-project-cmd (project-name project-dir &optional subdir-list)
(if (null subdir-list)
`(fset (intern ,project-name) #'(lambda () (interactive) (dired ,project-dir)))
`(dolist (dir ,subdir-list)
(fset (intern (concat ,project-name "-" dir))
#'(lambda () (interactive) (dired (concat ,project-dir "/" dir)))))))
The problem here is the "dir" in the last line is supposed to bond to the "dir" in dolist clause. And since there is no closure in elisp, when I call a function that is generated, it will complain dir is void.
As you can see from the code, I have faked a closure for "project-dir". I can't fake it the same way for "dir". Even though lexical-let will make it work here, I'm trying to avoid it, since it has some memory issues, and I don't want to grow a habit of using it (maybe I'm too picky here).
I do not have a good way to handle this. Anyone have any good suggestions?
How to overcome the lack of local variable for emacs lisp closure
How do I do closures in Emacs Lisp?
http://www.emacswiki.org/emacs/FakeClosures
Edit: If lexical-let is out, how about something like this:
(defmacro create-project-cmd (project-name project-dir &optional subdir-list)
(if (null subdir-list)
`(fset (intern ,project-name) #'(lambda () (interactive) (dired ,project-dir)))
(let ((fsets nil))
(dolist (dir subdir-list)
(add-to-list
'fsets
`(fset (intern (concat ,project-name "-" ,dir))
#'(lambda () (interactive) (dired (concat ,project-dir "/" ,dir))))))
`(progn ,#fsets))))
(create-project-cmd "projfoo" "projdir" ("foo" "bar" "baz"))
(symbol-function 'projfoo-bar)
(lambda nil (interactive) (dired (concat "projdir" "/" "bar")))

Close all buffers besides the current one in Emacs

How do I close all but the current buffer in Emacs? Similar to "Close other tabs" feature in modern web browsers?
For a more manual approach, you can list all buffers with C-x C-b, mark buffers in the list for deletion with d, and then use x to remove them.
I also recommend replacing list-buffers with the more advanced ibuffer: (global-set-key (kbd "C-x C-b") 'ibuffer). The above will work with ibuffer, but you could also do this:
m (mark the buffer you want to keep)
t (toggle marks)
D (kill all marked buffers)
I also use this snippet from the Emacs Wiki, which would further streamline this manual approach:
;; Ensure ibuffer opens with point at the current buffer's entry.
(defadvice ibuffer
(around ibuffer-point-to-most-recent) ()
"Open ibuffer with cursor pointed to most recent buffer name."
(let ((recent-buffer-name (buffer-name)))
ad-do-it
(ibuffer-jump-to-buffer recent-buffer-name)))
(ad-activate 'ibuffer)
From EmacsWiki: Killing Buffers:
(defun kill-other-buffers ()
"Kill all other buffers."
(interactive)
(mapc 'kill-buffer
(delq (current-buffer)
(remove-if-not 'buffer-file-name (buffer-list)))))
Edit: updated with feedback from Gilles
There isn't a way directly in emacs to do this.
You could write a function to do this. The following will close all the buffers:
(defun close-all-buffers ()
(interactive)
(mapc 'kill-buffer (buffer-list)))
There is a built in command m-x kill-some-buffers (I'm using 24.3.50) In my nextstep gui (not tried in a terminal but sure it's similar) you can then approve which buffers to kill.
(defun only-current-buffer ()
(interactive)
(let ((tobe-killed (cdr (buffer-list (current-buffer)))))
(while tobe-killed
(kill-buffer (car tobe-killed))
(setq tobe-killed (cdr tobe-killed)))))
It works as you expected.
And after reading #Starkey's answer, I think this will be better:
(defun only-current-buffer ()
(interactive)
(mapc 'kill-buffer (cdr (buffer-list (current-buffer)))))
(buffer-list (current-buffer)) will return a list that contains all the existing buffers, with the current buffer at the head of the list.
This is my first answer on StackOverflow. Hope it helps :)
I found this solution to be the simplest one. This deletes every buffer except the current one. You have to add this code to your .emacs file
(defun kill-other-buffers ()
"Kill all other buffers."
(interactive)
(mapc 'kill-buffer (delq (current-buffer) (buffer-list))))
Of course, then you use it with M-x kill-other-buffers RET or you paste the following code in the .emacs file too and then just press C-xC-b
(global-set-key (kbd "C-x C-b") 'kill-other-buffers)
You can like this one as well - kill all buffers except current one, *Messages* and *scratch* (which are handy to have, I call them "toolkit"), close redundant windows as well, living you which one window which current buffer.
(defun my/kill-all-buffers-except-toolbox ()
"Kill all buffers except current one and toolkit (*Messages*, *scratch*). Close other windows."
(interactive)
(mapc 'kill-buffer (remove-if
(lambda (x)
(or
(eq x (current-buffer))
(member (buffer-name x) '("*Messages*" "*scratch*"))))
(buffer-list)))
(delete-other-windows))
I've use crux-kill-other-buffers for some months.
But I want dired buffers get deleted too. #Euge's and #wenjun.yan's answers solve this. But it will delete special buffers (e.g *git-credential-cache--daemon*, *scratch*, helm operation, and etc). So I came up with this (current) solution.
(defun aza-kill-other-buffers ()
"Kill all buffers but current buffer and special buffers"
(interactive)
(dolist (buffer (delq (current-buffer) (buffer-list)))
(let ((name (buffer-name buffer)))
(when (and name (not (string-equal name ""))
(/= (aref name 0) ?\s)
(string-match "^[^\*]" name))
(funcall 'kill-buffer buffer)))))
Inspired from kill-matching-buffers. You can add more condition on other buffer-name to exclude, if you want to.
Hope it helps :)
I've used one of the solutions in this list for years, but now I have a new one of my own.
(defun kill-all-file-buffers ()
"Kills all buffers that are open to files. Does not kill
modified buffers or special buffers."
(interactive)
(mapc 'kill-buffer (cl-loop for buffer being the buffers
when (and (buffer-file-name buffer)
(not (buffer-modified-p buffer)))
unless (eq buffer (current-buffer))
collect buffer)))
cl-loop has buffers built in as a collection that you can iterate over. It gives you a chance to parse out anything you don't want to close. Here, I've made sure that it doesn't close anything you've modified, and it uses buffer-file-name instead of just buffer-name so it doesn't kill special buffers. I also added an 'unless' to take out the current buffer (though you could obviously add it to the 'when', I just thought this was clearer).
But for an even more generic solution, we can define this as a macro, and pass in a function that will apply to all these buffers.
(defmacro operate-on-file-buffers (func)
"Takes any function that takes a single buffer as an argument
and applies that to all open file buffers that haven't been
modified, and aren't the current one."
`(mapc ,func (cl-loop for buffer being the buffers
when (and (buffer-file-name buffer)
(not (buffer-modified-p buffer)))
unless (eq buffer (current-buffer))
collect buffer)))
Now if you want to kill all buffers that match this, you can call it like this
(operate-on-file-buffers 'kill-buffer)
This is what you want:
C-x 1
source: https://blasphemousbits.wordpress.com/2007/05/04/learning-emacs-part-4-buffers-windows-and-frames/