2010-11-20 2 views
6

Quello che mi piacerebbe fare è impostare in modo intelligente un valore predefinito locale del buffer per l'argomento stringa alla funzione compile.Emacs/Emacs Lisp: posso inserire un consiglio prima del modulo interattivo? o come impostare in modo intelligente il comando di compilazione?

In questo momento compile.el utilizza per impostazione predefinita "make" come comando. Posso impostarlo impostando compile-command. Posso persino rendere quella variabile buffer-local. Funziona se voglio lo stesso valore statico, sempre.

Ma mi piacerebbe selezionare in modo intelligente lo compile-command a seconda del contenuto del buffer, del nome del buffer, del contenuto della directory contenente il file (se presente) e della fase lunare. Fondamentalmente voglio controllare il valore predefinito e quindi consentire all'utente interattivo di sovrascrivere quel valore preimpostato.

Speravo di fare questo prima di un consiglio. Ma questo non funziona come mi aspettavo.

Lettura del file advice.el, vedo

Supponiamo che una speciale forma di funzione/macro/subr/ha N pezzi di prima consulenza, M pezzi di circa consulenza e K pezzi di dopo consigli. Supponendo che nessuno dei consigli è protetto, la sua definizione consigliato sarà simile a questa (indici di corpo a forma corrispondono alla posizione del rispettivo consiglio in quella classe consulenza):

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

Che cosa questo mi dice è che quando la funzione consigliata è interattiva, `call-interattively 'richiama il modulo interattivo prima di invocare il consiglio precedente o qualsiasi consiglio.

E, quando aggiungo un avviso a compile, il comportamento che osservo lo conferma. Il suggerimento viene invocato dopo il il modulo interattivo viene elaborato. Il modulo interattivo suggerisce la stringa da utilizzare per la compilazione, prima del, il mio consiglio ha la possibilità di indovinare a cosa dovrebbe essere e di pre-impostarlo.

Quindi ...

  • Come posso ottenere il mio codice da eseguire prima di un formulario interattivo? può consiglio fare questo? Se non consiglio, qualcos'altro? oppure
  • come è possibile preimpostare dinamicamente compile-command per qualsiasi buffer?

Idee apprezzate.

+0

Il comportamento ha un senso se si considera che tutti i consigli ha accesso ai valori degli argomenti che la funzione è stata richiamata con, e che, al fine di determinare i valori in un contesto interattivo, di un formulario interattivo deve essere valutata in anticipo. (Chiunque fosse interessato dovrebbe fare riferimento alla risposta di Trey, che dimostra come consigliare il modulo interattivo.) – phils

risposta

4

Ah, sai cosa ho fatto? Ho usato una strategia obliqua.

Ho impostato globalmente C-xC-e su compile. Anziché utilizzare i consigli, ho definito una funzione che include compile e quindi associato C-xC-e a che. All'interno del wrapper, faccio l'ipotesi per il comando compile.

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

E la funzione ipotesi è come questo:

(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 possibilità è quella di impostare la variabile compile-command in un gancio modalità, qualcosa come

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

Qualche volta ho aggiunto specializzato comandi per modificare la linea di compilazione corrente (attiva/disattiva flag di debug, flag di ottimizzazione, ecc.), quindi associa questi comandi a comode sequenze di tasti nel mini-buffer.

Per quanto riguarda l'aggiunta di un avviso prima del modulo interactive, è necessario fornire un consiglio (prima o intorno) che ha un modulo interattivo che si desidera. Dalla libreria advice.el, un esempio:

;;(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 non deve essere una stringa. La funzione di compilazione evals esso, in modo che possa essere una funzione che restituisce una stringa che è specifico per il buffer o che dipende dal momento della giornata, ecc:

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

Inoltre, anche se non probabilmente non utile per le vostre esigenze specifiche , si può sempre definire la fase di compilazione comando in un file di sezione variabile:

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

o

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

compilazione comando viene effettivamente utilizzato come esempio di una variabile file in the manual.

0

In base al manuale, è possibile semplicemente ignorare il modulo interattivo di una funzione con il proprio includendo un modulo interattivo nei propri consigli. Non penso che tu possa modificare o avvolgere il modulo interattivo esistente, ma solo sovrascriverlo completamente.

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

+0

E ho appena provato questo su una funzione che volevo cambiare, e ha funzionato magnificamente. –

1

Ecco alcuni codice che sto usando che seleziona in modo intelligente il comando di compilazione cortesia del University of Wyoming. Al momento l'ho impostato per C, C++ e Fortran. Puoi aggiungere altro per soddisfare le tue esigenze. Se apro una programmazione con estensione C++ e eseguo M-xcompile, il comando di compilazione sputa g++ -Wall currentfilename.cpp -o currentfilename -std=c++14. Devo solo premere immettere.

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