aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Hansen2022-06-28 16:25:43 -0400
committerLars Ingebrigtsen2022-09-11 13:46:30 +0200
commitf47a5324f44e5b8d0016cff2a4f995ff418a5d19 (patch)
tree17570eb9f0dbd76fa8ba683c67ea3e42fab121bd
parent395786f42b0eed361ee34cd398bc8ee33802ed04 (diff)
downloademacs-f47a5324f44e5b8d0016cff2a4f995ff418a5d19.tar.gz
emacs-f47a5324f44e5b8d0016cff2a4f995ff418a5d19.zip
whitespace: Redo BoB/EoB empty line highlighting
* lisp/whitespace.el (whitespace--empty-at-bob-matcher, whitespace--empty-at-eob-matcher, whitespace--update-bob-eob, whitespace-color-off, whitespace-color-on, whitespace-empty-at-bob-regexp, whitespace-empty-at-eob-regexp, whitespace-looking-back, whitespace-post-command-hook): Redo the `empty' line highlighting logic to ensure that a buffer change causes all affected `empty' lines to become (un)highlighted (bug#37467). Also, for improved UX, don't highlight BoB empty lines at or below point (not just when point is at 1), or EoB empty lines at or above point (not just when point is `eobp'). (whitespace-bob-marker, whitespace-eob-marker): Clarify documentation. * test/lisp/whitespace-tests.el (whitespace--with-test-buffer, whitespace--fu, whitespace-tests--empty-bob, whitespace-tests--empty-eob): Add tests.
-rw-r--r--lisp/whitespace.el255
-rw-r--r--test/lisp/whitespace-tests.el230
2 files changed, 385 insertions, 100 deletions
diff --git a/lisp/whitespace.el b/lisp/whitespace.el
index 8146eff9b0a..ae4d8ae3f06 100644
--- a/lisp/whitespace.el
+++ b/lisp/whitespace.el
@@ -1139,12 +1139,21 @@ Used by function `whitespace-trailing-regexp' (which see).")
1139 "Region whose highlighting depends on `whitespace-point'.") 1139 "Region whose highlighting depends on `whitespace-point'.")
1140 1140
1141(defvar-local whitespace-bob-marker nil 1141(defvar-local whitespace-bob-marker nil
1142 "Used to save locally the bob marker value. 1142 "Position of the buffer's first non-empty line.
1143Used by function `whitespace-post-command-hook' (which see).") 1143This marker is positioned at the beginning of the first line in
1144the buffer that contains a non-space character. If no such line
1145exists, this is positioned at the end of the buffer (which could
1146be after `whitespace-eob-marker' if the buffer contains nothing
1147but empty lines).")
1144 1148
1145(defvar-local whitespace-eob-marker nil 1149(defvar-local whitespace-eob-marker nil
1146 "Used to save locally the eob marker value. 1150 "Position after the buffer's last non-empty line.
1147Used by function `whitespace-post-command-hook' (which see).") 1151This marker is positioned at the beginning of the first line
1152immediately following the last line in the buffer that contains a
1153non-space character. If no such line exists, this is positioned
1154at the beginning of the buffer (which could be before
1155`whitespace-bob-marker' if the buffer contains nothing but empty
1156lines).")
1148 1157
1149(defvar-local whitespace-buffer-changed nil 1158(defvar-local whitespace-buffer-changed nil
1150 "Used to indicate locally if buffer changed. 1159 "Used to indicate locally if buffer changed.
@@ -2059,9 +2068,14 @@ resultant list will be returned."
2059 (delete-overlay ol) ol)) 2068 (delete-overlay ol) ol))
2060 (setq-local whitespace-bob-marker (point-min-marker)) 2069 (setq-local whitespace-bob-marker (point-min-marker))
2061 (setq-local whitespace-eob-marker (point-max-marker)) 2070 (setq-local whitespace-eob-marker (point-max-marker))
2071 (whitespace--update-bob-eob)
2062 (setq-local whitespace-buffer-changed nil) 2072 (setq-local whitespace-buffer-changed nil)
2063 (add-hook 'post-command-hook #'whitespace-post-command-hook nil t) 2073 (add-hook 'post-command-hook #'whitespace-post-command-hook nil t)
2064 (add-hook 'before-change-functions #'whitespace-buffer-changed nil t) 2074 (add-hook 'before-change-functions #'whitespace-buffer-changed nil t)
2075 (add-hook 'after-change-functions #'whitespace--update-bob-eob
2076 ;; The -1 ensures that it runs before any
2077 ;; `font-lock-mode' hook functions.
2078 -1 t)
2065 ;; Add whitespace-mode color into font lock. 2079 ;; Add whitespace-mode color into font lock.
2066 (setq 2080 (setq
2067 whitespace-font-lock-keywords 2081 whitespace-font-lock-keywords
@@ -2114,11 +2128,11 @@ resultant list will be returned."
2114 `((,whitespace-big-indent-regexp 1 'whitespace-big-indent t))) 2128 `((,whitespace-big-indent-regexp 1 'whitespace-big-indent t)))
2115 ,@(when (memq 'empty whitespace-active-style) 2129 ,@(when (memq 'empty whitespace-active-style)
2116 ;; Show empty lines at beginning of buffer. 2130 ;; Show empty lines at beginning of buffer.
2117 `((,#'whitespace-empty-at-bob-regexp 2131 `((,#'whitespace--empty-at-bob-matcher
2118 1 whitespace-empty t) 2132 0 whitespace-empty t)
2119 ;; Show empty lines at end of buffer. 2133 ;; Show empty lines at end of buffer.
2120 (,#'whitespace-empty-at-eob-regexp 2134 (,#'whitespace--empty-at-eob-matcher
2121 1 whitespace-empty t))) 2135 0 whitespace-empty t)))
2122 ,@(when (or (memq 'space-after-tab whitespace-active-style) 2136 ,@(when (or (memq 'space-after-tab whitespace-active-style)
2123 (memq 'space-after-tab::tab whitespace-active-style) 2137 (memq 'space-after-tab::tab whitespace-active-style)
2124 (memq 'space-after-tab::space whitespace-active-style)) 2138 (memq 'space-after-tab::space whitespace-active-style))
@@ -2153,6 +2167,8 @@ resultant list will be returned."
2153 (when (whitespace-style-face-p) 2167 (when (whitespace-style-face-p)
2154 (remove-hook 'post-command-hook #'whitespace-post-command-hook t) 2168 (remove-hook 'post-command-hook #'whitespace-post-command-hook t)
2155 (remove-hook 'before-change-functions #'whitespace-buffer-changed t) 2169 (remove-hook 'before-change-functions #'whitespace-buffer-changed t)
2170 (remove-hook 'after-change-functions #'whitespace--update-bob-eob
2171 t)
2156 (font-lock-remove-keywords nil whitespace-font-lock-keywords) 2172 (font-lock-remove-keywords nil whitespace-font-lock-keywords)
2157 (font-lock-flush))) 2173 (font-lock-flush)))
2158 2174
@@ -2201,115 +2217,83 @@ resultant list will be returned."
2201 (format ".\\{%d\\}" rem))))) 2217 (format ".\\{%d\\}" rem)))))
2202 limit t)) 2218 limit t))
2203 2219
2204(defun whitespace-empty-at-bob-regexp (limit) 2220(defun whitespace--empty-at-bob-matcher (limit)
2205 "Match spaces at beginning of buffer (BOB) which do not contain point at BOB." 2221 "Match empty/space-only lines at beginning of buffer (BoB).
2206 (let ((b (point)) 2222Match does not extend past position LIMIT. For improved UX, the
2207 r) 2223line containing `whitespace-point' and subsequent lines are
2208 (cond 2224excluded from the match. (The idea is that the user might be
2209 ;; at bob 2225about to start typing, and if they do, that line and any
2210 ((= b 1) 2226following empty lines will no longer be BoB empty lines.
2211 (setq r (and (looking-at whitespace-empty-at-bob-regexp) 2227Highlighting those lines can be distracting.)"
2212 (or (/= whitespace-point 1) 2228 (let ((p (point))
2213 (progn (whitespace-point--used (match-beginning 0) 2229 (e (min whitespace-bob-marker limit
2214 (match-end 0)) 2230 ;; EoB marker will be before BoB marker if the buffer
2215 nil)))) 2231 ;; has nothing but empty lines.
2216 (set-marker whitespace-bob-marker (if r (match-end 1) b))) 2232 whitespace-eob-marker
2217 ;; inside bob empty region 2233 (save-excursion (goto-char whitespace-point)
2218 ((<= limit whitespace-bob-marker) 2234 (line-beginning-position)))))
2219 (setq r (looking-at whitespace-empty-at-bob-regexp)) 2235 (when (= p 1)
2220 (if r 2236 ;; See the comment in `whitespace--update-bob-eob' for why this
2221 (when (< (match-end 1) limit) 2237 ;; text property is added here.
2222 (set-marker whitespace-bob-marker (match-end 1))) 2238 (put-text-property 1 whitespace-bob-marker
2223 (set-marker whitespace-bob-marker b))) 2239 'font-lock-multiline t))
2224 ;; intersection with end of bob empty region 2240 (when (< p e)
2225 ((<= b whitespace-bob-marker) 2241 (set-match-data (list p e))
2226 (setq r (looking-at whitespace-empty-at-bob-regexp)) 2242 (goto-char e))))
2227 (set-marker whitespace-bob-marker (if r (match-end 1) b))) 2243
2228 ;; it is not inside bob empty region 2244(defsubst whitespace--looking-back (regexp)
2229 (t
2230 (setq r nil)))
2231 ;; move to end of matching
2232 (and r (goto-char (match-end 1)))
2233 r))
2234
2235
2236(defsubst whitespace-looking-back (regexp limit)
2237 (save-excursion 2245 (save-excursion
2238 (when (/= 0 (skip-chars-backward " \t\n" limit)) 2246 (when (/= 0 (skip-chars-backward " \t\n"))
2239 (unless (bolp) 2247 (unless (bolp)
2240 (forward-line 1)) 2248 (forward-line 1))
2241 (looking-at regexp)))) 2249 (looking-at regexp))))
2242 2250
2243 2251(defun whitespace--empty-at-eob-matcher (limit)
2244(defun whitespace-empty-at-eob-regexp (limit) 2252 "Match empty/space-only lines at end of buffer (EoB).
2245 "Match spaces at end of buffer which do not contain the point at end of \ 2253Match does not extend past position LIMIT. For improved UX, the
2246buffer." 2254line containing `whitespace-point' and preceding lines are
2247 (let ((b (point)) 2255excluded from the match. (The idea is that the user might be
2248 (e (1+ (buffer-size))) 2256about to start typing, and if they do, that line and previous
2249 r) 2257empty lines will no longer be EoB empty lines. Highlighting
2250 (cond 2258those lines can be distracting.)"
2251 ;; at eob 2259 (when (= limit (1+ (buffer-size)))
2252 ((= limit e) 2260 ;; See the comment in `whitespace--update-bob-eob' for why this
2253 (goto-char limit) 2261 ;; text property is added here.
2254 (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b)) 2262 (put-text-property whitespace-eob-marker limit
2255 (when (and r (= whitespace-point e)) 2263 'font-lock-multiline t))
2256 (setq r nil) 2264 (let ((b (max (point) whitespace-eob-marker
2257 (whitespace-point--used (match-beginning 0) (match-end 0))) 2265 whitespace-bob-marker ; See comment in the bob func.
2258 (if r 2266 (save-excursion (goto-char whitespace-point)
2259 (set-marker whitespace-eob-marker (match-beginning 1)) 2267 (forward-line 1)
2260 (set-marker whitespace-eob-marker limit) 2268 (point)))))
2261 (goto-char b))) ; return back to initial position 2269 (when (< b limit)
2262 ;; inside eob empty region 2270 (set-match-data (list b limit))
2263 ((>= b whitespace-eob-marker) 2271 (goto-char limit))))
2264 (goto-char limit)
2265 (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b))
2266 (if r
2267 (when (> (match-beginning 1) b)
2268 (set-marker whitespace-eob-marker (match-beginning 1)))
2269 (set-marker whitespace-eob-marker limit)
2270 (goto-char b))) ; return back to initial position
2271 ;; intersection with beginning of eob empty region
2272 ((>= limit whitespace-eob-marker)
2273 (goto-char limit)
2274 (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b))
2275 (if r
2276 (set-marker whitespace-eob-marker (match-beginning 1))
2277 (set-marker whitespace-eob-marker limit)
2278 (goto-char b))) ; return back to initial position
2279 ;; it is not inside eob empty region
2280 (t
2281 (setq r nil)))
2282 r))
2283
2284 2272
2285(defun whitespace-buffer-changed (_beg _end) 2273(defun whitespace-buffer-changed (_beg _end)
2286 "Set `whitespace-buffer-changed' variable to t." 2274 "Set `whitespace-buffer-changed' variable to t."
2287 (setq whitespace-buffer-changed t)) 2275 (setq whitespace-buffer-changed t))
2288 2276
2289
2290(defun whitespace-post-command-hook () 2277(defun whitespace-post-command-hook ()
2291 "Save current point into `whitespace-point' variable. 2278 "Save current point into `whitespace-point' variable.
2292Also refontify when necessary." 2279Also refontify when necessary."
2293 (unless (and (eq whitespace-point (point)) 2280 (unless (and (eq whitespace-point (point))
2294 (not whitespace-buffer-changed)) 2281 (not whitespace-buffer-changed))
2282 (when (and (not whitespace-buffer-changed)
2283 (memq 'empty whitespace-active-style))
2284 ;; No need to handle the `whitespace-buffer-changed' case here
2285 ;; because that is taken care of by the `font-lock-multiline'
2286 ;; text property.
2287 (when (<= (min (point) whitespace-point) whitespace-bob-marker)
2288 (font-lock-flush 1 whitespace-bob-marker))
2289 (when (>= (max (point) whitespace-point) whitespace-eob-marker)
2290 (font-lock-flush whitespace-eob-marker (1+ (buffer-size)))))
2295 (setq-local whitespace-buffer-changed nil) 2291 (setq-local whitespace-buffer-changed nil)
2296 (setq whitespace-point (point)) ; current point position 2292 (setq whitespace-point (point)) ; current point position
2297 (let ((refontify 2293 (let ((refontify (and (eolp) ; It is at end of line ...
2298 (cond 2294 ;; ... with trailing SPACE or TAB
2299 ;; It is at end of buffer (eob). 2295 (or (memq (preceding-char) '(?\s ?\t)))
2300 ((= whitespace-point (1+ (buffer-size))) 2296 (line-beginning-position)))
2301 (when (whitespace-looking-back whitespace-empty-at-eob-regexp
2302 nil)
2303 (match-beginning 0)))
2304 ;; It is at end of line ...
2305 ((and (eolp)
2306 ;; ... with trailing SPACE or TAB
2307 (or (memq (preceding-char) '(?\s ?\t))))
2308 (line-beginning-position))
2309 ;; It is at beginning of buffer (bob).
2310 ((and (= whitespace-point 1)
2311 (looking-at whitespace-empty-at-bob-regexp))
2312 (match-end 0))))
2313 (ostart (overlay-start whitespace-point--used))) 2297 (ostart (overlay-start whitespace-point--used)))
2314 (cond 2298 (cond
2315 ((not refontify) 2299 ((not refontify)
@@ -2363,6 +2347,77 @@ to `indent-tabs-mode' and `tab-width'."
2363 (when whitespace-mode 2347 (when whitespace-mode
2364 (font-lock-flush))))) 2348 (font-lock-flush)))))
2365 2349
2350(defun whitespace--update-bob-eob (&optional beg end &rest _)
2351 "Update `whitespace-bob-marker' and `whitespace-eob-marker'.
2352Also apply `font-lock-multiline' text property. If BEG and END
2353are non-nil, assume that only characters in that range have
2354changed since the last call to this function (for optimization
2355purposes)."
2356 (when (memq 'empty whitespace-active-style)
2357 ;; When a line is changed, `font-lock-mode' normally limits
2358 ;; re-processing to only the changed line. That behavior is
2359 ;; problematic for highlighting `empty' lines because adding or
2360 ;; deleting a character might affect lines before or after the
2361 ;; change. To address this, all `empty' lines are marked with a
2362 ;; non-nil `font-lock-multiline' text property. This forces
2363 ;; `font-lock-mode' to re-process all of the lines whenever
2364 ;; there's an edit within any one of them.
2365 ;;
2366 ;; The text property must be set on `empty' lines twice per
2367 ;; relevant change:
2368 ;;
2369 ;; 1. Before the change. This is necessary to ensure that
2370 ;; previously highlighted lines become un-highlighted if
2371 ;; necessary. The text property must be added after the
2372 ;; previous `font-lock-mode' run (the run in reaction to the
2373 ;; previous change) because `font-lock-mode' clears the text
2374 ;; property when it runs.
2375 ;;
2376 ;; 2. After the change, but before `font-lock-mode' reacts to
2377 ;; the change. This is necessary to ensure that new `empty'
2378 ;; lines become highlighted.
2379 ;;
2380 ;; This hook function is responsible for #2, while the
2381 ;; `whitespace--empty-at-bob-matcher' and
2382 ;; `whitespace--empty-at-eob-matcher' functions are responsible
2383 ;; for #1. (Those functions run after `font-lock-mode' clears the
2384 ;; text property and before the next change.)
2385 (save-excursion
2386 (save-restriction
2387 (widen)
2388 (when (or (null beg)
2389 (<= beg (save-excursion
2390 (goto-char whitespace-bob-marker)
2391 ;; Any change in the first non-`empty'
2392 ;; line, even if it's not the first
2393 ;; character in the line, can potentially
2394 ;; cause subsequent lines to become
2395 ;; classified as `empty' (e.g., delete the
2396 ;; "x" from " x").
2397 (forward-line 1)
2398 (point))))
2399 (goto-char 1)
2400 (set-marker whitespace-bob-marker (point))
2401 (save-match-data
2402 (when (looking-at whitespace-empty-at-bob-regexp)
2403 (set-marker whitespace-bob-marker (match-end 1))
2404 (put-text-property (match-beginning 1) (match-end 1)
2405 'font-lock-multiline t))))
2406 (when (or (null end)
2407 (>= end (save-excursion
2408 (goto-char whitespace-eob-marker)
2409 ;; See above comment for the BoB case.
2410 (forward-line -1)
2411 (point))))
2412 (goto-char (1+ (buffer-size)))
2413 (set-marker whitespace-eob-marker (point))
2414 (save-match-data
2415 (when (whitespace--looking-back
2416 whitespace-empty-at-eob-regexp)
2417 (set-marker whitespace-eob-marker (match-beginning 1))
2418 (put-text-property (match-beginning 1) (match-end 1)
2419 'font-lock-multiline t))))))))
2420
2366 2421
2367;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2422;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2368;;;; Hacked from visws.el (Miles Bader <miles@gnu.org>) 2423;;;; Hacked from visws.el (Miles Bader <miles@gnu.org>)
diff --git a/test/lisp/whitespace-tests.el b/test/lisp/whitespace-tests.el
index 2a59bfe9d80..792e157ec08 100644
--- a/test/lisp/whitespace-tests.el
+++ b/test/lisp/whitespace-tests.el
@@ -20,8 +20,35 @@
20;;; Code: 20;;; Code:
21 21
22(require 'ert) 22(require 'ert)
23(require 'ert-x)
24(require 'faceup)
23(require 'whitespace) 25(require 'whitespace)
24 26
27(defmacro whitespace-tests--with-test-buffer (style &rest body)
28 "Run BODY in a buffer with `whitespace-mode' style STYLE.
29The buffer is displayed in `selected-window', and
30`noninteractive' is set to nil even in batch mode."
31 (declare (debug ((style form) def-body))
32 (indent 1))
33 `(ert-with-test-buffer-selected ()
34 ;; In case global-*-mode is enabled.
35 (whitespace-mode -1)
36 (font-lock-mode -1)
37 (let ((noninteractive nil)
38 (whitespace-style ,style))
39 (font-lock-mode 1)
40 (whitespace-mode 1)
41 ,@body)))
42
43(defun whitespace-tests--faceup (&rest lines)
44 "Convenience wrapper around `faceup-test-font-lock-buffer'.
45Returns non-nil if the concatenated LINES match the current
46buffer's content."
47 (faceup-test-font-lock-buffer nil (apply #'concat lines)))
48(let ((x (get 'faceup-test-font-lock-buffer 'ert-explainer)))
49 (put 'whitespace-tests--faceup 'ert-explainer
50 (lambda (&rest lines) (funcall x nil (apply #'concat lines)))))
51
25(defun whitespace-tests--cleanup-string (string) 52(defun whitespace-tests--cleanup-string (string)
26 (with-temp-buffer 53 (with-temp-buffer
27 (insert string) 54 (insert string)
@@ -80,6 +107,209 @@
80 (whitespace-turn-off) 107 (whitespace-turn-off)
81 buffer-display-table)))))) 108 buffer-display-table))))))
82 109
110(ert-deftest whitespace-tests--empty-bob ()
111 (whitespace-tests--with-test-buffer '(face empty)
112 (electric-indent-mode -1)
113
114 ;; Insert some empty lines. None of the lines should be
115 ;; highlighted even though point is on the last line because the
116 ;; entire buffer is empty lines.
117 (execute-kbd-macro (kbd "SPC RET C-q TAB RET RET SPC"))
118 (should (equal (buffer-string) " \n\t\n\n "))
119 (should (equal (line-number-at-pos) 4))
120 (should (whitespace-tests--faceup " \n"
121 "\t\n"
122 "\n"
123 " "))
124
125 ;; Adding content on the last line (and keeping point there)
126 ;; should cause the previous lines to be highlighted. Note that
127 ;; the `whitespace-empty' face applies to the newline just before
128 ;; the last line, which has the desired property of extending the
129 ;; highlight the full width of the window.
130 (execute-kbd-macro (kbd "x"))
131 (should (equal (buffer-string) " \n\t\n\n x"))
132 (should (equal (line-number-at-pos) 4))
133 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
134 "\t\n"
135 "\n"
136 "» x"))
137
138 ;; Lines should become un-highlighted as point moves up into the
139 ;; empty lines.
140 (execute-kbd-macro (kbd "<up>"))
141 (should (equal (line-number-at-pos) 3))
142 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
143 "\t\n"
144 "»\n"
145 " x"))
146 (execute-kbd-macro (kbd "<up>"))
147 (should (equal (line-number-at-pos) 2))
148 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
149 "»\t\n"
150 "\n"
151 " x"))
152 (execute-kbd-macro (kbd "<up> <home>"))
153 (should (equal (point) 1))
154 (should (whitespace-tests--faceup " \n"
155 "\t\n"
156 "\n"
157 " x"))
158
159 ;; Line 1 should be un-highlighted when point is in line 1 even if
160 ;; point is not bobp.
161 (execute-kbd-macro (kbd "<right>"))
162 (should (equal (line-number-at-pos) 1))
163 (should (> (point) 1))
164 (should (whitespace-tests--faceup " \n"
165 "\t\n"
166 "\n"
167 " x"))
168
169 ;; Make sure lines become re-highlighted as point moves down.
170 (execute-kbd-macro (kbd "<down>"))
171 (should (equal (line-number-at-pos) 2))
172 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
173 "»\t\n"
174 "\n"
175 " x"))
176 (execute-kbd-macro (kbd "<down>"))
177 (should (equal (line-number-at-pos) 3))
178 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
179 "\t\n"
180 "»\n"
181 " x"))
182 (execute-kbd-macro (kbd "<down>"))
183 (should (equal (line-number-at-pos) 4))
184 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
185 "\t\n"
186 "\n"
187 "» x"))
188
189 ;; Inserting content on line 2 should un-highlight lines 2 and 3.
190 (execute-kbd-macro (kbd "<up> <up> <end>"))
191 (should (equal (line-number-at-pos) 2))
192 (should (equal (- (point) (line-beginning-position)) 1))
193 (execute-kbd-macro (kbd "y <down> <down>"))
194 (should (equal (line-number-at-pos) 4))
195 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
196 "»\ty\n"
197 "\n"
198 " x"))
199
200 ;; Removing the content on line 2 should re-highlight lines 2 and
201 ;; 3.
202 (execute-kbd-macro (kbd "<up> <up> <end>"))
203 (should (equal (line-number-at-pos) 2))
204 (should (equal (- (point) (line-beginning-position)) 2))
205 (execute-kbd-macro (kbd "DEL <down> <down>"))
206 (should (equal (line-number-at-pos) 4))
207 (should (whitespace-tests--faceup "«:whitespace-empty: \n"
208 "\t\n"
209 "\n"
210 "» x"))))
211
212(ert-deftest whitespace-tests--empty-eob ()
213 (whitespace-tests--with-test-buffer '(face empty)
214 (electric-indent-mode -1)
215
216 ;; Insert some empty lines. None of the lines should be
217 ;; highlighted even though point is on line 1 because the entire
218 ;; buffer is empty lines.
219 (execute-kbd-macro (kbd "RET RET C-q TAB RET SPC C-<home>"))
220 (should (equal (buffer-string) "\n\n\t\n "))
221 (should (equal (line-number-at-pos) 1))
222 (should (whitespace-tests--faceup "\n"
223 "\n"
224 "\t\n"
225 " "))
226
227 ;; Adding content on the first line (and keeping point there)
228 ;; should cause the subsequent lines to be highlighted.
229 (execute-kbd-macro (kbd "x"))
230 (should (equal (buffer-string) "x\n\n\t\n "))
231 (should (equal (line-number-at-pos) 1))
232 (should (whitespace-tests--faceup "x\n"
233 "«:whitespace-empty:\n"
234 "\t\n"
235 " »"))
236
237 ;; Lines should become un-highlighted as point moves down into the
238 ;; empty lines.
239 (execute-kbd-macro (kbd "<down>"))
240 (should (equal (line-number-at-pos) 2))
241 (should (whitespace-tests--faceup "x\n"
242 "\n"
243 "«:whitespace-empty:\t\n"
244 " »"))
245 (execute-kbd-macro (kbd "<down>"))
246 (should (equal (line-number-at-pos) 3))
247 (should (whitespace-tests--faceup "x\n"
248 "\n"
249 "\t\n"
250 "«:whitespace-empty: »"))
251 (execute-kbd-macro (kbd "C-<end>"))
252 (should (equal (line-number-at-pos) 4))
253 (should (eobp))
254 (should (equal (- (point) (line-beginning-position)) 1))
255 (should (whitespace-tests--faceup "x\n"
256 "\n"
257 "\t\n"
258 " "))
259
260 ;; The last line should be un-highlighted when point is in that
261 ;; line even if point is not eobp.
262 (execute-kbd-macro (kbd "<left>"))
263 (should (equal (line-number-at-pos) 4))
264 (should (not (eobp)))
265 (should (whitespace-tests--faceup "x\n"
266 "\n"
267 "\t\n"
268 " "))
269
270 ;; Make sure lines become re-highlighted as point moves up.
271 (execute-kbd-macro (kbd "<up>"))
272 (should (equal (line-number-at-pos) 3))
273 (should (whitespace-tests--faceup "x\n"
274 "\n"
275 "\t\n"
276 "«:whitespace-empty: »"))
277 (execute-kbd-macro (kbd "<up>"))
278 (should (equal (line-number-at-pos) 2))
279 (should (whitespace-tests--faceup "x\n"
280 "\n"
281 "«:whitespace-empty:\t\n"
282 " »"))
283 (execute-kbd-macro (kbd "<up>"))
284 (should (equal (line-number-at-pos) 1))
285 (should (whitespace-tests--faceup "x\n"
286 "«:whitespace-empty:\n"
287 "\t\n"
288 " »"))
289
290 ;; Inserting content on line 3 should un-highlight lines 2 and 3.
291 (execute-kbd-macro (kbd "<down> <down> <home>"))
292 (should (equal (line-number-at-pos) 3))
293 (should (equal (- (point) (line-beginning-position)) 0))
294 (execute-kbd-macro (kbd "y <up> <up>"))
295 (should (equal (line-number-at-pos) 1))
296 (should (whitespace-tests--faceup "x\n"
297 "\n"
298 "y\t\n"
299 "«:whitespace-empty: »"))
300
301 ;; Removing the content on line 3 should re-highlight lines 2 and
302 ;; 3.
303 (execute-kbd-macro (kbd "<down> <down> <home>"))
304 (should (equal (line-number-at-pos) 3))
305 (should (equal (- (point) (line-beginning-position)) 0))
306 (execute-kbd-macro (kbd "<deletechar> <up> <up>"))
307 (should (equal (line-number-at-pos) 1))
308 (should (whitespace-tests--faceup "x\n"
309 "«:whitespace-empty:\n"
310 "\t\n"
311 " »"))))
312
83(provide 'whitespace-tests) 313(provide 'whitespace-tests)
84 314
85;;; whitespace-tests.el ends here 315;;; whitespace-tests.el ends here