Compare commits

..

10 Commits

Author SHA1 Message Date
509db9bbde Add an update function 2024-09-21 00:26:46 +02:00
8fd156e918 Change default value of center-content-hide-mode-line 2024-09-21 00:26:41 +02:00
ea42c54438 Typos 2024-09-20 23:51:53 +02:00
936f79e5db Optionally use an overlay for vertical margin 2024-09-15 02:46:54 +02:00
21dfc29045 Add a lighter 2024-09-15 02:05:53 +02:00
2d82f55835 Cache the original header- and mode-line-format unconditionally 2024-09-15 02:05:21 +02:00
f1a1c4a172 Make things a bit more configurable 2024-09-15 01:52:25 +02:00
1db2c7bff6 Split into horizontal and vertical centering
Also remove forcibly redisplaing. Not sure it's necessary, so let's wait and
see if things break.
2024-09-14 23:42:16 +02:00
d8551328f0 Buggy when position isn't recomputed 2024-09-14 23:37:52 +02:00
bfc3e1c792 Nit 2024-09-14 23:27:43 +02:00

View File

@ -1,4 +1,4 @@
;;; center-content.el --- Center buffer content horizontally and vertically -*- lexical-binding: t; -*-
;;; center-content.el --- Center buffer content -*- lexical-binding: t; -*-
;;; Commentary:
@ -9,13 +9,45 @@
(require 'face-remap)
(defgroup center-content ()
"Center buffer content."
:group 'convenience
:prefix "center-content-")
(defcustom center-content-horizontal t
"Enable horizontal centering."
:type 'boolean
:group 'center-content)
(defcustom center-content-vertical t
"Enable vertical centering."
:type 'boolean
:group 'center-content)
(defcustom center-content-vertical-by-overlay nil
"Enable vertical by using overlays.
Using overlays for vertical centering may give some undesirable
effects on the first line. By default, vertical centering is achieved
by using setting `header-line-format'."
:type 'boolean
:group 'center-content)
(defcustom center-content-hide-mode-line nil
"Hide mode-line when centering."
:type 'boolean
:group 'center-content)
(defvar-local center-content--horizontal-overlay nil
"Overlay used to add left margin for horizontal centering.")
(defvar-local center-content--original-header-line-format nil
(defvar-local center-content--vertical-overlay nil
"Overlay used to add top margin for vertical centering.")
(defvar-local center-content--original-header-line-format header-line-format
"Stores the original `header-line-format` to restore upon disabling.")
(defvar-local center-content--original-mode-line-format nil
(defvar-local center-content--original-mode-line-format mode-line-format
"Stores the original `mode-line-format` to restore upon disabling.")
(defvar-local center-content--header-line-face-remap-cookie nil
@ -23,7 +55,7 @@
(defun center-content--content-pixel-size ()
"Return the size of the content of the visible text in pixels."
(window-text-pixel-size (selected-window) (window-start) (window-end)))
(window-text-pixel-size (selected-window) (window-start) (window-end nil t)))
(defun center-content--calculate-left-margin (content-width)
"Calculate the left margin relative to CONTENT-WIDTH."
@ -37,29 +69,44 @@
(line-height (default-line-height)))
(/ (max 0 (- window-height content-height)) (* 2 line-height))))
(defun center-content--enable ()
"Enable horizontal and vertical centering of content."
(let* ((content-size (center-content--content-pixel-size))
(left-margin (center-content--calculate-left-margin (car content-size)))
(top-margin (center-content--calculate-top-margin (cdr content-size))))
;; Apply horizontal centering using overlay
(let ((overlay (make-overlay (point-min) (point-max))))
(overlay-put overlay 'line-prefix
(propertize " " 'display `(space :width ,left-margin)))
(setq center-content--horizontal-overlay overlay))
;; Apply vertical centering using header-line-format
(defun center-content--horizontal (content-width)
"Add overlay for horizontal centering relative to CONTENT-WIDTH."
(let* ((left-margin (center-content--calculate-left-margin content-width))
(overlay (make-overlay (point-min) (point-max)))
(space (propertize " " 'display `(space :width ,left-margin))))
(overlay-put overlay 'line-prefix space)
(setq center-content--horizontal-overlay overlay)))
(defun center-content--vertical (content-height)
"Add overlay for vertical centering relative to CONTENT-HEIGHT."
(let* ((top-margin (center-content--calculate-top-margin content-height)))
;; Save and remap the header-line face to match the default face
(setq center-content--original-header-line-format header-line-format)
(setq center-content--header-line-face-remap-cookie
(face-remap-add-relative 'header-line 'default))
(setq header-line-format
(propertize " " 'display `(height ,top-margin)))
;; Save and hide the mode line
(setq center-content--original-mode-line-format mode-line-format)
(setq mode-line-format nil)
;; Force redisplay
(force-mode-line-update)
(redisplay)))
(setq header-line-format (propertize " " 'display `(height ,top-margin)))))
(defun center-content--vertical-by-overlay (content-height)
"Add overlay for vertical centering relative to CONTENT-HEIGHT."
(let* ((top-margin (center-content--calculate-top-margin content-height))
(overlay (make-overlay (window-start) (window-start) nil t t))
(space (propertize " " 'display `(space :width 0 :height ,top-margin))))
(overlay-put overlay 'intangible t)
(overlay-put overlay 'before-string space)
(setq center-content--vertical-overlay overlay)))
(defun center-content--enable ()
"Enable horizontal and vertical centering of content."
(setq center-content--original-header-line-format header-line-format)
(setq center-content--original-mode-line-format mode-line-format)
(let* ((content-size (center-content--content-pixel-size)))
(when center-content-horizontal
(center-content--horizontal (car content-size)))
(when center-content-vertical
(if center-content-vertical-by-overlay
(center-content--vertical-by-overlay (cdr content-size))
(center-content--vertical (cdr content-size))))
(when center-content-hide-mode-line
(setq mode-line-format nil))))
(defun center-content--disable ()
"Disable centering of content."
@ -67,30 +114,35 @@
(when (overlayp center-content--horizontal-overlay)
(delete-overlay center-content--horizontal-overlay)
(setq center-content--horizontal-overlay nil))
;; Remove vertical centering overlay
(when (overlayp center-content--vertical-overlay)
(delete-overlay center-content--vertical-overlay)
(setq center-content--vertical-overlay nil))
;; Restore the header-line face remapping
(when center-content--header-line-face-remap-cookie
(face-remap-remove-relative center-content--header-line-face-remap-cookie)
(setq center-content--header-line-face-remap-cookie nil))
;; Restore the header-line-format
(setq header-line-format center-content--original-header-line-format)
(setq center-content--original-mode-line-format nil)
;; Restore the original mode-line-format
(setq mode-line-format center-content--original-mode-line-format)
(setq center-content--original-header-line-format nil)
;; Force redisplay
(force-mode-line-update)
(redisplay))
(setq mode-line-format center-content--original-mode-line-format))
(defun center-content-update ()
"Updates the centering if `center-content-mode' is enabled."
(interactive)
(when (bound-and-true-p center-content-mode)
(center-content--disable)
(center-content--enable)))
;;;###autoload
(define-minor-mode center-content-mode
"Toggle horizontal and vertical centering of buffer content.
When enabled, the content of the buffer is centered both
horizontally and vertically within the window. The mode line is
hidden for a clean appearance."
When enabled, the content of the buffer is centered both horizontally
and vertically within the window."
:init-value nil
:global nil
:lighter nil ;; Remove the lighter to keep the mode line clean
:lighter " Center"
(if center-content-mode
(center-content--enable)
(center-content--disable)))