All,
I'm looking for a way to switch buffers in multiple windows similar to other IDEs. Let's say I split my frame into two windows (C-x 3). I'd like to handle buffers for .c filesalways in the left window and .h files in the right. I'm looking for a way to couple a list of buffers to a specific window, and cycle buffers only belonging to the current window. So if I'm editing a .h file on the right side, and press a key combination I get the next .h file.
Thanks for any advice,
Janos
I use buffer-stack (available via MELPA) for something similar. buffer-stack allows you to cycle between buffers in a very flexible way (it remembers your most recent used buffers, and it uses separates stacks per frame).
You can add filter functions to buffer switching commands. So you could add a filter function for considering only buffers with filenames with same extension than the current one. I use a filtering function to switch among buffers of the same mode. Here is it as an example that shows my keybindings to switch filtering by current mode and also swith to dired buffers. It would be easy to add another filter based on file extension:
(defmacro command (&rest body)
`(lambda ()
(interactive)
,#body))
(defvar buffer-stack-mode)
(defun buffer-op-by-mode (op &optional mode)
(let ((buffer-stack-filter 'buffer-stack-filter-by-mode)
(buffer-stack-mode (or mode major-mode)))
(funcall op)))
(defun buffer-stack-filter-by-mode (buffer)
(with-current-buffer buffer
(equal major-mode buffer-stack-mode)))
(global-set-key [(meta kp-7)]
(command (buffer-op-by-mode 'buffer-stack-up)))
(global-set-key [(meta kp-9)]
(command (buffer-op-by-mode 'buffer-stack-down)))
(global-set-key [(meta kp-3)]
(command (buffer-op-by-mode 'buffer-stack-down 'dired-mode)))
(global-set-key [(meta kp-1)]
(command (buffer-op-by-mode 'buffer-stack-up 'dired-mode)))
You can use ff-find-other-file. With a prefix argument
C-u, it will open another window.
As for your idea of getting the next .h file, you're just limiting
yourself by trying to bring a bad idea from IDE into Emacs.
Use projectile or ido-switch-buffer or helm-buffers-list: these
tools can manage hundreds of files at a time, while the approach of "getting the next file"
(i.e. tabs) fails around 20.
Related
I'm using dedicated.el which is very similar to dedicate-windows-manually.el to manually mark certain windows as "dedicated" to their buffer and also inelegible for splitting by various commands that open new buffers (grep, compilation, etc.).
But I really only want the second part.
In other words, I want find-file, kill-buffer, switch-buffer and so on to work as if the current window was not dedicated. But I want other commands (grep, compile) to honor the dedicated status and not split that window.
I made a small attempt at this, but it doesn't work properly and seems like a misguided way to go about it, likely missing many cases.
(One of the problems is that the "dedicated" minor mode is associated with a buffer while set-window-dedicated-p applies to a window; this could be overcome, but I still feel there must be a better way to accomplish what I want...)
(defun with-undedicated (f)
(interactive)
(let ((was-dedicated (bound-and-true-p dedicated-mode)))
(progn
(if was-dedicated (dedicated-mode))
(command-execute f)
(if was-dedicated (dedicated-mode)))))
(defun undedicated-find-file ()
(interactive)
(with-undedicated 'ido-find-file))
(defun undedicated-kill-buffer ()
(interactive)
(with-undedicated 'ido-kill-buffer))
(defun undedicated-switch-buffer ()
(interactive)
(with-undedicated 'ido-switch-buffer))
(global-set-key (kbd "C-x C-f") 'undedicated-find-file)
(global-set-key (kbd "C-x k") 'undedicated-kill-buffer)
(global-set-key (kbd "C-x b") 'undedicated-switch-buffer)
edit
The following was performed to test Drew's answer:
(defun make-weak-dedicated ()
(interactive)
(set-window-dedicated-p (selected-window) "weak"))
(defun dedicated-status ()
(interactive)
(minibuffer-message "window-dedicated-p: %s" (window-dedicated-p (selected-window))))
Making the window "weak"ly dedicated does indeed do what I want: grep and other popup buffers do not replace the buffer in the weakly dedicated window. However, in that weakly dedicated window, find-file seems to reset window-dedicated-p to nil as tested by my dedicated-status function, so I still don't have a technique to prevent popup buffers from using or splitting a window and allowing find-file etc. to work as normal within that window.
clarification
Sorry for not being clear. Here's what I want to happen:
I mark a window as [weakly] dedicated (or whatever equivalent may exist)
I invoke grep, compilation, and so on, and they do not split that window nor replace the buffer in that window (instead splitting some other window that is not marked dedicated)
Within the weakly dedicated window, I invoke find-file, which replaces the buffer in the window but leaves the window weakly dedicated to the now changed buffer
It's that last bit that isn't working how I had hoped: after find-file, the window is no longer weakly dedicated (window-dedicated-p is nil). Since the property in question is associated with the window, I find it surprising that changing the buffer affected that window property, but so it is.
See the Elisp manual, node Dedicated Windows. If you use function set-window-dedicated-p to give a window a non-nil and non-t value then function set-window-buffer will respect it as a weakly dedicated window. That may be what you are looking for.
I would like to customize the behavior when I split windows in Emacs:
I am always splitting because I want to view a separate buffer side-by-side with the one I'm currently editing.
I use electric-buffer-list (bound to C-x C-b) to navigate buffers.
I end up doing all of the following separately:
C-x 3 to split horizontally.
C-x o to switch to the other window.
C-x C-b to invoke electric-buffer-list so I can select the buffer I want to view.
It seems like I should be able to write an Elisp function that will do all of this when I press C-x 3.
I found this post which describes the focus switching part of the behavior that I want, but I don't understand how to extend that answer to achieve all of what I'm trying to do.
Edit: After reviewing #lawlist's post and debugging my syntax, I think I want to do something like this:
(defun split-right-and-buffer-list ()
(interactive)
(split-window-horizontally)
(other-window 0)
(electric-buffer-list 0))
(global-set-key (kbd "C-x 3") 'split-right-and-buffer-list)
This does everything I want, except that the buffer list that comes up only lists the current buffer, instead of the normal list of all buffers that I get when I invoke electric-buffer-list from its key binding.
With some very small modifications the function you came up with will do what you want:
(defun split-right-and-buffer-list ()
(interactive)
(split-window-horizontally)
(other-window 1)
(electric-buffer-list nil))
(global-set-key (kbd "C-x 3") 'split-right-and-buffer-list)
Passing 1 instead of 0 as an argument to other-window causes Emacs to select the new window created as a result of calling split-window-horizontally.
Passing nil instead of 0 as an argument to electric-buffer-list causes Emacs to show all buffers, not just file-visiting ones.
The thing that can trip you up here is that this isn't mentioned in the documentation for electric-buffer-list (which doesn't include any information about the ARG it takes). But when you look at the source code of this command, you'll notice that it simply passes the value of the argument on to a function called list-buffers-noselect (and doesn't use it for anything else). The documentation of this function contains the missing piece of information mentioned above.
If you do not mind having custom commands to do what you want try the following functions
(require 'ido)
(defun my-split-window-open-buffer-right (buffer)
(interactive (list (ido-read-buffer "Please select a buffer: ")))
(select-window (split-window-right))
(switch-to-buffer buffer))
(defun my-split-window-open-buffer-below (buffer)
(interactive (list (ido-read-buffer "Please select a buffer: ")))
(select-window (split-window-below))
(switch-to-buffer buffer))
Bind them to keys of you liking. I would prefer this over redefining/advising functions I have not written.
I would like to implement a function that would let me cycle only through directory buffers that are open, and skip files or scratch buffers.
How would I go about that?
Take a look at tabbar mode -- you can define the groups to anything you want (e.g., dired), and cycle between groups with tabbar-backward-group and tabbar-forward-group:
http://www.emacswiki.org/emacs/TabBarMode
tabbar-buffer-list-function can be used to further define whether certain files are displayed (or hidden).
tabbar-buffer-groups is the default group which can be modified with setq to whatever you want. If you want to create alternative methods of grouping, you can use tabbar-buffer-groups-function.
If dired is a group, then you can switch between those buffers by using (setq tabbar-cycle-scope 'tabs) with tabbar-backward and tabbar-forward.
If you'd like to have a go at implementing something,
have a look at Buffer-menu-mode. It's already got a toggle T for
showing only files.
And then it's just a matter to see how it builds the list
and filter it with
(eq major-mode 'dired-mode)
The source is quite small at strangely 665 lines.
I use buffer-stack for this.
I wrote two different functions that use that package: one for switching between dired buffers, and other for switching between buffers of the same mode I am. I use both intensively. This is how I do it:
;; For shorter keybindings
(defmacro command (&rest body)
`(lambda ()
(interactive)
,#body))
(defvar buffer-stack-mode)
(defun buffer-op-by-mode (op &optional mode)
(let ((buffer-stack-filter 'buffer-stack-filter-by-mode)
(buffer-stack-mode (or mode major-mode)))
(funcall op)))
(defun buffer-stack-filter-by-mode (buffer)
(with-current-buffer buffer
(equal major-mode buffer-stack-mode)))
(global-set-key [(meta kp-7)]
(command (buffer-op-by-mode 'buffer-stack-up)))
(global-set-key [(meta kp-9)]
(command (buffer-op-by-mode 'buffer-stack-down)))
(global-set-key [(meta kp-3)]
(command (buffer-op-by-mode 'buffer-stack-down 'dired-mode)))
(global-set-key [(meta kp-1)]
(command (buffer-op-by-mode 'buffer-stack-up 'dired-mode)))
EDIT:
I include the macro I use for command keybindings
Icicles offers a couple ways to do this.
Start in a Dired buffer and do C-0 C-x b TAB
C-x b, then C-x m +, then enter dired-mode (using completion), then TAB
Those give you only Dired buffers as the available candidates, which you can then match by name.
You can cycle among the buffers that match your input, using arrow keys (C-up, C-down). Use RET or C-g to end.
Prefix arg 0 means the candidates are the buffers in the same mode as the current buffer --- hence the first option above.
When completing, C-x C-m + prompts you for a mode and then filters out all candidates whose mode is not the same as or derived from the mode you enter (in this case, dired-mode) --- hence the second option above.
C-x b is bound in Icicle mode to icicle-buffer. If you want to open the buffers in different windows then use C-x 4 b (icicle-buffer-other-window).
See http://www.emacswiki.org/emacs/Icicles_-_Buffer-Name_Input for more info.
Is there a way to execute emacs command on multiple buffers without having to selecting them individually and executing it on each individual buffer.
I usually open multiple files matching a particular regex, e.g. ~/*.py and wish to enable a particular mode, say hs-minor-mode or glasses-mode on each, or say execute C-c # C-M-h on each. Currently I have to select each one of them and do it individually. So is there a hack or a loop to automate the task.
Lets say I mark the buffers from the buffer-list and then run the command for all those marked.
I tried this but after executing the commands in eval-expression I completely lost access to my minibuffer, meaning whenever I typed M-x the minibuffer returned this
unable to access the minibuffer emacs error "Process Menu Mode doesn't support Hideshow Minor Mode"
and I was forced to actually kill the entire emacs process because the C-x C-s wasn't working neither was the End Task.
PS: I have no experience in elisp
You can use ibuffer mode for this (It is part of the default Emacs distribution).
(global-set-key "\C-x\C-b" 'ibuffer) ;; make ibuffer the default
In *Ibuffer* you can mark the required buffers with m and then
execute a form in each with E.
Generally, ibuffer is a lot more flexible then the usual buffer list and I think ibuffer should really be the default buffer-list in Emacs.
If you do this often, you might want to switch those particular modes on every time you enter python mode by attaching them to the mode-hook:
(add-hook 'python-mode-hook 'hs-minor-mode)
(add-hook 'python-mode-hook 'glasses-mode)
I didn't know ibuffer had that feature!
Anyway, for those who are more familiar with dired, here is a command that do the same. Select the files in dired with m or any other more powerful method. Then do, M-xdired-do-command and write a form or a command just as in M-x.
(defun dired-do-command (command)
"Run COMMAND on marked files. Any files not already open will be opened.
After this command has been run, any buffers it's modified will remain
open and unsaved."
(interactive
(list
(let ((print-level nil)
(minibuffer-history-position 0)
(minibuffer-history-sexp-flag (1+ (minibuffer-depth))))
(unwind-protect
(read-from-minibuffer
"Command: " (prin1-to-string (nth 0 command-history))
read-expression-map t
(cons 'command-history 0))
;; If command was added to command-history as a
;; string, get rid of that. We want only
;; evaluable expressions there.
(if (stringp (car command-history))
(setq command-history (cdr command-history)))))))
(dolist (filename (dired-get-marked-files))
(with-current-buffer (find-file-noselect filename)
(if (symbolp command)
(call-interactively command)
(eval command)))))
When switching buffers with emacs ido mode enabled, a list of completions are displayed in the minibuffer. It appears there is a "feature" that buffers that are already open are put to the end of the list. I, however, often open the same buffer in multiple panes.
Is there a way to either turn this "feature" off, or alternatively do the opposite: have the buffers that are already open be at the front of the completion list?
The main point of ido mode is that you don't use arrows to navigate between buffers in the minibuffer. Instead you type the part of the buffer's name. In this case it doesn't matter where the buffer is in the list.
This is not possible unless you want to wade deep in ido's intestines.
As eGlyph already said: You're likely using ido wrongly (and there's also C-s for <right> and C-r for <left>; no need for arrow keys).
But you can define command for choosing among the already shown buffers (here only from the current frame, if you want all shown buffers you have to collect the windows first via `frame-list):
(defun choose-from-shown-buffers ()
(interactive)
(let ((buffers (mapcar (lambda (window)
(buffer-name (window-buffer window)))
(window-list))))
(pop-to-buffer (ido-completing-read "Buffer: " buffers))))