3

I am writing this mode where I only want to show one paragraph at a time. Ideally I'd like to show the paragraph in the center of the screen. Getting it horizontally centered is trivial, but I have not found out how to enter text vertically. What do you think would be the best way to achieve vertical alignment of a few lines of text in an otherwise empty buffer?

Currently thinking of:

  1. Pasting paragraph into new buffer
  2. Adding a bunch of new-lines
  3. Going to the top of the buffer
  4. Select the visible buffer
  5. Count the number of empty lines in visible buffer with (how-many "^$")
  6. Ensure that there are empty-lines-in-visible-buffer/2 empty lines before the paragraph.

I'm sure there is a better way to do this though.

The Unfun Cat
  • 2,393
  • 16
  • 32
  • What about using `recenter`? You'll still need to add new lines I guess. – glucas Mar 05 '15 at 20:11
  • Please do add that as an answer. Brilliant! I need to fill the buffer with newlines before the paragraph, but still much easier than what I was thinking of doing. – The Unfun Cat Mar 05 '15 at 20:20

2 Answers2

2

There is a recenter command that should do what you want: it will center the line containing point in the current window.

Depending on how you want things to recenter as the paragraph grows, you may want to count the lines in the paragraph and move point to the middle line before calling recenter each time. You also need enough empty lines before the paragraph to recenter. Here's a possible implementation:

(defun recenter-paragraph ()
  (interactive)
  (save-excursion
    (mark-paragraph)
    (let* ((start (region-beginning))
           (end (region-end))
           (count (count-lines start end))
           (min (/ (window-size) 2)))

      ;; pad buffer with empty lines if necessary
      (when (< (line-number-at-pos start) min)
        (goto-char start)
        (newline min))

      ;; go to paragraph midpoint and recenter
      (goto-char end)
      (previous-line (/ count 2))
      (recenter))))
glucas
  • 20,175
  • 1
  • 51
  • 83
2

My approach would be a bit different:

  • Figure out the height of the content to be centered
  • Display a newly created buffer in a window
  • Figure out the window's height
  • Insert a newline with the display property to make it appear tall enough with the height
  • Insert content

An actual implementation is demonstrated in the magic-buffer package, it differs from the proposed strategy in that it's using an overlay for the height adjustment and the usage of various hooks that impact the window height and triggers readjustment on such events.

edit:

(defun my-display-centered-paragraph (text)
  (let* ((buffer (get-buffer-create "*demo*"))
         (window (display-buffer buffer)))
    (with-current-buffer buffer
      (with-selected-window window
        (let ((inhibit-read-only t)
              (window-height (window-body-height window t))
              content-height)
          (delete-region (point-min) (point-max))
          (insert text)
          (set-window-start window (point-min))
          (unless (looking-back "\n$")
            (insert "\n"))
          (setq content-height (cdr (posn-x-y (posn-at-point))))
          (goto-char (point-min))
          (insert (propertize "\n" 'line-height
                              (/ (- window-height content-height) 2))))))))
wasamasa
  • 21,803
  • 1
  • 65
  • 97
  • This seems slightly less hackish, since it only uses one newline. Could you please include a minimal example of adding a newline with a height display property please? – The Unfun Cat Mar 06 '15 at 04:39