2010-11-20 14 views
6

Lo que me gustaría hacer es preestablecer inteligentemente un valor predeterminado de buffer local para el argumento de cadena a la función compile.Emacs/Emacs Lisp: ¿puedo insertar consejos antes de un formulario interactivo? o cómo preestablecer inteligentemente el compile-command?

Ahora compile.el está predeterminado a usar "make" como el comando. Puedo establecer esto estableciendo compile-command. Incluso puedo hacer esa variable buffer-local. Eso funciona si quiero el mismo valor estático, siempre.

Pero me gustaría seleccionar inteligentemente el compile-command dependiendo del contenido del búfer, el nombre del búfer, el contenido del directorio contenedor del archivo (si lo hay) y la fase de la luna. Básicamente quiero control sobre el valor predeterminado y luego permitir que el usuario interactivo anule ese valor preestablecido.

Tenía la esperanza de hacer esto con consejos anteriores. Pero esto no está funcionando como esperaba.

Leer el archivo advice.el, veo

Supongamos que una forma especial de función/macro/subr/tiene N piezas de antes de consejo, M piezas de alrededor de asesoramiento y K piezas de después de consejo. Suponiendo que ninguno de los consejos está protegido, su definición aconsejado tendrá este aspecto (índices cuerpo de forma corresponden a la posición del respectivo consejo en esa clase de consejos):

([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)) 

Lo que esto me dice es que cuando la función recomendada es interactiva, 'invocar interactivamente' invoca el formulario interactivo antes de invocar el consejo anterior o cualquier consejo.

Y, cuando agrego consejos a compile, el comportamiento que observo confirma esto. El consejo se invoca después de se procesa el formulario interactivo. La forma interactiva sugiere la cadena que se utilizará para la compilación, antes de mi consejo tiene la oportunidad de adivinar lo que debería ser y preestablecerlo.

Entonces ...

  • ¿Cómo puedo obtener mi código se ejecute antes de que el formulario interactivo? ¿Puede un consejo hacer esto? Si no es un consejo, ¿algo más? o
  • ¿cómo puedo predefinir dinámicamente compile-command para cualquier memoria intermedia?

Ideas apreciadas.

+0

El comportamiento tiene sentido si tenemos en cuenta que todos los consejos tiene acceso a los valores de los argumentos que la función se invoca con, y que con el fin de determinar esos valores en un contexto interactivo, la forma interactiva se debe evaluar de antemano. (Cualquier persona interesada debe consultar la respuesta de Trey, que demuestra cómo asesorar al formulario interactivo.) – phils

Respuesta

4

Ahh, ¿sabes lo que hice? Usé una estrategia oblicua.

He configurado globalmente C-xC-e como compile. En lugar de utilizar el consejo, definí una función que ajusta compile, y luego uní C-xC-e a que. Dentro de la envoltura, adivino el comando de compilación.

(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)) 

Y la función conjetura es así:

(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 ")))) 
5

Una opción es establecer la variable compile-command en un gancho modo, algo así como

(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)))) 

veces he añadido especializada comandos para ajustar la línea de compilación actual (activar/desactivar indicadores de depuración, indicadores de optimización, etc.), y luego vincular esos comandos a las teclas convenientes en el mini-buffer.

En cuanto a la adición de consejos antes del formulario interactive, debe realizar un asesoramiento (ya sea antes o alrededor) que tiene una forma interactiva que desee. Desde la biblioteca advice.el, un ejemplo:

;;(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

compile-command no tiene que ser una cadena. La función de compilación evals ella, por lo que puede ser una función que devuelve una cadena que es específico para el buffer o que depende de la hora del día, etc:

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

Además, aunque no es probable que no es útil para sus necesidades específicas , siempre se puede definir de compilación de comandos en un archivo de sección variable:

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

o

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

compilación comando se utiliza en realidad como un ejemplo de una variable de archivo en the manual.

0

De acuerdo con el manual, puede simplemente anular la forma interactiva de una función con la suya incluyendo un formulario interactivo en su consejo. No creo que pueda modificar o ajustar el formulario interactivo existente, solo anularlo por completo.

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

+0

Y acabo de probar esto en una función que quería cambiar, y funcionó muy bien. –

1

Aquí hay un código que estoy usando que selecciona de forma inteligente la cortesía de comandos de compilación de la University of Wyoming. Actualmente lo tengo configurado para C, C++ y Fortran. Puede agregar más para satisfacer sus necesidades. Si abro una programación que tiene una extensión C++ y ejecuto M-xcompile, mi comando de compilación escupe g++ -Wall currentfilename.cpp -o currentfilename -std=c++14. Entonces solo tengo que presionar ingrese.

;; 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)) 
Cuestiones relacionadas