2
0
Fork 0

first work on API

This commit is contained in:
Luca Bilke 2024-04-18 16:47:37 +02:00
commit f621decc97
No known key found for this signature in database
GPG Key ID: AD6630D0A1E650AC
7 changed files with 261 additions and 0 deletions

8
.editorconfig Normal file
View File

@ -0,0 +1,8 @@
root = true
[*.lua]
charset = utf-8
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

9
.luacheckrc Normal file
View File

@ -0,0 +1,9 @@
ignore = {
"631", -- max_line_length
}
read_globals = {
"vim",
"describe",
"it",
"assert"
}

15
LICENSE Normal file
View File

@ -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.

22
README.md Normal file
View File

@ -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

View File

@ -0,0 +1,3 @@
local M = {}
return M

27
lua/transformer/init.lua Normal file
View File

@ -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

View File

@ -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