aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorRasmus2017-09-29 10:41:51 +0200
committerRasmus2017-09-29 10:41:51 +0200
commitd4b2bbdc73ace5cb0971a32a75941486489d1cc5 (patch)
treedc92eb83d4a66f112e3688ad10632e14ca6601ff /lisp
parenteaefbc26d5c6cffbe4a22d3a9f4c7e6209a7b5a7 (diff)
parentaf130f900fc499f71ea22f10ba055a75ce35ed4e (diff)
downloademacs-d4b2bbdc73ace5cb0971a32a75941486489d1cc5.tar.gz
emacs-d4b2bbdc73ace5cb0971a32a75941486489d1cc5.zip
Merge branch 'emacs-26' into scratch/org-mode-merge
Diffstat (limited to 'lisp')
-rw-r--r--lisp/calendar/cal-tex.el2
-rw-r--r--lisp/emacs-lisp/ert-x.el57
-rw-r--r--lisp/emacs-lisp/ert.el5
-rw-r--r--lisp/emacs-lisp/smie.el4
-rw-r--r--lisp/emacs-lisp/subr-x.el2
-rw-r--r--lisp/emacs-lisp/syntax.el107
-rw-r--r--lisp/emacs-lisp/timer-list.el6
-rw-r--r--lisp/eshell/esh-util.el2
-rw-r--r--lisp/files.el42
-rw-r--r--lisp/frame.el20
-rw-r--r--lisp/frameset.el13
-rw-r--r--lisp/gnus/message.el1
-rw-r--r--lisp/mouse.el28
-rw-r--r--lisp/mwheel.el1
-rw-r--r--lisp/net/mailcap.el6
-rw-r--r--lisp/net/tramp-adb.el2
-rw-r--r--lisp/net/tramp-compat.el33
-rw-r--r--lisp/net/tramp-sh.el28
-rw-r--r--lisp/net/tramp-smb.el10
-rw-r--r--lisp/net/tramp.el33
-rw-r--r--lisp/net/trampver.el9
-rw-r--r--lisp/org/ChangeLog.14
-rw-r--r--lisp/progmodes/bat-mode.el6
-rw-r--r--lisp/progmodes/flymake-proc.el1100
-rw-r--r--lisp/progmodes/flymake-ui.el634
-rw-r--r--lisp/progmodes/flymake.el1629
-rw-r--r--lisp/progmodes/python.el6
-rw-r--r--lisp/progmodes/sh-script.el34
-rw-r--r--lisp/progmodes/xref.el2
-rw-r--r--lisp/simple.el59
-rw-r--r--lisp/subr.el7
-rw-r--r--lisp/term/ns-win.el19
-rw-r--r--lisp/textmodes/css-mode.el2
-rw-r--r--lisp/textmodes/ispell.el6
-rw-r--r--lisp/textmodes/page-ext.el2
-rw-r--r--lisp/vc/log-view.el14
-rw-r--r--lisp/vc/smerge-mode.el2
-rw-r--r--lisp/vc/vc-git.el2
-rw-r--r--lisp/xdg.el4
39 files changed, 1984 insertions, 1959 deletions
diff --git a/lisp/calendar/cal-tex.el b/lisp/calendar/cal-tex.el
index 72db03e5e60..1d295606f23 100644
--- a/lisp/calendar/cal-tex.el
+++ b/lisp/calendar/cal-tex.el
@@ -266,7 +266,7 @@ specified in ARGS. When ARGS is omitted, by default the option
266\"12pt,a4paper\" is passed. When ARGS has any other value, then 266\"12pt,a4paper\" is passed. When ARGS has any other value, then
267no option is passed to the class. 267no option is passed to the class.
268 268
269Insert the \"\\usepacakge{geometry}\" directive when ARGS 269Insert the \"\\usepackage{geometry}\" directive when ARGS
270contains the \"landscape\" string." 270contains the \"landscape\" string."
271 (set-buffer (generate-new-buffer cal-tex-buffer)) 271 (set-buffer (generate-new-buffer cal-tex-buffer))
272 (save-match-data 272 (save-match-data
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index 6d9a7d9211a..71d46c11077 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -286,27 +286,60 @@ BUFFER defaults to current buffer. Does not modify BUFFER."
286 286
287 287
288(defmacro ert-with-message-capture (var &rest body) 288(defmacro ert-with-message-capture (var &rest body)
289 "Execute BODY while collecting anything written with `message' in VAR. 289 "Execute BODY while collecting messages in VAR.
290 290
291Capture all messages produced by `message' when it is called from 291Capture messages issued by Lisp code and concatenate them
292Lisp, and concatenate them separated by newlines into one string. 292separated by newlines into one string. This includes messages
293written by `message' as well as objects printed by `print',
294`prin1' and `princ' to the echo area. Messages issued from C
295code using the above mentioned functions will not be captured.
293 296
294This is useful for separating the issuance of messages by the 297This is useful for separating the issuance of messages by the
295code under test from the behavior of the *Messages* buffer." 298code under test from the behavior of the *Messages* buffer."
296 (declare (debug (symbolp body)) 299 (declare (debug (symbolp body))
297 (indent 1)) 300 (indent 1))
298 (let ((g-advice (gensym))) 301 (let ((g-message-advice (gensym))
302 (g-print-advice (gensym))
303 (g-collector (gensym)))
299 `(let* ((,var "") 304 `(let* ((,var "")
300 (,g-advice (lambda (func &rest args) 305 (,g-collector (lambda (msg) (setq ,var (concat ,var msg))))
301 (if (or (null args) (equal (car args) "")) 306 (,g-message-advice (ert--make-message-advice ,g-collector))
302 (apply func args) 307 (,g-print-advice (ert--make-print-advice ,g-collector)))
303 (let ((msg (apply #'format-message args))) 308 (advice-add 'message :around ,g-message-advice)
304 (setq ,var (concat ,var msg "\n")) 309 (advice-add 'prin1 :around ,g-print-advice)
305 (funcall func "%s" msg)))))) 310 (advice-add 'princ :around ,g-print-advice)
306 (advice-add 'message :around ,g-advice) 311 (advice-add 'print :around ,g-print-advice)
307 (unwind-protect 312 (unwind-protect
308 (progn ,@body) 313 (progn ,@body)
309 (advice-remove 'message ,g-advice))))) 314 (advice-remove 'print ,g-print-advice)
315 (advice-remove 'princ ,g-print-advice)
316 (advice-remove 'prin1 ,g-print-advice)
317 (advice-remove 'message ,g-message-advice)))))
318
319(defun ert--make-message-advice (collector)
320 "Create around advice for `message' for `ert-collect-messages'.
321COLLECTOR will be called with the message before it is passed
322to the real `message'."
323 (lambda (func &rest args)
324 (if (or (null args) (equal (car args) ""))
325 (apply func args)
326 (let ((msg (apply #'format-message args)))
327 (funcall collector (concat msg "\n"))
328 (funcall func "%s" msg)))))
329
330(defun ert--make-print-advice (collector)
331 "Create around advice for print functions for `ert-collect-messages'.
332The created advice function will just call the original function
333unless the output is going to the echo area (when PRINTCHARFUN is
334t or PRINTCHARFUN is nil and `standard-output' is t). If the
335output is destined for the echo area, the advice function will
336convert it to a string and pass it to COLLECTOR first."
337 (lambda (func object &optional printcharfun)
338 (if (not (eq t (or printcharfun standard-output)))
339 (funcall func object printcharfun)
340 (funcall collector (with-output-to-string
341 (funcall func object)))
342 (funcall func object printcharfun))))
310 343
311 344
312(provide 'ert-x) 345(provide 'ert-x)
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index d4276221ba5..83acbacb883 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -742,9 +742,8 @@ run. ARGS are the arguments to `debugger'."
742 ;; backtrace ready for printing is important for batch 742 ;; backtrace ready for printing is important for batch
743 ;; use. 743 ;; use.
744 ;; 744 ;;
745 ;; Grab the frames starting from `signal', frames below 745 ;; Grab the frames above the debugger.
746 ;; that are all from the debugger. 746 (backtrace (cdr (backtrace-frames debugger)))
747 (backtrace (backtrace-frames 'signal))
748 (infos (reverse ert--infos))) 747 (infos (reverse ert--infos)))
749 (setf (ert--test-execution-info-result info) 748 (setf (ert--test-execution-info-result info)
750 (cl-ecase type 749 (cl-ecase type
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el
index 87c4782e217..da1e12b1408 100644
--- a/lisp/emacs-lisp/smie.el
+++ b/lisp/emacs-lisp/smie.el
@@ -1956,7 +1956,7 @@ E.g. provided via a file-local call to `smie-config-local'.")
1956(defvar smie-config--modefuns nil) 1956(defvar smie-config--modefuns nil)
1957 1957
1958(defun smie-config--setter (var value) 1958(defun smie-config--setter (var value)
1959 (setq-default var value) 1959 (set-default var value)
1960 (let ((old-modefuns smie-config--modefuns)) 1960 (let ((old-modefuns smie-config--modefuns))
1961 (setq smie-config--modefuns nil) 1961 (setq smie-config--modefuns nil)
1962 (pcase-dolist (`(,mode . ,rules) value) 1962 (pcase-dolist (`(,mode . ,rules) value)
@@ -1982,7 +1982,7 @@ value with which to replace it."
1982 ;; FIXME improve value-type. 1982 ;; FIXME improve value-type.
1983 :type '(choice (const nil) 1983 :type '(choice (const nil)
1984 (alist :key-type symbol)) 1984 (alist :key-type symbol))
1985 :initialize 'custom-initialize-default 1985 :initialize 'custom-initialize-set
1986 :set #'smie-config--setter) 1986 :set #'smie-config--setter)
1987 1987
1988(defun smie-config-local (rules) 1988(defun smie-config-local (rules)
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 077ad22c75d..edba6550fa2 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -128,7 +128,7 @@ binding value is nil. If all are non-nil, the value of THEN is
128returned, or the last form in ELSE is returned. 128returned, or the last form in ELSE is returned.
129 129
130Each element of VARLIST is a list (SYMBOL VALUEFORM) which binds 130Each element of VARLIST is a list (SYMBOL VALUEFORM) which binds
131SYMBOL to the value of VALUEFORM). An element can additionally 131SYMBOL to the value of VALUEFORM. An element can additionally
132be of the form (VALUEFORM), which is evaluated and checked for 132be of the form (VALUEFORM), which is evaluated and checked for
133nil; i.e. SYMBOL can be omitted if only the test result is of 133nil; i.e. SYMBOL can be omitted if only the test result is of
134interest." 134interest."
diff --git a/lisp/emacs-lisp/syntax.el b/lisp/emacs-lisp/syntax.el
index f6137837858..9eb6bde7454 100644
--- a/lisp/emacs-lisp/syntax.el
+++ b/lisp/emacs-lisp/syntax.el
@@ -381,10 +381,26 @@ This function should move the cursor back to some syntactically safe
381point (where the PPSS is equivalent to nil).") 381point (where the PPSS is equivalent to nil).")
382(make-obsolete-variable 'syntax-begin-function nil "25.1") 382(make-obsolete-variable 'syntax-begin-function nil "25.1")
383 383
384(defvar-local syntax-ppss-cache nil 384;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
385 "List of (POS . PPSS) pairs, in decreasing POS order.") 385;; Several caches.
386(defvar-local syntax-ppss-last nil 386;;
387 "Cache of (LAST-POS . LAST-PPSS).") 387;; Because `syntax-ppss' is equivalent to (parse-partial-sexp
388;; (POINT-MIN) x), we need either to empty the cache when we narrow
389;; the buffer, which is suboptimal, or we need to use several caches.
390;; We use two of them, one for widened buffer, and one for narrowing.
391;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
392
393(defvar-local syntax-ppss-wide nil
394 "Cons of two elements (LAST . CACHE).
395Where LAST is a pair (LAST-POS . LAST-PPS) caching the last invocation
396and CACHE is a list of (POS . PPSS) pairs, in decreasing POS order.
397These are valid when the buffer has no restriction.")
398
399(defvar-local syntax-ppss-narrow nil
400 "Same as `syntax-ppss-wide' but for a narrowed buffer.")
401
402(defvar-local syntax-ppss-narrow-start nil
403 "Start position of the narrowing for `syntax-ppss-narrow'.")
388 404
389(defalias 'syntax-ppss-after-change-function 'syntax-ppss-flush-cache) 405(defalias 'syntax-ppss-after-change-function 'syntax-ppss-flush-cache)
390(defun syntax-ppss-flush-cache (beg &rest ignored) 406(defun syntax-ppss-flush-cache (beg &rest ignored)
@@ -392,24 +408,29 @@ point (where the PPSS is equivalent to nil).")
392 ;; Set syntax-propertize to refontify anything past beg. 408 ;; Set syntax-propertize to refontify anything past beg.
393 (setq syntax-propertize--done (min beg syntax-propertize--done)) 409 (setq syntax-propertize--done (min beg syntax-propertize--done))
394 ;; Flush invalid cache entries. 410 ;; Flush invalid cache entries.
395 (while (and syntax-ppss-cache (> (caar syntax-ppss-cache) beg)) 411 (dolist (cell (list syntax-ppss-wide syntax-ppss-narrow))
396 (setq syntax-ppss-cache (cdr syntax-ppss-cache))) 412 (pcase cell
397 ;; Throw away `last' value if made invalid. 413 (`(,last . ,cache)
398 (when (< beg (or (car syntax-ppss-last) 0)) 414 (while (and cache (> (caar cache) beg))
399 ;; If syntax-begin-function jumped to BEG, then the old state at BEG can 415 (setq cache (cdr cache)))
400 ;; depend on the text after BEG (which is presumably changed). So if 416 ;; Throw away `last' value if made invalid.
401 ;; BEG=(car (nth 10 syntax-ppss-last)) don't reuse that data because the 417 (when (< beg (or (car last) 0))
402 ;; assumed nil state at BEG may not be valid any more. 418 ;; If syntax-begin-function jumped to BEG, then the old state at BEG can
403 (if (<= beg (or (syntax-ppss-toplevel-pos (cdr syntax-ppss-last)) 419 ;; depend on the text after BEG (which is presumably changed). So if
404 (nth 3 syntax-ppss-last) 420 ;; BEG=(car (nth 10 syntax-ppss-last)) don't reuse that data because the
405 0)) 421 ;; assumed nil state at BEG may not be valid any more.
406 (setq syntax-ppss-last nil) 422 (if (<= beg (or (syntax-ppss-toplevel-pos (cdr last))
407 (setcar syntax-ppss-last nil))) 423 (nth 3 last)
408 ;; Unregister if there's no cache left. Sadly this doesn't work 424 0))
409 ;; because `before-change-functions' is temporarily bound to nil here. 425 (setq last nil)
410 ;; (unless syntax-ppss-cache 426 (setcar last nil)))
411 ;; (remove-hook 'before-change-functions 'syntax-ppss-flush-cache t)) 427 ;; Unregister if there's no cache left. Sadly this doesn't work
412 ) 428 ;; because `before-change-functions' is temporarily bound to nil here.
429 ;; (unless cache
430 ;; (remove-hook 'before-change-functions 'syntax-ppss-flush-cache t))
431 (setcar cell last)
432 (setcdr cell cache)))
433 ))
413 434
414(defvar syntax-ppss-stats 435(defvar syntax-ppss-stats
415 [(0 . 0.0) (0 . 0.0) (0 . 0.0) (0 . 0.0) (0 . 0.0) (1 . 2500.0)]) 436 [(0 . 0.0) (0 . 0.0) (0 . 0.0) (0 . 0.0) (0 . 0.0) (1 . 2500.0)])
@@ -423,6 +444,17 @@ point (where the PPSS is equivalent to nil).")
423(defvar-local syntax-ppss-table nil 444(defvar-local syntax-ppss-table nil
424 "Syntax-table to use during `syntax-ppss', if any.") 445 "Syntax-table to use during `syntax-ppss', if any.")
425 446
447(defun syntax-ppss--data ()
448 (if (eq (point-min) 1)
449 (progn
450 (unless syntax-ppss-wide
451 (setq syntax-ppss-wide (cons nil nil)))
452 syntax-ppss-wide)
453 (unless (eq syntax-ppss-narrow-start (point-min))
454 (setq syntax-ppss-narrow-start (point-min))
455 (setq syntax-ppss-narrow (cons nil nil)))
456 syntax-ppss-narrow))
457
426(defun syntax-ppss (&optional pos) 458(defun syntax-ppss (&optional pos)
427 "Parse-Partial-Sexp State at POS, defaulting to point. 459 "Parse-Partial-Sexp State at POS, defaulting to point.
428The returned value is the same as that of `parse-partial-sexp' 460The returned value is the same as that of `parse-partial-sexp'
@@ -439,10 +471,13 @@ running the hook."
439 (syntax-propertize pos) 471 (syntax-propertize pos)
440 ;; 472 ;;
441 (with-syntax-table (or syntax-ppss-table (syntax-table)) 473 (with-syntax-table (or syntax-ppss-table (syntax-table))
442 (let ((old-ppss (cdr syntax-ppss-last)) 474 (let* ((cell (syntax-ppss--data))
443 (old-pos (car syntax-ppss-last)) 475 (ppss-last (car cell))
444 (ppss nil) 476 (ppss-cache (cdr cell))
445 (pt-min (point-min))) 477 (old-ppss (cdr ppss-last))
478 (old-pos (car ppss-last))
479 (ppss nil)
480 (pt-min (point-min)))
446 (if (and old-pos (> old-pos pos)) (setq old-pos nil)) 481 (if (and old-pos (> old-pos pos)) (setq old-pos nil))
447 ;; Use the OLD-POS if usable and close. Don't update the `last' cache. 482 ;; Use the OLD-POS if usable and close. Don't update the `last' cache.
448 (condition-case nil 483 (condition-case nil
@@ -475,7 +510,7 @@ running the hook."
475 ;; The OLD-* data can't be used. Consult the cache. 510 ;; The OLD-* data can't be used. Consult the cache.
476 (t 511 (t
477 (let ((cache-pred nil) 512 (let ((cache-pred nil)
478 (cache syntax-ppss-cache) 513 (cache ppss-cache)
479 (pt-min (point-min)) 514 (pt-min (point-min))
480 ;; I differentiate between PT-MIN and PT-BEST because 515 ;; I differentiate between PT-MIN and PT-BEST because
481 ;; I feel like it might be important to ensure that the 516 ;; I feel like it might be important to ensure that the
@@ -491,7 +526,7 @@ running the hook."
491 (if cache (setq pt-min (caar cache) ppss (cdar cache))) 526 (if cache (setq pt-min (caar cache) ppss (cdar cache)))
492 527
493 ;; Setup the before-change function if necessary. 528 ;; Setup the before-change function if necessary.
494 (unless (or syntax-ppss-cache syntax-ppss-last) 529 (unless (or ppss-cache ppss-last)
495 (add-hook 'before-change-functions 530 (add-hook 'before-change-functions
496 'syntax-ppss-flush-cache t t)) 531 'syntax-ppss-flush-cache t t))
497 532
@@ -541,7 +576,7 @@ running the hook."
541 pt-min (setq pt-min (/ (+ pt-min pos) 2)) 576 pt-min (setq pt-min (/ (+ pt-min pos) 2))
542 nil nil ppss)) 577 nil nil ppss))
543 (push (cons pt-min ppss) 578 (push (cons pt-min ppss)
544 (if cache-pred (cdr cache-pred) syntax-ppss-cache))) 579 (if cache-pred (cdr cache-pred) ppss-cache)))
545 580
546 ;; Compute the actual return value. 581 ;; Compute the actual return value.
547 (setq ppss (parse-partial-sexp pt-min pos nil nil ppss)) 582 (setq ppss (parse-partial-sexp pt-min pos nil nil ppss))
@@ -562,13 +597,15 @@ running the hook."
562 (if (> (- (caar cache-pred) pos) syntax-ppss-max-span) 597 (if (> (- (caar cache-pred) pos) syntax-ppss-max-span)
563 (push pair (cdr cache-pred)) 598 (push pair (cdr cache-pred))
564 (setcar cache-pred pair)) 599 (setcar cache-pred pair))
565 (if (or (null syntax-ppss-cache) 600 (if (or (null ppss-cache)
566 (> (- (caar syntax-ppss-cache) pos) 601 (> (- (caar ppss-cache) pos)
567 syntax-ppss-max-span)) 602 syntax-ppss-max-span))
568 (push pair syntax-ppss-cache) 603 (push pair ppss-cache)
569 (setcar syntax-ppss-cache pair))))))))) 604 (setcar ppss-cache pair)))))))))
570 605
571 (setq syntax-ppss-last (cons pos ppss)) 606 (setq ppss-last (cons pos ppss))
607 (setcar cell ppss-last)
608 (setcdr cell ppss-cache)
572 ppss) 609 ppss)
573 (args-out-of-range 610 (args-out-of-range
574 ;; If the buffer is more narrowed than when we built the cache, 611 ;; If the buffer is more narrowed than when we built the cache,
@@ -582,7 +619,7 @@ running the hook."
582(defun syntax-ppss-debug () 619(defun syntax-ppss-debug ()
583 (let ((pt nil) 620 (let ((pt nil)
584 (min-diffs nil)) 621 (min-diffs nil))
585 (dolist (x (append syntax-ppss-cache (list (cons (point-min) nil)))) 622 (dolist (x (append (cdr (syntax-ppss--data)) (list (cons (point-min) nil))))
586 (when pt (push (- pt (car x)) min-diffs)) 623 (when pt (push (- pt (car x)) min-diffs))
587 (setq pt (car x))) 624 (setq pt (car x)))
588 min-diffs)) 625 min-diffs))
diff --git a/lisp/emacs-lisp/timer-list.el b/lisp/emacs-lisp/timer-list.el
index 44a315f9806..69c67419835 100644
--- a/lisp/emacs-lisp/timer-list.el
+++ b/lisp/emacs-lisp/timer-list.el
@@ -25,7 +25,7 @@
25;;; Code: 25;;; Code:
26 26
27;;;###autoload 27;;;###autoload
28(defun timer-list (&optional _ignore-auto _nonconfirm) 28(defun list-timers (&optional _ignore-auto _nonconfirm)
29 "List all timers in a buffer." 29 "List all timers in a buffer."
30 (interactive) 30 (interactive)
31 (pop-to-buffer-same-window (get-buffer-create "*timer-list*")) 31 (pop-to-buffer-same-window (get-buffer-create "*timer-list*"))
@@ -67,7 +67,7 @@
67 (goto-char (point-min))) 67 (goto-char (point-min)))
68;; This command can be destructive if they don't know what they are 68;; This command can be destructive if they don't know what they are
69;; doing. Kids, don't try this at home! 69;; doing. Kids, don't try this at home!
70;;;###autoload (put 'timer-list 'disabled "Beware: manually canceling timers can ruin your Emacs session.") 70;;;###autoload (put 'list-timers 'disabled "Beware: manually canceling timers can ruin your Emacs session.")
71 71
72(defvar timer-list-mode-map 72(defvar timer-list-mode-map
73 (let ((map (make-sparse-keymap))) 73 (let ((map (make-sparse-keymap)))
@@ -84,7 +84,7 @@
84 (setq bidi-paragraph-direction 'left-to-right) 84 (setq bidi-paragraph-direction 'left-to-right)
85 (setq truncate-lines t) 85 (setq truncate-lines t)
86 (buffer-disable-undo) 86 (buffer-disable-undo)
87 (setq-local revert-buffer-function 'timer-list) 87 (setq-local revert-buffer-function #'list-timers)
88 (setq buffer-read-only t) 88 (setq buffer-read-only t)
89 (setq header-line-format 89 (setq header-line-format
90 (format "%4s %10s %8s %s" 90 (format "%4s %10s %8s %s"
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index c204ec869b5..8b24ec3c430 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -142,7 +142,7 @@ function `string-to-number'."
142(defmacro eshell-condition-case (tag form &rest handlers) 142(defmacro eshell-condition-case (tag form &rest handlers)
143 "If `eshell-handle-errors' is non-nil, this is `condition-case'. 143 "If `eshell-handle-errors' is non-nil, this is `condition-case'.
144Otherwise, evaluates FORM with no error handling." 144Otherwise, evaluates FORM with no error handling."
145 (declare (indent 2)) 145 (declare (indent 2) (debug (sexp form &rest form)))
146 (if eshell-handle-errors 146 (if eshell-handle-errors
147 `(condition-case-unless-debug ,tag 147 `(condition-case-unless-debug ,tag
148 ,form 148 ,form
diff --git a/lisp/files.el b/lisp/files.el
index c55c8097c16..211457ac7d7 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -150,8 +150,13 @@ Called with an absolute file name as argument, it returns t to enable backup.")
150(defcustom buffer-offer-save nil 150(defcustom buffer-offer-save nil
151 "Non-nil in a buffer means always offer to save buffer on exit. 151 "Non-nil in a buffer means always offer to save buffer on exit.
152Do so even if the buffer is not visiting a file. 152Do so even if the buffer is not visiting a file.
153Automatically local in all buffers." 153Automatically local in all buffers.
154 :type 'boolean 154
155Set to the symbol `always' to offer to save buffer whenever
156`save-some-buffers' is called."
157 :type '(choice (const :tag "Never" nil)
158 (const :tag "On Emacs exit" t)
159 (const :tag "Whenever save-some-buffers is called" always))
155 :group 'backup) 160 :group 'backup)
156(make-variable-buffer-local 'buffer-offer-save) 161(make-variable-buffer-local 'buffer-offer-save)
157(put 'buffer-offer-save 'permanent-local t) 162(put 'buffer-offer-save 'permanent-local t)
@@ -5190,12 +5195,9 @@ change the additional actions you can take on files."
5190 (not (buffer-base-buffer buffer)) 5195 (not (buffer-base-buffer buffer))
5191 (or 5196 (or
5192 (buffer-file-name buffer) 5197 (buffer-file-name buffer)
5193 (and pred 5198 (with-current-buffer buffer
5194 (progn 5199 (or (eq buffer-offer-save 'always)
5195 (set-buffer buffer) 5200 (and pred buffer-offer-save (> (buffer-size) 0)))))
5196 (and buffer-offer-save (> (buffer-size) 0))))
5197 (buffer-local-value
5198 'write-contents-functions buffer))
5199 (or (not (functionp pred)) 5201 (or (not (functionp pred))
5200 (with-current-buffer buffer (funcall pred))) 5202 (with-current-buffer buffer (funcall pred)))
5201 (if arg 5203 (if arg
@@ -5336,7 +5338,7 @@ instance of such commands."
5336 "Make directory DIR if it is not already a directory. Return nil." 5338 "Make directory DIR if it is not already a directory. Return nil."
5337 (condition-case err 5339 (condition-case err
5338 (make-directory-internal dir) 5340 (make-directory-internal dir)
5339 (file-already-exists 5341 (error
5340 (unless (file-directory-p dir) 5342 (unless (file-directory-p dir)
5341 (signal (car err) (cdr err)))))) 5343 (signal (car err) (cdr err))))))
5342 5344
@@ -5372,7 +5374,7 @@ raised."
5372 (while (progn 5374 (while (progn
5373 (setq parent (directory-file-name 5375 (setq parent (directory-file-name
5374 (file-name-directory dir))) 5376 (file-name-directory dir)))
5375 (condition-case err 5377 (condition-case ()
5376 (files--ensure-directory dir) 5378 (files--ensure-directory dir)
5377 (file-missing 5379 (file-missing
5378 ;; Do not loop if root does not exist (Bug#2309). 5380 ;; Do not loop if root does not exist (Bug#2309).
@@ -5544,16 +5546,14 @@ into NEWNAME instead."
5544 ;; If NEWNAME is not a directory name, create it; 5546 ;; If NEWNAME is not a directory name, create it;
5545 ;; that is where we will copy the files of DIRECTORY. 5547 ;; that is where we will copy the files of DIRECTORY.
5546 (make-directory newname parents)) 5548 (make-directory newname parents))
5547 ;; If NEWNAME is a directory name and COPY-CONTENTS 5549 ;; NEWNAME is a directory name. If COPY-CONTENTS is non-nil,
5548 ;; is nil, copy into NEWNAME/[DIRECTORY-BASENAME]. 5550 ;; create NEWNAME if it is not already a directory;
5549 ((not copy-contents) 5551 ;; otherwise, create NEWNAME/[DIRECTORY-BASENAME].
5550 (setq newname (concat newname 5552 ((if copy-contents
5551 (file-name-nondirectory directory))) 5553 (or parents (not (file-directory-p newname)))
5552 (and (file-exists-p newname) 5554 (setq newname (concat newname
5553 (not (file-directory-p newname)) 5555 (file-name-nondirectory directory))))
5554 (error "Cannot overwrite non-directory %s with a directory" 5556 (make-directory (directory-file-name newname) parents)))
5555 newname))
5556 (make-directory newname t)))
5557 5557
5558 ;; Copy recursively. 5558 ;; Copy recursively.
5559 (dolist (file 5559 (dolist (file
@@ -5565,7 +5565,7 @@ into NEWNAME instead."
5565 (filetype (car (file-attributes file)))) 5565 (filetype (car (file-attributes file))))
5566 (cond 5566 (cond
5567 ((eq filetype t) ; Directory but not a symlink. 5567 ((eq filetype t) ; Directory but not a symlink.
5568 (copy-directory file newname keep-time parents)) 5568 (copy-directory file target keep-time parents t))
5569 ((stringp filetype) ; Symbolic link 5569 ((stringp filetype) ; Symbolic link
5570 (make-symbolic-link filetype target t)) 5570 (make-symbolic-link filetype target t))
5571 ((copy-file file target t keep-time))))) 5571 ((copy-file file target t keep-time)))))
diff --git a/lisp/frame.el b/lisp/frame.el
index 5f0e97d5b07..76c1842455c 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -604,11 +604,12 @@ new frame."
604 (select-frame (make-frame)))) 604 (select-frame (make-frame))))
605 605
606(defvar before-make-frame-hook nil 606(defvar before-make-frame-hook nil
607 "Functions to run before a frame is created.") 607 "Functions to run before `make-frame' creates a new frame.")
608 608
609(defvar after-make-frame-functions nil 609(defvar after-make-frame-functions nil
610 "Functions to run after a frame is created. 610 "Functions to run after `make-frame' created a new frame.
611The functions are run with one arg, the newly created frame.") 611The functions are run with one argument, the newly created
612frame.")
612 613
613(defvar after-setting-font-hook nil 614(defvar after-setting-font-hook nil
614 "Functions to run after a frame's font has been changed.") 615 "Functions to run after a frame's font has been changed.")
@@ -617,7 +618,7 @@ The functions are run with one arg, the newly created frame.")
617(define-obsolete-function-alias 'new-frame 'make-frame "22.1") 618(define-obsolete-function-alias 'new-frame 'make-frame "22.1")
618 619
619(defvar frame-inherited-parameters '() 620(defvar frame-inherited-parameters '()
620 "Parameters `make-frame' copies from the `selected-frame' to the new frame.") 621 "Parameters `make-frame' copies from the selected to the new frame.")
621 622
622(defvar x-display-name) 623(defvar x-display-name)
623 624
@@ -632,9 +633,6 @@ form (NAME . VALUE), for example:
632 (width . NUMBER) The frame should be NUMBER characters in width. 633 (width . NUMBER) The frame should be NUMBER characters in width.
633 (height . NUMBER) The frame should be NUMBER text lines high. 634 (height . NUMBER) The frame should be NUMBER text lines high.
634 635
635You cannot specify either `width' or `height', you must specify
636neither or both.
637
638 (minibuffer . t) The frame should have a minibuffer. 636 (minibuffer . t) The frame should have a minibuffer.
639 (minibuffer . nil) The frame should have no minibuffer. 637 (minibuffer . nil) The frame should have no minibuffer.
640 (minibuffer . only) The frame should contain only a minibuffer. 638 (minibuffer . only) The frame should contain only a minibuffer.
@@ -650,10 +648,10 @@ neither or both.
650In addition, any parameter specified in `default-frame-alist', 648In addition, any parameter specified in `default-frame-alist',
651but not present in PARAMETERS, is applied. 649but not present in PARAMETERS, is applied.
652 650
653Before creating the frame (via `frame-creation-function-alist'), 651Before creating the frame (via `frame-creation-function'), this
654this function runs the hook `before-make-frame-hook'. After 652function runs the hook `before-make-frame-hook'. After creating
655creating the frame, it runs the hook `after-make-frame-functions' 653the frame, it runs the hook `after-make-frame-functions' with one
656with one arg, the newly created frame. 654argument, the newly created frame.
657 655
658If a display parameter is supplied and a window-system is not, 656If a display parameter is supplied and a window-system is not,
659guess the window-system from the display. 657guess the window-system from the display.
diff --git a/lisp/frameset.el b/lisp/frameset.el
index 661f0aee273..593451a4d75 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -447,7 +447,7 @@ DO NOT MODIFY. See `frameset-filter-alist' for a full description.")
447 (buffer-predicate . :never) 447 (buffer-predicate . :never)
448 (buried-buffer-list . :never) 448 (buried-buffer-list . :never)
449 (delete-before . :never) 449 (delete-before . :never)
450 (font . frameset-filter-shelve-param) 450 (font . frameset-filter-font-param)
451 (foreground-color . frameset-filter-sanitize-color) 451 (foreground-color . frameset-filter-sanitize-color)
452 (fullscreen . frameset-filter-shelve-param) 452 (fullscreen . frameset-filter-shelve-param)
453 (GUI:font . frameset-filter-unshelve-param) 453 (GUI:font . frameset-filter-unshelve-param)
@@ -631,6 +631,17 @@ see `frameset-filter-alist'."
631 (setcdr found val) 631 (setcdr found val)
632 nil)))) 632 nil))))
633 633
634(defun frameset-filter-font-param (current filtered parameters saving
635 &optional prefix)
636 "When switching from a tty frame to a GUI frame, remove the FONT param.
637
638When switching from a GUI frame to a tty frame, behave
639as `frameset-filter-shelve-param' does."
640 (or saving
641 (if (frameset-switch-to-gui-p parameters)
642 (frameset-filter-shelve-param current filtered parameters saving
643 prefix))))
644
634(defun frameset-filter-iconified (_current _filtered parameters saving) 645(defun frameset-filter-iconified (_current _filtered parameters saving)
635 "Remove CURRENT when saving an iconified frame. 646 "Remove CURRENT when saving an iconified frame.
636This is used for positional parameters `left' and `top', which are 647This is used for positional parameters `left' and `top', which are
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 690dd28c8a4..a9e66cede16 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -991,7 +991,6 @@ are replaced:
991 %F The first name if present, e.g.: \"John\", else fall 991 %F The first name if present, e.g.: \"John\", else fall
992 back to the mail address. 992 back to the mail address.
993 %L The last name if present, e.g.: \"Doe\". 993 %L The last name if present, e.g.: \"Doe\".
994 %Z, %z The time zone in the numeric form, e.g.:\"+0000\".
995 994
996All other format specifiers are passed to `format-time-string' 995All other format specifiers are passed to `format-time-string'
997which is called using the date from the article your replying to, but 996which is called using the date from the article your replying to, but
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 3f448f018a4..169d2632f4f 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1916,6 +1916,34 @@ CLICK position, kill the secondary selection."
1916 (> (length str) 0) 1916 (> (length str) 0)
1917 (gui-set-selection 'SECONDARY str)))) 1917 (gui-set-selection 'SECONDARY str))))
1918 1918
1919(defun secondary-selection-exist-p ()
1920 "Return non-nil if the secondary selection exists in the current buffer."
1921 (memq mouse-secondary-overlay (overlays-in (point-min) (point-max))))
1922
1923(defun secondary-selection-to-region ()
1924 "Set beginning and end of the region to those of the secondary selection.
1925This puts mark and point at the beginning and the end of the
1926secondary selection, respectively. This works when the secondary
1927selection exists and the region does not exist in current buffer;
1928the secondary selection will be deleted afterward.
1929If the region is active, or the secondary selection doesn't exist,
1930this function does nothing."
1931 (when (and (not (region-active-p))
1932 (secondary-selection-exist-p))
1933 (let ((beg (overlay-start mouse-secondary-overlay))
1934 (end (overlay-end mouse-secondary-overlay)))
1935 (push-mark beg t t)
1936 (goto-char end))
1937 ;; Delete the secondary selection on current buffer.
1938 (delete-overlay mouse-secondary-overlay)))
1939
1940(defun secondary-selection-from-region ()
1941 "Set beginning and end of the secondary selection to those of the region.
1942When there is no region, this function does nothing."
1943 (when (region-active-p) ; Create the secondary selection from the region.
1944 (delete-overlay mouse-secondary-overlay) ; Delete the secondary selection even on a different buffer.
1945 (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
1946
1919 1947
1920(defcustom mouse-buffer-menu-maxlen 20 1948(defcustom mouse-buffer-menu-maxlen 20
1921 "Number of buffers in one pane (submenu) of the buffer menu. 1949 "Number of buffers in one pane (submenu) of the buffer menu.
diff --git a/lisp/mwheel.el b/lisp/mwheel.el
index 2956ba55162..0c0dcb3beb1 100644
--- a/lisp/mwheel.el
+++ b/lisp/mwheel.el
@@ -232,6 +232,7 @@ non-Windows systems."
232 ;; When the double-mouse-N comes in, a mouse-N has been executed already, 232 ;; When the double-mouse-N comes in, a mouse-N has been executed already,
233 ;; So by adding things up we get a squaring up (1, 3, 6, 10, 15, ...). 233 ;; So by adding things up we get a squaring up (1, 3, 6, 10, 15, ...).
234 (setq amt (* amt (event-click-count event)))) 234 (setq amt (* amt (event-click-count event))))
235 (when (numberp amt) (setq amt (* amt (event-line-count event))))
235 (unwind-protect 236 (unwind-protect
236 (let ((button (mwheel-event-button event))) 237 (let ((button (mwheel-event-button event)))
237 (cond ((eq button mouse-wheel-down-event) 238 (cond ((eq button mouse-wheel-down-event)
diff --git a/lisp/net/mailcap.el b/lisp/net/mailcap.el
index ed35c220ec5..86587466ef5 100644
--- a/lisp/net/mailcap.el
+++ b/lisp/net/mailcap.el
@@ -165,9 +165,13 @@ is consulted."
165 (type . "application/zip") 165 (type . "application/zip")
166 ("copiousoutput")) 166 ("copiousoutput"))
167 ("pdf" 167 ("pdf"
168 (viewer . pdf-view-mode)
169 (type . "application/pdf")
170 (test . window-system))
171 ("pdf"
168 (viewer . doc-view-mode) 172 (viewer . doc-view-mode)
169 (type . "application/pdf") 173 (type . "application/pdf")
170 (test . (eq window-system 'x))) 174 (test . window-system))
171 ("pdf" 175 ("pdf"
172 (viewer . "gv -safer %s") 176 (viewer . "gv -safer %s")
173 (type . "application/pdf") 177 (type . "application/pdf")
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index c22869d2cc2..760d020f672 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -740,7 +740,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
740 740
741 ;; Remote newname. 741 ;; Remote newname.
742 (when (and (file-directory-p newname) 742 (when (and (file-directory-p newname)
743 (directory-name-p newname)) 743 (tramp-compat-directory-name-p newname))
744 (setq newname 744 (setq newname
745 (expand-file-name 745 (expand-file-name
746 (file-name-nondirectory filename) newname))) 746 (file-name-nondirectory filename) newname)))
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index 5d9a1fd1967..214ad040a17 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -23,8 +23,9 @@
23 23
24;;; Commentary: 24;;; Commentary:
25 25
26;; Tramp's main Emacs version for development is Emacs 26. This 26;; Tramp's main Emacs version for development is Emacs 27. This
27;; package provides compatibility functions for Emacs 24 and Emacs 25. 27;; package provides compatibility functions for Emacs 24, Emacs 25 and
28;; Emacs 26.
28 29
29;;; Code: 30;;; Code:
30 31
@@ -104,6 +105,10 @@ Add the extension of F, if existing."
104 'tramp-error vec-or-proc 105 'tramp-error vec-or-proc
105 (if (fboundp 'user-error) 'user-error 'error) format args)) 106 (if (fboundp 'user-error) 'user-error 'error) format args))
106 107
108;; `default-toplevel-value' has been declared in Emacs 24.4.
109(unless (fboundp 'default-toplevel-value)
110 (defalias 'default-toplevel-value 'symbol-value))
111
107;; `file-attribute-*' are introduced in Emacs 25.1. 112;; `file-attribute-*' are introduced in Emacs 25.1.
108 113
109(if (fboundp 'file-attribute-type) 114(if (fboundp 'file-attribute-type)
@@ -163,14 +168,23 @@ This is a floating point number if the size is too large for an integer."
163This is a string of ten letters or dashes as in ls -l." 168This is a string of ten letters or dashes as in ls -l."
164 (nth 8 attributes))) 169 (nth 8 attributes)))
165 170
166;; `default-toplevel-value' has been declared in Emacs 24.4.
167(unless (fboundp 'default-toplevel-value)
168 (defalias 'default-toplevel-value 'symbol-value))
169
170;; `format-message' is new in Emacs 25.1. 171;; `format-message' is new in Emacs 25.1.
171(unless (fboundp 'format-message) 172(unless (fboundp 'format-message)
172 (defalias 'format-message 'format)) 173 (defalias 'format-message 'format))
173 174
175;; `directory-name-p' is new in Emacs 25.1.
176(if (fboundp 'directory-name-p)
177 (defalias 'tramp-compat-directory-name-p 'directory-name-p)
178 (defsubst tramp-compat-directory-name-p (name)
179 "Return non-nil if NAME ends with a directory separator character."
180 (let ((len (length name))
181 (lastc ?.))
182 (if (> len 0)
183 (setq lastc (aref name (1- len))))
184 (or (= lastc ?/)
185 (and (memq system-type '(windows-nt ms-dos))
186 (= lastc ?\\))))))
187
174;; `file-missing' is introduced in Emacs 26.1. 188;; `file-missing' is introduced in Emacs 26.1.
175(defconst tramp-file-missing 189(defconst tramp-file-missing
176 (if (get 'file-missing 'error-conditions) 'file-missing 'file-error) 190 (if (get 'file-missing 'error-conditions) 'file-missing 'file-error)
@@ -221,13 +235,6 @@ If NAME is a remote file name, the local part of NAME is unquoted."
221 ((eq tramp-syntax 'sep) 'separate) 235 ((eq tramp-syntax 'sep) 'separate)
222 (t tramp-syntax))) 236 (t tramp-syntax)))
223 237
224;; Older Emacsen keep incompatible autoloaded values of `tramp-syntax'.
225(eval-after-load 'tramp
226 '(unless
227 (memq tramp-syntax (tramp-compat-funcall (quote tramp-syntax-values)))
228 (tramp-compat-funcall
229 (quote tramp-change-syntax) (tramp-compat-tramp-syntax))))
230
231(provide 'tramp-compat) 238(provide 'tramp-compat)
232 239
233;;; TODO: 240;;; TODO:
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 7df5aa3b7b0..a744a53ca42 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -613,7 +613,7 @@ use Cwd \"realpath\";
613 613
614sub myrealpath { 614sub myrealpath {
615 my ($file) = @_; 615 my ($file) = @_;
616 return realpath($file) if -e $file; 616 return realpath($file) if (-e $file || -l $file);
617} 617}
618 618
619sub recursive { 619sub recursive {
@@ -1139,12 +1139,7 @@ component is used as the target of the symlink."
1139 (tramp-shell-quote-argument localname))) 1139 (tramp-shell-quote-argument localname)))
1140 (with-current-buffer (tramp-get-connection-buffer v) 1140 (with-current-buffer (tramp-get-connection-buffer v)
1141 (goto-char (point-min)) 1141 (goto-char (point-min))
1142 (setq result (buffer-substring (point-min) (point-at-eol)))) 1142 (setq result (buffer-substring (point-min) (point-at-eol)))))
1143 (when (and (file-symlink-p filename)
1144 (string-equal result localname))
1145 (tramp-error
1146 v 'file-error
1147 "Apparent cycle of symbolic links for %s" filename)))
1148 1143
1149 ;; Use Perl implementation. 1144 ;; Use Perl implementation.
1150 ((and (tramp-get-remote-perl v) 1145 ((and (tramp-get-remote-perl v)
@@ -1198,16 +1193,6 @@ component is used as the target of the symlink."
1198 (setq numchase (1+ numchase)) 1193 (setq numchase (1+ numchase))
1199 (when (file-name-absolute-p symlink-target) 1194 (when (file-name-absolute-p symlink-target)
1200 (setq result nil)) 1195 (setq result nil))
1201 ;; If the symlink was absolute, we'll get a
1202 ;; string like "/user@host:/some/target";
1203 ;; extract the "/some/target" part from it.
1204 (when (tramp-tramp-file-p symlink-target)
1205 (unless (tramp-equal-remote filename symlink-target)
1206 (tramp-error
1207 v 'file-error
1208 "Symlink target `%s' on wrong host"
1209 symlink-target))
1210 (setq symlink-target localname))
1211 (setq steps 1196 (setq steps
1212 (append 1197 (append
1213 (split-string symlink-target "/" 'omit) steps))) 1198 (split-string symlink-target "/" 'omit) steps)))
@@ -1226,6 +1211,13 @@ component is used as the target of the symlink."
1226 "/")) 1211 "/"))
1227 (when (string= "" result) 1212 (when (string= "" result)
1228 (setq result "/"))))) 1213 (setq result "/")))))
1214
1215 ;; Detect cycle.
1216 (when (and (file-symlink-p filename)
1217 (string-equal result localname))
1218 (tramp-error
1219 v 'file-error
1220 "Apparent cycle of symbolic links for %s" filename))
1229 ;; If the resulting localname looks remote, we must quote it 1221 ;; If the resulting localname looks remote, we must quote it
1230 ;; for security reasons. 1222 ;; for security reasons.
1231 (when (or quoted (file-remote-p result)) 1223 (when (or quoted (file-remote-p result))
@@ -1985,7 +1977,7 @@ tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'"
1985 ;; scp or rsync DTRT. 1977 ;; scp or rsync DTRT.
1986 (progn 1978 (progn
1987 (when (and (file-directory-p newname) 1979 (when (and (file-directory-p newname)
1988 (not (directory-name-p newname))) 1980 (not (tramp-compat-directory-name-p newname)))
1989 (tramp-error v 'file-already-exists newname)) 1981 (tramp-error v 'file-already-exists newname))
1990 (setq dirname (directory-file-name (expand-file-name dirname)) 1982 (setq dirname (directory-file-name (expand-file-name dirname))
1991 newname (directory-file-name (expand-file-name newname))) 1983 newname (directory-file-name (expand-file-name newname)))
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 49695666707..35aa8110946 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -415,7 +415,7 @@ pass to the OPERATION."
415 (with-tramp-progress-reporter 415 (with-tramp-progress-reporter
416 v 0 (format "Copying %s to %s" dirname newname) 416 v 0 (format "Copying %s to %s" dirname newname)
417 (when (and (file-directory-p newname) 417 (when (and (file-directory-p newname)
418 (not (directory-name-p newname))) 418 (not (tramp-compat-directory-name-p newname)))
419 (tramp-error v 'file-already-exists newname)) 419 (tramp-error v 'file-already-exists newname))
420 (cond 420 (cond
421 ;; We must use a local temporary directory. 421 ;; We must use a local temporary directory.
@@ -535,7 +535,7 @@ pass to the OPERATION."
535 ;; Reset the transfer process properties. 535 ;; Reset the transfer process properties.
536 (tramp-set-connection-property v "process-name" nil) 536 (tramp-set-connection-property v "process-name" nil)
537 (tramp-set-connection-property v "process-buffer" nil) 537 (tramp-set-connection-property v "process-buffer" nil)
538 (when t1 (delete-directory tmpdir 'recurse)))) 538 (when t1 (delete-directory tmpdir 'recursive))))
539 539
540 ;; Handle KEEP-DATE argument. 540 ;; Handle KEEP-DATE argument.
541 (when keep-date 541 (when keep-date
@@ -586,7 +586,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
586 586
587 ;; Remote newname. 587 ;; Remote newname.
588 (when (and (file-directory-p newname) 588 (when (and (file-directory-p newname)
589 (directory-name-p newname)) 589 (tramp-compat-directory-name-p newname))
590 (setq newname 590 (setq newname
591 (expand-file-name (file-name-nondirectory filename) newname))) 591 (expand-file-name (file-name-nondirectory filename) newname)))
592 592
@@ -1583,6 +1583,10 @@ If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"."
1583 "Read entries which match DIRECTORY. 1583 "Read entries which match DIRECTORY.
1584Either the shares are listed, or the `dir' command is executed. 1584Either the shares are listed, or the `dir' command is executed.
1585Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)." 1585Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)."
1586 ;; If CIFS capabilities are enabled, symlinks are not listed
1587 ;; by `dir'. This is a consequence of
1588 ;; <https://www.samba.org/samba/news/symlink_attack.html>. See also
1589 ;; <https://bugzilla.samba.org/show_bug.cgi?id=5116>.
1586 (with-parsed-tramp-file-name (file-name-as-directory directory) nil 1590 (with-parsed-tramp-file-name (file-name-as-directory directory) nil
1587 (setq localname (or localname "/")) 1591 (setq localname (or localname "/"))
1588 (with-tramp-file-property v localname "file-entries" 1592 (with-tramp-file-property v localname "file-entries"
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 45776078be3..3573eeb7d49 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -3169,7 +3169,7 @@ User is always nil."
3169 3169
3170(defun tramp-handle-file-truename (filename) 3170(defun tramp-handle-file-truename (filename)
3171 "Like `file-truename' for Tramp files." 3171 "Like `file-truename' for Tramp files."
3172 (let ((result filename) 3172 (let ((result (expand-file-name filename))
3173 (numchase 0) 3173 (numchase 0)
3174 ;; Don't make the following value larger than 3174 ;; Don't make the following value larger than
3175 ;; necessary. People expect an error message in a 3175 ;; necessary. People expect an error message in a
@@ -3180,7 +3180,7 @@ User is always nil."
3180 symlink-target) 3180 symlink-target)
3181 (format 3181 (format
3182 "%s%s" 3182 "%s%s"
3183 (with-parsed-tramp-file-name (expand-file-name result) v1 3183 (with-parsed-tramp-file-name result v1
3184 (with-tramp-file-property v1 v1-localname "file-truename" 3184 (with-tramp-file-property v1 v1-localname "file-truename"
3185 (while (and (setq symlink-target (file-symlink-p result)) 3185 (while (and (setq symlink-target (file-symlink-p result))
3186 (< numchase numchase-limit)) 3186 (< numchase numchase-limit))
@@ -3850,7 +3850,7 @@ Erase echoed commands if exists."
3850 (min (+ (point-min) tramp-echo-mark-marker-length) 3850 (min (+ (point-min) tramp-echo-mark-marker-length)
3851 (point-max)))))) 3851 (point-max))))))
3852 ;; No echo to be handled, now we can look for the regexp. 3852 ;; No echo to be handled, now we can look for the regexp.
3853 ;; Sometimes, lines are much to long, and we run into a "Stack 3853 ;; Sometimes, lines are much too long, and we run into a "Stack
3854 ;; overflow in regexp matcher". For example, //DIRED// lines of 3854 ;; overflow in regexp matcher". For example, //DIRED// lines of
3855 ;; directory listings with some thousand files. Therefore, we 3855 ;; directory listings with some thousand files. Therefore, we
3856 ;; look from the end. 3856 ;; look from the end.
@@ -4547,16 +4547,23 @@ Only works for Bourne-like shells."
4547 (t process))) 4547 (t process)))
4548 pid) 4548 pid)
4549 ;; If it's a Tramp process, send the INT signal remotely. 4549 ;; If it's a Tramp process, send the INT signal remotely.
4550 (when (and (processp proc) (process-live-p proc) 4550 (when (and (processp proc) (setq pid (process-get proc 'remote-pid)))
4551 (setq pid (process-get proc 'remote-pid))) 4551 (if (not (process-live-p proc))
4552 (tramp-message proc 5 "Interrupt process %s with pid %s" proc pid) 4552 (tramp-error proc 'error "Process %s is not active" proc)
4553 ;; This is for tramp-sh.el. Other backends do not support this (yet). 4553 (tramp-message proc 5 "Interrupt process %s with pid %s" proc pid)
4554 (tramp-compat-funcall 4554 ;; This is for tramp-sh.el. Other backends do not support this (yet).
4555 'tramp-send-command 4555 (tramp-compat-funcall
4556 (tramp-get-connection-property proc "vector" nil) 4556 'tramp-send-command
4557 (format "kill -2 %d" pid)) 4557 (tramp-get-connection-property proc "vector" nil)
4558 ;; Report success. 4558 (format "kill -2 %d" pid))
4559 proc))) 4559 ;; Wait, until the process has disappeared.
4560 (with-timeout
4561 (1 (tramp-error proc 'error "Process %s did not interrupt" proc))
4562 (while (process-live-p proc)
4563 ;; We cannot run `tramp-accept-process-output', it blocks timers.
4564 (accept-process-output proc 0.1)))
4565 ;; Report success.
4566 proc))))
4560 4567
4561;; `interrupt-process-functions' exists since Emacs 26.1. 4568;; `interrupt-process-functions' exists since Emacs 26.1.
4562(when (boundp 'interrupt-process-functions) 4569(when (boundp 'interrupt-process-functions)
diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el
index 91222bd7817..318e3351237 100644
--- a/lisp/net/trampver.el
+++ b/lisp/net/trampver.el
@@ -7,7 +7,7 @@
7;; Maintainer: Michael Albinus <michael.albinus@gmx.de> 7;; Maintainer: Michael Albinus <michael.albinus@gmx.de>
8;; Keywords: comm, processes 8;; Keywords: comm, processes
9;; Package: tramp 9;; Package: tramp
10;; Version: 2.3.3-pre 10;; Version: 2.3.3.26.1
11 11
12;; This file is part of GNU Emacs. 12;; This file is part of GNU Emacs.
13 13
@@ -33,7 +33,7 @@
33;; should be changed only there. 33;; should be changed only there.
34 34
35;;;###tramp-autoload 35;;;###tramp-autoload
36(defconst tramp-version "2.3.3-pre" 36(defconst tramp-version "2.3.3.26.1"
37 "This version of Tramp.") 37 "This version of Tramp.")
38 38
39;;;###tramp-autoload 39;;;###tramp-autoload
@@ -55,7 +55,7 @@
55;; Check for Emacs version. 55;; Check for Emacs version.
56(let ((x (if (>= emacs-major-version 24) 56(let ((x (if (>= emacs-major-version 24)
57 "ok" 57 "ok"
58 (format "Tramp 2.3.3-pre is not fit for %s" 58 (format "Tramp 2.3.3.26.1 is not fit for %s"
59 (when (string-match "^.*$" (emacs-version)) 59 (when (string-match "^.*$" (emacs-version))
60 (match-string 0 (emacs-version))))))) 60 (match-string 0 (emacs-version)))))))
61 (unless (string-match "\\`ok\\'" x) (error "%s" x))) 61 (unless (string-match "\\`ok\\'" x) (error "%s" x)))
@@ -69,7 +69,8 @@
69 ("2.2.3-24.1" . "24.1") ("2.2.3-24.1" . "24.2") ("2.2.6-24.3" . "24.3") 69 ("2.2.3-24.1" . "24.1") ("2.2.3-24.1" . "24.2") ("2.2.6-24.3" . "24.3")
70 ("2.2.9-24.4" . "24.4") ("2.2.11-24.5" . "24.5") 70 ("2.2.9-24.4" . "24.4") ("2.2.11-24.5" . "24.5")
71 ("2.2.13.25.1" . "25.1") ("2.2.13.25.2" . "25.2") 71 ("2.2.13.25.1" . "25.1") ("2.2.13.25.2" . "25.2")
72 ("2.2.13.25.2" . "25.3"))) 72 ("2.2.13.25.2" . "25.3")
73 ("2.3.3.26.1" . "26.1")))
73 74
74(add-hook 'tramp-unload-hook 75(add-hook 'tramp-unload-hook
75 (lambda () 76 (lambda ()
diff --git a/lisp/org/ChangeLog.1 b/lisp/org/ChangeLog.1
index 366a3ee9fcd..ee50f6fb040 100644
--- a/lisp/org/ChangeLog.1
+++ b/lisp/org/ChangeLog.1
@@ -5015,10 +5015,10 @@
5015 * ox-latex.el (org-latex-listings): Update docstring. 5015 * ox-latex.el (org-latex-listings): Update docstring.
5016 5016
5017 * org-pcomplete.el (pcomplete/org-mode/file-option/options): 5017 * org-pcomplete.el (pcomplete/org-mode/file-option/options):
5018 Apply changes to export back-end definiton. 5018 Apply changes to export back-end definition.
5019 5019
5020 * org.el (org-get-export-keywords): Apply changes to export 5020 * org.el (org-get-export-keywords): Apply changes to export
5021 back-end definiton. 5021 back-end definition.
5022 5022
5023 * ox-html.el (org-html--format-toc-headline): Make use of 5023 * ox-html.el (org-html--format-toc-headline): Make use of
5024 anonymous back-ends. 5024 anonymous back-ends.
diff --git a/lisp/progmodes/bat-mode.el b/lisp/progmodes/bat-mode.el
index f4852fe5b6b..102c3186200 100644
--- a/lisp/progmodes/bat-mode.el
+++ b/lisp/progmodes/bat-mode.el
@@ -84,11 +84,11 @@
84 . 'bat-label-face) 84 . 'bat-label-face)
85 ("\\_<\\(defined\\|set\\)\\_>[ \t]*\\(\\(\\sw\\|\\s_\\)+\\)" 85 ("\\_<\\(defined\\|set\\)\\_>[ \t]*\\(\\(\\sw\\|\\s_\\)+\\)"
86 (2 font-lock-variable-name-face)) 86 (2 font-lock-variable-name-face))
87 ("%\\(\\(\\sw\\|\\s_\\)+\\)%" 87 ("%\\([^%~ \n]+\\)%?"
88 (1 font-lock-variable-name-face)) 88 (1 font-lock-variable-name-face))
89 ("!\\(\\(\\sw\\|\\s_\\)+\\)!" ; delayed-expansion !variable! 89 ("!\\([^!%~ \n]+\\)!?" ; delayed-expansion !variable!
90 (1 font-lock-variable-name-face)) 90 (1 font-lock-variable-name-face))
91 ("%%\\(?:~[adfnpstxz]*\\(?:\\$\\(\\(?:\\sw\\|\\s_\\)+\\):\\)?\\)?\\([]!#$&-:?-[_-{}~]\\)" 91 ("%%\\(?:~[adfnpstxz]*\\(?:\\$\\(\\(?:\\sw\\|\\s_\\|_\\)+\\):\\)?\\)?\\([]!#$&-:?-[_-{}~]\\)"
92 (1 font-lock-variable-name-face nil t) ; PATH expansion 92 (1 font-lock-variable-name-face nil t) ; PATH expansion
93 (2 font-lock-variable-name-face)) ; iteration variable or positional parameter 93 (2 font-lock-variable-name-face)) ; iteration variable or positional parameter
94 ("[ =][-/]+\\(\\w+\\)" 94 ("[ =][-/]+\\(\\w+\\)"
diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
deleted file mode 100644
index df1a0750cfb..00000000000
--- a/lisp/progmodes/flymake-proc.el
+++ /dev/null
@@ -1,1100 +0,0 @@
1;;; flymake-proc.el --- Flymake for external syntax checker processes -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
4
5;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
6;; Maintainer: Leo Liu <sdl.web@gmail.com>
7;; Version: 0.3
8;; Keywords: c languages tools
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software: you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24
25;;; Commentary:
26;;
27;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.
28;;
29;; This file contains the most original implementation of flymake's
30;; main source of on-the-fly diagnostic info, the external syntax
31;; checker backend.
32;;
33;;; Bugs/todo:
34
35;; - Only uses "Makefile", not "makefile" or "GNUmakefile"
36;; (from http://bugs.debian.org/337339).
37
38;;; Code:
39
40(require 'flymake-ui)
41
42(defcustom flymake-compilation-prevents-syntax-check t
43 "If non-nil, don't start syntax check if compilation is running."
44 :group 'flymake
45 :type 'boolean)
46
47(defcustom flymake-xml-program
48 (if (executable-find "xmlstarlet") "xmlstarlet" "xml")
49 "Program to use for XML validation."
50 :type 'file
51 :group 'flymake
52 :version "24.4")
53
54(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest")
55 "Dirs where to look for master files."
56 :group 'flymake
57 :type '(repeat (string)))
58
59(defcustom flymake-master-file-count-limit 32
60 "Max number of master files to check."
61 :group 'flymake
62 :type 'integer)
63
64(defcustom flymake-allowed-file-name-masks
65 '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init)
66 ("\\.xml\\'" flymake-xml-init)
67 ("\\.html?\\'" flymake-xml-init)
68 ("\\.cs\\'" flymake-simple-make-init)
69 ("\\.p[ml]\\'" flymake-perl-init)
70 ("\\.php[345]?\\'" flymake-php-init)
71 ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup)
72 ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup)
73 ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup)
74 ("\\.tex\\'" flymake-simple-tex-init)
75 ("\\.idl\\'" flymake-simple-make-init)
76 ;; ("\\.cpp\\'" 1)
77 ;; ("\\.java\\'" 3)
78 ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'")
79 ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2))
80 ;; ("\\.idl\\'" 1)
81 ;; ("\\.odl\\'" 1)
82 ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'")
83 ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
84 ;; ("\\.tex\\'" 1)
85 )
86 "Files syntax checking is allowed for.
87This is an alist with elements of the form:
88 REGEXP [INIT [CLEANUP [NAME]]]
89REGEXP is a regular expression that matches a file name.
90INIT is the init function to use, missing means disable `flymake-mode'.
91CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'.
92NAME is the file name function to use, default `flymake-get-real-file-name'."
93 :group 'flymake
94 :type '(alist :key-type (regexp :tag "File regexp")
95 :value-type
96 (list :tag "Handler functions"
97 (choice :tag "Init function"
98 (const :tag "disable" nil)
99 function)
100 (choice :tag "Cleanup function"
101 (const :tag "flymake-simple-cleanup" nil)
102 function)
103 (choice :tag "Name function"
104 (const :tag "flymake-get-real-file-name" nil)
105 function))))
106
107(defvar flymake-processes nil
108 "List of currently active flymake processes.")
109
110(defvar-local flymake-output-residual nil)
111
112(defun flymake-get-file-name-mode-and-masks (file-name)
113 "Return the corresponding entry from `flymake-allowed-file-name-masks'."
114 (unless (stringp file-name)
115 (error "Invalid file-name"))
116 (let ((fnm flymake-allowed-file-name-masks)
117 (mode-and-masks nil))
118 (while (and (not mode-and-masks) fnm)
119 (let ((item (pop fnm)))
120 (when (string-match (car item) file-name)
121 (setq mode-and-masks item)))) ; (cdr item) may be nil
122 (setq mode-and-masks (cdr mode-and-masks))
123 (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
124 mode-and-masks))
125
126(defun flymake-proc-can-syntax-check-buffer ()
127 "Determine whether we can syntax check current buffer.
128Return nil if we cannot, non-nil if
129we can."
130 (and buffer-file-name
131 (if (flymake-get-init-function buffer-file-name) t nil)))
132
133(defun flymake-get-init-function (file-name)
134 "Return init function to be used for the file."
135 (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name))))
136 ;;(flymake-log 0 "calling %s" init-f)
137 ;;(funcall init-f (current-buffer))
138 init-f))
139
140(defun flymake-get-cleanup-function (file-name)
141 "Return cleanup function to be used for the file."
142 (or (nth 1 (flymake-get-file-name-mode-and-masks file-name))
143 'flymake-simple-cleanup))
144
145(defun flymake-get-real-file-name-function (file-name)
146 (or (nth 2 (flymake-get-file-name-mode-and-masks file-name))
147 'flymake-get-real-file-name))
148
149(defvar flymake-find-buildfile-cache (make-hash-table :test #'equal))
150
151(defun flymake-get-buildfile-from-cache (dir-name)
152 "Look up DIR-NAME in cache and return its associated value.
153If DIR-NAME is not found, return nil."
154 (gethash dir-name flymake-find-buildfile-cache))
155
156(defun flymake-add-buildfile-to-cache (dir-name buildfile)
157 "Associate DIR-NAME with BUILDFILE in the buildfile cache."
158 (puthash dir-name buildfile flymake-find-buildfile-cache))
159
160(defun flymake-clear-buildfile-cache ()
161 "Clear the buildfile cache."
162 (clrhash flymake-find-buildfile-cache))
163
164(defun flymake-find-buildfile (buildfile-name source-dir-name)
165 "Find buildfile starting from current directory.
166Buildfile includes Makefile, build.xml etc.
167Return its file name if found, or nil if not found."
168 (or (flymake-get-buildfile-from-cache source-dir-name)
169 (let* ((file (locate-dominating-file source-dir-name buildfile-name)))
170 (if file
171 (progn
172 (flymake-log 3 "found buildfile at %s" file)
173 (flymake-add-buildfile-to-cache source-dir-name file)
174 file)
175 (progn
176 (flymake-log 3 "buildfile for %s not found" source-dir-name)
177 nil)))))
178
179(defun flymake-fix-file-name (name)
180 "Replace all occurrences of `\\' with `/'."
181 (when name
182 (setq name (expand-file-name name))
183 (setq name (abbreviate-file-name name))
184 (setq name (directory-file-name name))
185 name))
186
187(defun flymake-same-files (file-name-one file-name-two)
188 "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
189Return t if so, nil if not."
190 (equal (flymake-fix-file-name file-name-one)
191 (flymake-fix-file-name file-name-two)))
192
193;; This is bound dynamically to pass a parameter to a sort predicate below
194(defvar flymake-included-file-name)
195
196(defun flymake-find-possible-master-files (file-name master-file-dirs masks)
197 "Find (by name and location) all possible master files.
198
199Name is specified by FILE-NAME and location is specified by
200MASTER-FILE-DIRS. Master files include .cpp and .c for .h.
201Files are searched for starting from the .h directory and max
202max-level parent dirs. File contents are not checked."
203 (let* ((dirs master-file-dirs)
204 (files nil)
205 (done nil))
206
207 (while (and (not done) dirs)
208 (let* ((dir (expand-file-name (car dirs) (file-name-directory file-name)))
209 (masks masks))
210 (while (and (file-exists-p dir) (not done) masks)
211 (let* ((mask (car masks))
212 (dir-files (directory-files dir t mask)))
213
214 (flymake-log 3 "dir %s, %d file(s) for mask %s"
215 dir (length dir-files) mask)
216 (while (and (not done) dir-files)
217 (when (not (file-directory-p (car dir-files)))
218 (setq files (cons (car dir-files) files))
219 (when (>= (length files) flymake-master-file-count-limit)
220 (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit)
221 (setq done t)))
222 (setq dir-files (cdr dir-files))))
223 (setq masks (cdr masks))))
224 (setq dirs (cdr dirs)))
225 (when files
226 (let ((flymake-included-file-name (file-name-nondirectory file-name)))
227 (setq files (sort files 'flymake-master-file-compare))))
228 (flymake-log 3 "found %d possible master file(s)" (length files))
229 files))
230
231(defun flymake-master-file-compare (file-one file-two)
232 "Compare two files specified by FILE-ONE and FILE-TWO.
233This function is used in sort to move most possible file names
234to the beginning of the list (File.h -> File.cpp moved to top)."
235 (and (equal (file-name-sans-extension flymake-included-file-name)
236 (file-name-base file-one))
237 (not (equal file-one file-two))))
238
239(defvar flymake-check-file-limit 8192
240 "Maximum number of chars to look at when checking possible master file.
241Nil means search the entire file.")
242
243(defun flymake-check-patch-master-file-buffer
244 (master-file-temp-buffer
245 master-file-name patched-master-file-name
246 source-file-name patched-source-file-name
247 include-dirs regexp)
248 "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
249If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
250instead of SOURCE-FILE-NAME.
251
252For example, foo.cpp is a master file if it includes foo.h.
253
254When a buffer for MASTER-FILE-NAME exists, use it as a source
255instead of reading master file from disk."
256 (let* ((source-file-nondir (file-name-nondirectory source-file-name))
257 (source-file-extension (file-name-extension source-file-nondir))
258 (source-file-nonext (file-name-sans-extension source-file-nondir))
259 (found nil)
260 (inc-name nil)
261 (search-limit flymake-check-file-limit))
262 (setq regexp
263 (format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
264 ;; Hack for tex files, where \include often excludes .tex.
265 ;; Maybe this is safe generally.
266 (if (and (> (length source-file-extension) 1)
267 (string-equal source-file-extension "tex"))
268 (format "%s\\(?:\\.%s\\)?"
269 (regexp-quote source-file-nonext)
270 (regexp-quote source-file-extension))
271 (regexp-quote source-file-nondir))))
272 (unwind-protect
273 (with-current-buffer master-file-temp-buffer
274 (if (or (not search-limit)
275 (> search-limit (point-max)))
276 (setq search-limit (point-max)))
277 (flymake-log 3 "checking %s against regexp %s"
278 master-file-name regexp)
279 (goto-char (point-min))
280 (while (and (< (point) search-limit)
281 (re-search-forward regexp search-limit t))
282 (let ((match-beg (match-beginning 1))
283 (match-end (match-end 1)))
284
285 (flymake-log 3 "found possible match for %s" source-file-nondir)
286 (setq inc-name (match-string 1))
287 (and (> (length source-file-extension) 1)
288 (string-equal source-file-extension "tex")
289 (not (string-match (format "\\.%s\\'" source-file-extension)
290 inc-name))
291 (setq inc-name (concat inc-name "." source-file-extension)))
292 (when (eq t (compare-strings
293 source-file-nondir nil nil
294 inc-name (- (length inc-name)
295 (length source-file-nondir)) nil))
296 (flymake-log 3 "inc-name=%s" inc-name)
297 (when (flymake-check-include source-file-name inc-name
298 include-dirs)
299 (setq found t)
300 ;; replace-match is not used here as it fails in
301 ;; XEmacs with 'last match not a buffer' error as
302 ;; check-includes calls replace-in-string
303 (flymake-replace-region
304 match-beg match-end
305 (file-name-nondirectory patched-source-file-name))))
306 (forward-line 1)))
307 (when found
308 (flymake-save-buffer-in-file patched-master-file-name)))
309 ;;+(flymake-log 3 "killing buffer %s"
310 ;; (buffer-name master-file-temp-buffer))
311 (kill-buffer master-file-temp-buffer))
312 ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found)
313 (when found
314 (flymake-log 2 "found master file %s" master-file-name))
315 found))
316
317;;; XXX: remove
318(defun flymake-replace-region (beg end rep)
319 "Replace text in BUFFER in region (BEG END) with REP."
320 (save-excursion
321 (goto-char end)
322 ;; Insert before deleting, so as to better preserve markers's positions.
323 (insert rep)
324 (delete-region beg end)))
325
326(defun flymake-read-file-to-temp-buffer (file-name)
327 "Insert contents of FILE-NAME into newly created temp buffer."
328 (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name))))))
329 (with-current-buffer temp-buffer
330 (insert-file-contents file-name))
331 temp-buffer))
332
333(defun flymake-copy-buffer-to-temp-buffer (buffer)
334 "Copy contents of BUFFER into newly created temp buffer."
335 (with-current-buffer
336 (get-buffer-create (generate-new-buffer-name
337 (concat "flymake:" (buffer-name buffer))))
338 (insert-buffer-substring buffer)
339 (current-buffer)))
340
341(defun flymake-check-include (source-file-name inc-name include-dirs)
342 "Check if SOURCE-FILE-NAME can be found in include path.
343Return t if it can be found via include path using INC-NAME."
344 (if (file-name-absolute-p inc-name)
345 (flymake-same-files source-file-name inc-name)
346 (while (and include-dirs
347 (not (flymake-same-files
348 source-file-name
349 (concat (file-name-directory source-file-name)
350 "/" (car include-dirs)
351 "/" inc-name))))
352 (setq include-dirs (cdr include-dirs)))
353 include-dirs))
354
355(defun flymake-find-buffer-for-file (file-name)
356 "Check if there exists a buffer visiting FILE-NAME.
357Return t if so, nil if not."
358 (let ((buffer-name (get-file-buffer file-name)))
359 (if buffer-name
360 (get-buffer buffer-name))))
361
362(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp)
363 "Save SOURCE-FILE-NAME with a different name.
364Find master file, patch and save it."
365 (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks))
366 (master-file-count (length possible-master-files))
367 (idx 0)
368 (temp-buffer nil)
369 (master-file-name nil)
370 (patched-master-file-name nil)
371 (found nil))
372
373 (while (and (not found) (< idx master-file-count))
374 (setq master-file-name (nth idx possible-master-files))
375 (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master"))
376 (if (flymake-find-buffer-for-file master-file-name)
377 (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name)))
378 (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)))
379 (setq found
380 (flymake-check-patch-master-file-buffer
381 temp-buffer
382 master-file-name
383 patched-master-file-name
384 source-file-name
385 patched-source-file-name
386 (funcall get-incl-dirs-f (file-name-directory master-file-name))
387 include-regexp))
388 (setq idx (1+ idx)))
389 (if found
390 (list master-file-name patched-master-file-name)
391 (progn
392 (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count
393 (file-name-nondirectory source-file-name))
394 nil))))
395
396(defun flymake-save-buffer-in-file (file-name)
397 "Save the entire buffer contents into file FILE-NAME.
398Create parent directories as needed."
399 (make-directory (file-name-directory file-name) 1)
400 (write-region nil nil file-name nil 566)
401 (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name))
402
403(defun flymake-process-filter (process output)
404 "Parse OUTPUT and highlight error lines.
405It's flymake process filter."
406 (let ((source-buffer (process-buffer process)))
407
408 (flymake-log 3 "received %d byte(s) of output from process %d"
409 (length output) (process-id process))
410 (when (buffer-live-p source-buffer)
411 (with-current-buffer source-buffer
412 (flymake-parse-output-and-residual output)))))
413
414(defun flymake-process-sentinel (process _event)
415 "Sentinel for syntax check buffers."
416 (when (memq (process-status process) '(signal exit))
417 (let* ((exit-status (process-exit-status process))
418 (command (process-command process))
419 (source-buffer (process-buffer process))
420 (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer))))
421
422 (flymake-log 2 "process %d exited with code %d"
423 (process-id process) exit-status)
424 (condition-case err
425 (progn
426 (flymake-log 3 "cleaning up using %s" cleanup-f)
427 (when (buffer-live-p source-buffer)
428 (with-current-buffer source-buffer
429 (funcall cleanup-f)))
430
431 (delete-process process)
432 (setq flymake-processes (delq process flymake-processes))
433
434 (when (buffer-live-p source-buffer)
435 (with-current-buffer source-buffer
436
437 (flymake-parse-residual)
438 (flymake-post-syntax-check exit-status command)
439 (setq flymake-is-running nil))))
440 (error
441 (let ((err-str (format "Error in process sentinel for buffer %s: %s"
442 source-buffer (error-message-string err))))
443 (flymake-log 0 err-str)
444 (with-current-buffer source-buffer
445 (setq flymake-is-running nil))))))))
446
447(defun flymake-post-syntax-check (exit-status command)
448 (save-restriction
449 (widen)
450 (setq flymake-err-info flymake-new-err-info)
451 (setq flymake-new-err-info nil)
452 (setq flymake-err-info
453 (flymake-fix-line-numbers
454 flymake-err-info 1 (count-lines (point-min) (point-max))))
455 (flymake-delete-own-overlays)
456 (flymake-highlight-err-lines flymake-err-info)
457 (let (err-count warn-count)
458 (setq err-count (flymake-get-err-count flymake-err-info "e"))
459 (setq warn-count (flymake-get-err-count flymake-err-info "w"))
460 (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)"
461 (buffer-name) err-count warn-count
462 (- (float-time) flymake-check-start-time))
463 (setq flymake-check-start-time nil)
464
465 (if (and (equal 0 err-count) (equal 0 warn-count))
466 (if (equal 0 exit-status)
467 (flymake-report-status "" "") ; PASSED
468 (if (not flymake-check-was-interrupted)
469 (flymake-report-fatal-status "CFGERR"
470 (format "Configuration error has occurred while running %s" command))
471 (flymake-report-status nil ""))) ; "STOPPED"
472 (flymake-report-status (format "%d/%d" err-count warn-count) "")))))
473
474(defun flymake-parse-output-and-residual (output)
475 "Split OUTPUT into lines, merge in residual if necessary."
476 (let* ((buffer-residual flymake-output-residual)
477 (total-output (if buffer-residual (concat buffer-residual output) output))
478 (lines-and-residual (flymake-split-output total-output))
479 (lines (nth 0 lines-and-residual))
480 (new-residual (nth 1 lines-and-residual)))
481 (setq flymake-output-residual new-residual)
482 (setq flymake-new-err-info
483 (flymake-parse-err-lines
484 flymake-new-err-info lines))))
485
486(defun flymake-parse-residual ()
487 "Parse residual if it's non empty."
488 (when flymake-output-residual
489 (setq flymake-new-err-info
490 (flymake-parse-err-lines
491 flymake-new-err-info
492 (list flymake-output-residual)))
493 (setq flymake-output-residual nil)))
494
495(defun flymake-fix-line-numbers (err-info-list min-line max-line)
496 "Replace line numbers with fixed value.
497If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE.
498If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE.
499The reason for this fix is because some compilers might report
500line number outside the file being compiled."
501 (let* ((count (length err-info-list))
502 (err-info nil)
503 (line 0))
504 (while (> count 0)
505 (setq err-info (nth (1- count) err-info-list))
506 (setq line (flymake-er-get-line err-info))
507 (when (or (< line min-line) (> line max-line))
508 (setq line (if (< line min-line) min-line max-line))
509 (setq err-info-list (flymake-set-at err-info-list (1- count)
510 (flymake-er-make-er line
511 (flymake-er-get-line-err-info-list err-info)))))
512 (setq count (1- count))))
513 err-info-list)
514
515(defun flymake-parse-err-lines (err-info-list lines)
516 "Parse err LINES, store info in ERR-INFO-LIST."
517 (let* ((count (length lines))
518 (idx 0)
519 (line-err-info nil)
520 (real-file-name nil)
521 (source-file-name buffer-file-name)
522 (get-real-file-name-f (flymake-get-real-file-name-function source-file-name)))
523
524 (while (< idx count)
525 (setq line-err-info (flymake-parse-line (nth idx lines)))
526 (when line-err-info
527 (setq real-file-name (funcall get-real-file-name-f
528 (flymake-ler-file line-err-info)))
529 (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name))
530
531 (when (flymake-same-files real-file-name source-file-name)
532 (setq line-err-info (flymake-ler-set-file line-err-info nil))
533 (setq err-info-list (flymake-add-err-info err-info-list line-err-info))))
534 (flymake-log 3 "parsed `%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no"))
535 (setq idx (1+ idx)))
536 err-info-list))
537
538(defun flymake-split-output (output)
539 "Split OUTPUT into lines.
540Return last one as residual if it does not end with newline char.
541Returns ((LINES) RESIDUAL)."
542 (when (and output (> (length output) 0))
543 (let* ((lines (split-string output "[\n\r]+" t))
544 (complete (equal "\n" (char-to-string (aref output (1- (length output))))))
545 (residual nil))
546 (when (not complete)
547 (setq residual (car (last lines)))
548 (setq lines (butlast lines)))
549 (list lines residual))))
550
551(defun flymake-reformat-err-line-patterns-from-compile-el (original-list)
552 "Grab error line patterns from ORIGINAL-LIST in compile.el format.
553Convert it to flymake internal format."
554 (let* ((converted-list '()))
555 (dolist (item original-list)
556 (setq item (cdr item))
557 (let ((regexp (nth 0 item))
558 (file (nth 1 item))
559 (line (nth 2 item))
560 (col (nth 3 item)))
561 (if (consp file) (setq file (car file)))
562 (if (consp line) (setq line (car line)))
563 (if (consp col) (setq col (car col)))
564
565 (when (not (functionp line))
566 (setq converted-list (cons (list regexp file line col) converted-list)))))
567 converted-list))
568
569(require 'compile)
570
571(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text
572 (append
573 '(
574 ;; MS Visual C++ 6.0
575 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
576 1 3 nil 4)
577 ;; jikes
578 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
579 1 3 nil 4)
580 ;; MS midl
581 ("midl[ ]*:[ ]*\\(command line error .*\\)"
582 nil nil nil 1)
583 ;; MS C#
584 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
585 1 3 nil 4)
586 ;; perl
587 ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
588 ;; PHP
589 ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1)
590 ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1)
591 ;; ant/javac. Note this also matches gcc warnings!
592 (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::[0-9]+\\)?:[ \t\n]*\\(.+\\)"
593 2 4 nil 5))
594 ;; compilation-error-regexp-alist)
595 (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist))
596 "Patterns for matching error/warning lines. Each pattern has the form
597\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
598Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns
599from compile.el")
600
601(define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate "24.4")
602(defvar flymake-warning-predicate "^[wW]arning"
603 "Predicate matching against error text to detect a warning.
604Takes a single argument, the error's text and should return non-nil
605if it's a warning.
606Instead of a function, it can also be a regular expression.")
607
608(defun flymake-parse-line (line)
609 "Parse LINE to see if it is an error or warning.
610Return its components if so, nil otherwise."
611 (let ((raw-file-name nil)
612 (line-no 0)
613 (err-type "e")
614 (err-text nil)
615 (patterns flymake-err-line-patterns)
616 (matched nil))
617 (while (and patterns (not matched))
618 (when (string-match (car (car patterns)) line)
619 (let* ((file-idx (nth 1 (car patterns)))
620 (line-idx (nth 2 (car patterns))))
621
622 (setq raw-file-name (if file-idx (match-string file-idx line) nil))
623 (setq line-no (if line-idx (string-to-number
624 (match-string line-idx line)) 0))
625 (setq err-text (if (> (length (car patterns)) 4)
626 (match-string (nth 4 (car patterns)) line)
627 (flymake-patch-err-text
628 (substring line (match-end 0)))))
629 (if (null err-text)
630 (setq err-text "<no error text>")
631 (when (cond ((stringp flymake-warning-predicate)
632 (string-match flymake-warning-predicate err-text))
633 ((functionp flymake-warning-predicate)
634 (funcall flymake-warning-predicate err-text)))
635 (setq err-type "w")))
636 (flymake-log
637 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s"
638 file-idx line-idx raw-file-name line-no err-text)
639 (setq matched t)))
640 (setq patterns (cdr patterns)))
641 (if matched
642 (flymake-ler-make-ler raw-file-name line-no err-type err-text)
643 ())))
644
645(defun flymake-get-project-include-dirs-imp (basedir)
646 "Include dirs for the project current file belongs to."
647 (if (flymake-get-project-include-dirs-from-cache basedir)
648 (progn
649 (flymake-get-project-include-dirs-from-cache basedir))
650 ;;else
651 (let* ((command-line (concat "make -C "
652 (shell-quote-argument basedir)
653 " DUMPVARS=INCLUDE_DIRS dumpvars"))
654 (output (shell-command-to-string command-line))
655 (lines (split-string output "\n" t))
656 (count (length lines))
657 (idx 0)
658 (inc-dirs nil))
659 (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines))))
660 (setq idx (1+ idx)))
661 (when (< idx count)
662 (let* ((inc-lines (split-string (nth idx lines) " *-I" t))
663 (inc-count (length inc-lines)))
664 (while (> inc-count 0)
665 (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines)))
666 (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs))
667 (setq inc-count (1- inc-count)))))
668 (flymake-add-project-include-dirs-to-cache basedir inc-dirs)
669 inc-dirs)))
670
671(defvar flymake-get-project-include-dirs-function #'flymake-get-project-include-dirs-imp
672 "Function used to get project include dirs, one parameter: basedir name.")
673
674(defun flymake-get-project-include-dirs (basedir)
675 (funcall flymake-get-project-include-dirs-function basedir))
676
677(defun flymake-get-system-include-dirs ()
678 "System include dirs - from the `INCLUDE' env setting."
679 (let* ((includes (getenv "INCLUDE")))
680 (if includes (split-string includes path-separator t) nil)))
681
682(defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal))
683
684(defun flymake-get-project-include-dirs-from-cache (base-dir)
685 (gethash base-dir flymake-project-include-dirs-cache))
686
687(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs)
688 (puthash base-dir include-dirs flymake-project-include-dirs-cache))
689
690(defun flymake-clear-project-include-dirs-cache ()
691 (clrhash flymake-project-include-dirs-cache))
692
693(defun flymake-get-include-dirs (base-dir)
694 "Get dirs to use when resolving local file names."
695 (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs))))
696 include-dirs))
697
698;; (defun flymake-restore-formatting ()
699;; "Remove any formatting made by flymake."
700;; )
701
702;; (defun flymake-get-program-dir (buffer)
703;; "Get dir to start program in."
704;; (unless (bufferp buffer)
705;; (error "Invalid buffer"))
706;; (with-current-buffer buffer
707;; default-directory))
708
709(defun flymake-safe-delete-file (file-name)
710 (when (and file-name (file-exists-p file-name))
711 (delete-file file-name)
712 (flymake-log 1 "deleted file %s" file-name)))
713
714(defun flymake-safe-delete-directory (dir-name)
715 (condition-case nil
716 (progn
717 (delete-directory dir-name)
718 (flymake-log 1 "deleted dir %s" dir-name))
719 (error
720 (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
721
722(defun flymake-proc-start-syntax-check ()
723 "Start syntax checking for current buffer."
724 (interactive)
725 (flymake-log 3 "flymake is running: %s" flymake-is-running)
726 (when (not flymake-is-running)
727 (when (or (not flymake-compilation-prevents-syntax-check)
728 (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP")
729 (flymake-clear-buildfile-cache)
730 (flymake-clear-project-include-dirs-cache)
731
732 (setq flymake-check-was-interrupted nil)
733
734 (let* ((source-file-name buffer-file-name)
735 (init-f (flymake-get-init-function source-file-name))
736 (cleanup-f (flymake-get-cleanup-function source-file-name))
737 (cmd-and-args (funcall init-f))
738 (cmd (nth 0 cmd-and-args))
739 (args (nth 1 cmd-and-args))
740 (dir (nth 2 cmd-and-args)))
741 (if (not cmd-and-args)
742 (progn
743 (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name)
744 (funcall cleanup-f))
745 (progn
746 (setq flymake-last-change-time nil)
747 (flymake-start-syntax-check-process cmd args dir)))))))
748
749(defun flymake-start-syntax-check-process (cmd args dir)
750 "Start syntax check process."
751 (condition-case err
752 (let* ((process
753 (let ((default-directory (or dir default-directory)))
754 (when dir
755 (flymake-log 3 "starting process on dir %s" dir))
756 (apply 'start-file-process
757 "flymake-proc" (current-buffer) cmd args))))
758 (set-process-sentinel process 'flymake-process-sentinel)
759 (set-process-filter process 'flymake-process-filter)
760 (set-process-query-on-exit-flag process nil)
761 (push process flymake-processes)
762
763 (setq flymake-is-running t)
764 (setq flymake-last-change-time nil)
765 (setq flymake-check-start-time (float-time))
766
767 (flymake-report-status nil "*")
768 (flymake-log 2 "started process %d, command=%s, dir=%s"
769 (process-id process) (process-command process)
770 default-directory)
771 process)
772 (error
773 (let* ((err-str
774 (format-message
775 "Failed to launch syntax check process `%s' with args %s: %s"
776 cmd args (error-message-string err)))
777 (source-file-name buffer-file-name)
778 (cleanup-f (flymake-get-cleanup-function source-file-name)))
779 (flymake-log 0 err-str)
780 (funcall cleanup-f)
781 (flymake-report-fatal-status "PROCERR" err-str)))))
782
783(defun flymake-kill-process (proc)
784 "Kill process PROC."
785 (kill-process proc)
786 (let* ((buf (process-buffer proc)))
787 (when (buffer-live-p buf)
788 (with-current-buffer buf
789 (setq flymake-check-was-interrupted t))))
790 (flymake-log 1 "killed process %d" (process-id proc)))
791
792(defun flymake-stop-all-syntax-checks ()
793 "Kill all syntax check processes."
794 (interactive)
795 (while flymake-processes
796 (flymake-kill-process (pop flymake-processes))))
797
798(defun flymake-compilation-is-running ()
799 (and (boundp 'compilation-in-progress)
800 compilation-in-progress))
801
802(defun flymake-compile ()
803 "Kill all flymake syntax checks, start compilation."
804 (interactive)
805 (flymake-stop-all-syntax-checks)
806 (call-interactively 'compile))
807
808;;;; general init-cleanup and helper routines
809(defun flymake-create-temp-inplace (file-name prefix)
810 (unless (stringp file-name)
811 (error "Invalid file-name"))
812 (or prefix
813 (setq prefix "flymake"))
814 (let* ((ext (file-name-extension file-name))
815 (temp-name (file-truename
816 (concat (file-name-sans-extension file-name)
817 "_" prefix
818 (and ext (concat "." ext))))))
819 (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
820 temp-name))
821
822(defun flymake-create-temp-with-folder-structure (file-name _prefix)
823 (unless (stringp file-name)
824 (error "Invalid file-name"))
825
826 (let* ((dir (file-name-directory file-name))
827 ;; Not sure what this slash-pos is all about, but I guess it's just
828 ;; trying to remove the leading / of absolute file names.
829 (slash-pos (string-match "/" dir))
830 (temp-dir (expand-file-name (substring dir (1+ slash-pos))
831 temporary-file-directory)))
832
833 (file-truename (expand-file-name (file-name-nondirectory file-name)
834 temp-dir))))
835
836(defun flymake-delete-temp-directory (dir-name)
837 "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error."
838 (let* ((temp-dir temporary-file-directory)
839 (suffix (substring dir-name (1+ (length temp-dir)))))
840
841 (while (> (length suffix) 0)
842 (setq suffix (directory-file-name suffix))
843 ;;+(flymake-log 0 "suffix=%s" suffix)
844 (flymake-safe-delete-directory
845 (file-truename (expand-file-name suffix temp-dir)))
846 (setq suffix (file-name-directory suffix)))))
847
848(defvar-local flymake-temp-source-file-name nil)
849(defvar-local flymake-master-file-name nil)
850(defvar-local flymake-temp-master-file-name nil)
851(defvar-local flymake-base-dir nil)
852
853(defun flymake-init-create-temp-buffer-copy (create-temp-f)
854 "Make a temporary copy of the current buffer, save its name in buffer data and return the name."
855 (let* ((source-file-name buffer-file-name)
856 (temp-source-file-name (funcall create-temp-f source-file-name "flymake")))
857
858 (flymake-save-buffer-in-file temp-source-file-name)
859 (setq flymake-temp-source-file-name temp-source-file-name)
860 temp-source-file-name))
861
862(defun flymake-simple-cleanup ()
863 "Do cleanup after `flymake-init-create-temp-buffer-copy'.
864Delete temp file."
865 (flymake-safe-delete-file flymake-temp-source-file-name)
866 (setq flymake-last-change-time nil))
867
868(defun flymake-get-real-file-name (file-name-from-err-msg)
869 "Translate file name from error message to \"real\" file name.
870Return full-name. Names are real, not patched."
871 (let* ((real-name nil)
872 (source-file-name buffer-file-name)
873 (master-file-name flymake-master-file-name)
874 (temp-source-file-name flymake-temp-source-file-name)
875 (temp-master-file-name flymake-temp-master-file-name)
876 (base-dirs
877 (list flymake-base-dir
878 (file-name-directory source-file-name)
879 (if master-file-name (file-name-directory master-file-name))))
880 (files (list (list source-file-name source-file-name)
881 (list temp-source-file-name source-file-name)
882 (list master-file-name master-file-name)
883 (list temp-master-file-name master-file-name))))
884
885 (when (equal 0 (length file-name-from-err-msg))
886 (setq file-name-from-err-msg source-file-name))
887
888 (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files))
889 ;; if real-name is nil, than file name from err msg is none of the files we've patched
890 (if (not real-name)
891 (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs)))
892 (if (not real-name)
893 (setq real-name file-name-from-err-msg))
894 (setq real-name (flymake-fix-file-name real-name))
895 (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name)
896 real-name))
897
898(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files)
899 (let* ((base-dirs-count (length base-dirs))
900 (file-count (length files))
901 (real-name nil))
902
903 (while (and (not real-name) (> base-dirs-count 0))
904 (setq file-count (length files))
905 (while (and (not real-name) (> file-count 0))
906 (let* ((this-dir (nth (1- base-dirs-count) base-dirs))
907 (this-file (nth 0 (nth (1- file-count) files)))
908 (this-real-name (nth 1 (nth (1- file-count) files))))
909 ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg)
910 (when (and this-dir this-file (flymake-same-files
911 (expand-file-name file-name-from-err-msg this-dir)
912 this-file))
913 (setq real-name this-real-name)))
914 (setq file-count (1- file-count)))
915 (setq base-dirs-count (1- base-dirs-count)))
916 real-name))
917
918(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
919 (let* ((real-name nil))
920 (if (file-name-absolute-p file-name-from-err-msg)
921 (setq real-name file-name-from-err-msg)
922 (let* ((base-dirs-count (length base-dirs)))
923 (while (and (not real-name) (> base-dirs-count 0))
924 (let* ((full-name (expand-file-name file-name-from-err-msg
925 (nth (1- base-dirs-count) base-dirs))))
926 (if (file-exists-p full-name)
927 (setq real-name full-name))
928 (setq base-dirs-count (1- base-dirs-count))))))
929 real-name))
930
931(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name)
932 "Find buildfile, store its dir in buffer data and return its dir, if found."
933 (let* ((buildfile-dir
934 (flymake-find-buildfile buildfile-name
935 (file-name-directory source-file-name))))
936 (if buildfile-dir
937 (setq flymake-base-dir buildfile-dir)
938 (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name)
939 (flymake-report-fatal-status
940 "NOMK" (format "No buildfile (%s) found for %s"
941 buildfile-name source-file-name)))))
942
943(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp)
944 "Find master file (or buffer), create its copy along with a copy of the source file."
945 (let* ((source-file-name buffer-file-name)
946 (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))
947 (master-and-temp-master (flymake-create-master-file
948 source-file-name temp-source-file-name
949 get-incl-dirs-f create-temp-f
950 master-file-masks include-regexp)))
951
952 (if (not master-and-temp-master)
953 (progn
954 (flymake-log 1 "cannot find master file for %s" source-file-name)
955 (flymake-report-status "!" "") ; NOMASTER
956 nil)
957 (setq flymake-master-file-name (nth 0 master-and-temp-master))
958 (setq flymake-temp-master-file-name (nth 1 master-and-temp-master)))))
959
960(defun flymake-master-cleanup ()
961 (flymake-simple-cleanup)
962 (flymake-safe-delete-file flymake-temp-master-file-name))
963
964;;;; make-specific init-cleanup routines
965(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f)
966 "Create a command line for syntax check using GET-CMD-LINE-F."
967 (funcall get-cmd-line-f
968 (if use-relative-source
969 (file-relative-name source-file-name base-dir)
970 source-file-name)
971 (if use-relative-base-dir
972 (file-relative-name base-dir
973 (file-name-directory source-file-name))
974 base-dir)))
975
976(defun flymake-get-make-cmdline (source base-dir)
977 (list "make"
978 (list "-s"
979 "-C"
980 base-dir
981 (concat "CHK_SOURCES=" source)
982 "SYNTAX_CHECK_MODE=1"
983 "check-syntax")))
984
985(defun flymake-get-ant-cmdline (source base-dir)
986 (list "ant"
987 (list "-buildfile"
988 (concat base-dir "/" "build.xml")
989 (concat "-DCHK_SOURCES=" source)
990 "check-syntax")))
991
992(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f)
993 "Create syntax check command line for a directly checked source file.
994Use CREATE-TEMP-F for creating temp copy."
995 (let* ((args nil)
996 (source-file-name buffer-file-name)
997 (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name)))
998 (if buildfile-dir
999 (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)))
1000 (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir
1001 use-relative-base-dir use-relative-source
1002 get-cmdline-f))))
1003 args))
1004
1005(defun flymake-simple-make-init ()
1006 (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline))
1007
1008(defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp)
1009 "Create make command line for a source file checked via master file compilation."
1010 (let* ((make-args nil)
1011 (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
1012 get-incl-dirs-f 'flymake-create-temp-inplace
1013 master-file-masks include-regexp)))
1014 (when temp-master-file-name
1015 (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile")))
1016 (if buildfile-dir
1017 (setq make-args (flymake-get-syntax-check-program-args
1018 temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline)))))
1019 make-args))
1020
1021(defun flymake-find-make-buildfile (source-dir)
1022 (flymake-find-buildfile "Makefile" source-dir))
1023
1024;;;; .h/make specific
1025(defun flymake-master-make-header-init ()
1026 (flymake-master-make-init
1027 'flymake-get-include-dirs
1028 '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
1029 "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
1030
1031;;;; .java/make specific
1032(defun flymake-simple-make-java-init ()
1033 (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline))
1034
1035(defun flymake-simple-ant-java-init ()
1036 (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline))
1037
1038(defun flymake-simple-java-cleanup ()
1039 "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs."
1040 (flymake-safe-delete-file flymake-temp-source-file-name)
1041 (when flymake-temp-source-file-name
1042 (flymake-delete-temp-directory
1043 (file-name-directory flymake-temp-source-file-name))))
1044
1045;;;; perl-specific init-cleanup routines
1046(defun flymake-perl-init ()
1047 (let* ((temp-file (flymake-init-create-temp-buffer-copy
1048 'flymake-create-temp-inplace))
1049 (local-file (file-relative-name
1050 temp-file
1051 (file-name-directory buffer-file-name))))
1052 (list "perl" (list "-wc " local-file))))
1053
1054;;;; php-specific init-cleanup routines
1055(defun flymake-php-init ()
1056 (let* ((temp-file (flymake-init-create-temp-buffer-copy
1057 'flymake-create-temp-inplace))
1058 (local-file (file-relative-name
1059 temp-file
1060 (file-name-directory buffer-file-name))))
1061 (list "php" (list "-f" local-file "-l"))))
1062
1063;;;; tex-specific init-cleanup routines
1064(defun flymake-get-tex-args (file-name)
1065 ;;(list "latex" (list "-c-style-errors" file-name))
1066 (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
1067
1068(defun flymake-simple-tex-init ()
1069 (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)))
1070
1071;; Perhaps there should be a buffer-local variable flymake-master-file
1072;; that people can set to override this stuff. Could inherit from
1073;; the similar AUCTeX variable.
1074(defun flymake-master-tex-init ()
1075 (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
1076 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace
1077 '("\\.tex\\'")
1078 "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}")))
1079 (when temp-master-file-name
1080 (flymake-get-tex-args temp-master-file-name))))
1081
1082(defun flymake-get-include-dirs-dot (_base-dir)
1083 '("."))
1084
1085;;;; xml-specific init-cleanup routines
1086(defun flymake-xml-init ()
1087 (list flymake-xml-program
1088 (list "val" (flymake-init-create-temp-buffer-copy
1089 'flymake-create-temp-inplace))))
1090
1091
1092;;;; Hook onto flymake-ui
1093
1094(add-to-list 'flymake-backends
1095 `(flymake-proc-can-syntax-check-buffer
1096 .
1097 flymake-proc-start-syntax-check))
1098
1099(provide 'flymake-proc)
1100;;; flymake-proc.el ends here
diff --git a/lisp/progmodes/flymake-ui.el b/lisp/progmodes/flymake-ui.el
deleted file mode 100644
index bf5218c41d2..00000000000
--- a/lisp/progmodes/flymake-ui.el
+++ /dev/null
@@ -1,634 +0,0 @@
1;;; flymake-ui.el --- A universal on-the-fly syntax checker -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
4
5;; Author: Pavel Kobyakov <pk_at_work@yahoo.com>
6;; Maintainer: Leo Liu <sdl.web@gmail.com>
7;; Version: 0.3
8;; Keywords: c languages tools
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software: you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24
25;;; Commentary:
26;;
27;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.xo
28;;
29;; This file contains the UI for displaying and interacting with the
30;; results of such checks, as well as entry points for backends to
31;; hook on to. Backends are sources of diagnostic info.
32;;
33;;; Code:
34
35(eval-when-compile (require 'cl-lib))
36
37(defgroup flymake nil
38 "Universal on-the-fly syntax checker."
39 :version "23.1"
40 :link '(custom-manual "(flymake) Top")
41 :group 'tools)
42
43(defcustom flymake-error-bitmap '(exclamation-mark error)
44 "Bitmap (a symbol) used in the fringe for indicating errors.
45The value may also be a list of two elements where the second
46element specifies the face for the bitmap. For possible bitmap
47symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'.
48
49The option `flymake-fringe-indicator-position' controls how and where
50this is used."
51 :group 'flymake
52 :version "24.3"
53 :type '(choice (symbol :tag "Bitmap")
54 (list :tag "Bitmap and face"
55 (symbol :tag "Bitmap")
56 (face :tag "Face"))))
57
58(defcustom flymake-warning-bitmap 'question-mark
59 "Bitmap (a symbol) used in the fringe for indicating warnings.
60The value may also be a list of two elements where the second
61element specifies the face for the bitmap. For possible bitmap
62symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'.
63
64The option `flymake-fringe-indicator-position' controls how and where
65this is used."
66 :group 'flymake
67 :version "24.3"
68 :type '(choice (symbol :tag "Bitmap")
69 (list :tag "Bitmap and face"
70 (symbol :tag "Bitmap")
71 (face :tag "Face"))))
72
73(defcustom flymake-fringe-indicator-position 'left-fringe
74 "The position to put flymake fringe indicator.
75The value can be nil (do not use indicators), `left-fringe' or `right-fringe'.
76See `flymake-error-bitmap' and `flymake-warning-bitmap'."
77 :group 'flymake
78 :version "24.3"
79 :type '(choice (const left-fringe)
80 (const right-fringe)
81 (const :tag "No fringe indicators" nil)))
82
83(defcustom flymake-start-syntax-check-on-newline t
84 "Start syntax check if newline char was added/removed from the buffer."
85 :group 'flymake
86 :type 'boolean)
87
88(defcustom flymake-no-changes-timeout 0.5
89 "Time to wait after last change before starting compilation."
90 :group 'flymake
91 :type 'number)
92
93(defcustom flymake-gui-warnings-enabled t
94 "Enables/disables GUI warnings."
95 :group 'flymake
96 :type 'boolean)
97(make-obsolete-variable 'flymake-gui-warnings-enabled
98 "it no longer has any effect." "26.1")
99
100(defcustom flymake-start-syntax-check-on-find-file t
101 "Start syntax check on find file."
102 :group 'flymake
103 :type 'boolean)
104
105(defcustom flymake-log-level -1
106 "Logging level, only messages with level lower or equal will be logged.
107-1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
108 :group 'flymake
109 :type 'integer)
110
111(defcustom flymake-backends '()
112 "Ordered list of backends providing syntax check information for a buffer.
113Value is an alist of conses (PREDICATE . CHECKER). Both PREDICATE
114and CHECKER are functions called with a single argument, the
115buffer in which `flymake-mode' was enabled. PREDICATE is expected
116to (quickly) return t or nil if the buffer can be syntax checked
117by CHECKER, which in can performs more morose operations,
118possibly asynchronously."
119 :group 'flymake
120 :type 'alist)
121
122(defvar-local flymake-timer nil
123 "Timer for starting syntax check.")
124
125(defvar-local flymake-last-change-time nil
126 "Time of last buffer change.")
127
128(defvar-local flymake-check-start-time nil
129 "Time at which syntax check was started.")
130
131(defvar-local flymake-check-was-interrupted nil
132 "Non-nil if syntax check was killed by `flymake-compile'.")
133
134(defvar-local flymake-err-info nil
135 "Sorted list of line numbers and lists of err info in the form (file, err-text).")
136
137(defvar-local flymake-new-err-info nil
138 "Same as `flymake-err-info', effective when a syntax check is in progress.")
139
140(defun flymake-log (level text &rest args)
141 "Log a message at level LEVEL.
142If LEVEL is higher than `flymake-log-level', the message is
143ignored. Otherwise, it is printed using `message'.
144TEXT is a format control string, and the remaining arguments ARGS
145are the string substitutions (see the function `format')."
146 (if (<= level flymake-log-level)
147 (let* ((msg (apply #'format-message text args)))
148 (message "%s" msg))))
149
150(defun flymake-ins-after (list pos val)
151 "Insert VAL into LIST after position POS.
152POS counts from zero."
153 (let ((tmp (copy-sequence list)))
154 (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp)))
155 tmp))
156
157(defun flymake-set-at (list pos val)
158 "Set VAL at position POS in LIST.
159POS counts from zero."
160 (let ((tmp (copy-sequence list)))
161 (setcar (nthcdr pos tmp) val)
162 tmp))
163
164(defun flymake-er-make-er (line-no line-err-info-list)
165 (list line-no line-err-info-list))
166
167(defun flymake-er-get-line (err-info)
168 (nth 0 err-info))
169
170(defun flymake-er-get-line-err-info-list (err-info)
171 (nth 1 err-info))
172
173(cl-defstruct (flymake-ler
174 (:constructor nil)
175 (:constructor flymake-ler-make-ler (file line type text &optional full-file)))
176 file line type text full-file)
177
178(defun flymake-ler-set-file (line-err-info file)
179 (flymake-ler-make-ler file
180 (flymake-ler-line line-err-info)
181 (flymake-ler-type line-err-info)
182 (flymake-ler-text line-err-info)
183 (flymake-ler-full-file line-err-info)))
184
185(defun flymake-ler-set-full-file (line-err-info full-file)
186 (flymake-ler-make-ler (flymake-ler-file line-err-info)
187 (flymake-ler-line line-err-info)
188 (flymake-ler-type line-err-info)
189 (flymake-ler-text line-err-info)
190 full-file))
191
192(defun flymake-ler-set-line (line-err-info line)
193 (flymake-ler-make-ler (flymake-ler-file line-err-info)
194 line
195 (flymake-ler-type line-err-info)
196 (flymake-ler-text line-err-info)
197 (flymake-ler-full-file line-err-info)))
198
199(defun flymake-get-line-err-count (line-err-info-list type)
200 "Return number of errors of specified TYPE.
201Value of TYPE is either \"e\" or \"w\"."
202 (let* ((idx 0)
203 (count (length line-err-info-list))
204 (err-count 0))
205
206 (while (< idx count)
207 (when (equal type (flymake-ler-type (nth idx line-err-info-list)))
208 (setq err-count (1+ err-count)))
209 (setq idx (1+ idx)))
210 err-count))
211
212(defun flymake-get-err-count (err-info-list type)
213 "Return number of errors of specified TYPE for ERR-INFO-LIST."
214 (let* ((idx 0)
215 (count (length err-info-list))
216 (err-count 0))
217 (while (< idx count)
218 (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type)))
219 (setq idx (1+ idx)))
220 err-count))
221
222(defun flymake-highlight-err-lines (err-info-list)
223 "Highlight error lines in BUFFER using info from ERR-INFO-LIST."
224 (save-excursion
225 (dolist (err err-info-list)
226 (flymake-highlight-line (car err) (nth 1 err)))))
227
228(defun flymake-overlay-p (ov)
229 "Determine whether overlay OV was created by flymake."
230 (and (overlayp ov) (overlay-get ov 'flymake-overlay)))
231
232(defun flymake-make-overlay (beg end tooltip-text face bitmap)
233 "Allocate a flymake overlay in range BEG and END."
234 (when (not (flymake-region-has-flymake-overlays beg end))
235 (let ((ov (make-overlay beg end nil t))
236 (fringe (and flymake-fringe-indicator-position
237 (propertize "!" 'display
238 (cons flymake-fringe-indicator-position
239 (if (listp bitmap)
240 bitmap
241 (list bitmap)))))))
242 (overlay-put ov 'face face)
243 (overlay-put ov 'help-echo tooltip-text)
244 (overlay-put ov 'flymake-overlay t)
245 (overlay-put ov 'priority 100)
246 (overlay-put ov 'evaporate t)
247 (overlay-put ov 'before-string fringe)
248 ;;+(flymake-log 3 "created overlay %s" ov)
249 ov)
250 (flymake-log 3 "created an overlay at (%d-%d)" beg end)))
251
252(defun flymake-delete-own-overlays ()
253 "Delete all flymake overlays in BUFFER."
254 (dolist (ol (overlays-in (point-min) (point-max)))
255 (when (flymake-overlay-p ol)
256 (delete-overlay ol)
257 ;;+(flymake-log 3 "deleted overlay %s" ol)
258 )))
259
260(defun flymake-region-has-flymake-overlays (beg end)
261 "Check if region specified by BEG and END has overlay.
262Return t if it has at least one flymake overlay, nil if no overlay."
263 (let ((ov (overlays-in beg end))
264 (has-flymake-overlays nil))
265 (while (consp ov)
266 (when (flymake-overlay-p (car ov))
267 (setq has-flymake-overlays t))
268 (setq ov (cdr ov)))
269 has-flymake-overlays))
270
271(defface flymake-errline
272 '((((supports :underline (:style wave)))
273 :underline (:style wave :color "Red1"))
274 (t
275 :inherit error))
276 "Face used for marking error lines."
277 :version "24.4"
278 :group 'flymake)
279
280(defface flymake-warnline
281 '((((supports :underline (:style wave)))
282 :underline (:style wave :color "DarkOrange"))
283 (t
284 :inherit warning))
285 "Face used for marking warning lines."
286 :version "24.4"
287 :group 'flymake)
288
289(defun flymake-highlight-line (line-no line-err-info-list)
290 "Highlight line LINE-NO in current buffer.
291Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting."
292 (goto-char (point-min))
293 (forward-line (1- line-no))
294 (pcase-let* ((beg (progn (back-to-indentation) (point)))
295 (end (progn
296 (end-of-line)
297 (skip-chars-backward " \t\f\t\n" beg)
298 (if (eq (point) beg)
299 (line-beginning-position 2)
300 (point))))
301 (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list "\n"))
302 (`(,face ,bitmap)
303 (if (> (flymake-get-line-err-count line-err-info-list "e") 0)
304 (list 'flymake-errline flymake-error-bitmap)
305 (list 'flymake-warnline flymake-warning-bitmap))))
306 (flymake-make-overlay beg end tooltip-text face bitmap)))
307
308(defun flymake-find-err-info (err-info-list line-no)
309 "Find (line-err-info-list pos) for specified LINE-NO."
310 (if err-info-list
311 (let* ((line-err-info-list nil)
312 (pos 0)
313 (count (length err-info-list)))
314
315 (while (and (< pos count) (< (car (nth pos err-info-list)) line-no))
316 (setq pos (1+ pos)))
317 (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no))
318 (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list))))
319 (list line-err-info-list pos))
320 '(nil 0)))
321
322(defun flymake-line-err-info-is-less-or-equal (line-one line-two)
323 (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two))
324 (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
325 (not (flymake-ler-file line-one)) (flymake-ler-file line-two))
326 (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
327 (or (and (flymake-ler-file line-one) (flymake-ler-file line-two))
328 (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two)))))))
329
330(defun flymake-add-line-err-info (line-err-info-list line-err-info)
331 "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO.
332For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'.
333The new element is inserted in the proper position, according to
334the predicate `flymake-line-err-info-is-less-or-equal'.
335The updated value of LINE-ERR-INFO-LIST is returned."
336 (if (not line-err-info-list)
337 (list line-err-info)
338 (let* ((count (length line-err-info-list))
339 (idx 0))
340 (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info))
341 (setq idx (1+ idx)))
342 (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list)))
343 (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info))))
344 line-err-info-list)))
345
346(defun flymake-add-err-info (err-info-list line-err-info)
347 "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order.
348Returns the updated value of ERR-INFO-LIST.
349For the format of ERR-INFO-LIST, see `flymake-err-info'.
350For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'."
351 (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info)))
352 (info-and-pos (flymake-find-err-info err-info-list line-no))
353 (exists (car info-and-pos))
354 (pos (nth 1 info-and-pos))
355 (line-err-info-list nil)
356 (err-info nil))
357
358 (if exists
359 (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list)))))
360 (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info))
361
362 (setq err-info (flymake-er-make-er line-no line-err-info-list))
363 (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info)))
364 ((equal 0 pos) (setq err-info-list (cons err-info err-info-list)))
365 (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info))))
366 err-info-list))
367
368(defvar-local flymake-is-running nil
369 "If t, flymake syntax check process is running for the current buffer.")
370
371(defun flymake-on-timer-event (buffer)
372 "Start a syntax check for buffer BUFFER if necessary."
373 (when (buffer-live-p buffer)
374 (with-current-buffer buffer
375 (when (and (not flymake-is-running)
376 flymake-last-change-time
377 (> (- (float-time) flymake-last-change-time)
378 flymake-no-changes-timeout))
379
380 (setq flymake-last-change-time nil)
381 (flymake-log 3 "starting syntax check as more than 1 second passed since last change")
382 (flymake--start-syntax-check)))))
383
384(define-obsolete-function-alias 'flymake-display-err-menu-for-current-line
385 'flymake-popup-current-error-menu "24.4")
386
387(defun flymake-popup-current-error-menu (&optional event)
388 "Pop up a menu with errors/warnings for current line."
389 (interactive (list last-nonmenu-event))
390 (let* ((line-no (line-number-at-pos))
391 (errors (or (car (flymake-find-err-info flymake-err-info line-no))
392 (user-error "No errors for current line")))
393 (menu (mapcar (lambda (x)
394 (if (flymake-ler-file x)
395 (cons (format "%s - %s(%d)"
396 (flymake-ler-text x)
397 (flymake-ler-file x)
398 (flymake-ler-line x))
399 x)
400 (list (flymake-ler-text x))))
401 errors))
402 (event (if (mouse-event-p event)
403 event
404 (list 'mouse-1 (posn-at-point))))
405 (title (format "Line %d: %d error(s), %d warning(s)"
406 line-no
407 (flymake-get-line-err-count errors "e")
408 (flymake-get-line-err-count errors "w")))
409 (choice (x-popup-menu event (list title (cons "" menu)))))
410 (flymake-log 3 "choice=%s" choice)
411 (when choice
412 (flymake-goto-file-and-line (flymake-ler-full-file choice)
413 (flymake-ler-line choice)))))
414
415(defun flymake-goto-file-and-line (file line)
416 "Try to get buffer for FILE and goto line LINE in it."
417 (if (not (file-exists-p file))
418 (flymake-log 1 "File %s does not exist" file)
419 (find-file file)
420 (goto-char (point-min))
421 (forward-line (1- line))))
422
423;; flymake minor mode declarations
424(defvar-local flymake-mode-line nil)
425(defvar-local flymake-mode-line-e-w nil)
426(defvar-local flymake-mode-line-status nil)
427
428(defun flymake-report-status (e-w &optional status)
429 "Show status in mode line."
430 (when e-w
431 (setq flymake-mode-line-e-w e-w))
432 (when status
433 (setq flymake-mode-line-status status))
434 (let* ((mode-line " Flymake"))
435 (when (> (length flymake-mode-line-e-w) 0)
436 (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
437 (setq mode-line (concat mode-line flymake-mode-line-status))
438 (setq flymake-mode-line mode-line)
439 (force-mode-line-update)))
440
441;; Nothing in flymake uses this at all any more, so this is just for
442;; third-party compatibility.
443(define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1")
444
445(defun flymake-report-fatal-status (status warning)
446 "Display a warning and switch flymake mode off."
447 ;; This first message was always shown by default, and flymake-log
448 ;; does nothing by default, hence the use of message.
449 ;; Another option is display-warning.
450 (if (< flymake-log-level 0)
451 (message "Flymake: %s. Flymake will be switched OFF" warning))
452 (flymake-mode 0)
453 (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s"
454 (buffer-name) status warning))
455
456(defvar-local flymake--backend nil
457 "The currently active backend selected by `flymake-mode'")
458
459(defun flymake--can-syntax-check-buffer (buffer)
460 (let ((all flymake-backends)
461 (candidate))
462 (catch 'done
463 (while (setq candidate (pop all))
464 (when (with-current-buffer buffer (funcall (car candidate)))
465 (throw 'done (cdr candidate)))))))
466
467(defun flymake--start-syntax-check ()
468 (funcall flymake--backend))
469
470;;;###autoload
471(define-minor-mode flymake-mode nil
472 :group 'flymake :lighter flymake-mode-line
473 (cond
474
475 ;; Turning the mode ON.
476 (flymake-mode
477 (let* ((backend (flymake--can-syntax-check-buffer (current-buffer))))
478 (cond
479 ((not backend)
480 (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
481 (t
482 (setq flymake--backend backend)
483
484 (add-hook 'after-change-functions 'flymake-after-change-function nil t)
485 (add-hook 'after-save-hook 'flymake-after-save-hook nil t)
486 (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)
487 ;;+(add-hook 'find-file-hook 'flymake-find-file-hook)
488
489 (flymake-report-status "" "")
490
491 (setq flymake-timer
492 (run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
493
494 (when (and flymake-start-syntax-check-on-find-file
495 ;; Since we write temp files in current dir, there's no point
496 ;; trying if the directory is read-only (bug#8954).
497 (file-writable-p (file-name-directory buffer-file-name)))
498 (with-demoted-errors
499 (flymake--start-syntax-check)))))
500 )
501 )
502
503 ;; Turning the mode OFF.
504 (t
505 (setq flymake--backend nil)
506
507 (remove-hook 'after-change-functions 'flymake-after-change-function t)
508 (remove-hook 'after-save-hook 'flymake-after-save-hook t)
509 (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t)
510 ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t)
511
512 (flymake-delete-own-overlays)
513
514 (when flymake-timer
515 (cancel-timer flymake-timer)
516 (setq flymake-timer nil))
517
518 (setq flymake-is-running nil))))
519
520;; disabling flymake-mode is safe, enabling - not necessarily so
521(put 'flymake-mode 'safe-local-variable 'null)
522
523;;;###autoload
524(defun flymake-mode-on ()
525 "Turn flymake mode on."
526 (flymake-mode 1)
527 (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name)))
528
529;;;###autoload
530(defun flymake-mode-off ()
531 "Turn flymake mode off."
532 (flymake-mode 0)
533 (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name)))
534
535(defun flymake-after-change-function (start stop _len)
536 "Start syntax check for current buffer if it isn't already running."
537 ;;+(flymake-log 0 "setting change time to %s" (float-time))
538 (let((new-text (buffer-substring start stop)))
539 (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
540 (flymake-log 3 "starting syntax check as new-line has been seen")
541 (flymake--start-syntax-check))
542 (setq flymake-last-change-time (float-time))))
543
544(defun flymake-after-save-hook ()
545 (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved?
546 (progn
547 (flymake-log 3 "starting syntax check as buffer was saved")
548 (flymake--start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???)
549
550(defun flymake-kill-buffer-hook ()
551 (when flymake-timer
552 (cancel-timer flymake-timer)
553 (setq flymake-timer nil)))
554
555;;;###autoload
556(defun flymake-find-file-hook ()
557 ;;+(when flymake-start-syntax-check-on-find-file
558 ;;+ (flymake-log 3 "starting syntax check on file open")
559 ;;+ (flymake--start-syntax-check)
560 ;;+)
561 (when (and (not (local-variable-p 'flymake-mode (current-buffer)))
562 (flymake--can-syntax-check-buffer (current-buffer)))
563 (flymake-mode)
564 (flymake-log 3 "automatically turned ON flymake mode")))
565
566(defun flymake-get-first-err-line-no (err-info-list)
567 "Return first line with error."
568 (when err-info-list
569 (flymake-er-get-line (car err-info-list))))
570
571(defun flymake-get-last-err-line-no (err-info-list)
572 "Return last line with error."
573 (when err-info-list
574 (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list))))
575
576(defun flymake-get-next-err-line-no (err-info-list line-no)
577 "Return next line with error."
578 (when err-info-list
579 (let* ((count (length err-info-list))
580 (idx 0))
581 (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list))))
582 (setq idx (1+ idx)))
583 (if (< idx count)
584 (flymake-er-get-line (nth idx err-info-list))))))
585
586(defun flymake-get-prev-err-line-no (err-info-list line-no)
587 "Return previous line with error."
588 (when err-info-list
589 (let* ((count (length err-info-list)))
590 (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list))))
591 (setq count (1- count)))
592 (if (> count 0)
593 (flymake-er-get-line (nth (1- count) err-info-list))))))
594
595(defun flymake-skip-whitespace ()
596 "Move forward until non-whitespace is reached."
597 (while (looking-at "[ \t]")
598 (forward-char)))
599
600(defun flymake-goto-line (line-no)
601 "Go to line LINE-NO, then skip whitespace."
602 (goto-char (point-min))
603 (forward-line (1- line-no))
604 (flymake-skip-whitespace))
605
606(defun flymake-goto-next-error ()
607 "Go to next error in err ring."
608 (interactive)
609 (let ((line-no (flymake-get-next-err-line-no flymake-err-info (line-number-at-pos))))
610 (when (not line-no)
611 (setq line-no (flymake-get-first-err-line-no flymake-err-info))
612 (flymake-log 1 "passed end of file"))
613 (if line-no
614 (flymake-goto-line line-no)
615 (flymake-log 1 "no errors in current buffer"))))
616
617(defun flymake-goto-prev-error ()
618 "Go to previous error in err ring."
619 (interactive)
620 (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (line-number-at-pos))))
621 (when (not line-no)
622 (setq line-no (flymake-get-last-err-line-no flymake-err-info))
623 (flymake-log 1 "passed beginning of file"))
624 (if line-no
625 (flymake-goto-line line-no)
626 (flymake-log 1 "no errors in current buffer"))))
627
628(defun flymake-patch-err-text (string)
629 (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string)
630 (match-string 1 string)
631 string))
632
633(provide 'flymake-ui)
634;;; flymake-ui.el ends here
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 059bce95eed..866116fbecd 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -24,18 +24,1629 @@
24 24
25;;; Commentary: 25;;; Commentary:
26;; 26;;
27;; Flymake is a minor Emacs mode performing on-the-fly syntax checks. 27;; Flymake is a minor Emacs mode performing on-the-fly syntax checks
28;; 28;; using the external syntax check tool (for C/C++ this is usually the
29;; It collects diagnostic information for multiple sources and 29;; compiler).
30;; visually annotates the relevant lines in the buffer. 30
31;; 31;;; Bugs/todo:
32;; This file is just a stub for that loads the UI and backends, which 32
33;; could also be loaded separately. 33;; - Only uses "Makefile", not "makefile" or "GNUmakefile"
34;; (from http://bugs.debian.org/337339).
34 35
35;;; Code: 36;;; Code:
36 37
37(require 'flymake-ui) 38(eval-when-compile (require 'cl-lib))
38(require 'flymake-proc) 39
40(defgroup flymake nil
41 "Universal on-the-fly syntax checker."
42 :version "23.1"
43 :link '(custom-manual "(flymake) Top")
44 :group 'tools)
45
46(defcustom flymake-error-bitmap '(exclamation-mark error)
47 "Bitmap (a symbol) used in the fringe for indicating errors.
48The value may also be a list of two elements where the second
49element specifies the face for the bitmap. For possible bitmap
50symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'.
51
52The option `flymake-fringe-indicator-position' controls how and where
53this is used."
54 :group 'flymake
55 :version "24.3"
56 :type '(choice (symbol :tag "Bitmap")
57 (list :tag "Bitmap and face"
58 (symbol :tag "Bitmap")
59 (face :tag "Face"))))
60
61(defcustom flymake-warning-bitmap 'question-mark
62 "Bitmap (a symbol) used in the fringe for indicating warnings.
63The value may also be a list of two elements where the second
64element specifies the face for the bitmap. For possible bitmap
65symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'.
66
67The option `flymake-fringe-indicator-position' controls how and where
68this is used."
69 :group 'flymake
70 :version "24.3"
71 :type '(choice (symbol :tag "Bitmap")
72 (list :tag "Bitmap and face"
73 (symbol :tag "Bitmap")
74 (face :tag "Face"))))
75
76(defcustom flymake-fringe-indicator-position 'left-fringe
77 "The position to put flymake fringe indicator.
78The value can be nil (do not use indicators), `left-fringe' or `right-fringe'.
79See `flymake-error-bitmap' and `flymake-warning-bitmap'."
80 :group 'flymake
81 :version "24.3"
82 :type '(choice (const left-fringe)
83 (const right-fringe)
84 (const :tag "No fringe indicators" nil)))
85
86(defcustom flymake-compilation-prevents-syntax-check t
87 "If non-nil, don't start syntax check if compilation is running."
88 :group 'flymake
89 :type 'boolean)
90
91(defcustom flymake-start-syntax-check-on-newline t
92 "Start syntax check if newline char was added/removed from the buffer."
93 :group 'flymake
94 :type 'boolean)
95
96(defcustom flymake-no-changes-timeout 0.5
97 "Time to wait after last change before starting compilation."
98 :group 'flymake
99 :type 'number)
100
101(defcustom flymake-gui-warnings-enabled t
102 "Enables/disables GUI warnings."
103 :group 'flymake
104 :type 'boolean)
105(make-obsolete-variable 'flymake-gui-warnings-enabled
106 "it no longer has any effect." "26.1")
107
108(defcustom flymake-start-syntax-check-on-find-file t
109 "Start syntax check on find file."
110 :group 'flymake
111 :type 'boolean)
112
113(defcustom flymake-log-level -1
114 "Logging level, only messages with level lower or equal will be logged.
115-1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
116 :group 'flymake
117 :type 'integer)
118
119(defcustom flymake-xml-program
120 (if (executable-find "xmlstarlet") "xmlstarlet" "xml")
121 "Program to use for XML validation."
122 :type 'file
123 :group 'flymake
124 :version "24.4")
125
126(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest")
127 "Dirs where to look for master files."
128 :group 'flymake
129 :type '(repeat (string)))
130
131(defcustom flymake-master-file-count-limit 32
132 "Max number of master files to check."
133 :group 'flymake
134 :type 'integer)
135
136(defcustom flymake-allowed-file-name-masks
137 '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init)
138 ("\\.xml\\'" flymake-xml-init)
139 ("\\.html?\\'" flymake-xml-init)
140 ("\\.cs\\'" flymake-simple-make-init)
141 ("\\.p[ml]\\'" flymake-perl-init)
142 ("\\.php[345]?\\'" flymake-php-init)
143 ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup)
144 ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup)
145 ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup)
146 ("\\.tex\\'" flymake-simple-tex-init)
147 ("\\.idl\\'" flymake-simple-make-init)
148 ;; ("\\.cpp\\'" 1)
149 ;; ("\\.java\\'" 3)
150 ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'")
151 ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2))
152 ;; ("\\.idl\\'" 1)
153 ;; ("\\.odl\\'" 1)
154 ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'")
155 ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
156 ;; ("\\.tex\\'" 1)
157 )
158 "Files syntax checking is allowed for.
159This is an alist with elements of the form:
160 REGEXP INIT [CLEANUP [NAME]]
161REGEXP is a regular expression that matches a file name.
162INIT is the init function to use, missing means disable `flymake-mode'.
163CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'.
164NAME is the file name function to use, default `flymake-get-real-file-name'."
165 :group 'flymake
166 :type '(alist :key-type (regexp :tag "File regexp")
167 :value-type
168 (list :tag "Handler functions"
169 (choice :tag "Init function"
170 (const :tag "disable" nil)
171 function)
172 (choice :tag "Cleanup function"
173 (const :tag "flymake-simple-cleanup" nil)
174 function)
175 (choice :tag "Name function"
176 (const :tag "flymake-get-real-file-name" nil)
177 function))))
178
179(defvar-local flymake-is-running nil
180 "If t, flymake syntax check process is running for the current buffer.")
181
182(defvar-local flymake-timer nil
183 "Timer for starting syntax check.")
184
185(defvar-local flymake-last-change-time nil
186 "Time of last buffer change.")
187
188(defvar-local flymake-check-start-time nil
189 "Time at which syntax check was started.")
190
191(defvar-local flymake-check-was-interrupted nil
192 "Non-nil if syntax check was killed by `flymake-compile'.")
193
194(defvar-local flymake-err-info nil
195 "Sorted list of line numbers and lists of err info in the form (file, err-text).")
196
197(defvar-local flymake-new-err-info nil
198 "Same as `flymake-err-info', effective when a syntax check is in progress.")
199
200(defun flymake-log (level text &rest args)
201 "Log a message at level LEVEL.
202If LEVEL is higher than `flymake-log-level', the message is
203ignored. Otherwise, it is printed using `message'.
204TEXT is a format control string, and the remaining arguments ARGS
205are the string substitutions (see the function `format')."
206 (if (<= level flymake-log-level)
207 (let* ((msg (apply #'format-message text args)))
208 (message "%s" msg))))
209
210(defun flymake-ins-after (list pos val)
211 "Insert VAL into LIST after position POS.
212POS counts from zero."
213 (let ((tmp (copy-sequence list)))
214 (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp)))
215 tmp))
216
217(defun flymake-set-at (list pos val)
218 "Set VAL at position POS in LIST.
219POS counts from zero."
220 (let ((tmp (copy-sequence list)))
221 (setcar (nthcdr pos tmp) val)
222 tmp))
223
224(defvar flymake-processes nil
225 "List of currently active flymake processes.")
226
227(defvar-local flymake-output-residual nil)
228
229(defun flymake-get-file-name-mode-and-masks (file-name)
230 "Return the corresponding entry from `flymake-allowed-file-name-masks'."
231 (unless (stringp file-name)
232 (error "Invalid file-name"))
233 (let ((fnm flymake-allowed-file-name-masks)
234 (mode-and-masks nil))
235 (while (and (not mode-and-masks) fnm)
236 (let ((item (pop fnm)))
237 (when (string-match (car item) file-name)
238 (setq mode-and-masks item)))) ; (cdr item) may be nil
239 (setq mode-and-masks (cdr mode-and-masks))
240 (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
241 mode-and-masks))
242
243(defun flymake-can-syntax-check-file (file-name)
244 "Determine whether we can syntax check FILE-NAME.
245Return nil if we cannot, non-nil if we can."
246 (if (flymake-get-init-function file-name) t nil))
247
248(defun flymake-get-init-function (file-name)
249 "Return init function to be used for the file."
250 (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name))))
251 ;;(flymake-log 0 "calling %s" init-f)
252 ;;(funcall init-f (current-buffer))
253 init-f))
254
255(defun flymake-get-cleanup-function (file-name)
256 "Return cleanup function to be used for the file."
257 (or (nth 1 (flymake-get-file-name-mode-and-masks file-name))
258 'flymake-simple-cleanup))
259
260(defun flymake-get-real-file-name-function (file-name)
261 (or (nth 2 (flymake-get-file-name-mode-and-masks file-name))
262 'flymake-get-real-file-name))
263
264(defvar flymake-find-buildfile-cache (make-hash-table :test #'equal))
265
266(defun flymake-get-buildfile-from-cache (dir-name)
267 "Look up DIR-NAME in cache and return its associated value.
268If DIR-NAME is not found, return nil."
269 (gethash dir-name flymake-find-buildfile-cache))
270
271(defun flymake-add-buildfile-to-cache (dir-name buildfile)
272 "Associate DIR-NAME with BUILDFILE in the buildfile cache."
273 (puthash dir-name buildfile flymake-find-buildfile-cache))
274
275(defun flymake-clear-buildfile-cache ()
276 "Clear the buildfile cache."
277 (clrhash flymake-find-buildfile-cache))
278
279(defun flymake-find-buildfile (buildfile-name source-dir-name)
280 "Find buildfile starting from current directory.
281Buildfile includes Makefile, build.xml etc.
282Return its file name if found, or nil if not found."
283 (or (flymake-get-buildfile-from-cache source-dir-name)
284 (let* ((file (locate-dominating-file source-dir-name buildfile-name)))
285 (if file
286 (progn
287 (flymake-log 3 "found buildfile at %s" file)
288 (flymake-add-buildfile-to-cache source-dir-name file)
289 file)
290 (progn
291 (flymake-log 3 "buildfile for %s not found" source-dir-name)
292 nil)))))
293
294(defun flymake-fix-file-name (name)
295 "Replace all occurrences of `\\' with `/'."
296 (when name
297 (setq name (expand-file-name name))
298 (setq name (abbreviate-file-name name))
299 (setq name (directory-file-name name))
300 name))
301
302(defun flymake-same-files (file-name-one file-name-two)
303 "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
304Return t if so, nil if not."
305 (equal (flymake-fix-file-name file-name-one)
306 (flymake-fix-file-name file-name-two)))
307
308;; This is bound dynamically to pass a parameter to a sort predicate below
309(defvar flymake-included-file-name)
310
311(defun flymake-find-possible-master-files (file-name master-file-dirs masks)
312 "Find (by name and location) all possible master files.
313
314Name is specified by FILE-NAME and location is specified by
315MASTER-FILE-DIRS. Master files include .cpp and .c for .h.
316Files are searched for starting from the .h directory and max
317max-level parent dirs. File contents are not checked."
318 (let* ((dirs master-file-dirs)
319 (files nil)
320 (done nil))
321
322 (while (and (not done) dirs)
323 (let* ((dir (expand-file-name (car dirs) (file-name-directory file-name)))
324 (masks masks))
325 (while (and (file-exists-p dir) (not done) masks)
326 (let* ((mask (car masks))
327 (dir-files (directory-files dir t mask)))
328
329 (flymake-log 3 "dir %s, %d file(s) for mask %s"
330 dir (length dir-files) mask)
331 (while (and (not done) dir-files)
332 (when (not (file-directory-p (car dir-files)))
333 (setq files (cons (car dir-files) files))
334 (when (>= (length files) flymake-master-file-count-limit)
335 (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit)
336 (setq done t)))
337 (setq dir-files (cdr dir-files))))
338 (setq masks (cdr masks))))
339 (setq dirs (cdr dirs)))
340 (when files
341 (let ((flymake-included-file-name (file-name-nondirectory file-name)))
342 (setq files (sort files 'flymake-master-file-compare))))
343 (flymake-log 3 "found %d possible master file(s)" (length files))
344 files))
345
346(defun flymake-master-file-compare (file-one file-two)
347 "Compare two files specified by FILE-ONE and FILE-TWO.
348This function is used in sort to move most possible file names
349to the beginning of the list (File.h -> File.cpp moved to top)."
350 (and (equal (file-name-sans-extension flymake-included-file-name)
351 (file-name-base file-one))
352 (not (equal file-one file-two))))
353
354(defvar flymake-check-file-limit 8192
355 "Maximum number of chars to look at when checking possible master file.
356Nil means search the entire file.")
357
358(defun flymake-check-patch-master-file-buffer
359 (master-file-temp-buffer
360 master-file-name patched-master-file-name
361 source-file-name patched-source-file-name
362 include-dirs regexp)
363 "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
364If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
365instead of SOURCE-FILE-NAME.
366
367For example, foo.cpp is a master file if it includes foo.h.
368
369When a buffer for MASTER-FILE-NAME exists, use it as a source
370instead of reading master file from disk."
371 (let* ((source-file-nondir (file-name-nondirectory source-file-name))
372 (source-file-extension (file-name-extension source-file-nondir))
373 (source-file-nonext (file-name-sans-extension source-file-nondir))
374 (found nil)
375 (inc-name nil)
376 (search-limit flymake-check-file-limit))
377 (setq regexp
378 (format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
379 ;; Hack for tex files, where \include often excludes .tex.
380 ;; Maybe this is safe generally.
381 (if (and (> (length source-file-extension) 1)
382 (string-equal source-file-extension "tex"))
383 (format "%s\\(?:\\.%s\\)?"
384 (regexp-quote source-file-nonext)
385 (regexp-quote source-file-extension))
386 (regexp-quote source-file-nondir))))
387 (unwind-protect
388 (with-current-buffer master-file-temp-buffer
389 (if (or (not search-limit)
390 (> search-limit (point-max)))
391 (setq search-limit (point-max)))
392 (flymake-log 3 "checking %s against regexp %s"
393 master-file-name regexp)
394 (goto-char (point-min))
395 (while (and (< (point) search-limit)
396 (re-search-forward regexp search-limit t))
397 (let ((match-beg (match-beginning 1))
398 (match-end (match-end 1)))
399
400 (flymake-log 3 "found possible match for %s" source-file-nondir)
401 (setq inc-name (match-string 1))
402 (and (> (length source-file-extension) 1)
403 (string-equal source-file-extension "tex")
404 (not (string-match (format "\\.%s\\'" source-file-extension)
405 inc-name))
406 (setq inc-name (concat inc-name "." source-file-extension)))
407 (when (eq t (compare-strings
408 source-file-nondir nil nil
409 inc-name (- (length inc-name)
410 (length source-file-nondir)) nil))
411 (flymake-log 3 "inc-name=%s" inc-name)
412 (when (flymake-check-include source-file-name inc-name
413 include-dirs)
414 (setq found t)
415 ;; replace-match is not used here as it fails in
416 ;; XEmacs with 'last match not a buffer' error as
417 ;; check-includes calls replace-in-string
418 (flymake-replace-region
419 match-beg match-end
420 (file-name-nondirectory patched-source-file-name))))
421 (forward-line 1)))
422 (when found
423 (flymake-save-buffer-in-file patched-master-file-name)))
424 ;;+(flymake-log 3 "killing buffer %s"
425 ;; (buffer-name master-file-temp-buffer))
426 (kill-buffer master-file-temp-buffer))
427 ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found)
428 (when found
429 (flymake-log 2 "found master file %s" master-file-name))
430 found))
431
432;;; XXX: remove
433(defun flymake-replace-region (beg end rep)
434 "Replace text in BUFFER in region (BEG END) with REP."
435 (save-excursion
436 (goto-char end)
437 ;; Insert before deleting, so as to better preserve markers's positions.
438 (insert rep)
439 (delete-region beg end)))
440
441(defun flymake-read-file-to-temp-buffer (file-name)
442 "Insert contents of FILE-NAME into newly created temp buffer."
443 (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name))))))
444 (with-current-buffer temp-buffer
445 (insert-file-contents file-name))
446 temp-buffer))
447
448(defun flymake-copy-buffer-to-temp-buffer (buffer)
449 "Copy contents of BUFFER into newly created temp buffer."
450 (with-current-buffer
451 (get-buffer-create (generate-new-buffer-name
452 (concat "flymake:" (buffer-name buffer))))
453 (insert-buffer-substring buffer)
454 (current-buffer)))
455
456(defun flymake-check-include (source-file-name inc-name include-dirs)
457 "Check if SOURCE-FILE-NAME can be found in include path.
458Return t if it can be found via include path using INC-NAME."
459 (if (file-name-absolute-p inc-name)
460 (flymake-same-files source-file-name inc-name)
461 (while (and include-dirs
462 (not (flymake-same-files
463 source-file-name
464 (concat (file-name-directory source-file-name)
465 "/" (car include-dirs)
466 "/" inc-name))))
467 (setq include-dirs (cdr include-dirs)))
468 include-dirs))
469
470(defun flymake-find-buffer-for-file (file-name)
471 "Check if there exists a buffer visiting FILE-NAME.
472Return t if so, nil if not."
473 (let ((buffer-name (get-file-buffer file-name)))
474 (if buffer-name
475 (get-buffer buffer-name))))
476
477(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp)
478 "Save SOURCE-FILE-NAME with a different name.
479Find master file, patch and save it."
480 (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks))
481 (master-file-count (length possible-master-files))
482 (idx 0)
483 (temp-buffer nil)
484 (master-file-name nil)
485 (patched-master-file-name nil)
486 (found nil))
487
488 (while (and (not found) (< idx master-file-count))
489 (setq master-file-name (nth idx possible-master-files))
490 (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master"))
491 (if (flymake-find-buffer-for-file master-file-name)
492 (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name)))
493 (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)))
494 (setq found
495 (flymake-check-patch-master-file-buffer
496 temp-buffer
497 master-file-name
498 patched-master-file-name
499 source-file-name
500 patched-source-file-name
501 (funcall get-incl-dirs-f (file-name-directory master-file-name))
502 include-regexp))
503 (setq idx (1+ idx)))
504 (if found
505 (list master-file-name patched-master-file-name)
506 (progn
507 (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count
508 (file-name-nondirectory source-file-name))
509 nil))))
510
511(defun flymake-save-buffer-in-file (file-name)
512 "Save the entire buffer contents into file FILE-NAME.
513Create parent directories as needed."
514 (make-directory (file-name-directory file-name) 1)
515 (write-region nil nil file-name nil 566)
516 (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name))
517
518(defun flymake-process-filter (process output)
519 "Parse OUTPUT and highlight error lines.
520It's flymake process filter."
521 (let ((source-buffer (process-buffer process)))
522
523 (flymake-log 3 "received %d byte(s) of output from process %d"
524 (length output) (process-id process))
525 (when (buffer-live-p source-buffer)
526 (with-current-buffer source-buffer
527 (flymake-parse-output-and-residual output)))))
528
529(defun flymake-process-sentinel (process _event)
530 "Sentinel for syntax check buffers."
531 (when (memq (process-status process) '(signal exit))
532 (let* ((exit-status (process-exit-status process))
533 (command (process-command process))
534 (source-buffer (process-buffer process))
535 (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer))))
536
537 (flymake-log 2 "process %d exited with code %d"
538 (process-id process) exit-status)
539 (condition-case err
540 (progn
541 (flymake-log 3 "cleaning up using %s" cleanup-f)
542 (when (buffer-live-p source-buffer)
543 (with-current-buffer source-buffer
544 (funcall cleanup-f)))
545
546 (delete-process process)
547 (setq flymake-processes (delq process flymake-processes))
548
549 (when (buffer-live-p source-buffer)
550 (with-current-buffer source-buffer
551
552 (flymake-parse-residual)
553 (flymake-post-syntax-check exit-status command)
554 (setq flymake-is-running nil))))
555 (error
556 (let ((err-str (format "Error in process sentinel for buffer %s: %s"
557 source-buffer (error-message-string err))))
558 (flymake-log 0 err-str)
559 (with-current-buffer source-buffer
560 (setq flymake-is-running nil))))))))
561
562(defun flymake-post-syntax-check (exit-status command)
563 (save-restriction
564 (widen)
565 (setq flymake-err-info flymake-new-err-info)
566 (setq flymake-new-err-info nil)
567 (setq flymake-err-info
568 (flymake-fix-line-numbers
569 flymake-err-info 1 (count-lines (point-min) (point-max))))
570 (flymake-delete-own-overlays)
571 (flymake-highlight-err-lines flymake-err-info)
572 (let (err-count warn-count)
573 (setq err-count (flymake-get-err-count flymake-err-info "e"))
574 (setq warn-count (flymake-get-err-count flymake-err-info "w"))
575 (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)"
576 (buffer-name) err-count warn-count
577 (- (float-time) flymake-check-start-time))
578 (setq flymake-check-start-time nil)
579
580 (if (and (equal 0 err-count) (equal 0 warn-count))
581 (if (equal 0 exit-status)
582 (flymake-report-status "" "") ; PASSED
583 (if (not flymake-check-was-interrupted)
584 (flymake-report-fatal-status "CFGERR"
585 (format "Configuration error has occurred while running %s" command))
586 (flymake-report-status nil ""))) ; "STOPPED"
587 (flymake-report-status (format "%d/%d" err-count warn-count) "")))))
588
589(defun flymake-parse-output-and-residual (output)
590 "Split OUTPUT into lines, merge in residual if necessary."
591 (let* ((buffer-residual flymake-output-residual)
592 (total-output (if buffer-residual (concat buffer-residual output) output))
593 (lines-and-residual (flymake-split-output total-output))
594 (lines (nth 0 lines-and-residual))
595 (new-residual (nth 1 lines-and-residual)))
596 (setq flymake-output-residual new-residual)
597 (setq flymake-new-err-info
598 (flymake-parse-err-lines
599 flymake-new-err-info lines))))
600
601(defun flymake-parse-residual ()
602 "Parse residual if it's non empty."
603 (when flymake-output-residual
604 (setq flymake-new-err-info
605 (flymake-parse-err-lines
606 flymake-new-err-info
607 (list flymake-output-residual)))
608 (setq flymake-output-residual nil)))
609
610(defun flymake-er-make-er (line-no line-err-info-list)
611 (list line-no line-err-info-list))
612
613(defun flymake-er-get-line (err-info)
614 (nth 0 err-info))
615
616(defun flymake-er-get-line-err-info-list (err-info)
617 (nth 1 err-info))
618
619(cl-defstruct (flymake-ler
620 (:constructor nil)
621 (:constructor flymake-ler-make-ler (file line type text &optional full-file)))
622 file line type text full-file)
623
624(defun flymake-ler-set-file (line-err-info file)
625 (flymake-ler-make-ler file
626 (flymake-ler-line line-err-info)
627 (flymake-ler-type line-err-info)
628 (flymake-ler-text line-err-info)
629 (flymake-ler-full-file line-err-info)))
630
631(defun flymake-ler-set-full-file (line-err-info full-file)
632 (flymake-ler-make-ler (flymake-ler-file line-err-info)
633 (flymake-ler-line line-err-info)
634 (flymake-ler-type line-err-info)
635 (flymake-ler-text line-err-info)
636 full-file))
637
638(defun flymake-ler-set-line (line-err-info line)
639 (flymake-ler-make-ler (flymake-ler-file line-err-info)
640 line
641 (flymake-ler-type line-err-info)
642 (flymake-ler-text line-err-info)
643 (flymake-ler-full-file line-err-info)))
644
645(defun flymake-get-line-err-count (line-err-info-list type)
646 "Return number of errors of specified TYPE.
647Value of TYPE is either \"e\" or \"w\"."
648 (let* ((idx 0)
649 (count (length line-err-info-list))
650 (err-count 0))
651
652 (while (< idx count)
653 (when (equal type (flymake-ler-type (nth idx line-err-info-list)))
654 (setq err-count (1+ err-count)))
655 (setq idx (1+ idx)))
656 err-count))
657
658(defun flymake-get-err-count (err-info-list type)
659 "Return number of errors of specified TYPE for ERR-INFO-LIST."
660 (let* ((idx 0)
661 (count (length err-info-list))
662 (err-count 0))
663 (while (< idx count)
664 (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type)))
665 (setq idx (1+ idx)))
666 err-count))
667
668(defun flymake-fix-line-numbers (err-info-list min-line max-line)
669 "Replace line numbers with fixed value.
670If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE.
671If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE.
672The reason for this fix is because some compilers might report
673line number outside the file being compiled."
674 (let* ((count (length err-info-list))
675 (err-info nil)
676 (line 0))
677 (while (> count 0)
678 (setq err-info (nth (1- count) err-info-list))
679 (setq line (flymake-er-get-line err-info))
680 (when (or (< line min-line) (> line max-line))
681 (setq line (if (< line min-line) min-line max-line))
682 (setq err-info-list (flymake-set-at err-info-list (1- count)
683 (flymake-er-make-er line
684 (flymake-er-get-line-err-info-list err-info)))))
685 (setq count (1- count))))
686 err-info-list)
687
688(defun flymake-highlight-err-lines (err-info-list)
689 "Highlight error lines in BUFFER using info from ERR-INFO-LIST."
690 (save-excursion
691 (dolist (err err-info-list)
692 (flymake-highlight-line (car err) (nth 1 err)))))
693
694(defun flymake-overlay-p (ov)
695 "Determine whether overlay OV was created by flymake."
696 (and (overlayp ov) (overlay-get ov 'flymake-overlay)))
697
698(defun flymake-make-overlay (beg end tooltip-text face bitmap)
699 "Allocate a flymake overlay in range BEG and END."
700 (when (not (flymake-region-has-flymake-overlays beg end))
701 (let ((ov (make-overlay beg end nil t))
702 (fringe (and flymake-fringe-indicator-position
703 (propertize "!" 'display
704 (cons flymake-fringe-indicator-position
705 (if (listp bitmap)
706 bitmap
707 (list bitmap)))))))
708 (overlay-put ov 'face face)
709 (overlay-put ov 'help-echo tooltip-text)
710 (overlay-put ov 'flymake-overlay t)
711 (overlay-put ov 'priority 100)
712 (overlay-put ov 'evaporate t)
713 (overlay-put ov 'before-string fringe)
714 ;;+(flymake-log 3 "created overlay %s" ov)
715 ov)
716 (flymake-log 3 "created an overlay at (%d-%d)" beg end)))
717
718(defun flymake-delete-own-overlays ()
719 "Delete all flymake overlays in BUFFER."
720 (dolist (ol (overlays-in (point-min) (point-max)))
721 (when (flymake-overlay-p ol)
722 (delete-overlay ol)
723 ;;+(flymake-log 3 "deleted overlay %s" ol)
724 )))
725
726(defun flymake-region-has-flymake-overlays (beg end)
727 "Check if region specified by BEG and END has overlay.
728Return t if it has at least one flymake overlay, nil if no overlay."
729 (let ((ov (overlays-in beg end))
730 (has-flymake-overlays nil))
731 (while (consp ov)
732 (when (flymake-overlay-p (car ov))
733 (setq has-flymake-overlays t))
734 (setq ov (cdr ov)))
735 has-flymake-overlays))
736
737(defface flymake-errline
738 '((((supports :underline (:style wave)))
739 :underline (:style wave :color "Red1"))
740 (t
741 :inherit error))
742 "Face used for marking error lines."
743 :version "24.4"
744 :group 'flymake)
745
746(defface flymake-warnline
747 '((((supports :underline (:style wave)))
748 :underline (:style wave :color "DarkOrange"))
749 (t
750 :inherit warning))
751 "Face used for marking warning lines."
752 :version "24.4"
753 :group 'flymake)
754
755(defun flymake-highlight-line (line-no line-err-info-list)
756 "Highlight line LINE-NO in current buffer.
757Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting."
758 (goto-char (point-min))
759 (forward-line (1- line-no))
760 (pcase-let* ((beg (progn (back-to-indentation) (point)))
761 (end (progn
762 (end-of-line)
763 (skip-chars-backward " \t\f\t\n" beg)
764 (if (eq (point) beg)
765 (line-beginning-position 2)
766 (point))))
767 (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list "\n"))
768 (`(,face ,bitmap)
769 (if (> (flymake-get-line-err-count line-err-info-list "e") 0)
770 (list 'flymake-errline flymake-error-bitmap)
771 (list 'flymake-warnline flymake-warning-bitmap))))
772 (flymake-make-overlay beg end tooltip-text face bitmap)))
773
774(defun flymake-parse-err-lines (err-info-list lines)
775 "Parse err LINES, store info in ERR-INFO-LIST."
776 (let* ((count (length lines))
777 (idx 0)
778 (line-err-info nil)
779 (real-file-name nil)
780 (source-file-name buffer-file-name)
781 (get-real-file-name-f (flymake-get-real-file-name-function source-file-name)))
782
783 (while (< idx count)
784 (setq line-err-info (flymake-parse-line (nth idx lines)))
785 (when line-err-info
786 (setq real-file-name (funcall get-real-file-name-f
787 (flymake-ler-file line-err-info)))
788 (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name))
789
790 (when (flymake-same-files real-file-name source-file-name)
791 (setq line-err-info (flymake-ler-set-file line-err-info nil))
792 (setq err-info-list (flymake-add-err-info err-info-list line-err-info))))
793 (flymake-log 3 "parsed `%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no"))
794 (setq idx (1+ idx)))
795 err-info-list))
796
797(defun flymake-split-output (output)
798 "Split OUTPUT into lines.
799Return last one as residual if it does not end with newline char.
800Returns ((LINES) RESIDUAL)."
801 (when (and output (> (length output) 0))
802 (let* ((lines (split-string output "[\n\r]+" t))
803 (complete (equal "\n" (char-to-string (aref output (1- (length output))))))
804 (residual nil))
805 (when (not complete)
806 (setq residual (car (last lines)))
807 (setq lines (butlast lines)))
808 (list lines residual))))
809
810(defun flymake-reformat-err-line-patterns-from-compile-el (original-list)
811 "Grab error line patterns from ORIGINAL-LIST in compile.el format.
812Convert it to flymake internal format."
813 (let* ((converted-list '()))
814 (dolist (item original-list)
815 (setq item (cdr item))
816 (let ((regexp (nth 0 item))
817 (file (nth 1 item))
818 (line (nth 2 item))
819 (col (nth 3 item)))
820 (if (consp file) (setq file (car file)))
821 (if (consp line) (setq line (car line)))
822 (if (consp col) (setq col (car col)))
823
824 (when (not (functionp line))
825 (setq converted-list (cons (list regexp file line col) converted-list)))))
826 converted-list))
827
828(require 'compile)
829
830(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text
831 (append
832 '(
833 ;; MS Visual C++ 6.0
834 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
835 1 3 nil 4)
836 ;; jikes
837 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
838 1 3 nil 4)
839 ;; MS midl
840 ("midl[ ]*:[ ]*\\(command line error .*\\)"
841 nil nil nil 1)
842 ;; MS C#
843 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
844 1 3 nil 4)
845 ;; perl
846 ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
847 ;; PHP
848 ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1)
849 ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1)
850 ;; ant/javac. Note this also matches gcc warnings!
851 (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::[0-9]+\\)?:[ \t\n]*\\(.+\\)"
852 2 4 nil 5))
853 ;; compilation-error-regexp-alist)
854 (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist))
855 "Patterns for matching error/warning lines. Each pattern has the form
856\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
857Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns
858from compile.el")
859
860(define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate "24.4")
861(defvar flymake-warning-predicate "^[wW]arning"
862 "Predicate matching against error text to detect a warning.
863Takes a single argument, the error's text and should return non-nil
864if it's a warning.
865Instead of a function, it can also be a regular expression.")
866
867(defun flymake-parse-line (line)
868 "Parse LINE to see if it is an error or warning.
869Return its components if so, nil otherwise."
870 (let ((raw-file-name nil)
871 (line-no 0)
872 (err-type "e")
873 (err-text nil)
874 (patterns flymake-err-line-patterns)
875 (matched nil))
876 (while (and patterns (not matched))
877 (when (string-match (car (car patterns)) line)
878 (let* ((file-idx (nth 1 (car patterns)))
879 (line-idx (nth 2 (car patterns))))
880
881 (setq raw-file-name (if file-idx (match-string file-idx line) nil))
882 (setq line-no (if line-idx (string-to-number
883 (match-string line-idx line)) 0))
884 (setq err-text (if (> (length (car patterns)) 4)
885 (match-string (nth 4 (car patterns)) line)
886 (flymake-patch-err-text
887 (substring line (match-end 0)))))
888 (if (null err-text)
889 (setq err-text "<no error text>")
890 (when (cond ((stringp flymake-warning-predicate)
891 (string-match flymake-warning-predicate err-text))
892 ((functionp flymake-warning-predicate)
893 (funcall flymake-warning-predicate err-text)))
894 (setq err-type "w")))
895 (flymake-log
896 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s"
897 file-idx line-idx raw-file-name line-no err-text)
898 (setq matched t)))
899 (setq patterns (cdr patterns)))
900 (if matched
901 (flymake-ler-make-ler raw-file-name line-no err-type err-text)
902 ())))
903
904(defun flymake-find-err-info (err-info-list line-no)
905 "Find (line-err-info-list pos) for specified LINE-NO."
906 (if err-info-list
907 (let* ((line-err-info-list nil)
908 (pos 0)
909 (count (length err-info-list)))
910
911 (while (and (< pos count) (< (car (nth pos err-info-list)) line-no))
912 (setq pos (1+ pos)))
913 (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no))
914 (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list))))
915 (list line-err-info-list pos))
916 '(nil 0)))
917
918(defun flymake-line-err-info-is-less-or-equal (line-one line-two)
919 (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two))
920 (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
921 (not (flymake-ler-file line-one)) (flymake-ler-file line-two))
922 (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
923 (or (and (flymake-ler-file line-one) (flymake-ler-file line-two))
924 (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two)))))))
925
926(defun flymake-add-line-err-info (line-err-info-list line-err-info)
927 "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO.
928For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'.
929The new element is inserted in the proper position, according to
930the predicate `flymake-line-err-info-is-less-or-equal'.
931The updated value of LINE-ERR-INFO-LIST is returned."
932 (if (not line-err-info-list)
933 (list line-err-info)
934 (let* ((count (length line-err-info-list))
935 (idx 0))
936 (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info))
937 (setq idx (1+ idx)))
938 (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list)))
939 (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info))))
940 line-err-info-list)))
941
942(defun flymake-add-err-info (err-info-list line-err-info)
943 "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order.
944Returns the updated value of ERR-INFO-LIST.
945For the format of ERR-INFO-LIST, see `flymake-err-info'.
946For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'."
947 (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info)))
948 (info-and-pos (flymake-find-err-info err-info-list line-no))
949 (exists (car info-and-pos))
950 (pos (nth 1 info-and-pos))
951 (line-err-info-list nil)
952 (err-info nil))
953
954 (if exists
955 (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list)))))
956 (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info))
957
958 (setq err-info (flymake-er-make-er line-no line-err-info-list))
959 (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info)))
960 ((equal 0 pos) (setq err-info-list (cons err-info err-info-list)))
961 (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info))))
962 err-info-list))
963
964(defun flymake-get-project-include-dirs-imp (basedir)
965 "Include dirs for the project current file belongs to."
966 (if (flymake-get-project-include-dirs-from-cache basedir)
967 (progn
968 (flymake-get-project-include-dirs-from-cache basedir))
969 ;;else
970 (let* ((command-line (concat "make -C "
971 (shell-quote-argument basedir)
972 " DUMPVARS=INCLUDE_DIRS dumpvars"))
973 (output (shell-command-to-string command-line))
974 (lines (split-string output "\n" t))
975 (count (length lines))
976 (idx 0)
977 (inc-dirs nil))
978 (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines))))
979 (setq idx (1+ idx)))
980 (when (< idx count)
981 (let* ((inc-lines (split-string (nth idx lines) " *-I" t))
982 (inc-count (length inc-lines)))
983 (while (> inc-count 0)
984 (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines)))
985 (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs))
986 (setq inc-count (1- inc-count)))))
987 (flymake-add-project-include-dirs-to-cache basedir inc-dirs)
988 inc-dirs)))
989
990(defvar flymake-get-project-include-dirs-function #'flymake-get-project-include-dirs-imp
991 "Function used to get project include dirs, one parameter: basedir name.")
992
993(defun flymake-get-project-include-dirs (basedir)
994 (funcall flymake-get-project-include-dirs-function basedir))
995
996(defun flymake-get-system-include-dirs ()
997 "System include dirs - from the `INCLUDE' env setting."
998 (let* ((includes (getenv "INCLUDE")))
999 (if includes (split-string includes path-separator t) nil)))
1000
1001(defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal))
1002
1003(defun flymake-get-project-include-dirs-from-cache (base-dir)
1004 (gethash base-dir flymake-project-include-dirs-cache))
1005
1006(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs)
1007 (puthash base-dir include-dirs flymake-project-include-dirs-cache))
1008
1009(defun flymake-clear-project-include-dirs-cache ()
1010 (clrhash flymake-project-include-dirs-cache))
1011
1012(defun flymake-get-include-dirs (base-dir)
1013 "Get dirs to use when resolving local file names."
1014 (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs))))
1015 include-dirs))
1016
1017;; (defun flymake-restore-formatting ()
1018;; "Remove any formatting made by flymake."
1019;; )
1020
1021;; (defun flymake-get-program-dir (buffer)
1022;; "Get dir to start program in."
1023;; (unless (bufferp buffer)
1024;; (error "Invalid buffer"))
1025;; (with-current-buffer buffer
1026;; default-directory))
1027
1028(defun flymake-safe-delete-file (file-name)
1029 (when (and file-name (file-exists-p file-name))
1030 (delete-file file-name)
1031 (flymake-log 1 "deleted file %s" file-name)))
1032
1033(defun flymake-safe-delete-directory (dir-name)
1034 (condition-case nil
1035 (progn
1036 (delete-directory dir-name)
1037 (flymake-log 1 "deleted dir %s" dir-name))
1038 (error
1039 (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
1040
1041(defun flymake-start-syntax-check ()
1042 "Start syntax checking for current buffer."
1043 (interactive)
1044 (flymake-log 3 "flymake is running: %s" flymake-is-running)
1045 (when (and (not flymake-is-running)
1046 (flymake-can-syntax-check-file buffer-file-name))
1047 (when (or (not flymake-compilation-prevents-syntax-check)
1048 (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP")
1049 (flymake-clear-buildfile-cache)
1050 (flymake-clear-project-include-dirs-cache)
1051
1052 (setq flymake-check-was-interrupted nil)
1053
1054 (let* ((source-file-name buffer-file-name)
1055 (init-f (flymake-get-init-function source-file-name))
1056 (cleanup-f (flymake-get-cleanup-function source-file-name))
1057 (cmd-and-args (funcall init-f))
1058 (cmd (nth 0 cmd-and-args))
1059 (args (nth 1 cmd-and-args))
1060 (dir (nth 2 cmd-and-args)))
1061 (if (not cmd-and-args)
1062 (progn
1063 (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name)
1064 (funcall cleanup-f))
1065 (progn
1066 (setq flymake-last-change-time nil)
1067 (flymake-start-syntax-check-process cmd args dir)))))))
1068
1069(defun flymake-start-syntax-check-process (cmd args dir)
1070 "Start syntax check process."
1071 (condition-case err
1072 (let* ((process
1073 (let ((default-directory (or dir default-directory)))
1074 (when dir
1075 (flymake-log 3 "starting process on dir %s" dir))
1076 (apply 'start-file-process
1077 "flymake-proc" (current-buffer) cmd args))))
1078 (set-process-sentinel process 'flymake-process-sentinel)
1079 (set-process-filter process 'flymake-process-filter)
1080 (set-process-query-on-exit-flag process nil)
1081 (push process flymake-processes)
1082
1083 (setq flymake-is-running t)
1084 (setq flymake-last-change-time nil)
1085 (setq flymake-check-start-time (float-time))
1086
1087 (flymake-report-status nil "*")
1088 (flymake-log 2 "started process %d, command=%s, dir=%s"
1089 (process-id process) (process-command process)
1090 default-directory)
1091 process)
1092 (error
1093 (let* ((err-str
1094 (format-message
1095 "Failed to launch syntax check process `%s' with args %s: %s"
1096 cmd args (error-message-string err)))
1097 (source-file-name buffer-file-name)
1098 (cleanup-f (flymake-get-cleanup-function source-file-name)))
1099 (flymake-log 0 err-str)
1100 (funcall cleanup-f)
1101 (flymake-report-fatal-status "PROCERR" err-str)))))
1102
1103(defun flymake-kill-process (proc)
1104 "Kill process PROC."
1105 (kill-process proc)
1106 (let* ((buf (process-buffer proc)))
1107 (when (buffer-live-p buf)
1108 (with-current-buffer buf
1109 (setq flymake-check-was-interrupted t))))
1110 (flymake-log 1 "killed process %d" (process-id proc)))
1111
1112(defun flymake-stop-all-syntax-checks ()
1113 "Kill all syntax check processes."
1114 (interactive)
1115 (while flymake-processes
1116 (flymake-kill-process (pop flymake-processes))))
1117
1118(defun flymake-compilation-is-running ()
1119 (and (boundp 'compilation-in-progress)
1120 compilation-in-progress))
1121
1122(defun flymake-compile ()
1123 "Kill all flymake syntax checks, start compilation."
1124 (interactive)
1125 (flymake-stop-all-syntax-checks)
1126 (call-interactively 'compile))
1127
1128(defun flymake-on-timer-event (buffer)
1129 "Start a syntax check for buffer BUFFER if necessary."
1130 (when (buffer-live-p buffer)
1131 (with-current-buffer buffer
1132 (when (and (not flymake-is-running)
1133 flymake-last-change-time
1134 (> (- (float-time) flymake-last-change-time)
1135 flymake-no-changes-timeout))
1136
1137 (setq flymake-last-change-time nil)
1138 (flymake-log 3 "starting syntax check as more than 1 second passed since last change")
1139 (flymake-start-syntax-check)))))
1140
1141(define-obsolete-function-alias 'flymake-display-err-menu-for-current-line
1142 'flymake-popup-current-error-menu "24.4")
1143
1144(defun flymake-popup-current-error-menu (&optional event)
1145 "Pop up a menu with errors/warnings for current line."
1146 (interactive (list last-nonmenu-event))
1147 (let* ((line-no (line-number-at-pos))
1148 (errors (or (car (flymake-find-err-info flymake-err-info line-no))
1149 (user-error "No errors for current line")))
1150 (menu (mapcar (lambda (x)
1151 (if (flymake-ler-file x)
1152 (cons (format "%s - %s(%d)"
1153 (flymake-ler-text x)
1154 (flymake-ler-file x)
1155 (flymake-ler-line x))
1156 x)
1157 (list (flymake-ler-text x))))
1158 errors))
1159 (event (if (mouse-event-p event)
1160 event
1161 (list 'mouse-1 (posn-at-point))))
1162 (title (format "Line %d: %d error(s), %d warning(s)"
1163 line-no
1164 (flymake-get-line-err-count errors "e")
1165 (flymake-get-line-err-count errors "w")))
1166 (choice (x-popup-menu event (list title (cons "" menu)))))
1167 (flymake-log 3 "choice=%s" choice)
1168 (when choice
1169 (flymake-goto-file-and-line (flymake-ler-full-file choice)
1170 (flymake-ler-line choice)))))
1171
1172(defun flymake-goto-file-and-line (file line)
1173 "Try to get buffer for FILE and goto line LINE in it."
1174 (if (not (file-exists-p file))
1175 (flymake-log 1 "File %s does not exist" file)
1176 (find-file file)
1177 (goto-char (point-min))
1178 (forward-line (1- line))))
1179
1180;; flymake minor mode declarations
1181(defvar-local flymake-mode-line nil)
1182(defvar-local flymake-mode-line-e-w nil)
1183(defvar-local flymake-mode-line-status nil)
1184
1185(defun flymake-report-status (e-w &optional status)
1186 "Show status in mode line."
1187 (when e-w
1188 (setq flymake-mode-line-e-w e-w))
1189 (when status
1190 (setq flymake-mode-line-status status))
1191 (let* ((mode-line " Flymake"))
1192 (when (> (length flymake-mode-line-e-w) 0)
1193 (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
1194 (setq mode-line (concat mode-line flymake-mode-line-status))
1195 (setq flymake-mode-line mode-line)
1196 (force-mode-line-update)))
1197
1198;; Nothing in flymake uses this at all any more, so this is just for
1199;; third-party compatibility.
1200(define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1")
1201
1202(defun flymake-report-fatal-status (status warning)
1203 "Display a warning and switch flymake mode off."
1204 ;; This first message was always shown by default, and flymake-log
1205 ;; does nothing by default, hence the use of message.
1206 ;; Another option is display-warning.
1207 (if (< flymake-log-level 0)
1208 (message "Flymake: %s. Flymake will be switched OFF" warning))
1209 (flymake-mode 0)
1210 (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s"
1211 (buffer-name) status warning))
1212
1213;;;###autoload
1214(define-minor-mode flymake-mode nil
1215 :group 'flymake :lighter flymake-mode-line
1216 (cond
1217
1218 ;; Turning the mode ON.
1219 (flymake-mode
1220 (cond
1221 ((not buffer-file-name)
1222 (message "Flymake unable to run without a buffer file name"))
1223 ((not (flymake-can-syntax-check-file buffer-file-name))
1224 (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
1225 (t
1226 (add-hook 'after-change-functions 'flymake-after-change-function nil t)
1227 (add-hook 'after-save-hook 'flymake-after-save-hook nil t)
1228 (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)
1229 ;;+(add-hook 'find-file-hook 'flymake-find-file-hook)
1230
1231 (flymake-report-status "" "")
1232
1233 (setq flymake-timer
1234 (run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
1235
1236 (when (and flymake-start-syntax-check-on-find-file
1237 ;; Since we write temp files in current dir, there's no point
1238 ;; trying if the directory is read-only (bug#8954).
1239 (file-writable-p (file-name-directory buffer-file-name)))
1240 (with-demoted-errors
1241 (flymake-start-syntax-check))))))
1242
1243 ;; Turning the mode OFF.
1244 (t
1245 (remove-hook 'after-change-functions 'flymake-after-change-function t)
1246 (remove-hook 'after-save-hook 'flymake-after-save-hook t)
1247 (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t)
1248 ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t)
1249
1250 (flymake-delete-own-overlays)
1251
1252 (when flymake-timer
1253 (cancel-timer flymake-timer)
1254 (setq flymake-timer nil))
1255
1256 (setq flymake-is-running nil))))
1257
1258;;;###autoload
1259(defun flymake-mode-on ()
1260 "Turn flymake mode on."
1261 (flymake-mode 1)
1262 (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name)))
1263
1264;;;###autoload
1265(defun flymake-mode-off ()
1266 "Turn flymake mode off."
1267 (flymake-mode 0)
1268 (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name)))
1269
1270(defun flymake-after-change-function (start stop _len)
1271 "Start syntax check for current buffer if it isn't already running."
1272 ;;+(flymake-log 0 "setting change time to %s" (float-time))
1273 (let((new-text (buffer-substring start stop)))
1274 (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
1275 (flymake-log 3 "starting syntax check as new-line has been seen")
1276 (flymake-start-syntax-check))
1277 (setq flymake-last-change-time (float-time))))
1278
1279(defun flymake-after-save-hook ()
1280 (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved?
1281 (progn
1282 (flymake-log 3 "starting syntax check as buffer was saved")
1283 (flymake-start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???)
1284
1285(defun flymake-kill-buffer-hook ()
1286 (when flymake-timer
1287 (cancel-timer flymake-timer)
1288 (setq flymake-timer nil)))
1289
1290;;;###autoload
1291(defun flymake-find-file-hook ()
1292 ;;+(when flymake-start-syntax-check-on-find-file
1293 ;;+ (flymake-log 3 "starting syntax check on file open")
1294 ;;+ (flymake-start-syntax-check)
1295 ;;+)
1296 (when (and (not (local-variable-p 'flymake-mode (current-buffer)))
1297 (flymake-can-syntax-check-file buffer-file-name))
1298 (flymake-mode)
1299 (flymake-log 3 "automatically turned ON flymake mode")))
1300
1301(defun flymake-get-first-err-line-no (err-info-list)
1302 "Return first line with error."
1303 (when err-info-list
1304 (flymake-er-get-line (car err-info-list))))
1305
1306(defun flymake-get-last-err-line-no (err-info-list)
1307 "Return last line with error."
1308 (when err-info-list
1309 (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list))))
1310
1311(defun flymake-get-next-err-line-no (err-info-list line-no)
1312 "Return next line with error."
1313 (when err-info-list
1314 (let* ((count (length err-info-list))
1315 (idx 0))
1316 (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list))))
1317 (setq idx (1+ idx)))
1318 (if (< idx count)
1319 (flymake-er-get-line (nth idx err-info-list))))))
1320
1321(defun flymake-get-prev-err-line-no (err-info-list line-no)
1322 "Return previous line with error."
1323 (when err-info-list
1324 (let* ((count (length err-info-list)))
1325 (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list))))
1326 (setq count (1- count)))
1327 (if (> count 0)
1328 (flymake-er-get-line (nth (1- count) err-info-list))))))
1329
1330(defun flymake-skip-whitespace ()
1331 "Move forward until non-whitespace is reached."
1332 (while (looking-at "[ \t]")
1333 (forward-char)))
1334
1335(defun flymake-goto-line (line-no)
1336 "Go to line LINE-NO, then skip whitespace."
1337 (goto-char (point-min))
1338 (forward-line (1- line-no))
1339 (flymake-skip-whitespace))
1340
1341(defun flymake-goto-next-error ()
1342 "Go to next error in err ring."
1343 (interactive)
1344 (let ((line-no (flymake-get-next-err-line-no flymake-err-info (line-number-at-pos))))
1345 (when (not line-no)
1346 (setq line-no (flymake-get-first-err-line-no flymake-err-info))
1347 (flymake-log 1 "passed end of file"))
1348 (if line-no
1349 (flymake-goto-line line-no)
1350 (flymake-log 1 "no errors in current buffer"))))
1351
1352(defun flymake-goto-prev-error ()
1353 "Go to previous error in err ring."
1354 (interactive)
1355 (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (line-number-at-pos))))
1356 (when (not line-no)
1357 (setq line-no (flymake-get-last-err-line-no flymake-err-info))
1358 (flymake-log 1 "passed beginning of file"))
1359 (if line-no
1360 (flymake-goto-line line-no)
1361 (flymake-log 1 "no errors in current buffer"))))
1362
1363(defun flymake-patch-err-text (string)
1364 (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string)
1365 (match-string 1 string)
1366 string))
1367
1368;;;; general init-cleanup and helper routines
1369(defun flymake-create-temp-inplace (file-name prefix)
1370 (unless (stringp file-name)
1371 (error "Invalid file-name"))
1372 (or prefix
1373 (setq prefix "flymake"))
1374 (let* ((ext (file-name-extension file-name))
1375 (temp-name (file-truename
1376 (concat (file-name-sans-extension file-name)
1377 "_" prefix
1378 (and ext (concat "." ext))))))
1379 (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
1380 temp-name))
1381
1382(defun flymake-create-temp-with-folder-structure (file-name _prefix)
1383 (unless (stringp file-name)
1384 (error "Invalid file-name"))
1385
1386 (let* ((dir (file-name-directory file-name))
1387 ;; Not sure what this slash-pos is all about, but I guess it's just
1388 ;; trying to remove the leading / of absolute file names.
1389 (slash-pos (string-match "/" dir))
1390 (temp-dir (expand-file-name (substring dir (1+ slash-pos))
1391 temporary-file-directory)))
1392
1393 (file-truename (expand-file-name (file-name-nondirectory file-name)
1394 temp-dir))))
1395
1396(defun flymake-delete-temp-directory (dir-name)
1397 "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error."
1398 (let* ((temp-dir temporary-file-directory)
1399 (suffix (substring dir-name (1+ (length temp-dir)))))
1400
1401 (while (> (length suffix) 0)
1402 (setq suffix (directory-file-name suffix))
1403 ;;+(flymake-log 0 "suffix=%s" suffix)
1404 (flymake-safe-delete-directory
1405 (file-truename (expand-file-name suffix temp-dir)))
1406 (setq suffix (file-name-directory suffix)))))
1407
1408(defvar-local flymake-temp-source-file-name nil)
1409(defvar-local flymake-master-file-name nil)
1410(defvar-local flymake-temp-master-file-name nil)
1411(defvar-local flymake-base-dir nil)
1412
1413(defun flymake-init-create-temp-buffer-copy (create-temp-f)
1414 "Make a temporary copy of the current buffer, save its name in buffer data and return the name."
1415 (let* ((source-file-name buffer-file-name)
1416 (temp-source-file-name (funcall create-temp-f source-file-name "flymake")))
1417
1418 (flymake-save-buffer-in-file temp-source-file-name)
1419 (setq flymake-temp-source-file-name temp-source-file-name)
1420 temp-source-file-name))
1421
1422(defun flymake-simple-cleanup ()
1423 "Do cleanup after `flymake-init-create-temp-buffer-copy'.
1424Delete temp file."
1425 (flymake-safe-delete-file flymake-temp-source-file-name)
1426 (setq flymake-last-change-time nil))
1427
1428(defun flymake-get-real-file-name (file-name-from-err-msg)
1429 "Translate file name from error message to \"real\" file name.
1430Return full-name. Names are real, not patched."
1431 (let* ((real-name nil)
1432 (source-file-name buffer-file-name)
1433 (master-file-name flymake-master-file-name)
1434 (temp-source-file-name flymake-temp-source-file-name)
1435 (temp-master-file-name flymake-temp-master-file-name)
1436 (base-dirs
1437 (list flymake-base-dir
1438 (file-name-directory source-file-name)
1439 (if master-file-name (file-name-directory master-file-name))))
1440 (files (list (list source-file-name source-file-name)
1441 (list temp-source-file-name source-file-name)
1442 (list master-file-name master-file-name)
1443 (list temp-master-file-name master-file-name))))
1444
1445 (when (equal 0 (length file-name-from-err-msg))
1446 (setq file-name-from-err-msg source-file-name))
1447
1448 (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files))
1449 ;; if real-name is nil, than file name from err msg is none of the files we've patched
1450 (if (not real-name)
1451 (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs)))
1452 (if (not real-name)
1453 (setq real-name file-name-from-err-msg))
1454 (setq real-name (flymake-fix-file-name real-name))
1455 (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name)
1456 real-name))
1457
1458(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files)
1459 (let* ((base-dirs-count (length base-dirs))
1460 (file-count (length files))
1461 (real-name nil))
1462
1463 (while (and (not real-name) (> base-dirs-count 0))
1464 (setq file-count (length files))
1465 (while (and (not real-name) (> file-count 0))
1466 (let* ((this-dir (nth (1- base-dirs-count) base-dirs))
1467 (this-file (nth 0 (nth (1- file-count) files)))
1468 (this-real-name (nth 1 (nth (1- file-count) files))))
1469 ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg)
1470 (when (and this-dir this-file (flymake-same-files
1471 (expand-file-name file-name-from-err-msg this-dir)
1472 this-file))
1473 (setq real-name this-real-name)))
1474 (setq file-count (1- file-count)))
1475 (setq base-dirs-count (1- base-dirs-count)))
1476 real-name))
1477
1478(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
1479 (let* ((real-name nil))
1480 (if (file-name-absolute-p file-name-from-err-msg)
1481 (setq real-name file-name-from-err-msg)
1482 (let* ((base-dirs-count (length base-dirs)))
1483 (while (and (not real-name) (> base-dirs-count 0))
1484 (let* ((full-name (expand-file-name file-name-from-err-msg
1485 (nth (1- base-dirs-count) base-dirs))))
1486 (if (file-exists-p full-name)
1487 (setq real-name full-name))
1488 (setq base-dirs-count (1- base-dirs-count))))))
1489 real-name))
1490
1491(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name)
1492 "Find buildfile, store its dir in buffer data and return its dir, if found."
1493 (let* ((buildfile-dir
1494 (flymake-find-buildfile buildfile-name
1495 (file-name-directory source-file-name))))
1496 (if buildfile-dir
1497 (setq flymake-base-dir buildfile-dir)
1498 (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name)
1499 (flymake-report-fatal-status
1500 "NOMK" (format "No buildfile (%s) found for %s"
1501 buildfile-name source-file-name)))))
1502
1503(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp)
1504 "Find master file (or buffer), create its copy along with a copy of the source file."
1505 (let* ((source-file-name buffer-file-name)
1506 (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))
1507 (master-and-temp-master (flymake-create-master-file
1508 source-file-name temp-source-file-name
1509 get-incl-dirs-f create-temp-f
1510 master-file-masks include-regexp)))
1511
1512 (if (not master-and-temp-master)
1513 (progn
1514 (flymake-log 1 "cannot find master file for %s" source-file-name)
1515 (flymake-report-status "!" "") ; NOMASTER
1516 nil)
1517 (setq flymake-master-file-name (nth 0 master-and-temp-master))
1518 (setq flymake-temp-master-file-name (nth 1 master-and-temp-master)))))
1519
1520(defun flymake-master-cleanup ()
1521 (flymake-simple-cleanup)
1522 (flymake-safe-delete-file flymake-temp-master-file-name))
1523
1524;;;; make-specific init-cleanup routines
1525(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f)
1526 "Create a command line for syntax check using GET-CMD-LINE-F."
1527 (funcall get-cmd-line-f
1528 (if use-relative-source
1529 (file-relative-name source-file-name base-dir)
1530 source-file-name)
1531 (if use-relative-base-dir
1532 (file-relative-name base-dir
1533 (file-name-directory source-file-name))
1534 base-dir)))
1535
1536(defun flymake-get-make-cmdline (source base-dir)
1537 (list "make"
1538 (list "-s"
1539 "-C"
1540 base-dir
1541 (concat "CHK_SOURCES=" source)
1542 "SYNTAX_CHECK_MODE=1"
1543 "check-syntax")))
1544
1545(defun flymake-get-ant-cmdline (source base-dir)
1546 (list "ant"
1547 (list "-buildfile"
1548 (concat base-dir "/" "build.xml")
1549 (concat "-DCHK_SOURCES=" source)
1550 "check-syntax")))
1551
1552(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f)
1553 "Create syntax check command line for a directly checked source file.
1554Use CREATE-TEMP-F for creating temp copy."
1555 (let* ((args nil)
1556 (source-file-name buffer-file-name)
1557 (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name)))
1558 (if buildfile-dir
1559 (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)))
1560 (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir
1561 use-relative-base-dir use-relative-source
1562 get-cmdline-f))))
1563 args))
1564
1565(defun flymake-simple-make-init ()
1566 (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline))
1567
1568(defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp)
1569 "Create make command line for a source file checked via master file compilation."
1570 (let* ((make-args nil)
1571 (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
1572 get-incl-dirs-f 'flymake-create-temp-inplace
1573 master-file-masks include-regexp)))
1574 (when temp-master-file-name
1575 (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile")))
1576 (if buildfile-dir
1577 (setq make-args (flymake-get-syntax-check-program-args
1578 temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline)))))
1579 make-args))
1580
1581(defun flymake-find-make-buildfile (source-dir)
1582 (flymake-find-buildfile "Makefile" source-dir))
1583
1584;;;; .h/make specific
1585(defun flymake-master-make-header-init ()
1586 (flymake-master-make-init
1587 'flymake-get-include-dirs
1588 '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
1589 "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
1590
1591;;;; .java/make specific
1592(defun flymake-simple-make-java-init ()
1593 (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline))
1594
1595(defun flymake-simple-ant-java-init ()
1596 (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline))
1597
1598(defun flymake-simple-java-cleanup ()
1599 "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs."
1600 (flymake-safe-delete-file flymake-temp-source-file-name)
1601 (when flymake-temp-source-file-name
1602 (flymake-delete-temp-directory
1603 (file-name-directory flymake-temp-source-file-name))))
1604
1605;;;; perl-specific init-cleanup routines
1606(defun flymake-perl-init ()
1607 (let* ((temp-file (flymake-init-create-temp-buffer-copy
1608 'flymake-create-temp-inplace))
1609 (local-file (file-relative-name
1610 temp-file
1611 (file-name-directory buffer-file-name))))
1612 (list "perl" (list "-wc " local-file))))
1613
1614;;;; php-specific init-cleanup routines
1615(defun flymake-php-init ()
1616 (let* ((temp-file (flymake-init-create-temp-buffer-copy
1617 'flymake-create-temp-inplace))
1618 (local-file (file-relative-name
1619 temp-file
1620 (file-name-directory buffer-file-name))))
1621 (list "php" (list "-f" local-file "-l"))))
1622
1623;;;; tex-specific init-cleanup routines
1624(defun flymake-get-tex-args (file-name)
1625 ;;(list "latex" (list "-c-style-errors" file-name))
1626 (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
1627
1628(defun flymake-simple-tex-init ()
1629 (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)))
1630
1631;; Perhaps there should be a buffer-local variable flymake-master-file
1632;; that people can set to override this stuff. Could inherit from
1633;; the similar AUCTeX variable.
1634(defun flymake-master-tex-init ()
1635 (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
1636 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace
1637 '("\\.tex\\'")
1638 "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}")))
1639 (when temp-master-file-name
1640 (flymake-get-tex-args temp-master-file-name))))
1641
1642(defun flymake-get-include-dirs-dot (_base-dir)
1643 '("."))
1644
1645;;;; xml-specific init-cleanup routines
1646(defun flymake-xml-init ()
1647 (list flymake-xml-program
1648 (list "val" (flymake-init-create-temp-buffer-copy
1649 'flymake-create-temp-inplace))))
39 1650
40(provide 'flymake) 1651(provide 'flymake)
41;;; flymake.el ends here 1652;;; flymake.el ends here
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index f3513ced4bb..365191c56b0 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -4271,8 +4271,10 @@ See `python-check-command' for the default."
4271 import inspect 4271 import inspect
4272 try: 4272 try:
4273 str_type = basestring 4273 str_type = basestring
4274 argspec_function = inspect.getargspec
4274 except NameError: 4275 except NameError:
4275 str_type = str 4276 str_type = str
4277 argspec_function = inspect.getfullargspec
4276 if isinstance(obj, str_type): 4278 if isinstance(obj, str_type):
4277 obj = eval(obj, globals()) 4279 obj = eval(obj, globals())
4278 doc = inspect.getdoc(obj) 4280 doc = inspect.getdoc(obj)
@@ -4285,9 +4287,7 @@ See `python-check-command' for the default."
4285 target = obj 4287 target = obj
4286 objtype = 'def' 4288 objtype = 'def'
4287 if target: 4289 if target:
4288 args = inspect.formatargspec( 4290 args = inspect.formatargspec(*argspec_function(target))
4289 *inspect.getargspec(target)
4290 )
4291 name = obj.__name__ 4291 name = obj.__name__
4292 doc = '{objtype} {name}{args}'.format( 4292 doc = '{objtype} {name}{args}'.format(
4293 objtype=objtype, name=name, args=args 4293 objtype=objtype, name=name, args=args
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 0bda8bc275d..14598bcafb9 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -593,11 +593,7 @@ sign. See `sh-feature'."
593 (sexp :format "Evaluate: %v")))) 593 (sexp :format "Evaluate: %v"))))
594 :group 'sh-script) 594 :group 'sh-script)
595 595
596 596(define-obsolete-variable-alias 'sh-indentation 'sh-basic-offset "26.1")
597(defcustom sh-indentation 4
598 "The width for further indentation in Shell-Script mode."
599 :type 'integer
600 :group 'sh-script)
601(put 'sh-indentation 'safe-local-variable 'integerp) 597(put 'sh-indentation 'safe-local-variable 'integerp)
602 598
603(defcustom sh-remember-variable-min 3 599(defcustom sh-remember-variable-min 3
@@ -1617,7 +1613,7 @@ with your script for an edit-interpret-debug cycle."
1617 (setq-local skeleton-pair-alist '((?` _ ?`))) 1613 (setq-local skeleton-pair-alist '((?` _ ?`)))
1618 (setq-local skeleton-pair-filter-function 'sh-quoted-p) 1614 (setq-local skeleton-pair-filter-function 'sh-quoted-p)
1619 (setq-local skeleton-further-elements 1615 (setq-local skeleton-further-elements
1620 '((< '(- (min sh-indentation (current-column)))))) 1616 '((< '(- (min sh-basic-offset (current-column))))))
1621 (setq-local skeleton-filter-function 'sh-feature) 1617 (setq-local skeleton-filter-function 'sh-feature)
1622 (setq-local skeleton-newline-indent-rigidly t) 1618 (setq-local skeleton-newline-indent-rigidly t)
1623 (setq-local defun-prompt-regexp 1619 (setq-local defun-prompt-regexp
@@ -2012,7 +2008,7 @@ May return nil if the line should not be treated as continued."
2012 (forward-line -1) 2008 (forward-line -1)
2013 (if (sh-smie--looking-back-at-continuation-p) 2009 (if (sh-smie--looking-back-at-continuation-p)
2014 (current-indentation) 2010 (current-indentation)
2015 (+ (current-indentation) sh-indentation)))) 2011 (+ (current-indentation) sh-basic-offset))))
2016 (t 2012 (t
2017 ;; Just make sure a line-continuation is indented deeper. 2013 ;; Just make sure a line-continuation is indented deeper.
2018 (save-excursion 2014 (save-excursion
@@ -2033,13 +2029,13 @@ May return nil if the line should not be treated as continued."
2033 ;; check the line before that one. 2029 ;; check the line before that one.
2034 (> ci indent)) 2030 (> ci indent))
2035 (t ;Previous line is the beginning of the continued line. 2031 (t ;Previous line is the beginning of the continued line.
2036 (setq indent (min (+ ci sh-indentation) max)) 2032 (setq indent (min (+ ci sh-basic-offset) max))
2037 nil))))) 2033 nil)))))
2038 indent)))))) 2034 indent))))))
2039 2035
2040(defun sh-smie-sh-rules (kind token) 2036(defun sh-smie-sh-rules (kind token)
2041 (pcase (cons kind token) 2037 (pcase (cons kind token)
2042 (`(:elem . basic) sh-indentation) 2038 (`(:elem . basic) sh-basic-offset)
2043 (`(:after . "case-)") (- (sh-var-value 'sh-indent-for-case-alt) 2039 (`(:after . "case-)") (- (sh-var-value 'sh-indent-for-case-alt)
2044 (sh-var-value 'sh-indent-for-case-label))) 2040 (sh-var-value 'sh-indent-for-case-label)))
2045 (`(:before . ,(or `"(" `"{" `"[" "while" "if" "for" "case")) 2041 (`(:before . ,(or `"(" `"{" `"[" "while" "if" "for" "case"))
@@ -2248,8 +2244,8 @@ Point should be before the newline."
2248 2244
2249(defun sh-smie-rc-rules (kind token) 2245(defun sh-smie-rc-rules (kind token)
2250 (pcase (cons kind token) 2246 (pcase (cons kind token)
2251 (`(:elem . basic) sh-indentation) 2247 (`(:elem . basic) sh-basic-offset)
2252 ;; (`(:after . "case") (or sh-indentation smie-indent-basic)) 2248 ;; (`(:after . "case") (or sh-basic-offset smie-indent-basic))
2253 (`(:after . ";") 2249 (`(:after . ";")
2254 (if (smie-rule-parent-p "case") 2250 (if (smie-rule-parent-p "case")
2255 (smie-rule-parent (sh-var-value 'sh-indent-after-case)))) 2251 (smie-rule-parent (sh-var-value 'sh-indent-after-case))))
@@ -2490,7 +2486,7 @@ the value thus obtained, and the result is used instead."
2490 2486
2491(defun sh-basic-indent-line () 2487(defun sh-basic-indent-line ()
2492 "Indent a line for Sh mode (shell script mode). 2488 "Indent a line for Sh mode (shell script mode).
2493Indent as far as preceding non-empty line, then by steps of `sh-indentation'. 2489Indent as far as preceding non-empty line, then by steps of `sh-basic-offset'.
2494Lines containing only comments are considered empty." 2490Lines containing only comments are considered empty."
2495 (interactive) 2491 (interactive)
2496 (let ((previous (save-excursion 2492 (let ((previous (save-excursion
@@ -2514,9 +2510,9 @@ Lines containing only comments are considered empty."
2514 (delete-region (point) 2510 (delete-region (point)
2515 (progn (beginning-of-line) (point))) 2511 (progn (beginning-of-line) (point)))
2516 (if (eolp) 2512 (if (eolp)
2517 (max previous (* (1+ (/ current sh-indentation)) 2513 (max previous (* (1+ (/ current sh-basic-offset))
2518 sh-indentation)) 2514 sh-basic-offset))
2519 (* (1+ (/ current sh-indentation)) sh-indentation)))))) 2515 (* (1+ (/ current sh-basic-offset)) sh-basic-offset))))))
2520 (if (< (current-column) (current-indentation)) 2516 (if (< (current-column) (current-indentation))
2521 (skip-chars-forward " \t")))) 2517 (skip-chars-forward " \t"))))
2522 2518
@@ -3594,6 +3590,10 @@ so that `occur-next' and `occur-prev' will work."
3594(defun sh-learn-buffer-indent (&optional arg) 3590(defun sh-learn-buffer-indent (&optional arg)
3595 "Learn how to indent the buffer the way it currently is. 3591 "Learn how to indent the buffer the way it currently is.
3596 3592
3593If `sh-use-smie' is non-nil, call `smie-config-guess'.
3594Otherwise, run the sh-script specific indent learning command, as
3595decribed below.
3596
3597Output in buffer \"*indent*\" shows any lines which have conflicting 3597Output in buffer \"*indent*\" shows any lines which have conflicting
3598values of a variable, and the final value of all variables learned. 3598values of a variable, and the final value of all variables learned.
3599When called interactively, pop to this buffer automatically if 3599When called interactively, pop to this buffer automatically if
@@ -3610,8 +3610,7 @@ to the value of variable `sh-learn-basic-offset'.
3610 3610
3611Abnormal hook `sh-learned-buffer-hook' if non-nil is called when the 3611Abnormal hook `sh-learned-buffer-hook' if non-nil is called when the
3612function completes. The function is abnormal because it is called 3612function completes. The function is abnormal because it is called
3613with an alist of variables learned. This feature may be changed or 3613with an alist of variables learned.
3614removed in the future.
3615 3614
3616This command can often take a long time to run." 3615This command can often take a long time to run."
3617 (interactive "P") 3616 (interactive "P")
@@ -3809,7 +3808,6 @@ This command can often take a long time to run."
3809 " has" "s have") 3808 " has" "s have")
3810 (if (zerop num-diffs) 3809 (if (zerop num-diffs)
3811 "." ":")))))) 3810 "." ":"))))))
3812 ;; Are abnormal hooks considered bad form?
3813 (run-hook-with-args 'sh-learned-buffer-hook learned-var-list) 3811 (run-hook-with-args 'sh-learned-buffer-hook learned-var-list)
3814 (and (called-interactively-p 'any) 3812 (and (called-interactively-p 'any)
3815 (or sh-popup-occur-buffer (> num-diffs 0)) 3813 (or sh-popup-occur-buffer (> num-diffs 0))
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 623c9c4e07f..80cdcb3f18b 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -928,12 +928,14 @@ IGNORES is a list of glob patterns."
928 files 928 files
929 (expand-file-name dir) 929 (expand-file-name dir)
930 ignores)) 930 ignores))
931 (def default-directory)
931 (buf (get-buffer-create " *xref-grep*")) 932 (buf (get-buffer-create " *xref-grep*"))
932 (`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist)) 933 (`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist))
933 (status nil) 934 (status nil)
934 (hits nil)) 935 (hits nil))
935 (with-current-buffer buf 936 (with-current-buffer buf
936 (erase-buffer) 937 (erase-buffer)
938 (setq default-directory def)
937 (setq status 939 (setq status
938 (call-process-shell-command command nil t)) 940 (call-process-shell-command command nil t))
939 (goto-char (point-min)) 941 (goto-char (point-min))
diff --git a/lisp/simple.el b/lisp/simple.el
index 1ffe1810672..469557713d7 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -39,11 +39,11 @@
39 39
40(defcustom shell-command-dont-erase-buffer nil 40(defcustom shell-command-dont-erase-buffer nil
41 "If non-nil, output buffer is not erased between shell commands. 41 "If non-nil, output buffer is not erased between shell commands.
42Also, a non-nil value set the point in the output buffer 42Also, a non-nil value sets the point in the output buffer
43once the command complete. 43once the command completes.
44The value `beg-last-out' set point at the beginning of the output, 44The value `beg-last-out' sets point at the beginning of the output,
45`end-last-out' set point at the end of the buffer, `save-point' 45`end-last-out' sets point at the end of the buffer, `save-point'
46restore the buffer position before the command." 46restores the buffer position before the command."
47 :type '(choice 47 :type '(choice
48 (const :tag "Erase buffer" nil) 48 (const :tag "Erase buffer" nil)
49 (const :tag "Set point to beginning of last output" beg-last-out) 49 (const :tag "Set point to beginning of last output" beg-last-out)
@@ -53,9 +53,9 @@ restore the buffer position before the command."
53 :version "26.1") 53 :version "26.1")
54 54
55(defvar shell-command-saved-pos nil 55(defvar shell-command-saved-pos nil
56 "Point position in the output buffer after command complete. 56 "Point position in the output buffer after command completes.
57It is an alist (BUFFER . POS), where BUFFER is the output 57It is an alist of (BUFFER . POS), where BUFFER is the output
58buffer, and POS is the point position in BUFFER once the command finish. 58buffer, and POS is the point position in BUFFER once the command finishes.
59This variable is used when `shell-command-dont-erase-buffer' is non-nil.") 59This variable is used when `shell-command-dont-erase-buffer' is non-nil.")
60 60
61(defcustom idle-update-delay 0.5 61(defcustom idle-update-delay 0.5
@@ -434,10 +434,6 @@ A non-nil INTERACTIVE argument means to run the `post-self-insert-hook'."
434 ;; Do the rest in post-self-insert-hook, because we want to do it 434 ;; Do the rest in post-self-insert-hook, because we want to do it
435 ;; *before* other functions on that hook. 435 ;; *before* other functions on that hook.
436 (lambda () 436 (lambda ()
437 ;; We are not going to insert any newlines if arg is
438 ;; non-positive.
439 (or (and (numberp arg) (<= arg 0))
440 (cl-assert (eq ?\n (char-before))))
441 ;; Mark the newline(s) `hard'. 437 ;; Mark the newline(s) `hard'.
442 (if use-hard-newlines 438 (if use-hard-newlines
443 (set-hard-newline-properties 439 (set-hard-newline-properties
@@ -456,25 +452,22 @@ A non-nil INTERACTIVE argument means to run the `post-self-insert-hook'."
456 ;; starts a page. 452 ;; starts a page.
457 (or was-page-start 453 (or was-page-start
458 (move-to-left-margin nil t))))) 454 (move-to-left-margin nil t)))))
459 (unwind-protect 455 (if (not interactive)
460 (if (not interactive) 456 ;; FIXME: For non-interactive uses, many calls actually
461 ;; FIXME: For non-interactive uses, many calls actually 457 ;; just want (insert "\n"), so maybe we should do just
462 ;; just want (insert "\n"), so maybe we should do just 458 ;; that, so as to avoid the risk of filling or running
463 ;; that, so as to avoid the risk of filling or running 459 ;; abbrevs unexpectedly.
464 ;; abbrevs unexpectedly. 460 (let ((post-self-insert-hook (list postproc)))
465 (let ((post-self-insert-hook (list postproc))) 461 (self-insert-command arg))
466 (self-insert-command arg)) 462 (unwind-protect
467 (unwind-protect 463 (progn
468 (progn 464 (add-hook 'post-self-insert-hook postproc nil t)
469 (add-hook 'post-self-insert-hook postproc nil t) 465 (self-insert-command arg))
470 (self-insert-command arg)) 466 ;; We first used let-binding to protect the hook, but that
471 ;; We first used let-binding to protect the hook, but that 467 ;; was naive since add-hook affects the symbol-default
472 ;; was naive since add-hook affects the symbol-default 468 ;; value of the variable, whereas the let-binding might
473 ;; value of the variable, whereas the let-binding might 469 ;; only protect the buffer-local value.
474 ;; only protect the buffer-local value. 470 (remove-hook 'post-self-insert-hook postproc t))))
475 (remove-hook 'post-self-insert-hook postproc t)))
476 (cl-assert (not (member postproc post-self-insert-hook)))
477 (cl-assert (not (member postproc (default-value 'post-self-insert-hook))))))
478 nil) 471 nil)
479 472
480(defun set-hard-newline-properties (from to) 473(defun set-hard-newline-properties (from to)
@@ -1010,7 +1003,7 @@ Called with one argument METHOD.
1010If METHOD is `delete-only', then delete the region; the return value 1003If METHOD is `delete-only', then delete the region; the return value
1011is undefined. If METHOD is nil, then return the content as a string. 1004is undefined. If METHOD is nil, then return the content as a string.
1012If METHOD is `bounds', then return the boundaries of the region 1005If METHOD is `bounds', then return the boundaries of the region
1013as a list of the form (START . END). 1006as a list of pairs of (START . END) positions.
1014If METHOD is anything else, delete the region and return its content 1007If METHOD is anything else, delete the region and return its content
1015as a string, after filtering it with `filter-buffer-substring', which 1008as a string, after filtering it with `filter-buffer-substring', which
1016is called with METHOD as its 3rd argument.") 1009is called with METHOD as its 3rd argument.")
@@ -5480,7 +5473,7 @@ also checks the value of `use-empty-active-region'."
5480 (progn (cl-assert (mark)) t))) 5473 (progn (cl-assert (mark)) t)))
5481 5474
5482(defun region-bounds () 5475(defun region-bounds ()
5483 "Return the boundaries of the region as a list of (START . END) positions." 5476 "Return the boundaries of the region as a list of pairs of (START . END) positions."
5484 (funcall region-extract-function 'bounds)) 5477 (funcall region-extract-function 'bounds))
5485 5478
5486(defun region-noncontiguous-p () 5479(defun region-noncontiguous-p ()
diff --git a/lisp/subr.el b/lisp/subr.el
index 79ae1f4830d..cf15ec287ff 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -289,7 +289,7 @@ The name is made by appending `gensym-counter' to PREFIX.
289PREFIX is a string, and defaults to \"g\"." 289PREFIX is a string, and defaults to \"g\"."
290 (let ((num (prog1 gensym-counter 290 (let ((num (prog1 gensym-counter
291 (setq gensym-counter (1+ gensym-counter))))) 291 (setq gensym-counter (1+ gensym-counter)))))
292 (make-symbol (format "%s%d" prefix num)))) 292 (make-symbol (format "%s%d" (or prefix "g") num))))
293 293
294(defun ignore (&rest _ignore) 294(defun ignore (&rest _ignore)
295 "Do nothing and return nil. 295 "Do nothing and return nil.
@@ -1270,6 +1270,11 @@ See `event-start' for a description of the value returned."
1270 "Return the multi-click count of EVENT, a click or drag event. 1270 "Return the multi-click count of EVENT, a click or drag event.
1271The return value is a positive integer." 1271The return value is a positive integer."
1272 (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1)) 1272 (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1))
1273
1274(defsubst event-line-count (event)
1275 "Return the line count of EVENT, a mousewheel event.
1276The return value is a positive integer."
1277 (if (and (consp event) (integerp (nth 3 event))) (nth 3 event) 1))
1273 1278
1274;;;; Extracting fields of the positions in an event. 1279;;;; Extracting fields of the positions in an event.
1275 1280
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
index 68b659bf751..bc211ea9589 100644
--- a/lisp/term/ns-win.el
+++ b/lisp/term/ns-win.el
@@ -736,6 +736,25 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.")
736(global-unset-key [horizontal-scroll-bar drag-mouse-1]) 736(global-unset-key [horizontal-scroll-bar drag-mouse-1])
737 737
738 738
739;;;; macOS-like defaults for trackpad and mouse wheel scrolling on
740;;;; macOS 10.7+.
741
742;; FIXME: This doesn't look right. Is there a better way to do this
743;; that keeps customize happy?
744(let ((appkit-version (progn
745 (string-match "^appkit-\\([^\s-]*\\)" ns-version-string)
746 (string-to-number (match-string 1 ns-version-string)))))
747 ;; Appkit 1138 ~= macOS 10.7.
748 (when (and (featurep 'cocoa) (>= appkit-version 1138))
749 (setq mouse-wheel-scroll-amount '(1 ((shift) . 5) ((control))))
750 (put 'mouse-wheel-scroll-amount 'customized-value
751 (list (custom-quote (symbol-value 'mouse-wheel-scroll-amount))))
752
753 (setq mouse-wheel-progressive-speed nil)
754 (put 'mouse-wheel-progressive-speed 'customized-value
755 (list (custom-quote (symbol-value 'mouse-wheel-progressive-speed))))))
756
757
739;;;; Color support. 758;;;; Color support.
740 759
741;; Functions for color panel + drag 760;; Functions for color panel + drag
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index dde9e6a8d91..ce9bbf47e77 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -1578,7 +1578,7 @@ to look up will be substituted there."
1578 (goto-char (point-min)) 1578 (goto-char (point-min))
1579 (let ((window (get-buffer-window (current-buffer) 'visible))) 1579 (let ((window (get-buffer-window (current-buffer) 'visible)))
1580 (when window 1580 (when window
1581 (when (re-search-forward "^Summary" nil 'move) 1581 (when (re-search-forward "^\\(Summary\\|Syntax\\)" nil 'move)
1582 (beginning-of-line) 1582 (beginning-of-line)
1583 (set-window-start window (point)))))) 1583 (set-window-start window (point))))))
1584 1584
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index 0c0a51e7df0..6a169622f52 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -1492,8 +1492,10 @@ This is passed to the Ispell process using the `-p' switch.")
1492 (assoc ispell-current-dictionary ispell-local-dictionary-alist) 1492 (assoc ispell-current-dictionary ispell-local-dictionary-alist)
1493 (assoc ispell-current-dictionary ispell-dictionary-alist) 1493 (assoc ispell-current-dictionary ispell-dictionary-alist)
1494 (error "No data for dictionary \"%s\" in `ispell-local-dictionary-alist' or `ispell-dictionary-alist'" 1494 (error "No data for dictionary \"%s\" in `ispell-local-dictionary-alist' or `ispell-dictionary-alist'"
1495 ispell-current-dictionary)))) 1495 ispell-current-dictionary)))
1496 (decode-coding-string (nth n slot) (ispell-get-coding-system) t))) 1496 (str (nth n slot)))
1497 (if (stringp str)
1498 (decode-coding-string str (ispell-get-coding-system) t))))
1497 1499
1498(defun ispell-get-casechars () 1500(defun ispell-get-casechars ()
1499 (ispell-get-decoded-string 1)) 1501 (ispell-get-decoded-string 1))
diff --git a/lisp/textmodes/page-ext.el b/lisp/textmodes/page-ext.el
index d744bd2cf01..94b68decfb7 100644
--- a/lisp/textmodes/page-ext.el
+++ b/lisp/textmodes/page-ext.el
@@ -583,6 +583,7 @@ directory for only the accessible portion of the buffer."
583 (with-output-to-temp-buffer pages-directory-buffer 583 (with-output-to-temp-buffer pages-directory-buffer
584 (with-current-buffer standard-output 584 (with-current-buffer standard-output
585 (pages-directory-mode) 585 (pages-directory-mode)
586 (setq buffer-read-only nil)
586 (insert 587 (insert
587 "==== Pages Directory: use `C-c C-c' to go to page under cursor. ====" ?\n) 588 "==== Pages Directory: use `C-c C-c' to go to page under cursor. ====" ?\n)
588 (setq pages-buffer pages-target-buffer) 589 (setq pages-buffer pages-target-buffer)
@@ -631,6 +632,7 @@ directory for only the accessible portion of the buffer."
631 ))))) 632 )))))
632 633
633 (set-buffer standard-output) 634 (set-buffer standard-output)
635 (setq buffer-read-only t)
634 ;; Put positions in increasing order to go with buffer. 636 ;; Put positions in increasing order to go with buffer.
635 (setq pages-pos-list (nreverse pages-pos-list)) 637 (setq pages-pos-list (nreverse pages-pos-list))
636 (if (called-interactively-p 'interactive) 638 (if (called-interactively-p 'interactive)
diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index 52f56ed990f..d6963d0a1b9 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -608,10 +608,16 @@ considered file(s)."
608 (log-view-diff-common beg end t))) 608 (log-view-diff-common beg end t)))
609 609
610(defun log-view-diff-common (beg end &optional whole-changeset) 610(defun log-view-diff-common (beg end &optional whole-changeset)
611 (let ((to (log-view-current-tag beg)) 611 (let* ((to (log-view-current-tag beg))
612 (fr (log-view-current-tag end))) 612 (fr-entry (log-view-current-entry end))
613 (when (string-equal fr to) 613 (fr (cadr fr-entry)))
614 ;; TO and FR are the same, look at the previous revision. 614 ;; When TO and FR are the same, or when point is on a line after
615 ;; the last entry, look at the previous revision.
616 (when (or (string-equal fr to)
617 (>= (point)
618 (save-excursion
619 (goto-char (car fr-entry))
620 (forward-line))))
615 (setq fr (vc-call-backend log-view-vc-backend 'previous-revision nil fr))) 621 (setq fr (vc-call-backend log-view-vc-backend 'previous-revision nil fr)))
616 (vc-diff-internal 622 (vc-diff-internal
617 t (list log-view-vc-backend 623 t (list log-view-vc-backend
diff --git a/lisp/vc/smerge-mode.el b/lisp/vc/smerge-mode.el
index 112a9bc5247..91be89b5dc1 100644
--- a/lisp/vc/smerge-mode.el
+++ b/lisp/vc/smerge-mode.el
@@ -725,7 +725,7 @@ this keeps \"UUU\"."
725 (let ((i 3)) 725 (let ((i 3))
726 (while (or (not (match-end i)) 726 (while (or (not (match-end i))
727 (< (point) (match-beginning i)) 727 (< (point) (match-beginning i))
728 (>= (point) (match-end i))) 728 (> (point) (match-end i)))
729 (cl-decf i)) 729 (cl-decf i))
730 i)) 730 i))
731 731
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 095f184ddf1..9d7a4d49b8b 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -1035,6 +1035,7 @@ If LIMIT is non-nil, show no more than this many entries."
1035 1035
1036(defun vc-git-log-outgoing (buffer remote-location) 1036(defun vc-git-log-outgoing (buffer remote-location)
1037 (interactive) 1037 (interactive)
1038 (vc-setup-buffer buffer)
1038 (vc-git-command 1039 (vc-git-command
1039 buffer 'async nil 1040 buffer 'async nil
1040 "log" 1041 "log"
@@ -1048,6 +1049,7 @@ If LIMIT is non-nil, show no more than this many entries."
1048 1049
1049(defun vc-git-log-incoming (buffer remote-location) 1050(defun vc-git-log-incoming (buffer remote-location)
1050 (interactive) 1051 (interactive)
1052 (vc-setup-buffer buffer)
1051 (vc-git-command nil 0 nil "fetch") 1053 (vc-git-command nil 0 nil "fetch")
1052 (vc-git-command 1054 (vc-git-command
1053 buffer 'async nil 1055 buffer 'async nil
diff --git a/lisp/xdg.el b/lisp/xdg.el
index e94fa8ec924..76106f42586 100644
--- a/lisp/xdg.el
+++ b/lisp/xdg.el
@@ -84,7 +84,7 @@
84 84
85(defun xdg-thumb-uri (filename) 85(defun xdg-thumb-uri (filename)
86 "Return the canonical URI for FILENAME. 86 "Return the canonical URI for FILENAME.
87If FILENAME has absolute path /foo/bar.jpg, its canonical URI is 87If FILENAME has absolute file name /foo/bar.jpg, its canonical URI is
88file:///foo/bar.jpg" 88file:///foo/bar.jpg"
89 (concat "file://" (expand-file-name filename))) 89 (concat "file://" (expand-file-name filename)))
90 90
@@ -197,8 +197,6 @@ Optional argument GROUP defaults to the string \"Desktop Entry\"."
197 (unless (looking-at xdg-desktop-group-regexp) 197 (unless (looking-at xdg-desktop-group-regexp)
198 (error "Expected group name! Instead saw: %s" 198 (error "Expected group name! Instead saw: %s"
199 (buffer-substring (point) (point-at-eol)))) 199 (buffer-substring (point) (point-at-eol))))
200 (unless (equal (match-string 1) "Desktop Entry")
201 (error "Wrong first group: %s" (match-string 1)))
202 (when group 200 (when group
203 (while (and (re-search-forward xdg-desktop-group-regexp nil t) 201 (while (and (re-search-forward xdg-desktop-group-regexp nil t)
204 (not (equal (match-string 1) group))))) 202 (not (equal (match-string 1) group)))))