Skip to content

Commit 48e1400

Browse files
YaroSpaceigorlfs
andauthored
feat: kulala_http in markdown blocks, syntax hl, diagnostics + fixes (#600)
* refact: ui/jumps, formatters * fix(env_manager): fix using vim.ui.select * fix(parser): grammar for $auth.token vars * feat(ui): add kulala_http parser to markdown code blocks * feat(ui): add diagnostics for invalid paths * fix(cmd): set assert status to false for non-zero response code * feat(ui): add syntax hl to '@,=' * fix(jump): off by one (#613) --------- Co-authored-by: Igor Lacerda <igorlfs@ufmg.br>
1 parent 9d3206d commit 48e1400

File tree

28 files changed

+2664
-2641
lines changed

28 files changed

+2664
-2641
lines changed

docs/docs/getting-started/configuration-options.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ Function called when Kulala LSP attaches to the buffer
928928
enable = true,
929929
keymaps = false, -- disabled by default, as Kulala relies on default Neovim LSP keymaps
930930
formatter = {
931-
sort = { -- enable/disable alphabetical sorting in request body
931+
sort = { -- enable/disable alphabetical sorting
932932
metadata = true,
933933
variables = true,
934934
commands = true,

lua/kulala/cmd/diagnostics.lua

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ local function get_diagnostics(bufnr, parser)
2929
end_lnum = end_lnum,
3030
col = col,
3131
end_col = end_col,
32-
severity = 1, -- Error severity in LSP
32+
severity = vim.diagnostic.ERROR,
3333
source = "kulala",
3434
message = "Parsing error" .. (parent_type and " in " .. parent_type or ""),
35+
type = "treesitter",
3536
})
3637
end
3738

@@ -46,7 +47,16 @@ end
4647

4748
local function update_diagnostics(bufnr)
4849
local parser = ts.get_parser(bufnr, "kulala_http")
49-
local diags = get_diagnostics(bufnr, parser)
50+
51+
local existing_diags = vim.diagnostic.get(bufnr) or {}
52+
local parser_diags = vim
53+
.iter(existing_diags)
54+
:filter(function(diag)
55+
return diag.type == "parser"
56+
end)
57+
:totable()
58+
59+
local diags = vim.list_extend(get_diagnostics(bufnr, parser), parser_diags)
5060
vim.diagnostic.set(kulala_diag_ns(), bufnr, diags, {})
5161
end
5262

@@ -62,4 +72,40 @@ function M.setup(bufnr)
6272
})
6373
end
6474

75+
M.add_diagnostics = function(bufnr, message, severity, ls, cs, le, ce)
76+
local diags = vim.diagnostic.get(bufnr)
77+
ls = math.max(0, ls or 0)
78+
le = math.max(0, le or ls or 0)
79+
80+
if vim.iter(diags):find(function(diag)
81+
return diag.message == message and diag.lnum == ls
82+
end) then return end
83+
84+
table.insert(diags, {
85+
bufnr = bufnr,
86+
lnum = ls,
87+
end_lnum = le,
88+
col = cs or 0,
89+
end_col = ce or cs or 0,
90+
severity = severity or vim.diagnostic.ERROR,
91+
source = "kulala",
92+
message = message,
93+
type = "parser",
94+
})
95+
96+
vim.diagnostic.set(kulala_diag_ns(), bufnr, diags, {})
97+
end
98+
99+
M.clear_diagnostics = function(bufnr, type)
100+
local diags = not type and {}
101+
or vim
102+
.iter(vim.diagnostic.get(bufnr))
103+
:filter(function(diag)
104+
return diag.type ~= type
105+
end)
106+
:totable()
107+
108+
vim.diagnostic.set(kulala_diag_ns(), bufnr, diags, {})
109+
end
110+
65111
return M

lua/kulala/cmd/formatter.lua

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
local Config = require("kulala.config")
2-
local Graphql = require("kulala.parser.graphql")
3-
local Json = require("kulala.utils.json")
4-
local Xml = require("kulala.utils.xml")
2+
local Formatter = require("kulala.formatter")
53

64
local format_opts = Config.options.lsp.formatter
75
format_opts = type(format_opts) == "table" and format_opts or { sort = { json = true } }
@@ -282,23 +280,23 @@ format_rules = {
282280

283281
["xml_body"] = function(node)
284282
local body = get_text(node)
285-
local formatted = Xml.format(body) or body
283+
local formatted = Formatter.xml(body) or body
286284

287285
current_section().request.body = formatted:gsub("\n*$", "")
288286
return formatted
289287
end,
290288

291289
["json_body"] = function(node)
292290
local json = get_text(node)
293-
local formatted = Json.format(json, { sort = format_opts.sort.json }) or json
291+
local formatted = Formatter.json(json, { sort = format_opts.sort.json }) or json
294292

295293
current_section().request.body = formatted:gsub("\n*$", "")
296294
return formatted
297295
end,
298296

299297
["graphql_body"] = function(node)
300298
local body = get_text(node)
301-
local formatted = Graphql.format(body, { sort = format_opts.sort.json }) or body
299+
local formatted = Formatter.graphql(body, { sort = format_opts.sort.json }) or body
302300

303301
current_section().request.body = formatted:gsub("\n*$", "")
304302
return formatted
@@ -364,10 +362,11 @@ M.format = function(buffer, params)
364362
params = params or {}
365363
buf = buffer or vim.api.nvim_get_current_buf()
366364

367-
local diag = vim.diagnostic.get(buf)
368-
if #diag > 0 and vim.fn.input("Document contains errors. Do you still want to format it? (y/n): ") ~= "y" then
369-
return
370-
end
365+
local diag = vim.iter(vim.diagnostic.get(buf) or {}):find(function(d)
366+
return d.type == "treesitter"
367+
end)
368+
369+
if diag and vim.fn.input("Document contains errors. Do you still want to format it? (y/n): ") ~= "y" then return end
371370

372371
local lang = "kulala_http"
373372
local tree = ts.get_parser(buf, lang):parse()[1]

lua/kulala/cmd/init.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function queue.run_next(self)
6565

6666
if not (status and cb_status) then
6767
self:reset()
68-
Logger.error(("Errors running a scheduled task: %s %s"):format(errors or "", cb_errors), 1, true)
68+
Logger.error(("Errors running a scheduled task: %s %s"):format(errors or "", cb_errors), 1, { report = true })
6969
end
7070

7171
self.done = self.done + 1
@@ -147,6 +147,7 @@ local function set_request_stats(response)
147147
response.stats = Json.parse(response.stats) or {}
148148
response.response_code = tonumber(response.stats.response_code) or response.code
149149
response.status = response.code == 0 and response.response_code < 400
150+
response.assert_status = response.status and response.assert_status
150151

151152
return response
152153
end
@@ -179,7 +180,7 @@ local function save_response(request_status, parsed_request)
179180

180181
local responses = DB.global_update().responses
181182
if #responses > 0 and responses[#responses].id == id and responses[#responses].code == -1 then
182-
table.remove(responses) -- remove the last response if it's the same request and status was unfinished
183+
table.remove(responses) -- remove the last response if it's the same request and status was unfinished (for chunked response)
183184
end
184185

185186
---@type Response
@@ -261,7 +262,7 @@ local function process_errors(request, request_status, processing_errors)
261262
)
262263

263264
Logger.error(message, 2)
264-
_ = processing_errors and Logger.error(processing_errors, 2, true)
265+
_ = processing_errors and Logger.error(processing_errors, 2, { report = true })
265266

266267
request_status.errors = processing_errors and request_status.errors .. "\n" .. processing_errors
267268
or request_status.errors

lua/kulala/cmd/lsp.lua

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ local sources = {
356356
auth_configs = auth_configs,
357357
methods = { Lsp_sources.methods, "Method" },
358358
schemes = { Lsp_sources.schemes, "Scheme" },
359-
header_names = { Lsp_sources.header_names, "Header" },
360-
header_values = { Lsp_sources.header_values, "Header" },
359+
header_names = { Lsp_sources.header_names, "Header name" },
360+
header_values = { Lsp_sources.header_values, "Header value" },
361361
metadata = { Lsp_sources.metadata, "Metadata" },
362362
curl = { Lsp_sources.curl, "Curl" },
363363
grpc = { Lsp_sources.grpc, "Grpc" },
@@ -398,7 +398,8 @@ local function source_type(params)
398398
if find_upwards(params.position.line, "query.*{") or find_upwards(params.position.line, "mutation.*{") then
399399
return { "graphql", "urls" }
400400
end
401-
if find_upwards(params.position.line, "{%%") then return { "scripts", "urls", "headers_names", "header_values" } end
401+
402+
if find_upwards(params.position.line, "{%%") then return { "scripts", "urls", "header_names", "header_values" } end
402403

403404
return { "commands", "methods", "schemes", "urls", "header_names", "snippets" }
404405
end
@@ -693,7 +694,10 @@ local function new_server()
693694
_ = handlers[method] and handler(nil, handlers[method](params))
694695
end, debug.traceback)
695696

696-
if not status then require("kulala.logger").error("Errors in Kulala LSP:\n" .. (error or ""), 2, true) end
697+
if not status then
698+
require("kulala.logger").error("Errors in Kulala LSP:\n" .. (error or ""), 2, { report = true })
699+
end
700+
697701
return true
698702
end
699703

lua/kulala/config/defaults.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ local M = {
100100
---@type table<string, string|vim.api.keyset.highlight>
101101
syntax_hl = {
102102
["@punctuation.bracket.kulala_http"] = "Number",
103+
["@character.special.kulala_http"] = "Special",
104+
["@operator.kulala_http"] = "Special",
105+
["@variable.kulala_http"] = "String",
103106
},
104107

105108
-- enable/disable request summary in the output window

lua/kulala/formatter/init.lua

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
local Config = require("kulala.config")
2+
local Graphql = require("kulala.parser.graphql")
13
local Logger = require("kulala.logger")
4+
local Shell = require("kulala.cmd.shell_utils")
25

36
local M = {}
47

@@ -7,25 +10,66 @@ M.format = function(formatter, contents, opts)
710
verbose = true,
811
})
912

10-
if type(formatter) == "function" then
11-
return formatter(contents)
12-
elseif type(formatter) == "table" then
13-
local cmd = formatter
13+
if type(formatter) == "function" then return formatter(contents) end
14+
if not type(formatter) == "table" then return contents end
1415

15-
local status, result = pcall(function()
16-
return vim.system(cmd, { stdin = contents, text = true }):wait()
17-
end)
16+
local executable = formatter[1]
1817

19-
if not status or result.code ~= 0 then
20-
_ = opts.verbose
21-
and Logger.warn(("Error running external formatter: %s"):format(not status and result or result.stderr))
22-
return contents
23-
end
18+
if vim.fn.executable(executable) == 0 then
19+
_ = opts.versbose and Logger.warn("Formatting failed: " .. executable .. " is not available.")
20+
return contents
21+
end
22+
23+
local result = Shell.run(formatter, {
24+
sync = true,
25+
stdin = contents,
26+
err_msg = "Failed to format with " .. executable,
27+
abort_on_stderr = true,
28+
})
29+
30+
if not result or result.code ~= 0 or result.stderr ~= "" or result.stdout == "" then return contents end
31+
32+
return result.stdout
33+
end
34+
35+
M.json = function(contents, opts)
36+
local formatter = Config.get().contenttypes["application/json"]
37+
if not formatter then return contents end
38+
39+
opts = vim.tbl_deep_extend("keep", opts or {}, { sort = true })
40+
_ = opts.sort and formatter and table.insert(formatter.formatter, 2, "--sort-keys")
41+
42+
contents = type(contents) == "table" and vim.json.encode(contents, opts) or contents
2443

25-
return result.stdout
44+
return M.format(formatter.formatter, contents, opts)
45+
end
46+
47+
M.graphql = function(contents, opts)
48+
local formatter = Config.get().contenttypes["application/graphql"]
49+
if not formatter then return contents end
50+
51+
local _, json = Graphql.get_json(contents)
52+
if not json then return contents end
53+
54+
local formatted = M.format(formatter.formatter, json.query, opts)
55+
56+
if json.variables and next(json.variables) then
57+
formatted = formatted .. "\n" .. M.json(json.variables, { sort = opts.sort })
2658
end
2759

28-
return contents
60+
return formatted
61+
end
62+
63+
M.html = function(contents, opts)
64+
local formatter = Config.get().contenttypes["application/html"]
65+
if not formatter then return contents end
66+
return M.format(formatter.formatter, contents, opts)
67+
end
68+
69+
M.xml = function(contents, opts)
70+
local formatter = Config.get().contenttypes["application/xml"]
71+
if not formatter then return contents end
72+
return M.format(formatter.formatter, contents, opts)
2973
end
3074

3175
return M

lua/kulala/init.lua

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ local Fmt = require("kulala.cmd.fmt")
55
local Fs = require("kulala.utils.fs")
66
local GLOBALS = require("kulala.globals")
77
local Graphql = require("kulala.graphql")
8-
local JUMPS = require("kulala.jumps")
98
local Logger = require("kulala.logger")
109
local ScriptsUtils = require("kulala.parser.scripts.utils")
1110
local UI = require("kulala.ui")
@@ -55,11 +54,11 @@ M.version = function()
5554
end
5655

5756
M.jump_next = function()
58-
JUMPS.jump_next()
57+
UI:jump_next()
5958
end
6059

6160
M.jump_prev = function()
62-
JUMPS.jump_prev()
61+
UI:jump_prev()
6362
end
6463

6564
M.toggle_view = function()

lua/kulala/jumps/init.lua

Lines changed: 0 additions & 19 deletions
This file was deleted.

lua/kulala/logger/init.lua

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ local function generate_bug_report(message)
1616
if choice == 1 then require("kulala.logger.bug_report").generate_bug_report(message) end
1717
end
1818

19-
M.log = function(message, level)
19+
M.log = function(message, level, opts)
20+
opts = vim.tbl_extend("force", default_options, opts or {})
2021
level = level or log_levels.INFO
22+
2123
local notify = vim.notify
2224

2325
if not vim.fn.has("gui_running") then
@@ -26,21 +28,23 @@ M.log = function(message, level)
2628
notify = vim.schedule_wrap(vim.notify)
2729
end
2830

29-
notify(message, level, default_options)
31+
notify(message, level, opts)
3032
end
3133

32-
M.info = function(message)
33-
_ = debug_level() > 2 and M.log(message, log_levels.INFO)
34+
M.info = function(message, opts)
35+
_ = debug_level() > 2 and M.log(message, log_levels.INFO, opts)
3436
end
3537

36-
M.warn = function(message)
37-
_ = debug_level() > 1 and M.log(message, log_levels.WARN)
38+
M.warn = function(message, opts)
39+
_ = debug_level() > 1 and M.log(message, log_levels.WARN, opts)
3840
end
3941

4042
---@param message string
4143
---@param lines_no number|nil -- no of error lines to show
4244
---@param report boolean|nil -- whether to generate a bug report
43-
M.error = function(message, lines_no, report)
45+
M.error = function(message, lines_no, opts)
46+
opts = opts or {}
47+
4448
local debug = debug_level()
4549
if debug == 0 then return end
4650

@@ -50,7 +54,7 @@ M.error = function(message, lines_no, report)
5054

5155
M.log(message, log_levels.ERROR)
5256

53-
if require("kulala.config").options.generate_bug_report or report then generate_bug_report(message) end
57+
if require("kulala.config").options.generate_bug_report or opts.report then generate_bug_report(message) end
5458
end
5559

5660
return M

0 commit comments

Comments
 (0)