From be0b3fd58ff60c0ddb7e550965d61d086ac7d10a Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 2 Apr 2026 09:47:18 +0300 Subject: [PATCH 1/2] fix: unload environment when changing to diriectory without `.envrc` Signed-off-by: NotAShelf Change-Id: I58ab61782a24f87a81d007a49aca1f1d6a6a6964 --- lua/direnv.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lua/direnv.lua b/lua/direnv.lua index 8e1b6a1..6c75379 100644 --- a/lua/direnv.lua +++ b/lua/direnv.lua @@ -23,6 +23,9 @@ local cache = { pending_request = false, } +local direnv_env = {} +local unload_pending = false + local notification_queue = {} local pending_callbacks = {} @@ -215,6 +218,25 @@ M.refresh_status = function() M._get_rc_status(function() end) end +--- Unload direnv environment by clearing tracked variables +M._unload = function() + if next(direnv_env) == nil then + return + end + + unload_pending = true + vim.schedule(function() + if unload_pending then + for key, _ in pairs(direnv_env) do + vim.env[key] = nil + end + direnv_env = {} + unload_pending = false + notify("direnv environment unloaded", vim.log.levels.DEBUG) + end + end) +end + --- Initialize direnv for current directory --- @param path string Path to .envrc file M._init = function(path) @@ -258,6 +280,9 @@ M._init = function(path) return end + unload_pending = false + direnv_env = {} + for key, value in pairs(env) do if value == vim.NIL or value == nil then vim.env[key] = nil @@ -266,6 +291,7 @@ M._init = function(path) value = tostring(value) end vim.env[key] = value + direnv_env[key] = true end end @@ -421,6 +447,7 @@ end M.check_direnv = function() local on_exit = function(status, path) if status == nil or path == nil then + M._unload() return end From be64c2efb7f416376440f644fedfa0c2dcd15ddb Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 13 May 2026 11:29:44 +0300 Subject: [PATCH 2/2] fix: defer to direnv for env tracking Signed-off-by: NotAShelf Change-Id: I6e8b1291ee589ab2f398f24dd7bad1966a6a6964 --- lua/direnv.lua | 54 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/lua/direnv.lua b/lua/direnv.lua index 6c75379..a192bdd 100644 --- a/lua/direnv.lua +++ b/lua/direnv.lua @@ -23,9 +23,6 @@ local cache = { pending_request = false, } -local direnv_env = {} -local unload_pending = false - local notification_queue = {} local pending_callbacks = {} @@ -218,23 +215,48 @@ M.refresh_status = function() M._get_rc_status(function() end) end ---- Unload direnv environment by clearing tracked variables +--- Unload direnv environment by running direnv export in the current directory. +--- direnv handles proper env restoration (including $PATH), unlike manual tracking. M._unload = function() - if next(direnv_env) == nil then + local cwd = get_cwd() + if not cwd then return end - unload_pending = true - vim.schedule(function() - if unload_pending then - for key, _ in pairs(direnv_env) do - vim.env[key] = nil + vim.system( + { M.config.bin, "export", "json" }, + { text = true, cwd = cwd }, + function(obj) + if obj.code ~= 0 then + return end - direnv_env = {} - unload_pending = false - notify("direnv environment unloaded", vim.log.levels.DEBUG) + + vim.schedule(function() + local stdout = obj.stdout or "" + if stdout == "" then + return + end + + local ok, env = pcall(vim.json.decode, stdout) + if not ok or type(env) ~= "table" then + return + end + + for key, value in pairs(env) do + if value == vim.NIL or value == nil then + vim.env[key] = nil + else + if type(value) ~= "string" then + value = tostring(value) + end + vim.env[key] = value + end + end + + notify("direnv environment unloaded", vim.log.levels.DEBUG) + end) end - end) + ) end --- Initialize direnv for current directory @@ -280,9 +302,6 @@ M._init = function(path) return end - unload_pending = false - direnv_env = {} - for key, value in pairs(env) do if value == vim.NIL or value == nil then vim.env[key] = nil @@ -291,7 +310,6 @@ M._init = function(path) value = tostring(value) end vim.env[key] = value - direnv_env[key] = true end end