omake-mode.el を Mac で動くようにしてみた

最近の寒波で, 実家周辺が久々に大雪だそうで, 今からちょっと憂鬱です. 東京も寒波で部屋だけは寒いですねー. 逆に外の方が慣れるのであまり寒いとは感じません.

話は変わって, 私は OCaml で開発する際には, なるだけ OMake を使うようにしています. 1 ファイルだけとかのときは端折るときははありますが.
OMake + Emacs で開発する時には, id:camlspotter さんが公開されている omake-mode.el を便利に利用させてもらっています.

ですが, そのままの omake-mode.el だと, 私の環境 (linux & MacOSX mountain lion) だと, 次のような問題が出ていました.

  • たまに (場合によっては毎回), OMake からの出力が, omake-mode のバッファではなく, 編集中のバッファに出てしまう :-(
  • なんか知らないけど, omake-mode のバッファがクリアされず, 複数回のビルドログが溜まる.
  • MacOSX で動かない X-|

帰省中には, Mac でしか開発が行えないため, 結構死活問題になりそうだったので, ちょっと時間をとって修正を試みてみました.

結論としては,

  • なんか出力のときにバッファを指定するようにしてみたらいかなくなったっぽい.
  • Mac の場合, 改行が^M\n のようにきていて, ^M を\n にしてしまうと, \n\n みたいになってしまい, 想定されている形式にならないっぽい
  • Mac の場合, aplay が無いので必ずそこで落ちていた.

という感じらしいので, とりあえず私の環境では, どちらでも動作するようにしてみました.

多分同じような環境の方なら動くと思い・・・たいです.
オリジナルとの差分だけ貼っておきます. この修正方法が正しいかどうかは, 私の Emacs 知識ではわかりませんのであしからず. こうしたほうがいいんでね? というのは歓迎です.

*** /home/derui/work/ocaml/omake-mode/omake-mode.el	2011-02-02 17:17:28.000000000 +0900
--- /home/derui/.emacs.d/site-lisp/omake-mode.el	2012-12-27 17:23:27.937238469 +0900
***************
*** 9,15 ****
  ;   (setq omake-error-highlight-background "#880000")
  ;
  ;   ; key bindings (jfuruse's setting)
! ;   (global-unset-key "\M-P") ; Shift+Alt+p
  ;   (global-unset-key "\M-N") ; Shift+Alt+n
  ;   (global-unset-key "\M-o") ; Alt+o
  ;   (global-unset-key "\M-O") ; Shift+Alt+o
--- 9,15 ----
  ;   (setq omake-error-highlight-background "#880000")
  ;
  ;   ; key bindings (jfuruse's setting)
! ;   (global-unset-key "\M-P") ; Shift+Alt+p
  ;   (global-unset-key "\M-N") ; Shift+Alt+n
  ;   (global-unset-key "\M-o") ; Alt+o
  ;   (global-unset-key "\M-O") ; Shift+Alt+o
***************
*** 37,52 ****
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Configurables

  ; omake path and args
! (defconst omake-program-path "/mnt/global/base/bin/jomake")
! (defconst omake-program-arguments "-P -w -j 3 --verbose")

  ; sounds
! (defconst omake-sound-success "/home/jfuruse/sounds/eu2/hihat.wav")
! (defconst omake-sound-error "/usr/share/sounds/pop.wav")
! (defconst omake-sound-start "/home/jfuruse/sounds/eu2/if_nope.wav")

  ; colors
! (defconst omake-error-highlight-background "#FFFF00")

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

--- 37,72 ----
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Configurables

  ; omake path and args
! (defcustom omake-program-path "/usr/bin/omake" "set your OMake program location"
!   :group 'omake-mode
!   :type 'string)
! (defcustom omake-program-arguments "-P -w -j 3 --verbose"
!   "Arguments to give omake from `omake-program-path'"
!   :group 'omake-mode
!   :type 'string)
! (defcustom omake-play-sound-program "aplay" "set your playing sound program location"
!   :group 'omake-mode
!   :type 'string)

  ; sounds
! (defcustom omake-sound-success "/home/jfuruse/sounds/eu2/hihat.wav"
!   "set sound file when success running omake process"
!   :group 'omake-mode
!   :type 'string)
! (defcustom omake-sound-error "/usr/share/sounds/pop.wav"
!   "set sound file when occur error running omake process"
!   :group 'omake-mode
!   :type 'string)
! (defcustom omake-sound-start "/home/jfuruse/sounds/eu2/if_nope.wav"
!   "set sound file when start omake process"
!   :group 'omake-mode
!   :type 'string)

  ; colors
! (defcustom omake-error-highlight-background "#FFFF00"
!   "color of overlay when omake happended error and jump to it"
!   :group 'omake-mode
!   :type 'string)

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

***************
*** 68,74 ****
--- 88,98 ----

  (defvar omake-buffers nil)

+ (defvar omake-root-dir nil)
+
  ; overlay
+ (defvar omake-overlay-log nil)
+ (defvar omake-overlay-source nil)
  (setq omake-overlay-log nil)
  (setq omake-overlay-source nil)

***************
*** 81,100 ****
      overlay))

  (defun omake-display-overlay-log (buffer start end)
-   (interactive)
    (if (not (overlayp omake-overlay-log))
        (setq omake-overlay-log (omake-create-overlay)))
    (move-overlay omake-overlay-log start end buffer))

  (defun omake-display-overlay-source (buffer start end)
-   (interactive)
    (if (not (overlayp omake-overlay-source))
        (setq omake-overlay-source (omake-create-overlay)))
    (move-overlay omake-overlay-source start end buffer))

  ; CR jfuruse: use the variable above!
  (defconst omake-font-lock-keywords
!   (list
     (cons omake-error-regexp font-lock-warning-face)
     (cons omake-progress-regexp font-lock-doc-face)
     (cons omake-directory-regexp font-lock-function-name-face)
--- 105,122 ----
      overlay))

  (defun omake-display-overlay-log (buffer start end)
    (if (not (overlayp omake-overlay-log))
        (setq omake-overlay-log (omake-create-overlay)))
    (move-overlay omake-overlay-log start end buffer))

  (defun omake-display-overlay-source (buffer start end)
    (if (not (overlayp omake-overlay-source))
        (setq omake-overlay-source (omake-create-overlay)))
    (move-overlay omake-overlay-source start end buffer))

  ; CR jfuruse: use the variable above!
  (defconst omake-font-lock-keywords
!   (list
     (cons omake-error-regexp font-lock-warning-face)
     (cons omake-progress-regexp font-lock-doc-face)
     (cons omake-directory-regexp font-lock-function-name-face)
***************
*** 115,126 ****

  (defun omake-filter-rev (p lst)
    (let ((res nil))
!     (mapcar (lambda (x) (if (funcall p x) (setq res (cons x res)))) lst)
      res))

  (defun omake-filter (p lst)
    (reverse (omake-filter-rev p lst)))
!
  (defun omake-filter-map (p lst)
    (if lst
        (let ((x (funcall p (car lst))))
--- 137,148 ----

  (defun omake-filter-rev (p lst)
    (let ((res nil))
!     (mapc (lambda (x) (if (funcall p x) (setq res (cons x res)))) lst)
      res))

  (defun omake-filter (p lst)
    (reverse (omake-filter-rev p lst)))
!
  (defun omake-filter-map (p lst)
    (if lst
        (let ((x (funcall p (car lst))))
***************
*** 129,140 ****
      nil))

  (defun omake-round-buffers ()
!   (if omake-buffers
        (let ((res (car omake-buffers)))
          (setq omake-buffers (cdr omake-buffers))
          res)
!     (setq omake-buffers
!           (omake-filter (lambda (buf)
                            (string-match "\\*omake\\*" (buffer-name buf)))
                          (buffer-list)))
      (if omake-buffers (omake-round-buffers))))
--- 151,162 ----
      nil))

  (defun omake-round-buffers ()
!   (if omake-buffers
        (let ((res (car omake-buffers)))
          (setq omake-buffers (cdr omake-buffers))
          res)
!     (setq omake-buffers
!           (omake-filter (lambda (buf)
                            (string-match "\\*omake\\*" (buffer-name buf)))
                          (buffer-list)))
      (if omake-buffers (omake-round-buffers))))
***************
*** 153,159 ****
      buf))

  (defun omake-set-font-lock ()
!   (setq font-lock-defaults
          '(omake-font-lock-keywords t ; keyword only
                                     nil nil nil))
    (font-lock-mode 1))
--- 175,181 ----
      buf))

  (defun omake-set-font-lock ()
!   (setq font-lock-defaults
          '(omake-font-lock-keywords t ; keyword only
                                     nil nil nil))
    (font-lock-mode 1))
***************
*** 172,192 ****
      (setq last-line-was-end-of-build nil)
      (make-local-variable 'no-error)
      (setq no-error t)
!     (make-local-variable 'root-dir)
!     (setq root-dir dir)
      buffer-name))

  (defun omake-play-sound (file)
!   (start-process "omake-sound" omake-misc-buffer-name "aplay" file))

! (defun omake-insert-line (string)
    (save-excursion
      (goto-char (point-max))
      (insert-before-markers string) ; (insert string)
      ))

  (defun omake-insert-progress (string)
!   (if string
        (save-excursion
          (goto-char (point-max))
          (setq last-progress-point (point))
--- 194,215 ----
      (setq last-line-was-end-of-build nil)
      (make-local-variable 'no-error)
      (setq no-error t)
!     (make-local-variable 'omake-root-dir)
!     (setq omake-root-dir dir)
      buffer-name))

  (defun omake-play-sound (file)
!   (start-process "omake-sound" omake-misc-buffer-name omake-play-sound-program file))

! (defun omake-insert-line (buffer string)
    (save-excursion
+     (set-buffer buffer)
      (goto-char (point-max))
      (insert-before-markers string) ; (insert string)
      ))

  (defun omake-insert-progress (string)
!   (if string
        (save-excursion
          (goto-char (point-max))
          (setq last-progress-point (point))
***************
*** 201,213 ****
  (setq last-progress-meter nil)

  (defun omake-process-filter (process output)
!   (save-current-buffer
!     (let ((buffer (process-buffer process)))
!       ; if buffer is gone, we do nothing.
!       (if buffer
!           (progn
!             (set-buffer buffer)

              ;; concat remained output
              (if remained-output
                  (setq output (concat remained-output output)))
--- 224,235 ----
  (setq last-progress-meter nil)

  (defun omake-process-filter (process output)
!   (let ((buffer (process-buffer process)))
!                                         ; if buffer is gone, we do nothing.
!     (if buffer
!         (with-current-buffer buffer

+           (progn
              ;; concat remained output
              (if remained-output
                  (setq output (concat remained-output output)))
***************
*** 216,225 ****
              ;; if we print progress meter in the last call, delete it
              (if last-progress-point
                  (save-excursion
!             (delete-region last-progress-point (point-max))))
!
              ;; fix 
 => \n
!             (while (string-match "
" output)
                (setq output (replace-match "\n" t nil output)))

              ;; remove progress meter string from log
--- 238,247 ----
              ;; if we print progress meter in the last call, delete it
              (if last-progress-point
                  (save-excursion
!                   (delete-region last-progress-point (point-max))))
!
              ;; fix 
 => \n
!             (while (string-match "
\n?" output)
                (setq output (replace-match "\n" t nil output)))

              ;; remove progress meter string from log
***************
*** 230,248 ****

              ;; print output per line
              (while (string-match ".*\n" output)
!
                ;; clear if a new make started
                (if last-line-was-end-of-build (erase-buffer))

                ;; get the line
                (setq line (match-string 0 output))
                (setq output (substring output (match-end 0)))
!               ;; and print
!               (omake-insert-line line)

                ;; root
                (if (string-match omake-root-regexp line)
!                   (setq root-dir (match-string 1 line)))

                ;; error / warning lines
                (if (string-match omake-error-regexp line)
--- 252,270 ----

              ;; print output per line
              (while (string-match ".*\n" output)
!
                ;; clear if a new make started
                (if last-line-was-end-of-build (erase-buffer))

                ;; get the line
                (setq line (match-string 0 output))
                (setq output (substring output (match-end 0)))
!               ;; and print
!               (omake-insert-line buffer line)

                ;; root
                (if (string-match omake-root-regexp line)
!                   (setq omake-root-dir (match-string 1 line)))

                ;; error / warning lines
                (if (string-match omake-error-regexp line)
***************
*** 257,280 ****
                      (omake-play-sound omake-sound-error)
                      (setq no-error nil)
                      (omake-display-buffer buffer)))
!
                (if (string-match omake-rebuild-regexp line)
                    (progn
                      (omake-play-sound omake-sound-start)))
!
                ;; find the end of build
                (setq last-line-was-end-of-build
                      (string-match "\\*\\*\\* omake: polling for filesystem changes" line))
                (if last-line-was-end-of-build
                    (progn
                      (setq last-progress-meter nil)
!                     (omake-insert-line "OMAKE IS WAITING YOUR CHANGE")
                      (if no-error
                          (omake-play-sound omake-sound-success))
                      (setq no-error t)
                      (omake-display-buffer buffer)))
                )
!
              ;; if something left, it is not ended with \n. Keep it
              (setq remained-output output)

--- 279,302 ----
                      (omake-play-sound omake-sound-error)
                      (setq no-error nil)
                      (omake-display-buffer buffer)))
!
                (if (string-match omake-rebuild-regexp line)
                    (progn
                      (omake-play-sound omake-sound-start)))
!
                ;; find the end of build
                (setq last-line-was-end-of-build
                      (string-match "\\*\\*\\* omake: polling for filesystem changes" line))
                (if last-line-was-end-of-build
                    (progn
                      (setq last-progress-meter nil)
!                     (omake-insert-line buffer "OMAKE IS WAITING YOUR CHANGE\n")
                      (if no-error
                          (omake-play-sound omake-sound-success))
                      (setq no-error t)
                      (omake-display-buffer buffer)))
                )
!
              ;; if something left, it is not ended with \n. Keep it
              (setq remained-output output)

***************
*** 288,301 ****
             nil)))

  (defun omake-display-error (dir file line char-start char-end)
!   (let
!       ((path (concat (file-name-as-directory (concat (file-name-as-directory root-dir) dir)) file)))
      (message path)
      (setq target-buffer (omake-find-file-existing path))
      (if target-buffer
!         (progn
            (goto-line line)
!           (let*
                ((char-of-line (line-beginning-position))
                 (char-of-start (+ char-of-line char-start))
                 (char-of-end (+ char-of-line char-end)))
--- 310,323 ----
             nil)))

  (defun omake-display-error (dir file line char-start char-end)
!   (let
!       ((path (concat (file-name-as-directory (concat (file-name-as-directory omake-root-dir) dir)) file)))
      (message path)
      (setq target-buffer (omake-find-file-existing path))
      (if target-buffer
!         (progn
            (goto-line line)
!           (let*
                ((char-of-line (line-beginning-position))
                 (char-of-start (+ char-of-line char-start))
                 (char-of-end (+ char-of-line char-end)))
***************
*** 306,312 ****

  (defun omake-jump-error (next)
    (if (get-buffer omake-current-buffer)
!       (progn
          (set-buffer omake-current-buffer)
          (if next (move-end-of-line nil)
            (move-beginning-of-line nil))
--- 328,334 ----

  (defun omake-jump-error (next)
    (if (get-buffer omake-current-buffer)
!       (progn
          (set-buffer omake-current-buffer)
          (if next (move-end-of-line nil)
            (move-beginning-of-line nil))
***************
*** 320,330 ****
                (char-end -1)
                (window (get-buffer-window (current-buffer))))
            (if (progn
!                 (if
                      (if next
                          ; sometimes the error has tab in its head...
                          (re-search-forward omake-error-regexp
!                                            nil ; CR BOUND can be used to avoid the summary
                                             t ; ignore not found error and return simply nil
                                             )
                        (re-search-backward omake-error-regexp
--- 342,352 ----
                (char-end -1)
                (window (get-buffer-window (current-buffer))))
            (if (progn
!                 (if
                      (if next
                          ; sometimes the error has tab in its head...
                          (re-search-forward omake-error-regexp
!                                            nil ; CR BOUND can be used to avoid the summary
                                             t ; ignore not found error and return simply nil
                                             )
                        (re-search-backward omake-error-regexp
***************
*** 333,349 ****
                        (setq found-start (match-beginning 0))
                        (setq found-end (match-end 0))
                        (setq file (match-string 1))
!                       (setq line (string-to-int (match-string 2)))
!                       (setq char-start (string-to-int (match-string 3)))
!                       (setq char-end (string-to-int (match-string 4)))
                        (set-window-point window (if next found-end found-start))
                        (save-excursion
  ;                        (if (re-search-backward "Entering directory `\\(.*\\)'" nil t)
                          (if (re-search-forward omake-directory-regexp nil t)
!                             (progn
                                (setq dir (match-string 1))
                                t)
!                           (progn
                              (message "Error message found but no directory info")
                              nil))))
                    (progn
--- 355,371 ----
                        (setq found-start (match-beginning 0))
                        (setq found-end (match-end 0))
                        (setq file (match-string 1))
!                       (setq line (string-to-number (match-string 2)))
!                       (setq char-start (string-to-number (match-string 3)))
!                       (setq char-end (string-to-number (match-string 4)))
                        (set-window-point window (if next found-end found-start))
                        (save-excursion
  ;                        (if (re-search-backward "Entering directory `\\(.*\\)'" nil t)
                          (if (re-search-forward omake-directory-regexp nil t)
!                             (progn
                                (setq dir (match-string 1))
                                t)
!                           (progn
                              (message "Error message found but no directory info")
                              nil))))
                    (progn
***************
*** 357,367 ****
                  ))))
      (message "no omake buffer selected")))

! (defun omake-next-error ()
    (interactive)
    (omake-jump-error t))

! (defun omake-previous-error ()
    (interactive)
    (omake-jump-error nil))

--- 379,389 ----
                  ))))
      (message "no omake buffer selected")))

! (defun omake-next-error ()
    (interactive)
    (omake-jump-error t))

! (defun omake-previous-error ()
    (interactive)
    (omake-jump-error nil))

***************
*** 375,384 ****
    (save-current-buffer
      (setq debug-on-error t)
      (let* ((buffer (omake-create-buffer dir))
!            (process
!             (start-process-shell-command buffer buffer
!                                          omake-program-path
!                                          omake-program-arguments)))
        (setq last-progress-meter nil)
        (set-process-filter process 'omake-process-filter)
        (omake-display-buffer buffer)
--- 397,405 ----
    (save-current-buffer
      (setq debug-on-error t)
      (let* ((buffer (omake-create-buffer dir))
!            (process
!             (start-process-shell-command buffer buffer
!                                          (concat omake-program-path " " omake-program-arguments))))
        (setq last-progress-meter nil)
        (set-process-filter process 'omake-process-filter)
        (omake-display-buffer buffer)
***************
*** 386,391 ****
--- 407,416 ----

  (defun omake-run ()
    (interactive)
+   (if (overlayp omake-overlay-source)
+       (progn
+         (delete-overlay omake-overlay-source)
+         (setq omake-overlay-source nil)))
    (omake-run-dir default-directory))

  (defun omake-rerun ()
***************
*** 396,401 ****
--- 421,431 ----
                  (dir (save-current-buffer
                         (set-buffer omake-current-buffer)
                         default-directory)))
+             (if (overlayp omake-overlay-source)
+                 (progn
+                   (delete-overlay omake-overlay-log)
+                   (setq omake-overlay-log nil)))
+
              (omake-run-dir dir)
              (kill-buffer old-buffer))
          (message "no current omake buffer"))

そろそろOCamlspotを使わないと厳しくなってきた気配がするので、使えるようにしていこうと思います。