Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Variable Management in Hurl.nvim #228

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 71 additions & 27 deletions lua/hurl/main.lua
Original file line number Diff line number Diff line change
@@ -245,61 +245,105 @@ function M.setup()

-- Show all global variables
utils.create_cmd('HurlManageVariable', function()
-- Prepare the lines to display in the popup
-- Load persisted variables
local persisted_vars = utils.load_persisted_vars()

-- Load variables from env files
local env_vars = {}
local env_files = _HURL_GLOBAL_CONFIG.find_env_files_in_folders()
for _, env in ipairs(env_files) do
if vim.fn.filereadable(env.path) == 1 then
local vars = utils.parse_env_file(env.path)
for k, v in pairs(vars) do
env_vars[k] = v
end
end
end

-- Merge variables, with persisted taking precedence
local all_vars = vim.tbl_deep_extend('force', env_vars, persisted_vars)
_HURL_GLOBAL_CONFIG.global_vars = all_vars

-- Prepare display lines
local lines = {}
if not _HURL_GLOBAL_CONFIG.global_vars or vim.tbl_isempty(_HURL_GLOBAL_CONFIG.global_vars) then
utils.log_info('hurl: no global variables set')
utils.notify('hurl: no global variables set', vim.log.levels.INFO)
table.insert(lines, 'No global variables set. Please use :HurlSetVariable to set one.')
if vim.tbl_isempty(all_vars) then
table.insert(lines, 'No variables set. Press "n" to create a new variable.')
else
for var_name, var_value in pairs(_HURL_GLOBAL_CONFIG.global_vars) do
table.insert(lines, var_name .. ' = ' .. var_value)
-- Add env file variables
for name, value in pairs(env_vars) do
table.insert(lines, name .. ' = ' .. value .. ' (from env)')
end
-- Add persisted variables
for name, value in pairs(persisted_vars) do
if not env_vars[name] then
table.insert(lines, name .. ' = ' .. value)
end
end
table.sort(lines)
end

local popup = require('hurl.popup')
local text_popup = popup.show_text(
'Hurl.nvim - Global variables',
'Hurl.nvim - Variables',
lines,
"Press 'q' to close, 'e' to edit, or 'n' to create a variable."
"Press 'q' to close, 'e' to edit, 'n' to create, or 'd' to delete"
)

-- Add e key binding to edit the variable
-- Edit variable
text_popup:map('n', 'e', function()
local line = vim.api.nvim_get_current_line()
local var_name = line:match('^(.-) =')
local var_name = line:match('^([^=]+)=')
if var_name then
var_name = var_name:gsub('%s*$', '')
local new_value = vim.fn.input('Enter new value for ' .. var_name .. ': ')
_HURL_GLOBAL_CONFIG.global_vars[var_name] = new_value
vim.api.nvim_set_current_line(var_name .. ' = ' .. new_value)
if new_value ~= '' then
persisted_vars[var_name] = new_value
_HURL_GLOBAL_CONFIG.global_vars[var_name] = new_value
utils.save_persisted_vars(persisted_vars)
vim.api.nvim_set_current_line(var_name .. ' = ' .. new_value)
end
end
end)

-- Add 'n' to create new variable
-- Create new variable
text_popup:map('n', 'n', function()
local var_name = vim.fn.input('Enter new variable name: ')
if not var_name or var_name == '' then
utils.notify('hurl: variable name cannot be empty', vim.log.levels.INFO)
if var_name == '' then
utils.notify('Variable name cannot be empty', vim.log.levels.WARN)
return
end

local var_value = vim.fn.input('Enter new variable value: ')
if not var_value or var_value == '' then
utils.notify('hurl: variable value cannot be empty', vim.log.levels.INFO)
local var_value = vim.fn.input('Enter variable value: ')
if var_value == '' then
utils.notify('Variable value cannot be empty', vim.log.levels.WARN)
return
end

local line_position = -1
local first_line = vim.api.nvim_buf_get_lines(0, 0, 1, false)
if first_line[1] == 'No global variables set. Please use :HurlSetVariable to set one.' then
-- Clear the buffer if it's empty
line_position = 0
end
persisted_vars[var_name] = var_value
_HURL_GLOBAL_CONFIG.global_vars[var_name] = var_value
utils.save_persisted_vars(persisted_vars)

vim.cmd('HurlSetVariable ' .. var_name .. ' ' .. var_value)
-- Append to the last line
-- Update display
local line_position = vim.tbl_isempty(all_vars) and 0 or -1
vim.api.nvim_buf_set_lines(0, line_position, -1, false, { var_name .. ' = ' .. var_value })
end)

-- Delete variable
text_popup:map('n', 'd', function()
local line = vim.api.nvim_get_current_line()
local var_name = line:match('^([^=]+)=')
if var_name then
var_name = var_name:gsub('%s*$', '')
if env_vars[var_name] then
utils.notify('Cannot delete variable from env file', vim.log.levels.WARN)
return
end
persisted_vars[var_name] = nil
_HURL_GLOBAL_CONFIG.global_vars[var_name] = nil
utils.save_persisted_vars(persisted_vars)
vim.api.nvim_buf_set_lines(0, vim.fn.line('.') - 1, vim.fn.line('.'), false, {})
end
end)
end, {
nargs = '*',
range = true,
74 changes: 74 additions & 0 deletions lua/hurl/utils.lua
Original file line number Diff line number Diff line change
@@ -275,4 +275,78 @@ M.has_file_in_opts = function(opts)
return false
end

--- Parse env file content into variables
---@param file_path string
---@return table
M.parse_env_file = function(file_path)
local vars = {}
local file = io.open(file_path, 'r')
if not file then
return vars
end

for line in file:lines() do
-- Skip comments and empty lines
if not line:match('^%s*#') and line:match('%S') then
local name, value = line:match('([^=]+)=(.+)')
if name and value then
name = name:gsub('^%s*(.-)%s*$', '%1')
value = value:gsub('^%s*(.-)%s*$', '%1')
vars[name] = value
end
end
end
file:close()
return vars
end

--- Get persistent storage path
---@return string
M.get_storage_path = function()
local data_path = vim.fn.stdpath('data')
local hurl_path = data_path .. '/hurl-nvim'
if vim.fn.isdirectory(hurl_path) == 0 then
vim.fn.mkdir(hurl_path, 'p')
end
return hurl_path .. '/variables.json'
end

--- Load persisted variables
---@return table
M.load_persisted_vars = function()
local file_path = M.get_storage_path()
local file = io.open(file_path, 'r')
if not file then
return {}
end

local content = file:read('*all')
file:close()

local ok, vars = pcall(vim.json.decode, content)
return ok and vars or {}
end

--- Save variables to persistent storage
---@param vars table
M.save_persisted_vars = function(vars)
local file_path = M.get_storage_path()
local file = io.open(file_path, 'w')
if not file then
M.log_error('Failed to open storage file for writing: ' .. file_path)
return false
end

local ok, content = pcall(vim.json.encode, vars)
if not ok then
M.log_error('Failed to encode variables to JSON')
file:close()
return false
end

file:write(content)
file:close()
return true
end

return M
53 changes: 53 additions & 0 deletions test/plugin_spec.lua
Original file line number Diff line number Diff line change
@@ -17,3 +17,56 @@ describe('Hurl.nvim plugin', function()
assert.are.same(true, _HURL_GLOBAL_CONFIG.debug)
end)
end)

describe('Variable Management', function()
local utils = require('hurl.utils')

before_each(function()
-- Clear persisted variables
utils.save_persisted_vars({})
-- Reset global vars
_HURL_GLOBAL_CONFIG.global_vars = {}
end)

it('should load variables from env file', function()
-- Create test env file
local test_env = vim.fn.tempname()
local f = io.open(test_env, 'w')
f:write('TEST_VAR=test_value\n')
f:close()

local vars = utils.parse_env_file(test_env)
assert.are.same({ TEST_VAR = 'test_value' }, vars)
os.remove(test_env)
end)

it('should persist variables between sessions', function()
local test_vars = { test_var = 'test_value' }
assert.is_true(utils.save_persisted_vars(test_vars))

local loaded_vars = utils.load_persisted_vars()
assert.are.same(test_vars, loaded_vars)
end)

it('should merge env and persisted variables', function()
-- Create test env file
local test_env = vim.fn.tempname()
local f = io.open(test_env, 'w')
f:write('ENV_VAR=env_value\n')
f:close()

-- Add persisted variable
utils.save_persisted_vars({ PERS_VAR = 'pers_value' })

local env_vars = utils.parse_env_file(test_env)
local pers_vars = utils.load_persisted_vars()

local merged = vim.tbl_deep_extend('force', env_vars, pers_vars)
assert.are.same({
ENV_VAR = 'env_value',
PERS_VAR = 'pers_value',
}, merged)

os.remove(test_env)
end)
end)