[Перевод] Как можно потерять контроль над оболочкой
Пару недель назад я разбирался с поддержкой Language Server в редакторе Zed, пытаясь заставить его, обнаруживать исполняемый файл языкового сервера gopls в $PATH. В случае его присутствия система должна использовать этот файл, а не скачивать новый.
Проблема: $PATH часто динамически изменяется такими инструментами, как direnv, asdf, mise и прочими, которые позволяют устанавливать конкретный $PATH в заданном каталоге. (Зачем они это делают? Потому что это даёт вам возможность, например, добавить в начало $PATH путь ./my_custom_binaries, когда вы находитесь в my-cool-project). В итоге мы не можем просто использовать $PATH, связанный с процессом Zed. Нам нужен $PATH в том виде, в каком он представлен, когда мы переходим с помощью cd в каталог проекта.
Легко, подумал я. Нужно просто запустить $SHELL, перейти с помощью cd в проект для активации direnv или аналогичного инструмента, выполнить env, сохранить среду, извлечь $PATH и найти в нём исполняемые файлы.
Легко и получилось. Вот часть кода, которая запускает $SHELL, выполняет cd и получает env:
fn load_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {
// Получаем $SHELL
let shell = std::env::var(«SHELL»)?;
// Создаём команду, которую должна выполнить $SHELL
let command = format!(«cd {:?}; /usr/bin/env -0;», dir);
// Запускаем $SHELL в качестве интерактивной оболочки (чтобы использовались файлы rc пользователя)
// и выполняем `command`:
let output = std::process::Command::new(&shell)
.args([«-i», «-c», &command])
.output()?;
// [… проверка кода выхода, получение stdout, преобразование stdout в HashMap и так далее. …]
}
За исключением одного: после запуска в терминале экземпляра Zed, который выполнял эту функцию, я больше не смог закрыть Zed нажатием Ctrl-C.
Что? Читать дальше →