Hook to switch the linter binaries in Emacs Lisp according to virtual environment

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
4
down vote
favorite
Problem
I use Emacs for Python development along with several linters. When I activate a Python virtual environment (venv) from within Emacs, I would like to set the linter binaries according to the following rules:
- If the venv has a particular linter installed, use it
- If the venv does not have a particular linter, use the one in a pre-specified, default venv
- If the linter does not exist in either the active venv or the default venv, set the linter binary to
nil
For example, let's say I activate a venv called my_venv that has pylint installed, but no flake8. flake8 is however installed in my default linters venv. After activating my_venv, the linters that will be used are
- pylint -- my_venv
- flake8 -- linters
Purpose
The reason for implementing this is that I develop Python on multiple machines that share a single, version-controlled init.el file. I do not want to guarantee that I have the same Python binaries and venvs across these machines; this implementation helps decouple my Emacs setup from the Python venvs that are present on a machine.
Additional info
- The code will go inside my
init.elfile - I use flycheck as the interface between Emacs and the linters
- I use pyvenv for Python virtual environments in Emacs
Code
(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python")))
(defvar default-linter-venv-path (concat (getenv "WORKON_HOME") "/linters/"))
(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then no linter will be set."
(dolist (exec linter-execs)
(let ((venv-linter-bin (concat pyvenv-virtual-env (nth 1 exec)))
(default-linter-bin (concat default-linter-venv-path (nth 1 exec)))
(flycheck-var (nth 0 exec)))
(cond ((file-exists-p venv-linter-bin)
(set flycheck-var venv-linter-bin))
((file-exists-p default-linter-bin)
(set flycheck-var default-linter-bin))
(t (set flycheck-var nil))))))
(add-hook 'pyvenv-post-activate-hooks 'switch-linters)
Explanation
linter-execsis a list of two-element lists. The first element of an entry is theflycheckvariable that contains the path of a linter binary. The second element is the relative path of the binary from within the venv.- The default linter venv is
$WORKON_HOME/linters switch-lintersis the call-back function attached topyvenv-post-activate-hooks- The conditional checks for the presence of the linter binary files, first in the current venv and next in the default venv. Failing these, it sets the binary to
nilin the line(t (set flycheck-var nil))
Specific questions
- Is this idiomatic elisp, or is it too "Pythonic"?
- Is
linter-execsthe proper way to implement a list of tuples in elisp?
elisp
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |Â
up vote
4
down vote
favorite
Problem
I use Emacs for Python development along with several linters. When I activate a Python virtual environment (venv) from within Emacs, I would like to set the linter binaries according to the following rules:
- If the venv has a particular linter installed, use it
- If the venv does not have a particular linter, use the one in a pre-specified, default venv
- If the linter does not exist in either the active venv or the default venv, set the linter binary to
nil
For example, let's say I activate a venv called my_venv that has pylint installed, but no flake8. flake8 is however installed in my default linters venv. After activating my_venv, the linters that will be used are
- pylint -- my_venv
- flake8 -- linters
Purpose
The reason for implementing this is that I develop Python on multiple machines that share a single, version-controlled init.el file. I do not want to guarantee that I have the same Python binaries and venvs across these machines; this implementation helps decouple my Emacs setup from the Python venvs that are present on a machine.
Additional info
- The code will go inside my
init.elfile - I use flycheck as the interface between Emacs and the linters
- I use pyvenv for Python virtual environments in Emacs
Code
(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python")))
(defvar default-linter-venv-path (concat (getenv "WORKON_HOME") "/linters/"))
(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then no linter will be set."
(dolist (exec linter-execs)
(let ((venv-linter-bin (concat pyvenv-virtual-env (nth 1 exec)))
(default-linter-bin (concat default-linter-venv-path (nth 1 exec)))
(flycheck-var (nth 0 exec)))
(cond ((file-exists-p venv-linter-bin)
(set flycheck-var venv-linter-bin))
((file-exists-p default-linter-bin)
(set flycheck-var default-linter-bin))
(t (set flycheck-var nil))))))
(add-hook 'pyvenv-post-activate-hooks 'switch-linters)
Explanation
linter-execsis a list of two-element lists. The first element of an entry is theflycheckvariable that contains the path of a linter binary. The second element is the relative path of the binary from within the venv.- The default linter venv is
$WORKON_HOME/linters switch-lintersis the call-back function attached topyvenv-post-activate-hooks- The conditional checks for the presence of the linter binary files, first in the current venv and next in the default venv. Failing these, it sets the binary to
nilin the line(t (set flycheck-var nil))
Specific questions
- Is this idiomatic elisp, or is it too "Pythonic"?
- Is
linter-execsthe proper way to implement a list of tuples in elisp?
elisp
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |Â
up vote
4
down vote
favorite
up vote
4
down vote
favorite
Problem
I use Emacs for Python development along with several linters. When I activate a Python virtual environment (venv) from within Emacs, I would like to set the linter binaries according to the following rules:
- If the venv has a particular linter installed, use it
- If the venv does not have a particular linter, use the one in a pre-specified, default venv
- If the linter does not exist in either the active venv or the default venv, set the linter binary to
nil
For example, let's say I activate a venv called my_venv that has pylint installed, but no flake8. flake8 is however installed in my default linters venv. After activating my_venv, the linters that will be used are
- pylint -- my_venv
- flake8 -- linters
Purpose
The reason for implementing this is that I develop Python on multiple machines that share a single, version-controlled init.el file. I do not want to guarantee that I have the same Python binaries and venvs across these machines; this implementation helps decouple my Emacs setup from the Python venvs that are present on a machine.
Additional info
- The code will go inside my
init.elfile - I use flycheck as the interface between Emacs and the linters
- I use pyvenv for Python virtual environments in Emacs
Code
(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python")))
(defvar default-linter-venv-path (concat (getenv "WORKON_HOME") "/linters/"))
(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then no linter will be set."
(dolist (exec linter-execs)
(let ((venv-linter-bin (concat pyvenv-virtual-env (nth 1 exec)))
(default-linter-bin (concat default-linter-venv-path (nth 1 exec)))
(flycheck-var (nth 0 exec)))
(cond ((file-exists-p venv-linter-bin)
(set flycheck-var venv-linter-bin))
((file-exists-p default-linter-bin)
(set flycheck-var default-linter-bin))
(t (set flycheck-var nil))))))
(add-hook 'pyvenv-post-activate-hooks 'switch-linters)
Explanation
linter-execsis a list of two-element lists. The first element of an entry is theflycheckvariable that contains the path of a linter binary. The second element is the relative path of the binary from within the venv.- The default linter venv is
$WORKON_HOME/linters switch-lintersis the call-back function attached topyvenv-post-activate-hooks- The conditional checks for the presence of the linter binary files, first in the current venv and next in the default venv. Failing these, it sets the binary to
nilin the line(t (set flycheck-var nil))
Specific questions
- Is this idiomatic elisp, or is it too "Pythonic"?
- Is
linter-execsthe proper way to implement a list of tuples in elisp?
elisp
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Problem
I use Emacs for Python development along with several linters. When I activate a Python virtual environment (venv) from within Emacs, I would like to set the linter binaries according to the following rules:
- If the venv has a particular linter installed, use it
- If the venv does not have a particular linter, use the one in a pre-specified, default venv
- If the linter does not exist in either the active venv or the default venv, set the linter binary to
nil
For example, let's say I activate a venv called my_venv that has pylint installed, but no flake8. flake8 is however installed in my default linters venv. After activating my_venv, the linters that will be used are
- pylint -- my_venv
- flake8 -- linters
Purpose
The reason for implementing this is that I develop Python on multiple machines that share a single, version-controlled init.el file. I do not want to guarantee that I have the same Python binaries and venvs across these machines; this implementation helps decouple my Emacs setup from the Python venvs that are present on a machine.
Additional info
- The code will go inside my
init.elfile - I use flycheck as the interface between Emacs and the linters
- I use pyvenv for Python virtual environments in Emacs
Code
(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python")))
(defvar default-linter-venv-path (concat (getenv "WORKON_HOME") "/linters/"))
(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then no linter will be set."
(dolist (exec linter-execs)
(let ((venv-linter-bin (concat pyvenv-virtual-env (nth 1 exec)))
(default-linter-bin (concat default-linter-venv-path (nth 1 exec)))
(flycheck-var (nth 0 exec)))
(cond ((file-exists-p venv-linter-bin)
(set flycheck-var venv-linter-bin))
((file-exists-p default-linter-bin)
(set flycheck-var default-linter-bin))
(t (set flycheck-var nil))))))
(add-hook 'pyvenv-post-activate-hooks 'switch-linters)
Explanation
linter-execsis a list of two-element lists. The first element of an entry is theflycheckvariable that contains the path of a linter binary. The second element is the relative path of the binary from within the venv.- The default linter venv is
$WORKON_HOME/linters switch-lintersis the call-back function attached topyvenv-post-activate-hooks- The conditional checks for the presence of the linter binary files, first in the current venv and next in the default venv. Failing these, it sets the binary to
nilin the line(t (set flycheck-var nil))
Specific questions
- Is this idiomatic elisp, or is it too "Pythonic"?
- Is
linter-execsthe proper way to implement a list of tuples in elisp?
elisp
elisp
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 4 hours ago
kmdouglass
212
212
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
kmdouglass is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
3
down vote
It would be a good idea to write a docstring for the
defvar'd variables likelinter-execs. The explanations in the post would make an excellent start, for example:(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python"))
"The linter executables, as list of two-element lists. The
first element of an entry is the flycheck variable that contains
the path of a linter executable. The second element is the
relative path of the executable from within the venv.")Writing
(nth 0 exec)and(nth 1 exec)makes it hard to understand the meaning of these items of data. In Python you'd use tuple unpacking to give meaningful names to each element of theexecdata structure, like this:flycheck_var, path = execIn Emacs Lisp you can use
cl-destructuring-bindin a similar way:(dolist (exec linter-execs)
(cl-destructuring-bind (flycheck-var path) exec
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcBut
execcomes from a list that you are looping over, so you could use thecl-loopmacro instead ofdolist, andcl-loophas destructuring built in:(cl-loop for (flycheck-var path) in linter-execs do
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcYou'll need
(require 'cl-macs)to usecl-destructuring-bindorcl-loop.The two directories
pyvenv-virtual-envanddefault-linter-venv-pathare treated in exactly the same way: first we do(let ((Y (concat X path))and then(file-exists-p Y)and finally(set flycheck-var Y). This repetition could be factored out into a loop:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var
(cl-loop for directory in dirs
for executable = (concat directory path)
if (file-exists-p executable) return executable)))Instead of
file-exists-p, you probably want to usefile-executable-p.Looking for a file in a list of directories is built into Emacs as the function
locate-file. Using this, we get:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var (locate-file path dirs nil 'file-executable-p))))
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
It would be a good idea to write a docstring for the
defvar'd variables likelinter-execs. The explanations in the post would make an excellent start, for example:(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python"))
"The linter executables, as list of two-element lists. The
first element of an entry is the flycheck variable that contains
the path of a linter executable. The second element is the
relative path of the executable from within the venv.")Writing
(nth 0 exec)and(nth 1 exec)makes it hard to understand the meaning of these items of data. In Python you'd use tuple unpacking to give meaningful names to each element of theexecdata structure, like this:flycheck_var, path = execIn Emacs Lisp you can use
cl-destructuring-bindin a similar way:(dolist (exec linter-execs)
(cl-destructuring-bind (flycheck-var path) exec
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcBut
execcomes from a list that you are looping over, so you could use thecl-loopmacro instead ofdolist, andcl-loophas destructuring built in:(cl-loop for (flycheck-var path) in linter-execs do
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcYou'll need
(require 'cl-macs)to usecl-destructuring-bindorcl-loop.The two directories
pyvenv-virtual-envanddefault-linter-venv-pathare treated in exactly the same way: first we do(let ((Y (concat X path))and then(file-exists-p Y)and finally(set flycheck-var Y). This repetition could be factored out into a loop:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var
(cl-loop for directory in dirs
for executable = (concat directory path)
if (file-exists-p executable) return executable)))Instead of
file-exists-p, you probably want to usefile-executable-p.Looking for a file in a list of directories is built into Emacs as the function
locate-file. Using this, we get:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var (locate-file path dirs nil 'file-executable-p))))
add a comment |Â
up vote
3
down vote
It would be a good idea to write a docstring for the
defvar'd variables likelinter-execs. The explanations in the post would make an excellent start, for example:(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python"))
"The linter executables, as list of two-element lists. The
first element of an entry is the flycheck variable that contains
the path of a linter executable. The second element is the
relative path of the executable from within the venv.")Writing
(nth 0 exec)and(nth 1 exec)makes it hard to understand the meaning of these items of data. In Python you'd use tuple unpacking to give meaningful names to each element of theexecdata structure, like this:flycheck_var, path = execIn Emacs Lisp you can use
cl-destructuring-bindin a similar way:(dolist (exec linter-execs)
(cl-destructuring-bind (flycheck-var path) exec
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcBut
execcomes from a list that you are looping over, so you could use thecl-loopmacro instead ofdolist, andcl-loophas destructuring built in:(cl-loop for (flycheck-var path) in linter-execs do
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcYou'll need
(require 'cl-macs)to usecl-destructuring-bindorcl-loop.The two directories
pyvenv-virtual-envanddefault-linter-venv-pathare treated in exactly the same way: first we do(let ((Y (concat X path))and then(file-exists-p Y)and finally(set flycheck-var Y). This repetition could be factored out into a loop:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var
(cl-loop for directory in dirs
for executable = (concat directory path)
if (file-exists-p executable) return executable)))Instead of
file-exists-p, you probably want to usefile-executable-p.Looking for a file in a list of directories is built into Emacs as the function
locate-file. Using this, we get:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var (locate-file path dirs nil 'file-executable-p))))
add a comment |Â
up vote
3
down vote
up vote
3
down vote
It would be a good idea to write a docstring for the
defvar'd variables likelinter-execs. The explanations in the post would make an excellent start, for example:(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python"))
"The linter executables, as list of two-element lists. The
first element of an entry is the flycheck variable that contains
the path of a linter executable. The second element is the
relative path of the executable from within the venv.")Writing
(nth 0 exec)and(nth 1 exec)makes it hard to understand the meaning of these items of data. In Python you'd use tuple unpacking to give meaningful names to each element of theexecdata structure, like this:flycheck_var, path = execIn Emacs Lisp you can use
cl-destructuring-bindin a similar way:(dolist (exec linter-execs)
(cl-destructuring-bind (flycheck-var path) exec
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcBut
execcomes from a list that you are looping over, so you could use thecl-loopmacro instead ofdolist, andcl-loophas destructuring built in:(cl-loop for (flycheck-var path) in linter-execs do
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcYou'll need
(require 'cl-macs)to usecl-destructuring-bindorcl-loop.The two directories
pyvenv-virtual-envanddefault-linter-venv-pathare treated in exactly the same way: first we do(let ((Y (concat X path))and then(file-exists-p Y)and finally(set flycheck-var Y). This repetition could be factored out into a loop:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var
(cl-loop for directory in dirs
for executable = (concat directory path)
if (file-exists-p executable) return executable)))Instead of
file-exists-p, you probably want to usefile-executable-p.Looking for a file in a list of directories is built into Emacs as the function
locate-file. Using this, we get:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var (locate-file path dirs nil 'file-executable-p))))
It would be a good idea to write a docstring for the
defvar'd variables likelinter-execs. The explanations in the post would make an excellent start, for example:(defvar linter-execs '((flycheck-python-flake8-executable "bin/flake8")
(flycheck-python-pylint-executable "bin/pylint")
(flycheck-python-pycompile-executable "bin/python"))
"The linter executables, as list of two-element lists. The
first element of an entry is the flycheck variable that contains
the path of a linter executable. The second element is the
relative path of the executable from within the venv.")Writing
(nth 0 exec)and(nth 1 exec)makes it hard to understand the meaning of these items of data. In Python you'd use tuple unpacking to give meaningful names to each element of theexecdata structure, like this:flycheck_var, path = execIn Emacs Lisp you can use
cl-destructuring-bindin a similar way:(dolist (exec linter-execs)
(cl-destructuring-bind (flycheck-var path) exec
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcBut
execcomes from a list that you are looping over, so you could use thecl-loopmacro instead ofdolist, andcl-loophas destructuring built in:(cl-loop for (flycheck-var path) in linter-execs do
(let ((venv-linter-bin (concat pyvenv-virtual-env path))
;; etcYou'll need
(require 'cl-macs)to usecl-destructuring-bindorcl-loop.The two directories
pyvenv-virtual-envanddefault-linter-venv-pathare treated in exactly the same way: first we do(let ((Y (concat X path))and then(file-exists-p Y)and finally(set flycheck-var Y). This repetition could be factored out into a loop:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var
(cl-loop for directory in dirs
for executable = (concat directory path)
if (file-exists-p executable) return executable)))Instead of
file-exists-p, you probably want to usefile-executable-p.Looking for a file in a list of directories is built into Emacs as the function
locate-file. Using this, we get:(defun switch-linters ()
"Switch linter executables to those in the current venv.
If the venv does not have any linter packages, then they will be
set to those in the `default-linter-venv-path` venv. If these do
not exist, then the linter will be set to nil."
(cl-loop with dirs = (list pyvenv-virtual-env default-linter-venv-path)
for (flycheck-var path) in linter-execs
do (set flycheck-var (locate-file path dirs nil 'file-executable-p))))
answered 1 hour ago
Gareth Rees
41.9k394168
41.9k394168
add a comment |Â
add a comment |Â
kmdouglass is a new contributor. Be nice, and check out our Code of Conduct.
kmdouglass is a new contributor. Be nice, and check out our Code of Conduct.
kmdouglass is a new contributor. Be nice, and check out our Code of Conduct.
kmdouglass is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f203808%2fhook-to-switch-the-linter-binaries-in-emacs-lisp-according-to-virtual-environmen%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
