aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/buffers.texi15
-rw-r--r--doc/lispref/files.texi3
-rw-r--r--doc/lispref/frames.texi58
-rw-r--r--doc/lispref/text.texi24
-rw-r--r--etc/NEWS21
-rw-r--r--lisp/emacs-lisp/ert.el5
-rw-r--r--lisp/emacs-lisp/smie.el4
-rw-r--r--lisp/emacs-lisp/syntax.el107
-rw-r--r--lisp/eshell/esh-util.el2
-rw-r--r--lisp/files.el19
-rw-r--r--lisp/frame.el20
-rw-r--r--lisp/net/tramp-smb.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.el20
-rw-r--r--lisp/xdg.el4
-rw-r--r--src/callint.c7
-rw-r--r--src/dbusbind.c3
-rw-r--r--src/editfns.c46
-rw-r--r--src/gtkutil.c5
-rw-r--r--src/lisp.h1
-rw-r--r--src/nsterm.m28
-rw-r--r--src/w32term.c6
-rw-r--r--src/xdisp.c4
-rw-r--r--test/lisp/emacs-lisp/subr-x-tests.el9
-rw-r--r--test/lisp/net/tramp-tests.el15
-rw-r--r--test/lisp/textmodes/css-mode-tests.el21
-rw-r--r--test/lisp/xdg-tests.el3
32 files changed, 1938 insertions, 1923 deletions
diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi
index cf24a730ba6..0d02cb3d3e9 100644
--- a/doc/lispref/buffers.texi
+++ b/doc/lispref/buffers.texi
@@ -1089,12 +1089,15 @@ is not cleared by changing major modes.
1089 1089
1090@defopt buffer-offer-save 1090@defopt buffer-offer-save
1091This variable, if non-@code{nil} in a particular buffer, tells 1091This variable, if non-@code{nil} in a particular buffer, tells
1092@code{save-buffers-kill-emacs} and @code{save-some-buffers} (if the 1092@code{save-buffers-kill-emacs} to offer to save that buffer, just as
1093second optional argument to that function is @code{t}) to offer to 1093it offers to save file-visiting buffers. If @code{save-some-buffers}
1094save that buffer, just as they offer to save file-visiting buffers. 1094is called with the second optional argument set to @code{t}, it will
1095@xref{Definition of save-some-buffers}. The variable 1095also offer to save the buffer. Lastly, if this variable is set to the
1096@code{buffer-offer-save} automatically becomes buffer-local when set 1096symbol @code{always}, both @code{save-buffers-kill-emacs} and
1097for any reason. @xref{Buffer-Local Variables}. 1097@code{save-some-buffers} will always offer to save. @xref{Definition
1098of save-some-buffers}. The variable @code{buffer-offer-save}
1099automatically becomes buffer-local when set for any reason.
1100@xref{Buffer-Local Variables}.
1098@end defopt 1101@end defopt
1099 1102
1100@defvar buffer-save-without-query 1103@defvar buffer-save-without-query
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index b1b858a6b4b..f49b02de97c 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -368,8 +368,7 @@ With an argument of 0, unconditionally do @emph{not} make any backup file.
368This command saves some modified file-visiting buffers. Normally it 368This command saves some modified file-visiting buffers. Normally it
369asks the user about each buffer. But if @var{save-silently-p} is 369asks the user about each buffer. But if @var{save-silently-p} is
370non-@code{nil}, it saves all the file-visiting buffers without 370non-@code{nil}, it saves all the file-visiting buffers without
371querying the user. Additionally, buffers whose name begins with a 371querying the user.
372space (``internal'' buffers) will not be offered for save.
373 372
374@vindex save-some-buffers-default-predicate 373@vindex save-some-buffers-default-predicate
375The optional @var{pred} argument provides a predicate that controls 374The optional @var{pred} argument provides a predicate that controls
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 6431bbdedb9..f66ecee8e8e 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -112,37 +112,39 @@ window of another Emacs frame. @xref{Child Frames}.
112* Display Feature Testing:: Determining the features of a terminal. 112* Display Feature Testing:: Determining the features of a terminal.
113@end menu 113@end menu
114 114
115
115@node Creating Frames 116@node Creating Frames
116@section Creating Frames 117@section Creating Frames
117@cindex frame creation 118@cindex frame creation
118 119
119To create a new frame, call the function @code{make-frame}. 120To create a new frame, call the function @code{make-frame}.
120 121
121@deffn Command make-frame &optional alist 122@deffn Command make-frame &optional parameters
122This function creates and returns a new frame, displaying the current 123This function creates and returns a new frame, displaying the current
123buffer. 124buffer.
124 125
125The @var{alist} argument is an alist that specifies frame parameters 126The @var{parameters} argument is an alist that specifies frame
126for the new frame. @xref{Frame Parameters}. If you specify the 127parameters for the new frame. @xref{Frame Parameters}. If you specify
127@code{terminal} parameter in @var{alist}, the new frame is created on 128the @code{terminal} parameter in @var{parameters}, the new frame is
128that terminal. Otherwise, if you specify the @code{window-system} 129created on that terminal. Otherwise, if you specify the
129frame parameter in @var{alist}, that determines whether the frame 130@code{window-system} frame parameter in @var{parameters}, that
130should be displayed on a text terminal or a graphical terminal. 131determines whether the frame should be displayed on a text terminal or a
131@xref{Window Systems}. If neither is specified, the new frame is 132graphical terminal. @xref{Window Systems}. If neither is specified,
132created in the same terminal as the selected frame. 133the new frame is created in the same terminal as the selected frame.
133 134
134Any parameters not mentioned in @var{alist} default to the values in 135Any parameters not mentioned in @var{parameters} default to the values
135the alist @code{default-frame-alist} (@pxref{Initial Parameters}); 136in the alist @code{default-frame-alist} (@pxref{Initial Parameters});
136parameters not specified there default from the X resources or its 137parameters not specified there default from the X resources or its
137equivalent on your operating system (@pxref{X Resources,, X Resources, 138equivalent on your operating system (@pxref{X Resources,, X Resources,
138emacs, The GNU Emacs Manual}). After the frame is created, Emacs 139emacs, The GNU Emacs Manual}). After the frame is created, this
139applies any parameters listed in @code{frame-inherited-parameters} 140function applies any parameters specified in
140(see below) and not present in the argument, taking the values from 141@code{frame-inherited-parameters} (see below) it has no assigned yet,
141the frame that was selected when @code{make-frame} was called. 142taking the values from the frame that was selected when
143@code{make-frame} was called.
142 144
143Note that on multi-monitor displays (@pxref{Multiple Terminals}), the 145Note that on multi-monitor displays (@pxref{Multiple Terminals}), the
144window manager might position the frame differently than specified by 146window manager might position the frame differently than specified by
145the positional parameters in @var{alist} (@pxref{Position 147the positional parameters in @var{parameters} (@pxref{Position
146Parameters}). For example, some window managers have a policy of 148Parameters}). For example, some window managers have a policy of
147displaying the frame on the monitor that contains the largest part of 149displaying the frame on the monitor that contains the largest part of
148the window (a.k.a.@: the @dfn{dominating} monitor). 150the window (a.k.a.@: the @dfn{dominating} monitor).
@@ -158,20 +160,28 @@ A normal hook run by @code{make-frame} before it creates the frame.
158@end defvar 160@end defvar
159 161
160@defvar after-make-frame-functions 162@defvar after-make-frame-functions
161An abnormal hook run by @code{make-frame} after it creates the frame. 163An abnormal hook run by @code{make-frame} after it created the frame.
162Each function in @code{after-make-frame-functions} receives one argument, the 164Each function in @code{after-make-frame-functions} receives one
163frame just created. 165argument, the frame just created.
164@end defvar 166@end defvar
165 167
168Note that any functions added to these hooks by your initial file are
169usually not run for the initial frame, since Emacs reads the initial
170file only after creating that frame. However, if the initial frame is
171specified to use a separate minibuffer frame (@pxref{Minibuffers and
172Frames}), the functions will be run for both, the minibuffer-less and
173the minibuffer frame.
174
166@defvar frame-inherited-parameters 175@defvar frame-inherited-parameters
167This variable specifies the list of frame parameters that a newly 176This variable specifies the list of frame parameters that a newly
168created frame inherits from the currently selected frame. For each 177created frame inherits from the currently selected frame. For each
169parameter (a symbol) that is an element in the list and is not present 178parameter (a symbol) that is an element in this list and has not been
170in the argument to @code{make-frame}, the function sets the value of 179assigned earlier when processing @code{make-frame}, the function sets
171that parameter in the created frame to its value in the selected 180the value of that parameter in the created frame to its value in the
172frame. 181selected frame.
173@end defvar 182@end defvar
174 183
184
175@node Multiple Terminals 185@node Multiple Terminals
176@section Multiple Terminals 186@section Multiple Terminals
177@cindex multiple terminals 187@cindex multiple terminals
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index a7d10797cd0..baa3c708e90 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -54,6 +54,8 @@ the character after point.
54* Registers:: How registers are implemented. Accessing the text or 54* Registers:: How registers are implemented. Accessing the text or
55 position stored in a register. 55 position stored in a register.
56* Transposition:: Swapping two portions of a buffer. 56* Transposition:: Swapping two portions of a buffer.
57* Replacing:: Replacing the text of one buffer with the text
58 of another buffer.
57* Decompression:: Dealing with compressed data. 59* Decompression:: Dealing with compressed data.
58* Base 64:: Conversion to or from base 64 encoding. 60* Base 64:: Conversion to or from base 64 encoding.
59* Checksum/Hash:: Computing cryptographic hashes. 61* Checksum/Hash:: Computing cryptographic hashes.
@@ -4328,6 +4330,28 @@ is non-@code{nil}, @code{transpose-regions} does not do this---it leaves
4328all markers unrelocated. 4330all markers unrelocated.
4329@end defun 4331@end defun
4330 4332
4333@node Replacing
4334@section Replacing Buffer Text
4335
4336 You can use the following function to replace the text of one buffer
4337with the text of another buffer:
4338
4339@deffn Command replace-buffer-contents source
4340This function replaces the accessible portion of the current buffer
4341with the accessible portion of the buffer @var{source}. @var{source}
4342may either be a buffer object or the name of a buffer. When
4343@code{replace-buffer-contents} succeeds, the text of the accessible
4344portion of the current buffer will be equal to the text of the
4345accessible portion of the @var{source} buffer. This function attempts
4346to keep point, markers, text properties, and overlays in the current
4347buffer intact. One potential case where this behavior is useful is
4348external code formatting programs: they typically write the
4349reformatted text into a temporary buffer or file, and using
4350@code{delete-region} and @code{insert-buffer-substring} would destroy
4351these properties. However, the latter combination is typically
4352faster. @xref{Deletion}, and @ref{Insertion}.
4353@end deffn
4354
4331@node Decompression 4355@node Decompression
4332@section Dealing With Compressed Data 4356@section Dealing With Compressed Data
4333 4357
diff --git a/etc/NEWS b/etc/NEWS
index 34561acae56..1b5ae658f6c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -117,6 +117,11 @@ The effect is similar to that of "toolBar" resource on the tool bar.
117 117
118* Changes in Emacs 26.1 118* Changes in Emacs 26.1
119 119
120+++
121** Option 'buffer-offer-save' can be set to new value, 'always'. When
122 set to 'always', the command `save-some-buffers' will always offer
123 this buffer for saving.
124
120** Security vulnerability related to Enriched Text mode is removed. 125** Security vulnerability related to Enriched Text mode is removed.
121 126
122+++ 127+++
@@ -144,8 +149,7 @@ init file:
144'save-buffer' process. Previously, saving a buffer that was not 149'save-buffer' process. Previously, saving a buffer that was not
145visiting a file would always prompt for a file name. Now it only does 150visiting a file would always prompt for a file name. Now it only does
146so if 'write-contents-functions' is nil (or all its functions return 151so if 'write-contents-functions' is nil (or all its functions return
147nil). A non-nil buffer-local value for this variable is sufficient 152nil).
148for 'save-some-buffers' to consider the buffer for saving.
149 153
150--- 154---
151** New variable 'executable-prefix-env' for inserting magic signatures. 155** New variable 'executable-prefix-env' for inserting magic signatures.
@@ -578,7 +582,6 @@ Negative prefix arg flips the direction of selection. Also,
578defun are selected unless they are separated from the defun by a blank 582defun are selected unless they are separated from the defun by a blank
579line. 583line.
580 584
581---
582** New command 'replace-buffer-contents'. 585** New command 'replace-buffer-contents'.
583This command replaces the contents of the accessible portion of the 586This command replaces the contents of the accessible portion of the
584current buffer with the contents of the accessible portion of a 587current buffer with the contents of the accessible portion of a
@@ -1350,6 +1353,12 @@ non-nil, but the code returned the list in the increasing order of
1350priority instead. Now the code does what the documentation says it 1353priority instead. Now the code does what the documentation says it
1351should do. 1354should do.
1352 1355
1356---
1357** 'eldoc-message' only accepts one argument now. Programs that
1358called it with multiple arguments before should pass them through
1359'format' first. Even that is discouraged: for ElDoc support, you
1360should set 'eldoc-documentation-function' instead of calling
1361'eldoc-message' directly.
1353 1362
1354* Lisp Changes in Emacs 26.1 1363* Lisp Changes in Emacs 26.1
1355 1364
@@ -1891,9 +1900,9 @@ of frame decorations on macOS 10.9+.
1891 1900
1892--- 1901---
1893** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more 1902** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more
1894like the macOS default. The new variables 1903like the macOS default. The new variables 'ns-mwheel-line-height',
1895'ns-use-system-mwheel-acceleration', 'ns-touchpad-scroll-line-height' 1904'ns-use-mwheel-acceleration' and 'ns-use-mwheel-momentum' can be used
1896and 'ns-touchpad-use-momentum' can be used to customize the behavior. 1905to customize the behavior.
1897 1906
1898 1907
1899---------------------------------------------------------------------- 1908----------------------------------------------------------------------
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/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/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 f0a1f2380d9..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)
@@ -5188,15 +5193,11 @@ change the additional actions you can take on files."
5188 (and (buffer-live-p buffer) 5193 (and (buffer-live-p buffer)
5189 (buffer-modified-p buffer) 5194 (buffer-modified-p buffer)
5190 (not (buffer-base-buffer buffer)) 5195 (not (buffer-base-buffer buffer))
5191 (not (eq (aref (buffer-name buffer) 0) ?\s))
5192 (or 5196 (or
5193 (buffer-file-name buffer) 5197 (buffer-file-name buffer)
5194 (and pred 5198 (with-current-buffer buffer
5195 (progn 5199 (or (eq buffer-offer-save 'always)
5196 (set-buffer buffer) 5200 (and pred buffer-offer-save (> (buffer-size) 0)))))
5197 (and buffer-offer-save (> (buffer-size) 0))))
5198 (buffer-local-value
5199 'write-contents-functions buffer))
5200 (or (not (functionp pred)) 5201 (or (not (functionp pred))
5201 (with-current-buffer buffer (funcall pred))) 5202 (with-current-buffer buffer (funcall pred)))
5202 (if arg 5203 (if arg
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/net/tramp-smb.el b/lisp/net/tramp-smb.el
index ee6baaab121..35aa8110946 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -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
@@ -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/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 4e42fd52415..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
@@ -1003,7 +1003,7 @@ Called with one argument METHOD.
1003If METHOD is `delete-only', then delete the region; the return value 1003If METHOD is `delete-only', then delete the region; the return value
1004is 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.
1005If METHOD is `bounds', then return the boundaries of the region 1005If METHOD is `bounds', then return the boundaries of the region
1006as a list of the form (START . END). 1006as a list of pairs of (START . END) positions.
1007If METHOD is anything else, delete the region and return its content 1007If METHOD is anything else, delete the region and return its content
1008as a string, after filtering it with `filter-buffer-substring', which 1008as a string, after filtering it with `filter-buffer-substring', which
1009is called with METHOD as its 3rd argument.") 1009is called with METHOD as its 3rd argument.")
@@ -5473,7 +5473,7 @@ also checks the value of `use-empty-active-region'."
5473 (progn (cl-assert (mark)) t))) 5473 (progn (cl-assert (mark)) t)))
5474 5474
5475(defun region-bounds () 5475(defun region-bounds ()
5476 "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."
5477 (funcall region-extract-function 'bounds)) 5477 (funcall region-extract-function 'bounds))
5478 5478
5479(defun region-noncontiguous-p () 5479(defun region-noncontiguous-p ()
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)))))
diff --git a/src/callint.c b/src/callint.c
index 105ec071d07..469205cc380 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -272,7 +272,7 @@ invoke it. If KEYS is omitted or nil, the return value of
272{ 272{
273 /* `args' will contain the array of arguments to pass to the function. 273 /* `args' will contain the array of arguments to pass to the function.
274 `visargs' will contain the same list but in a nicer form, so that if we 274 `visargs' will contain the same list but in a nicer form, so that if we
275 pass it to `Fformat_message' it will be understandable to a human. */ 275 pass it to styled_format it will be understandable to a human. */
276 Lisp_Object *args, *visargs; 276 Lisp_Object *args, *visargs;
277 Lisp_Object specs; 277 Lisp_Object specs;
278 Lisp_Object filter_specs; 278 Lisp_Object filter_specs;
@@ -502,10 +502,7 @@ invoke it. If KEYS is omitted or nil, the return value of
502 for (i = 2; *tem; i++) 502 for (i = 2; *tem; i++)
503 { 503 {
504 visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n")); 504 visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n"));
505 if (strchr (SSDATA (visargs[1]), '%')) 505 callint_message = styled_format (i - 1, visargs + 1, true, false);
506 callint_message = Fformat_message (i - 1, visargs + 1);
507 else
508 callint_message = visargs[1];
509 506
510 switch (*tem) 507 switch (*tem)
511 { 508 {
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 4a7068416fe..789aa008611 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -237,7 +237,8 @@ static char *
237XD_OBJECT_TO_STRING (Lisp_Object object) 237XD_OBJECT_TO_STRING (Lisp_Object object)
238{ 238{
239 AUTO_STRING (format, "%s"); 239 AUTO_STRING (format, "%s");
240 return SSDATA (CALLN (Fformat, format, object)); 240 Lisp_Object args[] = { format, object };
241 return SSDATA (styled_format (ARRAYELTS (args), args, false, false));
241} 242}
242 243
243#define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \ 244#define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \
diff --git a/src/editfns.c b/src/editfns.c
index 2f8b075817a..e326604467c 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -74,7 +74,6 @@ static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec,
74static long int tm_gmtoff (struct tm *); 74static long int tm_gmtoff (struct tm *);
75static int tm_diff (struct tm *, struct tm *); 75static int tm_diff (struct tm *, struct tm *);
76static void update_buffer_properties (ptrdiff_t, ptrdiff_t); 76static void update_buffer_properties (ptrdiff_t, ptrdiff_t);
77static Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool);
78 77
79#ifndef HAVE_TM_GMTOFF 78#ifndef HAVE_TM_GMTOFF
80# define HAVE_TM_GMTOFF false 79# define HAVE_TM_GMTOFF false
@@ -3959,7 +3958,7 @@ usage: (message FORMAT-STRING &rest ARGS) */)
3959 } 3958 }
3960 else 3959 else
3961 { 3960 {
3962 Lisp_Object val = Fformat_message (nargs, args); 3961 Lisp_Object val = styled_format (nargs, args, true, false);
3963 message3 (val); 3962 message3 (val);
3964 return val; 3963 return val;
3965 } 3964 }
@@ -3985,7 +3984,7 @@ usage: (message-box FORMAT-STRING &rest ARGS) */)
3985 } 3984 }
3986 else 3985 else
3987 { 3986 {
3988 Lisp_Object val = Fformat_message (nargs, args); 3987 Lisp_Object val = styled_format (nargs, args, true, false);
3989 Lisp_Object pane, menu; 3988 Lisp_Object pane, menu;
3990 3989
3991 pane = list1 (Fcons (build_string ("OK"), Qt)); 3990 pane = list1 (Fcons (build_string ("OK"), Qt));
@@ -4141,7 +4140,7 @@ produced text.
4141usage: (format STRING &rest OBJECTS) */) 4140usage: (format STRING &rest OBJECTS) */)
4142 (ptrdiff_t nargs, Lisp_Object *args) 4141 (ptrdiff_t nargs, Lisp_Object *args)
4143{ 4142{
4144 return styled_format (nargs, args, false); 4143 return styled_format (nargs, args, false, true);
4145} 4144}
4146 4145
4147DEFUN ("format-message", Fformat_message, Sformat_message, 1, MANY, 0, 4146DEFUN ("format-message", Fformat_message, Sformat_message, 1, MANY, 0,
@@ -4157,13 +4156,16 @@ and right quote replacement characters are specified by
4157usage: (format-message STRING &rest OBJECTS) */) 4156usage: (format-message STRING &rest OBJECTS) */)
4158 (ptrdiff_t nargs, Lisp_Object *args) 4157 (ptrdiff_t nargs, Lisp_Object *args)
4159{ 4158{
4160 return styled_format (nargs, args, true); 4159 return styled_format (nargs, args, true, true);
4161} 4160}
4162 4161
4163/* Implement ‘format-message’ if MESSAGE is true, ‘format’ otherwise. */ 4162/* Implement ‘format-message’ if MESSAGE is true, ‘format’ otherwise.
4163 If NEW_RESULT, the result is a new string; otherwise, the result
4164 may be one of the arguments. */
4164 4165
4165static Lisp_Object 4166Lisp_Object
4166styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) 4167styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message,
4168 bool new_result)
4167{ 4169{
4168 ptrdiff_t n; /* The number of the next arg to substitute. */ 4170 ptrdiff_t n; /* The number of the next arg to substitute. */
4169 char initial_buffer[4000]; 4171 char initial_buffer[4000];
@@ -4193,6 +4195,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4193 /* The start and end bytepos in the output string. */ 4195 /* The start and end bytepos in the output string. */
4194 ptrdiff_t start, end; 4196 ptrdiff_t start, end;
4195 4197
4198 /* Whether the argument is a newly created string. */
4199 bool_bf new_string : 1;
4200
4196 /* Whether the argument is a string with intervals. */ 4201 /* Whether the argument is a string with intervals. */
4197 bool_bf intervals : 1; 4202 bool_bf intervals : 1;
4198 } *info; 4203 } *info;
@@ -4342,7 +4347,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4342 memset (&discarded[format0 - format_start], 1, 4347 memset (&discarded[format0 - format_start], 1,
4343 format - format0 - (conversion == '%')); 4348 format - format0 - (conversion == '%'));
4344 if (conversion == '%') 4349 if (conversion == '%')
4345 goto copy_char; 4350 {
4351 new_result = true;
4352 goto copy_char;
4353 }
4346 4354
4347 ++n; 4355 ++n;
4348 if (! (n < nargs)) 4356 if (! (n < nargs))
@@ -4352,6 +4360,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4352 if (nspec < ispec) 4360 if (nspec < ispec)
4353 { 4361 {
4354 spec->argument = args[n]; 4362 spec->argument = args[n];
4363 spec->new_string = false;
4355 spec->intervals = false; 4364 spec->intervals = false;
4356 nspec = ispec; 4365 nspec = ispec;
4357 } 4366 }
@@ -4369,6 +4378,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4369 { 4378 {
4370 Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; 4379 Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
4371 spec->argument = arg = Fprin1_to_string (arg, noescape); 4380 spec->argument = arg = Fprin1_to_string (arg, noescape);
4381 spec->new_string = true;
4372 if (STRING_MULTIBYTE (arg) && ! multibyte) 4382 if (STRING_MULTIBYTE (arg) && ! multibyte)
4373 { 4383 {
4374 multibyte = true; 4384 multibyte = true;
@@ -4387,6 +4397,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4387 goto retry; 4397 goto retry;
4388 } 4398 }
4389 spec->argument = arg = Fchar_to_string (arg); 4399 spec->argument = arg = Fchar_to_string (arg);
4400 spec->new_string = true;
4390 } 4401 }
4391 4402
4392 if (!EQ (arg, args[n])) 4403 if (!EQ (arg, args[n]))
@@ -4409,6 +4420,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4409 4420
4410 if (conversion == 's') 4421 if (conversion == 's')
4411 { 4422 {
4423 if (format == end && format - format_start == 2
4424 && (!new_result || spec->new_string)
4425 && ! string_intervals (args[0]))
4426 return arg;
4427
4412 /* handle case (precision[n] >= 0) */ 4428 /* handle case (precision[n] >= 0) */
4413 4429
4414 ptrdiff_t prec = -1; 4430 ptrdiff_t prec = -1;
@@ -4487,6 +4503,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4487 if (string_intervals (arg)) 4503 if (string_intervals (arg))
4488 spec->intervals = arg_intervals = true; 4504 spec->intervals = arg_intervals = true;
4489 4505
4506 new_result = true;
4490 continue; 4507 continue;
4491 } 4508 }
4492 } 4509 }
@@ -4754,6 +4771,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4754 } 4771 }
4755 spec->end = nchars; 4772 spec->end = nchars;
4756 4773
4774 new_result = true;
4757 continue; 4775 continue;
4758 } 4776 }
4759 } 4777 }
@@ -4772,9 +4790,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4772 } 4790 }
4773 convsrc = format_char == '`' ? uLSQM : uRSQM; 4791 convsrc = format_char == '`' ? uLSQM : uRSQM;
4774 convbytes = 3; 4792 convbytes = 3;
4793 new_result = true;
4775 } 4794 }
4776 else if (format_char == '`' && quoting_style == STRAIGHT_QUOTING_STYLE) 4795 else if (format_char == '`' && quoting_style == STRAIGHT_QUOTING_STYLE)
4777 convsrc = "'"; 4796 {
4797 convsrc = "'";
4798 new_result = true;
4799 }
4778 else 4800 else
4779 { 4801 {
4780 /* Copy a single character from format to buf. */ 4802 /* Copy a single character from format to buf. */
@@ -4798,6 +4820,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4798 int c = BYTE8_TO_CHAR (format_char); 4820 int c = BYTE8_TO_CHAR (format_char);
4799 convbytes = CHAR_STRING (c, str); 4821 convbytes = CHAR_STRING (c, str);
4800 convsrc = (char *) str; 4822 convsrc = (char *) str;
4823 new_result = true;
4801 } 4824 }
4802 } 4825 }
4803 4826
@@ -4844,6 +4867,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4844 if (bufsize < p - buf) 4867 if (bufsize < p - buf)
4845 emacs_abort (); 4868 emacs_abort ();
4846 4869
4870 if (! new_result)
4871 return args[0];
4872
4847 if (maybe_combine_byte) 4873 if (maybe_combine_byte)
4848 nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf); 4874 nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf);
4849 Lisp_Object val = make_specified_string (buf, nchars, p - buf, multibyte); 4875 Lisp_Object val = make_specified_string (buf, nchars, p - buf, multibyte);
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 0203a5d5c1a..0da70399193 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1217,7 +1217,10 @@ xg_create_frame_widgets (struct frame *f)
1217 with regular X drawing primitives, so from a GTK/GDK point of 1217 with regular X drawing primitives, so from a GTK/GDK point of
1218 view, the widget is totally blank. When an expose comes, this 1218 view, the widget is totally blank. When an expose comes, this
1219 will make the widget blank, and then Emacs redraws it. This flickers 1219 will make the widget blank, and then Emacs redraws it. This flickers
1220 a lot, so we turn off double buffering. */ 1220 a lot, so we turn off double buffering.
1221 FIXME: gtk_widget_set_double_buffered is deprecated and might stop
1222 working in the future. We need to migrate away from combining
1223 X and GTK+ drawing to a pure GTK+ build. */
1221 gtk_widget_set_double_buffered (wfixed, FALSE); 1224 gtk_widget_set_double_buffered (wfixed, FALSE);
1222 1225
1223 gtk_window_set_wmclass (GTK_WINDOW (wtop), 1226 gtk_window_set_wmclass (GTK_WINDOW (wtop),
diff --git a/src/lisp.h b/src/lisp.h
index c5030824427..0c3ca3ae06b 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3969,6 +3969,7 @@ extern _Noreturn void time_overflow (void);
3969extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool); 3969extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool);
3970extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, 3970extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t,
3971 ptrdiff_t, bool); 3971 ptrdiff_t, bool);
3972extern Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool, bool);
3972extern void init_editfns (bool); 3973extern void init_editfns (bool);
3973extern void syms_of_editfns (void); 3974extern void syms_of_editfns (void);
3974 3975
diff --git a/src/nsterm.m b/src/nsterm.m
index fb3ebc963e7..f0b6a70dae3 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6520,7 +6520,7 @@ not_in_argv (NSString *arg)
6520 6520
6521 /* FIXME: At the top or bottom of the buffer we should 6521 /* FIXME: At the top or bottom of the buffer we should
6522 * ignore momentum-phase events. */ 6522 * ignore momentum-phase events. */
6523 if (! ns_touchpad_use_momentum 6523 if (! ns_use_mwheel_momentum
6524 && [theEvent momentumPhase] != NSEventPhaseNone) 6524 && [theEvent momentumPhase] != NSEventPhaseNone)
6525 return; 6525 return;
6526 6526
@@ -6529,8 +6529,8 @@ not_in_argv (NSString *arg)
6529 static int totalDeltaX, totalDeltaY; 6529 static int totalDeltaX, totalDeltaY;
6530 int lineHeight; 6530 int lineHeight;
6531 6531
6532 if (NUMBERP (ns_touchpad_scroll_line_height)) 6532 if (NUMBERP (ns_mwheel_line_height))
6533 lineHeight = XINT (ns_touchpad_scroll_line_height); 6533 lineHeight = XINT (ns_mwheel_line_height);
6534 else 6534 else
6535 { 6535 {
6536 /* FIXME: Use actual line height instead of the default. */ 6536 /* FIXME: Use actual line height instead of the default. */
@@ -6571,7 +6571,7 @@ not_in_argv (NSString *arg)
6571 totalDeltaX = 0; 6571 totalDeltaX = 0;
6572 } 6572 }
6573 6573
6574 if (lines > 1 && ! ns_use_system_mwheel_acceleration) 6574 if (lines > 1 && ! ns_use_mwheel_acceleration)
6575 lines = 1; 6575 lines = 1;
6576 } 6576 }
6577 else 6577 else
@@ -6589,7 +6589,7 @@ not_in_argv (NSString *arg)
6589 delta = [theEvent scrollingDeltaY]; 6589 delta = [theEvent scrollingDeltaY];
6590 } 6590 }
6591 6591
6592 lines = (ns_use_system_mwheel_acceleration) 6592 lines = (ns_use_mwheel_acceleration)
6593 ? ceil (fabs (delta)) : 1; 6593 ? ceil (fabs (delta)) : 1;
6594 6594
6595 scrollUp = delta > 0; 6595 scrollUp = delta > 0;
@@ -9284,22 +9284,22 @@ Note that this does not apply to images.
9284This variable is ignored on Mac OS X < 10.7 and GNUstep. */); 9284This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9285 ns_use_srgb_colorspace = YES; 9285 ns_use_srgb_colorspace = YES;
9286 9286
9287 DEFVAR_BOOL ("ns-use-system-mwheel-acceleration", 9287 DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9288 ns_use_system_mwheel_acceleration, 9288 ns_use_mwheel_acceleration,
9289 doc: /*Non-nil means use macOS's standard mouse wheel acceleration. 9289 doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
9290This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); 9290This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9291 ns_use_system_mwheel_acceleration = YES; 9291 ns_use_mwheel_acceleration = YES;
9292 9292
9293 DEFVAR_LISP ("ns-touchpad-scroll-line-height", ns_touchpad_scroll_line_height, 9293 DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9294 doc: /*The number of pixels touchpad scrolling considers a line. 9294 doc: /*The number of pixels touchpad scrolling considers one line.
9295Nil or a non-number means use the default frame line height. 9295Nil or a non-number means use the default frame line height.
9296This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */); 9296This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */);
9297 ns_touchpad_scroll_line_height = Qnil; 9297 ns_mwheel_line_height = Qnil;
9298 9298
9299 DEFVAR_BOOL ("ns-touchpad-use-momentum", ns_touchpad_use_momentum, 9299 DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9300 doc: /*Non-nil means touchpad scrolling uses momentum. 9300 doc: /*Non-nil means mouse wheel scrolling uses momentum.
9301This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); 9301This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9302 ns_touchpad_use_momentum = YES; 9302 ns_use_mwheel_momentum = YES;
9303 9303
9304 /* TODO: move to common code */ 9304 /* TODO: move to common code */
9305 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, 9305 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
diff --git a/src/w32term.c b/src/w32term.c
index a7a510b9ecb..d7ec40118f3 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -6252,7 +6252,8 @@ w32fullscreen_hook (struct frame *f)
6252 6252
6253 if (FRAME_PREV_FSMODE (f) == FULLSCREEN_BOTH) 6253 if (FRAME_PREV_FSMODE (f) == FULLSCREEN_BOTH)
6254 { 6254 {
6255 SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW); 6255 if (!FRAME_UNDECORATED (f))
6256 SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
6256 SetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f)); 6257 SetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
6257 } 6258 }
6258 else if (FRAME_PREV_FSMODE (f) == FULLSCREEN_HEIGHT 6259 else if (FRAME_PREV_FSMODE (f) == FULLSCREEN_HEIGHT
@@ -6278,7 +6279,8 @@ w32fullscreen_hook (struct frame *f)
6278 6279
6279 w32_fullscreen_rect (hwnd, f->want_fullscreen, 6280 w32_fullscreen_rect (hwnd, f->want_fullscreen,
6280 FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect); 6281 FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect);
6281 SetWindowLong (hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW); 6282 if (!FRAME_UNDECORATED (f))
6283 SetWindowLong (hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
6282 SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, 6284 SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
6283 rect.right - rect.left, rect.bottom - rect.top, 6285 rect.right - rect.left, rect.bottom - rect.top,
6284 SWP_NOOWNERZORDER | SWP_FRAMECHANGED); 6286 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
diff --git a/src/xdisp.c b/src/xdisp.c
index 141275f15a0..86164eb9f6f 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -10194,7 +10194,7 @@ vadd_to_log (char const *format, va_list ap)
10194 for (ptrdiff_t i = 1; i <= nargs; i++) 10194 for (ptrdiff_t i = 1; i <= nargs; i++)
10195 args[i] = va_arg (ap, Lisp_Object); 10195 args[i] = va_arg (ap, Lisp_Object);
10196 Lisp_Object msg = Qnil; 10196 Lisp_Object msg = Qnil;
10197 msg = Fformat_message (nargs, args); 10197 msg = styled_format (nargs, args, true, false);
10198 10198
10199 ptrdiff_t len = SBYTES (msg) + 1; 10199 ptrdiff_t len = SBYTES (msg) + 1;
10200 USE_SAFE_ALLOCA; 10200 USE_SAFE_ALLOCA;
@@ -19525,7 +19525,7 @@ DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "",
19525usage: (trace-to-stderr STRING &rest OBJECTS) */) 19525usage: (trace-to-stderr STRING &rest OBJECTS) */)
19526 (ptrdiff_t nargs, Lisp_Object *args) 19526 (ptrdiff_t nargs, Lisp_Object *args)
19527{ 19527{
19528 Lisp_Object s = Fformat (nargs, args); 19528 Lisp_Object s = styled_format (nargs, args, false, false);
19529 fwrite (SDATA (s), 1, SBYTES (s), stderr); 19529 fwrite (SDATA (s), 1, SBYTES (s), stderr);
19530 return Qnil; 19530 return Qnil;
19531} 19531}
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index 2c6740a96cf..0e8871d9a9c 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -397,9 +397,14 @@
397 (should (equal 1 (let ((x 1)) (and-let* (x))))) 397 (should (equal 1 (let ((x 1)) (and-let* (x)))))
398 (should (equal nil (and-let* ((x nil))))) 398 (should (equal nil (and-let* ((x nil)))))
399 (should (equal 1 (and-let* ((x 1))))) 399 (should (equal 1 (and-let* ((x 1)))))
400 (should-error (and-let* (nil (x 1))) :type 'setting-constant) 400 ;; The error doesn't trigger when compiled: the compiler will give
401 ;; a warning and then drop the erroneous code. Therefore, use
402 ;; `eval' to avoid compilation.
403 (should-error (eval '(and-let* (nil (x 1))) lexical-binding)
404 :type 'setting-constant)
401 (should (equal nil (and-let* ((nil) (x 1))))) 405 (should (equal nil (and-let* ((nil) (x 1)))))
402 (should-error (and-let* (2 (x 1))) :type 'wrong-type-argument) 406 (should-error (eval (and-let* (2 (x 1))) lexical-binding)
407 :type 'wrong-type-argument)
403 (should (equal 1 (and-let* ((2) (x 1))))) 408 (should (equal 1 (and-let* ((2) (x 1)))))
404 (should (equal 2 (and-let* ((x 1) (2))))) 409 (should (equal 2 (and-let* ((x 1) (2)))))
405 (should (equal nil (let ((x nil)) (and-let* (x) x)))) 410 (should (equal nil (let ((x nil)) (and-let* (x) x))))
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 88e97092ed7..bfdc3017804 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -2653,8 +2653,9 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
2653 (tmp-name1 (tramp--test-make-temp-name nil quoted)) 2653 (tmp-name1 (tramp--test-make-temp-name nil quoted))
2654 (tmp-name2 (tramp--test-make-temp-name nil quoted)) 2654 (tmp-name2 (tramp--test-make-temp-name nil quoted))
2655 (tmp-name3 (tramp--test-make-temp-name 'local quoted)) 2655 (tmp-name3 (tramp--test-make-temp-name 'local quoted))
2656 (tmp-name4 (tramp--test-make-temp-name nil quoted))) 2656 (tmp-name4 (tramp--test-make-temp-name nil quoted))
2657 2657 (tmp-name5
2658 (expand-file-name (file-name-nondirectory tmp-name1) tmp-name4)))
2658 ;; Check `make-symbolic-link'. 2659 ;; Check `make-symbolic-link'.
2659 (unwind-protect 2660 (unwind-protect
2660 (tramp--test-ignore-make-symbolic-link-error 2661 (tramp--test-ignore-make-symbolic-link-error
@@ -2716,9 +2717,11 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
2716 (funcall 2717 (funcall
2717 (if quoted 'tramp-compat-file-name-unquote 'identity) 2718 (if quoted 'tramp-compat-file-name-unquote 'identity)
2718 (file-remote-p tmp-name1 'localname)) 2719 (file-remote-p tmp-name1 'localname))
2719 (file-symlink-p 2720 (file-symlink-p tmp-name5)))
2720 (expand-file-name 2721 ;; `smbclient' does not show symlinks in directories, so
2721 (file-name-nondirectory tmp-name1) tmp-name4))))) 2722 ;; we cannot delete a non-empty directory. We delete the
2723 ;; file explicitely.
2724 (delete-file tmp-name5))
2722 2725
2723 ;; Cleanup. 2726 ;; Cleanup.
2724 (ignore-errors 2727 (ignore-errors
@@ -2737,7 +2740,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
2737 (should-error 2740 (should-error
2738 (add-name-to-file tmp-name1 tmp-name2) 2741 (add-name-to-file tmp-name1 tmp-name2)
2739 :type 'file-already-exists) 2742 :type 'file-already-exists)
2740 ;; number means interactive case. 2743 ;; A number means interactive case.
2741 (cl-letf (((symbol-function 'yes-or-no-p) 'ignore)) 2744 (cl-letf (((symbol-function 'yes-or-no-p) 'ignore))
2742 (should-error 2745 (should-error
2743 (add-name-to-file tmp-name1 tmp-name2 0) 2746 (add-name-to-file tmp-name1 tmp-name2 0)
diff --git a/test/lisp/textmodes/css-mode-tests.el b/test/lisp/textmodes/css-mode-tests.el
index f93fdbbc5af..47cf5f9244b 100644
--- a/test/lisp/textmodes/css-mode-tests.el
+++ b/test/lisp/textmodes/css-mode-tests.el
@@ -80,6 +80,27 @@
80 (equal (seq-sort #'string-lessp (css--value-class-lookup 'position)) 80 (equal (seq-sort #'string-lessp (css--value-class-lookup 'position))
81 '("bottom" "calc()" "center" "left" "right" "top")))) 81 '("bottom" "calc()" "center" "left" "right" "top"))))
82 82
83(ert-deftest css-test-current-defun-name ()
84 (with-temp-buffer
85 (insert "body { top: 0; }")
86 (goto-char 7)
87 (should (equal (css-current-defun-name) "body"))
88 (goto-char 18)
89 (should (equal (css-current-defun-name) "body"))))
90
91(ert-deftest css-test-current-defun-name-nested ()
92 (with-temp-buffer
93 (insert "body > .main a { top: 0; }")
94 (goto-char 20)
95 (should (equal (css-current-defun-name) "body > .main a"))))
96
97(ert-deftest css-test-current-defun-name-complex ()
98 (with-temp-buffer
99 (insert "input[type=submit]:hover { color: red; }")
100 (goto-char 30)
101 (should (equal (css-current-defun-name)
102 "input[type=submit]:hover"))))
103
83;;; Completion 104;;; Completion
84 105
85(defun css-mode-tests--completions () 106(defun css-mode-tests--completions ()
diff --git a/test/lisp/xdg-tests.el b/test/lisp/xdg-tests.el
index e3c9a743e44..b80f5e85524 100644
--- a/test/lisp/xdg-tests.el
+++ b/test/lisp/xdg-tests.el
@@ -42,9 +42,6 @@
42 (should (equal "frobnicate" (gethash "Exec" tab2)))) 42 (should (equal "frobnicate" (gethash "Exec" tab2))))
43 (should-error 43 (should-error
44 (xdg-desktop-read-file 44 (xdg-desktop-read-file
45 (expand-file-name "wrong.desktop" xdg-tests-data-dir)))
46 (should-error
47 (xdg-desktop-read-file
48 (expand-file-name "malformed.desktop" xdg-tests-data-dir))) 45 (expand-file-name "malformed.desktop" xdg-tests-data-dir)))
49 (let ((tab (xdg-desktop-read-file 46 (let ((tab (xdg-desktop-read-file
50 (expand-file-name "l10n.desktop" xdg-tests-data-dir))) 47 (expand-file-name "l10n.desktop" xdg-tests-data-dir)))