Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
93a6832
feat(parser): add opts `urlencode_skip/force`, add `[]` to default
YaroSpace Aug 27, 2025
4374ef4
perf(formatter): call external formatters only once
YaroSpace Aug 28, 2025
8ccd47e
feat(formatter): add formatting for js and lua
YaroSpace Aug 31, 2025
7608986
fix(parser): allow all chars in multiline url
YaroSpace Aug 31, 2025
0d03fe7
feat(ui): add syntax hl for grpc errors
YaroSpace Sep 1, 2025
bffa208
sync main
YaroSpace Sep 1, 2025
8d39217
fix(formatter): typos
YaroSpace Sep 1, 2025
d981ad8
fix(grammar): allow `.` and `[]` in variables
YaroSpace Sep 2, 2025
576e374
fix(parser): make headers lookup case insensitive
YaroSpace Sep 4, 2025
f98e011
fix(oauth): pkce verifier/challenge generation
YaroSpace Sep 6, 2025
81bf97f
fix(oauth): defer coroutine resume in callback
YaroSpace Sep 8, 2025
edf3516
fix(oauth): manual token acquire
YaroSpace Sep 10, 2025
f3ef231
docs(recipes): update variables in http-profile.env.json from scripts
YaroSpace Sep 12, 2025
47daed2
fix(formatter): check for invalid channel
YaroSpace Sep 13, 2025
43ec0c7
sync main
YaroSpace Sep 14, 2025
d4ea827
release(5.3.3)
YaroSpace Sep 14, 2025
60ed249
sync main
YaroSpace Sep 14, 2025
1c0f6f9
docs: update
YaroSpace Sep 14, 2025
5ff0308
sync main
YaroSpace Sep 14, 2025
2c9b610
feat(ui): add env to response summary
YaroSpace Sep 18, 2025
f5e7dba
docs: Removed plain basic auth separated with spaces (#690)
icalvo Sep 19, 2025
0edffc7
feat(ui): add `winbar_labels` and `winbar_labels_keymaps` config options
YaroSpace Sep 20, 2025
aff4a9b
feat: custom_dynamic_variables
YaroSpace Sep 24, 2025
5d34559
fix(formatter): retry on error
YaroSpace Sep 26, 2025
5f69150
feat(cmd): support `run` commands with metadata and without URL
YaroSpace Sep 26, 2025
da896bd
feat(ui): add toggle split/float display mode `|`
YaroSpace Sep 26, 2025
5dd5ff8
fix(parser): do not throw when cancel prompt
YaroSpace Sep 26, 2025
5974be7
chore(deps): bump on-headers and compression in /docs (#699)
dependabot[bot] Sep 26, 2025
fdfd27f
fix(lsp): do not trigger folding for unloaded buffer
YaroSpace Sep 27, 2025
eff240f
fix(cmd): allow replay with variables
YaroSpace Sep 28, 2025
71c9038
sync main
YaroSpace Sep 28, 2025
ecf95e6
sync main
YaroSpace Sep 28, 2025
3edb39b
fix(parser): do not include `###` on last line into request
YaroSpace Sep 30, 2025
54fc8e6
docs(recipes): iterating over response results, modifying request json
YaroSpace Sep 30, 2025
cadfce5
fix(ui): open float when vim.o.columns/lines = 0
YaroSpace Oct 6, 2025
2260121
Add cookies to graphql introspection request (#707)
rafaelsmgomes Oct 7, 2025
cccaa80
feat(parser): shared block
YaroSpace Oct 4, 2025
a9a79d6
refact(parser): remove global-curl/grpc flags in favor of Shared blocks
YaroSpace Oct 11, 2025
d51dbce
refact(parser): move variables into request obj
YaroSpace Oct 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Version 5.3.4

### Feature: `Shared blocks` [Shared blocks](usage/shared-blocks.md)
### Breaking changes: deprecate `curl-global` and `grpc-global` flags in favor of flags in `Shared` block
### Enhancement: add `winbar_labels` and `winbar_labels_keymaps` config options to customize winbar labels [Configuration](getting-started/configuration-options.mdx)
### Feature: support for `custom_dynamic_variables`
### Feature: support `run` command with metadata and without URL [Import and Run](usage/import-and-run-http.md)
Expand Down
7 changes: 7 additions & 0 deletions docs/docs/getting-started/configuration-options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ Example:
}
```

### variables_scope

Set variable scope: "document" - variables shared across all requests in the document, no matter where they are defined, later declarations shadow earlier ones.
"request" - variables scoped to the request they are defined in, variables in Shared block are immutable.

Default: `document`

### custom_dynamic_variables

Define your own dynamic variables here, e.g. $randomEmail
Expand Down
23 changes: 22 additions & 1 deletion docs/docs/scripts/lua-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,31 @@ Authorization: Bearer {{TOKEN}}

:::tip

If you want to modify request URL, use `request.url_raw`.
If you want to modify request URL, headers or body, use `request.url_raw`, `request.headers_raw` or `request.body_raw` respectively.

:::

### Changing JSON body of a request

```http
### Change JSON body

< {%
-- lua
local json = require("kulala.utils.json")
local body = json.parse(request.body)

body.your_var = "whatever"
request.body_raw = json.encode(body)
%}

POST http://httpbin.org/post HTTP/1.1

{
"your_var": "original_value"
}
```

### Iterating over results and making requests for each item

```http
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/usage/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ For example:
:::info

If you need to set custom curl flags for authentication requests, e.g., `--insecure` to skip secure connection verification - you can do this
with `# @curl-global-..` flags in your .http file or by setting `additional_curl_options` in Kulala's config.
with `# @curl-..` flags in your .http file `Shared` block or by setting `additional_curl_options` in Kulala's config.

:::

Expand Down Expand Up @@ -570,4 +570,4 @@ In the http-client.private.env.json file, add `verifyHostCertificate": false` to

If you run a request with this environment, the certificate verification will be disabled.

This is equivalent to setting `--insecure` flag in `additional_curl_options` in the config file or with `# @curl-global-insecure` in the request.
This is equivalent to setting `--insecure` flag in `additional_curl_options` in the config file or with `# @curl-insecure` in the request.
4 changes: 2 additions & 2 deletions docs/docs/usage/basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ require("nvim-lightbulb").setup({
#### Directives

- `# @accept chunked` allows you to accept Transfer-Encoding: chunked responses and streamed responses.
- `# @curl-global-...` and `# @curl-...` allows you to set global and per-request flags for curl requests.
- `# @grpc-global-...` and `# @grpc-...` allows you to set global and per-request flags for gRPC requests.
- `# @curl-...` allows you to set flags for curl requests.
- `# @grpc-...` allows you to set flags for gRPC requests.
- `# @stdin-cmd-pre` allows you to execute an external command before the request is sent.
- `# @stdin-cmd` allows you to execute an external command
- `# @jq` allows you to filter the response body using jq.
Expand Down
18 changes: 7 additions & 11 deletions docs/docs/usage/custom-curl-flags.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
# Custom Curl Flags

- You can customize the curl command used to make requests in Kulala, on a per-request basis or globally for all requests in a buffer.
- You can customize the curl command used to make requests in Kulala, on a per-request basis or globally for all requests in a buffer, if included in the `Shared` block.

## Usage

- Local flags: `# @curl-..` apply for current request only.
- Global flags: `# @curl-global-..` apply when running all requests in a buffer.
Use `# @curl-..` prefix, followed by the curl flag you want to use.

```http
# @curl-global-compressed
# @curl-global-non-buffer

# @curl-compressed
# @curl-non-buffer
# @curl-location

GET /api/get
Host: example.com
```

:::warning

Local flags take precedence over global flags.
:::info

If you need to apply curl flags to OAuth requests, you have to use `# @curl-global-..` flags.
If you need to apply curl flags to OAuth requests, you have to put it into `Shared` block.

In order for global flags to take effect, the request where they are defined must be run at least once.
:::

### Some common curl flags you might want to use:
Expand Down
23 changes: 9 additions & 14 deletions docs/docs/usage/grpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ Ensure you have `grpcurl` installed to use this feature. You can find it here: [
To make a gRPC request, use the following format:

```http
# @grpc-global-flags
# @grpc-flags
GRPC flags address command service.method
```

For example:

```http
# @grpc-global-import-path ../protos
# @grpc-global-proto helloworld.proto
### Shared

# @grpc-import-path ../protos
# @grpc-proto helloworld.proto

###

GRPC localhost:50051 helloworld.Greeter/SayHello
Content-Type: application/json

Expand All @@ -48,10 +52,7 @@ GRPC helloworld.Greeter/SayHello

### Flags

Flags can be set through metadata either locally per request or globally per buffer. Use the following formats:

- Local flags: `@grpc-..` apply for current request only.
- Global flags: `@grpc-global-..` apply for all requests in the buffer. Global settings will persist until the buffer is closed or globals are cleared with `<leaderRx>`.
Flags can be set through metadata either locally per request or globally per buffer, if included in the `Shared` block.

### Variables

Expand All @@ -61,15 +62,9 @@ Just as with HTTP requests, you can use variables in gRPC requests. For example:
@address=localhost:50051
@service=helloworld.Greeter
@flags=-import-path ../protos -proto helloworld.proto -- [!] flags must be prefixed with `-`

GRPC {{flags}} {{address}} {{service}}/SayHello
Content-Type: application/json

< /path/to/file.json
```

:::warning

Flags set in variables override flags set in metatadata, which in turn override global flags.
In order for global flags to take effect, the request where they are defined must be run at least once.

:::
60 changes: 60 additions & 0 deletions docs/docs/usage/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,63 @@ Content-Type: application/json
console.log(vars);
%}
```

### Changing JSON body of a request

```http
### Change JSON body

< {%
-- lua
local json = require("kulala.utils.json")
local body = json.parse(request.body)

body.your_var = "whatever"
request.body_raw = json.encode(body)
%}

POST http://httpbin.org/post HTTP/1.1

{
"your_var": "original_value"
}
```

### Iterating over results and making requests for each item

```http
### Request_one

POST https://httpbin.org/post HTTP/1.1
Accept: application/json
Content-Type: application/json

{
"results": [
{ "id": 1, "desc": "some_username" },
{ "id": 2, "desc": "another_username" }
]
}

### Request_two

< {%
-- lua
local response = client.responses["Request_one"].json -- get body of the response decoded as json
if not response then return end

local item = response.json.results[request.iteration()]
if not item then return request.skip() end -- skip if no more items

client.log(item)
request.url_raw = request.environment.url .. "?" .. item.desc
%}

@url = https://httpbin.org/get
GET {{url}}

> {%
-- lua
request.replay()
%}
```
76 changes: 76 additions & 0 deletions docs/docs/usage/shared-blocks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Shared Blocks

Shared blocks can be used to share variables, metadata, scripts and requests between multiple requests.

To declare a shared block, use the `### Shared` or `### Shared each` request name for the `first` request in the document.

Shared variables and metadata will apply to all requests that follow the shared block.
Variables and metadata declared in a request will shadow shared variables and metadata.

Scripts and requests declared in the shared block and called with `run` command will be executed before the request you run.

## `### Shared` block

- When executing `run request`, the shared scripts and requests will be executed before the request you run.
- When executing `run all requests`, the shared scripts and requests will be executed `once` before all requests.

## `### Shared each` block

- When executing `run request`, the shared scripts and requests will be executed before the request you run.
- When executing `run all requests`, the shared scripts and requests will be executed before `each` request.

## Variable Scope

By default variables are scoped to `document`, which means they are shared across all requests in the document
and later declarations will override previous ones, including the ones in shared blocks.

You can change the scope to `variables_scope = "request"` in the options, which will make variables scoped to the current request only
and shared variables will not be overridden by request variables.

```http
### Shared

@shared_var_1 = shared_value_1
@shared_var_2 = shared_value_2

# @curl-connect-timeout 20
# @curl-location

run ./login.http

< {%
console.log("pre request 0");
%}

< ./pre_request.js

POST https://httpbin.org/post HTTP/1.1
Content-Type: application/json

{
"shared_var_1": 1,
"shared_var_2": 2
}

> ./post_request.js

> {%
console.log("post request 0");
%}


### request 1

@local_var_1 = local_value_1
@shared_var_2 = local_value_2

# @curl-connect-timeout 10

POST https://httpbin.org/post HTTP/1.1
Content-Type: application/json

{
"shared_var_1": 3,
"shared_var_2": 4
}
```
7 changes: 7 additions & 0 deletions docs/docs/usage/using-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ you will be prompted to enter a value for `pokemon`.

These variables are available for the current request and
all subsequent requests in the file.

## Variables scope

By default, variables are scoped to the entire document, i.e., they are available in all requests in the file,
no matter where they are declared and later declarations will override earlier ones.

You can change the scope to `variables_scope = "request"` in the options, which will make variables scoped to the current request only.
3 changes: 2 additions & 1 deletion docs/sidebars.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';

const sidebars: SidebarsConfig = {
defaultSidebar: [
Expand Down Expand Up @@ -38,6 +38,7 @@ const sidebars: SidebarsConfig = {
"usage/magic-variables",
"usage/authentication",
"usage/import-and-run-http",
"usage/shared-blocks",
"usage/reading-file-data",
"usage/filter-response",
"usage/redirect-the-response",
Expand Down
2 changes: 1 addition & 1 deletion lua/cli/colors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ M.print = function(str, hl_group)
end

M.print_buf = function(buf)
--TODO: optimize be reading end line and end column
--TODO: optimize by reading end line and end column

local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
local char, char_i, color_char
Expand Down
10 changes: 5 additions & 5 deletions lua/cli/kulala_cli.lua
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ local function print_response()
end

local get_requests = function()
local variables, requests = Parser.get_document()
if args.list or #args.name + #args.line == 0 then return requests, variables end
local requests = Parser.get_document()
if args.list or #args.name + #args.line == 0 then return requests end

requests = vim
.iter(requests)
Expand All @@ -159,7 +159,7 @@ local get_requests = function()
end)
:totable()

return requests, variables
return requests
end

local function is_last()
Expand All @@ -173,7 +173,7 @@ local function run_file(file)
local buf = vim.fn.bufnr(file)
Db.set_current_buffer(buf)

local requests, variables = get_requests()
local requests = get_requests()
if #requests == 0 then return Logger.error("No requests found in " .. file) end

if args.list then return print_requests(file, requests) end
Expand All @@ -182,7 +182,7 @@ local function run_file(file)
local processing = true
local status = true

Cmd.run_parser(requests, variables, 0, function()
Cmd.run_parser(requests, 0, function()
io.write("*")

db.current_response_pos = #db.responses
Expand Down
4 changes: 2 additions & 2 deletions lua/kulala/augroups/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ local show_variable_info_text = function()
local line = vim.api.nvim_get_current_line()
local env = Env.get_env() or {}

local document_variables = Parser.get_document() or {}
local variables = vim.tbl_extend("force", document_variables, env)
local request = Parser.get_document() or {}
local variables = vim.tbl_extend("force", request.variables, env)

-- get variable under cursor
-- a variable is a string that starts with two {{ and ends with two }}
Expand Down
Loading