From ba68b4fb96d41efaeaf45adcc23f5bed20d1d89c Mon Sep 17 00:00:00 2001 From: "Dung Duc Huynh (Kaka)" <870029+jellydn@users.noreply.github.com> Date: Tue, 31 Oct 2023 00:47:58 +0800 Subject: [PATCH] Run hurl cmd at current line (#13) * refactor: add formatter options * chore: migrate to new global config table * refactor: use cache to save log file * feat: run hurl cmd at current line * docs: add new usage for run Hurl at current line --- README.md | 10 ++--- lua/hurl/init.lua | 12 +++++- lua/hurl/main.lua | 98 ++++++++++++++++++++++++++++++++++++-------- lua/hurl/utils.lua | 9 ++-- lua/hurl/vlog.lua | 3 +- test/hurl_spec.lua | 4 ++ test/plugin_spec.lua | 8 ++-- 7 files changed, 111 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 33d4f47..734691c 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,8 @@ Add the following configuration to your Neovim setup: ```lua { "jellydn/hurl.nvim", - ft = "hurl", dependencies = { "MunifTanjim/nui.nvim" }, - cmd = { "HurlRunner" }, + cmd = { "HurlRunner", "HurlRunnerAt" }, opts = { -- Show debugging info debug = false, @@ -27,9 +26,10 @@ Add the following configuration to your Neovim setup: }, keys = { -- Run API request - { "ra", "HurlRunner", desc = "Run API requests" }, - -- Run API request in visual mode - { "cr", ":HurlRunner", desc = "Run API request", mode = "v" }, + { "rA", "HurlRunner", desc = "Run All requests" }, + { "ra", "HurlRunnerAt", desc = "Run Api request" }, + -- Run Hurl request in visual mode + { "h", ":HurlRunner", desc = "Hurl Runner", mode = "v" }, }, } } diff --git a/lua/hurl/init.lua b/lua/hurl/init.lua index dec275a..c1b54d5 100644 --- a/lua/hurl/init.lua +++ b/lua/hurl/init.lua @@ -2,9 +2,17 @@ local default_config = { debug = false, mode = 'split', + formatters = { + json = { 'jq' }, + html = { + 'prettier', + '--parser', + 'html', + }, + }, } --- Global configuration for entire plugin, easy to access from anywhere -_HURL_CFG = default_config +_HURL_GLOBAL_CONFIG = default_config local M = {} --- Setup hurl.nvim @@ -12,7 +20,7 @@ local M = {} -- - debug: (boolean | nil) default: false. -- - mode: ('popup' | 'split') default: popup. function M.setup(options) - _HURL_CFG = vim.tbl_extend('force', _HURL_CFG, options or default_config) + _HURL_GLOBAL_CONFIG = vim.tbl_extend('force', _HURL_GLOBAL_CONFIG, options or default_config) require('hurl.main').setup() end diff --git a/lua/hurl/main.lua b/lua/hurl/main.lua index ecbc083..c2a835a 100644 --- a/lua/hurl/main.lua +++ b/lua/hurl/main.lua @@ -1,4 +1,4 @@ -local util = require('hurl.utils') +local utils = require('hurl.utils') local M = {} @@ -7,7 +7,6 @@ local response = {} --- Output handler ---@class Output local on_output = function(code, data, event) - util.log_info('hurl: code ', code) local head_state if data[1] == '' then table.remove(data, 1) @@ -18,7 +17,7 @@ local on_output = function(code, data, event) if event == 'stderr' and #data > 1 then response.body = data - util.log_error(vim.inspect(data)) + utils.log_error(vim.inspect(data)) response.raw = data response.headers = {} return @@ -49,9 +48,9 @@ local on_output = function(code, data, event) end response.raw = data - util.log_info('hurl: response status ' .. response.status) - util.log_info('hurl: response headers ' .. vim.inspect(response.headers)) - util.log_info('hurl: response body ' .. response.body) + utils.log_info('hurl: response status ' .. response.status) + utils.log_info('hurl: response headers ' .. vim.inspect(response.headers)) + utils.log_info('hurl: response body ' .. response.body) end --- Call hurl command @@ -62,11 +61,15 @@ local function request(opts, callback) local cmd = vim.list_extend({ 'hurl', '-i', '--no-color' }, opts) response = {} + if _HURL_GLOBAL_CONFIG.debug then + vim.fn.setqflist({ { filename = vim.inspect(cmd), text = vim.inspect(opts) } }) + end + vim.fn.jobstart(cmd, { on_stdout = on_output, on_stderr = on_output, on_exit = function(i, code) - util.log_info('exit at ' .. i .. ' , code ' .. code) + utils.log_info('exit at ' .. i .. ' , code ' .. code) if code ~= 0 then -- Send error code and response to quickfix and open it vim.fn.setqflist({ { filename = vim.inspect(cmd), text = vim.inspect(response.body) } }) @@ -84,12 +87,17 @@ local function request(opts, callback) return end - local container = require('hurl.' .. _HURL_CFG.mode) - --show body if it is json - if util.is_json_response(response.headers['content-type']) then + local container = require('hurl.' .. _HURL_GLOBAL_CONFIG.mode) + local content_type = response.headers['content-type'] + or response.headers['Content-Type'] + or '' + + utils.log_info('Detected content type: ' .. content_type) + + if utils.is_json_response(content_type) then container.show(response, 'json') else - if util.is_html_response(response.headers['content-type']) then + if utils.is_html_response(content_type) then container.show(response, 'html') else container.show(response, 'text') @@ -113,11 +121,11 @@ end ---@param opts table The options local function run_selection(opts) opts = opts or {} - local lines = util.get_visual_selection() + local lines = utils.get_visual_selection() if not lines then return end - local fname = util.create_tmp_file(lines) + local fname = utils.create_tmp_file(lines) if not fname then vim.notify('hurl: create tmp file failed. Please try again!', vim.log.levels.WARN) @@ -126,24 +134,82 @@ local function run_selection(opts) table.insert(opts, fname) request(opts) + + -- Clean tmp file after 1s + local timeout = 1000 vim.defer_fn(function() local success = os.remove(fname) if not success then vim.notify('hurl: remove file failed', vim.log.levels.WARN) else - util.log_info('hurl: remove file success ' .. fname) + utils.log_info('hurl: remove file success ' .. fname) end - end, 1000) + end, timeout) +end + +local function find_http_verb(line, current_line_number) + if not line then + return nil + end + + -- TODO: Support other HTTP verbs + local verb_start, verb_end = line:find('GET') + if not verb_start then + verb_start, verb_end = line:find('POST') + end + + if verb_start then + return { line_number = current_line_number, start_pos = verb_start, end_pos = verb_end } + else + return nil + end +end + +local function find_http_verb_positions_in_buffer() + local buf = vim.api.nvim_get_current_buf() + local total_lines = vim.api.nvim_buf_line_count(buf) + local cursor = vim.api.nvim_win_get_cursor(0) + local current_line_number = cursor[1] + + local total = 0 + local current = 0 + + for i = 1, total_lines do + local line = vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] + local result = find_http_verb(line) + if result ~= nil then + total = total + 1 + if i == current_line_number then + current = total + end + end + end + + return { + total = total, + current = current, + } end function M.setup() - util.create_cmd('HurlRunner', function(opts) + utils.create_cmd('HurlRunner', function(opts) if opts.range ~= 0 then run_selection(opts.fargs) else run_current_file(opts.fargs) end end, { nargs = '*', range = true }) + + utils.create_cmd('HurlRunnerAt', function(opts) + local result = find_http_verb_positions_in_buffer() + if result.current > 0 then + opts.fargs = opts.fargs or {} + opts.fargs = vim.list_extend(opts.fargs, { '--to-entry', result.current }) + run_current_file(opts.fargs) + else + vim.notify('No GET/POST found in the current line') + end + end, { nargs = '*', range = true }) end return M diff --git a/lua/hurl/utils.lua b/lua/hurl/utils.lua index e482d27..cad40a5 100644 --- a/lua/hurl/utils.lua +++ b/lua/hurl/utils.lua @@ -6,7 +6,7 @@ local util = {} ---@vararg any util.log_info = function(...) -- Only save log when debug is on - if not _HURL_CFG.debug then + if not _HURL_GLOBAL_CONFIG.debug then return end @@ -17,7 +17,7 @@ end ---@vararg any util.log_error = function(...) -- Only save log when debug is on - if not _HURL_CFG.debug then + if not _HURL_GLOBAL_CONFIG.debug then return end @@ -69,7 +69,7 @@ util.create_tmp_file = function(content) f:close() -- Send to quicklist to open the temp file in debug mode - if _HURL_CFG.debug then + if _HURL_GLOBAL_CONFIG.debug then vim.fn.setqflist({ { filename = tmp_file, text = 'hurl.nvim' } }) vim.cmd('copen') end @@ -91,7 +91,8 @@ end ---@param type 'json' | 'html' | 'text' ---@return string[] | nil util.format = function(body, type) - local formatters = { json = { 'jq' }, html = { 'prettier', '--parser', 'html' } } + local formatters = _HURL_GLOBAL_CONFIG.formatters + or { json = { 'jq' }, html = { 'prettier', '--parser', 'html' } } -- If no formatter is defined, return the body if not formatters[type] then diff --git a/lua/hurl/vlog.lua b/lua/hurl/vlog.lua index b216160..7d0f47b 100644 --- a/lua/hurl/vlog.lua +++ b/lua/hurl/vlog.lua @@ -45,8 +45,7 @@ local unpack = unpack or table.unpack log.new = function(config, standalone) config = vim.tbl_deep_extend('force', default_config, config) - local outfile = - string.format('%s/%s.log', vim.api.nvim_call_function('stdpath', { 'data' }), config.plugin) + local outfile = string.format('%s/%s.log', vim.fn.stdpath('cache'), config.plugin) local obj if standalone then diff --git a/test/hurl_spec.lua b/test/hurl_spec.lua index ecae05b..e1ee507 100644 --- a/test/hurl_spec.lua +++ b/test/hurl_spec.lua @@ -8,4 +8,8 @@ describe('Hurl wrapper', function() it('should define a custom command: HurlRunner', function() assert.truthy(vim.fn.exists(':HurlRunner')) end) + + it('should define a custom command: HurlRunnerAt', function() + assert.truthy(vim.fn.exists(':HurlRunnerAt')) + end) end) diff --git a/test/plugin_spec.lua b/test/plugin_spec.lua index f466a8f..4eb737d 100644 --- a/test/plugin_spec.lua +++ b/test/plugin_spec.lua @@ -3,8 +3,8 @@ describe('Hurl.nvim plugin', function() local hurl = require('hurl') assert.truthy(hurl) - assert.are.same('split', _HURL_CFG.mode) - assert.are.same(false, _HURL_CFG.debug) + assert.are.same('split', _HURL_GLOBAL_CONFIG.mode) + assert.are.same(false, _HURL_GLOBAL_CONFIG.debug) end) it('should be able parse the configuration file', function() @@ -13,7 +13,7 @@ describe('Hurl.nvim plugin', function() mode = 'popup', }) - assert.are.same('popup', _HURL_CFG.mode) - assert.are.same(true, _HURL_CFG.debug) + assert.are.same('popup', _HURL_GLOBAL_CONFIG.mode) + assert.are.same(true, _HURL_GLOBAL_CONFIG.debug) end) end)