Skip to content

Commit e9324ac

Browse files
authored
Consecutive result overlays can now be seen (#3259)
Previously, if multiple overlays were created one after another that are meant to last for one command, every second overlay wouldn't show up. This is because there's some bad hook management causing the second overlay in a sequence to be deleted. Whenever we're creating a second overlay, the first one is automatically removed. But, `cider--remove-result-overlay' is still in the `post-command-hook', and thus, right after the second overlay is created, it's immediately deleted. Instead, when we're creating a new overlay, we should call remove any instances of `cider--remove-result-overlay' in the `post-command-hook', so that the newly created overlay doesn't get hosed.
1 parent d08609f commit e9324ac

File tree

3 files changed

+180
-21
lines changed

3 files changed

+180
-21
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Remove needless quotes from the choices of `cider-jack-in-auto-inject-clojure`.
1616
- [#2561](https://github.com/clojure-emacs/cider/issues/2561): Disable undo in `*cider-test-report*` buffers.
1717
- [#3251](https://github.com/clojure-emacs/cider/pull/3251): Disable undo in `*cider-stacktrace*` buffers.
18+
- Consecutive overlays will not be spuriously deleted.
1819

1920
## 1.5.0 (2022-08-24)
2021

cider-overlays.el

+7
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ overlay."
231231
;; inherit the face of the following text.
232232
(display-string (format (propertize format 'face 'default) value))
233233
(o nil))
234+
;; Remove any overlay at the position we're creating a new one, if it
235+
;; exists.
234236
(remove-overlays beg end 'category type)
235237
(funcall (if cider-overlays-use-font-lock
236238
#'font-lock-prepend-text-property
@@ -260,6 +262,11 @@ overlay."
260262
(pcase duration
261263
((pred numberp) (run-at-time duration nil #'cider--delete-overlay o))
262264
(`command
265+
;; Since the previous overlay was already removed above, we should
266+
;; remove the hook to remove all overlays after this function
267+
;; ends. Otherwise, we would inadvertently remove the newly created
268+
;; overlay too.
269+
(remove-hook 'post-command-hook 'cider--remove-result-overlay 'local)
263270
;; If inside a command-loop, tell `cider--remove-result-overlay'
264271
;; to only remove after the *next* command.
265272
(if this-command

test/cider-overlay-tests.el

+172-21
Original file line numberDiff line numberDiff line change
@@ -18,55 +18,206 @@
1818
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
1919

2020
;;; Code:
21-
2221
(require 'buttercup)
22+
(require 'cl-lib)
23+
2324
(require 'cider-overlays)
2425

26+
(defmacro cider--overlay-temp-buffer (&rest body)
27+
"Run `body' in a temp buffer with some text. Also set `this-command' to
28+
true by default, as some parts of `cider--make-result-overlay rely on it
29+
being set that way"
30+
(declare (indent 0)
31+
(debug (&rest form)))
32+
`(with-temp-buffer
33+
;; Will block some tests if this is not set
34+
(setq comment-start ";;")
35+
(insert "(+ 1 2)")
36+
(save-excursion
37+
(insert "\n(+ 3 4)")
38+
(insert "\n(+ 5 6)")
39+
(insert "\n(+ 7 8)")
40+
(insert "\n(+ 9 0)"))
41+
(let ((this-command t))
42+
,@body)))
43+
2544
(defmacro cider--with-overlay (overlay-args &rest body)
26-
"Run BODY in a temp buffer, with overlays created."
45+
"Use temp buffer created by `cider--overlay-temp-buffer', and create an overlay"
2746
(declare (indent 1)
2847
(debug (sexp sexp &rest form)))
29-
`(with-temp-buffer
30-
(insert "garbage")
31-
(save-excursion (insert "\nmore trash"))
32-
(cider--make-result-overlay ,@overlay-args)
33-
,@body))
34-
48+
`(cider--overlay-temp-buffer
49+
(let ((this-command t))
50+
(cider--make-result-overlay ,@overlay-args)
51+
,@body)))
52+
53+
(defconst cider-overlay--scale-time 0.01)
54+
55+
(defun cider-overlay--scale-down-time (args)
56+
(let ((plist (cdr args)))
57+
(when-let* ((value (plist-get plist :duration))
58+
((numberp value)))
59+
(setf (plist-get plist :duration)
60+
(* value cider-overlay--scale-time))
61+
(setf (cdr args) plist)))
62+
args)
63+
64+
(defun sleep--scale-down-time (args)
65+
(list (* cider-overlay--scale-time (car args))))
66+
67+
(defun cider-overlay--safe-to-speed-up-tests ()
68+
(and (<= 28 emacs-major-version)
69+
(not (member system-type
70+
'(ms-dos windows-nt cygwin)))))
3571

3672
(describe "cider--make-result-overlay"
37-
:var (overlay-position this-command)
73+
:var (overlay-count this-command)
3874

3975
(before-all
40-
(fset 'overlay-position (lambda ()
41-
;; FIXME: Why map `overlay-start' (or anything
42-
;; else) since the result is only ever compared
43-
;; to nil?
44-
(mapcar #'overlay-start
45-
(overlays-at (point-min))))))
76+
(fset 'overlay-count (lambda ()
77+
(save-excursion
78+
(goto-char (point-min))
79+
(let ((the-count 0))
80+
(while (not (eobp))
81+
(setq the-count (+ the-count
82+
(length (overlays-at (point)))))
83+
(forward-line 1))
84+
the-count))))
85+
(fset 'end-of-next-line (lambda ()
86+
(forward-line)
87+
(end-of-line)))
88+
(when (cider-overlay--safe-to-speed-up-tests)
89+
(advice-add #'cider--make-result-overlay
90+
:filter-args
91+
#'cider-overlay--scale-down-time)
92+
(advice-add #'sleep-for
93+
:filter-args
94+
#'sleep--scale-down-time)))
95+
96+
(after-all
97+
(when (cider-overlay--safe-to-speed-up-tests)
98+
(advice-remove #'cider--make-result-overlay
99+
#'cider-overlay--scale-down-time)
100+
(advice-remove #'sleep-for
101+
#'sleep--scale-down-time)))
46102

47103
(it "can create overlays"
104+
(cider--overlay-temp-buffer
105+
;; When there are no overlays, there are no overlays
106+
(expect (not (overlays-at (point-min))) :to-be-truthy))
107+
48108
(cider--with-overlay ("ok")
109+
;; When there are overlays, there are overlays.
49110
(expect (overlays-at (point-min)) :to-be-truthy)))
50111

112+
(describe "for all types of overlays"
113+
(it "creating multiple in the same spot will result in the old one being deleted"
114+
(cider--overlay-temp-buffer
115+
(dotimes (i 2)
116+
(dolist (type '(4 command change))
117+
(dotimes (i 3)
118+
(cider--make-result-overlay "ok" :duration type)
119+
(expect (overlay-count) :to-equal 1)))))))
120+
51121
(describe "when overlay duration is `command`"
52-
(it "erases overlays after the next command is executed"
122+
(it "will stay stay for one command"
53123
(cider--with-overlay ("ok" :duration 'command)
124+
;; post-command-hook runs right after overlay is created, so this isn't
125+
;; simulating the next command
54126
(run-hooks 'post-command-hook)
55-
(run-hooks 'post-command-hook)
56-
(expect (overlay-position) :to-equal nil))
127+
(expect (overlay-count) :to-equal 1)))
57128

129+
(it "erases overlays after the next command is executed"
58130
(cider--with-overlay ("ok" :duration 'command)
131+
;; Running post-command-hook twice indicates that not only was the
132+
;; overlay created, but that another command was run after that.
133+
(dotimes (i 2)
134+
(expect (overlay-count) :to-equal 1)
135+
(run-hooks 'post-command-hook))
136+
(expect (overlay-count) :to-equal 0))
137+
138+
(cider--overlay-temp-buffer
139+
;; Instead of the previous test, we can also set this-command to nil,
140+
;; indicating to cider--make-result-overlay that the overlay was created
141+
;; non-interactively, and thus should be deleted after one
142+
;; post-command-hook.
59143
(setq this-command nil)
144+
(cider--make-result-overlay "ok" :duration 'command)
60145
(run-hooks 'post-command-hook)
61-
(expect (overlay-position) :to-equal nil))))
146+
(expect (overlay-count) :to-equal 0)))
147+
148+
(it "will not erase overlays if they're created consecutively"
149+
(cider--overlay-temp-buffer
150+
(dotimes (i 2)
151+
(cider--make-result-overlay "ok" :duration 'command)
152+
(run-hooks 'post-command-hook)
153+
(expect (overlay-count) :to-equal 1)))))
62154

63155
(describe "when overlay duration is given in secs"
64156
(it "erases overlays after that duration"
65157
(cider--with-overlay ("ok" :duration 1.5)
66158
(sleep-for 1)
67-
(expect (overlay-position) :not :to-equal nil)
159+
(expect (overlay-count) :to-equal 1)
160+
(sleep-for 1)
161+
(expect (overlay-count) :to-equal 0)))
162+
163+
(it "overlays will be erased independently of each other"
164+
(cider--overlay-temp-buffer
165+
(cider--make-result-overlay "ok" :duration 1.5)
166+
(end-of-next-line)
167+
(cider--make-result-overlay "ok" :duration 0.5)
168+
(expect (overlay-count) :to-equal 2)
169+
(sleep-for 1)
170+
(expect (overlay-count) :to-equal 1)
68171
(sleep-for 1)
69-
(expect (overlay-position) :to-equal nil)))))
172+
(expect (overlay-count) :to-equal 0)))
173+
174+
(it "overlays don't respond to commands being run or insertions"
175+
(cider--overlay-temp-buffer
176+
(cider--make-result-overlay "ok" :duration 1)
177+
(run-hooks 'post-command-hook)
178+
(run-hooks 'post-command-hook)
179+
(insert "Hello")
180+
(expect (overlay-count) :to-equal 1)))
181+
182+
(it "duration overlays are currently the only overlays that can be deleted independently from the other types"
183+
(cider--overlay-temp-buffer
184+
;; Create overlays
185+
(dolist (type '(0.5 1.5 command change))
186+
(cider--make-result-overlay "ok" :duration type)
187+
(end-of-next-line))
188+
(expect (overlay-count) :to-equal 4)
189+
;; Doing nothing but sit there, one overlay should be removed just
190+
;; because of that.
191+
(sleep-for 1)
192+
(expect (overlay-count) :to-equal 3)
193+
(sleep-for 1)
194+
(expect (overlay-count) :to-equal 2))))
195+
196+
(describe "when overlay duration is `change'"
197+
(it "will not erase from running commands"
198+
(cider--with-overlay ("ok" :duration 'change)
199+
(dotimes (i 3)
200+
(run-hooks 'post-command-hook)
201+
(expect (overlay-count) :to-equal 1))))
202+
203+
(it "will change after making modifications to the buffer"
204+
(cider--with-overlay ("ok" :duration 'change)
205+
(insert "Hello")
206+
(expect (overlay-count) :to-equal 0)))
207+
208+
(it "multiple overlays can be created before they are all destroyed"
209+
(cider--overlay-temp-buffer
210+
(cider--make-result-overlay "ok" :duration 'change)
211+
(expect (overlay-count) :to-be 1)
212+
213+
(end-of-next-line)
214+
(run-hooks 'post-command-hook)
215+
(run-hooks 'post-command-hook)
216+
(cider--make-result-overlay "ok" :duration 'change)
217+
(expect (overlay-count) :to-be 2)
218+
219+
(insert "Hello")
220+
(expect (overlay-count) :to-be 0)))))
70221

71222
(describe "cider--delete-overlay"
72223
:var (overlay-position)

0 commit comments

Comments
 (0)