• Stars
    star
    252
  • Rank 161,312 (Top 4 %)
  • Language
    Emacs Lisp
  • Created over 4 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Emacs support for direnv which operates buffer-locally

Melpa Status Melpa Stable Status Build Status Support me

envrc.el - buffer-local direnv integration for Emacs

A GNU Emacs library which uses the direnv tool to determine per-directory/project environment variables and then set those environment variables on a per-buffer basis. This means that when you work across multiple projects which have .envrc files, all processes launched from the buffers "in" those projects will be executed with the environment variables specified in those files. This allows different versions of linters and other tools to be used in each project if desired.

This library is like the direnv.el package, but sets all environment variables buffer-locally, while direnv.el changes the global set of environment variables after each command.

Installation

Installable packages are available via MELPA: do M-x package-install RET envrc RET.

Alternatively, download the latest release or clone the repository, and install envrc.el with M-x package-install-file.

Usage

Add the following to your init.el (after calling package-initialize):

(envrc-global-mode)

It's probably wise to do this late in your startup sequence: you normally want envrc-mode to be initialized in each buffer before other minor modes like flycheck-mode which might look for executables. Counter-intuitively, this means that envrc-global-mode should be enabled after other global minor modes, since each prepends itself to various hooks.

You should only enable the mode if direnv is installed and available in the default Emacs exec-path. (There is a local minor mode envrc-mode, but you should not try to enable this granularly, e.g. for certain modes or projects, because compilation and other buffers might not get set up with the right environment.)

Regarding interaction with the mode, see envrc-mode-map, and the commands envrc-reload, envrc-allow and envrc-deny. (There's also envrc-reload-all as a "nuclear" reset, for now!)

In particular, you can enable keybindings for the above commands by binding your preferred prefix to envrc-command-map in envrc-mode-map, e.g.

(with-eval-after-load 'envrc
  (define-key envrc-mode-map (kbd "C-c e") 'envrc-command-map))

Troubleshooting

If you find that a particular Emacs command isn't picking up the environment of your current buffer, and you're sure that envrc-mode is active in that buffer, then it's possible you've found code that runs a process in a temp buffer and neglects to propagate your environment to that buffer before doing so.

A couple of common Emacs commands that suffer from this defect are also patched directly via advice in envrc.elshell-command-to-string is a prominent example!

The inheritenv package was designed to handle this case in general.

Design notes

By default, Emacs has a single global set of environment variables used for all subprocesses, stored in the process-environment variable. direnv.el switches that global environment using values from direnv when the user performs certain actions, such as switching between buffers in different projects.

In practice, this is simple and mostly works very well. But there are some quirks, and it feels wrong to me to mutate the global environment in order to support per-directory environments.

Now, in Emacs we can also set process-environment locally in a buffer. If this value could be correctly maintained in all buffers based on their various respective .envrc files, then buffers across multiple projects could simultaneously be "connected" to the environments of their corresponding project directories. I wrote envrc.el to explore this approach.

envrc.el uses a global minor mode (envrc-global-mode) to hook into practically every buffer created by Emacs, including hidden and temporary ones. When a buffer is found to be "inside" an .envrc-managed project, process-environment is set buffer-locally by running direnv, the results of which are also cached indefinitely so that this is not too costly overall. Each buffer has a local minor mode (envrc-mode) with an indicator which displays whether or not a direnv is in effect in that buffer. (Hooking into every buffer is important, rather than just those with certain major modes, since separate temporary, compilation and repl buffers are routinely used for executing processes.)

This approach also has some trade-offs:

  • Buffers like *Help* will have envrc-mode enabled based on the directory of the buffer which caused them to be created initially, and then those buffers often live for a long time. If you launch programs from such buffers while working on a different project, the results might not be what you expect. I might exclude certain modes to minimise confusion, but users will always have to be aware of the fact that environments are buffer-specific.

  • There's a (very small) overhead every time a buffer is created, and that happens quite a lot.

  • direnv updates are not automatic. direnv.el re-executes direnv when switching between buffers that visit files in different directories, whereas envrc-mode caches the environment until the user refreshes it explicitly with envrc-reload.

Overall this approach works well in practice, and feels cleaner than trying to strategically modify the global environment.

It's also possible that there's a way to call direnv more aggressively by allowing it to see values of DIRENV_* obtained previously such that it becomes a no-op.


💝 Support this project and my other Open Source work via Patreon

💼 LinkedIn profile

sanityinc.com

🐦 @sanityinc

More Repositories

1

emacs.d

An Emacs configuration bundle with batteries included
Emacs Lisp
6,646
star
2

exec-path-from-shell

Make Emacs use the $PATH set up by the user's shell
Emacs Lisp
1,325
star
3

sqlint

Simple SQL linter supporting ANSI and PostgreSQL syntaxes
Ruby
404
star
4

color-theme-sanityinc-tomorrow

A set of comprehensive Emacs color themes based on Chris Kempson's 'tomorrow' themes
Emacs Lisp
392
star
5

page-break-lines

Emacs: display ugly ^L page breaks as tidy horizontal lines
Emacs Lisp
222
star
6

emacs-reformatter

Define commands which run reformatters on the current Emacs buffer
Emacs Lisp
213
star
7

package-lint

A linting library for elisp package metadata
Emacs Lisp
191
star
8

nix-emacs-ci

Emacs installations for continuous integration
Nix
166
star
9

ibuffer-vc

Let Emacs' ibuffer-mode group files by git project etc., and show file state
Emacs Lisp
163
star
10

elisp-slime-nav

Slime-style navigation of Emacs Lisp source with M-. & M-,
Emacs Lisp
148
star
11

whitespace-cleanup-mode

In Emacs, intelligently call whitespace-cleanup on save
Emacs Lisp
118
star
12

setup-emacs

Github action which installs a given Emacs version
Shell
117
star
13

diredfl

Extra Emacs font lock rules for a more colourful dired
Emacs Lisp
115
star
14

ac-slime

Emacs auto-complete plugin for Slime symbols
Emacs Lisp
109
star
15

whole-line-or-region

In Emacs, operate on current line if no region is active
Emacs Lisp
106
star
16

less-css-mode

Emacs mode for LESS CSS (lesscss.org), with support for compile-on-save
Emacs Lisp
101
star
17

disable-mouse

Disable the mouse in Emacs
Emacs Lisp
100
star
18

darcs-to-git

Convert/mirror darcs repos into git repos
Ruby
96
star
19

airspeed

A lightweight Python template engine compatible with Velocity, used in OpenStack
Python
86
star
20

color-theme-sanityinc-solarized

A pair of Emacs color themes based on Ethan Schoonover's 'solarized' theme
Emacs Lisp
80
star
21

default-text-scale

Easily adjust the font size in all Emacs frames
Emacs Lisp
73
star
22

unfill

Functions providing the inverse of Emacs' fill-paragraph and fill-region
Emacs Lisp
72
star
23

jargs

GNU getopt-style command-line argument parser for Java, used in JBoss
Java
64
star
24

ibuffer-projectile

Group buffers in Emacs ibuffer-mode by their projectile root directory
Emacs Lisp
63
star
25

rails-runit

Run Rails reliably as runit services
Shell
43
star
26

paredit-everywhere

Enable some paredit features in non-lisp buffers
Emacs Lisp
38
star
27

flycheck-package

Flycheck checker for elisp package metadata
Emacs Lisp
38
star
28

postgresql-migrations

Simple Schema Migrations for PostgreSQL
PLpgSQL
36
star
29

flymake-easy

Helpers for easily building Emacs flymake checkers
Emacs Lisp
35
star
30

inheritenv

Make emacs temp buffers inherit buffer-local environment variables
Emacs Lisp
35
star
31

emacs-shfmt

Reformat shell script code in Emacs using shfmt
Emacs Lisp
33
star
32

flymake-flycheck

Use any Emacs flycheck checker as a flymake backend
Emacs Lisp
32
star
33

flymake-python-pyflakes

Emacs flymake handler for python using pyflakes
Emacs Lisp
29
star
34

flycheck-ledger

A flychecker for checking ledger files
Emacs Lisp
28
star
35

flymake-ruby

Emacs flymake handler for ruby-mode
Emacs Lisp
24
star
36

ns-auto-titlebar

In Emacs, set the MacOS transparent titlebar to match the current theme
Emacs Lisp
23
star
37

ruby-hash-syntax

In Emacs, toggle ruby hash syntax between classic and 1.9 styles
Emacs Lisp
22
star
38

windswap

Like Emacs's "windmove.el", but swaps buffers while moving
Emacs Lisp
20
star
39

osx-location

Make Emacs watch and respond to changes in geographical location on OS X
Emacs Lisp
19
star
40

flymake-jslint

Emacs flymake syntax-checker for javascript using jslint
Emacs Lisp
18
star
41

flymake-coffee

Emacs flymake handler for CoffeeScript
Emacs Lisp
15
star
42

flymake-php

Emacs flymake syntax-checker for php files
Emacs Lisp
15
star
43

mode-line-bell

Flash the Emacs mode line instead of ringing the bell
Emacs Lisp
15
star
44

adventofcode2016

Advent of Code 2016, in Haskell
Haskell
15
star
45

list-unicode-display

Search for and list unicode characters in Emacs
Emacs Lisp
15
star
46

ac-haskell-process

Haskell completion source for Emacs auto-complete package
Emacs Lisp
15
star
47

servant-elm

WIP: Generate Elm modules which talk to Haskell Servant APIs
Haskell
14
star
48

cl-libify

Update elisp code to use cl-lib instead of cl
Emacs Lisp
12
star
49

flymake-json

Emacs flymake handler for json using jsonlint
Emacs Lisp
11
star
50

emacs-nixpkgs-fmt

Reformat Nix code with nixpkgs-fmt in Emacs
Emacs Lisp
10
star
51

ac-inf-ruby

An Emacs auto-complete source for use in inf-ruby sessions
Emacs Lisp
10
star
52

flymake-shell

Emacs flymake syntax-checker for shell scripts
Emacs Lisp
9
star
53

rosettacode-clojure

My Clojure contributions to Rosettacode
Clojure
8
star
54

skewer-less

Live LESS stylesheet updates from Emacs via skewer-mode
Emacs Lisp
8
star
55

flycheck-relint

Flycheck integration for `relint`, which checks regexps in emacs lisp
Emacs Lisp
7
star
56

flymake-sass

Emacs flymake syntax-checker for sass stylesheets
Emacs Lisp
7
star
57

icfpc2017

2017 ICFP Contest - The Flux Ambassadors
Haskell
7
star
58

elm-life

Conway's Game of Life in Elm
Elm
7
star
59

ivy-smex

Use Ivy completion with Smex command matching
Emacs Lisp
6
star
60

hippie-expand-slime

Plug slime completion into Emacs' "hippie-expand"
Emacs Lisp
6
star
61

git-timemachine

Step through historic versions of git controlled file using everyone's favourite editor
Emacs Lisp
6
star
62

icfpc2015

My solo entry for the 2015 ICFP Contest - http://2015.icfpcontest.org/
Haskell
6
star
63

lively

Live-evaluated emacs lisp snippets
Emacs Lisp
6
star
64

dbdoc

Generate javadoc-style html documentation for a database schema
Python
6
star
65

adventofcode2017

Advent of Code 2017 in Haskell
Haskell
5
star
66

flymake-css

Emacs flymake syntax-checker for css using csslint
Emacs Lisp
5
star
67

company-cmake

Completion back-end for CMake
Emacs Lisp
5
star
68

wordchainsrevenge

Another run at the WordChains kata in haskell
Haskell
4
star
69

with-temp-postgres

Temporarily run postgres against a pre-existing data directory while you run a command
Shell
4
star
70

icfpc2018

2018 ICFP Contest
Haskell
4
star
71

elpa-audit

Handy functions for inspecting and comparing Emas package archives
Emacs Lisp
4
star
72

flymake-haskell-multi

Syntax-check haskell source in Emacs using both ghc and hlint
Emacs Lisp
4
star
73

adventofcode2018

Advent of Code 2018, in Haskell again because yay Haskell
Haskell
4
star
74

flymake-haml

Emacs flymake handler for haml and sass files
Emacs Lisp
4
star
75

redis-memo

Memoize clojure functions using redis as an out-of-process store for cached results
Clojure
4
star
76

dotr

Ruby wrapper for the 'dot' utility from graphviz
Ruby
3
star
77

dot-hammerspoon

My hammerspoon configuration
Lua
3
star
78

haskell-anagrams

A Haskell anagram generator, written for West London Hack Night
Haskell
3
star
79

emacs-docker

WIP: Tools for building docker images that contain emacs versions
Makefile
3
star
80

db_console

Defunct Rails plugin (now merged into Rails as script/dbconsole)
Ruby
3
star
81

gemdocindex

Generate an HTML index of your ruby gem rdocs, like a static 'gem --server'
3
star
82

color-theme-sanityinc

Two pleasant medium-contrast Emacs color themes in light and dark flavours
Emacs Lisp
3
star
83

codejam2016

Haskell solutions for qualification round of codejam 2016
Haskell
3
star
84

netstubs

Stub http and smtp servers, written in Python
Python
3
star
85

mockr

Tiny Ruby mock object library inspired by JMock
Ruby
2
star
86

fleeceminer

A toy crypto miner in ruby
Ruby
2
star
87

purcell

GitHub metadata
2
star
88

flymake-less

Emacs flymake handler for LESS stylesheets
Emacs Lisp
2
star
89

replit-j

Repl.it support for jlang
Nix
2
star
90

jquery.placeholder

Shows ghost text in empty input boxes, suggesting what the user should enter.
JavaScript
2
star
91

vm5294

"5294" Virtual Machine
Haskell
2
star
92

maintenance_server

Rails plugin providing a fallback server for mongrel
Ruby
2
star
93

farsync

A toy rsync-like tool written in ruby
Ruby
2
star
94

markov-chains-hs

A toy Markov Chain text generator in Haskell
Haskell
2
star
95

rsshole

Fetch a bunch of RSS feeds and classify new items (WIP)
Haskell
2
star
96

flymake-hlint

Emacs flymake handler for checking Haskell source code with hlint
Emacs Lisp
2
star
97

adventofcode2020

Advent of Code 2020, in J
J
2
star
98

purescript-life

WIP: purescript port of my Elm version of Conway's Game of Life (https://github.com/purcell/elm-life)
PureScript
2
star
99

adventofcodeteam

A team effort to solve all the Advent of Code challenges with Haskell in 2 days
Haskell
2
star
100

renumber_migrations

Rails plugin for renumbering clashing migrations in a project kept in svn
Ruby
2
star