first work on API
This commit is contained in:
commit
f621decc97
|
@ -0,0 +1,8 @@
|
|||
root = true
|
||||
|
||||
[*.lua]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
|
@ -0,0 +1,9 @@
|
|||
ignore = {
|
||||
"631", -- max_line_length
|
||||
}
|
||||
read_globals = {
|
||||
"vim",
|
||||
"describe",
|
||||
"it",
|
||||
"assert"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
ISC License
|
||||
|
||||
Copyright 2024 Luca Bilke
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,22 @@
|
|||
# transformer.nvim
|
||||
|
||||
## Development
|
||||
|
||||
### Run tests
|
||||
|
||||
Running tests requires [plenary.nvim][plenary] to be checked out in the parent
|
||||
directory of *this* repository. You can then run:
|
||||
|
||||
```bash
|
||||
nvim --headless --noplugin -u tests/minimal.vim \
|
||||
-c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal.vim'}"
|
||||
```
|
||||
|
||||
Or if you want to run a single test file:
|
||||
|
||||
```bash
|
||||
nvim --headless --noplugin -u tests/minimal.vim \
|
||||
-c "PlenaryBustedDirectory tests/path_to_file.lua {minimal_init = 'tests/minimal.vim'}"
|
||||
```
|
||||
|
||||
[plenary]: https://github.com/nvim-lua/plenary.nvim
|
|
@ -0,0 +1,3 @@
|
|||
local M = {}
|
||||
|
||||
return M
|
|
@ -0,0 +1,27 @@
|
|||
local M = {}
|
||||
|
||||
---@alias provider_name "anthropic"
|
||||
---@alias hook_name "request_started" | "request_finished"
|
||||
M.opts = {
|
||||
anthropic = {
|
||||
hooks = {
|
||||
request_started = nil,
|
||||
request_finished = nil,
|
||||
},
|
||||
api_url = nil, -- TODO: set default
|
||||
token = nil,
|
||||
},
|
||||
}
|
||||
|
||||
M.state = {
|
||||
anthropic = {
|
||||
num_callbacks = 0,
|
||||
spinner_index = 0,
|
||||
},
|
||||
}
|
||||
|
||||
function M.setup(opts)
|
||||
M.opts = vim.tbl_deep_extend("force", M._G.opts, opts)
|
||||
end
|
||||
|
||||
return M
|
|
@ -0,0 +1,177 @@
|
|||
local opts = require("transformer").opts
|
||||
local state = require("transformer").state
|
||||
|
||||
---@alias curl_callback fun(deserialized: table<string, any>)
|
||||
|
||||
---@class curl_opts
|
||||
---@field url string The url to make the request to
|
||||
---@field query table url query, append after the url
|
||||
---@field body string | table The request body, can be a path to a file
|
||||
---@field auth string | table Basic request auth, 'user:pass', or {"user", "pass"}
|
||||
---@field form table request form
|
||||
---@field raw table any additonal curl args
|
||||
---@field dry_run boolean whether to return the args to be ran through curl
|
||||
---@field output string download destination filepath
|
||||
---@field timeout integer request timeout in mseconds
|
||||
---@field http_version "HTTP/0.9" | "HTTP/1.0" | "HTTP/1.1" | "HTTP/2" | "HTTP/3" HTTP version to use
|
||||
---@field proxy string proxy url in this format: [protocol://]host[:port]
|
||||
---@field insecure boolean Allow insecure server connections
|
||||
|
||||
---@class curl_response
|
||||
---@field exit integer The shell process exit code
|
||||
---@field status integer The https response status
|
||||
---@field headers table The https response headers
|
||||
---@field body string The http response body
|
||||
|
||||
local M = {}
|
||||
|
||||
local spinner = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
}
|
||||
|
||||
--- TODO: Document this function
|
||||
---
|
||||
---@param provider provider_name
|
||||
---@return string spinner
|
||||
function M.get_spinner(provider)
|
||||
local p = state[provider]
|
||||
|
||||
if p.num_callbacks == 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
p.spinner_index = p.spinner_index + 1
|
||||
return spinner[p.spinner_index % #spinner + 1]
|
||||
end
|
||||
|
||||
--- TODO: Document this function
|
||||
---
|
||||
---@param provider provider_name
|
||||
---@param hook hook_name
|
||||
local function run_hook(provider, hook)
|
||||
local p = state[provider]
|
||||
|
||||
if hook == "request_started" then
|
||||
p.num_callbacks = p.num_callbacks + 1
|
||||
elseif hook == "request_finished" then
|
||||
p.num_callbacks = p.num_callbacks - 1
|
||||
end
|
||||
|
||||
pcall(M.opts[provider].hooks[hook])
|
||||
end
|
||||
|
||||
--- # Curl exit code test
|
||||
---
|
||||
--- Tests the curl exit code and notifies the user if something went wrong.
|
||||
---@param exit_code integer
|
||||
---@return boolean
|
||||
function M.test_code(exit_code)
|
||||
if exit_code == 127 then
|
||||
vim.notify("transformer.util couldn't find curl binary in path", vim.log.levels.ERROR)
|
||||
return false
|
||||
elseif exit_code ~= 0 then
|
||||
vim.notify("transformer.util unkown curl exit code: " .. exit_code, vim.log.levels.ERROR)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- TODO: Document this function
|
||||
---
|
||||
---@param provider provider_name
|
||||
---@return table<string, string>? headers
|
||||
local function make_headers(provider)
|
||||
local headers = { Content_Type = "application/json" }
|
||||
|
||||
if not opts[provider].token then
|
||||
vim.notify("transformer.util no API key provided for " .. provider, vim.log.levels.ERROR)
|
||||
return headers
|
||||
end
|
||||
|
||||
return vim.tbl_deep_extend("force", headers, { Authorization = "Bearer " .. opts[provider].token })
|
||||
end
|
||||
|
||||
--- TODO: Document this function
|
||||
---
|
||||
---@param provider provider_name
|
||||
---@param response curl_response
|
||||
---@param callback curl_callback
|
||||
local function curl_callback(provider, response, callback)
|
||||
if response.status ~= 200 then
|
||||
response.body = response.body:gsub("%s+", " ")
|
||||
print("Error: " .. response.status .. " " .. response.body)
|
||||
return
|
||||
end
|
||||
|
||||
if response.body == nil or response.body == "" then
|
||||
vim.notify("transformer.util empty response body", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
vim.schedule_wrap(function(body)
|
||||
local ok, result = pcall(vim.fn.json_decode, body)
|
||||
if ok then
|
||||
callback(result)
|
||||
else
|
||||
vim.notify("transformer.util failed to decode json: " .. result, vim.log.levels.ERROR)
|
||||
end
|
||||
end)(response.body)
|
||||
|
||||
run_hook(provider, "request_finished")
|
||||
end
|
||||
|
||||
--- TODO: Document this function
|
||||
---
|
||||
---@param provider provider_name
|
||||
---@param payload table<string, any>
|
||||
---@param callback fun(decoded: table<string, any>): nil
|
||||
function M.call(provider, payload, callback)
|
||||
local payload_str = vim.fn.json_encode(payload)
|
||||
local url = opts[provider].api_url
|
||||
local headers = make_headers(provider)
|
||||
|
||||
if type(opts[provider].hooks.request_started) == "function" then
|
||||
opts[provider].hooks.request_started()
|
||||
else
|
||||
vim.notify("transformer.util non-function variable set as hook for " .. provider, vim.log.levels.WARNING)
|
||||
end
|
||||
|
||||
require("plenary.curl").post(url, {
|
||||
body = payload_str,
|
||||
headers = headers,
|
||||
callback = function(response)
|
||||
curl_callback(provider, response, callback)
|
||||
end,
|
||||
on_error = function(err)
|
||||
vim.notify("transformer.util curl error from: " .. err.message, vim.log.levels.WARNING)
|
||||
run_hook(provider, "request_finished")
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
Loading…
Reference in New Issue