9

In the screenshot below I have simply set the background of the linum face to some color, however there is a blank region at the end of the buffer and there are gaps between the lines when line wrapping (global-visual-line-mode) is enabled:

Broken linum background with line wrap.

Ideally the whole left side should be in a uniform color. Is this possible? I know some Elisp, so if it’s possible, I could maybe write a fix myself with some instructions.

Malabarba
  • 22,878
  • 6
  • 78
  • 163
Lenar Hoyt
  • 1,163
  • 7
  • 25
  • I've noticed this when switching themes. The work around for me has been to go back to the default theme and then re-enable the specific theme. That usually resets the background colors. It might be worthwhile to take a look at the default theme settings to see if it is more diligent with specific faces that might lend a clue to how to write a function to fix it. – elarson Oct 07 '14 at 22:50
  • Fixing the color "in-between" might be viable (I'll give it a try). Fixing the color after buffer end is, regrettably, not---there's nothing there to be colored. – Malabarba Oct 08 '14 at 10:01
  • In fact, I've seen this asked around so often that it's probably a worthwhile feature request. – Malabarba Oct 08 '14 at 10:07
  • @Malabarba Why is it not possible to extend it into the area below the buffer? The fringe does this too after all. – Lenar Hoyt Oct 08 '14 at 12:20
  • @mcb The fringe also cannot customize what happens after the last line of the buffer. The farthest you can display something in the fringe is the line immediately after the buffer ends. The fringe *background color* does extend beyond that, in the same way that the buffer's background color does extend to the bottom of the screen. Emacs is that way by design, you can't display text anywhere beyond the last line (be it fringe, margin, or buffer) but the background color extends itself. – Malabarba Oct 08 '14 at 12:28
  • 1
    @mcb I understand a little better what you meant now. The fringe has its own face (whose background is extended to the bottom of the screen), the margin doesn't (it just borrows the default face). – Malabarba Oct 08 '14 at 12:31

2 Answers2

6

The Problem

The problem here is that there’s no face to control the appearance of the margins. You can display text in the margin using overlays (that’s what linum-mode does) but, like any text in Emacs, it’s constrained to the limits of the buffer. So you can’t have any control over the margin display beyond the last line of the buffer.

What you can do, is fix those faulty lines in-between.

What to put there

This variable controls what you want to display on those visual lines “between” two logical lines. The important part is the 'face 'linum, which ensures these lines will follow the appearance of linum-mode. The "-----" part is demonstrative, you can change it to spaces or whatever you wish.

(defvar endless/margin-display
  `((margin left-margin) ,(propertize "-----" 'face 'linum))
  "String used on the margin.")

How to do it

The following code goes through the buffer and places overlays (similar to the ones linum-mode uses) on each line which isn’t “real”.

(defvar-local endless/margin-overlays nil
  "List of overlays in current buffer.")

(defun endless/setup-margin-overlays ()
  "Put overlays on each line which is visually wrapped."
  (interactive)
  (let ((ww (- (window-width)
               (if (= 0 (or (cdr fringe-mode) 1)) 1 0)))
        ov)
    (mapc #'delete-overlay endless/margin-overlays)
    (save-excursion
      (goto-char (point-min))
      (while (null (eobp))
        ;; On each logical line
        (forward-line 1)
        (save-excursion
          (forward-char -1)
          ;; Check if it has multiple visual lines.
          (while (>= (current-column) ww)
            (endles/make-overlay-at (point))
            (forward-char (- ww))))))))

(defun endles/make-overlay-at (p)
  "Create a margin overlay at position P."
  (push (make-overlay p (1+ p)) endless/margin-overlays)
  (overlay-put
   (car endless/margin-overlays) 'before-string
   (propertize " "  'display endless/margin-display)))

And we want to it run whenever linum-mode updates the line numbers.

(add-hook 'linum-before-numbering-hook #'endless/setup-margin-overlays)
Malabarba
  • 22,878
  • 6
  • 78
  • 163
  • I’ve just tested it `org-mode` and it seems to introduce some lag during scrolling and it misses gaps for no obvious reason with adaptive wrap turned on. [Screenshot.](https://i.imgur.com/TN7fYIk.png) – Lenar Hoyt Oct 08 '14 at 18:48
  • @mcb Yes, performance is an issue here, but improving that would be a long and complicated matter. As for the org-mode problem, org makes heavy use of overlays, so it makes sense there would be conflict. I'm not aware of any way to fix it, but I'll give it some thought. – Malabarba Oct 08 '14 at 20:06
-1

You could put this in your config:

(set-face-background 'fringe "#f4a460")

... obviously change the colour code to the one you want.

tealeg
  • 1
  • 1
  • 2
    This will change the fringe color, line numbers are not displayed on the fringe. (try it and you'll see the difference) – Malabarba Oct 08 '14 at 09:01
  • 1
    It is also visible on the screenshot in the question: the "line numbers column" is the same background color as the buffer, whereas the fringe is the little area between the line numbers column and the buffer, in gray. – T. Verron Oct 08 '14 at 09:10
  • Yes, you're right. I suspect you'd have to introduce a new overlay in a functon run at the linum-before-numbering-hook and give it a face you can set. – tealeg Oct 08 '14 at 09:36