17

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”)

Undesired current behavior

Desired behavior mockup (vertically-centered)

Desired behavior

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.)

Jackson
  • 9,188
  • 6
  • 52
  • 77
  • I'm having difficulty reproducing the *tall* blue background bars with `(setq-default line-spacing 0.25)` and `(show-paren-mode 1)`. Can you please clarify a bit what you mean by *`(setq-default line-spacing 0.25)` . . . does not produce space before text, only after it.* – lawlist Oct 18 '14 at 15:55
  • It is a bit hard to see at `0.25`. In the above screenshot I used `1.0`. `emacs -q` and M-: `(show-paren-mode 1)` and M-: `(setq-default line-spacing 1.0)` should produce the tall bars. – Jackson Oct 18 '14 at 17:37
  • 1
    In the documentation it says "First Emacs uses height as a height spec to control extra space above the line", however as you can see in the above screenshot, extra space is only added after the words. I want to get this "extra space above the line" that the documentation alludes to, such that the blue bar above would extend upwards half as many extra pixels it currently extends downwards, such that the text is vertically-centered within the blue bar. – Jackson Oct 18 '14 at 17:40
  • Added some better screenshots to demonstrate this. – Jackson Oct 18 '14 at 17:56

3 Answers3

8

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.

tam5
  • 3,197
  • 5
  • 24
  • 45
  • This works, except for the mode-line and some buffers, like helm and org-agenda buffers. Is there any way to make this line-height global? – Choma May 24 '19 at 15:06
  • 1
    I have succumbed to the realization that this is simply not supported properly in emacs as of now. I used font forge to patch my own font with extra padding on top and bottom and I've been using this for a while without any issues – tam5 May 28 '19 at 13:23
  • This solution feels like a good start, but still has a ways to go. I see that the line height sometimes momentarily adjusts from the default value to the custom value when editing text. Also, the height of the “blinking square thing” that represents the current point (the “cursor”? dunno what it’s called) changes depending on if point is at whitespace or non whitespace. Both these behaviors are unfortunately rather distracting to me. – Jackson Jun 05 '19 at 06:11
  • You can use `remove-overlays` to simplify your code. – Stefan Jun 05 '19 at 14:09
7

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.
Drew
  • 29,895
  • 7
  • 74
  • 104
  • Actually the documentation says "If the property value is a *list* of the form (height total)...", implying that it can be a list. – Jackson Oct 18 '14 at 17:42
  • Perhaps there is some way to actually set line-height? I've tried `(set-face-attribute 'default nil :height 128)` and that makes the font relatively bigger but with the same hanging issue. `(set-face-attribute 'default nil :height '(128 256))` throws `(error "Default face height not absolute and positive" 128 256)`. – Jackson Oct 18 '14 at 18:02
  • `(set-face-attribute 'default nil :line-height 128)` and `(set-face-attribute 'default nil :line-height '(128 256))` each throw `(error "Invalid face attribute name" :line-height)`... where is this "text property" configured... – Jackson Oct 18 '14 at 18:04
  • What I said was that the doc says nothing about giving **`line-spacing`** a list value. And that is the case - for frame parameter, text/overlay property, and variable. You are perhaps confusing `line-spacing` with `line-height`. – Drew Oct 18 '14 at 23:05
  • `line-height` is a text or overlay property. `:line-height` is not. You really need to pay a bit more attention to the doc - maybe slow down a bit when reading it. Also: if you use `M-x customize-face` or `M-x customize-option` you will perhaps be less likely to get the names wrong, as standard face attributes are presented and possible option values are controlled to some extent. At least for testing, try Customize - it can provide some help, IMO. Anyway, I explained how to increas the inter-line spacing (use `line-spacing`, passing it a number). – Drew Oct 18 '14 at 23:11
  • When we had this conversation years ago, I didn’t really understand what a text property was. Since then I’ve learned that it’s a name-value pair that a person can set for a char at a point using functions like `put-text-property`. (As a point of reference for readers of this thread.) – Jackson Jun 05 '19 at 06:05
1

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.

Stefan
  • 27,908
  • 4
  • 53
  • 82
  • After many years I came to fully grasp the difference between a text property and a variable. I updated the question to remove that confusion. – Jackson Jun 05 '19 at 05:55