Skip to content

Commit 1180ed5

Browse files
committed
fix autocompletion
1 parent c1935a2 commit 1180ed5

File tree

2 files changed

+148
-2
lines changed

2 files changed

+148
-2
lines changed

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [1.4.0] 2025-05-01
8+
## [1.4.1] 2025-04-05
9+
### Improved
10+
* Context-aware Autocompletion System
11+
* Fixed headers autocompletion in request bodies - no longer suggesting headers in the body section
12+
* Improved script block detection for better completions in response handler scripts
13+
* Added enhanced context detection to provide appropriate suggestions based on cursor position
14+
* Added script-specific suggestions in response handler blocks (client.global.set, response.body, etc.)
15+
* Maintained environment variable {{...}} completion in request bodies while disabling header suggestions
16+
* Improved request body detection to properly recognize body sections
17+
18+
## [1.4.0] 2025-04-04
919
### Added
1020
* Intelligent Autocompletion System
1121
* Environment variable completion with `{{` trigger

lua/http_client/completion.lua

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,70 @@ local function add_to_recent(var)
7272
end
7373
end
7474

75+
-- Check if cursor is inside a response handler script block
76+
local function is_in_script_block()
77+
local line_num = vim.api.nvim_win_get_cursor(0)[1]
78+
local bufnr = vim.api.nvim_get_current_buf()
79+
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
80+
81+
-- Find the start of the current block
82+
local script_start = false
83+
for i = 1, line_num do
84+
local check_line = lines[i]
85+
if check_line:match("^>%s*{%%") then
86+
script_start = true
87+
elseif check_line:match("^%%}") and script_start then
88+
script_start = false
89+
end
90+
end
91+
92+
-- If we've seen a script start but no end, we're in a script block
93+
return script_start
94+
end
95+
96+
-- Check if cursor is inside a request body
97+
local function is_in_request_body()
98+
local line_num = vim.api.nvim_win_get_cursor(0)[1]
99+
local bufnr = vim.api.nvim_get_current_buf()
100+
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
101+
102+
-- Find the request line (GET, POST, etc.)
103+
local request_start = 0
104+
local header_end = 0
105+
106+
for i = line_num, 1, -1 do
107+
local check_line = lines[i]
108+
109+
-- Found a separator above current position, we're not in a request
110+
if check_line:match("^###") then
111+
break
112+
end
113+
114+
-- Found a request line (e.g. "GET http://example.com")
115+
if check_line:match("^%s*[A-Z]+%s+%S+") then
116+
request_start = i
117+
break
118+
end
119+
end
120+
121+
if request_start == 0 then
122+
return false -- Not in a request
123+
end
124+
125+
-- After finding the request start, look down to find where headers end
126+
-- Headers end at the first empty line after the request line
127+
for i = request_start + 1, line_num do
128+
local check_line = lines[i]
129+
if check_line:match("^%s*$") then
130+
header_end = i
131+
break
132+
end
133+
end
134+
135+
-- If we found an empty line and current line is after it, we're in body
136+
return header_end > 0 and line_num > header_end
137+
end
138+
75139
-- Get all available variables from current environment
76140
local function get_env_variables()
77141
local env = environment.get_current_env() or {}
@@ -334,6 +398,17 @@ M.create_method_source = function()
334398
return
335399
end
336400

401+
-- Check if we're inside a response handler script block
402+
local in_script_block = is_in_script_block()
403+
404+
-- Check if we're in a request body
405+
local in_body = is_in_request_body()
406+
407+
if in_script_block or in_body then
408+
callback({ items = {}, isIncomplete = false })
409+
return
410+
end
411+
337412
-- Check if we're in a good context for method completion:
338413
-- 1. Previous line must be a ### divider, or empty line after a request
339414
local valid_context = false
@@ -428,7 +503,13 @@ M.create_header_source = function()
428503
-- Check for request line pattern (HTTP method + URL)
429504
local is_request_line = line:match("^%s*[A-Z]+%s+%S+") ~= nil
430505

431-
if is_first_line or is_request_line then
506+
-- Check if we're inside a response handler script block
507+
local in_script_block = is_in_script_block()
508+
509+
-- Check if we're in a request body
510+
local in_body = is_in_request_body()
511+
512+
if is_first_line or is_request_line or in_script_block or in_body then
432513
callback({ items = {}, isIncomplete = false })
433514
return
434515
end
@@ -522,6 +603,61 @@ M.create_env_var_source = function()
522603
complete = function(self, request, callback)
523604
local cursor_before_line = request.context.cursor_before_line
524605

606+
-- Check if we're inside a script block - if so, we don't provide env var completions with {{ }}
607+
local in_script_block = is_in_script_block()
608+
609+
-- Inside script blocks, only provide completion for script context
610+
if in_script_block then
611+
local items = {}
612+
613+
-- Only add script-specific completions, without the {{ }} syntax
614+
table.insert(items, {
615+
label = "client.global.set",
616+
kind = 3, -- Function
617+
documentation = {
618+
kind = "markdown",
619+
value = "**client.global.set(key, value)**\n\nSets a global variable that will be available in subsequent requests.\n\nExample: `client.global.set(\"token\", response.body.token);`"
620+
},
621+
insertText = "client.global.set",
622+
})
623+
624+
table.insert(items, {
625+
label = "response.body",
626+
kind = 6, -- Variable
627+
documentation = {
628+
kind = "markdown",
629+
value = "**response.body**\n\nThe response body (parsed as JSON if possible).\n\nExample: `const data = response.body.data;`"
630+
},
631+
insertText = "response.body",
632+
})
633+
634+
table.insert(items, {
635+
label = "response.headers",
636+
kind = 6, -- Variable
637+
documentation = {
638+
kind = "markdown",
639+
value = "**response.headers**\n\nThe response headers.\n\nExample: `const contentType = response.headers['content-type'];`"
640+
},
641+
insertText = "response.headers",
642+
})
643+
644+
table.insert(items, {
645+
label = "response.status",
646+
kind = 6, -- Variable
647+
documentation = {
648+
kind = "markdown",
649+
value = "**response.status**\n\nThe HTTP status code.\n\nExample: `if (response.status === 200) { ... }`"
650+
},
651+
insertText = "response.status",
652+
})
653+
654+
callback({
655+
items = items,
656+
isIncomplete = true
657+
})
658+
return
659+
end
660+
525661
-- Check if we're typing inside {{ but before }}
526662
local match_start, match_end = cursor_before_line:find("{{[^}]*$")
527663

0 commit comments

Comments
 (0)