center-content-mode/center-content.el
2024-09-14 02:39:48 +02:00

95 lines
3.8 KiB
EmacsLisp

;;; center-content.el --- Center buffer content horizontally and vertically -*- lexical-binding: t; -*-
;;; Commentary:
;; This package provides a minor mode `center-content-mode` that centers the content
;; of the current buffer both horizontally and vertically. It calculates the necessary
;; margins and applies them using overlays. The mode line is hidden to provide a clean appearance.
;;; Code:
(defvar-local center-content--horizontal-overlay nil
"Overlay used to add left margin for horizontal centering.")
(defvar-local center-content--vertical-overlay nil
"Overlay used to add top margin for vertical centering.")
(defvar-local center-content--original-mode-line-format nil
"Stores the original `mode-line-format` to restore upon disabling.")
(defun center-content--calculate-left-margin ()
"Calculate the left margin needed to center the content horizontally."
(let* ((window (selected-window))
(window-width (window-pixel-width window))
(content-width (car (window-text-pixel-size
window
(window-start window)
(window-end window)))))
(/ (max 0 (- window-width content-width)) 2)))
(defun center-content--calculate-top-margin ()
"Calculate the top margin needed to center the content vertically."
(let* ((window (selected-window))
(window-height (window-pixel-height window))
(content-height (cdr (window-text-pixel-size window)))
(margin (/ (max 0 (- window-height content-height)) 2)))
margin))
(defun center-content--enable ()
"Enable horizontal and vertical centering of content."
(let ((left-margin (center-content--calculate-left-margin))
(top-margin (center-content--calculate-top-margin)))
;; Apply horizontal centering using overlay
(let ((horizontal-overlay (make-overlay (point-min) (point-max))))
(overlay-put horizontal-overlay 'line-prefix
(propertize " " 'display `(space :width (,left-margin))))
(setq center-content--horizontal-overlay horizontal-overlay))
;; Apply vertical centering using a before-string overlay
(let ((overlay (make-overlay (point-min) (point-min))))
(overlay-put overlay 'before-string
(propertize "\n" 'display `(space :height (,top-margin))))
;; Set low priority to avoid interfering with line-prefix
(overlay-put overlay 'priority -50)
(setq center-content--vertical-overlay overlay))
;; 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)))
(defun center-content--disable ()
"Disable centering of content."
;; Remove horizontal centering overlay
(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 original mode-line-format
(setq mode-line-format center-content--original-mode-line-format)
(setq center-content--original-mode-line-format nil)
;; Force redisplay
(force-mode-line-update)
(redisplay))
;;;###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."
:init-value nil
:global nil
:lighter nil ;; Remove the lighter to keep the mode line clean
(if center-content-mode
(center-content--enable)
(center-content--disable)))
(provide 'center-content)
;;; center-content.el ends here