Centering text in emacs window - emacs

Inside just one lonely emacs frame I switch frequently between editting 70-column text files (LaTeX) and 120-column programs (.h/.cpp files). I'd like to continue to use just one emacs frame, without resizing it or creating additional frames.
Here is the problem. The width of my window is about right for editting the 120-column programs, but during the extended text editting sessions, the 70 columns appear on the left side of the window. At the end of the day in front of a laptop, my neck seems to have acquired a semi-permanent tilt to the left.
Are you aware of a method to make the text appear centered, while still making the text files remain jagged on the right?

You could try narrowing the frame by increasing the fringe size. For example:
(set-fringe-style '(200 . 200))
would shave 200 pixels off each side of the main text area, leaving the work area 400 pixels narrower but still centered. To return to the regular view,
(set-fringe-style 'default)
will revert the fringe to the normal size.
And you can wrap that up inside some advice, which might work well for you if you stick to using just a single window:
(defadvice switch-to-buffer (after switch-to-buffer-adjust-fringe activate)
"depending on major mode, switch fringe style"
(if (memq major-mode '(latex-mode))
(set-fringe-style '(200 . 200))
(set-fringe-style 'default)))
Note: Update the list (latex-mode) to contain whatever modes you want to have the large fringes.

EmacsWiki has a page on shrink-wrapping frames. You could use the libraries and code referenced there to automatically shrink and grow your Emacs frame as necessary.

;; Add left and right margins, when file is markdown or text.
(defun center-window (window) ""
(let* ((current-extension (file-name-extension (or (buffer-file-name) "foo.unknown")))
(max-text-width 80)
(margin (max 0 (/ (- (window-width window) max-text-width) 2))))
(if (and (not (string= current-extension "md"))
(not (string= current-extension "txt")))
;; Do nothing if this isn't an .md or .txt file.
()
(set-window-margins window margin margin))))
;; Adjust margins of all windows.
(defun center-windows () ""
(walk-windows (lambda (window) (center-window window)) nil 1))
;; Listen to window changes.
(add-hook 'window-configuration-change-hook 'center-windows)
Add your file extensions above, below "md" and "txt".

Related

Emacs continuation lines before screen edge

I would like Emacs to display a line continuation at a specified column -- say column 80 -- rather than at the edge of the screen. Is this possible? I know that I can use visual-line-mode and possibly configure that to soft-break the lines at some pre-defined width, but I prefer working on logical lines and would therefore prefer not to use visual-line-mode.
Setting the window margins more or less does this, but it's going to cause some problems (at minimum, it can interfere with splitting windows).
If you want to dig deeper, this might be a starting point.
(defvar my-right-margin-column 80
"Used by `my-right-margin-update'.")
(defun my-right-margin-update ()
"Make the right margin occupy all space beyond `my-right-margin-column'.
See `my-right-margin-auto-update'."
(set-window-margins
nil 0 (max 0 (- (+ (window-text-width)
(or (cdr (window-margins)) 0))
my-right-margin-column)))
(set-window-parameter nil 'min-margins '(0 . 0)))
(defun my-right-margin-auto-update ()
"Configure buffer-local `window-configuration-change-hook'."
(add-hook 'window-configuration-change-hook
#'my-right-margin-update nil :local))
(add-hook 'text-mode-hook #'my-right-margin-auto-update)

Emacs Line Height

I am trying to set the line height of text in an Emacs buffer so there is space above and below the letters. From the documentation, I infer that the line-height text property may help me to accomplish this.
There is also a line-spacing variable which I can set like (setq-default line-spacing 0.25). This kind of works, except it does not produce space before text, only after it. I don’t like the way this looks when using modes like show-paren-mode, since it “dips” down:
Undesired current behavior (“hanging”)
Desired behavior mockup (vertically-centered)
I'd like to vertically-center the text.
I have discovered that I can temporarily get the effect I want with the following code:
(add-text-properties (point-min) (point-max)
'(line-spacing 0.25 line-height 1.25))
However, in some modes the properties go away in regions where I start typing. How do I make that top and bottom spacing the default? (Hooks won't work.)
Update
TLDR: I've succumbed to the fact that you can't really reliably achieve this natively with Emacs. You need to patch the font itself to include extra spacing. So, I created this script to take care of that.
Old/Incomplete Answer
TLDR: Add this somewhere in init file:
;; Set the padding between lines
(defvar line-padding 3)
(defun add-line-padding ()
"Add extra padding between lines"
; remove padding overlays if they already exist
(let ((overlays (overlays-at (point-min))))
(while overlays
(let ((overlay (car overlays)))
(if (overlay-get overlay 'is-padding-overlay)
(delete-overlay overlay)))
(setq overlays (cdr overlays))))
; add a new padding overlay
(let ((padding-overlay (make-overlay (point-min) (point-max))))
(overlay-put padding-overlay 'is-padding-overlay t)
(overlay-put padding-overlay 'line-spacing (* .1 line-padding))
(overlay-put padding-overlay 'line-height (+ 1 (* .1 line-padding))))
(setq mark-active nil))
(add-hook 'buffer-list-update-hook 'add-line-padding)
Increase or decrease the line-padding value to your liking.
This answer pretty much just summarizes the information in the above question, answer, and comments, so I suggest reading those first.
I use an overlay instead of text properties because it behaves more nicely when adding new text to the buffer (especially via copy/paste).
The buffer-list-update-hook is used as a means of identifying when a new buffer has been created and thus would need to have the overlay applied.
For performance reasons, to not continuously add overlays, the existing padding overlay is deleted if it aleady existed.
As the doc says, line-height is a text (or an overlay) property. It is not a variable.
Try (setq-default line-spacing 20).
line-spacing is a frame parameter or a buffer-local variable. Its value can be an integer number of pixels or a floating-point number specifying spacing relative to the frame's default line height. The doc says nothing about giving it a list value, such as (32 64).
And if you are using Emacs in terminal mode then none of this applies. As the doc says about that:
On text terminals, the line spacing cannot be altered.
Try "Help => More Manuals => Emacs Lisp Reference" and from there type i text properties RET. This will hopefully clarify the situation. As for your specific request, I don't think there's a simple way to get what you want right now. You might like to M-x report-emacs-bug about the display appearence of the paren-highlighting.

how to prevent Emacs dired from splitting frame into more than two windows?

In an Emacs dired buffer, if I navigate point over a filename and hit o for dired-find-file-other-window, dired successfully produces desired behavior: opening the file in a secondary window.
But if I then navigate point over a SECOND filename and again hit o, dired splits the frame AGAIN and opens the file in a THIRD window.
How do I direct dired to reuse the second window, such that I always have a maximum of two windows in a frame?
Tried to solve the same problem using by modifying value of split-width-threshold, but found that it often stops working when monitor configuration changes. Ended up writing an advice for window-splittable-p.
(setq split-width-threshold (- (window-width) 10))
(setq split-height-threshold nil)
(defun count-visible-buffers (&optional frame)
"Count how many buffers are currently being shown. Defaults to selected frame."
(length (mapcar #'window-buffer (window-list frame))))
(defun do-not-split-more-than-two-windows (window &optional horizontal)
(if (and horizontal (> (count-visible-buffers) 1))
nil
t))
(advice-add 'window-splittable-p :before-while #'do-not-split-more-than-two-windows)
Raise value of split-height-threshold to the extend it will not do another split.
You might have to raise split-width-threshold also - in case Emacs thinks it's smart to split that way than.
WRT questions in comment:
The value to choose IMO depends from number of lines displayed at window. Let's assume 40 lines are displayed. If a window is split, 20 are left. Then a `split-height-threshold' of 15 should prevent further split. Preventing further side-by-side split should work respective, just consider the columns displayed.
BTW would expect a way to adapt that dynamically.

emacs: second toolbar (row)

this is my first question, so apologies for breaking any rules.
I've just started writing some functions in elisp to help me navigate certain types of text files more efficiently. To make these accessible, I've added some buttons to the tool-bar. As it's now becoming busy, I'd like to either: 1) move some of these additional buttons to a second line; or 2) instantiate a second tool-bar that could be placed somewhere else in the frame (either under the existing tool-bar, or perhaps vertically along the side where the scrollbar is).
I've searched high and low but am unable to find an existing example of this and, as I don't yet really know what I'm doing, I wonder if somebody has a code snippet from which I might start to hack a solution together.
Many thanks in advance.
System: CentOS 5/6, emacs for linux 23.1
Edit:
Thanks for the comment, William. Here's a simple example representing what my tool-bar code might do:
;
; functions used by the toolbar
;
;
(defun copy-paste-whole-line ()
"copies and pastes the whole of the current into a new line underneath"
(interactive)
(beginning-of-line)
(set-mark (point))
(end-of-line)
(setq temp (buffer-substring (region-beginning) (region-end)))
(message " copying: %s" temp )
(newline)
(insert temp))
;
;
; population of the toolbar:
;
;
(when (find-image '((:type xpm :file "copy_paste_line.xpm")))
(unless tool-bar-mode (tool-bar-mode 1))
; (setq tool-bar-map (make-sparse-keymap)) ; <- uncomment this line to have only this button present
(tool-bar-add-item
"copy_paste_line"
'copy-paste-whole-line
'copy-paste-whole-line
:help "copies and pastes the whole of the current line into a new line underneath"))
so, as you can see (actually, I'm not allowed to post images until I have 10 reputation points, so you won't be able to see), the code adds an extra button to the end of the existing tool-bar buttons. I believe this to be a reasonable way to achieve this, but I'm not an experienced elisp programmer, so if you think it's poorly written, please comment - I'd like to understand why... :)
If I only had 1 button, it would be ok like that, however, I have multiple buttons. I would, thus, like to add them to a second instance of a similar tool-bar (or, perhaps a vertical one placed where the scrollbars are).
Thanks again for any input.
Frame parameter tool-bar-lines is supposed to control this. You can, for instance, customize option default-frames-alist if you want to change the number of tool-bar rows to 2 or 3 everywhere. Or you can do this on a mode-by-mode or frame-by-frame basis. You can, for instance, use M-: (set-frame-parameter nil 'tool-bar-lines 3).
Depending on your platform (and toolkit), the behavior might be variable. See the Elisp manual, node Layout Parameters and node Tool Bars.
I believe you are out of luck. It seems to me that (at least on ubuntu and cygwin) only one row of buttons in the tool-bar is supported.
Here is what I have tried without luck on both systems:
(progn
(set-frame-parameter nil 'tool-bar-lines 3)
(loop for i from 1 upto 20 do
(setcdr tool-bar-map (cons (cadr tool-bar-map) (cdr tool-bar-map)))))
The following picture shows what I get:
The other buttons appear in a pull-down menu if you click on the little triangle at the right end of the toolbar:
You can restore the old tool-bar with the following commands:
(progn
(setq tool-bar-map (make-sparse-keymap))
(tool-bar-setup))
Finally, I have 3 rows of buttons. This is possible with emacs-w32:
So it is the gtk+ / nextstep problem.

Make as much as possible of buffer visible in window instead of showing empty space after buffer

It is possible to "scroll past the end of the buffer" in a window. This is useful because Emacs has to somehow use the extra space when the buffer does not fill the whole area available to the window used to display it.
However sometimes when the whole buffer would fit completely into the window the top part still isn't displayed and more space than necessary is wasted below the buffer content to fill the available space. It would be better if the window were automatically scrolled to show the complete buffer or if it is bigger than the window as much as possible.
In other words the only time when a window displays something "below the buffer end" is when the window is to big.
Is there a mode or option to do that?
Edit: So something like this?
(add-hook 'post-command-hook 'my-eob-recenter)
(defun my-eob-recenter ()
(when (pos-visible-in-window-p (point-max))
(save-excursion
(goto-char (point-max))
(recenter -1))))
Original answer:
If you have a window which is larger than its contents and you want to shrink it to fit, there's a binding for that.
C-x- runs shrink-window-if-larger-than-buffer
Personally I suspect this would be annoying if it happened automatically, but you might try this:
(defadvice split-window (after my-split-window-shrink)
"Shrink the selected window after a window split
if it is larger than its contents."
(shrink-window-if-larger-than-buffer))
(ad-activate 'split-window)