minmo : minmo--vc-status-cache : bypass vc-state altogether with hooks and a timer restricted to visible windows
This commit is contained in:
parent
c2daac922c
commit
87d42fccd7
1 changed files with 74 additions and 72 deletions
|
|
@ -91,84 +91,86 @@ filesystem FSTYPE, 'git or 'disk."
|
||||||
(defun minmo-branch () minmo--vc-branch-cache)
|
(defun minmo-branch () minmo--vc-branch-cache)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;; tracked
|
;;;; status
|
||||||
|
|
||||||
;; along with auto-revert-check-vc-info and global-auto-revert-mode,
|
(defvar-local minmo--vc-status-cache nil
|
||||||
;; vc-mode works well. but, still too noisy without modification.
|
"Cached mode-line string for git file status.")
|
||||||
(defvar-local minmo--vc-tracked-cache nil
|
|
||||||
"Cached mode-line string for tracked git files.")
|
|
||||||
|
|
||||||
(defun minmo--vc-tracked-status-override (file)
|
(defun minmo-vc-status ()
|
||||||
"Replace the default `vc-git-mode-line-string' builder.
|
(or minmo--vc-status-cache " "))
|
||||||
Uses the fast `vc-state' cache rather than synchronous git calls."
|
|
||||||
(let* ((state (vc-state file)))
|
(defun minmo--update-vc-cache ()
|
||||||
(setq minmo--vc-branch-cache (minmo--fetch-vc-branch file))
|
"Call git and cache the mode-line string."
|
||||||
(setq minmo--vc-tracked-cache
|
(when (and (minmo--file-exists-locally-p)
|
||||||
(concat " " (pcase state
|
;; NOTE: this is cached via vc-backend and vc-file-prop-obarray,
|
||||||
;; NOTE: vc-mode adds its own space prefix to vc-git-mode-line-string:
|
;; so it's safe as a guardrail:
|
||||||
|
(eq (vc-responsible-backend buffer-file-name t) 'Git))
|
||||||
|
|
||||||
|
;; NOTE: this is cached via vc-file-prop-obarray
|
||||||
|
(setq minmo--vc-branch-cache (minmo--fetch-vc-branch buffer-file-name))
|
||||||
|
;; NOTE: this is not cached and will run git:
|
||||||
|
(let ((status (vc-git-state buffer-file-name)))
|
||||||
|
(setq minmo--vc-status-cache
|
||||||
|
(concat " " (pcase status
|
||||||
('up-to-date (minmo--status 'unmodified 'git))
|
('up-to-date (minmo--status 'unmodified 'git))
|
||||||
;; NOTE: vc-state does not distinguish between staged
|
|
||||||
;; and unstaged:
|
|
||||||
('edited (minmo--status 'modified/staged 'git))
|
('edited (minmo--status 'modified/staged 'git))
|
||||||
('added (minmo--status 'new 'git))
|
('added (minmo--status 'new 'git))
|
||||||
('needs-merge (minmo--status 'modified/staged 'git))
|
('needs-merge (minmo--status 'modified/staged 'git))
|
||||||
('conflict (minmo--status 'modified/staged 'git))
|
('conflict (minmo--status 'modified/staged 'git))
|
||||||
(_ (minmo--status 'unmodified 'git))
|
|
||||||
)))))
|
|
||||||
|
|
||||||
;; NOTE: :override replaces the function
|
|
||||||
(advice-add #'vc-git-mode-line-string :override #'minmo--vc-tracked-status-override)
|
|
||||||
|
|
||||||
(defun minmo-vc-tracked-status () minmo--vc-tracked-cache)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;;; untracked
|
|
||||||
|
|
||||||
;; this relies on calling git manually, and not the vc-state cache.
|
|
||||||
;; however, we cache the state ourselves here in this variable, and only change
|
|
||||||
;; it when the hooks fire.
|
|
||||||
(defvar-local minmo--vc-untracked-cache nil
|
|
||||||
"Cached mode-line string for untracked/ignored git files.")
|
|
||||||
|
|
||||||
(defun minmo--cache-vc-untracked ()
|
|
||||||
"Uses built-in vc to check if a file is untracked or ignored without blocking redisplay."
|
|
||||||
;; NOTE: this will run for remote files, which is still desirable, since
|
|
||||||
;; this will rely on normal vc-mode checks. the (minmo--file-exists-locally-p)
|
|
||||||
;; checks below are to prevent my hacks from running out of control when
|
|
||||||
;; remote or sudo.
|
|
||||||
(when (and buffer-file-name
|
|
||||||
(not vc-mode)
|
|
||||||
(minmo--file-exists-locally-p)
|
|
||||||
(eq (vc-responsible-backend buffer-file-name t) 'Git))
|
|
||||||
|
|
||||||
;; vc-git-state directly queries git
|
|
||||||
(let ((state (vc-git-state buffer-file-name)))
|
|
||||||
(setq minmo--vc-branch-cache (minmo--fetch-vc-branch buffer-file-name))
|
|
||||||
(setq minmo--vc-untracked-cache
|
|
||||||
(concat " " (pcase state
|
|
||||||
;; NOTE: we need the space prefix to match the output of vc-mode:
|
|
||||||
('unregistered (minmo--status 'nofile/untracked 'git))
|
('unregistered (minmo--status 'nofile/untracked 'git))
|
||||||
('ignored (minmo--status 'readonly/ignored 'git))
|
('ignored (minmo--status 'readonly/ignored 'git))
|
||||||
(_ nil)))))))
|
(_ (minmo--status 'unmodified 'git))))))))
|
||||||
|
|
||||||
;; NOTE: update the state when the file state changes
|
;; NOTE: update the cache with file changes
|
||||||
;; this is the only remaining part of this approach which is somewhat hacky, in
|
(add-hook 'find-file-hook #'minmo--update-vc-cache)
|
||||||
;; that vc-mode otherwise handles the refresh. but these are infrequent actions:
|
(add-hook 'after-save-hook #'minmo--update-vc-cache)
|
||||||
(add-hook 'find-file-hook #'minmo--cache-vc-untracked)
|
(add-hook 'after-revert-hook #'minmo--update-vc-cache)
|
||||||
(add-hook 'after-save-hook #'minmo--cache-vc-untracked)
|
|
||||||
(add-hook 'after-revert-hook #'minmo--cache-vc-untracked)
|
|
||||||
|
|
||||||
(defun minmo-vc-untracked-status () minmo--vc-untracked-cache)
|
;; and when window state changes:
|
||||||
|
(defun minmo--update-vc-cache-window-status (frame-or-window)
|
||||||
|
(let ((win (if (framep frame-or-window)
|
||||||
|
(frame-selected-window frame-or-window)
|
||||||
|
frame-or-window)))
|
||||||
|
(with-current-buffer (window-buffer win)
|
||||||
|
(minmo--update-vc-cache))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;
|
;; NOTE: window-state-change-functions includes size changes, which would be spammy.
|
||||||
;; unified interface
|
;; this does selection changes, eg other-window:
|
||||||
(defun minmo-vc-status ()
|
(add-hook 'window-selection-change-functions #'minmo--update-vc-cache-window-status)
|
||||||
(or
|
;; this does buffer changes, eg switch-to-buffer:
|
||||||
(minmo-vc-tracked-status)
|
(add-hook 'window-buffer-change-functions #'minmo--update-vc-cache-window-status)
|
||||||
(minmo-vc-untracked-status)
|
|
||||||
;; NOTE: need this space for files outside of VC:
|
;; this is set by vc-hooks.el, which is loaded with `vc'
|
||||||
" "
|
;; we still want this, because vc-responsible-backend and vc-git--symbolic-ref
|
||||||
))
|
;; use the cache set by this function:
|
||||||
|
;; (remove-hook 'find-file-hook #'vc-refresh-state)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;; timer
|
||||||
|
|
||||||
|
;; NOTE: the idea here is to keep the timer like vc-mode uses when
|
||||||
|
;; auto-revert-check-vc-info is t, but restrict to visible windows. Which is
|
||||||
|
;; somewhat an obvious optimization.
|
||||||
|
|
||||||
|
(defcustom minmo-vc-cache-timer-interval 5
|
||||||
|
"interval for `minmo-vc-cache-timer'")
|
||||||
|
|
||||||
|
(defvar minmo-vc-cache-timer nil)
|
||||||
|
|
||||||
|
(defun minmo--vc-update-cache-visible ()
|
||||||
|
"Update vc cache for visible windows."
|
||||||
|
(dolist (win (window-list))
|
||||||
|
(with-current-buffer (window-buffer win)
|
||||||
|
(minmo--update-vc-cache))))
|
||||||
|
|
||||||
|
;; guard against spawning multiple when this file is eval'd :
|
||||||
|
(when minmo-vc-cache-timer (cancel-timer minmo-vc-cache-timer))
|
||||||
|
(setq minmo-vc-cache-timer
|
||||||
|
;; TODO: run-with-idle-timer ?
|
||||||
|
(run-with-timer
|
||||||
|
minmo-vc-cache-timer-interval
|
||||||
|
minmo-vc-cache-timer-interval
|
||||||
|
'minmo--vc-update-cache-visible))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;; disk
|
;;;; disk
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue