Skip to content

Commit 9b4cf1e

Browse files
authored
Highlight request on run() and last() (#60)
New feature "highlight request on run() and last()". In order to implement this, we had to switch from synchronous call to plenary-curl to asynchronous with callback. Implementation is similar to the build-in vim.highlight.on_yank. This feature is enabled by default. Additionally, the old feature of moving the cursor to the current request line is disabled by default as the highlighting shows more accurate what is send and in my opinion it is nicer to have the cursor stay in place.
1 parent 6edb99e commit 9b4cf1e

File tree

8 files changed

+160
-73
lines changed

8 files changed

+160
-73
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,14 @@ use {
6161
result_split_horizontal = false,
6262
-- Skip SSL verification, useful for unknown certificates
6363
skip_ssl_verification = false,
64-
})
64+
-- Highlight request on run
65+
highlight = {
66+
enabled = true,
67+
timeout = 150,
68+
},
69+
-- Jump to request line on run
70+
jump_to_request = false,
71+
})
6572
end
6673
}
6774
```
@@ -100,6 +107,8 @@ To run `rest.nvim` you should map the following commands:
100107
on vertical)
101108
- `skip_ssl_verification` passes the `-k` flag to cURL in order to skip SSL verification,
102109
useful when using unknown certificates
110+
- `highlight` allows to enable and configure the highlighting of the selected request when send,
111+
- `jump_to_request` moves the cursor to the selected request line when send,
103112

104113
## Usage
105114

doc/rest-nvim.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ function, it looks like this by default:
5656
` result_split_horizontal = false,`
5757
` -- Skip SSL verification, useful for unknown certificates`
5858
` skip_ssl_verification = false,`
59+
` -- Highlight request on run`
60+
` highlight = {`
61+
` enabled = true,`
62+
` timeout = 150,`
63+
` },`
64+
` -- Jump to request line on run`
65+
` jump_to_request = false,`
5966
`})`
6067

6168
In this section we will be using `https://reqres.in/` for requests.

lua/rest-nvim/config/init.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ local M = {}
33
local config = {
44
result_split_horizontal = false,
55
skip_ssl_verification = false,
6+
highlight = {
7+
enabled = true,
8+
timeout = 150,
9+
},
10+
jump_to_request = false,
611
}
712

813
--- Get a configuration value

lua/rest-nvim/curl/init.lua

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local utils = require("rest-nvim.utils")
22
local curl = require("plenary.curl")
33
local config = require("rest-nvim.config")
4+
local log = require("plenary.log").new({ plugin = "rest.nvim", level = "debug" })
45

56
local M = {}
67
-- get_or_create_buf checks if there is already a buffer with the rest run results
@@ -39,75 +40,83 @@ M.get_or_create_buf = function()
3940
return new_bufnr
4041
end
4142

42-
-- curl_cmd runs curl with the passed options, gets or creates a new buffer
43-
-- and then the results are printed to the recently obtained/created buffer
44-
-- @param opts curl arguments
45-
M.curl_cmd = function(opts)
46-
local res = curl[opts.method](opts)
47-
if opts.dry_run then
48-
print("[rest.nvim] Request preview:\n" .. "curl " .. table.concat(res, " "))
49-
return
50-
end
43+
local function create_callback(method, url)
44+
return function(res)
45+
if res.exit ~= 0 then
46+
log.error("[rest.nvim] " .. utils.curl_error(res.exit))
47+
return
48+
end
49+
local res_bufnr = M.get_or_create_buf()
50+
local json_body = false
5151

52-
if res.exit ~= 0 then
53-
error("[rest.nvim] " .. utils.curl_error(res.exit))
54-
end
52+
-- Check if the content-type is "application/json" so we can format the JSON
53+
-- output later
54+
for _, header in ipairs(res.headers) do
55+
if string.find(header, "application/json") then
56+
json_body = true
57+
break
58+
end
59+
end
60+
61+
--- Add metadata into the created buffer (status code, date, etc)
62+
-- Request statement (METHOD URL)
63+
vim.api.nvim_buf_set_lines(res_bufnr, 0, 0, false, { method:upper() .. " " .. url })
5564

56-
local res_bufnr = M.get_or_create_buf()
57-
local json_body = false
65+
-- HTTP version, status code and its meaning, e.g. HTTP/1.1 200 OK
66+
local line_count = vim.api.nvim_buf_line_count(res_bufnr)
67+
vim.api.nvim_buf_set_lines(
68+
res_bufnr,
69+
line_count,
70+
line_count,
71+
false,
72+
{ "HTTP/1.1 " .. utils.http_status(res.status) }
73+
)
74+
-- Headers, e.g. Content-Type: application/json
75+
vim.api.nvim_buf_set_lines(
76+
res_bufnr,
77+
line_count + 1,
78+
line_count + 1 + #res.headers,
79+
false,
80+
res.headers
81+
)
5882

59-
-- Check if the content-type is "application/json" so we can format the JSON
60-
-- output later
61-
for _, header in ipairs(res.headers) do
62-
if string.find(header, "application/json") then
63-
json_body = true
64-
break
83+
--- Add the curl command results into the created buffer
84+
if json_body then
85+
-- format JSON body
86+
res.body = vim.fn.system("jq", res.body)
6587
end
66-
end
88+
local lines = utils.split(res.body, "\n")
89+
line_count = vim.api.nvim_buf_line_count(res_bufnr) - 1
90+
vim.api.nvim_buf_set_lines(res_bufnr, line_count, line_count + #lines, false, lines)
6791

68-
--- Add metadata into the created buffer (status code, date, etc)
69-
-- Request statement (METHOD URL)
70-
vim.api.nvim_buf_set_lines(res_bufnr, 0, 0, false, { opts.method:upper() .. " " .. opts.url })
71-
-- HTTP version, status code and its meaning, e.g. HTTP/1.1 200 OK
72-
local line_count = vim.api.nvim_buf_line_count(res_bufnr)
73-
vim.api.nvim_buf_set_lines(
74-
res_bufnr,
75-
line_count,
76-
line_count,
77-
false,
78-
{ "HTTP/1.1 " .. utils.http_status(res.status) }
79-
)
80-
-- Headers, e.g. Content-Type: application/json
81-
vim.api.nvim_buf_set_lines(
82-
res_bufnr,
83-
line_count + 1,
84-
line_count + 1 + #res.headers,
85-
false,
86-
res.headers
87-
)
92+
-- Only open a new split if the buffer is not loaded into the current window
93+
if vim.fn.bufwinnr(res_bufnr) == -1 then
94+
local cmd_split = [[vert sb]]
95+
if config.result_split_horizontal then
96+
cmd_split = [[sb]]
97+
end
98+
vim.cmd(cmd_split .. res_bufnr)
99+
-- Set unmodifiable state
100+
vim.api.nvim_buf_set_option(res_bufnr, "modifiable", false)
101+
end
88102

89-
--- Add the curl command results into the created buffer
90-
if json_body then
91-
-- format JSON body
92-
res.body = vim.fn.system("jq", res.body)
103+
-- Send cursor in response buffer to start
104+
utils.move_cursor(res_bufnr, 1)
93105
end
94-
local lines = utils.split(res.body, "\n")
95-
line_count = vim.api.nvim_buf_line_count(res_bufnr) - 1
96-
vim.api.nvim_buf_set_lines(res_bufnr, line_count, line_count + #lines, false, lines)
106+
end
97107

98-
-- Only open a new split if the buffer is not loaded into the current window
99-
if vim.fn.bufwinnr(res_bufnr) == -1 then
100-
local cmd_split = [[vert sb]]
101-
if config.result_split_horizontal == true then
102-
cmd_split = [[sb]]
103-
end
104-
vim.cmd(cmd_split .. res_bufnr)
105-
-- Set unmodifiable state
106-
vim.api.nvim_buf_set_option(res_bufnr, "modifiable", false)
108+
-- curl_cmd runs curl with the passed options, gets or creates a new buffer
109+
-- and then the results are printed to the recently obtained/created buffer
110+
-- @param opts curl arguments
111+
M.curl_cmd = function(opts)
112+
if opts.dry_run then
113+
local res = curl[opts.method](opts)
114+
log.debug("[rest.nvim] Request preview:\n" .. "curl " .. table.concat(res, " "))
115+
return
116+
else
117+
opts.callback = vim.schedule_wrap(create_callback(opts.method, opts.url))
118+
curl[opts.method](opts)
107119
end
108-
109-
-- Send cursor in response buffer to start
110-
utils.go_to_line(res_bufnr, 1)
111120
end
112121

113122
return M

lua/rest-nvim/init.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,15 @@ rest.run = function(verbose)
2525
raw = config.skip_ssl_verification and { "-k" } or nil,
2626
body = result.body,
2727
dry_run = verbose or false,
28+
bufnr = result.bufnr,
29+
start_line = result.start_line,
30+
end_line = result.end_line,
2831
}
2932

33+
if config.get("highlight").enabled then
34+
request.highlight(result.bufnr, result.start_line, result.end_line)
35+
end
36+
3037
local success_req, req_err = pcall(curl.curl_cmd, LastOpts)
3138

3239
if not success_req then
@@ -43,6 +50,11 @@ rest.last = function()
4350
vim.api.nvim_err_writeln("[rest.nvim]: Last request not found")
4451
return
4552
end
53+
54+
if config.get("highlight").enabled then
55+
request.highlight(LastOpts.bufnr, LastOpts.start_line, LastOpts.end_line)
56+
end
57+
4658
local success_req, req_err = pcall(curl.curl_cmd, LastOpts)
4759

4860
if not success_req then

lua/rest-nvim/request/init.lua

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
local utils = require("rest-nvim.utils")
22
local path = require("plenary.path")
3-
local log = require("plenary.log").new({ plugin = "rest.nvim", level = "warn" })
3+
local log = require("plenary.log").new({ plugin = "rest.nvim", level = "debug" })
4+
local config = require("rest-nvim.config")
45

56
-- get_importfile returns in case of an imported file the absolute filename
67
-- @param bufnr Buffer number, a.k.a id
78
-- @param stop_line Line to stop searching
89
local function get_importfile_name(bufnr, start_line, stop_line)
910
-- store old cursor position
1011
local oldpos = vim.fn.getcurpos()
11-
utils.go_to_line(bufnr, start_line)
12+
utils.move_cursor(bufnr, start_line)
1213

1314
local import_line = vim.fn.search("^<", "n", stop_line)
1415
-- restore old cursor position
15-
utils.go_to_line(bufnr, oldpos[2])
16+
utils.move_cursor(bufnr, oldpos[2])
1617

1718
if import_line > 0 then
1819
local fileimport_string
@@ -138,13 +139,19 @@ local function end_request(bufnr)
138139
if linenumber < vim.fn.line("$") then
139140
linenumber = linenumber + 1
140141
end
141-
utils.go_to_line(bufnr, linenumber)
142+
utils.move_cursor(bufnr, linenumber)
142143

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

145146
-- restore cursor position
146-
utils.go_to_line(bufnr, oldlinenumber)
147-
return next > 1 and next - 1 or vim.fn.line("$")
147+
utils.move_cursor(bufnr, oldlinenumber)
148+
local last_line = vim.fn.line("$")
149+
150+
if next == 0 or (oldlinenumber == last_line) then
151+
return last_line
152+
else
153+
return next - 1
154+
end
148155
end
149156

150157
-- parse_url returns a table with the method of the request and the URL
@@ -160,27 +167,63 @@ end
160167

161168
local M = {}
162169
M.get_current_request = function()
170+
local curpos = vim.fn.getcurpos()
163171
local bufnr = vim.api.nvim_win_get_buf(0)
164172

165173
local start_line = start_request()
166174
if start_line == 0 then
167175
error("No request found")
168176
end
169177
local end_line = end_request()
170-
utils.go_to_line(bufnr, start_line)
171178

172179
local parsed_url = parse_url(vim.fn.getline(start_line))
173180

174181
local headers, body_start = get_headers(bufnr, start_line, end_line)
175182

176183
local body = get_body(bufnr, body_start, end_line)
177184

185+
if config.get("jump_to_request") then
186+
utils.move_cursor(bufnr, start_line)
187+
else
188+
utils.move_cursor(bufnr, curpos[2], curpos[3])
189+
end
190+
178191
return {
179192
method = parsed_url.method,
180193
url = parsed_url.url,
181194
headers = headers,
182195
body = body,
196+
bufnr = bufnr,
197+
start_line = start_line,
198+
end_line = end_line,
183199
}
184200
end
185201

202+
local select_ns = vim.api.nvim_create_namespace("rest-nvim")
203+
M.highlight = function(bufnr, start_line, end_line)
204+
local opts = config.get("highlight") or {}
205+
local higroup = "IncSearch"
206+
local timeout = opts.timeout or 150
207+
208+
vim.api.nvim_buf_clear_namespace(bufnr, select_ns, 0, -1)
209+
210+
local end_column = string.len(vim.fn.getline(end_line))
211+
212+
vim.highlight.range(
213+
bufnr,
214+
select_ns,
215+
higroup,
216+
{ start_line - 1, 0 },
217+
{ end_line - 1, end_column },
218+
"c",
219+
false
220+
)
221+
222+
vim.defer_fn(function()
223+
if vim.api.nvim_buf_is_valid(bufnr) then
224+
vim.api.nvim_buf_clear_namespace(bufnr, select_ns, 0, -1)
225+
end
226+
end, timeout)
227+
end
228+
186229
return M

lua/rest-nvim/utils/init.lua

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ math.randomseed(os.time())
33

44
local M = {}
55

6-
-- go_to_line moves the cursor to the desired line in the provided buffer
6+
-- move_cursor moves the cursor to the desired position in the provided buffer
77
-- @param bufnr Buffer number, a.k.a id
8-
-- @param line the desired cursor position
9-
M.go_to_line = function(bufnr, line)
8+
-- @param line the desired line
9+
-- @param column the desired column, defaults to 1
10+
M.move_cursor = function(bufnr, line, column)
11+
column = column or 1
1012
vim.api.nvim_buf_call(bufnr, function()
11-
vim.fn.cursor(line, 1)
13+
vim.fn.cursor(line, column)
1214
end)
1315
end
1416

tests/external_file/multiple_requests.http

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ Content-Type: application/json
1616
< ./user.json
1717

1818
####
19-
19+
###
2020
GET https://reqres.in/api/users?page=5

0 commit comments

Comments
 (0)