I am looking for some assistance, please, to test for the existence of the same buffer in more than one window (on any frame) and whether the window-width of those windows (containing that particular buffer) are different.
Example I
Frame # 1:
Window A -- minor-mode-xyz -- (= (window-width) 55) -- (equal (buffer-name) "*TEST*")
Window B -- nothing important to this example
Window C -- minor-mode-xyz -- (= (window-width) 55) -- (equal (buffer-name) "*TEST*")
Frame # 2:
Window A -- minor-mode-xyz -- (= (window-width) 100) -- (equal (buffer-name) "*TEST*")
Window B -- nothing important to this example
Window C -- minor-mode-xyz -- (= (window-width) 55) -- (equal (buffer-name) "*TEST*")
Result: (message "The test yielded a positive result -- do something now.")
Example II
Frame # 1:
Window A -- minor-mode-xyz -- (= (window-width) 100) -- (equal (buffer-name) "*TEST*")
Window B -- nothing important to this example
Window C -- minor-mode-xyz -- (= (window-width) 100) -- (equal (buffer-name) "*TEST*")
Frame # 2:
Window A -- minor-mode-xyz -- (= (window-width) 100) -- (equal (buffer-name) "*TEST*")
Window B -- nothing important to this example
Window C -- minor-mode-xyz -- (= (window-width) 100) -- (equal (buffer-name) "*TEST*")
Result: (message "Everything is PERFECT -- do not do anything !!!")
Example III
Frame # 1:
Window A -- minor-mode-xyz -- (= (window-width) 100) -- (equal (buffer-name) "*TEST*")
Window B -- nothing important to this example
Window C -- nothing important to this example
Frame # 2:
Window A -- nothing important to this example
Window B -- nothing important to this example
Window C -- nothing important to this example
Result: (message "Everything is PERFECT -- do not do anything !!!")
Here is an example where the window-width in both windows is exactly equal, and the minor mode works well.
(source: lawlist.com)
Here is an example where the window-width in the windows are not equal, and the minor mode goes haywire in any window that does not have focus -- e.g., the horizontal / vertical yellow lines are not drawn correctly. When a situation like this arises, the best way to handle it would probably be to have a test and when it returns positive, disable the yellow horizontal / vertical lines in all windows.
(source: lawlist.com)
The following is just a draft concept idea, but is not yet capable of handling the test that is needed:
(defun test-function (&optional all-frames)
"If the same buffer displays on any frame -- with different `window-width`,
then do something."
(let* (
(wins (window-list (selected-frame) 'no-minibuf))
(bufs (delete-dups (mapcar #'window-buffer wins))))
(dolist (buf bufs)
(with-current-buffer buf
(dolist (win
(get-buffer-window-list (current-buffer) 'no-minibuf all-frames))
(select-window win)
(when test-mode
(message "hello-world.")))))))
Here is a function that returns a list of pairs of windows that share the same buffer but have different width:
(defun window-pairs ()
(let (wmap ret)
;; get a list of all windows
(dolist (frame (frame-list))
(dolist (window (window-list frame))
(let* ((buffer (window-buffer window))
(assoc (assoc buffer wmap)))
;; if the window shares the window with some previously
;; visited windows, also compare their widths
(if assoc
(let ((other-windows (cdr assoc)))
(dolist (other-window other-windows)
(unless (= (window-width window) (window-width other-window))
(push (cons window other-window) ret)))
(push (cons buffer (cons window other-windows)) wmap))
(push (cons buffer (list window)) wmap)))))
ret))
It finds all windows that share the same buffer, and each time a new window is found whose buffer has been seen before, it iterates over the previous windows to compare their widths with that of the current window.
Related
I'm aware of C-x 1, which will maxamize the current window both horizontally and vertically.
However, my quesiton is, is it possible to expand the current window to the edge of the frame on one direction only?
So in the below I want to expand window A to the right border of the frame, taking up the space currently occupied by B and C. But I want D and E to remain untouched.... and I want to do it in a single command.
Excuse the terrible attempt at ASCII art!
_______________________
| AAAAAA |BBBBBB |CCCC |
|________|_______|______|
| DDDDD | EEEEEEEEEE |
|________|______________|
I know you can move horizontally 1 char at a time, and that you can use the repeat n times command to do this many times, but both are clunky, when what I really want to say is expand until the right hand border, I don't care how far that is.
The nearest I've come up with this to go to each frame occupying the space you want and calling C-X 0, but this is still a bit clunky.
I need this to work in terminal mode (emacs -nw) rather than graphical/X-Windows mode.
Any ideas?
You can do this with library frame-cmds.el (description).
It provides these commands:
maximize-frame-horizontally, maximize-frame-vertically, and max-frame
restore-frame-horizontally, restore-frame-vertically, and restore-frame
The "restore" commands are actually toggles that alternate between maximizing and restoring. (They are aliased to commands toggle-max-frame*.)
Commands maximize-frame and restore-frame are general, and can act like the horizontal and vertical commands by giving them a prefix arg: negative for horizontally, non-negative for vertically.
I have the same problem: I would like to maximize a window horizontally but not vertically. After searching on the internet with no avail, I decided to write my own function. And I would like to share it here in case it might help someone in the future.
(require 'cl-lib)
(defun durand-maximize-window-horizontally (&optional window)
"Make WINDOW have the same width as the frame.
WINDOW defaults to the selected window.
Other windows are retained, but moved to the top."
(let* ((window (or window (selected-window)))
;; the list of windows to the left
(left-windows-list (let ((temp-window window)
window-list)
(cl-loop while (window-in-direction
'left temp-window t)
do (let ((left-win
(window-in-direction
'left temp-window t)))
(push left-win window-list)
(setf temp-window left-win)))
window-list))
;; the list of windows to the right
(right-windows-list (let ((temp-window window)
window-list)
(cl-loop while (window-in-direction
'right temp-window t)
do (let ((right-win
(window-in-direction
'right temp-window t)))
(setf window-list
(append window-list
(list right-win)))
(setf temp-window right-win)))
window-list))
;; the list of windows to the left and to the right
;; the order is from left to the right.
(same-level-list (append left-windows-list right-windows-list))
;; save all parameters: the car is the buffer, and the cadr is a list
;; of parameters.
(window-parameters-list
(cl-loop for win in same-level-list
collect (list (window-buffer win)
;; (window-width win)
(window-parameters win)))))
(cl-loop for win in same-level-list
do (delete-window win))
;; now our window is the only window horizontally speaking.
;; now we shall create them once again, if they exist.
(when same-level-list
(let* ((split-base-window
(split-window window nil 'above))
(new-windows (list split-base-window))
newly-created-window)
(cl-loop
for ind from 1 to (1- (length same-level-list))
do
(setf newly-created-window
(split-window split-base-window
nil 'right)
;; NOTE: it is important this list also follows the order
;; of going from the left to the right
new-windows (append new-windows
(list newly-created-window))
split-base-window newly-created-window))
(cl-loop for index from 0 to (1- (length same-level-list))
do
(let ((buf (car (nth index window-parameters-list)))
(paras (cadr (nth index window-parameters-list))))
(set-window-buffer
(nth index new-windows) buf)
(cl-loop for para-pair in paras
do (set-window-parameter
(nth index new-windows)
(car para-pair)
(cdr para-pair)))))))))
Many commercial word processors have a default behavior that automatically hides the vertical scroll bars when the lines of text in the document are less than the visible window; and, the scroll bars appear automatically when the lines of text in the document are greater than the visible window. Emacs is missing that ability and I'd like that to be the default behavior in a variety of different modes.
Does anyone have some ideas how to automatically remove or add the scroll-bars on the fly as the size (lines of text) of the document increases or decreases?
I was thinking of perhaps weaving it into the the functions for line numbers using a prior sample by #phils in a related thread: https://stackoverflow.com/a/10593165/2112489
I'd like it work even when I'm not using linum-mode. However, I don't think the scroll-bar function should run after every single command -- it should run only when a new line is added or subtracted, taking into consideration visual-line-mode (i.e., wrapping being active) potentially being active.
The following snippet was inspired by a previous answer from #abo-abo in a related thread: https://stackoverflow.com/a/20923695/2112489
(cond
((not (> (count-lines (point-min) (point-max)) (window-height)))
(set-window-scroll-bars (get-buffer-window (buffer-name) (selected-frame)) 0 nil))
((and
(> (count-lines (point-min) (point-max)) (window-height))
(not (equal (window-scroll-bars) `(15 2 t nil))))
(set-window-scroll-bars (get-buffer-window (buffer-name) (selected-frame)) 15 'right)))
EDIT (January 17, 2014): Working draft based upon the helpful answer to this thread by #Drew.
EDIT (January 19, 2014): Added a function to count each word-wrapped line using vertical-motion. Setting the initial-frame-default seems to be read by Emacs after the initial frame is created, so the scroll bars are visible for a split second -- to avoid seeing this, modifying the frame parameters of the initial frame seems to fix this visual issue. Now using window-text-height instead of window-height -- The returned height does not include dividers, the mode line, any header line, nor any partial-height lines at the bottom of the text area. Copied the method used by linum-mode in terms of using -- the post-command-hook, the change-major-mode-hook, and the window-configuration-change-hook). Added window-live-p condition to avoid post-command-hook errors when starting Emacs while various buffers are loading out of sight. Added condition to deal with narrow-to-region -- still unsure why that situation causes Emacs to freeze in a loop or something -- the workaround is needed for now. The latest version of Emacs Trunk from January 19, 2014 appears to fix visual display issues experienced in prior versions -- as such, redraw-frame is no longer necessary. Added (redisplay t) to the function count-vertical-lines, which speeds up displaying the new buffer when switching buffers. Added regexp for buffers that will always have scroll bars or never have scroll bars.
EDIT (January 20, 2014): Added just one main condition that there be a live window, and removed the same conditions from the various branches of the lawlist-scroll-bar function. Added additional condition for a narrow-to-region situation such that removing the scroll bars only need occur if scroll bars were present prior to narrowing.
EDIT (January 21, 2014): With this revision, it is no longer necessary to count lines (which causes a slow-down in large buffers). The new method is a much simpler mathematical calculation based on four (4) points that are determined in a mere fraction of a second -- i.e., point-min, point-max, window-start and window-end. If point-min moves off the screen, scroll bars are added -- I think this behavior makes sense -- although, I did stop to ponder whether the scroll-bar should also serve as a visual representation of whether the characters within the parameters of point-min to point-max could actually fit into the window regardless of whether point-min had moved beyond the window. None of the hooks in this example are able to deal with a display-buffer situation (targeting the same window of the same frame that both already have focus) -- so, I created my own display-buffer-hook (which is beyond the scope of this example).
;;;;;;;;;;;;;;;;;;;;;;;;;; LAWLIST SCROLL BAR MODE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar regexp-always-scroll-bar '("\\.yes" "\\*Scroll-Bar\\*")
"Regexp matching buffer names that will always have scroll bars.")
(defvar regexp-never-scroll-bar '("\\.off" "\\.not")
"Regexp matching buffer names that will never have scroll bars.")
(add-to-list 'default-frame-alist '(vertical-scroll-bars . nil))
(modify-all-frames-parameters (list (cons 'vertical-scroll-bars nil)))
(defun lawlist-scroll-bar ()
(when (window-live-p (get-buffer-window (current-buffer)))
(redisplay t)
(cond
;; not regexp matches | not narrow-to-region
((and
(not (regexp-match-p regexp-always-scroll-bar (buffer-name)))
(not (regexp-match-p regexp-never-scroll-bar (buffer-name)))
(equal (- (point-max) (point-min)) (buffer-size)))
(cond
;; Lines of text are less-than or equal-to window height,
;; and scroll bars are present (which need to be removed).
((and
(<= (- (point-max) (point-min)) (- (window-end) (window-start)))
(equal (window-scroll-bars) `(15 2 right nil)))
(set-window-scroll-bars (selected-window) 0 'right nil))
;; Lines of text are greater-than window height, and
;; scroll bars are not present and need to be added.
((and
(> (- (point-max) (point-min)) (- (window-end) (window-start)))
(not (equal (window-scroll-bars) `(15 2 right nil))))
(set-window-scroll-bars (selected-window) 15 'right nil))))
;; Narrow-to-region is active, and scroll bars are present
;; (which need to be removed).
((and
(not (equal (- (point-max) (point-min)) (buffer-size)))
(equal (window-scroll-bars) `(15 2 right nil)))
(set-window-scroll-bars (selected-window) 0 'right nil))
;; not narrow-to-region | regexp always scroll-bars
((and
(equal (- (point-max) (point-min)) (buffer-size))
(regexp-match-p regexp-always-scroll-bar (buffer-name)))
(set-window-scroll-bars (selected-window) 15 'right nil))
;; not narrow-to-region | regexp never scroll-bars
((and
(equal (- (point-max) (point-min)) (buffer-size))
(regexp-match-p regexp-never-scroll-bar (buffer-name)))
(set-window-scroll-bars (selected-window) 0 'right nil)))))
(define-minor-mode lawlist-scroll-bar-mode
"This is a custom scroll bar mode."
:lighter " sc"
(if lawlist-scroll-bar-mode
(progn
(add-hook 'post-command-hook 'lawlist-scroll-bar nil t)
;; (add-hook 'change-major-mode-hook 'lawlist-scroll-bar nil t)
;; (add-hook 'window-configuration-change-hook 'lawlist-scroll-bar nil t)
)
(remove-hook 'post-command-hook 'lawlist-scroll-bar t)
(remove-hook 'change-major-mode-hook 'lawlist-scroll-bar t)
(remove-hook 'window-configuration-change-hook 'lawlist-scroll-bar t)))
(define-globalized-minor-mode global-lawlist-scroll-bar-mode
lawlist-scroll-bar-mode lawlist-scroll-bar-on)
(defun lawlist-scroll-bar-on ()
(unless (minibufferp)
(lawlist-scroll-bar-mode 1)))
(global-lawlist-scroll-bar-mode)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Supporting regexp function:
;; https://github.com/kentaro/auto-save-buffers-enhanced
;; `regexp-match-p` function modified by #sds on stackoverflow
;; https://stackoverflow.com/questions/20343048/distinguishing-files-with-extensions-from-hidden-files-and-no-extensions
(defun regexp-match-p (regexps string)
(and string
(catch 'matched
(let ((inhibit-changing-match-data t)) ; small optimization
(dolist (regexp regexps)
(when (string-match regexp string)
(throw 'matched t)))))))
If you just want to toggle scroll bars on/off interactively, or on a hook, or from your code, then scroll-bar-mode should be all you need.
You can also use menu-bar-no-scroll-bar, menu-bar-left-scroll-bar, and menu-bar-right-scroll-bar. Or just do what each of those commands does: (customize-set-variable 'scroll-bar-mode WHATEVER). Or use set-scroll-bar-mode or set-window-scroll-bars, similarly. It depends on what behavior you are looking for.
I recommend M-x apropos scroll-bar. (Or if you use Icicles, just C-h f scroll-bar S-TAB, then repeat C-M-down...)
You can add it to mode-line-position, so that update of the mode line automatically triggers turning scroll bars on/off. This pretty much works, for instance:
(setq-default
mode-line-position
'(:eval
(progn
(if (> (count-lines (point-min) (point-max)) (window-height))
(set-window-scroll-bars nil 20 t)
(set-window-scroll-bars nil 0 t))
`((-3 ,(propertize
"%p"
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Buffer position, mouse-1: Line/col menu"))
(line-number-mode
((column-number-mode
(10 ,(propertize
" (%l,%c)"
'face (and (> (current-column)
modelinepos-column-limit)
'modelinepos-column-warning)
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Line and column, mouse-1: Line/col menu"))
(6 ,(propertize
" L%l"
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Line number, mouse-1: Line/col menu"))))
((column-number-mode
(5 ,(propertize
" C%c"
'face (and (> (current-column)
modelinepos-column-limit)
'modelinepos-column-warning)
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Column number, mouse-1: Line/col menu")))))))))
You can alternatively use the following, which employs Stefan's suggestion
to make it work better with scaled text, visual-line-mode, images, etc. However, in that case, scroll bars kick in whenever some text is outside the window because of scrolling, regardless of whether that text would fit in the window. Whether that is a feature or not is for you to decide. ;-)
(setq-default
mode-line-position
'(:eval
(let ((scroll-bars (nth 2 (window-scroll-bars))))
(if (or (> (point-max) (window-end)) (< (point-min) (window-start)))
(unless scroll-bars (set-window-scroll-bars nil 20 t))
(when scroll-bars (set-window-scroll-bars nil 0 t)))
(unless (equal scroll-bars (nth 2 (window-scroll-bars))) (redraw-frame))
`((-3 ,(propertize
"%p"
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Buffer position, mouse-1: Line/col menu"))
(line-number-mode
((column-number-mode
(10 ,(propertize
" (%l,%c)"
'face (and (> (current-column)
modelinepos-column-limit)
'modelinepos-column-warning)
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Line and column, mouse-1: Line/col menu"))
(6 ,(propertize
" L%l"
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Line number, mouse-1: Line/col menu"))))
((column-number-mode
(5 ,(propertize
" C%c"
'face (and (> (current-column)
modelinepos-column-limit)
'modelinepos-column-warning)
'local-map mode-line-column-line-number-mode-map
'mouse-face 'mode-line-highlight
'help-echo "Column number, mouse-1: Line/col menu")))))))))
If you are used to using scroll bars only as visual indicator of where you are in the buffer (rather than looking at the modeline for that), you might like a package like yascroll. It uses the fringe for displaying the scroll bar, and it does not show it if lines of text in the document are less than the visible window, as you want.
Advantage is that there is no widgets taking up real state from your screen.
Disadvantage is that you cannot use the scroll bars with the mouse (some users never do that, anyways)
Any ideas regarding how to configure Wanderlust to open emails in a new buffer, instead of a split window? There is just too much happening with four (4) windows -- summary message buffer; message buffer; big brother insidious database address manager; and the mini-buffer. (See the screenshot below.)
I think I've located the relevant portion of the code in wl-message.el, but I'm not sure what portion to change. (setq wl-message-window-size '(1 . 1)) in the init.el is not what I'm looking for, because I'd still have to share the screen with other buffers.
I'm spending a lot of time switching and closing windows to get a full size buffer, and I'm hoping to just eliminate multiple windows when checking my e-mail.
Thanks . . . any help would be greatly appreciated.
;;; wl-message.el -- Message buffer handling from summary buffer.
(defun wl-message-buffer-window ()
"Get message buffer window if any."
(let* ((start-win (selected-window))
(cur-win start-win))
(catch 'found
(while (progn
(setq cur-win (next-window cur-win))
(with-current-buffer (window-buffer cur-win)
(if (or (eq major-mode 'wl-message-mode)
(eq major-mode 'mime-view-mode))
(throw 'found cur-win)))
(not (eq cur-win start-win)))))))
(defun wl-message-select-buffer (buffer)
"Select BUFFER as a message buffer."
(let ((window (get-buffer-window buffer))
(sum (car wl-message-window-size))
(mes (cdr wl-message-window-size))
whi)
(when (and window
(not (eq (with-current-buffer (window-buffer window)
wl-message-buffer-cur-summary-buffer)
(current-buffer))))
(delete-window window)
(run-hooks 'wl-message-window-deleted-hook)
(setq window nil))
(if window
(select-window window)
(when wl-fixed-window-configuration
(delete-other-windows)
(and wl-stay-folder-window
(wl-summary-toggle-disp-folder)))
;; There's no buffer window. Search for message window and snatch it.
(if (setq window (wl-message-buffer-window))
(select-window window)
(setq whi (1- (window-height)))
(if mes
(progn
(let ((total (+ sum mes)))
(setq sum (max window-min-height (/ (* whi sum) total)))
(setq mes (max window-min-height (/ (* whi mes) total))))
(if (< whi (+ sum mes))
(enlarge-window (- (+ sum mes) whi)))))
(split-window (get-buffer-window (current-buffer)) sum)
(other-window 1)))
(switch-to-buffer buffer)))
(source: lawlist.com)
SOLUTION # 1: The variable wl-message-buffer-name that is defined within wl-vars.el makes the message buffer uninteresting by virtue of the space at the beginning of the buffer name: *WL:Message*. Inasmuch as Emacs hides uninteresting buffers by default, one solution is to modify the aforementioned variable by removing the space at the beginning of the buffer name. That way, the buffer is always visible and it is just a matter of switching to the window that displays the message and then delete-other-windows. The added advantage is that it is no longer necessary to return to the summary buffer to view an e-mail that has already been opened, since there is already an open buffer dedicated to said e-mail.
(defcustom wl-message-buffer-name "*WL:Message*" ;; " *WL:Message*"
"*Buffer name for message buffers."
:group 'wl-pref
:group 'wl-setting)
SOLUTION # 2: This second solution is no longer the preferred method and will most likely be removed entirely from this answer. The word search utility I was using could not comb the wl-vars.el file for some unknown reason, so this second solution was a workaround.
Edit the key map for wl-summary-read (inside wl-summary.el) and replace it with the function lawlist-wl-summary-read so that hitting the space bar activates said function. wl-summary-enter-handler remains defined as the enter key, which opens messages in the default manner.
(define-key wl-summary-mode-map " " 'lawlist-wl-summary-read)
(defun lawlist-wl-summary-read nil
"Clone the the buffer and make new buffer name unique."
(interactive)
(wl-summary-enter-handler)
(windmove-down)
(let ((n 0)
bufname)
(while (progn
(setq bufname (concat "email"
(if (= n 0) "" (int-to-string n))
"")) ;; could be an ending, like an asterick *
(setq n (1- n)) ;; if + instead of -, then no hyphen and no space between buffer name and the number
(get-buffer bufname)))
(clone-indirect-buffer bufname nil)
(switch-to-buffer bufname)
(delete-other-windows) ))
How do I detect that an Emacs window has already been split?
In my .emacs file, I have:
(when (display-graphic-p)
(set-frame-size (selected-frame) 166 85)
(split-window-horizontally))
which allows me to have two buffers side-by-side, each exactly 80 chars wide.
Every once in a while I change my .emacs file and want to reload it in place, so I run M-x load-file on my .emacs file and that window I'm in gets re-split.
Is there some sort of command I can call to check if the frame has already been split and only call (split-window-horizontally) if it hasn't? Something like:
(when (window-is-root)
(split-window-horizontally))
or
(when (not (window-is-already-split))
(split-window-horizontally))
window-list will return you a list of the windows (for the current frame), so you should be able to do:
(when (= (length (window-list)) 1)
(split-window-horizontally))
Check out the relevant documentation for windows.
This is a meaningless questions, windows are not split.
Yes, there are functions named split-window..., but what they do is merely to reduce the size of the window, and create a new one in the space thus freed.
You cannot just use (= 1 (length (window-list))) since you have at least one window per frame (not counting the simili-window of the minibuffer).
You could try:
(< (length (frame-list)) (length (window-list)))
but that doesn't tell you if there are several windows in the selected frame, which is what you are actually asking, since obviously it could be another frame that contains several windows.
So if you ask the question CORRECTLY, "how can I know whether the selected frame contains more than one window", you can easily find the answer:
(require 'cl)
(defun complement (fun)
(byte-compile `(lambda (&rest args) (not (apply ',fun args)))))
(defun* more-than-one-window-in-frame-p (&optional (frame (selected-frame)))
(< 1 (length (remove* frame (window-list)
:key (function window-frame)
:test (complement (function eql))))))
I want to make the compilation window in Emacs to always appear at the bottom of a window, and always be a certain height. So far I put the following lines in my .emacs file:
(setq split-height-threshold 0)
(setq compilation-window-height 10)
...and it does work for when I have only one window open, but as soon as I split the screen into two windows horizontally (that is, the dividing line in the middle goes from the top to the bottom), the compilation window stops respecting the height variable, and splits the window right in the middle.
How do I fix this?
I would use something like this, freely adapted from the EmacsWiki:
(defun my-compilation-hook ()
(when (not (get-buffer-window "*compilation*"))
(save-selected-window
(save-excursion
(let* ((w (split-window-vertically))
(h (window-height w)))
(select-window w)
(switch-to-buffer "*compilation*")
(shrink-window (- h compilation-window-height)))))))
(add-hook 'compilation-mode-hook 'my-compilation-hook)
If the *compilation* buffer is not visible, this will split the window vertically, resize the newly opened window to 10 lines height, and open the *compilation* buffer in it.
You can customize the variable compilation-window-height.
Combining code from How can I prevent emacs from opening new window for compilation output? and code from http://www.emacswiki.org/emacs/CompilationMode, this is all my code for compile, it provides you 4 features:
1). Use compile-again to run the same compile as the last time automatically, no prompt. If there is no last time, or there is a prefix argument, it acts like M-x compile.
2). compile will split the current window(always be a certain size), it will not affect the other windows in this frame.
3). it will auto-close the *compilation* buffer (window) if there is no error, keep it if error exists.
4). it will highlight the error line and line number of the source code in the *compilation* buffer, use M-n/p to navigate every error in *compilation* buffer, Enter in the error line to jump to the line in your code code.
(require 'compile)
(setq compilation-last-buffer nil)
(defun compile-again (ARG)
"Run the same compile as the last time.
If there is no last time, or there is a prefix argument, this acts like M-x compile."
(interactive "p")
(if (and (eq ARG 1)
compilation-last-buffer)
(progn
(set-buffer compilation-last-buffer)
(revert-buffer t t))
(progn
(call-interactively 'compile)
(setq cur (selected-window))
(setq w (get-buffer-window "*compilation*"))
(select-window w)
(setq h (window-height w))
(shrink-window (- h 10))
(select-window cur))))
(global-set-key (kbd "C-x C-m") 'compile-again)
(defun my-compilation-hook ()
"Make sure that the compile window is splitting vertically."
(progn
(if (not (get-buffer-window "*compilation*"))
(progn
(split-window-vertically)))))
(add-hook 'compilation-mode-hook 'my-compilation-hook)
(defun compilation-exit-autoclose (STATUS code msg)
"Close the compilation window if there was no error at all."
;; If M-x compile exists with a 0
(when (and (eq STATUS 'exit) (zerop code))
;; then bury the *compilation* buffer, so that C-x b doesn't go there
(bury-buffer)
;; and delete the *compilation* window
(delete-window (get-buffer-window (get-buffer "*compilation*"))))
;; Always return the anticipated result of compilation-exit-message-function
(cons msg code))
(setq compilation-exit-message-function 'compilation-exit-autoclose)
(defvar all-overlays ())
(defun delete-this-overlay(overlay is-after begin end &optional len)
(delete-overlay overlay)
)
(defun highlight-current-line ()
"Highlight current line."
(interactive)
(setq current-point (point))
(beginning-of-line)
(setq beg (point))
(forward-line 1)
(setq end (point))
;; Create and place the overlay
(setq error-line-overlay (make-overlay 1 1))
;; Append to list of all overlays
(setq all-overlays (cons error-line-overlay all-overlays))
(overlay-put error-line-overlay
'face '(background-color . "red"))
(overlay-put error-line-overlay
'modification-hooks (list 'delete-this-overlay))
(move-overlay error-line-overlay beg end)
(goto-char current-point))
(defun delete-all-overlays ()
"Delete all overlays"
(while all-overlays
(delete-overlay (car all-overlays))
(setq all-overlays (cdr all-overlays))))
(defun highlight-error-lines(compilation-buffer process-result)
(interactive)
(delete-all-overlays)
(condition-case nil
(while t
(next-error)
(highlight-current-line))
(error nil)))
(setq compilation-finish-functions 'highlight-error-lines)
There's an excellent package for these situations named Shackle. https://github.com/wasamasa/shackle
Easy to set up and works on pretty much any type of buffer