2024-09-14 00:39:20 +00:00
|
|
|
;;; center-content.el --- Center buffer content horizontally and vertically -*- lexical-binding: t; -*-
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
2024-09-14 21:14:02 +00:00
|
|
|
;; This package provides a minor mode `center-content-mode' that centers the
|
|
|
|
;; content of the current buffer both horizontally and vertically.
|
2024-09-14 00:39:20 +00:00
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
2024-09-14 21:25:33 +00:00
|
|
|
(require 'face-remap)
|
|
|
|
|
2024-09-14 00:39:48 +00:00
|
|
|
(defvar-local center-content--horizontal-overlay nil
|
|
|
|
"Overlay used to add left margin for horizontal centering.")
|
2024-09-14 00:39:20 +00:00
|
|
|
|
2024-09-14 21:14:02 +00:00
|
|
|
(defvar-local center-content--original-header-line-format nil
|
|
|
|
"Stores the original `header-line-format` to restore upon disabling.")
|
2024-09-14 00:39:20 +00:00
|
|
|
|
|
|
|
(defvar-local center-content--original-mode-line-format nil
|
|
|
|
"Stores the original `mode-line-format` to restore upon disabling.")
|
|
|
|
|
2024-09-14 21:14:02 +00:00
|
|
|
(defvar-local center-content--header-line-face-remap-cookie nil
|
|
|
|
"Cookie for the face remapping of `header-line`.")
|
|
|
|
|
2024-09-14 21:22:11 +00:00
|
|
|
(defun center-content--content-pixel-size ()
|
2024-09-14 21:25:33 +00:00
|
|
|
"Return the size of the content of the visible text in pixels."
|
2024-09-14 21:37:52 +00:00
|
|
|
(window-text-pixel-size (selected-window) (window-start) (window-end nil t)))
|
2024-09-14 21:22:11 +00:00
|
|
|
|
|
|
|
(defun center-content--calculate-left-margin (content-width)
|
2024-09-14 21:25:33 +00:00
|
|
|
"Calculate the left margin relative to CONTENT-WIDTH."
|
2024-09-14 21:22:11 +00:00
|
|
|
(let ((window-width (window-pixel-width))
|
|
|
|
(column-width (string-pixel-width " ")))
|
2024-09-14 21:14:02 +00:00
|
|
|
(/ (max 0 (- window-width content-width)) (* 2 column-width))))
|
2024-09-14 00:39:20 +00:00
|
|
|
|
2024-09-14 21:22:11 +00:00
|
|
|
(defun center-content--calculate-top-margin (content-height)
|
2024-09-14 21:25:33 +00:00
|
|
|
"Calculate the top margin relative to CONTENT-HEIGHT."
|
2024-09-14 21:22:11 +00:00
|
|
|
(let ((window-height (window-pixel-height))
|
|
|
|
(line-height (default-line-height)))
|
|
|
|
(/ (max 0 (- window-height content-height)) (* 2 line-height))))
|
2024-09-14 00:39:20 +00:00
|
|
|
|
|
|
|
(defun center-content--enable ()
|
|
|
|
"Enable horizontal and vertical centering of content."
|
2024-09-14 21:22:11 +00:00
|
|
|
(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))))
|
2024-09-14 00:39:20 +00:00
|
|
|
;; Apply horizontal centering using overlay
|
2024-09-14 21:27:43 +00:00
|
|
|
(let ((overlay (make-overlay (point-min) (point-max)))
|
|
|
|
(space (propertize " " 'display `(space :width ,left-margin))))
|
|
|
|
(overlay-put overlay 'line-prefix space)
|
2024-09-14 21:14:02 +00:00
|
|
|
(setq center-content--horizontal-overlay overlay))
|
|
|
|
;; Apply vertical centering using header-line-format
|
|
|
|
;; 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))
|
2024-09-14 21:27:43 +00:00
|
|
|
(setq header-line-format (propertize " " 'display `(height ,top-margin)))
|
2024-09-14 00:39:48 +00:00
|
|
|
;; Save and hide the mode line
|
2024-09-14 00:39:20 +00:00
|
|
|
(setq center-content--original-mode-line-format mode-line-format)
|
2024-09-14 00:39:48 +00:00
|
|
|
(setq mode-line-format nil)
|
|
|
|
;; Force redisplay
|
|
|
|
(force-mode-line-update)
|
|
|
|
(redisplay)))
|
2024-09-14 00:39:20 +00:00
|
|
|
|
|
|
|
(defun center-content--disable ()
|
|
|
|
"Disable centering of content."
|
|
|
|
;; Remove horizontal centering overlay
|
2024-09-14 00:39:48 +00:00
|
|
|
(when (overlayp center-content--horizontal-overlay)
|
|
|
|
(delete-overlay center-content--horizontal-overlay)
|
|
|
|
(setq center-content--horizontal-overlay nil))
|
2024-09-14 21:14:02 +00:00
|
|
|
;; 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)
|
2024-09-14 00:39:20 +00:00
|
|
|
;; Restore the original mode-line-format
|
|
|
|
(setq mode-line-format center-content--original-mode-line-format)
|
2024-09-14 21:14:02 +00:00
|
|
|
(setq center-content--original-header-line-format nil)
|
2024-09-14 00:39:48 +00:00
|
|
|
;; Force redisplay
|
2024-09-14 00:39:20 +00:00
|
|
|
(force-mode-line-update)
|
|
|
|
(redisplay))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(define-minor-mode center-content-mode
|
|
|
|
"Toggle horizontal and vertical centering of buffer content.
|
|
|
|
|
2024-09-14 00:39:48 +00:00
|
|
|
When enabled, the content of the buffer is centered both
|
2024-09-14 00:39:20 +00:00
|
|
|
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
|