2010-10-25 13 views
18

Gemäß der Emacs-Dokumentation gilt Directory Variables für alle Dateien unterhalb eines Verzeichnisses, das eine .dir-locals.el-Datei enthält.Wie kann ich auf den Pfad zum aktuellen Verzeichnis in einer Emacs-Verzeichnisvariablen zugreifen?

Wie kann ich in dieser Datei eine Variable auf den vollständigen Pfad festlegen, der die Datei enthält? Zum Beispiel:

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

Du hast es nicht explizit erwähnt, aber ich frage mich, ob Sie in eines der verschiedenen interessiert sein würden " Projekt "Pakete. Zum Beispiel habe ich gerade begonnen, https://github.com/bbatsov/projectile; Es könnte etwas von dem tun, was Sie mit Verzeichnis-Locals machen wollten. – offby1

Antwort

6

Ich denke, (file-name-directory (or load-file-name buffer-file-name)) sollte Ihnen den Verzeichnispfad geben.

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

bearbeiten: Außer es wird nicht, weil alle eval Ausdrücke im Zusammenhang mit dem Puffer ausgewertet werden, deren Variablen gehackt werden.

+2

Ja, aber ... so weit ich weiß, bewertet Emacs die Formulare in .dir-locals nicht; stattdessen liest es sie nur und weist den benannten Variablen Werte zu ... und die Werte müssen Konstanten sein. Ich hoffe, ich liege falsch, aber ich vermute, es gibt keine Möglichkeit, das zu tun. – offby1

+0

@ offby1: Diese Art von Ansatz scheint ein bisschen wahrscheinlicher zu arbeiten als nberth, zumindest ... – SamB

+0

@SamB Ich bin enttäuscht, dass keiner von uns, anscheinend, tatsächlich dies versucht hat; also habe ich es gerade getan. Es funktioniert nicht :-('' '((nicht. ((Did-it-work) (Dateiname-Verzeichnis (oder Ladedateiname Pufferdateiname)))))) ' '' Ich habe jedoch eine "unsafe-variable" Warnung erhalten. – offby1

2

Wenn es noch wichtig ist, um das OP oder eine andere, würde ich vorschlagen, Sie erstellen eine Funktion, um die .dir-locals.el Datei zu generieren. Dann könnte man etwas schreiben wie:

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

im Home-Verzeichnis des Projekts ausgeführt werden.

+1

Hmm. Könnte nicht die * schlechteste * Idee in der Welt sein, aber es lässt immer noch sehr viel zu wünschen übrig! – SamB

+0

Funktioniert, bis Sie das Verzeichnis verschieben, zB projektspezifische Einstellungen, die an ein Git Repo übergeben werden und jemand es an anderer Stelle ausprobiert –

1

hack-local-variables ist die Hauptfunktion alle lokalen Variablen für die Verarbeitung und ruft hack-dir-local-variables mit der .dir-locals.el Datei zu behandeln (oder einem Verzeichnis lokalen Klassenvariable, wenn Sie nicht, dass die Datei).

Der Code des Verzeichnisses für die Einrichtung in ihrer eigenen Funktion nicht isoliert, so dass wir es abschreiben in eine neue Funktion (das von GNU Emacs 24.0.95.1) müssen:

(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

Dieser Code scheint korrekt, wenn ein bisschen zu unhandlich zu setzen '. dir-locals.el' selbst ... – SamB

+0

Die Funktion würde zweifellos in der gleichen Bibliothek leben wie der Code, der die Information an erster Stelle benötigt.Sie ​​würden es wahrscheinlich nur als Funktion bezeichnen, anstatt eine Variable zu setzen (obwohl Sie es könnten packen Sie es mit einer automatisch pufferlokalen Variable zusammen, die erweitert wird die Funktion, um zu prüfen, ob diese Variable bereits gesetzt ist, und nur den vorhandenen Wert zurückzugeben, wenn es einen gibt; mache nur die Verarbeitung, um den Wert zu setzen, wenn es * nicht * bereits gesetzt ist). – phils

+0

Bibliothek? Wer hat etwas über eine Bibliothek gesagt? – SamB

10

fragte ich Ich selbst die gleiche Frage und keine Lösung im Internet gefunden, also denke ich, diese Antwort kann helfen. Tatsächlich stellt sich heraus, dass wir dir-locals-find-file wiederverwenden können, um das Verzeichnis zu erhalten, das die Datei .dir-locals.el enthält. Also hier ist, was ich gefunden, zB ein aspell persönliches Wörterbuch zu einem vollständigen Verzeichnis gewidmet Einrichtung:

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

Auch scheint es, Einträge in der Reihenfolge ausgewertet werden sie angegeben werden, so sollte der folgende Code funktioniert:

Emacs wird über unsichere lokale Variablen beschweren (aufgrund der eval Konstrukt), noch kann man es immer noch sicher markieren.

+0

Dieser Ansatz funktioniert nicht zuverlässig mit mehr als einem .dir-locals.el im Bereich. – SamB

+0

@SamB Ich habe es gerade versucht, und es scheint für mich gut zu funktionieren (solange Sie keine komplizierten Variablenabhängigkeiten zwischen Ihren '.dir-locals.el' Dateien haben); Mit einer Reihe von '.dir-locals.el', von denen jedes genau mein letztes Beispiel enthält, wird 'mein-project-path' auf den längsten Pfad im Bereich der besuchten Datei gesetzt. Allerdings weiß ich nicht genau, wie das Verhalten von Emacs w.r.t schuppig '.dir-locals.el' spezifiziert wurde. – nberth

+1

Mein Fehler: Mein Schnelltest war voreingenommen, da die '.dir-locals.el' alle identisch waren. In der Tat gibt 'dir-locals-find-file' immer das erste' .dir-locals.el' zurück, auf das Emacs (das am nächsten zur besuchten Datei) trifft. Ich erkenne die Einschränkung an. – nberth

1

Wenn Sie auf * nichts arbeiten, können Sie das Arbeitsverzeichnis durch den folgenden elisp Code erhalten,

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

Btw, ich erwähnt habe, dass (shell-command "pwd") im Verzeichnis führen, wo Datei (die entsprechend dem Puffer, den Sie gerade bearbeiten).

+1

Das Englisch ist in Ordnung :-). – DJJ

0

In meinem Fall wollte ich eine Datei finden, die relativ zu meinem aktuellen Arbeitsverzeichnis für mein Repository war, und die .dir-locals.sel-Datei wurde in das Stammverzeichnis eingecheckt, also eine Datei "local". dir-locals.el war auch eine Datei "local" zum Projekt root.

pajato0s obige Antwort funktionierte in einigen Fällen, aber es brach auch andere Modi (wie Magit).Ich habe, um das Problem durch die Verwendung des projectileprojectile-project-root Funktion des Pakets zu meinem dem Basispfad für mich zu finden:

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