branch: externals/topspace commit 42353585e048ef2998c5050bc6ffee5e169e6e41 Author: Trevor Pogue <pogu...@mcmaster.ca> Commit: Trevor Pogue <pogu...@mcmaster.ca>
Minor code improvements from the "low hanging fruit" in initial commit: - made text start closer to dead centered by changing division constant in the vcm--center-offset function/property - simplified the control of vcm-scroll-offset by removing an unnecessary conditional and making it strictly a variable instead of a property - rearranged order in which the code sections appear - added window-resizing hook, but it is not a complete window-resizing solution because it only works for windows in focus - removed before-change-functions-hook which is made redundant by after-change-functions-hook - added comment clarifications for: - purpose of variable vcm-first-recenter-done - fact that the use of term "properties" in this code is inspired specifically from the definition of properties in Python --- vertical-center-mode.el | 166 ++++++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 84 deletions(-) diff --git a/vertical-center-mode.el b/vertical-center-mode.el index 650cd7e158..b34cb773aa 100644 --- a/vertical-center-mode.el +++ b/vertical-center-mode.el @@ -24,10 +24,11 @@ ;;; TODO: ;; - support scrolling above top line with page scrolling as well +;; - wrapped lines being counted as single lines when centering ;; - cannot scroll above top line if buffer open in multiple windows and ;; one or more windows is scrolled above beginning of buffer -;; - centering is a bit lower than dead center -;; - support recentering on window resize +;; - recentering on window resize only occurs in selected buffer +;; - issues if enabling when top line in window is > line 1 ;; - submit to MELPA? (after optimizing/cleaning up code more) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -69,13 +70,19 @@ another window unless user has previously adjusted its height with scrolling. (defun vcm--turn-on () (setq-local vcm-on t) (setq-local vcm-overlay (make-overlay (point-min) (point-max))) + ;; vcm-scroll-offset: the overlay portion that the user adjusts with scrolling (setq-local vcm-scroll-offset 0) (setq-local vcm-user-scrolled nil) (vcm--add-hooks) (if (not (boundp 'vcm-first-recenter-done)) + ;; vcm-first-recenter-done is used to block too many recenterings occuring + ;; that are triggered by window-based hooks, (setq-local vcm-first-recenter-done nil)) - (if vcm-first-recenter-done - (vcm--recenter-reset-scroll))) + ;; Below: let user turn the mode off then on again to recenter while preventing + ;; recentering here on initial mode turn-on. This avoids a bug with buffer + ;; not being centered on emacs startup, but need to investigate further to + ;; understand the root cause behind this bug/solution relationship. + (if vcm-first-recenter-done (vcm--recenter-reset-scroll))) (defun vcm--turn-off () "Delete/unset data structures when the mode is turned off." @@ -86,7 +93,6 @@ another window unless user has previously adjusted its height with scrolling. (makunbound 'vcm-scroll-offset) (makunbound 'vcm-user-scrolled)) -;; handle insertions into the buffer (defun vcm--kill-buffer () (makunbound 'vcm-first-recenter-done) (vcm--turn-off)) @@ -95,32 +101,63 @@ another window unless user has previously adjusted its height with scrolling. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Hooks +;;; Properties (inspired specifically by definition of properties from Python) -(defvar vcm--hook-alist - '( - (window-configuration-change-hook . vcm--recenter-reset-scroll-conditional) - (kill-buffer-hook . vcm--kill-buffer) - (before-change-functions . vcm--recenter-keep-scroll) - (after-change-functions . vcm--recenter-keep-scroll) - (pre-command-hook . vcm--scroll-increase-overlay) - (post-command-hook . vcm--scroll-decrease-overlay)) - "A list of hooks so they only need to be written in one spot. -List of cons cells in format (hook-variable . function).") +(defun vcm--center-offset () + "Portion of the overlay that makes small buffers centered." + ;; dividing by slightly less than 2 here made buffers more dead centered + (let ((center-offset (/ (* (- (window-height) (vcm--buf-size)) 31) 64))) + (when (< center-offset 0) (setq center-offset 0)) + center-offset)) ; return center-offset -(defun vcm--add-hooks () - "Add hooks defined in variable `vcm-hook-alist'." - (mapc (lambda (entry) (add-hook (car entry) (cdr entry) t t)) - vcm--hook-alist)) +(defun vcm--add-to-scroll-offset (direction) + (let ((pos (+ (- (line-number-at-pos) (vcm--top-line)) (vcm--overlay-size))) + (bottom (- (window-height) 5))) + ;; avoids a bug with cursor suddenly scrolling up + (when (> pos bottom) (previous-line))) + ;; only put overlay when top line is 1 + (when (= (vcm--top-line) 1) + ;; block scrolling text fully below bottom of window + (unless (and (> direction 0) + (>= (vcm--overlay-size) (- (window-height) 5))) + (setq vcm-scroll-offset (+ vcm-scroll-offset direction))))) -(defun vcm--remove-hooks () - "Remove hooks defined in variable `vcm-hook-alist'." - (mapc (lambda (entry) (remove-hook (car entry) (cdr entry) t)) - vcm--hook-alist)) +(defun vcm--overlay-size () + "The total overlay size." + (+ vcm-scroll-offset (vcm--center-offset))) + +(defun vcm--buf-size () + "Size of the buffer text in lines." + (count-lines (point-min) (point-max))) + +(defun vcm--top-line () + "Line number of the top line of text shown in the window." + (line-number-at-pos (window-start))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Scrolling +;;; Overlay dislaying and recentering hooks + +;; the optional unused args in this section are just for hook compatibility + +(defun vcm--recenter-keep-scroll (&optional arg0 arg1 arg2) + "Use an overlay to display empty lines at the beginning of the buffer. +This emulates the ability to scroll above the top line." + (let ((overlay-size (vcm--overlay-size))) + (overlay-put vcm-overlay 'before-string + (when (> overlay-size 0) (make-string overlay-size ?\n)))) + (setq vcm-first-recenter-done t)) + +(defun vcm--recenter-reset-scroll (&optional arg0 arg1 arg2) + (setq vcm-scroll-offset 0) + (vcm--recenter-keep-scroll)) + +(defun vcm--recenter-reset-scroll-conditional (&optional arg0 arg1 arg2) + (unless (and vcm-user-scrolled) (vcm--recenter-reset-scroll))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Scrolling hooks (defun vcm--scroll (scroll-list ccm-list scroll-direction) "Emulate scrolling if user command was a scrolling command." @@ -131,7 +168,7 @@ List of cons cells in format (hook-variable . function).") (centering-cursor (member this-command ccm-list))) ;; shouldn't scroll from moving cursor unless in centered-cursor-mode (unless (bound-and-true-p centered-cursor-mode) (setq centering-cursor nil)) - (when (and (or user-is-scrolling centering-cursor)) + (when (or user-is-scrolling centering-cursor) (vcm--add-to-scroll-offset scroll-direction) (setq vcm-user-scrolled t) (vcm--recenter-keep-scroll)))) @@ -148,64 +185,25 @@ List of cons cells in format (hook-variable . function).") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Overlay dislaying and recentering - -(defun vcm--recenter-keep-scroll (&optional arg0 arg1 arg2) - "Use an overlay to display empty lines at the beginning of the buffer. -This emulates the ability to scroll above the top line." - (let ((overlay-size (vcm--overlay-size))) - (overlay-put vcm-overlay 'before-string - (when (> overlay-size 0) (make-string overlay-size ?\n)))) - (setq vcm-first-recenter-done t)) - -(defun vcm--recenter-reset-scroll (&optional arg0 arg1 arg2) - (vcm--reset-scroll) - (vcm--recenter-keep-scroll)) - -(defun vcm--recenter-reset-scroll-conditional (&optional arg0 arg1 arg2) - (unless (and vcm-user-scrolled) - (vcm--recenter-reset-scroll))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Properties - -(defun vcm--center-offset () - "Portion of the overlay that makes small buffer centered." - (let ((center-offset - (/ (- (window-height) (vcm--buf-size)) 2))) - (when (< center-offset 0) (setq center-offset 0)) - center-offset)) ; return center-offset - -(defun vcm--scroll-offset () - "Portion of the overlay the user adjusts with scrolling." - (let ((top-line (vcm--top-line))) - (if (> top-line 2) - (setq vcm-scroll-offset (- (*(vcm--center-offset) -1) 1)))) - vcm-scroll-offset) ; return vcm-scroll-offset - -(defun vcm--add-to-scroll-offset (direction) - (let ((pos (+ (- (line-number-at-pos) (vcm--top-line)) (vcm--overlay-size))) - (bottom (- (window-height) 5))) - ;; avoids a bug with cursor suddenly scrolling up - (when (> pos bottom) (previous-line))) - ;; only put overlay when top line is 1 - (when (= (vcm--top-line) 1) - ;; block scrolling text fully below bottom of window - (unless (and (> direction 0) - (>= (vcm--overlay-size) (- (window-height) 5))) - (setq vcm-scroll-offset (+ (vcm--scroll-offset) direction))))) - -(defun vcm--reset-scroll () (setq vcm-scroll-offset 0)) +;;; Hooks -(defun vcm--overlay-size () - "The total overlay size." - (+ (vcm--scroll-offset) (vcm--center-offset))) +(defvar vcm--hook-alist + '( + (window-configuration-change-hook . vcm--recenter-reset-scroll-conditional) + (window-size-change-functions . vcm--recenter-reset-scroll) + (kill-buffer-hook . vcm--kill-buffer) + (after-change-functions . vcm--recenter-keep-scroll) + (pre-command-hook . vcm--scroll-increase-overlay) + (post-command-hook . vcm--scroll-decrease-overlay)) + "A list of hooks so they only need to be written in one spot. +List of cons cells in format (hook-variable . function).") -(defun vcm--buf-size () - "Size of the buffer text in lines." - (count-lines (point-min) (point-max))) +(defun vcm--add-hooks () + "Add hooks defined in variable `vcm-hook-alist'." + (mapc (lambda (entry) (add-hook (car entry) (cdr entry) t t)) + vcm--hook-alist)) -(defun vcm--top-line () - "Line number of the top line of text shown in the window." - (line-number-at-pos (window-start))) +(defun vcm--remove-hooks () + "Remove hooks defined in variable `vcm-hook-alist'." + (mapc (lambda (entry) (remove-hook (car entry) (cdr entry) t)) + vcm--hook-alist))