How can I set environment variables to a buffer-local scope in emacs - emacs

In Emacs, I want to vary the values of my environment variables in different buffers.
My emacs environment depends on environment variables (flymake, compile etc), however I want to be able to be able to have multiple projects open at once in one emacs session but these projects might have conflicting environments.
For example something like different INCLUDE_PATH environment variables for flymake.

You can do this by making process-environment buffer-local:
(defun setup-some-mode-env ()
(make-local-variable 'process-environment)
;; inspect buffer-file-name and add stuff to process-environment as necessary
...)
(add-hook 'some-major-mode 'setup-some-mode-env)
A more elaborate example is this code that imports the Guile environment setup created by an external script. The script is designed to be "sourced" in the shell, but here its result gets imported into a single Emacs buffer:
(defun my-guile-setup ()
(make-local-variable 'process-environment)
(with-temp-buffer
(call-process "bash" nil t nil "-c"
"source ~/work/guileenv; env | egrep 'GUILE|LD_LIBRARY_PATH'")
(goto-char (point-min))
(while (not (eobp))
(setq process-environment
(cons (buffer-substring (point) (line-end-position))
process-environment))
(forward-line 1))))
(add-hook 'guile-hook 'my-guile-setup)

I put the following in .dir-locals.el at the root of the tree where I want to define some environment vars:
;; variables local to this directory and its children
((nil . ((eval . (setenv "SOME_VARIABLE" "TRUE")))))
This will warn the first time you open a file in that directory tree. After you accept, the given environment var will be defined for each buffer you open there.

One solution would be to temporary change the environment when you spawn an external command. The command will inherit the current environment. Remember that Emacs is a single-treaded application, so we don't have to worry about race conditions etc.
You can pick one of two ways of doing this:
1) Write you own functions like my-compile that changes the environment temporarily and calls the normal compile command.
2) Modify the low-level process functions and ensure that they modify the environment accordingly. Typically, you can do this with defadvice.

It may be possible to use dynamic binding for those variables.
Dynamic binding and Dynamic scoping are a bit hard to explain, for explanations see http://www.emacswiki.org/emacs/DynamicBindingVsLexicalBinding and
http://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping.

Here is an example where I create a local process-environment without necessarily making it buffer-local. The advantage is that the settings only affect the running process and they disappear once the process ends. In this example, I set the timzezone environmental variable and call the function with (funcall my-start-process ....) and everything else is just like start-process in terms of arguments and so forth.
(let* ((my-start-process
(lambda (name buffer program &rest program-args)
(unless (fboundp 'make-process)
(error "Emacs was compiled without subprocess support"))
(let* (
(temp (mapcar 'concat process-environment))
(newenv
(cond
((equal (car (cdr (current-time-zone))) "PDT")
(setenv-internal temp "TZ" "UTC+7" t))
((equal (car (cdr (current-time-zone))) "PST")
(setenv-internal temp "TZ" "UTC+8" t))))
(process-environment (or newenv temp)))
(apply #'make-process
(append (list :name name :buffer buffer)
(when program
(list :command (cons program program-args))))))))
(proc (funcall my-start-process ...))))

Related

Racket-Mode: Can I evaluate a single form within a given namespace at the REPL?

I'm working at the Racket REPL via racket-mode in Emacs, writing code in multiple modules.
Is there a way to execute a single form from a module I'm not currently 'in', in the context of its own module?
For instance:
web.rkt
#lang racket
(require "view.rkt")
(define (display-default-view)
(display (default-view)))
view.rkt
#lang racket
(provide default-view)
(define default-text "Hello")
(define (default-view)
(string-append default-text " world"))
If I call racket-run from web.rkt I get a prompt saying web.rkt>. If I then run (display-default-view) I get "Hello world".
If I then visit view.rkt and change the default-text definition to:
(define default-text "Hi")
and re-evaluate the default-text definition, it evaluates fine, and my prompt still says web.rkt>.
When I enter default-text at the REPL I get "Hi". But when I run (display-default-view) I still get "Hello world". I'm presuming this is because all I've done is define a new default-text in web.rkt.
I'd expect to see output change to "Hi world" --- i.e. the behaviour of the view.rkt module to be updated. Just like I'd see if default-text lived in the web.rkt module.
The idea of dynamically re-evaluating single forms at the repl to change program behaviour is terrific, but it seems to not quite work here.
Is there a way to get this behaving as I would expect in racket-mode? Or if not, a mechanism to just enter a module, without running it, so that I can build something myself to do an enter-execute-exit dance?
Updated, simpler answer:
We can evaluate forms in the REPL in the current file's namespace by entering that namespace in the REPL, evaluating these forms, and then re-entering our original namespace. The easiest way to do this seems to be wrapping these forms with functions to enter the current file's namespace (before) and re-entering the original namespace (after) and then sending all of this into the existing Racket-mode code for evaluating forms in the REPL.
We can do this by building a string of our wrapped commands, writing it to a temporary buffer, marking the whole buffer as our region, and then sending it to racket-send-region.
(defun my-racket-current-namespace-wrapped-commands (buffer-file-string commands)
"generate string containing commands wrapped with Racket functions to enter
the current-namespace and then exit it upon finishing"
(concat "(require (only-in racket/enter enter!))"
"(enter! (file "
buffer-file-string
"))"
commands
"(enter! #f)"))
(defun my-racket--send-wrapped-current-namespace (commands)
"sends wrapped form of commands to racket-send-region function via a temporary buffer"
(let ((buffer-file-string (prin1-to-string buffer-file-name)))
(with-temp-buffer
(insert
(my-racket-current-namespace-wrapped-commands buffer-file-string commands))
(mark-whole-buffer)
(racket-send-region (point-min) (point-max)))))
(defun my-racket-send-region-current-namespace (start end)
"send region to REPL in current namespace"
(interactive "r")
(unless (region-active-p)
(user-error "No region"))
(let ((commands (buffer-substring (region-beginning) (region-end))))
(my-racket--send-wrapped-current-namespace commands)))
(defun my-racket-send-last-sexp-current-namespace ()
"send last sexp to REPL in current namespace"
(interactive)
(let ((commands (buffer-substring (my-racket--repl-last-sexp-start)
(point))))
(my-racket--send-wrapped-current-namespace commands)))
(defun my-racket--repl-last-sexp-start ()
"get start point of last-sexp
permanent (and slightly simplified) copy of racket mode's last-sexp-start private function"
(save-excursion
(progn
(backward-sexp)
(if (save-match-data (looking-at "#;"))
(+ (point) 2)
(point)))))
These functions should mostly be version agnostic - they only depend on racket-send-buffer (which seems likely to remain in future versions).
Edit 1: (Note - this does not seem to work as is for newer versions of Racket-mode. This worked as of the April 01, 2018 release, but newer versions seem to have refactored some of the internals this relied on. In almost all cases, the code above is preferable.)
Sorry, I believe that I originally misunderstood the question. It looks like you mean executing the command straight from view.rkt without having to manually change the namespace in the REPL. I didn't see any built-in functionally in racket-mode that does this, but it's not too hard to write an Elisp wrapper around this process. The following imports in enter!, switches to the current buffer's file's namespace, sends the code in the region, and then switches back to the original namespace. The code used is very similar to what racket-mode uses for racket-send-region and racket-send-last-sexp.
(defun my-racket-send-region-current-namespace (start end)
"Send the current region to the Racket REPL as that namespace"
(interactive "r")
(when (and start end)
(racket-repl t)
(racket--repl-forget-errors)
(let ((proc (racket--get-repl-buffer-process)))
(with-racket-repl-buffer
(save-excursion
(goto-char (process-mark proc))
(insert ?\n)
(set-marker (process-mark proc) (point))))
(comint-send-string proc "(require (only-in racket/enter enter!))")
(comint-send-string proc
(concat "(enter! (file "
(prin1-to-string buffer-file-name)
"))"))
(comint-send-string proc "\n"))
(racket--repl-show-and-move-to-end)
(racket--send-region-to-repl start end)
(let ((proc (racket--get-repl-buffer-process)))
(with-racket-repl-buffer
(save-excursion
(goto-char (process-mark proc))
(insert ?\n)
(set-marker (process-mark proc) (point))))
(comint-send-string proc "(enter! #f)")
(comint-send-string proc "\n"))))
(defun my-racket-send-last-sexp-current-namespace ()
(interactive)
(my-racket-send-region-current-namespace
(save-excursion
(backward-sexp)
(if (save-match-data (looking-at "#;"))
(+ (point) 2)
(point)))
(point)))
Note that if you're using this frequently, this function could probably use more error checking (e.g. the import of require/enter will clobber any previous definition of enter!).
I've also kept the original text below about how to manually switch namespaces in the REPL, in case it helps.
You can use the function enter! in the racket/enter module to switch namespaces to modify definitions in the namespace of the other file.
After calling racket-run in web.rkt, you could do the following in the REPL:
(display-default-view) ;; output is "Hello world"
(require racket/enter)
(enter! "view.rkt") ;; change namespace to view.rkt
(define default-text "Hi")
(enter! #f) ;; return to original namespace
(display-default-view) ;; output is "Hi world"
See the Racket documentation for more details on interactive module loading.

use .dir-locals.el to pick major mode [duplicate]

I have defined a .dir-locals.el file with the following content:
((python-mode . ((cr/virtualenv-name . "saas"))))
In my .emacs I have the following function to retrieve this value and provide a virtualenv path:
(defun cr/virtualenv ()
(cond (cr/virtualenv-name (format "%s/%s" virtualenv-base cr/virtualenv-name))
((getenv "EMACS_VIRTUAL_ENV") (getenv "EMACS_VIRTUAL_ENV"))
(t "~/.emacs.d/python")))
Finally, in my python-mode-hook list, I have this hook function:
(add-hook 'python-mode-hook 'cr/python-mode-shell-setup)
(defun cr/python-mode-shell-setup ()
(message "virtualenv-name is %s" cr/virtualenv-name)
(let ((python-base (cr/virtualenv)))
(cond ((and (fboundp 'ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
(setq python-python-command (concat python-base "/bin/ipython"))
(setq py-python-command (concat python-base "/bin/ipython"))
(setq py-python-command-args '( "-colors" "NoColor")))
(t
(setq python-python-command (concat python-base "/bin/python"))
(setq py-python-command (concat python-base "/bin/python"))
(setq py-python-command-args nil)))))
When I open a new python file, the message logged by cr/python-mode-shell-setup indicates that cr/virtualenv-name is nil. However, when I C-h v the name, I get "saas" instead.
Obviously there's a load order issue here; is there a way to have my mode hook statements respond to directory-local variables?
This happens because normal-mode calls (set-auto-mode) and (hack-local-variables) in that order.
However hack-local-variables-hook is run after the local variables have been processed, which enables some solutions:
The first is to make Emacs run a new "local variables hook" for each major mode:
(add-hook 'hack-local-variables-hook 'run-local-vars-mode-hook)
(defun run-local-vars-mode-hook ()
"Run a hook for the major-mode after the local variables have been processed."
(run-hooks (intern (concat (symbol-name major-mode) "-local-vars-hook"))))
(add-hook 'python-mode-local-vars-hook 'cr/python-mode-shell-setup)
(Your original function can be used unmodified, with that approach.)
A second option is to utilise the optional LOCAL argument to add-hook that makes the specified function buffer-local. With this approach you could write your hook as follows:
(add-hook 'python-mode-hook 'cr/python-mode-shell-setup)
(defun cr/python-mode-shell-setup ()
(add-hook 'hack-local-variables-hook
(lambda () (message "virtualenv-name is %s" cr/virtualenv-name)
(let ((python-base (cr/virtualenv)))
(cond ((and (fboundp 'ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
(setq python-python-command (concat python-base "/bin/ipython"))
(setq py-python-command (concat python-base "/bin/ipython"))
(setq py-python-command-args '( "-colors" "NoColor")))
(t
(setq python-python-command (concat python-base "/bin/python"))
(setq py-python-command (concat python-base "/bin/python"))
(setq py-python-command-args nil)))))
nil t)) ; buffer-local hack-local-variables-hook
i.e. python-mode-hook runs first and registers the anonymous function with hack-local-variables-hook for the current buffer only; and that function is then called after the local variables have been processed.
Lindydancer's comment prompts a third approach. It's not nearly as clean as the other two, but proved interesting regardless. I didn't like the idea of causing (hack-local-variables) to be called twice, but I see that if you set the local-enable-local-variables buffer-locally, it prevents (hack-local-variables) from doing anything, so you could do this:
(defun cr/python-mode-shell-setup ()
(report-errors "File local-variables error: %s"
(hack-local-variables)))
(set (make-local-variable 'local-enable-local-variables) nil)
(let ((python-base (cr/virtualenv)))
...))
Obviously that modifies the normal sequence of execution a little, so side effects may be possible. I was worried that if the same major mode is set by a local variable comment in the file, this might cause infinite recursion, but that doesn't actually appear to be a problem.
Local variable header comments (e.g. -*- mode: foo -*-) are handled by (set-auto-mode), so those are fine; but a mode: foo Local Variables: comment seems like it would be an issue as it is handled by (hack-local-variables), and so if the mode is set that way I thought it would cause recursion.
In practice I was able to trigger the problem by using a simple function as a 'mode' which did nothing more than try to run its hooks; however testing with a 'proper' mode did not exhibit the problem, so it's probably safe in reality. I didn't look into this further (as the other two solutions are much cleaner than this), but I would guess the delayed mode hooks mechanism probably explains it?

Listing all top level global variables in emacs

Mostly for my own edification I'm trying to list all of the global variables loaded in the current Emacs session. What I was thinking about doing is producing an HTML file with all of the functions listed. Of course, what would also be useful is the file where the function, var, etc was defined.
Is there anything already built into emacs to help?
L-
Something along these lines should do:
(let ((result '()))
(mapatoms (lambda (x)
(when (boundp x)
(let ((file (ignore-errors
(find-lisp-object-file-name x 'defvar))))
(when file
(push (cons x file) result))))))
result)
Warning: it takes a long time to finish.

Emacs/Emacs Lisp: can I insert advice before interactive form? or how to intelligently pre-set the compile-command?

What I'd like to do is intelligently pre-set a buffer-local default value for the string argument to the compile function.
Right now compile.el defaults to using "make" as the command. I can set this by setting compile-command. I can even make that variable buffer-local. That works if I want the same static value, always.
But I'd like to intelligently select the compile-command depending on the contents of the buffer, the name of the buffer, the contents of the containing directory of the file (if any), and the phase of the moon. Basically I want control over the default value, and then allow the interactive user to override that pre-set value.
I was hoping to do this with before-advice. But this isn't working as I expected.
Reading the advice.el file, I see
Suppose a function/macro/subr/special-form has N pieces of before advice, M pieces of around advice and K pieces of after advice. Assuming none of the advices is protected, its advised definition will look like this (body-form indices correspond to the position of the respective advice in that advice class):
([macro] lambda <arglist>
[ [<advised-docstring>] [(interactive ...)] ]
(let (ad-return-value)
{<before-0-body-form>}*
....
{<before-N-1-body-form>}*
{<around-0-body-form>}*
{<around-1-body-form>}*
....
{<around-M-1-body-form>}*
(setq ad-return-value
<apply original definition to <arglist>>)
{<other-around-M-1-body-form>}*
....
{<other-around-1-body-form>}*
{<other-around-0-body-form>}*
{<after-0-body-form>}*
....
{<after-K-1-body-form>}*
ad-return-value))
What this says to me is that when the advised function is interactive, `call-interactively' invokes the interactive form before invoking the before advice, or any advice.
And, when I add advice to compile, the behavior I observe confirms this. The advice gets invoked after the interactive form is processed. The interactive form suggests the string to use for compilation, before my advice gets a chance to guess at what it should be, and to pre-set it.
So...
how can I get my code to run before the interactive form? can advice do this? If not advice, something else? or
how can I dynamically pre-set compile-command for any buffer?
Ideas appreciated.
One option is to set the variable compile-command in a mode hook, something like
(add-hook 'c++-mode-hook 'my-c++-set-compile-command)
(defun my-c++-set-compile-command ()
(setq (make-local-variable 'compile-command) (format "gmake %s" (buffer-file-name))))
I've sometimes added specialized commands to tweak the current compile line (turn on/off debug flags, optimization flags, etc.), and then bind those commands to convenient keystrokes in the mini-buffer.
Regarding adding advice before the interactive form, you need to make advice (either before or around) which has an interactive form that you want. From the advice.el library, an example:
;;(defadvice switch-to-buffer (around confirm-non-existing-buffers activate)
;; "Switch to non-existing buffers only upon confirmation."
;; (interactive "BSwitch to buffer: ")
;; (if (or (get-buffer (ad-get-arg 0))
;; (y-or-n-p (format "`%s' does not exist, create? " (ad-get-arg 0))))
;; ad-do-it))
compile-command doesn't have to be a string. The compile function evals it, so it can be a function that returns a string that's specific to the buffer or that depends on the time of day, etc:
(setq compile-command (lambda () (if (eq phase-of-moon 'waning)
"make -DWANING=1"
"make -DWANING=0")))
Also, though not probably not useful for your specific needs, you can always define compile-command in a file variable section:
/* -*- compile-command: "make -DFOO"; -*- */
or
// Local Variables:
// compile-command: "make -DSOMETHING_SPECIAL"
// End:
compile-command is actually used as an example of a file variable in the manual.
Ahh, you know what I did? I used an oblique strategy.
I have globally set C-xC-e to compile. Instead of using advice, I defined a function that wraps compile, and then bound C-xC-e to that. Within the wrapper, I make the guess for the compile command.
(defun cheeso-invoke-compile-interactively ()
"fn to wrap the `compile' function. This simply
checks to see if `compile-command' has been previously guessed, and
if not, invokes `cheeso-guess-compile-command' to set the value.
Then it invokes the `compile' function, interactively."
(interactive)
(cond
((not (boundp 'cheeso-local-compile-command-has-been-set))
(cheeso-guess-compile-command)
(set (make-local-variable 'cheeso-local-compile-command-has-been-set) t)))
;; local compile command has now been set
(call-interactively 'compile))
And the guess function is like this:
(defun cheeso-guess-compile-command ()
"set `compile-command' intelligently depending on the
current buffer, or the contents of the current directory."
(interactive)
(set (make-local-variable 'compile-command)
(cond
((or (file-expand-wildcards "*.csproj" t)
(file-expand-wildcards "*.vcproj" t)
(file-expand-wildcards "*.vbproj" t)
(file-expand-wildcards "*.shfbproj" t)
(file-expand-wildcards "*.sln" t))
"msbuild ")
;; sometimes, not sure why, the buffer-file-name is
;; not set. Can use it only if set.
(buffer-file-name
(let ((filename (file-name-nondirectory buffer-file-name)))
(cond
;; editing a .wxs (WIX Soluition) file
((string-equal (substring buffer-file-name -4) ".wxs")
(concat "nmake "
;; (substring buffer-file-name 0 -4) ;; includes full path
(file-name-sans-extension filename)
".msi" ))
;; a javascript file - run jslint
((string-equal (substring buffer-file-name -3) ".js")
(concat (getenv "windir")
"\\system32\\cscript.exe c:\\cheeso\\bin\\jslint-for-wsh.js "
filename))
;; something else - do a typical .exe build
(t
(concat "nmake "
(file-name-sans-extension filename)
".exe")))))
(t
"nmake "))))
Here is some code I am using that intelligently selects the compile command courtesy of the University of Wyoming. I currently have it set up for C, C++, and Fortran. You can add more to suit your needs. If I open a programming that has a C++ extension and I execute M-xcompile, my compile command spits out g++ -Wall currentfilename.cpp -o currentfilename -std=c++14. I then just have to hit enter.
;; M-x compile smarter in order to guess language
(require 'compile)
(defvar compile-guess-command-table
'((c-mode . "gcc -Wall -g %s -o %s -lm")
(c++-mode . "g++ -Wall %s -o %s -std=c++14")
(fortran-mode . "gfortran -C %s -o %s")
))
(defun compile-guess-command ()
(let ((command-for-mode (cdr (assq major-mode
compile-guess-command-table))))
(if (and command-for-mode
(stringp buffer-file-name))
(let* ((file-name (file-name-nondirectory buffer-file-name))
(file-name-sans-suffix (if (and (string-match "\\.[^.]*\\'"
file-name)
(> (match-beginning 0) 0))
(substring file-name
0 (match-beginning 0))
nil)))
(if file-name-sans-suffix
(progn
(make-local-variable 'compile-command)
(setq compile-command
(if (stringp command-for-mode)
;; Optimize the common case.
(format command-for-mode
file-name file-name-sans-suffix)
(funcall command-for-mode
file-name file-name-sans-suffix)))
compile-command)
nil))
nil)))
;; Add the appropriate mode hooks.
(add-hook 'c-mode-hook (function compile-guess-command))
(add-hook 'c++-mode-hook (function compile-guess-command))
(add-hook 'fortran-mode-hook (function compile-guess-command))
According to the manual, you can simply override the interactive form of a function with your own by including an interactive form in your advice. I don't think you can modify or wrap the existing interactive form, only override it completely.
http://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Advice.html

Emacs custom command line argument

From the documentation I can see I can access command line arguments (command-line-args).
I'd like to add my own arguments but Emacs complains at start up that it doesn't recognize them.
E.g.
emacs -my_argument
I get:
command-line-1: Unknown option `-my_argument'
What's a proper way to define my custom arguments and provide information to my Emacs session?
Is there a way to pop an argument from a command line?
Add something like this to your ~/.emacs, ~/.emacs.el, or ~/.emacs.d/init.el file:
(defun my-argument-fn (switch)
(message "i was passed -my_argument"))
(add-to-list 'command-switch-alist '("-my_argument" . my-argument-fn))
Then you can execute emacs -my_argument and it should print i was passed -my_argument to the minibuffer. You can find more information in the GNU elisp reference.
As stated in another post you can add your custom switches to command-switch-alist and emacs will call the handler function for any matching switch passed in on the command line. However, this operation is done after your .emacs file has been evaluated. This is fine for most cases but you may wish for a command line argument to alter the execution path or behaviour of your .emacs evaluation; I often do this to enable/disable configuration chunks (mainly for debugging).
To achieve this you can read command-line-args and check for your switch manually and then delete it from the list, this will stop emacs complaining about an unknown argument.
(setq my-switch-found (member "-myswitch" command-line-args))
(setq command-line-args (delete "-myswitch" command-line-args))
Which can alter your .emacs evaluation like so:
(unless my-switch-found
(message "Didn't find inhibit switch, loading some config.")
...)
And you could build this into a single step:
;; This was written in SO text-box, not been tested.
(defun found-custom-arg (switch)
(let ((found-switch (member switch command-line-args)))
(setq command-line-args (delete switch command-line-args))
found-switch))
(unless (found-custom-arg "-myswitch")
(message "Loading config...")
...)
For those who are interested, here is a code snip to show how to process custom arguments in Emacs lisp. In this case, I am processing an argument --suffix / -S to variable _suffix.
I pulled the idea from a BSD-Lite Script Emacs script.
(setq _suffix nil)
;; Process cli args
(while command-line-args-left
(setq k (car command-line-args-left))
(setq command-line-args-left (cdr command-line-args-left))
(setq command-line-args (delete k command-line-args))
(cond
(or (string-equal k "--cs-suffix")
(string-equal k "-S"))
(setq _suffix (intern (car command-line-args-left)))
(setq command-line-args-left (cdr command-line-args-left))
(setq command-line-args (delete _suffix command-line-args))
)))
This will roll through command-line-args-left and remove them all from command-line-args which will prevent Emacs from complaining.