@@ -342,27 +342,34 @@ in the echo-area."
342342 :group 'blamer
343343 :type '(repeat symbol))
344344
345- (defvar blamer-idle-timer nil
345+ (defvar-local blamer- -idle-timer nil
346346 " Current timer before commit info showing." )
347347
348- (defvar blamer--previous-line-number nil
348+ (defvar-local blamer--previous-line-number nil
349349 " Line number of previous popup." )
350350
351- (defvar blamer--previous-window-width nil
351+ (defvar-local blamer--previous-window-width nil
352352 " Previous window width." )
353353
354- (defvar blamer--previous-line-length nil
354+ (defvar-local blamer--previous-line-length nil
355355 " Current line number length for detect render function." )
356356
357- (defvar blamer--previous-point nil
357+ (defvar-local blamer--previous-point nil
358358 " Last preserved blamer point." )
359359
360- (defvar blamer--previous-region-active-p nil
360+ (defvar-local blamer--previous-region-active-p nil
361361 " Was previous state is active region?" )
362362
363- (defvar blamer--overlays '()
363+ (defvar-local blamer--overlays '()
364364 " Current active overlays for git blame messages." )
365365
366+ (defvar-local blamer--request-id 0
367+ " Incrementing ID to track and cancel outdated async requests." )
368+
369+ (defun blamer--inc-request-id ()
370+ " Increment request ID to invalidate pending async requests."
371+ (setq blamer--request-id (1+ blamer--request-id)))
372+
366373(defvar blamer--block-render-p nil
367374 " Lock rendering, useful for external packages." )
368375
@@ -396,7 +403,7 @@ Will show the available `blamer-bindings'."
396403
397404;;;### autoload
398405(defun blamer--clear-overlay ()
399- " Clear last overlay."
406+ " Clear last overlay and invalidate pending async requests ."
400407 (dolist (ov blamer--overlays)
401408 (delete-overlay ov))
402409 (setq blamer--overlays '()))
@@ -973,14 +980,16 @@ Return list of strings."
973980
974981(defun blamer--render-line-overlay (commit-info buffer render-point &optional type )
975982 " Render COMMIT-INFO overlay by optional TYPE in the BUFFER at the RENDER-POINT.
976- when not provided `blamer-type' will be used."
977- (with-current-buffer buffer
978- (save-excursion
979- (cond ((eq (or type blamer-type) 'overlay-popup ) (blamer--render-overlay-popup commit-info))
980- ((eq (or type blamer-type) 'echo-area ) (blamer--render-echo-area commit-info))
981- ((eq (or type blamer-type) 'posframe-popup ) (blamer--render-posframe-popup commit-info))
982- ((eq (or type blamer-type) 'margin-overlay ) (blamer--render-margin-overlay commit-info render-point))
983- (t (blamer--render-right-overlay commit-info render-point))))))
983+ when not provided `blamer-type' will be used.
984+ Does nothing if BUFFER is not alive or RENDER-POINT is nil."
985+ (when (and (buffer-live-p buffer) render-point)
986+ (with-current-buffer buffer
987+ (save-excursion
988+ (cond ((eq (or type blamer-type) 'overlay-popup ) (blamer--render-overlay-popup commit-info))
989+ ((eq (or type blamer-type) 'echo-area ) (blamer--render-echo-area commit-info))
990+ ((eq (or type blamer-type) 'posframe-popup ) (blamer--render-posframe-popup commit-info))
991+ ((eq (or type blamer-type) 'margin-overlay ) (blamer--render-margin-overlay commit-info render-point))
992+ (t (blamer--render-right-overlay commit-info render-point)))))))
984993
985994(defun blamer--get-async-blame-info (file-name start-line end-line callback )
986995 " Get blame info for FILE-NAME from START-LINE to END-LINE.
@@ -1015,7 +1024,8 @@ EXPLICIT - flag this rendering as interactive."
10151024 (line-number-at-pos )))
10161025 (file-name (blamer--get-local-name (buffer-file-name )))
10171026 (include-avatar-p (member type '(posframe-popup overlay-popup)))
1018- (current-buffer (current-buffer )))
1027+ (request-buffer (current-buffer ))
1028+ (request-id (blamer--inc-request-id)))
10191029
10201030 (blamer--clear-overlay)
10211031
@@ -1026,18 +1036,22 @@ EXPLICIT - flag this rendering as interactive."
10261036 (blamer--get-async-blame-info
10271037 file-name start-line-number end-line-number
10281038 (lambda (commit-infos )
1029- (when (or explicit (buffer-local-value 'blamer-mode current-buffer))
1039+ (when (and (buffer-live-p request-buffer)
1040+ (eq request-id (buffer-local-value 'blamer--request-id request-buffer))
1041+ (or explicit (buffer-local-value 'blamer-mode request-buffer)))
10301042 (blamer--handle-async-blame-info-result
10311043 commit-infos
1032- current -buffer
1044+ request -buffer
10331045 start-line-number
10341046 include-avatar-p
1047+ request-id
10351048 type)))))))))
10361049
1037- (defun blamer--handle-async-blame-info-result (commit-infos buffer start-line-number include-avatar-p &optional type )
1050+ (defun blamer--handle-async-blame-info-result (commit-infos buffer start-line-number include-avatar-p request-id &optional type )
10381051 " Handle COMMIT-INFOS for BUFFER and START-LINE-NUMBER.
10391052INCLUDE-AVATAR-P is optional argument that can replace
1040- global `blamer-show-avatar-p' variable
1053+ global `blamer-show-avatar-p' variable.
1054+ REQUEST-ID is used to check if this request is still valid.
10411055TYPE is optional view render type."
10421056 (let* ((commit-infos (if commit-infos
10431057 (butlast (split-string commit-infos " \n " ))
@@ -1049,11 +1063,13 @@ TYPE is optional view render type."
10491063 (blamer--async-parse-line-info
10501064 cmd-msg
10511065 (lambda (commit-info )
1052- (blamer--render-line-overlay
1053- commit-info
1054- buffer
1055- (blamer--get-render-point buffer (plist-get commit-info :line-number ))
1056- type))
1066+ (when (and (buffer-live-p buffer)
1067+ (eq request-id (buffer-local-value 'blamer--request-id buffer)))
1068+ (blamer--render-line-overlay
1069+ commit-info
1070+ buffer
1071+ (blamer--get-render-point buffer (plist-get commit-info :line-number ))
1072+ type)))
10571073 line-number
10581074 include-avatar-p)
10591075 (setq line-number (1+ line-number))))))
@@ -1073,12 +1089,16 @@ TYPE is optional view render type."
10731089 (forward-line (- line-number current-line-number)))))
10741090
10751091(defun blamer--get-render-point (buffer line-number )
1076- " Return render point by LINE-NUMBER from BUFFER."
1077- (with-current-buffer buffer
1078- (save-excursion
1079- (blamer--goto-line line-number)
1080- (end-of-line )
1081- (point ))))
1092+ " Return render point by LINE-NUMBER from BUFFER.
1093+ Returns nil if LINE-NUMBER doesn't exist in buffer."
1094+ (when (buffer-live-p buffer)
1095+ (with-current-buffer buffer
1096+ (save-excursion
1097+ (let ((max-line (line-number-at-pos (point-max ))))
1098+ (when (<= line-number max-line)
1099+ (blamer--goto-line line-number)
1100+ (end-of-line )
1101+ (point )))))))
10821102
10831103(defun blamer--safety-render (&optional type )
10841104 " Function for checking current active blamer type before rendering with delay.
@@ -1095,10 +1115,10 @@ Optional TYPE argument will override global `blamer-type'."
10951115
10961116(defun blamer--render-commit-info-with-delay ()
10971117 " Render commit info with delay."
1098- (when blamer-idle-timer
1099- (cancel-timer blamer-idle-timer))
1118+ (when blamer-- idle-timer
1119+ (cancel-timer blamer-- idle-timer))
11001120
1101- (setq blamer-idle-timer
1121+ (setq blamer-- idle-timer
11021122 (run-with-idle-timer (or blamer-idle-time 0 ) nil 'blamer--safety-render )))
11031123
11041124(defun blamer--preserve-state ()
@@ -1124,6 +1144,7 @@ LOCAL-TYPE is force replacement of current `blamer-type' for handle rendering."
11241144 (type (or local-type blamer-type)))
11251145
11261146 (when (and clear-overlays-p (not blamer--block-render-p))
1147+ (blamer--inc-request-id)
11271148 (blamer--clear-overlay))
11281149
11291150 (when (and (not long-region-p)
@@ -1139,22 +1160,24 @@ LOCAL-TYPE is force replacement of current `blamer-type' for handle rendering."
11391160 (not (eq blamer--previous-line-number (line-number-at-pos )))
11401161 (not (eq blamer--previous-line-length (length (thing-at-point 'line ))))))
11411162
1163+ (blamer--inc-request-id)
11421164 (blamer--clear-overlay)
11431165 (blamer--render-commit-info-with-delay))
11441166
11451167 (blamer--preserve-state)))
11461168
11471169(defun blamer--reset-state ()
11481170 " Reset all state after blamer mode is disabled."
1149- (if blamer-idle-timer
1150- (cancel-timer blamer-idle-timer))
1171+ (when blamer- -idle-timer
1172+ (cancel-timer blamer- -idle-timer))
11511173
11521174 (blamer--clear-overlay)
1153- (setq blamer-idle-timer nil )
1175+ (blamer--inc-request-id)
1176+ (setq blamer--idle-timer nil )
11541177 (setq blamer--previous-line-number nil )
11551178 (setq blamer--previous-window-width nil )
11561179 (setq blamer--previous-point nil )
1157- (when (not ( eq nil ( get-buffer blamer--buffer-name)) )
1180+ (when (get-buffer blamer--buffer-name)
11581181 (posframe-hide blamer--buffer-name))
11591182 (remove-hook 'post-command-hook #'blamer--try-render t )
11601183 (remove-hook 'window-state-change-hook #'blamer--try-render t ))
0 commit comments