diff --git a/focus.el b/focus.el index bf403b4..df330c5 100644 --- a/focus.el +++ b/focus.el @@ -63,6 +63,15 @@ In order for changes to take effect, reenable `focus-mode'." :type 'number :group 'focus) +(defcustom focus-update-idle-delay nil + "Delay (in seconds) before updating the focus after each command. +The default value of nil results in an immediate update. +Increase this value if you experience performance issues." + :type '(choice (const :tag "Immediate update" nil) + (const :tag "Delayed update (0.1s)" 0.1) + (number :tag "Custom delay")) + :group 'focus) + (defface focus-unfocused '((t :inherit shadow)) "The face that overlays the unfocused area." @@ -98,6 +107,9 @@ In order for changes to take effect, reenable `focus-mode'." The timer calls `focus-read-only-hide-cursor' after `focus-read-only-blink-seconds' seconds.") +(defvar-local focus-update-timer nil + "Timer started from `focus-update'") + (defun focus-get-thing () "Return the current thing, based on `focus-mode-to-thing'. @@ -120,16 +132,29 @@ This also sets `focus-current-thing-cache' to the current thing." (cons beg end))) (t (bounds-of-thing-at-point thing))))) -(defun focus-move-focus () +(defun focus-move-focus (buffer) "Move the focused section according to `focus-bounds'. If `focus-mode' is enabled, this command fires after each command." - (with-current-buffer focus-buffer + (with-current-buffer buffer + (setq focus-update-timer nil) (let* ((bounds (focus-bounds))) (when bounds (focus-move-overlays (car bounds) (cdr bounds)))))) +(defun focus-update () + "Trigger an update of the focus. + +When `focus-update-idle-delay' is non-nil, start update after the +specified idle delay." + (if focus-update-idle-delay + (unless focus-update-timer + (setq focus-update-timer + (run-with-idle-timer focus-update-idle-delay nil + #'focus-move-focus focus-buffer))) + (focus-move-focus focus-buffer))) + (defun focus-move-overlays (low high) "Move the overlays to highlight the region between LOW and HIGH." (move-overlay focus-pre-overlay (point-min) low) @@ -141,7 +166,7 @@ command." It sets the `focus-pre-overlay', `focus-min-overlay', and `focus-post-overlay' to overlays; these are invisible until -`focus-move-focus' is run. It adds `focus-move-focus' to +`focus-update' is run. It adds `focus-update' to `post-command-hook'." (unless (or focus-pre-overlay focus-post-overlay) (setq focus-pre-overlay (make-overlay (point-min) (point-min)) @@ -151,8 +176,9 @@ It sets the `focus-pre-overlay', `focus-min-overlay', and (overlay-put focus-mid-overlay 'face 'focus-focused) (mapc (lambda (o) (overlay-put o 'face 'focus-unfocused)) (list focus-pre-overlay focus-post-overlay)) - (add-hook 'post-command-hook 'focus-move-focus nil t) - (setq focus-current-thing-cache nil) + (setq focus-current-thing-cache nil + focus-update-timer nil) + (add-hook 'post-command-hook 'focus-update nil t) (add-hook 'change-major-mode-hook 'focus-terminate nil t))) (defun focus-terminate () @@ -160,12 +186,15 @@ It sets the `focus-pre-overlay', `focus-min-overlay', and The overlays pointed to by `focus-pre-overlay', `focus-mid-overlay' and `focus-post-overlay' are deleted, and -`focus-move-focus' is removed from `post-command-hook'." +`focus-update' is removed from `post-command-hook'." (when (and focus-pre-overlay focus-post-overlay) (mapc 'delete-overlay (list focus-pre-overlay focus-mid-overlay focus-post-overlay)) - (remove-hook 'post-command-hook 'focus-move-focus t) + (remove-hook 'post-command-hook 'focus-update t) + (when focus-update-timer + (cancel-timer focus-update-timer)) (setq focus-current-thing-cache nil + focus-update-timer nil focus-pre-overlay nil focus-mid-overlay nil focus-post-overlay nil))) @@ -194,13 +223,16 @@ default is overwritten. This function simply helps set the (when (bound-and-true-p focus-mode) (when (region-active-p) (focus-move-overlays (region-beginning) (region-end))) - (remove-hook 'post-command-hook 'focus-move-focus t))) + (when focus-update-timer + (cancel-timer focus-update-timer)) + (setq focus-update-timer nil) + (remove-hook 'post-command-hook 'focus-update t))) (defun focus-unpin () "Unpin the focused section." (interactive) (when (bound-and-true-p focus-mode) - (add-hook 'post-command-hook 'focus-move-focus nil t))) + (add-hook 'post-command-hook 'focus-update nil t))) (defun focus-next-thing (&optional n) "Move the point to the middle of the Nth next thing."