I use ibuffer as well as have opened several frames. The very frequent use-case of mine for ibuffer is to filter the list (C-x C-b) of buffers by name/filename. The catch is that filter works in the same way for all frame (it is predicted I believe). I'd want to have to apply filter for ibuffer listing per each frame I have.
E.g. in a first frame I'd like to see list of buffers filtered by a filename, in a second one filtered by mode.
Looking around ibuffer.el I have discovered an entity called ibuffer-filtering-qualifiers which holds an associative list of currently applied filters. I have tried played:
(let ((ibuffer-filtering-qualifiers '())) ;;; Imitate that there are no filters applied
(call-interactively 'ibuffer))
But this was not worked for me.
Could you please point me out how to achieve such desired behavior of ibuffer?
The function ibuffer-update uses the buffer-list, which includes all frames. Modifying ibuffer-update from using buffer-list to (frame-parameter (selected-frame) 'buffer-list) approaches the behavior you are seeking. An ibuffer filter based upon that same concept should also be possible.
In my opinion, the per frame buffer list (frame-parameter (selected-frame) 'buffer-list) is not the best method to associate buffers with frames because it gets modified too easily. The best method I have seen is frame-bufs by Al Parker: https://github.com/alpaker/Frame-Bufs This has been updated to work with a current version of Emacs, however, I am using a slightly modified version to suit my own needs.
So, the easiest method that I am aware to answer your question is to use a combination of frame-bufs by Al Parker, and use the frame-bufs-buffer-list within ibuffer-update. That gives you the best of both worlds. Here is an example that will give you a nice ibuffer with only the buffers associated with a given frame -- all other buffers will not be displayed. [FYI: frame-bufs also sorts by mode or by file name.]
(require 'ibuffer)
(defalias 'ibuffer-update 'lawlist-ibuffer-update)
(defun lawlist-ibuffer-update (arg &optional silent)
"Regenerate the list of all buffers.
Prefix arg non-nil means to toggle whether buffers that match
`ibuffer-maybe-show-predicates' should be displayed.
If optional arg SILENT is non-nil, do not display progress messages."
(interactive "P")
(if arg
(setq ibuffer-display-maybe-show-predicates
(not ibuffer-display-maybe-show-predicates)))
(ibuffer-forward-line 0)
;; (let* ((bufs (buffer-list))
(let* ((bufs (frame-parameter (selected-frame) 'frame-bufs-buffer-list))
(blist (ibuffer-filter-buffers
(current-buffer)
(if (and
(cadr bufs)
(eq ibuffer-always-show-last-buffer
:nomini)
(minibufferp (cadr bufs)))
(cl-caddr bufs)
(cadr bufs))
(ibuffer-current-buffers-with-marks bufs)
ibuffer-display-maybe-show-predicates)))
(and (null blist)
(featurep 'ibuf-ext)
ibuffer-filtering-qualifiers
(message "No buffers! (note: filtering in effect)"))
(unless silent
(message "Updating buffer list..."))
(ibuffer-redisplay-engine blist arg)
(unless silent
(message "Updating buffer list...done")))
(if (eq ibuffer-shrink-to-minimum-size 'onewindow)
(ibuffer-shrink-to-fit t)
(when ibuffer-shrink-to-minimum-size
(ibuffer-shrink-to-fit)))
(ibuffer-forward-line 0)
;; I tried to update this automatically from the mode-line-process format,
;; but changing nil-ness of header-line-format while computing
;; mode-line-format is asking a bit too much it seems. --Stef
(setq header-line-format
(and ibuffer-use-header-line
ibuffer-filtering-qualifiers
ibuffer-header-line-format)))
The issue you have is not that the ibuffer works in the same way for all frames. The issue is that the ibuffer buffer is the same for all the frames (each frame has a separate window (with its cursor) showing your ibuffer unique instance).
A simple solution is to clone the ibuffer buffer (M-x clone-buffer). And that is: you have two different buffers and you can apply filters to them independently.
Related
Edit: What the poster calls a "window", Emacs calls a "frame". I fixed the title.
Concisely, the question is: in a window, how do I switch quickly to a buffer previously visited in that window, even if it's already opened in another window?
A more detailed description follows.
Normally, in order to switch window to previous buffer one just types C-x b RET. That is, the default argument to switch-to-buffer (or ido-switch-buffer) is the previous buffer.
This is not, however, the case when that (previous) buffer is already shown in another window. That's exactly what bugs me.
Let's consider an example. Suppose I have three buffers (A, B and C) and two windows showing buffers A and B (C is not visible at this point).
Then I open buffer A in the second window, too. So, now I have buffer A shown in both windows. Then I switch (C-x b RET) to B again. After that, C-x b RET will bring me not to A, but to C because A is already shown in the other window.
How do I make C-x b RET behave more consistently?
Update
After this problem had been solved, I realized I needed more: namely, for point position to be remembered per-window, not per buffer. Luckily, there're ready-made solutions:
winpoint
per-window-point
They're quite similar; for a discussion of differences see here.
I've found a fix for switch-to-buffer. It eventually calls
(other-buffer (current-buffer))
while in order to fix your problem, the call needs to look like this:
(other-buffer (current-buffer) t)
i.e. the visible-ok argument needs to be t.
Here's an advice to have it always at t. Hopefully it won't break other stuff that uses other-buffer:
(defadvice other-buffer (around fix-switch-to-buffer
(&optional buffer visible-ok frame) activate)
(setq visible-ok t)
ad-do-it)
Note that ido-switch-to-buffer uses a different machinery, so a different method is needed to fix it.
update: fix for ido-switch-to-buffer
I needed to re-define ido-make-buffer-list:
(defun ido-make-buffer-list (default)
(let* ((ido-current-buffers (list (buffer-name (current-buffer))))
(ido-temp-list (ido-make-buffer-list-1 (selected-frame) ido-current-buffers)))
(if ido-temp-list
(nconc ido-temp-list ido-current-buffers)
(setq ido-temp-list ido-current-buffers))
(if default
(setq ido-temp-list
(cons default (delete default ido-temp-list))))
(if (bound-and-true-p ido-enable-virtual-buffers)
(ido-add-virtual-buffers-to-list))
(run-hooks 'ido-make-buffer-list-hook)
ido-temp-list))
The diff is just one line, but it's too messy to advice it.
update: use new advice system for other-buffer
The old stuff should still work for quite a while, but here's the new approach:
(defun other-buffer-advice (orig-fun &optional buffer visible-ok frame)
(funcall orig-fun buffer t frame))
(advice-add 'other-buffer :around #'other-buffer-advice)
;; (advice-remove 'other-buffer :around #'other-buffer-advice)
Instead of advising the built-in function other-buffer, you can pre-select visible buffers using a package.
1 Using Ivy
If you're using Ivy, you can use abo-abo's approach to override the lower-use function ivy-switch-buffer.
(defun user/ivy-switch-buffer ()
"Switch to another buffer with visible-ok preselection."
(interactive)
(ivy-read "Switch to buffer: " #'internal-complete-buffer
:keymap ivy-switch-buffer-map
:preselect (buffer-name (other-buffer (current-buffer) t))
:action #'ivy--switch-buffer-action
:matcher #'ivy--switch-buffer-matcher
:caller 'ivy-switch-buffer))
(advice-add 'ivy-switch-buffer :override #'user/ivy-switch-buffer)
2 Using Ido mode
2.1 Switching to a buffer shown in another frame
If by "window" you really mean "frame" (i.e., you'd like to ido-switch-buffer to a buffer that is currently shown in another frame), then ido-mode gives you the behavior you're looking for when you change ido-default-buffer-method from its default value of raise-frame to selected-window:
(setq ido-default-buffer-method 'selected-window)
Emacs constructs an independent buffer list for each frame, so the only thing you have to do is to configure Ido to avoid jumping to another frame when you switch buffers.
2.2 Switching to a buffer that is shown in another window inside the same frame
To get this behavior across windows within the same frame, you should hook a function that reorders the buffer list onto ido-make-buffer-list-hook.
From ido.el:
;; Changing the list of files
;; --------------------------
;; By default, the list of current files is most recent first,
;; oldest last, with the exception that the files visible in the
;; current frame are put at the end of the list. A hook exists to
;; allow other functions to order the list. For example, if you add:
;;
;; (add-hook 'ido-make-buffer-list-hook 'ido-summary-buffers-to-end)
;;
;; then all files matching "Summary" are moved to the end of the
;; list. (I find this handy for keeping the INBOX Summary and so on
;; out of the way.) It also moves files matching "output\*$" to the
;; end of the list (these are created by AUCTeX when compiling.)
;; Other functions could be made available which alter the list of
;; matching files (either deleting or rearranging elements.)
I have been wondering for a very long time now: how to get a dedicated misc buffer in Emacs?
Auto-completion, function descriptions and perhaps documentation all can go there without ending up somewhere unexpected, but instead at a predefined location (a quarter of the screen perhaps?).
(I'm assuming you mean a dedicated window instead of a dedicated buffer.) If you keep a window open without doing any other window-splitting commands, help/repl buffers will automatically use it. You can change the size of the window as described in this question.
If you want to do be able to do normal window manipulation but have help windows be a certain size, I suggest you investigate temp-buffer-show-hook, a hook that is run when temporary buffers (such as help buffers) are shown. I haven't tried it, but it would probably be possible to set it to a function that arranges your window configuration in a particular way.
Here is what I do in One On One, to define a dedicated *Help* frame:
;; *Help* frame
(if 1on1-*Help*-frame-flag
(add-to-list
'special-display-buffer-names
(list "*Help*" '1on1-display-*Help*-frame
(list (cons 'background-color 1on1-help-frame-background)
(cons 'mouse-color 1on1-help-frame-mouse+cursor-color)
(cons 'cursor-color 1on1-help-frame-mouse+cursor-color)
'(height . 40))))
(setq special-display-buffer-names
(1on1-remove-if (lambda (elt) (equal "*Help*" (car elt)))
special-display-buffer-names)))
(defun 1on1-display-*Help*-frame (buf &optional args)
"Display *Help* buffer in its own frame.
`special-display-function' is used to do the actual displaying.
BUF and ARGS are the arguments to `special-display-function'."
(let ((old-ptr-shape (and (boundp 'x-pointer-shape) x-pointer-shape))
return-window)
(when (boundp 'x-pointer-xterm) (setq x-pointer-shape x-pointer-xterm))
(setq return-window (select-window (funcall special-display-function buf args)))
(raise-frame)
(setq x-pointer-shape old-ptr-shape)
return-window))
You don't need all of those details (pointer shapes etc.), but that gives you the idea. The main thing is to put *Help* on special-display-buffer-names. That's really all you need to do.
The 1on1-* variables used for the frame parameters here are pretty obvious. The *-remove-if function is a standard remove-if. The complete code is here: oneonone.el.
If I use dabbrev-expand for expansion, Emacs searches the current buffer, then other buffers with the same mode. This is handled by dabbrev-friend-buffer-function which by default is set to dabbrev--same-major-mode-p.
This works fine, but I'd like to use hippie-expand.
(setq hippie-expand-try-functions-list
'(try-expand-dabbrev
try-expand-dabbrev-all-buffers))
This pulls completions from all buffers, even the buffers that don't match my current major mode.
How can I use hippie-expand with dabbrev completions only coming from buffers using the same major-mode as the current buffer?
Quick and dirty solution: Copy the source code of the function try-expand-dabbrev-all-buffers to a new location, rename it (say) try-expand-dabbrev-all-buffers-same-mode, and replace the expression (buffer-list) with the expression:
(remove-if-not (lambda (x) (eq major-mode (with-current-buffer x major-mode)))
(buffer-list))
(You'll need to (require 'cl) to get remove-if-not, or else re-implement it in terms of mapcar and delq.)
Then, of course, replace try-expand-dabbrev-all-buffers with try-expand-dabbrev-all-buffers-same-mode in hippie-expand-try-functions-list.
You can get the source of try-expand-dabbrev-all-buffers using C-hf.
Based on Sean's excellent suggestion (and assuming you have the dash.el list utility library installed):
(autoload '--filter "dash" nil t)
;; only consider buffers in the same mode with try-expand-dabbrev-all-buffers
(defun try-expand-dabbrev-matching-buffers (old)
(let ((matching-buffers (--filter
(eq major-mode (with-current-buffer it major-mode))
(buffer-list))))
(flet ((buffer-list () matching-buffers))
(try-expand-dabbrev-all-buffers old))))
I am planning on the following steps to get the output of the question.
get the list of buffers and iterate on it
get the contents of the buffers using the buffer name obtained in step 1.
change the contents and overwrite the buffer.
The (buffer-list) fn output is very confusing. It shows like
(# ...)
I dont understand what does # < and * stands for.
The output of buffer-list is a list of buffer objects.
Functions dealing with a specific buffer will typically accept a buffer object as an argument:
(buffer-name (car (buffer-list)))
The #<...> syntax is explained here:
M-: (info "(elisp) Printed Representation") RET
I can't imagine why you'd want to modify all buffers (remember this includes the minibuffer, possibly some internal-use buffers, various others like *Help*, *Messages*, and maybe some read-only buffers), but you could use the following as the basis:
(let ((buffers (buffer-list)))
(while (car buffers)
(set-buffer (car buffers))
(let ((contents (save-restriction (widen) (buffer-string))))
[do something with contents] )
(setq buffers (cdr buffers))))
How do you list the active minor modes in emacs?
C-h m or M-x describe-mode shows all the active minor modes (and major mode) and a brief description of each.
A list of all the minor mode commands is stored in the variable minor-mode-list. Finding out whether they're active or not is usually done by checking the variable of the same name. So you can do something like this:
(defun which-active-modes ()
"Give a message of which minor modes are enabled in the current buffer."
(interactive)
(let ((active-modes))
(mapc (lambda (mode) (condition-case nil
(if (and (symbolp mode) (symbol-value mode))
(add-to-list 'active-modes mode))
(error nil) ))
minor-mode-list)
(message "Active modes are %s" active-modes)))
Note: this only works for the current buffer (because the minor modes might be only enabled in certain buffers).
describe-mode can somehow come up with a list of enabled minor modes, why couldn't I? So after reading its source code I realized that it gets the list of active minor modes from both minor-mode-list and minor-mode-alist. Using 3rd-party dash.el list manipulation library I came with this code:
(--filter (and (boundp it) (symbol-value it)) minor-mode-list)
So, for example, to disable all minor modes, use -each:
(--each (--filter (and (boundp it) (symbol-value it)) minor-mode-list)
(funcall it -1))
Don't forget to save the list of minor modes in a variable, otherwise you would have to restart Emacs or enable them by memory.
If you want to programmatically do something with all buffers that have a certain mode active, then the best, most minimalistic, cleanest, built-in solution is as follows:
(dolist ($buf (buffer-list (current-buffer)))
(with-current-buffer $buf
(when some-buffer-local-minor-or-major-mode-variable-you-want-to-find
(message "x %s" $buf))))
It does the following:
Retrieve a list of all buffers via buffer-list, with the currently active buffer at the head of the list (so it's treated first, usually what you want, but leave out the current-buffer parameter if you don't care).
Loop through the buffer list and assign each buffer name to the variable $buf.
Use with-current-buffer $buf to tell Emacs that all code within the body should run as if it was running inside buffer $buf instead of whatever buffer you're really displaying on screen.
when <some mode variable> is the correct way to check if a mode is enabled; you can also use if and other such methods. Either way, the goal is to check if a minor or major-mode's main mode variable is set in the buffer. Almost all modes define a variable via "defining" a mode, which automatically causes them to create a buffer-local variable named after the mode, which is how this works. And if they don't have a standard variable, look at their own source code to see how their "toggle" code determines how to toggle them on and off. 99% of them use the existence of their modename's variable (and if they don't, I suggest reporting that as a bug to the mode's author). For example, to check if a buffer has whitespace-mode active, you would say when whitespace-mode.
After that, it just outputs a message to the Messages buffer, with an "x" and the name of the buffer that had the mode active. That's where you'd put your own code, to do whatever you wanted to do with the discovered buffer.
Enjoy! Onwards to greater and cleaner lisp code!
Here is a simple alternative snippet similar to some of the methods that have already been addressed in other answers:
(delq nil
(mapcar
(lambda (x)
(let ((car-x (car x)))
(when (and (symbolp car-x) (symbol-value car-x))
x)))
minor-mode-alist))
If you just want to know if a particular minor mode (say, evil-mode) is active in the buffer, you could evaluate the following:
(when (member 'evil-mode minor-mode-list)
(message "`evil-mode' is active!"))