center-content-mode/center-content.el

101 lines
4.2 KiB
EmacsLisp
Raw Normal View History

;;; 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 visible content
;; of the current buffer both horizontally and vertically. It calculates the necessary margins
;; and applies them using overlays and header line adjustments. The mode line is hidden to
;; provide a clean appearance.
;;; Code:
(defvar-local center-content--horiz-overlay nil
"Overlay used by `center-content-mode` to add left margin for horizontal centering.")
(defvar-local center-content--original-header-line-format nil
"Stores the original `header-line-format` to restore upon disabling.")
(defvar-local center-content--original-mode-line-format nil
"Stores the original `mode-line-format` to restore upon disabling.")
(defface center-content-header-line
`((t (:inherit default
:background ,(face-background 'default nil t)
:foreground ,(face-foreground 'default nil t))))
"Face for the header line in `center-content-mode`."
:group 'center-content)
(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))))
(space-width (string-pixel-width " "))
(margin (/ (max 0 (- window-width content-width)) (* 2 space-width))))
margin))
(defun center-content--calculate-top-margin ()
"Calculate the top margin needed to center the content vertically."
(let* ((window-height (window-pixel-height))
(content-height (cdr (window-text-pixel-size)))
(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 ((horiz-overlay (make-overlay (point-min) (point-max))))
(overlay-put horiz-overlay 'line-prefix
(propertize " " 'display `(space :width ,left-margin)))
(setq center-content--horiz-overlay horiz-overlay))
;; Save the original header-line-format
(setq center-content--original-header-line-format header-line-format)
;; Apply vertical centering using header-line-format with custom face
(setq header-line-format
(propertize " "
'display `(height ,(max 0 (/ top-margin (frame-char-height))))
'face 'center-content-header-line))
;; Save the original mode-line-format
(setq center-content--original-mode-line-format mode-line-format)
;; Hide the mode line
(setq mode-line-format nil)))
(defun center-content--disable ()
"Disable centering of content."
;; Remove horizontal centering overlay
(when (overlayp center-content--horiz-overlay)
(delete-overlay center-content--horiz-overlay)
(setq center-content--horiz-overlay nil))
;; Restore the original header-line-format
(setq header-line-format center-content--original-header-line-format)
(setq center-content--original-header-line-format 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 to remove any lingering effects
(force-mode-line-update)
(redisplay))
;;;###autoload
(define-minor-mode center-content-mode
"Toggle horizontal and vertical centering of buffer content.
When enabled, the visible 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