From e01f7649ed2850868b17982bbf1cf000a870f021 Mon Sep 17 00:00:00 2001 From: Grueslayer Date: Sat, 7 Sep 2024 17:17:18 +0200 Subject: [PATCH] Environment Scope (#216) * Environment Scope * rework(DB): naming like in prisma.io The reasoning behind this is to make it easier to find code that does updates, or just fetches a single item, or fetches the whole dataset. Additionally add global data which is currently only used for .replay(). .replay() should enable the user to run the last command in any buffer, not only in .http or .rest buffers. * rework(DB): naming like in prisma.io The reasoning behind this is to make it easier to find code that does updates, or just fetches a single item, or fetches the whole dataset. Additionally add global data which is currently only used for .replay(). .replay() should enable the user to run the last command in any buffer, not only in .http or .rest buffers. * move db_spec.lua --------- Co-authored-by: Jan Stocker Co-authored-by: Marco Kellershoff --- .../getting-started/configuration-options.md | 26 ++++++ lua/kulala/config/init.lua | 5 +- lua/kulala/db/init.lua | 80 +++++++++++++++++-- lua/kulala/external_processing/init.lua | 2 +- lua/kulala/internal_processing/init.lua | 12 +-- lua/kulala/parser/env.lua | 26 +++--- lua/kulala/parser/init.lua | 11 ++- lua/kulala/parser/request_variables.lua | 7 +- lua/kulala/ui/init.lua | 2 +- lua/kulala/ui/selector.lua | 5 +- lua/telescope/_extensions/kulala.lua | 7 +- tests/db/db_spec.lua | 24 ++++++ 12 files changed, 169 insertions(+), 38 deletions(-) create mode 100644 tests/db/db_spec.lua diff --git a/docs/docs/getting-started/configuration-options.md b/docs/docs/getting-started/configuration-options.md index a9182d33..18daea85 100644 --- a/docs/docs/getting-started/configuration-options.md +++ b/docs/docs/getting-started/configuration-options.md @@ -90,6 +90,9 @@ Here is a full example of setting up the Kulala plugin with the available `opts` -- disable the vim.print output of the scripts -- they will be still written to disk, but not printed immediately disable_script_print_output = false, + -- set scope for environment and request variables + -- possible values: b = buffer, g = global + environment_scope = "b", }, } ``` @@ -511,3 +514,26 @@ Example: }, } ``` +### environment_scope + +While using request variables the results will be stored for later use. +As usual variables they are file relevant and should be stored in the buffer. +If you want to share the variables between buffers you can use the global scope. + +Possible values: + +- `"b"` (buffer) +- `"g"` (global) + +Default: `"b"` + +Example: + +```lua +{ +"mistweaverco/kulala.nvim", + opts = { + environment_scope = "b", + }, +} +``` diff --git a/lua/kulala/config/init.lua b/lua/kulala/config/init.lua index 5a71867c..79590b9f 100644 --- a/lua/kulala/config/init.lua +++ b/lua/kulala/config/init.lua @@ -68,6 +68,9 @@ M.defaults = { -- disable the vim.print output of the scripts -- they will be still written to disk, but not printed immediately disable_script_print_output = false, + -- set scope for environment and request variables + -- possible values: b = buffer, g = global + environment_scope = "b", } M.default_contenttype = { @@ -76,7 +79,7 @@ M.default_contenttype = { pathresolver = nil, } -M.options = {} +M.options = M.defaults M.setup = function(config) M.options = vim.tbl_deep_extend("force", M.defaults, config or {}) diff --git a/lua/kulala/db/init.lua b/lua/kulala/db/init.lua index e7b780db..83566c51 100644 --- a/lua/kulala/db/init.lua +++ b/lua/kulala/db/init.lua @@ -1,10 +1,78 @@ +local CONFIG = require("kulala.config") + local M = {} -M.data = { - selected_env = nil, -- string - name of selected env - http_client_env = nil, -- table of envs from http-client.env.json - http_client_env_base = nil, -- table of base env values which should be applied to all requests - env = {}, -- table of envs from document sources -} +M.data = nil +M.global_data = {} + +local function default_data() + return { + selected_env = nil, -- string - name of selected env + http_client_env = nil, -- table of envs from http-client.env.json + http_client_env_base = nil, -- table of base env values which should be applied to all requests + env = {}, -- table of envs from document sources + scope_nr = nil, -- number - buffer number of the current scope + } +end + +local function get_current_scope_nr() + if CONFIG.get().environment_scope == "b" then + return vim.fn.bufnr() + elseif CONFIG.get().environment_scope == "g" then + return 0 + end +end + +local function load_data() + if CONFIG.get().environment_scope == "b" then + M.data = vim.b.kulala_data or default_data() + elseif CONFIG.get().environment_scope == "g" then + -- keep in lua only + if not M.data then + M.data = default_data() + end + end + M.data.scope_nr = get_current_scope_nr() +end + +local function save_data() + if CONFIG.get().environment_scope == "b" then + if vim.fn.bufexists(M.data.scope_nr) ~= -1 then + vim.b[M.data.scope_nr].kulala_data = M.data + end + elseif CONFIG.get().environment_scope == "g" then + -- keep in lua only + end +end + +M.global_find_many = function() + return M.global_data +end + +M.global_find_unique = function(key) + return M.global_data[key] +end + +M.global_update = function() + return M.global_data +end + +M.find_many = function() + if not M.data or not M.data.scope_nr then + load_data() + elseif M.data.scope_nr ~= get_current_scope_nr() then + save_data() + load_data() + end + return M.data +end + +M.update = function() + return M.find_many() +end + +M.find_unique = function(key) + return M.find_many()[key] +end return M diff --git a/lua/kulala/external_processing/init.lua b/lua/kulala/external_processing/init.lua index 69fe9627..a3f8637f 100644 --- a/lua/kulala/external_processing/init.lua +++ b/lua/kulala/external_processing/init.lua @@ -47,7 +47,7 @@ M.env_stdin_cmd = function(cmdstring, contents) end -- save the result to the environment variable - DB.data.env[env_name] = M.stdin_cmd(cmd_string, contents) + DB.update().env[env_name] = M.stdin_cmd(cmd_string, contents) end return M diff --git a/lua/kulala/internal_processing/init.lua b/lua/kulala/internal_processing/init.lua index 8eca9cd4..d62bbe33 100644 --- a/lua/kulala/internal_processing/init.lua +++ b/lua/kulala/internal_processing/init.lua @@ -106,11 +106,11 @@ M.set_env_for_named_request = function(name, body) cookies = get_cookies_as_table(), }, request = { - headers = DB.data.current_request.headers, - body = DB.data.current_request.body, + headers = DB.find_unique("current_request").headers, + body = DB.find_unique("current_request").body, }, } - DB.data.env[name] = named_request + DB.update().env[name] = named_request end M.env_header_key = function(cmd) @@ -122,7 +122,7 @@ M.env_header_key = function(cmd) if value == nil then vim.notify("env-header-key --> Header not found.", vim.log.levels.ERROR) else - DB.data.env[variable_name] = value + DB.update().env[variable_name] = value end end @@ -151,7 +151,7 @@ M.env_json_key = function(cmd, body) else local kv = vim.split(cmd, " ") local value = get_nested_value(json, kv[2]) - DB.data.env[kv[1]] = value + DB.update().env[kv[1]] = value end end @@ -163,7 +163,7 @@ M.prompt_var = function(metadata_value) if value == nil or value == "" then return false end - DB.data.env[key] = value + DB.update().env[key] = value return true end diff --git a/lua/kulala/parser/env.lua b/lua/kulala/parser/env.lua index 464cc608..12f615e7 100644 --- a/lua/kulala/parser/env.lua +++ b/lua/kulala/parser/env.lua @@ -13,8 +13,8 @@ M.get_env = function() env[key] = value end - DB.data.http_client_env_base = {} - DB.data.http_client_env = {} + DB.update().http_client_env_base = {} + DB.update().http_client_env = {} if Config.get().vscode_rest_client_environmentvars then local vscode_dir = FS.find_file_in_parent_dirs(".vscode") @@ -29,10 +29,11 @@ M.get_env = function() if settings and settings["rest-client.environmentVariables"] then local f = settings["rest-client.environmentVariables"] if f["$shared"] then - DB.data.http_client_env_base = vim.tbl_deep_extend("force", DB.data.http_client_env_base, f["$shared"]) + DB.update().http_client_env_base = + vim.tbl_deep_extend("force", DB.find_unique("http_client_env_base"), f["$shared"]) end f["$shared"] = nil - DB.data.http_client_env = vim.tbl_deep_extend("force", DB.data.http_client_env, f) + DB.update().http_client_env = vim.tbl_deep_extend("force", DB.find_unique("http_client_env"), f) end end end @@ -43,10 +44,11 @@ M.get_env = function() if settings and settings["rest-client.environmentVariables"] then local f = settings["rest-client.environmentVariables"] if f["$shared"] then - DB.data.http_client_env_base = vim.tbl_deep_extend("force", DB.data.http_client_env_base, f["$shared"]) + DB.update().http_client_env_base = + vim.tbl_deep_extend("force", DB.find_unique("http_client_env_base"), f["$shared"]) end f["$shared"] = nil - DB.data.http_client_env = vim.tbl_deep_extend("force", DB.data.http_client_env, f) + DB.update().http_client_env = vim.tbl_deep_extend("force", DB.find_unique("http_client_env"), f) end end end @@ -67,24 +69,26 @@ M.get_env = function() if http_client_env_json then local f = vim.fn.json_decode(vim.fn.readfile(http_client_env_json)) if f._base then - DB.data.http_client_env_base = vim.tbl_deep_extend("force", DB.data.http_client_env_base, f._base) + DB.update().http_client_env_base = vim.tbl_deep_extend("force", DB.find_unique("http_client_env_base"), f._base) end f._base = nil - DB.data.http_client_env = vim.tbl_deep_extend("force", DB.data.http_client_env, f) + DB.update().http_client_env = vim.tbl_deep_extend("force", DB.find_unique("http_client_env"), f) end - for key, value in pairs(DB.data.http_client_env_base) do + local http_client_env_base = DB.find_unique("http_client_env_base") or {} + for key, value in pairs(http_client_env_base) do if key ~= "DEFAULT_HEADERS" then env[key] = value end end - local selected_env = DB.data.http_client_env[vim.g.kulala_selected_env or Config.get().default_env] + local selected_env = DB.find_unique("http_client_env")[vim.g.kulala_selected_env or Config.get().default_env] if selected_env then env = vim.tbl_extend("force", env, selected_env) end - for key, value in pairs(DB.data.env) do + local db_env = DB.find_unique("env") or {} + for key, value in pairs(db_env) do env[key] = value end diff --git a/lua/kulala/parser/init.lua b/lua/kulala/parser/init.lua index 41379577..63375291 100644 --- a/lua/kulala/parser/init.lua +++ b/lua/kulala/parser/init.lua @@ -491,7 +491,7 @@ function M.parse(start_request_linenr) Scripts.javascript.run("pre_request", req.scripts.pre_request) local env = ENV_PARSER.get_env() - DB.data.previous_request = DB.data.current_request + DB.update().previous_request = DB.find_unique("current_request") document_variables = extend_document_variables(document_variables, req) @@ -531,8 +531,8 @@ function M.parse(start_request_linenr) end -- Merge headers from the _base environment if it exists - if DB.data.http_client_env_base then - local default_headers = DB.data.http_client_env_base["DEFAULT_HEADERS"] + if DB.find_unique("http_client_env_base") then + local default_headers = DB.find_unique("http_client_env_base")["DEFAULT_HEADERS"] if default_headers then for key, value in pairs(default_headers) do key = key:lower() @@ -664,7 +664,10 @@ function M.parse(start_request_linenr) if CONFIG.get().debug then FS.write_file(PLUGIN_TMP_DIR .. "/request.txt", table.concat(res.cmd, " "), false) end - DB.data.current_request = res + DB.update().current_request = res + -- Save this to global, + -- so .replay() can be triggered from any buffer or window + DB.global_update().replay = res return res end diff --git a/lua/kulala/parser/request_variables.lua b/lua/kulala/parser/request_variables.lua index c13bbfa1..d6ed6a69 100644 --- a/lua/kulala/parser/request_variables.lua +++ b/lua/kulala/parser/request_variables.lua @@ -43,7 +43,7 @@ local function get_config_contenttype(headers) end local function get_body_value_from_path(name, method, subpath) - local base_table = DB.data.env[name] + local base_table = DB.find_unique("env")[name] if not base_table then return nil end @@ -80,7 +80,7 @@ local function get_body_value_from_path(name, method, subpath) end local function get_header_value_from_path(name, method, subpath) - local base_table = DB.data.env[name] + local base_table = DB.find_unique("env")[name] if not base_table then return nil end @@ -110,7 +110,8 @@ local function get_header_value_from_path(name, method, subpath) end local function get_cookies_value_from_path(name, subpath) - local base_table = DB.data.env[name] + local db_env = DB.find_unique("env") + local base_table = db_env and db_env[name] or nil if not base_table then return nil end diff --git a/lua/kulala/ui/init.lua b/lua/kulala/ui/init.lua index 3db7f114..50c2972c 100644 --- a/lua/kulala/ui/init.lua +++ b/lua/kulala/ui/init.lua @@ -419,7 +419,7 @@ M.show_script_output = function() end M.replay = function() - local result = DB.data.current_request + local result = DB.global_find_unique("replay") if result == nil then vim.notify("No request to replay", vim.log.levels.WARN, { title = "kulala" }) return diff --git a/lua/kulala/ui/selector.lua b/lua/kulala/ui/selector.lua index acbae84a..be05e458 100644 --- a/lua/kulala/ui/selector.lua +++ b/lua/kulala/ui/selector.lua @@ -4,12 +4,13 @@ local FS = require("kulala.utils.fs") local M = {} function M.select_env() - if not DB.data.http_client_env then + local http_client_env = DB.find_unique("http_client_env") + if not http_client_env then return end local envs = {} - for key, _ in pairs(DB.data.http_client_env) do + for key, _ in pairs(http_client_env) do table.insert(envs, key) end diff --git a/lua/telescope/_extensions/kulala.lua b/lua/telescope/_extensions/kulala.lua index a2e9b74e..a8a07597 100644 --- a/lua/telescope/_extensions/kulala.lua +++ b/lua/telescope/_extensions/kulala.lua @@ -45,12 +45,13 @@ local function kulala_search(_) end local function kulala_env_select(_) - if not DB.data.http_client_env then + local http_client_env = DB.find_unique("http_client_env") + if not http_client_env then return end local envs = {} - for key, _ in pairs(DB.data.http_client_env) do + for key, _ in pairs(http_client_env) do table.insert(envs, key) end @@ -74,7 +75,7 @@ local function kulala_env_select(_) previewer = previewers.new_buffer_previewer({ title = "Environment", define_preview = function(self, entry) - local env = DB.data.http_client_env[entry.value] + local env = http_client_env[entry.value] if env == nil then return end diff --git a/tests/db/db_spec.lua b/tests/db/db_spec.lua new file mode 100644 index 00000000..e6d4f476 --- /dev/null +++ b/tests/db/db_spec.lua @@ -0,0 +1,24 @@ +local DB = require("kulala.db") + +describe("db scoped", function() + it("should not leak into other buffers", function() + vim.cmd("new") + local buf1 = vim.api.nvim_get_current_buf() + DB.update().key1 = "value1" + assert.equal(DB.find_unique("key1"), "value1") + + vim.cmd("new") + local buf2 = vim.api.nvim_get_current_buf() + DB.update().key2 = "value2" + assert.equal(DB.find_unique("key1"), nil) + assert.equal(DB.find_unique("key2"), "value2") + + vim.api.nvim_set_current_buf(buf1) + assert.equal(DB.find_unique("key1"), "value1") + assert.equal(DB.find_unique("key2"), nil) + + vim.api.nvim_set_current_buf(buf2) + assert.equal(DB.find_unique("key1"), nil) + assert.equal(DB.find_unique("key2"), "value2") + end) +end)