]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/compile.el
Merge branch 'emacs-25-merge'
[gnu-emacs] / lisp / progmodes / compile.el
index d9c482330ccc7e3e7a4847efca6a5426a3b6883c..f13906680cf7ff88a87465a6c9aae9b929611feb 100644 (file)
@@ -1,11 +1,11 @@
-;;; compile.el --- run compiler as inferior of Emacs, parse error messages
+;;; compile.el --- run compiler as inferior of Emacs, parse error messages  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1985-1987, 1993-1999, 2001-2013 Free Software
+;; Copyright (C) 1985-1987, 1993-1999, 2001-2015 Free Software
 ;; Foundation, Inc.
 
 ;; Authors: Roland McGrath <roland@gnu.org>,
 ;;         Daniel Pfeiffer <occitan@esperanto.org>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: tools, processes
 
 ;; This file is part of GNU Emacs.
@@ -134,7 +134,7 @@ and a string describing how the process finished.")
 ;; emacs -batch -l compile-tests.el -f ert-run-tests-batch-and-exit
 
 (defvar compilation-error-regexp-alist-alist
-  '((absoft
+  `((absoft
      "^\\(?:[Ee]rror on \\|[Ww]arning on\\( \\)\\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
 of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
 
@@ -145,7 +145,7 @@ 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]+\\):\\)?\
+     "^[ \t]*\\[[^] \n]+\\][ \t]*\\(\\(?:[A-Za-z]:\\\\\\)?[^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\):\\)?\
 \\( warning\\)?" 1 (2 . 4) (3 . 5) (6))
 
     (bash
@@ -167,7 +167,7 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
 
     (cucumber
      "\\(?:^cucumber\\(?: -p [^[:space:]]+\\)?\\|#\\)\
-\\(?: \\)\\([^\(].*\\):\\([1-9][0-9]*\\)" 1 2)
+\\(?: \\)\\([^(].*\\):\\([1-9][0-9]*\\)" 1 2)
 
     (msft
      ;; Must be before edg-1, so that MSVC's longer messages are
@@ -216,7 +216,7 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
     ;; due to matching filenames via \\(.*?\\).  This might be faster.
     (maven
      ;; Maven is a popular free software build tool for Java.
-     "\\([^ \n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\] " 1 2 3)
+     "\\(\\[WARNING\\] *\\)?\\([^ \n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\] " 2 3 4 (1))
 
     (jikes-line
      "^ *\\([0-9]+\\)\\.[ \t]+.*\n +\\(<-*>\n\\*\\*\\* \\(?:Error\\|Warnin\\(g\\)\\)\\)"
@@ -230,7 +230,7 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
      1 2 3 (4 . 5))
 
     (ruby-Test::Unit
-     "^[\t ]*\\[\\([^\(].*\\):\\([1-9][0-9]*\\)\\(\\]\\)?:in " 1 2)
+     "^[\t ]*\\[\\([^(].*\\):\\([1-9][0-9]*\\)\\(\\]\\)?:in " 1 2)
 
     (gnu
      ;; The first line matches the program name for
@@ -255,16 +255,46 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
      ;; can be composed of any non-newline char, but it also rules out some
      ;; valid but unlikely cases, such as a trailing space or a space
      ;; followed by a -, or a colon followed by a space.
-
+     ;;
      ;; The "in \\|from " exception was added to handle messages from Ruby.
-     "^\\(?:[[:alpha:]][-[:alnum:].]+: ?\\|[ \t]+\\(?:in \\|from \\)\\)?\
-\\([0-9]*[^0-9\n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\): ?\
-\\([0-9]+\\)\\(?:-\\(?4:[0-9]+\\)\\(?:\\.\\(?5:[0-9]+\\)\\)?\
-\\|[.:]\\(?3:[0-9]+\\)\\(?:-\\(?:\\(?4:[0-9]+\\)\\.\\)?\\(?5:[0-9]+\\)\\)?\\)?:\
-\\(?: *\\(\\(?:Future\\|Runtime\\)?[Ww]arning\\|W:\\)\\|\
- *\\([Ii]nfo\\(?:\\>\\|rmationa?l?\\)\\|I:\\|\\[ skipping .+ \\]\\|\
-\\(?:instantiated\\|required\\) from\\|[Nn]ote\\)\\|\
- *[Ee]rror\\|[0-9]?\\(?:[^0-9\n]\\|$\\)\\|[0-9][0-9][0-9]\\)"
+     ,(rx
+       bol
+       (? (| (regexp "[[:alpha:]][-[:alnum:].]+: ?")
+             (regexp "[ \t]+\\(?:in \\|from\\)")))
+       (group-n 1 (: (regexp "[0-9]*[^0-9\n]")
+                     (*? (| (regexp "[^\n :]")
+                            (regexp " [^-/\n]")
+                            (regexp ":[^ \n]")))))
+       (regexp ": ?")
+       (group-n 2 (regexp "[0-9]+"))
+       (? (| (: "-"
+                (group-n 4 (regexp "[0-9]+"))
+                (? "." (group-n 5 (regexp "[0-9]+"))))
+             (: (in ".:")
+                (group-n 3 (regexp "[0-9]+"))
+                (? "-"
+                   (? (group-n 4 (regexp "[0-9]+")) ".")
+                   (group-n 5 (regexp "[0-9]+"))))))
+       ":"
+       (| (: (* " ")
+             (group-n 6 (| "FutureWarning"
+                           "RuntimeWarning"
+                           "Warning"
+                           "warning"
+                           "W:")))
+          (: (* " ")
+             (group-n 7 (| (regexp "[Ii]nfo\\(?:\\>\\|rmationa?l?\\)")
+                           "I:"
+                           (: "[ skipping " (+ ".") " ]")
+                           "instantiated from"
+                           "required from"
+                           (regexp "[Nn]ote"))))
+          (: (* " ")
+             (regexp "[Ee]rror"))
+          (: (regexp "[0-9]?")
+             (| (regexp "[^0-9\n]")
+                eol))
+          (regexp "[0-9][0-9][0-9]")))
      1 (2 . 4) (3 . 5) (6 . 7))
 
     (lcc
@@ -347,7 +377,7 @@ File = \\(.+\\), Line = \\([0-9]+\\)\\(?:, Column = \\([0-9]+\\)\\)?"
      3 4 5 (1 . 2))
 
     (sun-ada
-     "^\\([^, \n\t]+\\), line \\([0-9]+\\), char \\([0-9]+\\)[:., \(-]" 1 2 3)
+     "^\\([^, \n\t]+\\), line \\([0-9]+\\), char \\([0-9]+\\)[:., (-]" 1 2 3)
 
     (watcom
      "^[ \t]*\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)): ?\
@@ -447,6 +477,30 @@ File = \\(.+\\), Line = \\([0-9]+\\)\\(?:, Column = \\([0-9]+\\)\\)?"
      ;;
      "^\\([^ \t\r\n(]+\\) (\\([0-9]+\\):\\([0-9]+\\)) "
      1 2 3)
+
+    ;; Guile compilation yields file-headers in the following format:
+    ;;
+    ;;   In sourcefile.scm:
+    ;;
+    ;; We need to catch those, but we also need to be aware that Emacs
+    ;; byte-compilation yields compiler headers in similar form of
+    ;; those:
+    ;;
+    ;;   In toplevel form:
+    ;;   In end of data:
+    ;;
+    ;; We want to catch the Guile file-headers but not the Emacs
+    ;; byte-compilation headers, because that will cause next-error
+    ;; and prev-error to break, because the files "toplevel form" and
+    ;; "end of data" does not exist.
+    ;;
+    ;; To differentiate between these two cases, we require that the
+    ;; file-match must always contain an extension.
+    ;;
+    ;; We should also only treat this as "info", not "error", because
+    ;; we do not know what lines will follow.
+    (guile-file "^In \\(.+\\..+\\):\n" 1 nil nil 0)
+    (guile-line "^ *\\([0-9]+\\): *\\([0-9]+\\)" nil 1 2)
     )
   "Alist of values for `compilation-error-regexp-alist'.")
 
@@ -513,7 +567,7 @@ listed text properties PROP# are given values VAL# as well."
   "Directory to restore to when doing `recompile'.")
 
 (defvar compilation-directory-matcher
-  '("\\(?:Entering\\|Leavin\\(g\\)\\) directory `\\(.+\\)'$" (2 . 1))
+  '("\\(?:Entering\\|Leavin\\(g\\)\\) directory [`']\\(.+\\)'$" (2 . 1))
   "A list for tracking when directories are entered or left.
 If nil, do not track directories, e.g. if all file names are absolute.  The
 first element is the REGEXP matching these messages.  It can match any number
@@ -526,7 +580,7 @@ directory we were in before the last entering message.  If you change this,
 you may also want to change `compilation-page-delimiter'.")
 
 (defvar compilation-page-delimiter
-  "^\\(?:\f\\|.*\\(?:Entering\\|Leaving\\) directory `.+'\n\\)+"
+  "^\\(?:\f\\|.*\\(?:Entering\\|Leaving\\) directory [`'].+'\n\\)+"
   "Value of `page-delimiter' in Compilation mode.")
 
 (defvar compilation-mode-font-lock-keywords
@@ -618,13 +672,15 @@ The value nil as an element means to try the default directory."
 Sometimes it is useful for files to supply local values for this variable.
 You might also use mode hooks to specify it in certain modes, like this:
 
-    (add-hook 'c-mode-hook
+    (add-hook \\='c-mode-hook
        (lambda ()
         (unless (or (file-exists-p \"makefile\")
                     (file-exists-p \"Makefile\"))
-          (set (make-local-variable 'compile-command)
+          (set (make-local-variable \\='compile-command)
                (concat \"make -k \"
-                       (file-name-sans-extension buffer-file-name))))))"
+                       (if buffer-file-name
+                         (shell-quote-argument
+                           (file-name-sans-extension buffer-file-name))))))))"
   :type 'string
   :group 'compilation)
 ;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (or (not (boundp 'compilation-read-command)) compilation-read-command))))
@@ -895,7 +951,7 @@ from a different message."
 (defvar compilation--previous-directory-cache nil
   "A pair (POS . RES) caching the result of previous directory search.
 Basically, this pair says that calling
-   (previous-single-property-change POS 'compilation-directory)
+   (previous-single-property-change POS \\='compilation-directory)
 returned RES, i.e. there is no change of `compilation-directory' between
 POS and RES.")
 (make-variable-buffer-local 'compilation--previous-directory-cache)
@@ -911,7 +967,7 @@ POS and RES.")
    (t (setq compilation--previous-directory-cache nil))))
 
 (defun compilation--previous-directory (pos)
-  "Like (previous-single-property-change POS 'compilation-directory), but faster."
+  "Like (previous-single-property-change POS \\='compilation-directory), but faster."
   ;; This avoids an N² behavior when there's no/few compilation-directory
   ;; entries, in which case each call to previous-single-property-change
   ;; ends up having to walk very far back to find the last change.
@@ -935,19 +991,12 @@ POS and RES.")
                     (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)))
+              (set-marker (car compilation--previous-directory-cache) pos)
               (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)))))
+              (set-marker cache pos)
+              (setcdr compilation--previous-directory-cache
+                      (copy-marker prev))
               prev))))
       (if (markerp res) (marker-position res) res))))
 
@@ -1002,7 +1051,7 @@ POS and RES.")
     (let ((win (get-buffer-window buffer 0)))
       (if win (set-window-point win pos)))
     (if compilation-auto-jump-to-first-error
-       (compile-goto-error nil t))))
+       (compile-goto-error))))
 
 ;; This function is the central driver, called when font-locking to gather
 ;; all information needed to later jump to corresponding source code.
@@ -1082,7 +1131,9 @@ 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))
+      ;; Presumably, the compilation tool doesn't know about our current
+      ;; `tab-width' setting, so it probably assumed 8-wide TABs (bug#21038).
+      (let ((tab-width 8)) (move-to-column (max col 0)))
     (goto-char (min (+ (line-beginning-position) col) (line-end-position)))))
 
 (defun compilation-internal-error-properties (file line end-line col end-col type fmts)
@@ -1352,9 +1403,7 @@ to `compilation-error-regexp-alist' if RULES is nil."
                           (eq (car face) 'face)
                           (or (symbolp (cadr face))
                               (stringp (cadr face))))
-                      (put-text-property
-                       (match-beginning mn) (match-end mn)
-                       'font-lock-face (cadr face))
+                      (compilation--put-prop mn 'font-lock-face (cadr face))
                       (add-text-properties
                        (match-beginning mn) (match-end mn)
                        (nthcdr 2 face)))
@@ -1392,6 +1441,9 @@ to `compilation-error-regexp-alist' if RULES is nil."
         (move-marker compilation--parsed limit)
         (goto-char start)
         (forward-line 0)  ;Not line-beginning-position: ignore (comint) fields.
+        (while (and (not (bobp))
+                    (get-text-property (1- (point)) 'compilation-multiline))
+          (forward-line -1))
         (with-silent-modifications
           (compilation--parse-region (point) compilation--parsed)))))
   nil)
@@ -1427,15 +1479,15 @@ If optional second arg COMINT is t the buffer will be in Comint mode with
 `compilation-shell-minor-mode'.
 
 Interactively, prompts for the command if the variable
-`compilation-read-command' is non-nil; otherwise uses`compile-command'.
+`compilation-read-command' is non-nil; otherwise uses `compile-command'.
 With prefix arg, always prompts.
 Additionally, with universal prefix arg, compilation buffer will be in
 comint mode, i.e. interactive.
 
 To run more than one compilation at once, start one then rename
-the \`*compilation*' buffer to some other name with
+the `*compilation*' buffer to some other name with
 \\[rename-buffer].  Then _switch buffers_ and start the new compilation.
-It will create a new \`*compilation*' buffer.
+It will create a new `*compilation*' buffer.
 
 On most systems, termination of the main compilation process
 kills its subprocesses.
@@ -1466,12 +1518,13 @@ If the optional argument `edit-command' is non-nil, the command can be edited."
   (interactive "P")
   (save-some-buffers (not compilation-ask-about-save)
                      compilation-save-buffers-predicate)
-  (let ((default-directory (or compilation-directory default-directory)))
+  (let ((default-directory (or compilation-directory default-directory))
+       (command (eval compile-command)))
     (when edit-command
-      (setcar compilation-arguments
-              (compilation-read-command (car compilation-arguments))))
-    (apply 'compilation-start (or compilation-arguments
-                                 `(,(eval compile-command))))))
+      (setq command (compilation-read-command (or (car compilation-arguments)
+                                                 command)))
+      (if compilation-arguments (setcar compilation-arguments command)))
+    (apply 'compilation-start (or compilation-arguments (list command)))))
 
 (defcustom compilation-scroll-output nil
   "Non-nil to scroll the *compilation* buffer window as output appears.
@@ -1581,7 +1634,16 @@ Returns the compilation buffer created."
                "\\\\\\(.\\)" "\\1"
                (substring command (1+ (match-beginning 1))
                           (1- (match-end 1)))))
-             (t (substitute-env-vars (match-string 1 command)))))
+             ;; Try globbing as well (bug#15417).
+             (t (let* ((substituted-dir
+                        (substitute-env-vars (match-string 1 command)))
+                       ;; FIXME: This also tries to expand `*' that were
+                       ;; introduced by the envvar expansion!
+                       (expanded-dir
+                        (file-expand-wildcards substituted-dir)))
+                  (if (= (length expanded-dir) 1)
+                      (car expanded-dir)
+                    substituted-dir)))))
        (erase-buffer)
        ;; Select the desired mode.
        (if (not (eq mode t))
@@ -1611,16 +1673,12 @@ Returns the compilation buffer created."
                (format "%s started at %s\n\n"
                        mode-name
                        (substring (current-time-string) 0 19))
-               ;; The command could be split into several lines, see
-               ;; `rgrep' for example.  We want to display it as one
-               ;; line.
-               (apply 'concat (split-string command (regexp-quote "\\\n") t))
-               "\n")
+               command "\n")
        (setq thisdir default-directory))
       (set-buffer-modified-p nil))
     ;; Pop up the compilation buffer.
     ;; http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01638.html
-    (setq outwin (display-buffer outbuf))
+    (setq outwin (display-buffer outbuf '(nil (allow-no-window . t))))
     (with-current-buffer outbuf
       (let ((process-environment
             (append
@@ -1632,17 +1690,22 @@ Returns the compilation buffer created."
                (list "TERM=emacs"
                      (format "TERMCAP=emacs:co#%d:tc=unknown:"
                              (window-width))))
-             ;; Set the EMACS variable, but
-             ;; don't override users' setting of $EMACS.
-             (unless (getenv "EMACS")
-               (list "EMACS=t"))
-             (list "INSIDE_EMACS=t")
+             (list (format "INSIDE_EMACS=%s,compile" emacs-version))
              (copy-sequence process-environment))))
        (set (make-local-variable 'compilation-arguments)
             (list command mode name-function highlight-regexp))
        (set (make-local-variable 'revert-buffer-function)
             'compilation-revert-buffer)
-       (set-window-start outwin (point-min))
+       (and outwin
+            ;; Forcing the window-start overrides the usual redisplay
+            ;; feature of bringing point into view, so setting the
+            ;; window-start to top of the buffer risks losing the
+            ;; effect of moving point to EOB below, per
+            ;; compilation-scroll-output, if the command is long
+            ;; enough to push point outside of the window.  This
+            ;; could happen, e.g., in `rgrep'.
+            (not compilation-scroll-output)
+            (set-window-start outwin (point-min)))
 
        ;; Position point as the user will see it.
        (let ((desired-visible-point
@@ -1651,15 +1714,15 @@ Returns the compilation buffer created."
                   (point-max)
                 ;; Normally put it at the top.
                 (point-min))))
-         (if (eq outwin (selected-window))
-             (goto-char desired-visible-point)
+         (goto-char desired-visible-point)
+         (when (and outwin (not (eq outwin (selected-window))))
            (set-window-point outwin desired-visible-point)))
 
        ;; The setup function is called before compilation-set-window-height
        ;; so it can set the compilation-window-height buffer locally.
        (if compilation-process-setup-function
            (funcall compilation-process-setup-function))
-       (compilation-set-window-height outwin)
+       (and outwin (compilation-set-window-height outwin))
        ;; Start the compilation.
        (if (fboundp 'start-process)
            (let ((proc
@@ -1941,6 +2004,12 @@ Runs `compilation-mode-hook' with `run-mode-hooks' (which see).
        compilation-page-delimiter)
   ;; (set (make-local-variable 'compilation-buffer-modtime) nil)
   (compilation-setup)
+  ;; Turn off deferred fontifications in the compilation buffer, if
+  ;; the user turned them on globally.  This is because idle timers
+  ;; aren't re-run after receiving input from a subprocess, so the
+  ;; buffer is left unfontified after the compilation exits, until
+  ;; some other input event happens.
+  (set (make-local-variable 'jit-lock-defer-time) nil)
   (setq buffer-read-only t)
   (run-mode-hooks 'compilation-mode-hook))
 
@@ -2030,8 +2099,7 @@ Optional argument MINOR indicates this is called from
   (if minor
       (progn
        (font-lock-add-keywords nil (compilation-mode-font-lock-keywords))
-       (if font-lock-mode
-            (font-lock-fontify-buffer)))
+        (font-lock-flush))
     (setq font-lock-defaults '(compilation-mode-font-lock-keywords t))))
 
 (defun compilation--unsetup ()
@@ -2040,8 +2108,7 @@ Optional argument MINOR indicates this is called from
   (remove-hook 'before-change-functions 'compilation--flush-parse t)
   (kill-local-variable 'compilation--parsed)
   (compilation--remove-properties)
-  (if font-lock-mode
-      (font-lock-fontify-buffer)))
+  (font-lock-flush))
 
 ;;;###autoload
 (define-minor-mode compilation-shell-minor-mode
@@ -2247,6 +2314,7 @@ looking for the next message."
   (or (compilation-buffer-p (current-buffer))
       (error "Not in a compilation buffer"))
   (or pt (setq pt (point)))
+  (compilation--ensure-parse pt)
   (let* ((msg (get-text-property pt 'compilation-message))
          ;; `loc', `msg', and `last' are used by the compilation-loop macro.
         (loc (and msg (compilation--message->loc msg)))
@@ -2259,7 +2327,8 @@ looking for the next message."
                                                    (line-beginning-position)))
          (unless (setq msg (get-text-property (max (1- pt) (point-min))
                                                'compilation-message))
-           (setq pt (next-single-property-change pt 'compilation-message nil
+           (setq pt (compilation-next-single-property-change
+                      pt 'compilation-message nil
                                                  (line-end-position)))
            (or (setq msg (get-text-property pt 'compilation-message))
                (setq pt (point)))))
@@ -2270,7 +2339,6 @@ looking for the next message."
                                "No more %ss yet"
                              "Moved past last %s")
                            (point-max))
-        (compilation--ensure-parse pt)
        ;; Don't move "back" to message at or before point.
        ;; Pass an explicit (point-min) to make sure pt is non-nil.
        (setq pt (previous-single-property-change
@@ -2317,9 +2385,9 @@ Prefix arg N says how many files to move backwards (or forwards, if negative)."
 
 (defalias 'compile-mouse-goto-error 'compile-goto-error)
 
-(defun compile-goto-error (&optional event nomsg)
+(defun compile-goto-error (&optional event)
   "Visit the source for the error message at point.
-Use this command in a compilation log buffer.  Sets the mark at point there."
+Use this command in a compilation log buffer."
   (interactive (list last-input-event))
   (if event (posn-set-point (event-end event)))
   (or (compilation-buffer-p (current-buffer))
@@ -2328,7 +2396,6 @@ Use this command in a compilation log buffer.  Sets the mark at point there."
   (if (get-text-property (point) 'compilation-directory)
       (dired-other-window
        (car (get-text-property (point) 'compilation-directory)))
-    (push-mark nil nomsg)
     (setq compilation-current-error (point))
     (next-error-internal)))
 
@@ -2478,9 +2545,9 @@ displays at the top of the window; there is no arrow."
                             (- 1 compilation-context-lines))
                            (point)))
     ;; If there is no left fringe.
-    (if (equal (car (window-fringes)) 0)
-       (set-window-start w (save-excursion
-                             (goto-char mk)
+    (when (equal (car (window-fringes w)) 0)
+      (set-window-start w (save-excursion
+                            (goto-char mk)
                            (beginning-of-line 1)
                            (point)))))
     (set-window-point w mk))
@@ -2492,7 +2559,7 @@ displays at the top of the window; there is no arrow."
 All arguments are markers.  If END-MK is non-nil, mark is set there
 and overlay is highlighted between MK and END-MK."
   ;; Show compilation buffer in other window, scrolled to this error.
-  (let* ((from-compilation-buffer (eq (window-buffer (selected-window))
+  (let* ((from-compilation-buffer (eq (window-buffer)
                                       (marker-buffer msg)))
          ;; Use an existing window if it is in a visible frame.
          (pre-existing (get-buffer-window (marker-buffer msg) 0))
@@ -2501,14 +2568,16 @@ and overlay is highlighted between MK and END-MK."
                 ;; the error location if the two buffers are in two
                 ;; different frames.  So don't do it if it's not necessary.
                 pre-existing
-             (display-buffer (marker-buffer msg))))
+             (display-buffer (marker-buffer msg) '(nil (allow-no-window . t)))))
         (highlight-regexp (with-current-buffer (marker-buffer msg)
                             ;; also do this while we change buffer
-                            (compilation-set-window w msg)
+                            (goto-char (marker-position msg))
+                            (and w (compilation-set-window w msg))
                             compilation-highlight-regexp)))
     ;; 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))
+    (when (and (not pre-existing) w)
+      (compilation-set-window-height w))
 
     (if from-compilation-buffer
         ;; If the compilation buffer window was selected,
@@ -2525,7 +2594,7 @@ and overlay is highlighted between MK and END-MK."
        (goto-char mk)))
     (if end-mk
         (push-mark end-mk t)
-      (if mark-active (setq mark-active)))
+      (if mark-active (setq mark-active nil)))
     ;; If hideshow got in the way of
     ;; seeing the right place, open permanently.
     (dolist (ov (overlays-at (point)))
@@ -2619,9 +2688,12 @@ attempts to find a file whose name is produced by (format FMT FILENAME)."
     (while (null buffer)    ;Repeat until the user selects an existing file.
       ;; The file doesn't exist.  Ask the user where to find it.
       (save-excursion            ;This save-excursion is probably not right.
-        (let ((pop-up-windows t))
-          (compilation-set-window (display-buffer (marker-buffer marker))
-                                  marker)
+        (let ((w (let ((pop-up-windows t))
+                  (display-buffer (marker-buffer marker)
+                                  '(nil (allow-no-window . t))))))
+          (with-current-buffer (marker-buffer marker)
+           (goto-char marker)
+           (and w (compilation-set-window w marker)))
           (let* ((name (read-file-name
                         (format "Find this %s in (default %s): "
                                 compilation-error filename)