понедельник, 10 января 2011 г.

улучшение compile-mode в emacs

В программировании важны мелочи. Хочется не тратить время на рутинные операции. Необходимо, чтобы инструмент которым ты пользуешься стал продолжением твоей руки - ее неотделимой частью и тогда многие операции будут делаться фактически автоматически. Пусть экономия может составлять пару секунд, но если это делается десятки раз в день, то может получиться солидный бонус.

Для меня таким инструментом, стал emacs. И операцией, которую мне всегда хотелось улучшить - была компиляция. Связка: "сохранить текст + скомпилировать/собрать и запустить тесты" выполняется мною в день очень часто и оптимизировать ее очень хотелось.

Чего хочется добиться:


  • автоматически сохранять все буфера перед началом компиляции: это избавит нас от надоедливых вопросах о необходимости сохранить измененные буфера
  • в некоторых каталогах проектов над которыми я работаю используются makefile из каталогов верхнего уровня: хочется, что бы при компиляции автоматически происходил поиск нежного файла - это избавит от необходимости переключаться на другой буфер перед компиляцией
  • хочется что бы после успешного завершения компиляции/тестирования окно compile автоматически закрывалось, а при ошибках оставалось бы для  дальнейших разбирательств
  • компиляцию и тестирование запускать различными комбинациями клавиш
Вооружившись следующими ссылками:

получилось следующее решение, удовлетворяющее вышеозначенным требованиям:

(defun upward-find-file (filename &optional startdir)
  "Move up directories until we find a certain filename. If we
  manage to find it, return the containing directory. Else if we
  get to the toplevel directory and still can't find it, return
  nil. Start at startdir or . if startdir not given"

  (let ((dirname (expand-file-name
 (if startdir startdir ".")))
(found nil) ; found is set as a flag to leave loop if we find it
(top nil))  ; top is set when we get
   ; to / so that we only check it once

    ; While we've neither been at the top last time nor have we found
    ; the file.
    (while (not (or found top))
      ; If we're at / set top flag.
      (if (string= (expand-file-name dirname) "/")
 (setq top t))
      
      ; Check for the file
      (if (file-exists-p (expand-file-name filename dirname))
 (setq found t)
; If not, move up a directory
(setq dirname (expand-file-name ".." dirname))))
    ; return statement
    (if found dirname nil)))


;; Helper for compilation. Close the compilation window if
;; there was no error at all.
(setq compilation-finish-functions 'compile-autoclose)
(defun compile-autoclose (buffer string)
  (cond ((and 
          (string-match "finished" string) 
          (not (string-match "*grep*" (buffer-name (get-buffer buffer)))))
         (bury-buffer "*compilation*")
         (winner-undo)
         (message "Build successful."))
        (t                                                                    
         (message "Compilation exited abnormally: %s" string))))

;;функция сохраняет содержимое всех буферов
;;и затем вызывает make из католога где находится текущий файл
(defun my-compile-file ()
  "Save all files and compile"
    (interactive)
    (save-some-buffers 1)
    (let ((default-directory (or (upward-find-file "Makefile") ".")))
      (compile (format "cd %s && make -k -j8" default-directory))
      )
  )

;; support for compile tests
(defun my-compile-tests-file ()
  "Save all files and compile"
    (interactive)
    (save-some-buffers 1)
    (let ((default-directory (or (upward-find-file "Makefile") ".")))
      (compile (format "cd %s && make -k -j8 check" default-directory))
      )
  )
;;устанавливаем нашу функцию
(global-set-key  [f7] 'my-compile-file)
(global-set-key  [(shift f7)] 'my-compile-tests-file)

Из недостатков:
если во время компиляции/тестирования переключать окна, то после успешного завершения процесса состояние окон может вернуться в другое состояние, что было перед началом процесса. В идеале было бы конечно создавать новое окно для компиляции, но тут надо разбираться дальше.

Комментариев нет:

Отправить комментарий