2010-10-25 3 views
18

In base alla documentazione di Emacs, Directory Variables si applica a tutti i file sotto una directory che contiene un file .dir-locals.el.Come posso accedere al percorso della directory corrente in un file di variabili di directory emacs?

Come posso, in quel file, impostare una variabile sul percorso completo che contiene il file? Ad esempio:

((nil . ((indent-tabs-mode . t) 
      (my-project-path **THIS_DIRECTORY**)))) 
+2

Lei non ha menzionato esplicitamente, ma mi chiedo se si sarebbe interessato a uno dei vari " progetto "pacchetti. Ad esempio, ho appena iniziato a utilizzare https://github.com/bbatsov/projectile; potrebbe fare qualcosa di quello che volevi fare con i locatori di directory. – offby1

risposta

6

Penso che (file-name-directory (or load-file-name buffer-file-name)) dovrebbe darti il ​​percorso della directory.

Vedi http://xahlee.org/emacs/elisp_idioms_batch.html

Edit: Solo che non lo farà, perché qualsiasi eval espressioni sono valutate nel contesto del buffer le cui variabili sono essere violato.

+2

Sì, ma ... per quanto ne so, emacs in realtà non valuta i moduli in .dir-locals; invece, si limita a leggerli e assegna valori alle variabili nominate ... e i valori devono essere costanti. Spero di sbagliarmi, ma sospetto che non ci sia modo di farlo io. – offby1

+0

@ offby1: Questo tipo di approccio sembra un po 'più probabile di lavorare di quello di nberth, almeno ... – SamB

+0

@ SamB Sono deluso che nessuno di noi, a quanto pare, ha effettivamente provato questo; così ho appena fatto. - Non funziona :-('' '((nil. ((Did-it-work (nome-file-directory (o carico-nome-file buffer-nome-file)))))) ' '' Ho comunque ricevuto un avviso di "variabile non sicura" – offby1

2

Nel caso in cui sia ancora importante, per l'OP o qualche altro, suggerirei di creare una funzione per generare il file .dir-locals.el. Quindi si potrebbe scrivere qualcosa come:

(let ((path default-directory) 
     file) 
    (setq file (format "%s/.dir-locals.el" path)) 
    (with-temp-buffer 
    (insert (format "((nil . ((indent-tabs-mode . t) 
      (my-project-path \"%s\"))))" path)) 
    (when (file-writable-p file) 
     (write-region (point-min) 
        (point-max) 
        file)))) 

da eseguire all'interno della home directory del progetto.

+1

Hmm. Potrebbe non essere l'idea peggiore del mondo, ma lascia ancora molto a desiderare! – SamB

+0

Funziona fino a quando non si sposta la directory, ad esempio impostazioni specifiche del progetto impegnate in un repository git e qualcuno lo controlla altrove –

1

hack-local-variables è la funzione principale per l'elaborazione di tutte le variabili locali, e chiama hack-dir-local-variables a che fare con il file .dir-locals.el (o una variabile dir classe locale, se non si sta usando il file).

Il codice per stabilire la directory non è isolato nella sua propria funzione, quindi dovremo copiare fuori in una nuova funzione (questo da GNU Emacs 24.0.95.1):

(defun my-dir-locals-dir() 
    "Return the directory local variables directory. 
Code taken from `hack-dir-local-variables'." 
    (let ((variables-file (dir-locals-find-file (or (buffer-file-name) default-directory))) 
     (dir-name nil)) 
    (cond 
    ((stringp variables-file) 
     (setq dir-name (file-name-directory variables-file))) 
    ((consp variables-file) 
     (setq dir-name (nth 0 variables-file)))) 
    dir-name)) 
+0

Questo codice sembra corretto, anche se un po 'troppo maneggevole da inserire in '. dir-locals.el' stesso ... – SamB

+0

La funzione senza dubbio vivrebbe nella stessa libreria del codice che richiedeva le informazioni in primo luogo. Probabilmente la chiameresti come una funzione invece di impostare una variabile (anche se potresti associarlo con una variabile locale del buffer automaticamente, estendendola la funzione per verificare se tale variabile è già impostata e solo restituendo il valore esistente se ce n'è uno; solo eseguendo l'elaborazione per impostare il valore se * non * è già impostato). – phils

+0

Biblioteca? Chi ha detto qualcosa su una biblioteca? – SamB

10

ho chiesto io stesso la stessa domanda e non ho trovato alcuna soluzione sul web, quindi penso che questa risposta possa aiutare. In realtà, è possibile riutilizzare dir-locals-find-file per ottenere la directory contenente il file .dir-locals.el. Quindi, ecco cosa ho trovato per, ad esempio, la creazione di un dizionario personale aspell dedicato ad un intera directory:

((nil . ((eval . (setq ispell-personal-dictionary 
         (expand-file-name 
         ".aspell_words" 
         (file-name-directory 
         (let ((d (dir-locals-find-file "."))) 
          (if (stringp d) d (car d)))))))))) 

Inoltre, a quanto pare le voci sono valutate nell'ordine in cui sono specificate, in modo che il codice seguente dovrebbe funzionare:

((nil . ((eval . (set (make-local-variable 'my-project-path) 
         (file-name-directory 
         (let ((d (dir-locals-find-file "."))) 
         (if (stringp d) d (car d)))))) 
     (eval . (message "Project directory set to `%s'." my-project-path))))) 

Emacs si lamenterà di variabili locali non sicuri (a causa della eval costrutto), ma si può ancora permanentemente segnare sul sicuro.

+0

Questo approccio non funzionerà in modo affidabile con più di uno .dir-locals.el nell'ambito. – SamB

+0

@SamB L'ho appena provato, e sembra funzionare bene per me (a patto di non avere complicate dipendenze variabili tra i file '.dir-locals.el'); con una serie di '.dir-locals.el' ognuno contenente esattamente il mio ultimo esempio sopra,' my-project-path' è impostato sul percorso più lungo nell'ambito del file visitato. Tuttavia, non so con precisione in che modo viene specificato il comportamento di Emacs che non ha imbriccato '.dir-locals.el'. – nberth

+1

Il mio male: il mio test rapido è stato di parte, poiché ".dir-locals.el" erano tutti identici. In effetti, 'dir-locals-find-file' restituisce sempre il primo' .dir-locals.el' incontrato da Emacs (il più vicino al file visitato). Prendo atto della limitazione. – nberth

1

Se si sta lavorando su * nix, si potrebbe ottenere la directory di lavoro dal seguente codice elisp,

(defun get-working-directory() 
    (getenv "PWD)) 

Btw, devo detto che, (shell-command "pwd") si tradurrà nella directory in cui il file (che è corrispondente al buffer che stai attualmente modificando).

+1

L'inglese è ok :-). – DJJ

0

Nel mio caso, volevo individuare un file che fosse relativo alla mia attuale directory di lavoro per il mio repository, e il file .dir-locals.el è stato controllato nella root, quindi un file "locale" al file. dir-locals.el era anche un file "locale" alla radice del progetto.

La risposta di pajato0 in precedenza ha funzionato per alcuni casi, ma ha anche infranto altre modalità (come Magit).Ho avuto tutto il problema utilizzando la funzione il pacchetto del projectileprojectile-project-root di trovare il mio percorso base per me:

((nil . ((eval . (setq cmake-ide-build-dir 
        (concat (projectile-project-root) "/build-make")) 
     ))))