@@ -72,6 +72,70 @@ local function add_to_recent(var)
72
72
end
73
73
end
74
74
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
+
75
139
-- Get all available variables from current environment
76
140
local function get_env_variables ()
77
141
local env = environment .get_current_env () or {}
@@ -334,6 +398,17 @@ M.create_method_source = function()
334
398
return
335
399
end
336
400
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
+
337
412
-- Check if we're in a good context for method completion:
338
413
-- 1. Previous line must be a ### divider, or empty line after a request
339
414
local valid_context = false
@@ -428,7 +503,13 @@ M.create_header_source = function()
428
503
-- Check for request line pattern (HTTP method + URL)
429
504
local is_request_line = line :match (" ^%s*[A-Z]+%s+%S+" ) ~= nil
430
505
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
432
513
callback ({ items = {}, isIncomplete = false })
433
514
return
434
515
end
@@ -522,6 +603,61 @@ M.create_env_var_source = function()
522
603
complete = function (self , request , callback )
523
604
local cursor_before_line = request .context .cursor_before_line
524
605
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\n Sets a global variable that will be available in subsequent requests.\n\n Example: `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\n The response body (parsed as JSON if possible).\n\n Example: `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\n The response headers.\n\n Example: `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\n The HTTP status code.\n\n Example: `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
+
525
661
-- Check if we're typing inside {{ but before }}
526
662
local match_start , match_end = cursor_before_line :find (" {{[^}]*$" )
527
663
0 commit comments