Quickly Opening .env/.envrc Files in Emacs

by Peter Stuart on July 2, 2023

I use Emacs’s built-in project.el to manage projects, and .env or .envrc files to manage environment variables for those projects. Those files are usually not tracked by git, so project-file-file doesn’t offer them as optionsInvoking project-find-file with a prefix argument will find uncommitted files, but also all other files that have been added to .gitignore, which I don’t want.

, so I wrote a small function that will find all .env and .envrc files (including files with suffixes, like .env.local and .envrc.sample) in the project root:

(defun ps/project-find-dotenv-file ()
  (interactive)
  (let* ((project           (project-current t))
         (default-directory (project-root project))
         (files             (file-expand-wildcards "\\`.env\\(rc\\)?\\(\\..+\\)?\\'" nil t))
         (completion        (lambda (str pred flag)
                              (pcase flag
                                ('metadata
                                 `(metadata (category . file)))
                                (_
                                 (all-completions str files pred)))))
         (file              (completing-read "Find .env/.envrc file: " completion)))
    (find-file file)))

completion could be a simple list of strings instead of a lambda, but I use marginalia to annotate completions with useful information, which requires that the category metadata be set on completions so that it knows that (in this case) it should treat the completions as files when annotating them.

I bind it in project-prefix-map and also add it to the project switcher:

(use-package project
  :ensure nil
  :init
  (setq project-switch-commands '((magit-project-status        "Magit")
                                  (project-find-file           "Find file")
                                  (ps/project-find-dotenv-file "Find .env file")))
  :bind
  (:map project-prefix-map
        ("m" . magit-project-status)
        ("v" . ps/project-find-dotenv-file)))