Skip to content

Commit

Permalink
feat: allow selecting of env files with command
Browse files Browse the repository at this point in the history
feat: running a response script to set env
  • Loading branch information
D-James-GH authored and teto committed Jan 4, 2023
1 parent f94c795 commit 090e253
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 30 deletions.
38 changes: 38 additions & 0 deletions doc/rest-nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ FEATURES *rest-nvim-features*
- Run request under cursor
- Syntax highlight for http files and output
- Possibility of using environment variables in http files
- Set environment variables based on the response


===============================================================================
Expand Down Expand Up @@ -118,6 +119,9 @@ COMMANDS *rest-nvim-usage-commands*
Same as `RestNvim` but it returns the cURL command without executing the
request. Intended for debugging purposes.

- `:RestSelectEnv path/to/env`
Set the path to an env file.


===============================================================================
REQUESTS *rest-nvim-usage-requests*
Expand Down Expand Up @@ -151,6 +155,40 @@ These environment variables can be obtained from:
- File in the current working directory (env_file in config or '.env')
- System

Environment variables can be set in .env format or in json.

To change the environment for the session use :RestSelectEnv path/to/environment

Environment variables can be set dynamically from the response body.
(see rest-nvim-usage-dynamic-variables)


===============================================================================
RESPONSE SCRIPT *rest-nvim-response-script*

A lua script can be run after a request has completed. This script must below
the body and wrapped in {% script %}. A context table is avaliable in the
response script. The context table can be used to read the response and set
environment variables.

The context table:
`{`
` result = res,`
` pretty_print = vim.pretty_print,`
` json_decode = vim.fn.json_decode,`
` set_env = utils.set_env,`
`}`

Now environment variables can be set like so:

`GET https://jsonplaceholder.typicode.com/posts/3`
` `
`{%`
` `
`local body = context.json_decode(context.result.body)`
`context.set_env("postId", body.id)`
` `
`%}`

===============================================================================
DYNAMIC VARIABLES *rest-nvim-usage-dynamic-variables*
Expand Down
1 change: 1 addition & 0 deletions doc/tags
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ rest-nvim-intro rest-nvim.txt /*rest-nvim-intro*
rest-nvim-issues rest-nvim.txt /*rest-nvim-issues*
rest-nvim-license rest-nvim.txt /*rest-nvim-license*
rest-nvim-quick-start rest-nvim.txt /*rest-nvim-quick-start*
rest-nvim-response-script rest-nvim.txt /*rest-nvim-response-script*
rest-nvim-usage rest-nvim.txt /*rest-nvim-usage*
rest-nvim-usage-commands rest-nvim.txt /*rest-nvim-usage-commands*
rest-nvim-usage-dynamic-variables rest-nvim.txt /*rest-nvim-usage-dynamic-variables*
Expand Down
19 changes: 17 additions & 2 deletions lua/rest-nvim/curl/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ M.get_or_create_buf = function()
return new_bufnr
end

local function create_callback(method, url)
local function create_callback(method, url, script_str)
return function(res)
if res.exit ~= 0 then
log.error("[rest.nvim] " .. utils.curl_error(res.exit))
Expand All @@ -68,6 +68,21 @@ local function create_callback(method, url)
end
end

if script_str ~= nil then
local context = {
result = res,
pretty_print = vim.pretty_print,
json_decode = vim.fn.json_decode,
set_env = utils.set_env,
}
local env = { context = context }
setmetatable(env, { __index = _G })
local f = load(script_str, nil, "bt", env)
if f ~= nil then
f()
end
end

if config.get("result").show_url then
--- Add metadata into the created buffer (status code, date, etc)
-- Request statement (METHOD URL)
Expand Down Expand Up @@ -212,7 +227,7 @@ M.curl_cmd = function(opts)
vim.api.nvim_echo({ { "[rest.nvim] Request preview:\n", "Comment" }, { curl_cmd } }, false, {})
return
else
opts.callback = vim.schedule_wrap(create_callback(opts.method, opts.url))
opts.callback = vim.schedule_wrap(create_callback(opts.method, opts.url, opts.script_str))
curl[opts.method](opts)
end
end
Expand Down
14 changes: 12 additions & 2 deletions lua/rest-nvim/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ end
rest.run_request = function(req, opts)
local result = req
opts = vim.tbl_deep_extend(
"force", -- use value from rightmost map
{verbose = false}, -- defaults
"force", -- use value from rightmost map
{ verbose = false }, -- defaults
opts or {}
)

Expand All @@ -74,6 +74,7 @@ rest.run_request = function(req, opts)
bufnr = result.bufnr,
start_line = result.start_line,
end_line = result.end_line,
script_str = result.script_str,
}

if not opts.verbose then
Expand Down Expand Up @@ -118,4 +119,13 @@ end

rest.request = request

rest.select_env = function(path)
if path ~= nil then
vim.validate({ path = { path, "string" } })
config.set({ env_file = path })
else
print("No path given")
end
end

return rest
73 changes: 58 additions & 15 deletions lua/rest-nvim/request/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ local function get_importfile_name(bufnr, start_line, stop_line)
local fileimport_spliced
fileimport_line = vim.api.nvim_buf_get_lines(bufnr, import_line - 1, import_line, false)
fileimport_string =
string.gsub(fileimport_line[1], "<", "", 1):gsub("^%s+", ""):gsub("%s+$", "")
string.gsub(fileimport_line[1], "<", "", 1):gsub("^%s+", ""):gsub("%s+$", "")
fileimport_spliced = utils.replace_vars(fileimport_string)
if path:new(fileimport_spliced):is_absolute() then
return fileimport_spliced
Expand Down Expand Up @@ -56,14 +56,19 @@ local function get_body(bufnr, start_line, stop_line, has_json)
end

local body = ""
local vars = utils.read_variables()
-- nvim_buf_get_lines is zero based and end-exclusive
-- but start_line and stop_line are one-based and inclusive
-- magically, this fits :-) start_line is the CRLF between header and body
-- which should not be included in the body, stop_line is the last line of the body
for _, line in ipairs(lines) do
-- stop if a script opening tag is found
if line:find("{%%") then
break
end
-- Ignore commented lines with and without indent
if not utils.contains_comments(line) then
body = body .. utils.replace_vars(line)
body = body .. utils.replace_vars(line, vars)
end
end

Expand All @@ -80,13 +85,46 @@ local function get_body(bufnr, start_line, stop_line, has_json)
json_body[key] = vim.fn.json_encode(val)
end
end
return json_body
return vim.fn.json_encode(json_body)
end
end


return body
end

local function get_response_script(bufnr, start_line, stop_line)
local all_lines = vim.api.nvim_buf_get_lines(bufnr, start_line, stop_line, false)
-- Check if there is a script
local script_start_rel
for i, line in ipairs(all_lines) do
-- stop if a script opening tag is found
if line:find("{%%") then
script_start_rel = i
break
end
end

if script_start_rel == nil then
return nil
end

-- Convert the relative script line number to the line number of the buffer
local script_start = start_line + script_start_rel - 1

local script_lines = vim.api.nvim_buf_get_lines(bufnr, script_start, stop_line, false)
local script_str = ""

for _, line in ipairs(script_lines) do
script_str = script_str .. line .. "\n"
if line:find("%%}") then
break
end
end

return script_str:match("{%%(.-)%%}")
end

-- is_request_line checks if the given line is a http request line according to RFC 2616
local function is_request_line(line)
local http_methods = { "GET", "POST", "PUT", "PATCH", "DELETE" }
Expand Down Expand Up @@ -202,7 +240,8 @@ local function end_request(bufnr, linenumber)
end
utils.move_cursor(bufnr, linenumber)

local next = vim.fn.search("^GET\\|^POST\\|^PUT\\|^PATCH\\|^DELETE", "cn", vim.fn.line("$"))
local next = vim.fn.search("^GET\\|^POST\\|^PUT\\|^PATCH\\|^DELETE\\^###\\", "cn",
vim.fn.line("$"))

-- restore cursor position
utils.move_cursor(bufnr, oldlinenumber)
Expand Down Expand Up @@ -296,24 +335,28 @@ M.buf_get_request = function(bufnr, curpos)
content_type:find("application/[^ ]*json")
)

local script_str = get_response_script(bufnr, headers_end, end_line)


if config.get("jump_to_request") then
utils.move_cursor(bufnr, start_line)
else
utils.move_cursor(bufnr, curpos[2], curpos[3])
end

return true,
{
method = parsed_url.method,
url = parsed_url.url,
http_version = parsed_url.http_version,
headers = headers,
raw = curl_args,
body = body,
bufnr = bufnr,
start_line = start_line,
end_line = end_line,
}
{
method = parsed_url.method,
url = parsed_url.url,
http_version = parsed_url.http_version,
headers = headers,
raw = curl_args,
body = body,
bufnr = bufnr,
start_line = start_line,
end_line = end_line,
script_str = script_str
}
end

M.print_request = function(req)
Expand Down
86 changes: 76 additions & 10 deletions lua/rest-nvim/utils/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,41 @@ M.move_cursor = function(bufnr, line, column)
end)
end

M.set_env = function(key, value)
local variables = M.get_env_variables()
variables[key] = value
M.write_env_file(variables)
end

M.write_env_file = function(variables)
local env_file = "/" .. (config.get("env_file") or ".env")

-- Directories to search for env files
local env_file_paths = {
-- current working directory
vim.fn.getcwd() .. env_file,
-- directory of the currently opened file
vim.fn.expand("%:p:h") .. env_file,
}

-- If there's an env file in the current working dir
for _, env_file_path in ipairs(env_file_paths) do
if M.file_exists(env_file_path) then
local file = io.open(env_file_path, "w+")
if file ~= nil then
if string.match(env_file_path, "(.-)%.json$") then
file:write(vim.fn.json_encode(variables))
else
for key, value in pairs(variables) do
file:write(key .. "=" .. value .. "\n")
end
end
file:close()
end
end
end
end

M.uuid = function()
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
return string.gsub(template, "[xy]", function(c)
Expand Down Expand Up @@ -43,10 +78,8 @@ M.read_file = function(file)
return lines
end

-- get_variables Reads the environment variables found in the env_file option
-- (defualt: .env) specified in configuration or from the files being read
-- with variables beginning with @ and returns a table with the variables
M.get_variables = function()
-- reads the variables contained in the current file
M.get_file_variables = function()
local variables = {}

-- If there is a line at the beginning with @ first
Expand All @@ -64,7 +97,11 @@ M.get_variables = function()
end
end
end

return variables
end
-- Gets the variables from the currently selected env_file
M.get_env_variables = function()
local variables = {}
local env_file = "/" .. (config.get("env_file") or ".env")

-- Directories to search for env files
Expand All @@ -78,12 +115,39 @@ M.get_variables = function()
-- If there's an env file in the current working dir
for _, env_file_path in ipairs(env_file_paths) do
if M.file_exists(env_file_path) then
for line in io.lines(env_file_path) do
local vars = M.split(line, "%s*=%s*", 1)
variables[vars[1]] = vars[2]
if string.match(env_file_path, "(.-)%.json$") then
local f = io.open(env_file_path, "r")
if f ~= nil then
local json_vars = f:read("*all")
variables = vim.fn.json_decode(json_vars)
f:close()
end
else
for line in io.lines(env_file_path) do
local vars = M.split(line, "%s*=%s*", 1)
variables[vars[1]] = vars[2]
end
end
end
end
return variables
end

-- get_variables Reads the environment variables found in the env_file option
-- (defualt: .env) specified in configuration or from the files being read
-- with variables beginning with @ and returns a table with the variables
M.get_variables = function()
local variables = {}
local file_variables = M.get_file_variables()
local env_variables = M.get_env_variables()

for k, v in pairs(file_variables) do
variables[k] = v
end

for k, v in pairs(env_variables) do
variables[k] = v
end

-- For each variable name
for name, _ in pairs(variables) do
Expand Down Expand Up @@ -165,8 +229,10 @@ end
-- replace_vars replaces the env variables fields in the provided string
-- with the env variable value
-- @param str Where replace the placers for the env variables
M.replace_vars = function(str)
local vars = M.read_variables()
M.replace_vars = function(str, vars)
if vars == nil then
vars = M.read_variables()
end
-- remove $dotenv tags, which are used by the vscode rest client for cross compatibility
str = str:gsub("%$dotenv ", ""):gsub("%$DOTENV ", "")

Expand Down

0 comments on commit 090e253

Please sign in to comment.