Skip to content

Commit 95f810a

Browse files
feat: evaluate context sequentially
1 parent 0258236 commit 95f810a

File tree

6 files changed

+95
-55
lines changed

6 files changed

+95
-55
lines changed

lua/rest-nvim/context.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ local M = {}
99
---@field vars table<string,string>
1010
---local variables
1111
---@field lv table<string,string>
12+
---current line number (to evaluate variable declaration sequentially)
13+
---@field linenr number
1214
local Context = {}
1315
Context.__index = Context
1416

@@ -45,6 +47,7 @@ function Context:new()
4547
---@type rest.Context
4648
local obj = {
4749
__index = self,
50+
linenr = 0,
4851
vars = {},
4952
lv = {},
5053
}

lua/rest-nvim/parser/init.lua

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ local NAMED_REQUEST_QUERY = vim.treesitter.query.parse("http", [[
2929
request: (_)) @request
3030
]])
3131

32-
local IN_PLACE_VARIABLE_QUERY = vim.treesitter.query.parse("http", [[
33-
(section
34-
!request
35-
(variable_declaration)+ @inplace_variable)
36-
]])
37-
3832
---@param node TSNode
3933
---@param field string
4034
---@param source Source
@@ -178,19 +172,22 @@ function parser.parse_body(content_type, body_node, source, context)
178172
return body
179173
end
180174

181-
---parse all in-place variables from source
182-
---@param source Source
183-
---@return rest.Context ctx
184-
function parser.create_context(source)
185-
local query = IN_PLACE_VARIABLE_QUERY
186-
local ctx = Context:new()
187-
local _, tree = utils.ts_parse_source(source)
188-
for _, node in query:iter_captures(tree:root(), source) do
189-
if node:type() == "variable_declaration" then
190-
parser.parse_variable_declaration(node, source, ctx)
175+
---In-place variables can be evaluated in loaded buffers due to treesitter limitations
176+
---@param source integer
177+
---@param ctx rest.Context
178+
---@param endline number zero-based line number
179+
function parser.eval_context(source, ctx, endline)
180+
vim.validate("source", source, "number")
181+
local startline = ctx.linenr
182+
for ln = startline, endline do
183+
local start_node = vim.treesitter.get_node({ pos = { ln, 0 }})
184+
if start_node then
185+
local node = utils.ts_find(start_node, "variable_declaration", true)
186+
if node then
187+
parser.parse_variable_declaration(node, source, ctx)
188+
end
191189
end
192190
end
193-
return ctx
194191
end
195192

196193
---@return TSNode? node TSNode with type `section`
@@ -327,6 +324,12 @@ function parser.parse(node, source, ctx)
327324
assert(req_node)
328325

329326
ctx = ctx or Context:new()
327+
-- TODO: note that in-place variables won't be evaluated due to treesitter limitations
328+
-- when source is given as raw string
329+
if type(source) == "number" then
330+
local start_row = node:range()
331+
parser.eval_context(source, ctx, start_row)
332+
end
330333
local method = get_node_field_text(req_node, "method", source)
331334
if not method then
332335
logger.info("no method provided, falling back to 'GET'")

lua/rest-nvim/request.lua

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ local ui = require("rest-nvim.ui.result")
1010
local nio = require("nio")
1111
local jar = require("rest-nvim.cookie_jar")
1212
local clients = require("rest-nvim.client")
13+
local Context = require("rest-nvim.context").Context
1314

1415
---@class rest.Request.Body
1516
---@field __TYPE "json"|"xml"|"raw"|"graphql"|"multipart_form_data"|"external"
@@ -35,6 +36,7 @@ local function run_request(req)
3536
if not client then
3637
logger.error("can't find registered client available for request:\n" .. vim.inspect(req))
3738
vim.notify("Can't find registered client available for request", vim.log.levels.ERROR, { title = "rest.nvim" })
39+
return
3840
end
3941
rest_nvim_last_request = req
4042

@@ -90,7 +92,7 @@ function M.run()
9092
vim.notify("Failed to find request at cursor position. See `:Rest logs` for more info.", vim.log.levels.ERROR, { title = "rest.nvim" })
9193
return
9294
end
93-
local ctx = parser.create_context(0)
95+
local ctx = Context:new()
9496
if config.env.enable and vim.b._rest_nvim_env_file then
9597
ctx:load_file(vim.b._rest_nvim_env_file)
9698
end
@@ -115,7 +117,7 @@ function M.run_by_name(name)
115117
vim.notify("Failed to find request by name: " .. name .. ". See `:Rest logs` for more info.", vim.log.levels.ERROR, { title = "rest.nvim" })
116118
return
117119
end
118-
local ctx = parser.create_context(0)
120+
local ctx = Context:new()
119121
if config.env.enable and vim.b._rest_nvim_env_file then
120122
ctx:load_file(vim.b._rest_nvim_env_file)
121123
end
@@ -145,7 +147,7 @@ end
145147
---run all requests in current file with same context
146148
function M.run_all()
147149
local reqs = parser.get_all_request_nodes(0)
148-
local ctx = parser.create_context(0)
150+
local ctx = Context:new()
149151
for _, req_node in ipairs(reqs) do
150152
local req = parser.parse(req_node, 0, ctx)
151153
if not req then

lua/rest-nvim/utils.lua

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,21 +194,34 @@ end
194194

195195
---@param source string|integer
196196
---@return vim.treesitter.LanguageTree
197-
---@return TSTree
198-
function utils.ts_parse_source(source)
199-
local ts_parser
197+
function utils.ts_get_parser(source)
200198
if type(source) == "string" then
201-
ts_parser = vim.treesitter.get_string_parser(source, "http")
199+
return vim.treesitter.get_string_parser(source, "http")
202200
else
203-
ts_parser = vim.treesitter.get_parser(source, "http")
201+
return vim.treesitter.get_parser(source, "http")
204202
end
203+
end
204+
205+
---@param source string|integer
206+
---@return vim.treesitter.LanguageTree
207+
---@return TSTree
208+
function utils.ts_parse_source(source)
209+
local ts_parser = utils.ts_get_parser(source)
205210
return ts_parser, assert(ts_parser:parse(false)[1])
206211
end
207212

208213
---@param node TSNode
209214
---@param type string
215+
---@param oneline boolean?
210216
---@return TSNode?
211-
function utils.ts_find(node, type)
217+
function utils.ts_find(node, type, oneline)
218+
if oneline then
219+
local sr, _, er, ec = node:range()
220+
local is_oneline = (sr == er) or (er - sr == 1 and ec == 0)
221+
if not is_oneline then
222+
return nil
223+
end
224+
end
212225
if node:type() == type then
213226
return node
214227
end

spec/examples/examples_spec.lua

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ require("spec.minimum_init")
44

55
local parser = require("rest-nvim.parser")
66
local utils = require("rest-nvim.utils")
7+
local Context = require("rest-nvim.context").Context
78

89
local function open(path)
910
vim.cmd.edit(path)
11+
vim.bo.filetype = "http"
1012
vim.cmd.source("ftplugin/http.lua")
1113
return 0
1214
end
@@ -54,30 +56,46 @@ describe("url without host", function ()
5456
end)
5557

5658
describe("in-place variables", function ()
57-
local source = open("spec/examples/variables/in_place_variables.http")
58-
local req_nodes = parser.get_all_request_nodes(source)
59-
assert.same(3, #req_nodes)
60-
local ctx = parser.create_context(source)
61-
it("example 1", function ()
62-
local req1 = assert(parser.parse(req_nodes[1], source, ctx))
63-
---@cast req1 rest.Request
64-
assert.same("example.org/users", req1.url)
65-
end)
66-
it("example 2", function ()
67-
local req2 = assert(parser.parse(req_nodes[2], source, ctx))
68-
assert.same("example.net/users", req2.url)
59+
it("parse context sequentially", function ()
60+
local source = open("spec/examples/variables/in_place_variables.http")
61+
local ctx = Context:new()
62+
parser.eval_context(source, ctx, -1)
63+
assert.same("", ctx:resolve("myhost"))
64+
parser.eval_context(source, ctx, 0)
65+
assert.same("", ctx:resolve("myhost"))
66+
parser.eval_context(source, ctx, 1)
67+
assert.same("example.org", ctx:resolve("myhost"))
68+
parser.eval_context(source, ctx, 2)
69+
assert.same("example.org", ctx:resolve("myhost"))
70+
parser.eval_context(source, ctx, 12)
71+
assert.same("example.net", ctx:resolve("myhost"))
6972
end)
70-
it("example 3", function ()
71-
local req3 = assert(parser.parse(req_nodes[3], source, ctx))
72-
assert.same("example.net/stats", req3.url)
73+
describe("evaluate context across multiple requests", function ()
74+
local source = open("spec/examples/variables/in_place_variables.http")
75+
local req_nodes = parser.get_all_request_nodes(source)
76+
assert.same(3, #req_nodes)
77+
local ctx = Context:new()
78+
it("example 1", function ()
79+
local req1 = assert(parser.parse(req_nodes[1], source, ctx))
80+
---@cast req1 rest.Request
81+
assert.same("example.org/users", req1.url)
82+
end)
83+
it("example 2", function ()
84+
local req2 = assert(parser.parse(req_nodes[2], source, ctx))
85+
assert.same("example.net/users", req2.url)
86+
end)
87+
it("example 3", function ()
88+
local req3 = assert(parser.parse(req_nodes[3], source, ctx))
89+
assert.same("example.net/stats", req3.url)
90+
end)
7391
end)
7492
end)
7593

7694
describe("pre-request script", function ()
7795
local source = open("spec/examples/script/pre_request_script.http")
7896
local req_nodes = parser.get_all_request_nodes(source)
7997
assert.same(2, #req_nodes)
80-
local ctx = parser.create_context(source)
98+
local ctx = Context:new()
8199
it("set local variable from pre-request script", function ()
82100
local req1 = assert(parser.parse(req_nodes[1], source, ctx))
83101
assert.same("https://jsonplaceholder.typicode.com/posts/3", req1.url)

spec/parser/http_parser_spec.lua

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -278,17 +278,18 @@ X-DATE: {{$date}}
278278
}, c.lv)
279279
end)
280280

281-
it("create context from source", function()
282-
local source = [[
283-
@foo=bar
284-
@bar=1234
285-
@baz={{foo}} adsf
286-
]]
287-
local ctx = parser.create_context(source)
288-
assert.same({
289-
foo = "bar",
290-
bar = "1234",
291-
baz = "bar adsf",
292-
}, ctx.vars)
293-
end)
281+
-- TODO: update this testcase
282+
-- it("create context from source", function()
283+
-- local source = [[
284+
-- @foo=bar
285+
-- @bar=1234
286+
-- @baz={{foo}} adsf
287+
-- ]]
288+
-- local ctx = parser.create_context(source)
289+
-- assert.same({
290+
-- foo = "bar",
291+
-- bar = "1234",
292+
-- baz = "bar adsf",
293+
-- }, ctx.vars)
294+
-- end)
294295
end)

0 commit comments

Comments
 (0)