]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/compile.el
Add new error and function `user-error'.
[gnu-emacs] / lisp / progmodes / compile.el
index 88f418f934a42a3ee9d06b28c8ab8958aa49111b..f22ee4f7ea5d51b2d1fc1a6151311875f3f05b7c 100644 (file)
@@ -1,6 +1,6 @@
 ;;; compile.el --- run compiler as inferior of Emacs, parse error messages
 
-;; Copyright (C) 1985-1987, 1993-1999, 2001-2011
+;; Copyright (C) 1985-1987, 1993-1999, 2001-2012
 ;;   Free Software Foundation, Inc.
 
 ;; Authors: Roland McGrath <roland@gnu.org>,
@@ -64,8 +64,24 @@ the compilation to be killed, you can use this hook:
                 integer)
   :group 'compilation)
 
+(defvar compilation-filter-hook nil
+  "Hook run after `compilation-filter' has inserted a string into the buffer.
+It is called with the variable `compilation-filter-start' bound
+to the position of the start of the inserted text, and point at
+its end.
+
+If Emacs lacks asynchronous process support, this hook is run
+after `call-process' inserts the grep output into the buffer.")
+
+(defvar compilation-filter-start nil
+  "Position of the start of the text inserted by `compilation-filter'.
+This is bound before running `compilation-filter-hook'.")
+
 (defvar compilation-first-column 1
-  "*This is how compilers number the first column, usually 1 or 0.")
+  "This is how compilers number the first column, usually 1 or 0.
+If this is buffer-local in the destination buffer, Emacs obeys
+that value, otherwise it uses the value in the *compilation*
+buffer.  This enables a major-mode to specify its own value.")
 
 (defvar compilation-parse-errors-filename-function nil
   "Function to call to post-process filenames while parsing error messages.
@@ -74,7 +90,7 @@ in the compilation output, and should return a transformed file name.")
 
 ;;;###autoload
 (defvar compilation-process-setup-function nil
-  "*Function to call to customize the compilation process.
+  "Function to call to customize the compilation process.
 This function is called immediately before the compilation process is
 started.  It can be used to set any variables or functions that are used
 while processing the output of the compilation process.")
@@ -116,6 +132,9 @@ and a string describing how the process finished.")
 
 (defvar compilation-num-errors-found)
 
+;; If you make any changes to `compilation-error-regexp-alist-alist',
+;; be sure to run the ERT test in test/automated/compile-tests.el.
+
 (defvar compilation-error-regexp-alist-alist
   '((absoft
      "^\\(?:[Ee]rror on \\|[Ww]arning on\\( \\)\\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
@@ -128,8 +147,8 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
      " in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
 
     (ant
-     "^[ \t]*\\[[^] \n]+\\][ \t]*\\([^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):[0-9]+:[0-9]+:\\)?\
-\\( warning\\)?" 1 2 3 (4))
+     "^[ \t]*\\[[^] \n]+\\][ \t]*\\([^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\):\\)?\
+\\( warning\\)?" 1 (2 . 4) (3 . 5) (6))
 
     (bash
      "^\\([^: \n\t]+\\): line \\([0-9]+\\):" 1 2)
@@ -139,9 +158,9 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
 \\([a-zA-Z]?:?[^:( \t\n]+\\)\
  \\([0-9]+\\)\\(?:[) \t]\\|:[^0-9\n]\\)" 2 3 nil (1))
 
-    (caml
-     "^ *File \\(\"?\\)\\([^,\" \n\t<>]+\\)\\1, lines? \\([0-9]+\\)-?\\([0-9]+\\)?\\(?:$\\|,\
-\\(?: characters? \\([0-9]+\\)-?\\([0-9]+\\)?:\\)?\\([ \n]Warning:\\)?\\)"
+    (python-tracebacks-and-caml
+     "^[ \t]*File \\(\"?\\)\\([^,\" \n\t<>]+\\)\\1, lines? \\([0-9]+\\)-?\\([0-9]+\\)?\\(?:$\\|,\
+\\(?: characters? \\([0-9]+\\)-?\\([0-9]+\\)?:\\)?\\([ \n]Warning\\(?: [0-9]+\\)?:\\)?\\)"
      2 (3 . 4) (5 . 6) (7))
 
     (comma
@@ -184,6 +203,14 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
 
     (jikes-file
      "^\\(?:Found\\|Issued\\) .* compiling \"\\(.+\\)\":$" 1 nil nil 0)
+
+
+    ;; This used to be pathologically slow on long lines (Bug#3441),
+    ;; due to matching filenames via \\(.*?\\).  This might be faster.
+    (maven
+     ;; Maven is a popular free software build tool for Java.
+     "\\([0-9]*[^0-9\n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\] " 1 2 3)
+
     (jikes-line
      "^ *\\([0-9]+\\)\\.[ \t]+.*\n +\\(<-*>\n\\*\\*\\* \\(?:Error\\|Warnin\\(g\\)\\)\\)"
      nil 1 nil 2 0
@@ -195,6 +222,9 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
 \\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?\\(?:\\(:\\)\\|\\(,\\|$\\)\\)?"
      1 2 3 (4 . 5))
 
+    (ruby-Test::Unit
+     "^[\t ]*\\[\\([^\(].*\\):\\([1-9][0-9]*\\)\\(\\]\\)?:in " 1 2)
+
     (gnu
      ;; The first line matches the program name for
 
@@ -226,7 +256,7 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
 \\(?:-\\([0-9]+\\)?\\(?:\\.\\([0-9]+\\)\\)?\\)?:\
 \\(?: *\\(\\(?:Future\\|Runtime\\)?[Ww]arning\\|W:\\)\\|\
  *\\([Ii]nfo\\(?:\\>\\|rmationa?l?\\)\\|I:\\|instantiated from\\|[Nn]ote\\)\\|\
-\[0-9]?\\(?:[^0-9\n]\\|$\\)\\|[0-9][0-9][0-9]\\)"
+ *[Ee]rror\\|\[0-9]?\\(?:[^0-9\n]\\|$\\)\\|[0-9][0-9][0-9]\\)"
      1 (2 . 4) (3 . 5) (6 . 7))
 
     (lcc
@@ -247,11 +277,6 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
                (end-of-line)
                nil)))
 
-    ;; This regexp is pathologically slow on long lines (Bug#3441).
-    ;; (maven
-    ;;  ;; Maven is a popular build tool for Java.  Maven is Free Software.
-    ;;  "\\(.*?\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\]" 1 2 3)
-
     ;; Should be lint-1, lint-2 (SysV lint)
     (mips-1
      " (\\([0-9]+\\)) in \\([^ \n]+\\)" 2 1)
@@ -292,9 +317,6 @@ during global destruction\\.$\\)" 1 2)
      "\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)"
      2 3 nil nil)
 
-    (ruby-Test::Unit
-     "[\t ]*\\[\\([^\(].*\\):\\([1-9][0-9]*\\)\\(\\]\\)?:$" 1 2)
-
     (rxp
      "^\\(?:Error\\|Warnin\\(g\\)\\):.*\n.* line \\([0-9]+\\) char\
  \\([0-9]+\\) of file://\\(.+\\)"
@@ -381,15 +403,16 @@ File = \\(.+\\), Line = \\([0-9]+\\)\\(?:, Column = \\([0-9]+\\)\\)?"
      "^# Failed test [0-9]+ in \\([^ \t\r\n]+\\) at line \\([0-9]+\\)"
      1 2)
     (perl--Test2
-     ;; Or when comparing got/want values,
+     ;; Or when comparing got/want values, with a "fail #n" if repeated
      ;; # Test 2 got: "xx" (t-compilation-perl-2.t at line 10)
+     ;; # Test 3 got: "xx" (t-compilation-perl-2.t at line 10 fail #2)
      ;;
      ;; And under Test::Harness they're preceded by progress stuff with
      ;; \r and "NOK",
      ;; ... NOK 1# Test 1 got: "1234" (t/foo.t at line 46)
      ;;
      "^\\(.*NOK.*\\)?# Test [0-9]+ got:.* (\\([^ \t\r\n]+\\) at line \
-\\([0-9]+\\))"
+\\([0-9]+\\)\\( fail #[0-9]+\\)?)"
      2 3)
     (perl--Test::Harness
      ;; perl Test::Harness output, eg.
@@ -503,7 +526,7 @@ you may also want to change `compilation-page-delimiter'.")
      ;; Command output lines.  Recognize `make[n]:' lines too.
      ("^\\([[:alnum:]_/.+-]+\\)\\(\\[\\([0-9]+\\)\\]\\)?[ \t]*:"
       (1 font-lock-function-name-face) (3 compilation-line-face nil t))
-     (" -\\(?:o[= ]?\\|-\\(?:outfile\\|output\\)[= ]\\)\\(\\S +\\)" . 1)
+     (" --?o\\(?:utfile\\|utput\\)?[= ]\\(\\S +\\)" . 1)
      ("^Compilation \\(finished\\).*"
       (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
       (1 compilation-info-face))
@@ -527,7 +550,10 @@ Otherwise they are interpreted as character positions, with
 each character occupying one column.
 The default is to use screen columns, which requires that the compilation
 program and Emacs agree about the display width of the characters,
-especially the TAB character."
+especially the TAB character.
+If this is buffer-local in the destination buffer, Emacs obeys
+that value, otherwise it uses the value in the *compilation*
+buffer.  This enables a major-mode to specify its own value."
   :type 'boolean
   :group 'compilation
   :version "20.4")
@@ -607,7 +633,7 @@ This only affects platforms that support asynchronous processes (see
 (defvar compilation-locs ())
 
 (defvar compilation-debug nil
-  "*Set this to t before creating a *compilation* buffer.
+  "Set this to t before creating a *compilation* buffer.
 Then every error line will have a debug text property with the matcher that
 fit this line and the match data.  Use `describe-text-properties'.")
 
@@ -617,29 +643,33 @@ This should be a function of three arguments: process status, exit status,
 and exit message; it returns a cons (MESSAGE . MODELINE) of the strings to
 write into the compilation buffer, and to put in its mode line.")
 
-(defvar compilation-environment nil
-  "*List of environment variables for compilation to inherit.
+(defcustom compilation-environment nil
+  "List of environment variables for compilation to inherit.
 Each element should be a string of the form ENVVARNAME=VALUE.
 This list is temporarily prepended to `process-environment' prior to
-starting the compilation process.")
+starting the compilation process."
+  :type '(repeat (string :tag "ENVVARNAME=VALUE"))
+  :options '(("LANG=C"))
+  :group 'compilation
+  :version "24.1")
 
 ;; History of compile commands.
 (defvar compile-history nil)
 
 (defface compilation-error
-  '((t :inherit font-lock-warning-face))
+  '((t :inherit error))
   "Face used to highlight compiler errors."
   :group 'compilation
   :version "22.1")
 
 (defface compilation-warning
-  '((t :inherit font-lock-variable-name-face))
+  '((t :inherit warning))
   "Face used to highlight compiler warnings."
   :group 'compilation
   :version "22.1")
 
 (defface compilation-info
-  '((t :inherit font-lock-type-face))
+  '((t :inherit success))
   "Face used to highlight compiler information."
   :group 'compilation
   :version "22.1")
@@ -709,7 +739,7 @@ Faces `compilation-error-face', `compilation-warning-face',
 ;; (make-variable-buffer-local 'compilation-buffer-modtime)
 
 (defvar compilation-skip-to-next-location t
-  "*If non-nil, skip multiple error messages for the same source location.")
+  "If non-nil, skip multiple error messages for the same source location.")
 
 (defcustom compilation-skip-threshold 1
   "Compilation motion commands skip less important messages.
@@ -833,7 +863,7 @@ returned RES, i.e. there is no change of `compilation-directory' between
 POS and RES.")
 (make-variable-buffer-local 'compilation--previous-directory-cache)
 
-(defun compilation--flush-directory-cache (start end)
+(defun compilation--flush-directory-cache (start _end)
   (cond
    ((or (not compilation--previous-directory-cache)
         (<= (car compilation--previous-directory-cache) start)))
@@ -860,27 +890,29 @@ POS and RES.")
                        (car compilation--previous-directory-cache)))
            (prev
             (previous-single-property-change
-             pos 'compilation-directory nil cache)))
-      (cond
-       ((null cache)
-        (setq compilation--previous-directory-cache
-              (cons (copy-marker pos) (copy-marker prev)))
-        prev)
-       ((eq prev cache)
-        (if cache
-            (set-marker (car compilation--previous-directory-cache) pos)
-          (setq compilation--previous-directory-cache
-                (cons (copy-marker pos) nil)))
-        (cdr compilation--previous-directory-cache))
-       (t
-        (if cache
-            (progn
-              (set-marker (car compilation--previous-directory-cache) pos)
-              (setcdr compilation--previous-directory-cache
-                      (copy-marker prev)))
-          (setq compilation--previous-directory-cache
-                (cons (copy-marker pos) (copy-marker prev))))
-        prev)))))
+             pos 'compilation-directory nil cache))
+           (res
+            (cond
+             ((null cache)
+              (setq compilation--previous-directory-cache
+                    (cons (copy-marker pos) (if prev (copy-marker prev))))
+              prev)
+             ((and prev (= prev cache))
+              (if cache
+                  (set-marker (car compilation--previous-directory-cache) pos)
+                (setq compilation--previous-directory-cache
+                      (cons (copy-marker pos) nil)))
+              (cdr compilation--previous-directory-cache))
+             (t
+              (if cache
+                  (progn
+                    (set-marker cache pos)
+                    (setcdr compilation--previous-directory-cache
+                            (copy-marker prev)))
+                (setq compilation--previous-directory-cache
+                      (cons (copy-marker pos) (if prev (copy-marker prev)))))
+              prev))))
+      (if (markerp res) (marker-position res) res))))
 
 ;; Internal function for calculating the text properties of a directory
 ;; change message.  The compilation-directory property is important, because it
@@ -889,7 +921,7 @@ POS and RES.")
 (defun compilation-directory-properties (idx leave)
   (if leave (setq leave (match-end leave)))
   ;; find previous stack, and push onto it, or if `leave' pop it
-  (let ((dir (compilation--previous-directory (point))))
+  (let ((dir (compilation--previous-directory (match-beginning 0))))
     (setq dir (if dir (or (get-text-property (1- dir) 'compilation-directory)
                          (get-text-property dir 'compilation-directory))))
     `(font-lock-face ,(if leave
@@ -948,7 +980,8 @@ POS and RES.")
                             (match-string-no-properties file))))
          (let ((dir
            (unless (file-name-absolute-p file)
-                   (let ((pos (compilation--previous-directory (point))))
+                   (let ((pos (compilation--previous-directory
+                               (match-beginning 0))))
                      (when pos
                        (or (get-text-property (1- pos) 'compilation-directory)
                            (get-text-property pos 'compilation-directory)))))))
@@ -962,12 +995,15 @@ POS and RES.")
            (let* ((prev
                    (or (get-text-property (1- prev-pos) 'compilation-message)
                        (get-text-property prev-pos 'compilation-message)))
-                  (prev-struct
-                   (car (nth 2 (car prev)))))
+                  (prev-file-struct
+                   (and prev
+                        (compilation--loc->file-struct
+                         (compilation--message->loc prev)))))
+
              ;; Construct FILE . DIR from that.
-             (if prev-struct
-                 (setq file (cons (car prev-struct)
-                                  (cadr prev-struct))))))
+             (if prev-file-struct
+                 (setq file (cons (caar prev-file-struct)
+                                  (cadr (car prev-file-struct)))))))
        (unless file
          (setq file '("*unknown*")))))
     ;; All of these fields are optional, get them only if we have an index, and
@@ -983,11 +1019,11 @@ POS and RES.")
             (setq col (funcall col))
           (and
            (setq col (match-string-no-properties col))
-           (setq col (- (string-to-number col) compilation-first-column)))))
+           (setq col (string-to-number col)))))
     (if (and end-col (functionp end-col))
         (setq end-col (funcall end-col))
       (if (and end-col (setq end-col (match-string-no-properties end-col)))
-          (setq end-col (- (string-to-number end-col) compilation-first-column -1))
+          (setq end-col (- (string-to-number end-col) -1))
         (if end-line (setq end-col -1))))
     (if (consp type)                   ; not a static type, check what it is.
        (setq type (or (and (car type) (match-end (car type)) 1)
@@ -1007,6 +1043,7 @@ POS and RES.")
   "Go to column COL on the current line.
 If SCREEN is non-nil, columns are screen columns, otherwise, they are
 just char-counts."
+  (setq col (- col compilation-first-column))
   (if screen
       (move-to-column (max col 0))
     (goto-char (min (+ (line-beginning-position) col) (line-end-position)))))
@@ -1026,7 +1063,8 @@ FMTS is a list of format specs for transforming the file name.
           (cadr (compilation--file-struct->loc-tree file-struct)))
         (marker
           (if marker-line (compilation--loc->marker (cadr marker-line))))
-        (compilation-error-screen-columns compilation-error-screen-columns)
+        (screen-columns compilation-error-screen-columns)
+        (first-column compilation-first-column)
         end-marker loc end-loc)
     (if (not (and marker (marker-buffer marker)))
        (setq marker nil)               ; no valid marker for this file
@@ -1034,16 +1072,24 @@ FMTS is a list of format specs for transforming the file name.
       (catch 'marker                   ; find nearest loc, at least one exists
        (dolist (x (cddr (compilation--file-struct->loc-tree
                           file-struct)))       ; Loop over remaining lines.
-         (if (> (car x) loc)           ; still bigger
+         (if (> (car x) loc)           ; Still bigger.
              (setq marker-line x)
            (if (> (- (or (car marker-line) 1) loc)
-                  (- loc (car x)))     ; current line is nearer
+                  (- loc (car x)))     ; Current line is nearer.
                (setq marker-line x))
            (throw 'marker t))))
       (setq marker (compilation--loc->marker (cadr marker-line))
            marker-line (or (car marker-line) 1))
       (with-current-buffer (marker-buffer marker)
-       (save-excursion
+        (let ((screen-columns
+               ;; Obey the compilation-error-screen-columns of the target
+               ;; buffer if its major mode set it buffer-locally.
+               (if (local-variable-p 'compilation-error-screen-columns)
+                   compilation-error-screen-columns screen-columns))
+             (compilation-first-column
+               (if (local-variable-p 'compilation-first-column)
+                   compilation-first-column first-column)))
+          (save-excursion
          (save-restriction
            (widen)
            (goto-char (marker-position marker))
@@ -1051,17 +1097,15 @@ FMTS is a list of format specs for transforming the file name.
              (beginning-of-line (- (or end-line line) marker-line -1))
              (if (or (null end-col) (< end-col 0))
                  (end-of-line)
-               (compilation-move-to-column
-                end-col compilation-error-screen-columns))
+               (compilation-move-to-column end-col screen-columns))
              (setq end-marker (point-marker)))
            (beginning-of-line (if end-line
                                   (- line end-line -1)
                                 (- loc marker-line -1)))
            (if col
-               (compilation-move-to-column
-                col compilation-error-screen-columns)
+               (compilation-move-to-column col screen-columns)
              (forward-to-indentation 0))
-           (setq marker (point-marker))))))
+           (setq marker (point-marker)))))))
 
     (setq loc (compilation-assq line (compilation--file-struct->loc-tree
                                       file-struct)))
@@ -1304,7 +1348,7 @@ to `compilation-error-regexp-alist' if RULES is nil."
           (compilation--parse-region (point) compilation--parsed)))))
   nil)
 
-(defun compilation--flush-parse (start end)
+(defun compilation--flush-parse (start _end)
   "Mark the region between START and END for re-parsing."
   (if (markerp compilation--parsed)
       (move-marker compilation--parsed (min start compilation--parsed))))
@@ -1396,31 +1440,31 @@ point on its location in the *compilation* buffer."
   :group 'compilation)
 
 
-(defun compilation-buffer-name (mode-name mode-command name-function)
+(defun compilation-buffer-name (name-of-mode mode-command name-function)
   "Return the name of a compilation buffer to use.
-If NAME-FUNCTION is non-nil, call it with one argument MODE-NAME
+If NAME-FUNCTION is non-nil, call it with one argument NAME-OF-MODE
 to determine the buffer name.
 Likewise if `compilation-buffer-name-function' is non-nil.
 If current buffer has the major mode MODE-COMMAND,
 return the name of the current buffer, so that it gets reused.
-Otherwise, construct a buffer name from MODE-NAME."
+Otherwise, construct a buffer name from NAME-OF-MODE."
   (cond (name-function
-        (funcall name-function mode-name))
+        (funcall name-function name-of-mode))
        (compilation-buffer-name-function
-        (funcall compilation-buffer-name-function mode-name))
+        (funcall compilation-buffer-name-function name-of-mode))
        ((eq mode-command major-mode)
         (buffer-name))
        (t
-        (concat "*" (downcase mode-name) "*"))))
+        (concat "*" (downcase name-of-mode) "*"))))
 
 ;; This is a rough emulation of the old hack, until the transition to new
 ;; compile is complete.
 (defun compile-internal (command error-message
-                                &optional name-of-mode parser
+                                &optional _name-of-mode parser
                                 error-regexp-alist name-function
-                                enter-regexp-alist leave-regexp-alist
-                                file-regexp-alist nomessage-regexp-alist
-                                no-async highlight-regexp local-map)
+                                _enter-regexp-alist _leave-regexp-alist
+                                file-regexp-alist _nomessage-regexp-alist
+                                _no-async highlight-regexp _local-map)
   (if parser
       (error "Compile now works very differently, see `compilation-error-regexp-alist'"))
   (let ((compilation-error-regexp-alist
@@ -1456,6 +1500,7 @@ Returns the compilation buffer created."
              "compilation"
            (replace-regexp-in-string "-mode\\'" "" (symbol-name mode))))
         (thisdir default-directory)
+        (thisenv compilation-environment)
         outwin outbuf)
     (with-current-buffer
        (setq outbuf
@@ -1502,8 +1547,9 @@ Returns the compilation buffer created."
         ;; Remember the original dir, so we can use it when we recompile.
         ;; default-directory' can't be used reliably for that because it may be
         ;; affected by the special handling of "cd ...;".
-        ;; NB: must be fone after (funcall mode) as that resets local variables
+        ;; NB: must be done after (funcall mode) as that resets local variables
         (set (make-local-variable 'compilation-directory) thisdir)
+       (set (make-local-variable 'compilation-environment) thisenv)
        (if highlight-regexp
            (set (make-local-variable 'compilation-highlight-regexp)
                 highlight-regexp))
@@ -1610,8 +1656,10 @@ Returns the compilation buffer created."
            ;; regardless of where the user sees point.
            (goto-char (point-max))
            (let* ((inhibit-read-only t) ; call-process needs to modify outbuf
+                  (compilation-filter-start (point))
                   (status (call-process shell-file-name nil outbuf nil "-c"
                                         command)))
+             (run-hooks 'compilation-filter-hook)
              (cond ((numberp status)
                     (compilation-handle-exit
                      'exit status
@@ -1934,12 +1982,15 @@ Optional argument MINOR indicates this is called from
 
 ;;;###autoload
 (define-minor-mode compilation-shell-minor-mode
-  "Toggle compilation shell minor mode.
-With arg, turn compilation mode on if and only if arg is positive.
-In this minor mode, all the error-parsing commands of the
-Compilation major mode are available but bound to keys that don't
-collide with Shell mode.  See `compilation-mode'.
-Turning the mode on runs the normal hook `compilation-shell-minor-mode-hook'."
+  "Toggle Compilation Shell minor mode.
+With a prefix argument ARG, enable Compilation Shell minor mode
+if ARG is positive, and disable it otherwise.  If called from
+Lisp, enable the mode if ARG is omitted or nil.
+
+When Compilation Shell minor mode is enabled, all the
+error-parsing commands of the Compilation major mode are
+available but bound to keys that don't collide with Shell mode.
+See `compilation-mode'."
   nil " Shell-Compile"
   :group 'compilation
   (if compilation-shell-minor-mode
@@ -1948,11 +1999,14 @@ Turning the mode on runs the normal hook `compilation-shell-minor-mode-hook'."
 
 ;;;###autoload
 (define-minor-mode compilation-minor-mode
-  "Toggle compilation minor mode.
-With arg, turn compilation mode on if and only if arg is positive.
-In this minor mode, all the error-parsing commands of the
-Compilation major mode are available.  See `compilation-mode'.
-Turning the mode on runs the normal hook `compilation-minor-mode-hook'."
+  "Toggle Compilation minor mode.
+With a prefix argument ARG, enable Compilation minor mode if ARG
+is positive, and disable it otherwise.  If called from Lisp,
+enable the mode if ARG is omitted or nil.
+
+When Compilation minor mode is enabled, all the error-parsing
+commands of Compilation major mode are available.  See
+`compilation-mode'."
   nil " Compilation"
   :group 'compilation
   (if compilation-minor-mode
@@ -2035,11 +2089,12 @@ and runs `compilation-filter-hook'."
             ;; If we are inserting at the end of the accessible part of the
             ;; buffer, keep the inserted text visible.
            (min (point-min-marker))
-           (max (copy-marker (point-max) t)))
+           (max (copy-marker (point-max) t))
+           (compilation-filter-start (marker-position (process-mark proc))))
         (unwind-protect
             (progn
              (widen)
-              (goto-char (process-mark proc))
+             (goto-char compilation-filter-start)
               ;; We used to use `insert-before-markers', so that windows with
               ;; point at `process-mark' scroll along with the output, but we
               ;; now use window-point-insertion-type instead.
@@ -2077,14 +2132,14 @@ and runs `compilation-filter-hook'."
           (if (or (eq (get-text-property ,limit 'compilation-message)
                       (get-text-property opt 'compilation-message))
                   (eq pt opt))
-              (error ,error compilation-error)
+              (user-error ,error compilation-error)
             (setq pt ,limit)))
        ;; prop 'compilation-message usually has 2 changes, on and off, so
        ;; re-search if off
        (or (setq msg (get-text-property pt 'compilation-message))
           (if (setq pt (,property-change pt 'compilation-message nil ,limit))
               (setq msg (get-text-property pt 'compilation-message)))
-          (error ,error compilation-error))
+          (user-error ,error compilation-error))
        (or (< (compilation--message->type msg) compilation-skip-threshold)
           (if different-file
               (eq (prog1 last
@@ -2225,8 +2280,9 @@ This is the value of `next-error-function' in Compilation buffers."
   (interactive "p")
   (when reset
     (setq compilation-current-error nil))
-  (let* ((columns compilation-error-screen-columns) ; buffer's local value
-        (last 1) timestamp
+  (let* ((screen-columns compilation-error-screen-columns)
+        (first-column compilation-first-column)
+        (last 1)
         (msg (compilation-next-error (or n 1) nil
                                      (or compilation-current-error
                                          compilation-messages-start
@@ -2260,29 +2316,37 @@ This is the value of `next-error-function' in Compilation buffers."
            marker
            (caar (compilation--loc->file-struct loc))
            (cadr (car (compilation--loc->file-struct loc))))
-       (save-restriction
-         (widen)
-         (goto-char (point-min))
-         ;; Treat file's found lines in forward order, 1 by 1.
-         (dolist (line (reverse (cddr (compilation--loc->file-struct loc))))
-           (when (car line)            ; else this is a filename w/o a line#
-             (beginning-of-line (- (car line) last -1))
-             (setq last (car line)))
-           ;; Treat line's found columns and store/update a marker for each.
-           (dolist (col (cdr line))
-             (if (compilation--loc->col col)
-                 (if (eq (compilation--loc->col col) -1)
-                      ;; Special case for range end.
-                     (end-of-line)
-                   (compilation-move-to-column (compilation--loc->col col)
-                                                columns))
-               (beginning-of-line)
-               (skip-chars-forward " \t"))
-             (if (compilation--loc->marker col)
-                  (set-marker (compilation--loc->marker col) (point))
-               (setf (compilation--loc->marker col) (point-marker)))
-              ;; (setf (compilation--loc->timestamp col) timestamp)
-              )))))
+        (let ((screen-columns
+               ;; Obey the compilation-error-screen-columns of the target
+               ;; buffer if its major mode set it buffer-locally.
+               (if (local-variable-p 'compilation-error-screen-columns)
+                   compilation-error-screen-columns screen-columns))
+              (compilation-first-column
+               (if (local-variable-p 'compilation-first-column)
+                   compilation-first-column first-column)))
+          (save-restriction
+            (widen)
+            (goto-char (point-min))
+            ;; Treat file's found lines in forward order, 1 by 1.
+            (dolist (line (reverse (cddr (compilation--loc->file-struct loc))))
+              (when (car line)         ; else this is a filename w/o a line#
+                (beginning-of-line (- (car line) last -1))
+                (setq last (car line)))
+              ;; Treat line's found columns and store/update a marker for each.
+              (dolist (col (cdr line))
+                (if (compilation--loc->col col)
+                    (if (eq (compilation--loc->col col) -1)
+                        ;; Special case for range end.
+                        (end-of-line)
+                      (compilation-move-to-column (compilation--loc->col col)
+                                                  screen-columns))
+                  (beginning-of-line)
+                  (skip-chars-forward " \t"))
+                (if (compilation--loc->marker col)
+                    (set-marker (compilation--loc->marker col) (point))
+                  (setf (compilation--loc->marker col) (point-marker)))
+                ;; (setf (compilation--loc->timestamp col) timestamp)
+                ))))))
     (compilation-goto-locus marker (compilation--loc->marker loc)
                             (compilation--loc->marker end-loc))
     (setf (compilation--loc->visited loc) t)))
@@ -2373,9 +2437,8 @@ and overlay is highlighted between MK and END-MK."
                             ;; also do this while we change buffer
                             (compilation-set-window w msg)
                             compilation-highlight-regexp)))
-    ;; Ideally, the window-size should be passed to `display-buffer' (via
-    ;; something like special-display-buffer) so it's only used when
-    ;; creating a new window.
+    ;; Ideally, the window-size should be passed to `display-buffer'
+    ;; so it's only used when creating a new window.
     (unless pre-existing (compilation-set-window-height w))
 
     (if from-compilation-buffer
@@ -2384,9 +2447,7 @@ and overlay is highlighted between MK and END-MK."
         ;; display the source in another window.
         (let ((pop-up-windows t))
           (pop-to-buffer (marker-buffer mk) 'other-window))
-      (if (window-dedicated-p (selected-window))
-          (pop-to-buffer (marker-buffer mk))
-        (switch-to-buffer (marker-buffer mk))))
+      (switch-to-buffer (marker-buffer mk)))
     (unless (eq (goto-char mk) (point))
       ;; If narrowing gets in the way of going to the right place, widen.
       (widen)
@@ -2599,9 +2660,6 @@ The file-structure looks like this:
                (if (eq v fs) (remhash k compilation-locs)))
              compilation-locs)))
 
-(add-to-list 'debug-ignored-errors "\\`No more [-a-z ]+s yet\\'")
-(add-to-list 'debug-ignored-errors "\\`Moved past last .*")
-
 ;;; Compatibility with the old compile.el.
 
 (defvaralias 'compilation-last-buffer 'next-error-last-buffer)