aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/emacs/maintaining.texi9
-rw-r--r--doc/misc/tramp.texi2
-rw-r--r--etc/NEWS10
-rw-r--r--lisp/dired.el2
-rw-r--r--lisp/emacs-lisp/map.el208
-rw-r--r--lisp/isearch.el25
-rw-r--r--lisp/progmodes/flymake.el21
-rw-r--r--lisp/progmodes/ruby-mode.el4
-rw-r--r--lisp/vc/vc-git.el7
-rw-r--r--lisp/vc/vc.el63
-rw-r--r--src/fileio.c28
-rw-r--r--src/textprop.c87
-rw-r--r--src/xdisp.c2
-rw-r--r--test/Makefile.in8
-rw-r--r--test/lisp/eshell/em-ls-tests.el14
-rw-r--r--test/lisp/net/secrets-tests.el7
-rw-r--r--test/lisp/progmodes/ruby-mode-tests.el90
-rw-r--r--test/src/fileio-tests.el4
18 files changed, 381 insertions, 210 deletions
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 4527c23d9e7..6a848f9d148 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -831,6 +831,14 @@ working tree containing the current VC fileset). If you invoke this
831command from a Dired buffer, it applies to the working tree containing 831command from a Dired buffer, it applies to the working tree containing
832the directory. 832the directory.
833 833
834@findex vc-root-version-diff
835@kindex C-u C-x v D
836 To compare two arbitrary revisions of the whole trees, call
837@code{vc-root-diff} with a prefix argument: @kbd{C-u C-x v D}. This
838prompts for two revision IDs (@pxref{VCS Concepts}), and displays a
839diff between those versions of the entire version-controlled directory
840trees (RCS, SCCS, CVS, and SRC do not support this feature).
841
834@vindex vc-diff-switches 842@vindex vc-diff-switches
835 You can customize the @command{diff} options that @kbd{C-x v =} and 843 You can customize the @command{diff} options that @kbd{C-x v =} and
836@kbd{C-x v D} use for generating diffs. The options used are taken 844@kbd{C-x v D} use for generating diffs. The options used are taken
@@ -963,6 +971,7 @@ and the maximum number of revisions to display.
963Directory Mode}) or a Dired buffer (@pxref{Dired}), it applies to the 971Directory Mode}) or a Dired buffer (@pxref{Dired}), it applies to the
964file listed on the current line. 972file listed on the current line.
965 973
974@kindex C-x v L
966@findex vc-print-root-log 975@findex vc-print-root-log
967@findex log-view-toggle-entry-display 976@findex log-view-toggle-entry-display
968 @kbd{C-x v L} (@code{vc-print-root-log}) displays a 977 @kbd{C-x v L} (@code{vc-print-root-log}) displays a
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index 5c5402133a7..a4946f0b8de 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -2741,6 +2741,8 @@ proxy @samp{bird@@bastion} to a remote file on @samp{you@@remotehost}:
2741 2741
2742Each involved method must be an inline method (@pxref{Inline methods}). 2742Each involved method must be an inline method (@pxref{Inline methods}).
2743 2743
2744Proxies can take patterns @code{%h} or @code{%u}.
2745
2744@value{tramp} adds the ad-hoc definitions on the fly to 2746@value{tramp} adds the ad-hoc definitions on the fly to
2745@code{tramp-default-proxies-alist} and is available for re-use 2747@code{tramp-default-proxies-alist} and is available for re-use
2746during that Emacs session. Subsequent @value{tramp} connections to 2748during that Emacs session. Subsequent @value{tramp} connections to
diff --git a/etc/NEWS b/etc/NEWS
index 6ae994d5942..0624c5690bc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -304,6 +304,12 @@ the node "(emacs) Directory Variables" of the user manual.
304 304
305* Changes in Specialized Modes and Packages in Emacs 27.1 305* Changes in Specialized Modes and Packages in Emacs 27.1
306 306
307** map.el
308*** Now defined via generic functions that can be extended via cl-defmethod.
309*** Deprecate the 'map-put' macro in favor of a new 'map-put!' function.
310*** map-contains-key now returns a boolean rather than the key.
311*** Deprecate the 'testfn' args of 'map-elt' and 'map-contains-key'.
312
307--- 313---
308** Follow mode 314** Follow mode
309In the current follow group of windows, "ghost" cursors are no longer 315In the current follow group of windows, "ghost" cursors are no longer
@@ -398,6 +404,10 @@ with conflicts existed in earlier versions of Emacs, but incorrectly
398never detected a conflict due to invalid assumptions about cached 404never detected a conflict due to invalid assumptions about cached
399values. 405values.
400 406
407+++
408*** 'C-u C-x v D' ('vc-root-version-diff') prompts for two revisions
409and compares their entire trees.
410
401** Diff mode 411** Diff mode
402*** Hunks are now automatically refined by default. 412*** Hunks are now automatically refined by default.
403To disable it, set the new defcustom 'diff-font-lock-refine' to nil. 413To disable it, set the new defcustom 'diff-font-lock-refine' to nil.
diff --git a/lisp/dired.el b/lisp/dired.el
index e5dc8623a49..72725dc8a09 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -1530,7 +1530,7 @@ change; the point does."
1530 ;; Sanity check of the point marker. 1530 ;; Sanity check of the point marker.
1531 (when (and (markerp point) 1531 (when (and (markerp point)
1532 (eq (marker-buffer point) buffer)) 1532 (eq (marker-buffer point) buffer))
1533 (unless (and (nth 0 prev) 1533 (unless (and (nth 1 prev)
1534 (dired-goto-file (nth 1 prev))) 1534 (dired-goto-file (nth 1 prev)))
1535 (goto-char (point-min)) 1535 (goto-char (point-min))
1536 (forward-line (1- (nth 2 prev)))) 1536 (forward-line (1- (nth 2 prev))))
diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el
index 987521d9d85..35759db6270 100644
--- a/lisp/emacs-lisp/map.el
+++ b/lisp/emacs-lisp/map.el
@@ -92,17 +92,17 @@ Returns the result of evaluating the form associated with MAP-VAR's type."
92 `(cond ((listp ,map-var) ,(plist-get args :list)) 92 `(cond ((listp ,map-var) ,(plist-get args :list))
93 ((hash-table-p ,map-var) ,(plist-get args :hash-table)) 93 ((hash-table-p ,map-var) ,(plist-get args :hash-table))
94 ((arrayp ,map-var) ,(plist-get args :array)) 94 ((arrayp ,map-var) ,(plist-get args :array))
95 (t (error "Unsupported map: %s" ,map-var))))) 95 (t (error "Unsupported map type `%S': %S"
96 (type-of ,map-var) ,map-var)))))
96 97
97(defun map-elt (map key &optional default testfn) 98(cl-defgeneric map-elt (map key &optional default testfn)
98 "Lookup KEY in MAP and return its associated value. 99 "Lookup KEY in MAP and return its associated value.
99If KEY is not found, return DEFAULT which defaults to nil. 100If KEY is not found, return DEFAULT which defaults to nil.
100 101
101If MAP is a list, `eql' is used to lookup KEY. Optional argument 102TESTFN is deprecated. Its default depends on the MAP argument.
102TESTFN, if non-nil, means use its function definition instead of 103If MAP is a list, the default is `eql' to lookup KEY.
103`eql'.
104 104
105MAP can be a list, hash-table or array." 105In the base definition, MAP can be an alist, hash-table, or array."
106 (declare 106 (declare
107 (gv-expander 107 (gv-expander
108 (lambda (do) 108 (lambda (do)
@@ -118,7 +118,7 @@ MAP can be a list, hash-table or array."
118 ,default nil ,testfn) 118 ,default nil ,testfn)
119 do) 119 do)
120 ,(funcall do `(map-elt ,mgetter ,key ,default) 120 ,(funcall do `(map-elt ,mgetter ,key ,default)
121 (lambda (v) `(map--put ,mgetter ,key ,v))))))))) 121 (lambda (v) `(map-put! ,mgetter ,key ,v)))))))))
122 (map--dispatch map 122 (map--dispatch map
123 :list (alist-get key map default nil testfn) 123 :list (alist-get key map default nil testfn)
124 :hash-table (gethash key map default) 124 :hash-table (gethash key map default)
@@ -133,9 +133,10 @@ with VALUE.
133When MAP is a list, test equality with TESTFN if non-nil, otherwise use `eql'. 133When MAP is a list, test equality with TESTFN if non-nil, otherwise use `eql'.
134 134
135MAP can be a list, hash-table or array." 135MAP can be a list, hash-table or array."
136 (declare (obsolete "use map-put! or (setf (map-elt ...) ...) instead" "27.1"))
136 `(setf (map-elt ,map ,key nil ,testfn) ,value)) 137 `(setf (map-elt ,map ,key nil ,testfn) ,value))
137 138
138(defun map-delete (map key) 139(cl-defgeneric map-delete (map key)
139 "Delete KEY from MAP and return MAP. 140 "Delete KEY from MAP and return MAP.
140No error is signaled if KEY is not a key of MAP. If MAP is an 141No error is signaled if KEY is not a key of MAP. If MAP is an
141array, store nil at the index KEY. 142array, store nil at the index KEY.
@@ -160,120 +161,121 @@ Map can be a nested map composed of alists, hash-tables and arrays."
160 map) 161 map)
161 default)) 162 default))
162 163
163(defun map-keys (map) 164(cl-defgeneric map-keys (map)
164 "Return the list of keys in MAP. 165 "Return the list of keys in MAP."
165
166MAP can be a list, hash-table or array."
167 (map-apply (lambda (key _) key) map)) 166 (map-apply (lambda (key _) key) map))
168 167
169(defun map-values (map) 168(cl-defgeneric map-values (map)
170 "Return the list of values in MAP. 169 "Return the list of values in MAP."
171
172MAP can be a list, hash-table or array."
173 (map-apply (lambda (_ value) value) map)) 170 (map-apply (lambda (_ value) value) map))
174 171
175(defun map-pairs (map) 172(cl-defgeneric map-pairs (map)
176 "Return the elements of MAP as key/value association lists. 173 "Return the elements of MAP as key/value association lists."
177
178MAP can be a list, hash-table or array."
179 (map-apply #'cons map)) 174 (map-apply #'cons map))
180 175
181(defun map-length (map) 176(cl-defgeneric map-length (map)
182 "Return the length of MAP. 177 ;; FIXME: Should we rename this to `map-size'?
183 178 "Return the number of elements in the map."
184MAP can be a list, hash-table or array." 179 (cond
185 (length (map-keys map))) 180 ((hash-table-p map) (hash-table-count map))
181 ((or (listp map) (arrayp map)) (length map))
182 (t (length (map-keys map)))))
186 183
187(defun map-copy (map) 184(cl-defgeneric map-copy (map)
188 "Return a copy of MAP. 185 "Return a copy of MAP."
189
190MAP can be a list, hash-table or array."
191 (map--dispatch map 186 (map--dispatch map
192 :list (seq-copy map) 187 :list (seq-copy map)
193 :hash-table (copy-hash-table map) 188 :hash-table (copy-hash-table map)
194 :array (seq-copy map))) 189 :array (seq-copy map)))
195 190
196(defun map-apply (function map) 191(cl-defgeneric map-apply (function map)
197 "Apply FUNCTION to each element of MAP and return the result as a list. 192 "Apply FUNCTION to each element of MAP and return the result as a list.
198FUNCTION is called with two arguments, the key and the value. 193FUNCTION is called with two arguments, the key and the value.
194The default implementation delegates to `map-do'."
195 (let ((res '()))
196 (map-do (lambda (k v) (push (funcall function k v) res)) map)
197 (nreverse res)))
199 198
200MAP can be a list, hash-table or array." 199(cl-defgeneric map-do (function map)
201 (funcall (map--dispatch map
202 :list #'map--apply-alist
203 :hash-table #'map--apply-hash-table
204 :array #'map--apply-array)
205 function
206 map))
207
208(defun map-do (function map)
209 "Apply FUNCTION to each element of MAP and return nil. 200 "Apply FUNCTION to each element of MAP and return nil.
210FUNCTION is called with two arguments, the key and the value." 201FUNCTION is called with two arguments, the key and the value.")
211 (funcall (map--dispatch map
212 :list #'map--do-alist
213 :hash-table #'maphash
214 :array #'map--do-array)
215 function
216 map))
217 202
218(defun map-keys-apply (function map) 203;; FIXME: I wish there was a way to avoid this η-redex!
219 "Return the result of applying FUNCTION to each key of MAP. 204(cl-defmethod map-do (function (map hash-table)) (maphash function map))
220 205
221MAP can be a list, hash-table or array." 206(cl-defgeneric map-keys-apply (function map)
207 "Return the result of applying FUNCTION to each key of MAP.
208The default implementation delegates to `map-apply'."
222 (map-apply (lambda (key _) 209 (map-apply (lambda (key _)
223 (funcall function key)) 210 (funcall function key))
224 map)) 211 map))
225 212
226(defun map-values-apply (function map) 213(cl-defgeneric map-values-apply (function map)
227 "Return the result of applying FUNCTION to each value of MAP. 214 "Return the result of applying FUNCTION to each value of MAP.
228 215The default implementation delegates to `map-apply'."
229MAP can be a list, hash-table or array."
230 (map-apply (lambda (_ val) 216 (map-apply (lambda (_ val)
231 (funcall function val)) 217 (funcall function val))
232 map)) 218 map))
233 219
234(defun map-filter (pred map) 220(cl-defgeneric map-filter (pred map)
235 "Return an alist of key/val pairs for which (PRED key val) is non-nil in MAP. 221 "Return an alist of key/val pairs for which (PRED key val) is non-nil in MAP.
236 222The default implementation delegates to `map-apply'."
237MAP can be a list, hash-table or array."
238 (delq nil (map-apply (lambda (key val) 223 (delq nil (map-apply (lambda (key val)
239 (if (funcall pred key val) 224 (if (funcall pred key val)
240 (cons key val) 225 (cons key val)
241 nil)) 226 nil))
242 map))) 227 map)))
243 228
244(defun map-remove (pred map) 229(cl-defgeneric map-remove (pred map)
245 "Return an alist of the key/val pairs for which (PRED key val) is nil in MAP. 230 "Return an alist of the key/val pairs for which (PRED key val) is nil in MAP.
246 231The default implementation delegates to `map-filter'."
247MAP can be a list, hash-table or array."
248 (map-filter (lambda (key val) (not (funcall pred key val))) 232 (map-filter (lambda (key val) (not (funcall pred key val)))
249 map)) 233 map))
250 234
251(defun mapp (map) 235(cl-defgeneric mapp (map)
252 "Return non-nil if MAP is a map (list, hash-table or array)." 236 "Return non-nil if MAP is a map (alist, hash-table, array, ...)."
253 (or (listp map) 237 (or (listp map)
254 (hash-table-p map) 238 (hash-table-p map)
255 (arrayp map))) 239 (arrayp map)))
256 240
257(defun map-empty-p (map) 241(cl-defgeneric map-empty-p (map)
258 "Return non-nil if MAP is empty. 242 "Return non-nil if MAP is empty.
243The default implementation delegates to `map-length'."
244 (zerop (map-length map)))
245
246(cl-defgeneric map-contains-key (map key &optional testfn)
247 ;; FIXME: The test function to use generally depends on the map object,
248 ;; so specifying `testfn' here is problematic: e.g. for hash-tables
249 ;; we shouldn't use `gethash' unless `testfn' is the same as the map's own
250 ;; test function!
251 "Return non-nil If and only if MAP contains KEY.
252TESTFN is deprecated. Its default depends on MAP.
253The default implementation delegates to `map-do'."
254 (unless testfn (setq testfn #'equal))
255 (catch 'map--catch
256 (map-do (lambda (k _v)
257 (if (funcall testfn key k) (throw 'map--catch t)))
258 map)
259 nil))
259 260
260MAP can be a list, hash-table or array." 261(cl-defmethod map-contains-key ((map list) key &optional testfn)
261 (map--dispatch map 262 (alist-get key map nil nil (or testfn #'equal)))
262 :list (null map)
263 :array (seq-empty-p map)
264 :hash-table (zerop (hash-table-count map))))
265
266(defun map-contains-key (map key &optional testfn)
267 "If MAP contain KEY return KEY, nil otherwise.
268Equality is defined by TESTFN if non-nil or by `equal' if nil.
269 263
270MAP can be a list, hash-table or array." 264(cl-defmethod map-contains-key ((map array) key &optional _testfn)
271 (seq-contains (map-keys map) key testfn)) 265 (and (integerp key)
266 (>= key 0)
267 (< key (length map))))
272 268
273(defun map-some (pred map) 269(cl-defmethod map-contains-key ((map hash-table) key &optional _testfn)
274 "Return a non-nil if (PRED key val) is non-nil for any key/value pair in MAP. 270 (let ((v '(nil)))
271 (not (eq v (gethash key map v)))))
275 272
276MAP can be a list, hash-table or array." 273(cl-defgeneric map-some (pred map)
274 "Return the first non-nil (PRED key val) in MAP.
275The default implementation delegates to `map-apply'."
276 ;; FIXME: Not sure if there's much benefit to defining it as defgeneric,
277 ;; since as defined, I can't think of a map-type where we could provide an
278 ;; algorithmically more efficient algorithm than the default.
277 (catch 'map--break 279 (catch 'map--break
278 (map-apply (lambda (key value) 280 (map-apply (lambda (key value)
279 (let ((result (funcall pred key value))) 281 (let ((result (funcall pred key value)))
@@ -282,10 +284,12 @@ MAP can be a list, hash-table or array."
282 map) 284 map)
283 nil)) 285 nil))
284 286
285(defun map-every-p (pred map) 287(cl-defgeneric map-every-p (pred map)
286 "Return non-nil if (PRED key val) is non-nil for all elements of the map MAP. 288 "Return non-nil if (PRED key val) is non-nil for all elements of the map MAP.
287 289The default implementation delegates to `map-apply'."
288MAP can be a list, hash-table or array." 290 ;; FIXME: Not sure if there's much benefit to defining it as defgeneric,
291 ;; since as defined, I can't think of a map-type where we could provide an
292 ;; algorithmically more efficient algorithm than the default.
289 (catch 'map--break 293 (catch 'map--break
290 (map-apply (lambda (key value) 294 (map-apply (lambda (key value)
291 (or (funcall pred key value) 295 (or (funcall pred key value)
@@ -294,9 +298,7 @@ MAP can be a list, hash-table or array."
294 t)) 298 t))
295 299
296(defun map-merge (type &rest maps) 300(defun map-merge (type &rest maps)
297 "Merge into a map of type TYPE all the key/value pairs in MAPS. 301 "Merge into a map of type TYPE all the key/value pairs in MAPS."
298
299MAP can be a list, hash-table or array."
300 (let ((result (map-into (pop maps) type))) 302 (let ((result (map-into (pop maps) type)))
301 (while maps 303 (while maps
302 ;; FIXME: When `type' is `list', we get an O(N^2) behavior. 304 ;; FIXME: When `type' is `list', we get an O(N^2) behavior.
@@ -310,7 +312,7 @@ MAP can be a list, hash-table or array."
310 312
311(defun map-merge-with (type function &rest maps) 313(defun map-merge-with (type function &rest maps)
312 "Merge into a map of type TYPE all the key/value pairs in MAPS. 314 "Merge into a map of type TYPE all the key/value pairs in MAPS.
313When two maps contain the same key, call FUNCTION on the two 315When two maps contain the same key (`eql'), call FUNCTION on the two
314values and use the value returned by it. 316values and use the value returned by it.
315MAP can be a list, hash-table or array." 317MAP can be a list, hash-table or array."
316 (let ((result (map-into (pop maps) type)) 318 (let ((result (map-into (pop maps) type))
@@ -318,24 +320,22 @@ MAP can be a list, hash-table or array."
318 (while maps 320 (while maps
319 (map-apply (lambda (key value) 321 (map-apply (lambda (key value)
320 (cl-callf (lambda (old) 322 (cl-callf (lambda (old)
321 (if (eq old not-found) 323 (if (eql old not-found)
322 value 324 value
323 (funcall function old value))) 325 (funcall function old value)))
324 (map-elt result key not-found))) 326 (map-elt result key not-found)))
325 (pop maps))) 327 (pop maps)))
326 result)) 328 result))
327 329
328(defun map-into (map type) 330(cl-defgeneric map-into (map type)
329 "Convert the map MAP into a map of type TYPE. 331 "Convert the map MAP into a map of type TYPE.")
332;; FIXME: I wish there was a way to avoid this η-redex!
333(cl-defmethod map-into (map (_type (eql list))) (map-pairs map))
330 334
331TYPE can be one of the following symbols: list or hash-table. 335(cl-defgeneric map-put! (map key v)
332MAP can be a list, hash-table or array." 336 "Associate KEY with VALUE in MAP and return VALUE.
333 (pcase type 337If KEY is already present in MAP, replace the associated value
334 ('list (map-pairs map)) 338with VALUE."
335 ('hash-table (map--into-hash-table map))
336 (_ (error "Not a map type name: %S" type))))
337
338(defun map--put (map key v)
339 (map--dispatch map 339 (map--dispatch map
340 :list (let ((p (assoc key map))) 340 :list (let ((p (assoc key map)))
341 (if p (setcdr p v) 341 (if p (setcdr p v)
@@ -343,24 +343,26 @@ MAP can be a list, hash-table or array."
343 :hash-table (puthash key v map) 343 :hash-table (puthash key v map)
344 :array (aset map key v))) 344 :array (aset map key v)))
345 345
346(defun map--apply-alist (function map) 346;; There shouldn't be old source code referring to `map--put', yet we do
347 "Private function used to apply FUNCTION over MAP, MAP being an alist." 347;; need to keep it for backward compatibility with .elc files where the
348;; expansion of `setf' may call this function.
349(define-obsolete-function-alias 'map--put #'map-put! "27.1")
350
351(cl-defmethod map-apply (function (map list))
348 (seq-map (lambda (pair) 352 (seq-map (lambda (pair)
349 (funcall function 353 (funcall function
350 (car pair) 354 (car pair)
351 (cdr pair))) 355 (cdr pair)))
352 map)) 356 map))
353 357
354(defun map--apply-hash-table (function map) 358(cl-defmethod map-apply (function (map hash-table))
355 "Private function used to apply FUNCTION over MAP, MAP being a hash-table."
356 (let (result) 359 (let (result)
357 (maphash (lambda (key value) 360 (maphash (lambda (key value)
358 (push (funcall function key value) result)) 361 (push (funcall function key value) result))
359 map) 362 map)
360 (nreverse result))) 363 (nreverse result)))
361 364
362(defun map--apply-array (function map) 365(cl-defmethod map-apply (function (map array))
363 "Private function used to apply FUNCTION over MAP, MAP being an array."
364 (let ((index 0)) 366 (let ((index 0))
365 (seq-map (lambda (elt) 367 (seq-map (lambda (elt)
366 (prog1 368 (prog1
@@ -368,7 +370,7 @@ MAP can be a list, hash-table or array."
368 (setq index (1+ index)))) 370 (setq index (1+ index))))
369 map))) 371 map)))
370 372
371(defun map--do-alist (function alist) 373(cl-defmethod map-do (function (alist list))
372 "Private function used to iterate over ALIST using FUNCTION." 374 "Private function used to iterate over ALIST using FUNCTION."
373 (seq-do (lambda (pair) 375 (seq-do (lambda (pair)
374 (funcall function 376 (funcall function
@@ -376,14 +378,16 @@ MAP can be a list, hash-table or array."
376 (cdr pair))) 378 (cdr pair)))
377 alist)) 379 alist))
378 380
379(defun map--do-array (function array) 381(cl-defmethod map-do (function (array array))
380 "Private function used to iterate over ARRAY using FUNCTION." 382 "Private function used to iterate over ARRAY using FUNCTION."
381 (seq-do-indexed (lambda (elt index) 383 (seq-do-indexed (lambda (elt index)
382 (funcall function index elt)) 384 (funcall function index elt))
383 array)) 385 array))
384 386
385(defun map--into-hash-table (map) 387(cl-defmethod map-into (map (_type (eql hash-table)))
386 "Convert MAP into a hash-table." 388 "Convert MAP into a hash-table."
389 ;; FIXME: Just knowing we want a hash-table is insufficient, since that
390 ;; doesn't tell us the test function to use with it!
387 (let ((ht (make-hash-table :size (map-length map) 391 (let ((ht (make-hash-table :size (map-length map)
388 :test 'equal))) 392 :test 'equal)))
389 (map-apply (lambda (key value) 393 (map-apply (lambda (key value)
diff --git a/lisp/isearch.el b/lisp/isearch.el
index dcd119a517c..dd0973d4ea6 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -2811,10 +2811,10 @@ the bottom."
2811If `shift', extend the search string by motion commands while holding down 2811If `shift', extend the search string by motion commands while holding down
2812the shift key. The search string is extended by yanking text that 2812the shift key. The search string is extended by yanking text that
2813ends at the new position after moving point in the current buffer. 2813ends at the new position after moving point in the current buffer.
2814If t, extend the search string without the shift key pressed 2814If t, extend the search string without the shift key pressed.
2815by motion commands that have the `isearch-move' property on their 2815To enable motion commands, put the `isearch-move' property on their
2816symbols equal to `enabled', or for which the shift-translated command 2816symbols to `enabled', or to disable an automatically detected
2817is not disabled by the value `disabled' of property `isearch-move'." 2817shift-translated command, use the property value `disabled'."
2818 :type '(choice (const :tag "Motion keys exit Isearch" nil) 2818 :type '(choice (const :tag "Motion keys exit Isearch" nil)
2819 (const :tag "Motion keys extend the search string" t) 2819 (const :tag "Motion keys extend the search string" t)
2820 (const :tag "Shifted motion keys extend the search string" shift)) 2820 (const :tag "Shifted motion keys extend the search string" shift))
@@ -2864,14 +2864,15 @@ See more for options in `search-exit-option'."
2864 (read-event) 2864 (read-event)
2865 (setq this-command 'isearch-edit-string)) 2865 (setq this-command 'isearch-edit-string))
2866 ;; Don't terminate the search for motion commands. 2866 ;; Don't terminate the search for motion commands.
2867 ((or (and (eq isearch-yank-on-move t) 2867 ((and isearch-yank-on-move
2868 (symbolp this-command) 2868 (symbolp this-command)
2869 (or (eq (get this-command 'isearch-move) 'enabled) 2869 (not (eq (get this-command 'isearch-move) 'disabled))
2870 (and (not (eq (get this-command 'isearch-move) 'disabled)) 2870 (or (eq (get this-command 'isearch-move) 'enabled)
2871 (stringp (nth 1 (interactive-form this-command))) 2871 (and (eq isearch-yank-on-move t)
2872 (string-match-p "^^" (nth 1 (interactive-form this-command)))))) 2872 (stringp (nth 1 (interactive-form this-command)))
2873 (and (eq isearch-yank-on-move 'shift) 2873 (string-match-p "^^" (nth 1 (interactive-form this-command))))
2874 this-command-keys-shift-translated)) 2874 (and (eq isearch-yank-on-move 'shift)
2875 this-command-keys-shift-translated)))
2875 (setq this-command-keys-shift-translated nil) 2876 (setq this-command-keys-shift-translated nil)
2876 (setq isearch-pre-move-point (point))) 2877 (setq isearch-pre-move-point (point)))
2877 ;; Append control characters to the search string 2878 ;; Append control characters to the search string
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index ad8f50cd7a5..7b100da42b8 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -4,7 +4,7 @@
4 4
5;; Author: Pavel Kobyakov <pk_at_work@yahoo.com> 5;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
6;; Maintainer: João Távora <joaotavora@gmail.com> 6;; Maintainer: João Távora <joaotavora@gmail.com>
7;; Version: 1.0.2 7;; Version: 1.0.3
8;; Package-Requires: ((emacs "26.1")) 8;; Package-Requires: ((emacs "26.1"))
9;; Keywords: c languages tools 9;; Keywords: c languages tools
10 10
@@ -293,7 +293,7 @@ generated it."
293 293
294(cl-defstruct (flymake--diag 294(cl-defstruct (flymake--diag
295 (:constructor flymake--diag-make)) 295 (:constructor flymake--diag-make))
296 buffer beg end type text backend data overlay) 296 buffer beg end type text backend data overlay-properties overlay)
297 297
298;;;###autoload 298;;;###autoload
299(defun flymake-make-diagnostic (buffer 299(defun flymake-make-diagnostic (buffer
@@ -301,13 +301,20 @@ generated it."
301 end 301 end
302 type 302 type
303 text 303 text
304 &optional data) 304 &optional data
305 overlay-properties)
305 "Make a Flymake diagnostic for BUFFER's region from BEG to END. 306 "Make a Flymake diagnostic for BUFFER's region from BEG to END.
306TYPE is a key to symbol and TEXT is a description of the problem 307TYPE is a key to symbol and TEXT is a description of the problem
307detected in this region. DATA is any object that the caller 308detected in this region. DATA is any object that the caller
308wishes to attach to the created diagnostic for later retrieval." 309wishes to attach to the created diagnostic for later retrieval.
310
311OVERLAY-PROPERTIES is an an alist of properties attached to the
312created diagnostic, overriding the default properties and any
313properties of `flymake-overlay-control' of the diagnostic's
314type."
309 (flymake--diag-make :buffer buffer :beg beg :end end 315 (flymake--diag-make :buffer buffer :beg beg :end end
310 :type type :text text :data data)) 316 :type type :text text :data data
317 :overlay-properties overlay-properties))
311 318
312;;;###autoload 319;;;###autoload
313(defun flymake-diagnostics (&optional beg end) 320(defun flymake-diagnostics (&optional beg end)
@@ -600,7 +607,9 @@ associated `flymake-category' return DEFAULT."
600 ;; properties. 607 ;; properties.
601 (cl-loop 608 (cl-loop
602 for (ov-prop . value) in 609 for (ov-prop . value) in
603 (append (reverse ; ensure ealier props override later ones 610 (append (reverse
611 (flymake--diag-overlay-properties diagnostic))
612 (reverse ; ensure ealier props override later ones
604 (flymake--lookup-type-property type 'flymake-overlay-control)) 613 (flymake--lookup-type-property type 'flymake-overlay-control))
605 (alist-get type flymake-diagnostic-types-alist)) 614 (alist-get type flymake-diagnostic-types-alist))
606 do (overlay-put ov ov-prop value)) 615 do (overlay-put ov ov-prop value))
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 2f68f004e7b..d60899cf182 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -517,6 +517,9 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
517 ((ruby-smie--opening-pipe-p) "opening-|") 517 ((ruby-smie--opening-pipe-p) "opening-|")
518 ((ruby-smie--closing-pipe-p) "closing-|") 518 ((ruby-smie--closing-pipe-p) "closing-|")
519 (t tok))) 519 (t tok)))
520 ((string-match "\\`[^|]+|\\'" tok)
521 (forward-char -1)
522 (substring tok 0 -1))
520 ((and (equal tok "") (looking-at "\\\\\n")) 523 ((and (equal tok "") (looking-at "\\\\\n"))
521 (goto-char (match-end 0)) (ruby-smie--forward-token)) 524 (goto-char (match-end 0)) (ruby-smie--forward-token))
522 ((equal tok "do") 525 ((equal tok "do")
@@ -559,6 +562,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
559 ((ruby-smie--opening-pipe-p) "opening-|") 562 ((ruby-smie--opening-pipe-p) "opening-|")
560 ((ruby-smie--closing-pipe-p) "closing-|") 563 ((ruby-smie--closing-pipe-p) "closing-|")
561 (t tok))) 564 (t tok)))
565 ((string-match-p "\\`[^|]+|\\'" tok) "closing-|")
562 ((string-match-p "\\`|[*&]\\'" tok) 566 ((string-match-p "\\`|[*&]\\'" tok)
563 (forward-char 1) 567 (forward-char 1)
564 (substring tok 1)) 568 (substring tok 1))
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index f3174005307..aa6809f626e 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -757,6 +757,11 @@ the commit message."
757 (interactive) 757 (interactive)
758 (log-edit-toggle-header "Sign-Off" "yes")) 758 (log-edit-toggle-header "Sign-Off" "yes"))
759 759
760(defun vc-git-log-edit-toggle-no-verify ()
761 "Toggle whether to bypass the pre-commit and commit-msg hooks."
762 (interactive)
763 (log-edit-toggle-header "No-Verify" "yes"))
764
760(defun vc-git-log-edit-toggle-amend () 765(defun vc-git-log-edit-toggle-amend ()
761 "Toggle whether this will amend the previous commit. 766 "Toggle whether this will amend the previous commit.
762If toggling on, also insert its message into the buffer." 767If toggling on, also insert its message into the buffer."
@@ -782,6 +787,7 @@ If toggling on, also insert its message into the buffer."
782(defvar vc-git-log-edit-mode-map 787(defvar vc-git-log-edit-mode-map
783 (let ((map (make-sparse-keymap "Git-Log-Edit"))) 788 (let ((map (make-sparse-keymap "Git-Log-Edit")))
784 (define-key map "\C-c\C-s" 'vc-git-log-edit-toggle-signoff) 789 (define-key map "\C-c\C-s" 'vc-git-log-edit-toggle-signoff)
790 (define-key map "\C-c\C-n" 'vc-git-log-edit-toggle-no-verify)
785 (define-key map "\C-c\C-e" 'vc-git-log-edit-toggle-amend) 791 (define-key map "\C-c\C-e" 'vc-git-log-edit-toggle-amend)
786 map)) 792 map))
787 793
@@ -825,6 +831,7 @@ It is based on `log-edit-mode', and has Git-specific extensions.")
825 `(("Author" . "--author") 831 `(("Author" . "--author")
826 ("Date" . "--date") 832 ("Date" . "--date")
827 ("Amend" . ,(boolean-arg-fn "--amend")) 833 ("Amend" . ,(boolean-arg-fn "--amend"))
834 ("No-Verify" . ,(boolean-arg-fn "--no-verify"))
828 ("Sign-Off" . ,(boolean-arg-fn "--signoff"))) 835 ("Sign-Off" . ,(boolean-arg-fn "--signoff")))
829 comment))) 836 comment)))
830 (when msg-file 837 (when msg-file
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index dbbc3e20380..48b7c98dfac 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -1817,7 +1817,7 @@ Return t if the buffer had changes, nil otherwise."
1817 1817
1818;;;###autoload 1818;;;###autoload
1819(defun vc-version-diff (_files rev1 rev2) 1819(defun vc-version-diff (_files rev1 rev2)
1820 "Report diffs between revisions of the fileset in the repository history." 1820 "Report diffs between REV1 and REV2 revisions of the fileset."
1821 (interactive (vc-diff-build-argument-list-internal)) 1821 (interactive (vc-diff-build-argument-list-internal))
1822 ;; All that was just so we could do argument completion! 1822 ;; All that was just so we could do argument completion!
1823 (when (and (not rev1) rev2) 1823 (when (and (not rev1) rev2)
@@ -1828,6 +1828,28 @@ Return t if the buffer had changes, nil otherwise."
1828 (called-interactively-p 'interactive))) 1828 (called-interactively-p 'interactive)))
1829 1829
1830;;;###autoload 1830;;;###autoload
1831(defun vc-root-version-diff (_files rev1 rev2)
1832 "Report diffs between REV1 and REV2 revisions of the whole tree."
1833 (interactive (vc-diff-build-argument-list-internal))
1834 ;; This is a mix of `vc-root-diff' and `vc-version-diff'
1835 (when (and (not rev1) rev2)
1836 (error "Not a valid revision range"))
1837 (let ((backend (vc-deduce-backend))
1838 (default-directory default-directory)
1839 rootdir)
1840 (if backend
1841 (setq rootdir (vc-call-backend backend 'root default-directory))
1842 (setq rootdir (read-directory-name "Directory for VC root-diff: "))
1843 (setq backend (vc-responsible-backend rootdir))
1844 (if backend
1845 (setq default-directory rootdir)
1846 (error "Directory is not version controlled")))
1847 (let ((default-directory rootdir))
1848 (vc-diff-internal
1849 t (list backend (list rootdir)) rev1 rev2
1850 (called-interactively-p 'interactive)))))
1851
1852;;;###autoload
1831(defun vc-diff (&optional historic not-urgent) 1853(defun vc-diff (&optional historic not-urgent)
1832 "Display diffs between file revisions. 1854 "Display diffs between file revisions.
1833Normally this compares the currently selected fileset with their 1855Normally this compares the currently selected fileset with their
@@ -1900,10 +1922,8 @@ The optional argument NOT-URGENT non-nil means it is ok to say no to
1900saving the buffer." 1922saving the buffer."
1901 (interactive (list current-prefix-arg t)) 1923 (interactive (list current-prefix-arg t))
1902 (if historic 1924 (if historic
1903 ;; FIXME: this does not work right, `vc-version-diff' ends up 1925 ;; We want the diff for the VC root dir.
1904 ;; calling `vc-deduce-fileset' to find the files to diff, and 1926 (call-interactively 'vc-root-version-diff)
1905 ;; that's not what we want here, we want the diff for the VC root dir.
1906 (call-interactively 'vc-version-diff)
1907 (when buffer-file-name (vc-buffer-sync not-urgent)) 1927 (when buffer-file-name (vc-buffer-sync not-urgent))
1908 (let ((backend (vc-deduce-backend)) 1928 (let ((backend (vc-deduce-backend))
1909 (default-directory default-directory) 1929 (default-directory default-directory)
@@ -2013,20 +2033,25 @@ Unlike `vc-find-revision-save', doesn't save the buffer to the file."
2013 (with-current-buffer filebuf 2033 (with-current-buffer filebuf
2014 (let ((failed t)) 2034 (let ((failed t))
2015 (unwind-protect 2035 (unwind-protect
2016 (let ((coding-system-for-read 'no-conversion) 2036 (with-current-buffer (or buffer (create-file-buffer filename))
2017 (coding-system-for-write 'no-conversion)) 2037 (unless buffer (setq buffer-file-name filename))
2018 (with-current-buffer (or buffer (create-file-buffer filename)) 2038 (let ((outbuf (current-buffer)))
2019 (unless buffer (setq buffer-file-name filename)) 2039 (with-current-buffer filebuf
2020 (let ((outbuf (current-buffer))) 2040 (if backend
2021 (with-current-buffer filebuf 2041 (vc-call-backend backend 'find-revision file revision outbuf)
2022 (if backend 2042 (vc-call find-revision file revision outbuf))))
2023 (vc-call-backend backend 'find-revision file revision outbuf) 2043 (decode-coding-inserted-region (point-min) (point-max) file)
2024 (vc-call find-revision file revision outbuf)))) 2044 (after-insert-file-set-coding (- (point-max) (point-min)))
2025 (goto-char (point-min)) 2045 (goto-char (point-min))
2026 (if buffer (let ((buffer-file-name file)) (normal-mode)) (normal-mode)) 2046 (if buffer
2027 (set-buffer-modified-p nil) 2047 ;; For non-interactive, skip any questions
2028 (setq buffer-read-only t)) 2048 (let ((enable-local-variables :safe) ;; to find `mode:'
2029 (setq failed nil)) 2049 (buffer-file-name file))
2050 (ignore-errors (set-auto-mode)))
2051 (normal-mode))
2052 (set-buffer-modified-p nil)
2053 (setq buffer-read-only t))
2054 (setq failed nil)
2030 (when (and failed (unless buffer (get-file-buffer filename))) 2055 (when (and failed (unless buffer (get-file-buffer filename)))
2031 (with-current-buffer (get-file-buffer filename) 2056 (with-current-buffer (get-file-buffer filename)
2032 (set-buffer-modified-p nil)) 2057 (set-buffer-modified-p nil))
diff --git a/src/fileio.c b/src/fileio.c
index d9795715f9e..687f6ec7452 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1692,6 +1692,34 @@ get_homedir (void)
1692 if (!home) 1692 if (!home)
1693 return ""; 1693 return "";
1694 } 1694 }
1695#ifdef DOS_NT
1696 /* If home is a drive-relative directory, expand it. */
1697 if (IS_DRIVE (*home)
1698 && IS_DEVICE_SEP (home[1])
1699 && !IS_DIRECTORY_SEP (home[2]))
1700 {
1701# ifdef WINDOWSNT
1702 static char hdir[MAX_UTF8_PATH];
1703# else
1704 static char hdir[MAXPATHLEN];
1705# endif
1706 if (!getdefdir (c_toupper (*home) - 'A' + 1, hdir))
1707 {
1708 hdir[0] = c_toupper (*home);
1709 hdir[1] = ':';
1710 hdir[2] = '/';
1711 hdir[3] = '\0';
1712 }
1713 if (home[2])
1714 {
1715 size_t homelen = strlen (hdir);
1716 if (!IS_DIRECTORY_SEP (hdir[homelen - 1]))
1717 strcat (hdir, "/");
1718 strcat (hdir, home + 2);
1719 }
1720 home = hdir;
1721 }
1722#endif
1695 if (IS_ABSOLUTE_FILE_NAME (home)) 1723 if (IS_ABSOLUTE_FILE_NAME (home))
1696 return home; 1724 return home;
1697 if (!emacs_wd) 1725 if (!emacs_wd)
diff --git a/src/textprop.c b/src/textprop.c
index 8e8baf43d9f..8a06f0ffad1 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -111,9 +111,6 @@ CHECK_STRING_OR_BUFFER (Lisp_Object x)
111 to by BEGIN and END may be integers or markers; if the latter, they 111 to by BEGIN and END may be integers or markers; if the latter, they
112 are coerced to integers. 112 are coerced to integers.
113 113
114 When OBJECT is a string, we increment *BEGIN and *END
115 to make them origin-one.
116
117 Note that buffer points don't correspond to interval indices. 114 Note that buffer points don't correspond to interval indices.
118 For example, point-max is 1 greater than the index of the last 115 For example, point-max is 1 greater than the index of the last
119 character. This difference is handled in the caller, which uses 116 character. This difference is handled in the caller, which uses
@@ -175,9 +172,6 @@ validate_interval_range (Lisp_Object object, Lisp_Object *begin,
175 if (! (0 <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end) 172 if (! (0 <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end)
176 && XFIXNUM (*end) <= len)) 173 && XFIXNUM (*end) <= len))
177 args_out_of_range (*begin, *end); 174 args_out_of_range (*begin, *end);
178 XSETFASTINT (*begin, XFIXNAT (*begin));
179 if (begin != end)
180 XSETFASTINT (*end, XFIXNAT (*end));
181 i = string_intervals (object); 175 i = string_intervals (object);
182 176
183 if (len == 0) 177 if (len == 0)
@@ -1348,13 +1342,9 @@ Lisp_Object
1348set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties, 1342set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties,
1349 Lisp_Object object, Lisp_Object coherent_change_p) 1343 Lisp_Object object, Lisp_Object coherent_change_p)
1350{ 1344{
1351 register INTERVAL i; 1345 INTERVAL i;
1352 Lisp_Object ostart, oend;
1353 bool first_time = true; 1346 bool first_time = true;
1354 1347
1355 ostart = start;
1356 oend = end;
1357
1358 properties = validate_plist (properties); 1348 properties = validate_plist (properties);
1359 1349
1360 if (NILP (object)) 1350 if (NILP (object))
@@ -1382,11 +1372,6 @@ set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties,
1382 if (NILP (properties)) 1372 if (NILP (properties))
1383 return Qnil; 1373 return Qnil;
1384 1374
1385 /* Restore the original START and END values
1386 because validate_interval_range increments them for strings. */
1387 start = ostart;
1388 end = oend;
1389
1390 i = validate_interval_range (object, &start, &end, hard); 1375 i = validate_interval_range (object, &start, &end, hard);
1391 /* This can return if start == end. */ 1376 /* This can return if start == end. */
1392 if (!i) 1377 if (!i)
@@ -1421,34 +1406,25 @@ set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties,
1421/* Replace properties of text from START to END with new list of 1406/* Replace properties of text from START to END with new list of
1422 properties PROPERTIES. OBJECT is the buffer or string containing 1407 properties PROPERTIES. OBJECT is the buffer or string containing
1423 the text. This does not obey any hooks. 1408 the text. This does not obey any hooks.
1424 You should provide the interval that START is located in as I. 1409 I is the interval that START is located in. */
1425 START and END can be in any order. */
1426 1410
1427void 1411void
1428set_text_properties_1 (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object, INTERVAL i) 1412set_text_properties_1 (Lisp_Object start, Lisp_Object end,
1413 Lisp_Object properties, Lisp_Object object, INTERVAL i)
1429{ 1414{
1430 register INTERVAL prev_changed = NULL; 1415 INTERVAL prev_changed = NULL;
1431 register ptrdiff_t s, len; 1416 ptrdiff_t s = XFIXNUM (start);
1432 INTERVAL unchanged; 1417 ptrdiff_t len = XFIXNUM (end) - s;
1433 1418
1434 if (XFIXNUM (start) < XFIXNUM (end)) 1419 if (len == 0)
1435 {
1436 s = XFIXNUM (start);
1437 len = XFIXNUM (end) - s;
1438 }
1439 else if (XFIXNUM (end) < XFIXNUM (start))
1440 {
1441 s = XFIXNUM (end);
1442 len = XFIXNUM (start) - s;
1443 }
1444 else
1445 return; 1420 return;
1421 eassert (0 < len);
1446 1422
1447 eassert (i); 1423 eassert (i);
1448 1424
1449 if (i->position != s) 1425 if (i->position != s)
1450 { 1426 {
1451 unchanged = i; 1427 INTERVAL unchanged = i;
1452 i = split_interval_right (unchanged, s - unchanged->position); 1428 i = split_interval_right (unchanged, s - unchanged->position);
1453 1429
1454 if (LENGTH (i) > len) 1430 if (LENGTH (i) > len)
@@ -1896,45 +1872,30 @@ Lisp_Object
1896copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, 1872copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src,
1897 Lisp_Object pos, Lisp_Object dest, Lisp_Object prop) 1873 Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
1898{ 1874{
1899 INTERVAL i; 1875 INTERVAL i = validate_interval_range (src, &start, &end, soft);
1900 Lisp_Object res;
1901 Lisp_Object stuff;
1902 Lisp_Object plist;
1903 ptrdiff_t s, e, e2, p, len;
1904 bool modified = false;
1905
1906 i = validate_interval_range (src, &start, &end, soft);
1907 if (!i) 1876 if (!i)
1908 return Qnil; 1877 return Qnil;
1909 1878
1910 CHECK_FIXNUM_COERCE_MARKER (pos); 1879 CHECK_FIXNUM_COERCE_MARKER (pos);
1911 {
1912 Lisp_Object dest_start, dest_end;
1913
1914 e = XFIXNUM (pos) + (XFIXNUM (end) - XFIXNUM (start));
1915 if (MOST_POSITIVE_FIXNUM < e)
1916 args_out_of_range (pos, end);
1917 dest_start = pos;
1918 XSETFASTINT (dest_end, e);
1919 /* Apply this to a copy of pos; it will try to increment its arguments,
1920 which we don't want. */
1921 validate_interval_range (dest, &dest_start, &dest_end, soft);
1922 }
1923 1880
1924 s = XFIXNUM (start); 1881 EMACS_INT dest_e = XFIXNUM (pos) + (XFIXNUM (end) - XFIXNUM (start));
1925 e = XFIXNUM (end); 1882 if (MOST_POSITIVE_FIXNUM < dest_e)
1926 p = XFIXNUM (pos); 1883 args_out_of_range (pos, end);
1884 Lisp_Object dest_end = make_fixnum (dest_e);
1885 validate_interval_range (dest, &pos, &dest_end, soft);
1886
1887 ptrdiff_t s = XFIXNUM (start), e = XFIXNUM (end), p = XFIXNUM (pos);
1927 1888
1928 stuff = Qnil; 1889 Lisp_Object stuff = Qnil;
1929 1890
1930 while (s < e) 1891 while (s < e)
1931 { 1892 {
1932 e2 = i->position + LENGTH (i); 1893 ptrdiff_t e2 = i->position + LENGTH (i);
1933 if (e2 > e) 1894 if (e2 > e)
1934 e2 = e; 1895 e2 = e;
1935 len = e2 - s; 1896 ptrdiff_t len = e2 - s;
1936 1897
1937 plist = i->plist; 1898 Lisp_Object plist = i->plist;
1938 if (! NILP (prop)) 1899 if (! NILP (prop))
1939 while (! NILP (plist)) 1900 while (! NILP (plist))
1940 { 1901 {
@@ -1959,9 +1920,11 @@ copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src,
1959 s = i->position; 1920 s = i->position;
1960 } 1921 }
1961 1922
1923 bool modified = false;
1924
1962 while (! NILP (stuff)) 1925 while (! NILP (stuff))
1963 { 1926 {
1964 res = Fcar (stuff); 1927 Lisp_Object res = Fcar (stuff);
1965 res = Fadd_text_properties (Fcar (res), Fcar (Fcdr (res)), 1928 res = Fadd_text_properties (Fcar (res), Fcar (Fcdr (res)),
1966 Fcar (Fcdr (Fcdr (res))), dest); 1929 Fcar (Fcdr (Fcdr (res))), dest);
1967 if (! NILP (res)) 1930 if (! NILP (res))
diff --git a/src/xdisp.c b/src/xdisp.c
index 4d9990cf46c..cb21397e7b9 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -23041,7 +23041,7 @@ Emacs UBA implementation, in particular with the test suite. */)
23041 } 23041 }
23042 else 23042 else
23043 { 23043 {
23044 CHECK_FIXNUM_COERCE_MARKER (vpos); 23044 CHECK_FIXNUM (vpos);
23045 nrow = XFIXNUM (vpos); 23045 nrow = XFIXNUM (vpos);
23046 } 23046 }
23047 23047
diff --git a/test/Makefile.in b/test/Makefile.in
index adb316c3d9c..4548323f26a 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -190,6 +190,12 @@ else
190maybe_exclude_module_tests := -name emacs-module-tests.el -prune -o 190maybe_exclude_module_tests := -name emacs-module-tests.el -prune -o
191endif 191endif
192 192
193## Optional list of .el files to exclude from testing.
194## Intended for use in automated testing where one or more files
195## has some problem and needs to be excluded.
196## To avoid writing full name, can use eg %foo-tests.el.
197EXCLUDE_TESTS =
198
193## To speed up parallel builds, put these slow test files (which can 199## To speed up parallel builds, put these slow test files (which can
194## take longer than all the rest combined) at the start of the list. 200## take longer than all the rest combined) at the start of the list.
195SLOW_TESTS = ${srcdir}/lisp/net/tramp-tests.el 201SLOW_TESTS = ${srcdir}/lisp/net/tramp-tests.el
@@ -202,6 +208,8 @@ ELFILES := $(sort $(shell find ${srcdir} -path "${srcdir}/manual" -prune -o \
202 208
203$(foreach slow,${SLOW_TESTS},$(eval ELFILES:= ${slow} $(filter-out ${slow},${ELFILES}))) 209$(foreach slow,${SLOW_TESTS},$(eval ELFILES:= ${slow} $(filter-out ${slow},${ELFILES})))
204 210
211$(foreach exclude,${EXCLUDE_TESTS},$(eval ELFILES:= $(filter-out ${exclude},${ELFILES})))
212
205## .log files may be in a different directory for out of source builds 213## .log files may be in a different directory for out of source builds
206LOGFILES := $(patsubst %.el,%.log, \ 214LOGFILES := $(patsubst %.el,%.log, \
207 $(patsubst $(srcdir)/%,%,$(ELFILES))) 215 $(patsubst $(srcdir)/%,%,$(ELFILES)))
diff --git a/test/lisp/eshell/em-ls-tests.el b/test/lisp/eshell/em-ls-tests.el
index c5c9eac3249..b89a54641bd 100644
--- a/test/lisp/eshell/em-ls-tests.el
+++ b/test/lisp/eshell/em-ls-tests.el
@@ -78,6 +78,11 @@
78 78
79(ert-deftest em-ls-test-bug27844 () 79(ert-deftest em-ls-test-bug27844 ()
80 "Test for https://debbugs.gnu.org/27844 ." 80 "Test for https://debbugs.gnu.org/27844 ."
81 ;; FIXME: it would be better to use something other than source-directory
82 ;; in this test.
83 (skip-unless (and source-directory
84 (file-exists-p
85 (expand-file-name "lisp/subr.el" source-directory))))
81 (let ((orig eshell-ls-use-in-dired) 86 (let ((orig eshell-ls-use-in-dired)
82 (dired-use-ls-dired 'unspecified) 87 (dired-use-ls-dired 'unspecified)
83 buf insert-directory-program) 88 buf insert-directory-program)
@@ -89,6 +94,15 @@
89 (should (cdr (dired-get-marked-files))) 94 (should (cdr (dired-get-marked-files)))
90 (kill-buffer buf) 95 (kill-buffer buf)
91 (setq buf (dired (expand-file-name "lisp/subr.el" source-directory))) 96 (setq buf (dired (expand-file-name "lisp/subr.el" source-directory)))
97 (when (getenv "EMACS_HYDRA_CI")
98 (message "X1%s" (buffer-substring-no-properties
99 (point-min) (point-max)))
100 (message "X2%s" (buffer-substring-no-properties
101 (line-beginning-position)
102 (line-end-position)))
103 (message "X3%s" (buffer-substring-no-properties
104 (point)
105 (line-end-position))))
92 (should (looking-at "subr\\.el"))) 106 (should (looking-at "subr\\.el")))
93 (customize-set-variable 'eshell-ls-use-in-dired orig) 107 (customize-set-variable 'eshell-ls-use-in-dired orig)
94 (and (buffer-live-p buf) (kill-buffer))))) 108 (and (buffer-live-p buf) (kill-buffer)))))
diff --git a/test/lisp/net/secrets-tests.el b/test/lisp/net/secrets-tests.el
index de3ce731bec..d34b0021952 100644
--- a/test/lisp/net/secrets-tests.el
+++ b/test/lisp/net/secrets-tests.el
@@ -90,10 +90,6 @@
90 (unwind-protect 90 (unwind-protect
91 (progn 91 (progn
92 (should (secrets-open-session)) 92 (should (secrets-open-session))
93
94 ;; There must be at least the collections "Login" and "session".
95 (should (or (member "Login" (secrets-list-collections))
96 (member "login" (secrets-list-collections))))
97 (should (member "session" (secrets-list-collections))) 93 (should (member "session" (secrets-list-collections)))
98 94
99 ;; Create a random collection. This asks for a password 95 ;; Create a random collection. This asks for a password
@@ -160,9 +156,6 @@
160 156
161 ;; There shall be no items in the "session" collection. 157 ;; There shall be no items in the "session" collection.
162 (should-not (secrets-list-items "session")) 158 (should-not (secrets-list-items "session"))
163 ;; There shall be items in the "Login" collection.
164 (should (or (secrets-list-items "Login")
165 (secrets-list-items "login")))
166 159
167 ;; Create a new item. 160 ;; Create a new item.
168 (should (setq item-path (secrets-create-item "session" "foo" "secret"))) 161 (should (setq item-path (secrets-create-item "session" "foo" "secret")))
diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el
index 72d83affaef..afd6d65c9d1 100644
--- a/test/lisp/progmodes/ruby-mode-tests.el
+++ b/test/lisp/progmodes/ruby-mode-tests.el
@@ -718,6 +718,96 @@ VALUES-PLIST is a list with alternating index and value elements."
718 (ruby-backward-sexp) 718 (ruby-backward-sexp)
719 (should (= 2 (line-number-at-pos))))) 719 (should (= 2 (line-number-at-pos)))))
720 720
721(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-no-args ()
722 (ruby-with-temp-buffer
723 (ruby-test-string
724 "proc do
725 |end")
726 (search-backward "do\n")
727 (ruby-forward-sexp)
728 (should (eobp))))
729
730(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-no-args ()
731 (ruby-with-temp-buffer
732 (ruby-test-string
733 "proc do
734 |end")
735 (goto-char (point-max))
736 (ruby-backward-sexp)
737 (should (looking-at "do$"))))
738
739(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-empty-args ()
740 (ruby-with-temp-buffer
741 (ruby-test-string
742 "proc do ||
743 |end")
744 (search-backward "do ")
745 (ruby-forward-sexp)
746 (should (eobp))))
747
748(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-empty-args ()
749 (ruby-with-temp-buffer
750 (ruby-test-string
751 "proc do ||
752 |end")
753 (goto-char (point-max))
754 (ruby-backward-sexp)
755 (should (looking-at "do "))))
756
757(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-args ()
758 (ruby-with-temp-buffer
759 (ruby-test-string
760 "proc do |a,b|
761 |end")
762 (search-backward "do ")
763 (ruby-forward-sexp)
764 (should (eobp))))
765
766(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-args ()
767 (ruby-with-temp-buffer
768 (ruby-test-string
769 "proc do |a,b|
770 |end")
771 (goto-char (point-max))
772 (ruby-backward-sexp)
773 (should (looking-at "do "))))
774
775(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-any-args ()
776 (ruby-with-temp-buffer
777 (ruby-test-string
778 "proc do |*|
779 |end")
780 (search-backward "do ")
781 (ruby-forward-sexp)
782 (should (eobp))))
783
784(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-expanded-one-arg ()
785 (ruby-with-temp-buffer
786 (ruby-test-string
787 "proc do |a,|
788 |end")
789 (search-backward "do ")
790 (ruby-forward-sexp)
791 (should (eobp))))
792
793(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-one-and-any-args ()
794 (ruby-with-temp-buffer
795 (ruby-test-string
796 "proc do |a,*|
797 |end")
798 (search-backward "do ")
799 (ruby-forward-sexp)
800 (should (eobp))))
801
802(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-one-and-any-args ()
803 (ruby-with-temp-buffer
804 (ruby-test-string
805 "proc do |a,*|
806 |end")
807 (goto-char (point-max))
808 (ruby-backward-sexp)
809 (should (looking-at "do "))))
810
721(ert-deftest ruby-toggle-string-quotes-quotes-correctly () 811(ert-deftest ruby-toggle-string-quotes-quotes-correctly ()
722 (let ((pairs 812 (let ((pairs
723 '(("puts '\"foo\"\\''" . "puts \"\\\"foo\\\"'\"") 813 '(("puts '\"foo\"\\''" . "puts \"\\\"foo\\\"'\"")
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el
index b7b78bbda09..a74bcea41f2 100644
--- a/test/src/fileio-tests.el
+++ b/test/src/fileio-tests.el
@@ -102,4 +102,8 @@ Also check that an encoding error can appear in a symlink."
102 (setenv "HOME" "a/b/c") 102 (setenv "HOME" "a/b/c")
103 (should (equal (expand-file-name "~/foo") 103 (should (equal (expand-file-name "~/foo")
104 (expand-file-name "a/b/c/foo"))) 104 (expand-file-name "a/b/c/foo")))
105 (when (memq system-type '(ms-dos windows-nt))
106 ;; Test expansion of drive-relative file names.
107 (setenv "HOME" "x:foo")
108 (should (equal (expand-file-name "~/bar") "x:/foo/bar")))
105 (setenv "HOME" old-home))) 109 (setenv "HOME" old-home)))