1

Problem

I'm using Emacs with projectile and vterm for my development workflow. I've configured vterm to use screen as its shell:

(setq vterm-shell "screen") 

I've created a function that opens a vterm terminal in my project root:

(defun open-terminal-in-project-root () (interactive) (let* ((project-root (projectile-project-root)) (buffer-name (format "*terminal-%s*" (projectile-project-name))) (existing-buffer (get-buffer buffer-name))) (if existing-buffer (pop-to-buffer existing-buffer) (let ((default-directory project-root)) (vterm) (rename-buffer buffer-name t))))) 

When I navigate away from the project root in the terminal, I'd like to be able to quickly return. My plan is to set a PROJECTILE_ROOT environment variable when the terminal starts, which I could then use in a shell function to return to that directory.

What I've tried

I've attempted to set the environment variable using:

(vterm-send-string (format "export PROJECTILE_ROOT=\"%s\"\n" project-root)) 

But this doesn't seem to work with screen as the shell. When I check with env | grep PROJECTILE, the variable isn't set.

Question

How can I reliably set an environment variable in a vterm terminal that's running screen in Emacs? Is there a special approach needed for the screen+vterm combination?

EDIT:

Thank you for the helpful explanation. I tried using vterm-environment as suggested:

(defun open-terminal-in-project-root () (interactive) (let* ((project-root (projectile-project-root)) (buffer-name (format "*terminal-%s*" (projectile-project-name))) (existing-buffer (get-buffer buffer-name))) (if existing-buffer (pop-to-buffer existing-buffer) (let ((default-directory project-root) (vterm-environment (list (format "PROJECTILE_ROOT=%s" project-root)))) (vterm) (rename-buffer buffer-name t))))) 

I confirmed that vterm-environment works correctly when I use bash directly - the variable appears when checking with env | grep PROJECTILE_ROOT.

However, I realized the issue is with my vterm-shell configuration. I have:

(setq vterm-shell "screen") 

The environment variable is being passed to screen itself rather than the shell inside screen.

So the core issue appears to be: How can I pass environment variables to the shell inside screen when using vterm?

I'm considering using a wrapper script approach like:

#!/bin/bash PROJECT_ROOT="$1" export PROJECTILE_ROOT="$PROJECT_ROOT" exec screen "${@:2}" 

And then setting:

(vterm-shell (format "~/bin/vterm-screen-wrapper.sh %s" (shell-quote-argument project-root))) 

Is this the right approach for this situation? Are there any pitfalls I should be aware of?

1 Answer 1

1

You misunderstand how environment variables work. When one process (the parent) executes another (the child), the child process inherits all of its environment variables from the parent. (The parent can either allow its own variables to be copied to the child, or compose a new list of variables to be given to the child.) Once the child is running it owns and manages its own variables. There’s generally no way to set them from the outside.

Obviously what you want to do is set the variable before vterm runs any child processes.

A quick look at the vterm package finds a variable called vterm-environment. You could set that variable before calling vterm. For example:

(defun my-vterm () (interactive) (let ((vterm-environment '("FOO=bar"))) (vterm))) 

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.