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.
Related
How to automatically set focus to window with displayed candidates (after tab punch) in default emacs read with autocompletion?
I can not use IDO nor other autocompletion systems in my case because I need to browse through 80k+ candidates, and only autocompletion system which can handle this is the default one.
I will be glad for any useful pointers.
EDIT
After some research, I get to work following imperfect solution:
(define-key minibuffer-local-completion-map
(kbd "<tab>")
(lambda ()
(interactive)
(call-interactively 'minibuffer-complete)
(call-interactively 'switch-to-completions)))
(define-key completion-list-mode-map
(kbd "C-f")
'isearch-forward)
Only problem is, after I enter completing-read-default, I must first hit TAB to open window with candidates (with newly added autofocus). But I want it to open window with candidates immediately without need to hit TAB. How to do it? I tried to call minibuffer-complete after call to completing-read-default but it doesnt opened window with candidates, only standard minibuffer prompt.
After some pain, I finally found solution
(defun custom/default-completing-read (question candidates)
(run-at-time "0.5" nil
(lambda ()
(minibuffer-complete)
(switch-to-completions)
(isearch-forward)))
(completing-read-default question candidates))
After call, it invokes default (written in C) completion system which can handle tons and tons of candidates without problems with automatic jump into candidate selection with isearch-forward enabled.
Hope it will help someone in future ...
I'm using emacs 24.3 from emacsformacosx.com on OS X 10.9 (Mavericks). The behavior is the same on emacs 23.4.1 on Debian Wheezy.
I want to automate applying set-window-dedicated-p so switching/opening a buffer won't use certain windows. For example, if I'm in the Calculator and manually use Meta-: and enter (set-window-dedicated-p (get-buffer-window) t) then it works great - my Calculator window doesn't get hijacked by other buffers. I want it to work like that automatically.
I put this in my .emacs file:
(add-hook 'calc-mode-hook
(lambda ()
(message "Dedicating %s" (buffer-name))
(set-window-dedicated-p (get-buffer-window) t)
(message "Dedication %s" (window-dedicated-p (get-buffer-window "*Calculator*")))))
Then I start up emacs, switch to the *Messages* window, and Meta-x calc. The *Messages* buffer shows
Dedicating *Calculator*
Dedication t
so I know my hook was called and what buffer it operated on. But the *Calculator* buffer is not dedicated - it doesn't behave properly and Meta-: (window-dedicated-p) returns nil. The *Messages* buffer is dedicated instead.
Why is the *Calculator* window shown as dedicated in the hook but not afterwards? What am I doing wrong here?
Unfortunately the *Calculator* buffer is not displayed in any window at the point your code runs.
Your 'validation' messages were misleading you. (buffer-name) is certainly the buffer you want, but it's not in any window, and so you're actually passing a nil argument for the window in all situations. i.e. You're setting the current window dedicated, and then confirming that it's dedicated (which it should indeed be).
I think after advice to calc is what you need here. e.g.:
(defadvice calc (after my-dedicated-calc-window)
"Make the *Calculator* window dedicated."
(let ((win (get-buffer-window "*Calculator*")))
(when win
(set-window-dedicated-p win t))))
(ad-activate 'calc)
n.b. I'm not sure exactly how the arguments to calc affect the window display, but I think with the test for the window wrapping the call to set-window-dedicated-p this code is probably fine in all cases.
The problem:
I'm in scheme-mode (simple quack)
scheme is already running
eval expression
it sends the expression to scheme buffer
but! doesn't bring that buffer up in 2nd window = no immediate feedback
and I have to manually switch second buffer to scheme which is annoying
Some (more recent) modes like fsharp-mode or tuareg do that automatically. Tried to read quack.el, but didn't find convenient separate function like "pop scheme". It's tangled within run-scheme which also changes focus. Settings also don't help.
I want to stay in my rkt/scm file and see repl buffer pop up if not already popped. Like this simple build logic in sublime-text but with persistent repl.
Maybe I should try geiser, but quack is ok for now. Just missing few obvious conveniences.
Just rungeiser. It's in MELPA now, so it's a quick install.
You can also try lispy (which uses geiser) for in-place scheme eval.
e will eval current expression and display the result in the minibuffer.
E will eval current expression and insert the result in current buffer.
u is bound to undo, so you can either e or Eu if you prefer.
I ended up writing this:
(setq scheme-program-name "guile")
(defun run-scheme-2.0 ()
"Loads your chosen Scheme implementation for interactive development,
and displays that buffer below your main editing buffer, and makes sure that
your cursor will be on your code."
(interactive)
(if (not (get-buffer "*scheme*"))
(progn
(setq starting-buffer (buffer-name))
(run-scheme scheme-program-name)
(split-window-below)
(other-window 1)
(shrink-window-if-larger-than-buffer)
(other-window 1)
(switch-to-buffer starting-buffer))))
(add-hook 'scheme-mode-hook 'run-scheme-2.0)
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.
I'm looking for a way to include some filtering in the other-buffer method in emacs.
Currently calling other-buffer pulls up the last most recent buffer, but the problem with this is that buffers that get modified by external processes keep coming up as other-buffer. I would like to implement some sort of filtering in other-buffer.
Currently I use evil with C-^ bound to other-buffer, and I have some tail.el buffers active, and when I try to switch bufffers the tail buffers keep popping up.
Is there some alternative to other-buffer or could someone scratch up some code to implement this, Thanks.
What has worked for me is winner-mode - it's like an undo, but for window configurations.
Here's my setup:
(winner-mode)
(global-set-key (kbd "<f7>") 'winner-undo)
(global-set-key (kbd "C-<f7>") 'winner-redo)
Also I'd recommend other-window on some very cheap shortcut, since it's
a command that's used a lot.
I've put it on C-p, since I didn't appreciate the inconsistency
that one of the direction keys is so far away from others.
I've got previous-line on C-h instead, so now
my direction keys are n h f b - they're almost together!
And I didn't really miss the defaults on C-h, since f1
has the same functionality.
Ok so I got some workable solution but its not perfect it using bits from this answer:
emacs lisp, how to get buffer major mode?
(defun buffer-mode (buffer-or-string)
"Returns the major mode associated with a buffer."
(with-current-buffer buffer-or-string (format "%s" major-mode)))
(defun other-buffer-ex ()
(interactive)
(switch-to-buffer
(if (string-equal (buffer-mode (other-buffer)) "comint-mode")
(next-buffer) (other-buffer))))