├── .circleci └── config.yml ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── Cask ├── Makefile ├── README.org ├── centered-window-mode-test.el ├── centered-window.el └── img ├── s-1.png ├── s-2.png └── s-3.png /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: silex/emacs:24 6 | steps: 7 | - checkout 8 | - run: 9 | name: Install Cask 10 | command: curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python 11 | - run: 12 | name: Run Tests 13 | command: PATH="$HOME/.cask/bin:$PATH" make 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Expected behavior 2 | 3 | 4 | 5 | ## Actual behavior 6 | 7 | 8 | 9 | ## Steps to reproduce 10 | 11 | 12 | 13 | ## Backtraces if necessary (`M-x toggle-debug-on-error`) 14 | 15 | 16 | 17 | ## Versions of `centered-window-mode`, Emacs, OS etc. 18 | 19 | - `centered-window-mode`: 20 | - Emacs: 21 | - OS: 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.cask 2 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source gnu) 2 | (source melpa) 3 | 4 | (package-file "centered-window-mode.el") 5 | 6 | (files 7 | "*.el" 8 | (:exclude "init.el" "centered-window-mode-test.el")) 9 | 10 | (development 11 | (depends-on "shut-up")) 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CASK = cask 2 | EMACS = emacs 3 | CASKEMACS = $(CASK) exec $(EMACS) 4 | 5 | LOAD = -l centered-window-mode.el -l centered-window-mode-test.el 6 | 7 | all: test 8 | 9 | cask: 10 | $(shell EMACS=$(EMACS) $(CASK)) 11 | 12 | compile: 13 | $(CASKEMACS) -Q $(LOAD) centered-window-mode.el 14 | 15 | test: 16 | $(CASKEMACS) -batch $(LOAD) -f ert-run-tests-batch-and-exit 17 | 18 | clean: 19 | rm -f *.elc 20 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | *NOTE*: Due to a lack of time to solve the issues of this project and the responsabilities derived from my recent paternity, I'm looking for someone to transfer the ownership of the project and who's willing to keep working in it. 2 | 3 | * Centered Window Mode 4 | 5 | Global minor mode that centers the text of the window. If another 6 | window is visible the text goes back to normal if its width is less than =cwm-centered-window-width=. 7 | 8 | You may want to activate =visual-line-mode= if your lines go out of reach. 9 | 10 | * Screenshots 11 | 12 | [[https://raw.githubusercontent.com/ikame/centered-window-mode/master/img/s-1.png]] 13 | [[https://raw.githubusercontent.com/ikame/centered-window-mode/master/img/s-2.png]] 14 | [[https://raw.githubusercontent.com/ikame/centered-window-mode/master/img/s-3.png]] 15 | 16 | * Installation 17 | 18 | ** Manual installation 19 | 20 | First, download =centered-window-mode.el= in your emacs load path. 21 | 22 | Then, to make it available, add this to your configuration file: 23 | 24 | #+begin_src emacs-lisp 25 | (require 'centered-window-mode) 26 | #+end_src 27 | 28 | ** Installation via el-get 29 | 30 | If you use [[https://github.com/dimitri/el-get][el-get]], the emacs package manager, simply add =centered-window-mode= to your packages list. 31 | 32 | ** Installation via use-package 33 | 34 | If you use [[https://github.com/jwiegley/use-package][use-package]], simply add the following to your init file. 35 | 36 | #+BEGIN_SRC elisp 37 | (use-package centered-window :ensure t) 38 | #+END_SRC 39 | 40 | * Activation 41 | 42 | ** On-the-fly 43 | 44 | Simply type =M-x centered-window-mode= in any buffer. 45 | 46 | ** Permanent 47 | 48 | To make this permanent, add this to your emacs configuration file: 49 | 50 | #+begin_src emacs-lisp 51 | (require 'centered-window-mode) 52 | (centered-window-mode t) 53 | #+end_src 54 | 55 | * Vertical padding 56 | 57 | Adding vertical padding to an Emacs window is kind of hard, I have tried a lot of different solutions but most of them add a lot of complexity and source of bugs to the mode. Currently there are the options =cwm-use-vertical-padding= (default =nil=, set to =t= if you want this feature) and =cwm-frame-internal-border= (default =70=) to add some padding to the frame, it's far from ideal but I have found it at most acceptable for most of the use cases where I need this feature. 58 | 59 | * Customization 60 | Once installed you can easily customize the mode use Emacs' 61 | customization mechanism: =M-x customize-groupcentered-window-mode= 62 | * License 63 | 64 | Copyleft (ɔ) Anler Hernández Peral 65 | 66 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 67 | 68 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 69 | 70 | You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. 71 | -------------------------------------------------------------------------------- /centered-window-mode-test.el: -------------------------------------------------------------------------------- 1 | (require 'centered-window-mode nil t) 2 | 3 | (ert-deftest cwm-mode-activation/deactivation () 4 | (with-temp-buffer 5 | (centered-window-mode-toggle) 6 | (should (eq t centered-window-mode)) 7 | (centered-window-mode-toggle) 8 | (should (eq nil centered-window-mode)))) 9 | -------------------------------------------------------------------------------- /centered-window.el: -------------------------------------------------------------------------------- 1 | ;;; centered-window.el --- Center the text when there's only one window -*- lexical-binding: t; -*- 2 | ;; 3 | ;; Author: Anler Hernández Peral 4 | ;; Version: 1.4.0 5 | ;; Contributors: 6 | ;; Mickael Kerjean 7 | ;; Pierre Lecocq 8 | ;; Syohei YOSHIDA 9 | ;; Lars Tveito 10 | ;; Tianxiang Xiong 11 | ;; Keywords: faces windows 12 | ;; URL: https://github.com/anler/centered-window-mode 13 | ;; Package-Requires: ((emacs "24.4")) 14 | ;; Compatibility: GNU Emacs 24.x 15 | ;; 16 | ;; This file is NOT part of GNU Emacs. 17 | ;; 18 | ;; This program is free software; you can redistribute it and/or 19 | ;; modify it under the terms of the GNU General Public License 20 | ;; as published by the Free Software Foundation; either version 2 21 | ;; of the License, or (at your option) any later version. 22 | ;; 23 | ;; This program is distributed in the hope that it will be useful, 24 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | ;; GNU General Public License for more details. 27 | ;; 28 | ;; You should have received a copy of the GNU General Public License 29 | ;; along with this program. If not, see . 30 | ;; 31 | ;;; Commentary: 32 | ;; 33 | ;; Enable centered-window-mode and your text is going to be centered when there's 34 | ;; only one window in the frame. 35 | ;; 36 | ;; Customizable options are: 37 | ;; cwm-lighter 38 | ;; cwm-centered-window-width 39 | ;; cwm-ignore-buffer-predicates 40 | ;; cwm-incremental-padding 41 | ;; cwm-incremental-padding-% 42 | ;; cwm-use-vertical-padding 43 | ;; cwm-frame-internal-border 44 | ;; 45 | ;;; Code: 46 | 47 | (eval-when-compile 48 | (require 'cl-lib)) 49 | (require 'face-remap) 50 | (require 'subr-x) 51 | (require 'mac-win nil t) 52 | (require 'mwheel nil t) 53 | 54 | (defgroup centered-window nil 55 | "Center text in windows." 56 | :group 'windows 57 | :prefix "cwm-") 58 | 59 | (defcustom cwm-lighter 60 | " #" 61 | "Mode's lighter used in the mode line." 62 | :group 'centered-window 63 | :type 'string) 64 | 65 | (defcustom cwm-centered-window-width 66 | 110 67 | "Minimum line length required to apply the margins." 68 | :group 'centered-window 69 | :initialize #'custom-initialize-default 70 | :set #'cwm--set-and-recenter-windows 71 | :type 'integer) 72 | 73 | (defcustom cwm-incremental-padding 74 | nil 75 | "If t even when the window's width is less than `cwm-centered-window-width' a padding of `cwm-incremental-padding-%' will be applied to each side." 76 | :group 'centered-window 77 | :type 'boolean) 78 | 79 | (defcustom cwm-incremental-padding-% 80 | 0 81 | "Incremental padding percentage to use when `cwm-incremental-padding' is t." 82 | :group 'centered-window 83 | :type 'integer) 84 | 85 | (defcustom cwm-use-vertical-padding 86 | nil 87 | "Whether or not use experimental vertical padding." 88 | :group 'centered-window 89 | :initialize #'custom-initialize-default 90 | :set #'cwm--set-and-recenter-windows 91 | :type 'boolean) 92 | 93 | (defcustom cwm-frame-internal-border 94 | 5 95 | "Frame internal border to use when vertical padding is used." 96 | :group 'centered-window 97 | :initialize #'custom-initialize-default 98 | :set #'cwm--set-and-recenter-windows 99 | :type 'integer) 100 | 101 | (defcustom cwm-left-fringe-ratio 102 | 0 103 | "Ratio by which the left fringe is padded more than the right. 104 | Should be a value between 0 and 100. A value of 0 means off." 105 | :group 'centered-window 106 | :initialize #'custom-initialize-default 107 | :set #'cwm--set-and-recenter-windows 108 | :type '(integer 109 | :validate (lambda (widget) 110 | (let ((ratio (widget-value widget))) 111 | (unless (<= 0 ratio 100) 112 | (widget-put widget :error (format "Invalid ratio (0-100): '%s'" ratio)) 113 | widget))))) 114 | 115 | (defcustom cwm-ignore-buffer-predicates 116 | (list #'cwm-special-buffer-p) 117 | "List of predicate functions. 118 | Each is run with current buffer and if it returns 't the 119 | mode won't activate in that buffer." 120 | :group 'centered-window 121 | :type '(list function)) 122 | 123 | (define-obsolete-variable-alias 124 | 'centered-window-mode-hooks 125 | 'cwm-hooks "1.3.0") 126 | (defcustom cwm-hooks 127 | nil 128 | "Hooks to run every time window is centered (be careful)." 129 | :group 'centered-window 130 | :type 'hook) 131 | 132 | (defun cwm--set-and-recenter-windows (var val) 133 | "Set customizable variable VAR to VAL and recenter windows. 134 | 135 | All windows in all frames are recentered. 136 | 137 | This is intended for use as the `setfunction' of a 138 | `defcustom'. See Info node `(elisp) Variable Definitions'." 139 | (set-default var val) 140 | (dolist (frame (frame-list)) 141 | (with-selected-frame frame 142 | (cwm-center-windows)))) 143 | 144 | (defadvice load-theme (after cwm-set-faces-on-load-theme activate) 145 | "Change the default fringe background whenever the theme changes." 146 | (cwm-update-fringe-background)) 147 | 148 | (defun cwm-ignore-window-p (window) 149 | "Check if BUFF should be ignored when activating the mode." 150 | (not 151 | (null 152 | (delq nil 153 | (mapcar (lambda (predicate) 154 | (funcall predicate (window-buffer window))) 155 | cwm-ignore-buffer-predicates))))) 156 | 157 | (defun cwm-special-buffer-p (buffer) 158 | "Return 't if BUFF buffer name is special (starts with an *). 159 | 160 | The *scratch* buffer although special, is treated as not special 161 | by this function." 162 | (let ((buffname (string-trim (buffer-name buffer)))) 163 | (and buffname 164 | (string-prefix-p "*" buffname) 165 | (not (string= "*scratch*" buffname))))) 166 | 167 | (defun cwm-update-fringe-background () 168 | (custom-set-faces 169 | `(fringe ((t (:background ,(face-attribute 'default :background))))))) 170 | 171 | (defun cwm-turn-on () 172 | (add-hook 'window-configuration-change-hook #'cwm-center-windows) 173 | (add-hook 'window-size-change-functions #'cwm-center-windows-frame) 174 | (cwm-center-windows) 175 | (when cwm-use-vertical-padding 176 | (set-frame-parameter nil 'internal-border-width cwm-frame-internal-border)) 177 | (cwm-bind-fringe-mouse-events)) 178 | 179 | (defun cwm-turn-off () 180 | (remove-hook 'window-configuration-change-hook #'cwm-center-windows) 181 | (remove-hook 'window-size-change-functions #'cwm-center-windows-frame) 182 | (cwm-center-windows) 183 | (set-frame-parameter 184 | nil 185 | 'internal-border-width 186 | (or (alist-get 'internal-border-width default-frame-alist) 187 | 0)) 188 | (cwm-unbind-fringe-mouse-events)) 189 | 190 | (defun cwm-center-windows-frame (frame) 191 | (when (frame-size-changed-p frame) 192 | (cwm-center-windows))) 193 | 194 | (defun cwm-center-windows () 195 | (let ((windows (window-list nil :exclude-minibuffer))) 196 | (mapc #'cwm-center-window-instructions 197 | (mapcar #'cwm-centering-instructions 198 | (cl-remove-if #'cwm-ignore-window-p windows))) 199 | (run-hooks 'centered-window-mode-hooks))) 200 | 201 | (cl-defstruct cwm-centering-instructions 202 | window 203 | left-width 204 | right-width) 205 | 206 | (defun cwm-center-window-instructions (instructions) 207 | (let* ((window (cwm-centering-instructions-window instructions))) 208 | (set-window-fringes window 209 | (cwm-centering-instructions-left-width instructions) 210 | (cwm-centering-instructions-right-width instructions)))) 211 | 212 | (defun cwm-centering-instructions (window) 213 | (let ((widths (cwm-calculate-appropriate-fringe-widths window))) 214 | (make-cwm-centering-instructions 215 | :window window 216 | :left-width (car widths) 217 | :right-width (cdr widths)))) 218 | 219 | (defun cwm-calculate-appropriate-fringe-widths (window) 220 | (let* ((mode-active-p (with-current-buffer (window-buffer window) centered-window-mode)) 221 | (pixel (frame-char-width (window-frame window))) 222 | (window-width (window-total-width window)) 223 | (n (if mode-active-p 224 | (max 225 | (/ (- window-width cwm-centered-window-width) 226 | 2) 227 | (if cwm-incremental-padding 228 | (/ (* window-width cwm-incremental-padding-%) 229 | 100) 230 | 0)) 231 | 0)) 232 | (ratio (/ (* n cwm-left-fringe-ratio) 100)) 233 | (left-width (and mode-active-p (* pixel (if (> n 0) (+ n ratio) n)))) 234 | (right-width (and mode-active-p (* pixel (if (> n 0) (- n ratio) n))))) 235 | `(,left-width . ,right-width))) 236 | 237 | (defun cwm-toggle-bind-fringe-mouse-events (&optional bind direction-command-alist) 238 | (dolist (fringe '("left" "right")) 239 | (dolist (wheel-speed '("" "double" "triple")) 240 | (dolist (scroll-direction '("left" "right" "up" "down")) 241 | (let ((key-name (kbd (concat 242 | "<" fringe "-fringe> " 243 | "<" wheel-speed 244 | (if (string= wheel-speed "") "" "-") 245 | "wheel-" scroll-direction ">")))) 246 | (if bind 247 | (global-set-key key-name 248 | (alist-get (intern-soft scroll-direction) 249 | direction-command-alist)) 250 | (global-unset-key key-name))))))) 251 | 252 | (defun cwm-bind-fringe-mouse-events () 253 | (cond ((and (eq window-system 'mac) (featurep 'mac-win)) 254 | (cwm-toggle-bind-fringe-mouse-events 255 | t 256 | '((left . mac-mwheel-scroll) 257 | (right . mac-mwheel-scroll) 258 | (up . mac-mwheel-scroll) 259 | (down . mac-mwheel-scroll)))) 260 | ((eq window-system nil) nil) 261 | (t 262 | (cwm-toggle-bind-fringe-mouse-events 263 | t 264 | '((left . mwheel-scroll) 265 | (right . mwheel-scroll) 266 | (up . mwheel-scroll) 267 | (down . mwheel-scroll)))))) 268 | 269 | (defun cwm-unbind-fringe-mouse-events () 270 | (cond ((and (eq window-system 'mac) (featurep 'mac-win)) 271 | (cwm-toggle-bind-fringe-mouse-events nil)) 272 | ((eq window-system nil) nil) 273 | (t (cwm-toggle-bind-fringe-mouse-events nil)))) 274 | 275 | ;;;###autoload 276 | (defun centered-window-mode-toggle () 277 | (if centered-window-mode 278 | (centered-window-mode -1) 279 | (centered-window-mode +1))) 280 | 281 | ;;;###autoload 282 | (define-minor-mode centered-window-mode 283 | "Minor mode to center text on the current buffer" 284 | :init-value nil 285 | :global t 286 | :lighter cwm-lighter 287 | (if centered-window-mode (cwm-turn-on) (cwm-turn-off))) 288 | 289 | (provide 'centered-window-mode) 290 | (provide 'centered-window) 291 | ;;; centered-window.el ends here 292 | -------------------------------------------------------------------------------- /img/s-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anler/centered-window-mode/80965f6c6afe8d918481433984b493de72af5399/img/s-1.png -------------------------------------------------------------------------------- /img/s-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anler/centered-window-mode/80965f6c6afe8d918481433984b493de72af5399/img/s-2.png -------------------------------------------------------------------------------- /img/s-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anler/centered-window-mode/80965f6c6afe8d918481433984b493de72af5399/img/s-3.png --------------------------------------------------------------------------------