9

Q: how do I temporarily show text in a window at screen locations with no text to propertize/overlay?

I'm familiar with the basic idea behind text properties and overlays (see also this thread), have used them a few times, but am by no means adept with them. My limited understanding is that there needs to be text to propertize or overlay, but I'm wondering how to use sections of a window that do not have any text in them.

Here's a screenshot for an example:

enter image description here

How could one put text (temporarily) in one of the red boxes in the screenshot, that is, the blank space to the right of the text, or below the last line in the buffer?

  • In short, You can use the display property to display text that isn't there. Somebody may give a full answer before I get home. – Malabarba Nov 3 '14 at 16:57
  • company-mode accomplishes putting an overlay either on text if there is enough after or before point with the display property, alternatively it uses the after-string property to display something below the end of the buffer. I'm less sure about displaying something at the side, but it seems to be possible to with the right width and position of the overlay. – wasamasa Nov 5 '14 at 13:59
  • Can you not just insert text into the buffer and propertize that? – rekado Nov 6 '14 at 6:50
6

I've whipped up a working example of a function that takes a string and temporarily displays it with a timeout after the buffer text:

(defun my-momentarily-display-after-buffer-end (string &optional timeout)
  (let ((ov (make-overlay (point-max) (point-max))))
    (overlay-put ov 'after-string
                 (concat (propertize " " 'display
                                     '(space :align-to (+ left-fringe 10)))
                         (propertize string 'display
                                     '(raise -1))
                         "\n\n"))
    (sit-for (or timeout 5))
    (delete-overlay ov)))

The following incantation will result in your lower red box example:

(my-momentarily-display-after-buffer-end "Nothing to see here...")

The reason this works is because overlays use markers as positions to be displayed between. Using the outermost position as start and end of the overlay enables you to display text after it by using the after-string property. Since overlays can contain propertized text, I set it up to appear indented and with whitespace around it.

The other example can use the same idea to display text after the end of the line:

(defun my-momentarily-display-after-line-end (string &optional timeout)
  (let ((ov (make-overlay (line-end-position) (line-end-position))))
    (overlay-put
     ov 'after-string
     (concat (propertize " " 'display
                         `(space :align-to (- right-fringe
                                              ,(1+ (length string)))))
             string))
    (sit-for (or timeout 5))
    (delete-overlay ov)))

The following invocation will result in your right side red box example:

(my-momentarily-display-after-line-end "annotation")

You can go a lot more crazy and add faces to distinguish these overlays from buffer text, display them longer than for a timeout, adjust their position, detect when there's no empty space and use normal overlays of propertized text, etc. I recommend looking at the source code of company-mode because it's very readable and demonstrates a more elaborate (and mostly bugfree) usage of overlays to create a flexible popup menu with the suggested features.

2

You can temporarily display text in a buffer with the function momentary-string-display. It takes a message to display and a position in the buffer.

This:

(momentary-string-display "hello there" 200)

will place the string "hello there" at position 200 in the buffer. It will move all other text at this point to the side to make room for "hello world", but everything will be restored to where it was when you hit any key.

You don't need text in the buffer to create overlays, although that's a requirement for text-properties. Here's an overlay with zero width that results in additional text to be displayed:

(let ((ov (make-overlay 1 1)))
  (overlay-put ov 'before-string "this text is not part of the buffer"))

Note that this overlay will push away the buffer text; it will not cover the text at the given position.

It does not seem to be possible to place an overlay at any position in the buffer that is greater than point-max / buffer-size, i.e. you probably won't be able to place text at some specific position below the buffer text unless you hack around this restriction. You can, of course, place text right after the buffer text with the after-string property on an overlay pinned to the point-max position.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.