Commits

Stephen Weeks committed 1d6677a Merge

auto merge

Comments (0)

Files changed (5)

+
+changes
+=========
+
+- There is a big change regarding window behavior.
+
+  The following variables were removed
+     Omake.show-buffer-for-next-error-in
+     Omake.set-standard-windows
+     Omake.use-display-buffer
+
+  They were replaced by
+     Omake.split-window-horizontally
+     Omake.show-error-buffer-in-top-or-left-window
+
+  See the info documentation for the new behavior.  This change was done
+  as a uniform method for supporting the various different ways of using
+  dedicated windows vs. automatic window selection.
+
+  Non-experts should not have to do anything (though they might want to
+  remove the variables that are no longer used from their .emacs.)
+
+--------------------------------------------------------------------------------
 
 new stuff
 =========
      setting jane-highlight-whitespace-style.
    * trailing whitespace is cleaned up on file save, only in certain modes
       (c-mode tuareg-mode)
- 
+
 bug fixes
 =========
 

elisp-for-ocaml-programmers.el

 ;;                  (funcall f ctr b)
 ;;                  (setq ctr (+ ctr 1))) l)))
 ;;
-;; This definition of List.iteri fails.  In (List.iteri g l) 
+;; This definition of List.iteri fails.  In (List.iteri g l)
 ;; `f' is bound to g in the beginning of the body of List.iteri, but when List.iter
 ;; is called, f gets rebound to (lambda (b) ...).  Thus the funcall fails
-;; because it expects only 1 argument.  
+;; because it expects only 1 argument.
 ;;
 ;; For example
 ;;
   `(let ((inhibit-quit t))
      ,@form))
 
+(defun nequal (x y) (not (equal x y)))
+
 
 ;; Lexical defun and let
 
 (defmacro defunl (name arglist &rest body)
-  "Lexical defun"
+  "Lexical defun.  Not for use with interactive functions"
   (declare (indent defun))
-  (let* ((args (remove-if (lambda (s) (equal (substring (symbol-name s) 0 1) "&")) arglist))
-         (args (mapcar (lambda (arg) (list arg arg)) args)))
-  `(defun ,name ,arglist
-     (lexical-let 
-         ,args
-       ,@body))))
+  (let* (;; remove &optional and &rest
+         (args (remove-if
+                (lambda (s) (equal (substring (symbol-name s) 0 1) "&"))
+                arglist))
+         (args (mapcar (lambda (arg) (list arg arg)) args))
+         ;; put the doc string before the lexical-let
+         (doc_body (if (and (> (length body) 1)
+                            (stringp (car body)))
+                       `(,(car body) . ,(cdr body))
+                     `(nil . ,body)))
+         (doc (car doc_body))
+         (body (cdr doc_body)))
+    `(defun ,name ,arglist
+       ,(if doc doc)
+       (lexical-let
+           ,args
+         ,@body))))
 ;; (macroexpand '(defunl f (x y) (+ x y)))
+;; (macroexpand '(defunl f (x y) "abc" (+ x y)))
 
 (def-edebug-spec defunl
   (&define name lambda-list
     &or symbolp (gate symbolp &optional form))
    body))
 
-(font-lock-add-keywords 
- 'emacs-lisp-mode 
+(font-lock-add-keywords
+ 'emacs-lisp-mode
  '(("\\<\\(defunl\\)" 1 font-lock-keyword-face)
    ("\\<\\(letl\\*?\\)" 1 font-lock-keyword-face))
  t)
 
 (defunl List.mapi (f l)
   (letl ((i 0))
-    (mapcar (lambda (x) 
+    (mapcar (lambda (x)
               (letl ((y (funcall f i x)))
                 (setq i (1+ i))
                 y)) l)))
   (let ((from (if from from 0)))
     (if (< n from) nil (List.upto-aux n from nil))))
 
-(Jane.test (List.upto 3) '(0 1 2 3)) 
-(Jane.test (List.upto 3 2) '(2 3)) 
+(Jane.test (List.upto 3) '(0 1 2 3))
+(Jane.test (List.upto 3 2) '(2 3))
 
 (defunl List.concat-map (f l)
   (apply 'append (List.map f l)))
               (cons nil nil) l))
 (Jane.test (List.partition (lambda (x) (< x 4)) '(1 2 3 4 5)) '((1 2 3) . (4 5)))
 
-(defunl List.inter (l1 l2) 
+(defunl List.inter (l1 l2)
   (List.filter (lambda (x) (List.mem l2 x)) l1))
 (Jane.test (List.inter '(1 2 3) '(2 3 4)) '(2 3))
 (Jane.test (List.inter '(1 2 3) '()) '())
   (let ((w (if w w (selected-window))))
     (get-window-with-predicate (lambda (w1) (not (equal w w1))) nil t)))
 
+(defun Window.all-visible ()
+  "Return all visible windows in all visible frames."
+  (apply 'append (mapcar (lambda (f) (window-list f "no-mini")) (frame-list))))
+;; (Window.all-visible)
+
 
 ;; Timers
 
 (defun Emacs.insert-object (x) (insert (prin1-to-string x)))
 ;; (Emacs.insert-object "sean")
 
+(defun File.byte-compile-check ()
+  (interactive)
+  (let ((file (read-file-name "File: ")))
+    (byte-compile-file file)
+    (message "removing compiled file")
+    (Shell.rm (concat file "c"))))
+
 
 ;; Hg
 

info/omake-server.texi

 
 @c -----------------------------------------------------------------------------
-@c  Header                                                                      
+@c  Header
 @c -----------------------------------------------------------------------------
 
 \input texinfo
 @contents
 
 @c -----------------------------------------------------------------------------
-@c  Top                                                                         
+@c  Top
 @c -----------------------------------------------------------------------------
 
 @node Top
 @end menu
 
 @c -----------------------------------------------------------------------------
-@c  Index                                                                       
+@c  Index
 @c -----------------------------------------------------------------------------
 
 @node Index
 @printindex fn
 
 @c -----------------------------------------------------------------------------
-@c  Keybindings                                                                 
+@c  Keybindings
 @c -----------------------------------------------------------------------------
 
 @node Keybindings
 @end itemize
 
 @c -----------------------------------------------------------------------------
-@c  Quick Start                                                                 
+@c  Quick Start
 @c -----------------------------------------------------------------------------
 
 @node Quick Start
 To start a compilation, open Emacs and open the dired buffer of
 the directory you want to compile.  Then do @kbd{C-c C-c} to run the
 command @kbd{M-x Omake.compile}.  This will start a compilation in that
-directory, and create a new window which shows the @ref{Errors Buffer}. 
+directory, and create a new window which shows the @ref{Errors Buffer}.
 
 @c -----------------------------------------------------------------------------
-@c  User Interface                                                              
+@c  User Interface
 @c -----------------------------------------------------------------------------
 
 @node User Interface
 @menu
 * Errors Buffer::
 * Raw Buffer::
-@end menu 
+@end menu
 
 @node Errors Buffer
 @section Errors Buffer
 @section Raw Buffer
 
 @c -----------------------------------------------------------------------------
-@c  Windows                                                                     
+@c  Windows
 @c -----------------------------------------------------------------------------
 
 @node Windows
 @chapter Windows
 
 In this section we describe the algorithm for determining in which windows
-to show the various omake-server buffers.  By ``windows'' we mean 
-Emacs windows. (@ref{Windows, , , emacs})  This is in contrast to X windows, which 
+to show the various omake-server buffers.  By ``windows'' we mean
+Emacs windows. (@ref{Windows, , , emacs})  This is in contrast to X windows, which
 correspond to Emacs frames. (@ref{Frames, , , emacs})  The
 @emph{selected window} is the window that currently has the cursor in
-it.  The @emph{selected frame} is the frame that currently has the cursor. 
+it.  The @emph{selected frame} is the frame that currently has the cursor.
 
 @section Dedicated windows and frames
 
-There are a number of ways to display the error and code buffers.  
+There are a number of ways to display the error and code buffers.
 If you always want them to appear in the same window
 (resp. frame), use the following functions.
 
-@defun Omake.set-dedicated-error-window 
+@defun Omake.set-dedicated-error-window
 Always show errors in this window.
 @end defun
 
-@defun Omake.set-dedicated-code-window 
+@defun Omake.set-dedicated-code-window
 Always show code in this window.
 @end defun
 
 Always show code in some window in this frame.
 @end defun
 
-@noindent 
+@noindent
 (Note that if you set a dedicated window (frame), and subsequently
 delete it, there is no longer a dedicated window.)  Depending on
 personal preference, there are reasons for setting a dedicated frame
 deleted much less frequently than windows, which means they will
 disappear less often.
 
-@noindent 
+@noindent
 We use the following abbreviations to describe the algorithm that
 follows.
-@verbatim 
-DCW       = dedicated code window 
-DCF       = dedicated code frame 
-DEW       = dedicated error window 
-DEF       = dedicated error frame 
-SW        = selected window 
-SF        = selected frame 
-EB        = errors buffer 
-CB        = code buffer 
+@verbatim
+DCW       = dedicated code window
+DCF       = dedicated code frame
+DEW       = dedicated error window
+DEF       = dedicated error frame
+SW        = selected window
+SF        = selected frame
+EB        = errors buffer
+CB        = code buffer
 frame(W)  = the frame of window W
 # CR sweeks: window(B) is ill-defined.  There can be multiple windows showing a buffer.
-window(B) = the window of buffer B 
-buffer(W) = the buffer of window W 
-split(W)  = the new window resulting from the split of existing window W 
-lru(F)    = least recently used window of frame F 
-EF        = final frame where EB is shown 
-CF        = final frame where CB is shown 
-EW        = final window where EB is shown 
+window(B) = the window of buffer B
+buffer(W) = the buffer of window W
+split(W)  = the new window resulting from the split of existing window W
+lru(F)    = least recently used window of frame F
+EF        = final frame where EB is shown
+CF        = final frame where CB is shown
+EW        = final window where EB is shown
 CW        = final window where CB is shown
-@end verbatim 
+@end verbatim
 
 The purpose of this section is to determine EW and CW from DCW, DCF,
 ECW, ECF, SW, SF.  Throughout this discussion, we assume that the DEW is
 distinct from the DCW.  (This is enforced by omake-server.)  We do not
-assume that the error buffer is not being shown in the DCW.  It is easy
-to imagine that someone manually switched to the errors buffer from the
-DCW.
+assume that buffer(DCW) <> EB.  It is easy
+to imagine that someone manually switched to EB from DCW.
 
 When we write ``split(W)'' we are always splitting a frame with
-a single window, and we split it according to the variable 
+a single window, and we split it according to the variable
 @code{Omake.split-window-horizontally}.  We assure that EW<>CW.
 
 @section Choosing the frame
 
-Choosing the correct frames for CW and EW is straightforward. 
+Choosing the correct frames for CW and EW is straightforward.
 
 @subsection Choosing CF
 
 @verbatim
 If EF and CF are distinct, we can select EW and CW independently.
 
-Case: EF and CF are distinct. 
+Case: EF and CF are distinct.
   [EW]
   Case: DEW exists
     EW=DEW
   Case: There exists W in EF such that buffer(W) = EB
     EW=W
-  Case: 
-    EW=lru(EF)  
+  Case:
+    EW=lru(EF)
 
   [CW]
   Case: DCW exists
     EW=DCW
   Case: SW in CF.
     EW=SW
-  Case: 
-    EW=lru(CF)  
+  Case:
+    EW=lru(CF)
 
 If EF=CF, we have to make sure the choices are not interfering
 with each other to maintain CW<>EW.
 Case: EF=CF(=F)
   Case: DEW and DCW exist (DCW <> DEW by assumption)
      EW=DEW
-     CW=DCW 
+     CW=DCW
   Case: DEW exists
      EW=DEW
      Case: SW<>DEW in F
         CW=SW
-     Case: There exists W <> DEW in F 
+     Case: There exists W <> DEW in F
         CW=W
      Case: F is a single window, DEW.
         CW=split(DEW).
      CW=DCW
      Case: There exists W <> DCW in F such that buffer(W)=EB.
         EW=W
-     Case: There exists W <> DCW in F 
+     Case: There exists W <> DCW in F
         EW=W
      Case: F is a single window, DCW
         EW=split(DCW).
      EW=W
      Case: SW<>W in F
         CW=SW
-     Case: There exists W' <> W in F 
+     Case: There exists W' <> W in F
         CW=W'
      Case: F is a single window, W
         CW=split(W)
 In the case that the frame F contains exactly two windows, one showing
 the error buffer and the other showing the code buffer, and if no
 dedicated windows exist, then arrange the windows according to the
-variable Omake.show-error-buffer-in-top-or-left-window as follows.
+variable @code{Omake.show-error-buffer-in-top-or-left-window} as follows.
 
 @subsection Errors buffer
 
-@defopt Omake.split-window-horizontally 
+@defopt Omake.split-window-horizontally
   If nil, omake-server will split the window vertically.  Otherwise
 it will split it horizontally.
 @end defopt
 Otherwise show the errors in the top (resp. left) window.
 @end defopt
 
-@noindent For example, suppose in your .emacs you have: 
+@noindent For example, suppose in your .emacs you have:
 
 @lisp
 (setq Omake.split-window-horizontally t)
 @end verbatim
 
 @c -----------------------------------------------------------------------------
-@c  Acknowledgments                                                             
+@c  Acknowledgments
 @c -----------------------------------------------------------------------------
 
 @node Acknowledgments
 This manual was written by Sean McLaughlin and Stephen Weeks.
 Dmitry Astapov,
 Sam Erlichman,
-David House, 
+David House,
 Yaron Minsky,
-Elnatan Reisner, 
+Elnatan Reisner,
 and Martin Willensdorfer
 made valuable comments and improvements.
 
   :group 'omake
   :type 'string)
 
-(defcustom Omake.show-buffer-for-next-error-in 'dedicated-code-window
-  "Either 'dedicated-code-window or 'selected-window"
-  :group 'omake
-  :type 'symbol)
-;; (setq Omake.show-buffer-for-next-error-in 'selected-window)
-
-(defcustom Omake.set-standard-windows nil
-  "If t, when you run `Omake.compile' in a frame, it
-will split the frame horizontally, show your code on the left window and the
-errors on the right window."
-  :group 'omake
-  :type 'boolean)
-;; (setq Omake.set-standard-windows t)
-
-(defcustom Omake.use-display-buffer nil
-  "If t, use display-buffer to show the code and error buffer.")
-
 (defcustom Omake.prompt-before-killing-project t
   "If t, prompt y/n before killing a project"
   :group 'omake
   :type 'boolean)
 ;; (setq Omake.prompt-before-killing-project nil)
 
+(defcustom Omake.split-window-horizontally t
+  "See the info documentation for when this variable takes effect."
+  :group 'omake
+  :type 'boolean)
+;; (setq Omake.split-window-horizontally t)
+;; (setq Omake.split-window-horizontally nil)
+
+(defcustom Omake.show-error-buffer-in-top-or-left-window nil
+  "See the info documentation for what this is and when it takes effect."
+  :group 'omake
+  :type 'boolean)
+;; (setq Omake.show-error-buffer-in-top-or-left-window t)
+;; (setq Omake.show-error-buffer-in-top-or-left-window nil)
+
 ;;============================================================================;;
 ;; Faces                                                                      ;;
 ;;============================================================================;;
 ;; If there has been a version change upon loading this library,
 ;; kill the o-server.
 (when (and (boundp 'Omake.version)
-           (not (equal Omake.pre-version Omake.version))
+           (nequal Omake.pre-version Omake.version)
            (Omake.Server.running-p))
   (let ((res (y-or-n-p
     "Omake was updated.  Kill your server and reload? ")))
 (defconst Omake.version Omake.pre-version)
 
 ;;============================================================================;;
-;; Windows                                                                    ;;
+;; Windows and frames
 ;;============================================================================;;
 
-;; The user can set dedicated windows for
-;;   - the error buffer
-;;   - the code buffer
+(defvar Omake.Window.Error nil)
+(defvar Omake.Window.Code nil)
+(defvar Omake.Frame.Error nil)
+(defvar Omake.Frame.Code nil)
 
-;; type window = Error | Code
+(defun Omake.Window.clear-dedicated ()
+  (setq Omake.Window.Error nil)
+  (setq Omake.Window.Code nil))
 
-(defstruct
-  (Omake.window-kind
-   (:constructor nil)
-   (:constructor Omake.Window.Error (&aux (data 1)))
-   (:constructor Omake.Window.Code  (&aux (data 2))))
-  (data nil :read-only t))
+(defmacro Omake.Window.check (w)
+  `(and ,w
+       (not (window-live-p ,w))
+       (setq ,w nil)))
+;; (macroexpand '(Omake.Window.check Omake.Window.Error))
 
-(defconst Omake.Window.Error (Omake.Window.Error))
-(defconst Omake.Window.Code  (Omake.Window.Code))
+(defmacro Omake.Frame.check (f)
+  `(and ,f
+        (or (not (frame-live-p ,f))
+            (not (frame-visible-p ,f)))
+        (setq ,f nil)))
+;; (macroexpand '(Omake.Frame.check Omake.Frame.Error))
+;; (frame-visible-p Omake.Frame.Error)
 
-(defvar Omake.Window.window-table (make-hash-table :test 'equal))
+(defun Omake.Window.kindp (kind)
+  (case kind
+    ((code error) t)
+    (t nil)))
+;; (Omake.Window.kindp 'code)
+;; (Omake.Window.kindp 'error)
+;; (Omake.Window.kindp 'abc)
+;; (Omake.Window.kindp nil)
 
-(defun Omake.Window.set (kind w)
-  (assert (Omake.window-kind-p kind))
-  (assert (window-live-p w))
-  (puthash kind w Omake.Window.window-table))
+(defun Omake.check-dedicated ()
+  (Omake.Window.check Omake.Window.Error)
+  (Omake.Window.check Omake.Window.Code)
+  (Omake.Frame.check Omake.Frame.Error)
+  (Omake.Frame.check Omake.Frame.Code)
+  (assert (or (null Omake.Window.Code)
+              (null Omake.Window.Error)
+              (nequal Omake.Window.Code Omake.Window.Error))))
 
 (defun Omake.Window.get (kind)
-  "Get an omake window.  Return the current window if none is set."
-  (assert (Omake.window-kind-p kind))
-  (if (and (equal kind Omake.Window.Code)
-           ;; CR sweeks: Seems like this should be a [case] expression.
-           (equal Omake.show-buffer-for-next-error-in 'selected-window))
-      (selected-window)
-    (let* ((w (gethash kind Omake.Window.window-table))
-           (ok (and w (window-live-p w)))
-           (w (if ok w (selected-window))))
-      (unless ok (Omake.Window.set kind w))
-      w)))
+  (assert (Omake.Window.kindp kind))
+  (case kind
+    ('error Omake.Window.Error)
+    ('code Omake.Window.Code)
+    (t (error "Impossible"))))
 
-(defun Omake.Window.guess-error-window ()
-  "Try to guess a good window for the error buffer"
-  (let ((w (selected-window))
-        (w1 (next-window t)))
-    (if (equal w w1) (split-window-horizontally) w1)))
+(defun Omake.Frame.get (kind)
+  (assert (Omake.Window.kindp kind))
+  (case kind
+    ('error Omake.Frame.Error)
+    ('code Omake.Frame.Code)
+    (t (error "Impossible"))))
+
+(defun Omake.Frame.split ()
+  ;; If we're splitting, there's a single frame with a single window.  If it's
+  ;; dedicated, we have no hope of maintaining it
+  (Omake.Window.clear-dedicated)
+  (let ((right (if Omake.split-window-horizontally
+                   (split-window-horizontally)
+                 (split-window-vertically)))
+        (left (selected-window)))
+    (if Omake.show-error-buffer-in-top-or-left-window
+        (cons right left)
+      (cons left right))))
+
+(defun Omake.choose-frame-and-maybe-window (kind buffer other-dedicated-window)
+  (assert (Omake.Window.kindp kind))
+  (let ((dw (Omake.Window.get kind))
+        (df (Omake.Frame.get kind)))
+    (if dw (cons (window-frame dw) dw)
+      (let* ((try-windows
+              (if df (window-list df) (Window.all-visible)))
+             (or-else-frame
+              (if df df (window-frame (selected-window))))
+             (final-window
+              (List.find
+               (lambda (w)
+                 (and
+                  buffer
+                  (equal (window-buffer w) buffer)
+                  (or (null other-dedicated-window)
+                      (nequal w other-dedicated-window))))
+               try-windows)))
+        (if final-window
+            (cons (window-frame final-window) final-window)
+          (cons or-else-frame nil))))))
+
+(defun Omake.obeys-dedicated (kind w)
+  (assert (Omake.Window.kindp kind))
+  (assert (window-live-p w))
+  (let ((dw (Omake.Window.get kind))
+        (df (Omake.Frame.get kind)))
+    (cond
+     (dw (equal dw w))
+     (df (equal df (window-frame w)))
+     (t t))))
+
+(defun Omake.choose-windows (id code-buffer-opt)
+  "Return (code-window . error-window) and set the code and error buffers"
+  (assert (Omake.id-p id))
+  (assert (or (null code-buffer-opt) (bufferp code-buffer-opt)))
+  (Omake.check-dedicated)
+  (let* (;; If there's no code buffer, grab an arbitrary buffer and use
+         ;; that as we go through the code.  Just don't set the code buffer
+         ;; in this case.
+         (model (Omake.Model.get id))
+         (error-buffer (Omake.model-error-buffer model))
+         (_ (assert (nequal code-buffer-opt error-buffer)))
+         (code (Omake.choose-frame-and-maybe-window
+                'code code-buffer-opt Omake.Window.Error))
+         (code-frame (car code))
+         (code-window (cdr code))
+         (err (Omake.choose-frame-and-maybe-window
+               'error error-buffer Omake.Window.Code))
+         (error-frame (car err))
+         (error-window (cdr err))
+         (_ (assert code-frame))
+         (_ (assert error-frame))
+         (or-selected (lambda (w f) (if w w (frame-selected-window f))))
+         (choice
+          (if (equal code-frame error-frame)
+              (let* ((frame code-frame)
+                     (sw (frame-selected-window frame))
+                     (windows (window-list frame))
+                     (unselected-ws (remove-if-not (lambda (w) (nequal w sw)) windows)))
+                (if (null unselected-ws) (Omake.Frame.split)
+                  (let* ((lru (when unselected-ws (car unselected-ws)))
+                         ;; Can't get lru from an arbitrary list of windows without digging into C
+                         (other-than (lambda (w) (if (equal w sw) lru sw))))
+                    (cond
+                     ((and code-window error-window) (cons code-window error-window))
+                     (code-window (cons code-window (funcall other-than code-window)))
+                     (error-window (cons (funcall other-than error-window) error-window))
+                     (t (cons sw lru))))))
+            ;; else
+            (cons (funcall or-selected code-window code-frame)
+                  (funcall or-selected error-window error-frame))))
+         (code (car choice))
+         (err (cdr choice)))
+    (assert (nequal code err))
+    (assert (Omake.obeys-dedicated 'code code))
+    (assert (Omake.obeys-dedicated 'error err))
+    choice))
 
 ;;============================================================================;;
 ;; Progress bar                                                               ;;
                  (string-match "[.~a-zA-Z0-9/_-]*[.a-zA-Z0-9~_-]" path)
                  (match-string 0 path))))
     (equal path legal)))
-;; (Omake.Path.ok "/home/sweeks/live/107.15.00/live/lib")
-;; (Omake.Path.ok "/home/sweeks/live/107.15.00/live/lib/aSet.ml")
-;; (Omake.Path.ok "/mnt/local/sda1/smclaughlin/elisp/dev/omake-mode")
-;; (Omake.Path.ok "/mnt/local.a.b.c/sda1/smclaughlin/elisp/dev/omake-mode")
-;; (Omake.Path.ok "~/gord-test")
+
+(progn
+  (Jane.test (Omake.Path.ok "/home/sweeks/live/107.15.00/live/lib") t)
+  (Jane.test (Omake.Path.ok "/home/sweeks/live/107.15.00/live/lib/aSet.ml") t)
+  (Jane.test (Omake.Path.ok "/mnt/local/sda1/smclaughlin/elisp/dev/omake-mode") t)
+  (Jane.test (Omake.Path.ok "/mnt/local.a.b.c/sda1/smclaughlin/elisp/dev/omake-mode") t)
+  (Jane.test (Omake.Path.ok "~/gord-test") t))
 
 (defun Omake.Path.omakeroot-dir (path)
   "Get the full, unaliased path to the OMakeroot file above the given path.
 
 (defun Omake.Error.show (e)
   (assert (Omake.error-p e))
-  (let* ((file (Omake.Error.file-path e))
-         (_
-          (if (not Omake.use-display-buffer)
-              (select-window (Omake.Window.get Omake.Window.Code))
-              (when
-                  (eq (current-buffer)
-                   (Omake.model-error-buffer (Omake.Model.current)))
-                (select-window (display-buffer
-                                (or (get-file-buffer file)
-                                    (create-file-buffer file)))))))
-         ;; At this point, the selected window is where we want to show the error.
-         (_ (find-file file))
+  (let* ((id (Omake.error-id e))
+         (model (Omake.Model.get id))
+         (error-buffer (Omake.model-error-buffer model))
+         (file (Omake.Error.file-path e))
+         (code-buffer (find-file-noselect file))
+         (ws (Omake.choose-windows id code-buffer))
+         (cw (car ws))
+         (ew (cdr ws))
          (line (Omake.error-line e))
          (char-beg (Omake.error-char-beg e))
          (char-end (Omake.error-char-end e)))
+    ;; This part is finicky.  I'm not sure at the moment why
+    ;; the `switch-to-buffer' call is needed, but it is.
+    (set-window-buffer ew error-buffer)
+    (set-window-buffer cw code-buffer)
+    (select-window cw)
+    (switch-to-buffer code-buffer)
     (remove-overlays (point-min) (point-max))
     (Buffer.goto-line line)
     (forward-char char-beg)
   (assert (Omake.Path.ok dir))
   (concat (Omake.Buffer.prefix kind) dir))
 
-(defun Omake.Buffer.get (kind dir)
-  (assert (Omake.buffer-kind-p kind))
-  (assert (stringp dir))
-  (let ((name (Omake.Buffer.name kind dir)))
-    (unless (buffer-live-p (Buffer.get name)) (error "No such buffer: %s" name))
-    (get-buffer-create name)))
-
 (defun Omake.Buffer.create (kind dir)
   (assert (Omake.buffer-kind-p kind))
   (assert (stringp dir))
 (defconst Omake.File.root "/tmp/omake-server")
 
 ;; CR cfalls: Not all users want this.  Also, you should use custom-set-variables.
+;;    smclaughlin: If this is not set, people get a message every few seconds
+;;                 in the minibuffer.  Maybe I can find a way to set it on a
+;;                 buffer-by-buffer basis.
 (setq auto-revert-verbose nil)
 
 (defun Omake.File.auto-revert (file buffer-name)
   "Show a model in the error buffer"
   (assert (Omake.model-p model))
   (let* ((error-buf (Omake.model-error-buffer model))
-         (error-win (Omake.Window.get Omake.Window.Error)))
+         (error-win (Omake.Window.get 'error)))
     (with-current-buffer error-buf
       (toggle-read-only -1)
       (let ((pt (point))
 
 (defun* Omake.Ping.version-mismatch (&key server-received server-version)
   "Called by the server to alert of a version mismatch"
-  (assert (not (equal server-received server-version)))
+  (assert (nequal server-received server-version))
   (let ((msg
          (if (< server-received server-version)
              (format "Server version (%d) is newer than elisp version (%d).  Run M-x load-library omake" server-version server-received)
 
 (defun Omake.set-dedicated-error-window ()
   (interactive)
-  (Omake.Window.set Omake.Window.Error (selected-window)))
+  (Omake.check-dedicated)
+  (let ((w (selected-window)))
+    (when (equal w (Omake.Window.get 'code))
+      (error "The current window is already dedicated to code.
+Do M-x Omake.clear-dedicated-windows to reset"))
+    (setq Omake.Window.Error w)))
 
 (defun Omake.set-dedicated-code-window ()
   (interactive)
-  (Omake.Window.set Omake.Window.Code (selected-window)))
+  (Omake.check-dedicated)
+  (let ((w (selected-window)))
+    (when (equal w (Omake.Window.get 'error))
+      (error "The current window is already dedicated to errors.
+Do M-x Omake.clear-dedicated-windows to reset"))
+    (setq Omake.Window.Code w)))
+
+(defun Omake.clear-dedicated-windows ()
+  (interactive)
+  (Omake.Window.clear-dedicated))
+
+(defun Omake.set-dedicated-error-frame ()
+  (interactive)
+  (setq Omake.Frame.Error (selected-frame)))
+
+(defun Omake.set-dedicated-code-frame ()
+  (interactive)
+  (setq Omake.Frame.Code (selected-frame)))
 
 (defun Omake.show-error-buffer ()
   (interactive)
-  (if Omake.use-display-buffer
-      (display-buffer (Omake.model-error-buffer (Omake.Model.current)))
-    (let ((error-buffer (Omake.model-error-buffer (Omake.Model.current))))
-      (set-window-buffer (Omake.Window.get Omake.Window.Error) error-buffer))))
-
-(defun Omake.set-standard-windows ()
-  (interactive)
-  (delete-other-windows)
-  (let ((new (split-window-horizontally)))
-    (Omake.set-dedicated-code-window)
-    (with-selected-window new (Omake.set-dedicated-error-window))))
+  (let* ((id (Omake.Id.current))
+         (model (Omake.Model.get id))
+         (eb (Omake.model-error-buffer model))
+         (ws (Omake.choose-windows id nil))
+         (ew (cdr ws)))
+    (set-window-buffer ew eb)))
 
 (defun Omake.compile (&optional read-command)
   "Compile the current directory."
   (Omake.install-hooks)
   (let ((server-was-running (Omake.Server.running-p)))
     (Omake.Server.ensure-running)
-    (when Omake.set-standard-windows (Omake.set-standard-windows))
     (let* ((path (Filename.default-directory))
            (id (Omake.Id.of-path path)))
       (catch 'exit
                                  path
                                  ))))
               (if kill (Omake.Model.kill id) (throw 'exit t)))))
-        ;; Set the code window where the user ran compile
-        (unless (Omake.Window.get Omake.Window.Code)
-          (Omake.Window.set Omake.Window.Code (selected-window)))
-        ;; Set the error window
-        (unless (Omake.Window.get Omake.Window.Error)
-          (Omake.Window.set Omake.Window.Error (Omake.Window.guess-error-window)))
         ;; Create the model
         (let ((user-command
                (when read-command
   (Omake.Model.reset-visited (Omake.Id.current)))
 
 (defun Omake.next-error (&optional user-num)
-  ;; If Omake.use-display-buffer then
-  ;; If I am in the error buffer, then display the code in another buffer
-  ;; If I am not in the error buffer, then display the errors buffer and
-  ;;    display the file in this buffer.
   (interactive "P")
-  (Omake.show-error-buffer)
   (let* ((model (Omake.Model.current))
          (result (Omake.model-result model))
          (current-file (buffer-file-name)))
                      ring)))
         (setf (Omake.model-result model) (Omake.Result.Ring ring))
         (if (Omake.Ring.is-empty ring)
+            (Omake.show-error-buffer)
             (message "There are no errors.")
           (let* ((current (Omake.ring-current ring))
                  (user-num
                       Omake.error-file-dir
                       Omake.user
                       (Omake.date)))
-         (body (format "%s: %s" user msg)))
+         (body (format "%s: %s" Omake.user msg)))
     (Shell.mail "omake-mode error" Omake.maintainer-email-addr msg)))
 ;; (Omake.notify-maintainer-of-error "/mnt/local/sda1/smclaughlin/gord/trunk/")
 
 ;;============================================================================;;
 
 (provide 'omake)
-

window_selection.ml

 
   let choose_windows ~code ~error ~selected_window ~visible_windows =
     (* Requirements that emacs is expected to guarantee. *)
+    assert (code.buffer <> error.buffer);
     assert (code.dedicated_window <> error.dedicated_window);
     (* The algorithm. *)
     let choose_frame_and_maybe_window kind ~other =
       choose_frame_and_maybe_window error ~other:code
     in
     let choice =
-      if code_frame <> error_frame then begin
-        let or_selected window_opt frame =
-          Option.value window_opt ~default:(Frame.selected_window frame)
-        in
-        { code  = or_selected code_window_opt  code_frame ;
-          error = or_selected error_window_opt error_frame;
-        }
-      end
-      else begin
+      if code_frame = error_frame then begin
         let frame = code_frame in
         let selected_window = Frame.selected_window frame in
         let windows = Frame.windows frame in
           | Some code, None -> { code; error = other_than code}
           | None, Some error -> { code = other_than error; error }
           | None, None -> { code = selected_window; error = lru }
+      end else begin
+        let or_selected window_opt frame =
+          Option.value window_opt ~default:(Frame.selected_window frame)
+        in
+        { code  = or_selected code_window_opt  code_frame ;
+          error = or_selected error_window_opt error_frame;
+        }
       end
     in
     (* Properties guaranteed by the algorithm. *)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.