Skip to content

Commit f811cfe

Browse files
committed
feat: defer splicing as late as possible
Right now we splice variables as we parse the request. This is annoying for several resons: variable needs to exist to create the request, so probably we need to run the previous requests before that.
1 parent 87941ab commit f811cfe

File tree

3 files changed

+137
-102
lines changed

3 files changed

+137
-102
lines changed

lua/rest-nvim/curl/init.lua

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ local function format_curl_cmd(res)
3131
return cmd
3232
end
3333

34-
3534
-- get_or_create_buf checks if there is already a buffer with the rest run results
3635
-- and if the buffer does not exists, then create a new one
3736
M.get_or_create_buf = function()
@@ -230,7 +229,7 @@ end
230229
M.curl_cmd = function(opts)
231230
-- plenary's curl module is strange in the sense that with "dry_run" it returns the command
232231
-- otherwise it starts the request :/
233-
local dry_run_opts = vim.tbl_extend("force", opts, { dry_run = true } )
232+
local dry_run_opts = vim.tbl_extend("force", opts, { dry_run = true })
234233
local res = curl[opts.method](dry_run_opts)
235234
local curl_cmd = format_curl_cmd(res)
236235

@@ -242,7 +241,8 @@ M.curl_cmd = function(opts)
242241
vim.api.nvim_echo({ { "[rest.nvim] Request preview:\n", "Comment" }, { curl_cmd } }, false, {})
243242
return
244243
else
245-
opts.callback = vim.schedule_wrap(create_callback(curl_cmd, opts.method, opts.url, opts.script_str))
244+
opts.callback =
245+
vim.schedule_wrap(create_callback(curl_cmd, opts.method, opts.url, opts.script_str))
246246
curl[opts.method](opts)
247247
end
248248
end

lua/rest-nvim/init.lua

+102-23
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@ local backend = require("rest-nvim.request")
22
local config = require("rest-nvim.config")
33
local curl = require("rest-nvim.curl")
44
local log = require("plenary.log").new({ plugin = "rest.nvim" })
5+
local utils = require("rest-nvim.utils")
6+
local path = require("plenary.path")
57

68
local rest = {}
79
local Opts = {}
810
local defaultRequestOpts = {
9-
verbose = false,
10-
highlight = false,
11-
engine = 'classic'
12-
}
11+
verbose = false,
12+
highlight = false,
13+
}
1314

1415
local LastOpts = {}
16+
1517
rest.setup = function(user_configs)
1618
config.set(user_configs or {})
17-
1819
end
1920

2021
-- run will retrieve the required request information from the current buffer
@@ -37,7 +38,7 @@ end
3738
-- @param string filename to load
3839
-- @param opts table
3940
-- 1. keep_going boolean keep running even when last request failed
40-
-- 2. verbose boolean
41+
-- 2. verbose boolean
4142
rest.run_file = function(filename, opts)
4243
log.info("Running file :" .. filename)
4344
opts = vim.tbl_deep_extend(
@@ -54,38 +55,113 @@ rest.run_file = function(filename, opts)
5455

5556
local requests = backend.buf_list_requests(new_buf)
5657
for _, req in pairs(requests) do
57-
vim.pretty_print("Request:")
58-
vim.pretty_print(req)
5958
rest.run_request(req, opts)
6059
end
6160

6261
return true
6362
end
6463

64+
-- replace variables in header values
65+
local function splice_headers(headers)
66+
for name, value in pairs(headers) do
67+
headers[name] = utils.replace_vars(value)
68+
end
69+
return headers
70+
end
71+
72+
-- return the spliced/resolved filename
73+
-- @param string the filename w/o variables
74+
local function load_external_payload(fileimport_string)
75+
local fileimport_spliced = utils.replace_vars(fileimport_string)
76+
if path:new(fileimport_spliced):is_absolute() then
77+
return fileimport_spliced
78+
else
79+
local file_dirname = vim.fn.expand("%:p:h")
80+
local file_name = path:new(path:new(file_dirname), fileimport_spliced)
81+
return file_name:absolute()
82+
end
83+
end
84+
85+
86+
-- @param headers table HTTP headers
87+
-- @param payload table of the form { external = bool, filename_tpl= path, body_tpl = string }
88+
-- with body_tpl an array of lines
89+
local function splice_body(headers, payload)
90+
local external_payload = payload.external
91+
local lines -- array of strings
92+
if external_payload then
93+
local importfile = load_external_payload(payload.filename_tpl)
94+
if not utils.file_exists(importfile) then
95+
error("import file " .. importfile .. " not found")
96+
end
97+
-- TODO we dont necessarily want to load the file, it can be slow
98+
-- https://github.com/rest-nvim/rest.nvim/issues/203
99+
lines = utils.read_file(importfile)
100+
else
101+
lines = payload.body_tpl
102+
end
103+
local content_type = ""
104+
for key, val in pairs(headers) do
105+
if string.lower(key) == "content-type" then
106+
content_type = val
107+
break
108+
end
109+
end
110+
local has_json = content_type:find("application/[^ ]*json")
111+
112+
local body = ""
113+
local vars = utils.read_variables()
114+
-- nvim_buf_get_lines is zero based and end-exclusive
115+
-- but start_line and stop_line are one-based and inclusive
116+
-- magically, this fits :-) start_line is the CRLF between header and body
117+
-- which should not be included in the body, stop_line is the last line of the body
118+
for _, line in ipairs(lines) do
119+
body = body .. utils.replace_vars(line, vars)
120+
end
121+
122+
local is_json, json_body = pcall(vim.json.decode, body)
123+
124+
if is_json and json_body then
125+
if has_json then
126+
-- convert entire json body to string.
127+
return vim.fn.json_encode(json_body)
128+
else
129+
-- convert nested tables to string.
130+
for key, val in pairs(json_body) do
131+
if type(val) == "table" then
132+
json_body[key] = vim.fn.json_encode(val)
133+
end
134+
end
135+
return vim.fn.json_encode(json_body)
136+
end
137+
end
138+
end
65139

66140
-- run will retrieve the required request information from the current buffer
67141
-- and then execute curl
68142
-- @param req table see validate_request to check the expected format
69143
-- @param opts table
70144
-- 1. keep_going boolean keep running even when last request failed
71145
rest.run_request = function(req, opts)
72-
-- TODO rename result to req
146+
-- TODO rename result to request
73147
local result = req
74148
opts = vim.tbl_deep_extend(
75149
"force", -- use value from rightmost map
76150
defaultRequestOpts,
77151
opts or {}
78152
)
79153

154+
-- body =
155+
80156
Opts = {
81157
method = result.method:lower(),
82158
url = result.url,
83159
-- plenary.curl can't set http protocol version
84160
-- http_version = result.http_version,
85-
headers = result.headers,
161+
headers = splice_headers(result.headers),
86162
raw = config.get("skip_ssl_verification") and vim.list_extend(result.raw, { "-k" })
87163
or result.raw,
88-
body = result.body,
164+
body = splice_body(result.headers, result.body),
89165
dry_run = opts.verbose,
90166
bufnr = result.bufnr,
91167
start_line = result.start_line,
@@ -103,18 +179,21 @@ rest.run_request = function(req, opts)
103179

104180
local request_id = vim.loop.now()
105181
local data = {
106-
requestId = request_id,
107-
request = req
108-
}
182+
requestId = request_id,
183+
request = req,
184+
}
109185

110186
vim.api.nvim_exec_autocmds("User", {
111-
pattern = "RestStartRequest",
112-
modeline = false,
113-
data = data
114-
})
187+
pattern = "RestStartRequest",
188+
modeline = false,
189+
data = data,
190+
})
115191
local success_req, req_err = pcall(curl.curl_cmd, Opts)
116-
vim.api.nvim_exec_autocmds("User", { pattern = "RestStopRequest", modeline = false,
117-
data = vim.tbl_extend("keep", { status = success_req, message = req_err }, data) })
192+
vim.api.nvim_exec_autocmds("User", {
193+
pattern = "RestStopRequest",
194+
modeline = false,
195+
data = vim.tbl_extend("keep", { status = success_req, message = req_err }, data),
196+
})
118197

119198
if not success_req then
120199
vim.api.nvim_err_writeln(
@@ -148,10 +227,10 @@ end
148227

149228
rest.request = backend
150229

151-
rest.select_env = function(path)
230+
rest.select_env = function(env_file)
152231
if path ~= nil then
153-
vim.validate({ path = { path, "string" } })
154-
config.set({ env_file = path })
232+
vim.validate({ env_file = { env_file, "string" } })
233+
config.set({ env_file = env_file })
155234
else
156235
print("No path given")
157236
end

0 commit comments

Comments
 (0)