Emacs / Emacs Lisp: могу ли я вставить совет перед интерактивной формой? или как правильно установить команду компиляции? - PullRequest
6 голосов
/ 20 ноября 2010

Что я хотел бы сделать, так это интеллектуально предварительно установить локальное значение буфера для строкового аргумента по умолчанию для функции compile.

Прямо сейчас compile.el по умолчанию использует "make" в качестве команды. Я могу установить это, установив compile-command. Я даже могу сделать эту переменную буфера локальным. Это работает, если я хочу одно и то же статическое значение, всегда.

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

Я надеялся сделать это с предварительным советом. Но это не работает, как я ожидал.

Читая файл advice.el, вижу

Предположим, что функция / макрос / subr / special-form имеет N частей до рекомендации, M частей вокруг рекомендации и K частей после рекомендации. Предполагая, что ни один из советов не защищен, его рекомендуемое определение будет выглядеть следующим образом (индексы формы тела соответствуют позиции соответствующего совета в этом классе рекомендаций):

([macro] lambda <arglist>
   [ [<advised-docstring>] [(interactive ...)] ]
   (let (ad-return-value)
 {<before-0-body-form>}*
       ....
 {<before-N-1-body-form>}*
 {<around-0-body-form>}*
    {<around-1-body-form>}*
      ....
       {<around-M-1-body-form>}*
      (setq ad-return-value
        <apply original definition to <arglist>>)
       {<other-around-M-1-body-form>}*
      ....
    {<other-around-1-body-form>}*
 {<other-around-0-body-form>}*
 {<after-0-body-form>}*
       ....
 {<after-K-1-body-form>}*
 ad-return-value))

Что это говорит мне о том, что, когда рекомендованная функция является интерактивной, `call-интерактивно 'вызывает интерактивную форму перед вызовом предварительного совета или какого-либо совета.

И, когда я добавляю совет к compile, наблюдаемое мной поведение подтверждает это. Рекомендация вызывается после обработки интерактивной формы. Интерактивная форма предлагает строку, которую нужно использовать для компиляции, за до мой совет получает возможность угадать, какой она должна быть, и предварительно установить ее.

Итак ...

  • как мне заставить мой код работать до интерактивной формы? может совет сделать это? Если не совет, что-то еще? или
  • как я могу динамически предварительно установить compile-command для любого буфера?

Идеи приветствуются.

Ответы [ 5 ]

5 голосов
/ 20 ноября 2010

Один из вариантов - установить переменную compile-command в режиме ловушки, что-то вроде

(add-hook 'c++-mode-hook 'my-c++-set-compile-command)
(defun my-c++-set-compile-command ()
   (setq (make-local-variable 'compile-command) (format "gmake %s" (buffer-file-name))))

Иногда я добавлял специальные команды для настройки текущей строки компиляции (включение / выключение флагов отладки, флагов оптимизации и т. Д.), А затем связывал эти команды с удобными нажатиями клавиш в мини-буфере.

Что касается добавления совета перед формой interactive, вам необходимо дать совет (либо до, либо около него), который имеет интерактивную форму, которую вы хотите. Из библиотеки advice.el, пример:

;;(defadvice switch-to-buffer (around confirm-non-existing-buffers activate)
;;  "Switch to non-existing buffers only upon confirmation."
;;  (interactive "BSwitch to buffer: ")
;;  (if (or (get-buffer (ad-get-arg 0))
;;          (y-or-n-p (format "`%s' does not exist, create? " (ad-get-arg 0))))
;;      ad-do-it))
5 голосов
/ 07 декабря 2012

команда компиляции не должна быть строкой. Функция компиляции очищает ее, поэтому она может быть функцией, которая возвращает строку, специфичную для буфера или зависящую от времени суток, и т. Д .:

(setq compile-command (lambda () (if (eq phase-of-moon 'waning) 
                                     "make -DWANING=1" 
                                    "make -DWANING=0")))

Кроме того, хотя это, вероятно, бесполезно для ваших конкретных потребностей, вы всегда можете определить команду компиляции в разделе файловой переменной:

/* -*- compile-command: "make -DFOO"; -*- */

или

// Local Variables:
// compile-command: "make -DSOMETHING_SPECIAL"
// End:

команда компиляции фактически используется в качестве примера файловой переменной в руководстве .

4 голосов
/ 20 ноября 2010

Ааа, вы знаете, что я сделал?Я использовал косую стратегию.

Я глобально установил C-xC-e на compile.Вместо того, чтобы использовать совет, я определил функцию, которая переносит compile, а затем привязал C-xC-e к , что .В оболочке я делаю предположение для команды компиляции.

(defun cheeso-invoke-compile-interactively ()
  "fn to wrap the `compile' function.  This simply
checks to see if `compile-command' has been previously guessed, and
if not, invokes `cheeso-guess-compile-command' to set the value.
Then it invokes the `compile' function, interactively."
  (interactive)
  (cond
   ((not (boundp 'cheeso-local-compile-command-has-been-set))
(cheeso-guess-compile-command)
(set (make-local-variable 'cheeso-local-compile-command-has-been-set) t)))
  ;; local compile command has now been set
  (call-interactively 'compile))

А функция угадывания выглядит так:

(defun cheeso-guess-compile-command ()
  "set `compile-command' intelligently depending on the
current buffer, or the contents of the current directory."
  (interactive)
  (set (make-local-variable 'compile-command)
   (cond
    ((or (file-expand-wildcards "*.csproj" t)
     (file-expand-wildcards "*.vcproj" t)
     (file-expand-wildcards "*.vbproj" t)
     (file-expand-wildcards "*.shfbproj" t)
     (file-expand-wildcards "*.sln" t))
     "msbuild ")

    ;; sometimes, not sure why, the buffer-file-name is
    ;; not set.  Can use it only if set.
    (buffer-file-name
     (let ((filename (file-name-nondirectory buffer-file-name)))
       (cond

    ;; editing a .wxs (WIX Soluition) file
    ((string-equal (substring buffer-file-name -4) ".wxs")
     (concat "nmake "
         ;; (substring buffer-file-name 0 -4) ;; includes full path
         (file-name-sans-extension filename)
         ".msi" ))

    ;; a javascript file - run jslint
    ((string-equal (substring buffer-file-name -3) ".js")
     (concat (getenv "windir")
         "\\system32\\cscript.exe c:\\cheeso\\bin\\jslint-for-wsh.js "
         filename))

    ;; something else - do a typical .exe build
    (t
     (concat "nmake "
         (file-name-sans-extension filename)
         ".exe")))))

    (t
     "nmake "))))
1 голос
/ 18 апреля 2015

Вот некоторый код, который я использую, который разумно выбирает команду компиляции благодаря Университету Вайоминга .В настоящее время я настроил его на C, C++ и Fortran.Вы можете добавить больше, чтобы удовлетворить ваши потребности.Если я открываю программу с расширением C++ и выполняю Mx compile , моя команда компиляции выплевывает g++ -Wall currentfilename.cpp -o currentfilename -std=c++14.Тогда я просто должен нажать введите .

;; M-x compile smarter in order to guess language
(require 'compile)
(defvar compile-guess-command-table
  '((c-mode       . "gcc -Wall -g %s -o %s -lm")
    (c++-mode     . "g++ -Wall %s -o %s -std=c++14")
    (fortran-mode . "gfortran -C %s -o %s")
    ))

(defun compile-guess-command ()
  (let ((command-for-mode (cdr (assq major-mode
                                     compile-guess-command-table))))
    (if (and command-for-mode
             (stringp buffer-file-name))
        (let* ((file-name (file-name-nondirectory buffer-file-name))
               (file-name-sans-suffix (if (and (string-match "\\.[^.]*\\'"
                                                             file-name)
                                               (> (match-beginning 0) 0))
                                          (substring file-name
                                                     0 (match-beginning 0))
                                        nil)))
          (if file-name-sans-suffix
              (progn
                (make-local-variable 'compile-command)
                (setq compile-command
                      (if (stringp command-for-mode)
                          ;; Optimize the common case.
                          (format command-for-mode
                                  file-name file-name-sans-suffix)
                        (funcall command-for-mode
                                 file-name file-name-sans-suffix)))
                compile-command)
            nil))
      nil)))


;; Add the appropriate mode hooks.
(add-hook 'c-mode-hook       (function compile-guess-command))
(add-hook 'c++-mode-hook     (function compile-guess-command))
(add-hook 'fortran-mode-hook (function compile-guess-command))
0 голосов
/ 11 августа 2014

Согласно руководству, вы можете просто переопределить интерактивную форму функции своей собственной, включив интерактивную форму в ваш совет. Я не думаю, что вы можете изменить или обернуть существующую интерактивную форму, только полностью ее переопределить.

http://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Advice.html

...