Skip to content

Commit d0750f1

Browse files
committed
refactor: remove plenary as a dependency
1 parent 42753a7 commit d0750f1

File tree

3 files changed

+143
-78
lines changed

3 files changed

+143
-78
lines changed

README.md

+1-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ https://user-images.githubusercontent.com/12272702/175755866-62be0b6c-31b2-4f45-
1010

1111
- [Features](#features)
1212
- [Dependencies](#dependencies)
13-
- [Required](#required)
14-
- [Optional](#optional)
1513
- [Installation](#installation)
1614
- [Setup](#setup)
1715
- [Usage](#usage)
@@ -27,11 +25,7 @@ https://user-images.githubusercontent.com/12272702/175755866-62be0b6c-31b2-4f45-
2725

2826
## Dependencies
2927

30-
### Required
31-
32-
- [Plenary](https://github.com/nvim-lua/plenary.nvim)
33-
34-
### Optional
28+
You can use the plugin without any dependencies, but if you have any of the following plugins installed, the plugin will use them to enhance the experience:
3529

3630
- [Telescope](https://github.com/nvim-telescope/telescope.nvim) or [fzf-lua](https://github.com/ibhagwan/fzf-lua)
3731

lua/forem-nvim/api.lua

+140-70
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
local M = {}
2-
local curl = require("plenary.curl")
3-
local job = require("plenary.job")
42
local notify = require("forem-nvim.notify")
53
local article = require("forem-nvim.article")
64

@@ -10,125 +8,197 @@ end
108

119
local BASE_URL = "https://dev.to/api"
1210

13-
local function handle_async_error(response)
14-
notify.error("Error: " .. tostring(response.body.error))
15-
end
11+
---@class Response
12+
---@field status number
13+
---@field body table
14+
15+
---@alias Method "GET" | "POST" | "PUT" | "DELETE"
1616

17+
---@param response Response
18+
---@param on_success fun(body: table)
1719
function M.handle_error(response, on_success)
1820
local start_status = string.sub(response.status, 1, 2)
1921

2022
if start_status == "20" then
2123
on_success(response.body)
2224
else
23-
notify.error("Error: " .. tostring(response.body.error))
25+
local error = response
26+
if response.body then
27+
error = response.body
28+
if response.body.error then
29+
error = response.body.error
30+
end
31+
end
32+
notify.error("Error: " .. tostring(error))
33+
end
34+
end
35+
36+
---@param out vim.SystemCompleted
37+
---@return Response
38+
local function system_completed_to_response(out)
39+
local status_code = nil
40+
local response_body = nil
41+
42+
if out.stdout then
43+
-- Extract status code from headers
44+
status_code = out.stdout:match("HTTP/%d%.?%d?%s+(%d+)")
45+
46+
-- Extract the body from the response (everything after the headers)
47+
response_body = out.stdout:match("\n\n(.*)")
48+
end
49+
50+
local body = nil
51+
-- Only attempt to decode if we have a body
52+
if response_body and response_body ~= "" then
53+
-- Protect against JSON decode errors
54+
body = vim.fn.json_decode(response_body)
2455
end
56+
57+
return {
58+
status = status_code,
59+
body = body
60+
}
2561
end
2662

27-
local function request(request_function, endpoint, options)
63+
---@param method Method
64+
---@param endpoint string
65+
---@param options table
66+
---@param on_exit fun(response: Response)?
67+
---@return vim.SystemObj
68+
local function curl(method, endpoint, options, on_exit)
69+
local headers = options.headers or {}
70+
local request_body = options.body and { "-d", vim.fn.json_encode(options.body) } or {}
71+
72+
local cmd = vim.iter({
73+
"curl",
74+
"-X",
75+
method,
76+
"-i", -- Include headers in the output
77+
vim.tbl_map(function(header)
78+
return { "-H", header }
79+
end, headers),
80+
request_body,
81+
BASE_URL .. endpoint
82+
}):flatten(2):totable()
83+
84+
return vim.system(cmd, { text = true }, function(out)
85+
vim.schedule(function()
86+
local response = system_completed_to_response(out)
87+
if on_exit then
88+
on_exit(response)
89+
end
90+
end)
91+
end)
92+
end
93+
94+
---@param method Method
95+
---@param endpoint string
96+
---@param options table
97+
---@return Response
98+
local function request(method, endpoint, options)
2899
local parameters = vim.tbl_extend(
29100
"force",
30101
{
31-
url = BASE_URL .. endpoint,
32102
headers = {
33-
["api-key"] = M.key(),
34-
content_type = "application/json",
35-
accept = "application/vnd.forem.api-v1+json"
103+
"api-key: " .. M.key(),
104+
"Content-Type: application/json",
105+
"Accept: application/vnd.forem.api-v1+json"
36106
}
37107
},
38108
options
39109
)
40-
local response = request_function(parameters)
41-
if response.body then
42-
return vim.tbl_extend(
43-
"force",
44-
response,
45-
{ body = vim.fn.json_decode(response.body) }
46-
)
47-
end
110+
111+
local out = curl(method, endpoint, parameters, nil):wait()
112+
local response = system_completed_to_response(out)
113+
48114
return response
49115
end
50116

51-
local function request_async(method, endpoint, options, on_success, on_error)
52-
-- TODO: Check if this could be done with `vim.system`
53-
return job:new({
54-
command = "curl",
55-
args = {
56-
"-X",
57-
method,
58-
"-H",
59-
"Content-Type: application/json",
60-
"-H",
61-
"Accept: application/vnd.forem.api-v1+json",
62-
"-H",
63-
"api-key: " .. tostring(M.key()),
64-
"-d",
65-
vim.fn.json_encode(options),
66-
BASE_URL .. endpoint
67-
},
68-
on_exit = function(this_job, code)
69-
vim.schedule(function()
70-
local result = table.concat(
71-
this_job:result(),
72-
"\n"
73-
)
74-
local response = vim.fn.json_decode(result)
75-
if code == 0 then
76-
on_success(response)
77-
return
78-
end
79-
handle_async_error(response)
80-
if on_error then
81-
on_error(response)
82-
end
83-
end)
84-
end
85-
}):start()
117+
---@param method Method
118+
---@param endpoint string
119+
---@param on_success fun(body: table)
120+
local function request_async(method, endpoint, on_success)
121+
local options = {
122+
headers = {
123+
"Api-Key: " .. M.key()
124+
}
125+
}
126+
127+
curl(method, endpoint, options, function(response)
128+
M.handle_error(
129+
response,
130+
on_success
131+
)
132+
end
133+
)
86134
end
87135

88-
local function get(endpoint, on_success, on_error)
89-
return request_async(
136+
---@param endpoint string
137+
---@param on_success fun(body: table)
138+
local function get(endpoint, on_success)
139+
request_async(
90140
"GET",
91141
endpoint,
92-
{},
93-
on_success,
94-
on_error
142+
on_success
95143
)
96144
end
97145

146+
---@param endpoint string
147+
---@param body table
148+
---@return Response
98149
local function put(endpoint, body)
99-
return request(curl.put, endpoint, { body = body })
150+
return request("PUT", endpoint, { body = body })
100151
end
101152

153+
---@param endpoint string
154+
---@param body table
155+
---@return Response
102156
local function post(endpoint, body)
103-
return request(curl.post, endpoint, { body = body })
157+
return request("POST", endpoint, { body = body })
104158
end
105159

106-
function M.my_articles(on_success, on_error) return get("/articles/me/all", on_success, on_error) end
160+
---@param on_success fun(body: table)
161+
function M.my_articles(on_success)
162+
return get("/articles/me/all", on_success)
163+
end
107164

165+
---@param id number
166+
---@param content string
167+
---@return Response
108168
function M.save_article(id, content)
109169
return put(
110170
"/articles/" .. tostring(id),
111-
vim.fn.json_encode({ article = { body_markdown = content } })
171+
{ article = { body_markdown = content } }
112172
)
113173
end
114174

175+
---@param title string
176+
---@return Response
115177
function M.new_article(title)
116178
return post(
117179
"/articles",
118-
vim.fn.json_encode({ article = { body_markdown = article.get_template(title) } })
180+
{ article = { body_markdown = article.get_template(title) } }
119181
)
120182
end
121183

122-
function M.feed(on_success, on_error) return get("/articles", on_success, on_error) end
184+
---@param on_success fun(body: table)
185+
function M.feed(on_success)
186+
get("/articles", on_success)
187+
end
123188

124-
function M.get_article(id, on_success, on_error)
125-
return get(
189+
---@param id number
190+
---@param on_success fun(body: table)
191+
function M.get_article(id, on_success)
192+
get(
126193
"/articles/" .. tostring(id),
127-
on_success,
128-
on_error
194+
on_success
129195
)
130196
end
131197

132-
function M.get_article_by_path(path, on_success, on_error) return get("/articles/" .. path, on_success, on_error) end
198+
---@param path string
199+
---@param on_success fun(body: table)
200+
function M.get_article_by_path(path, on_success)
201+
get("/articles/" .. path, on_success)
202+
end
133203

134204
return M

lua/forem-nvim/picker.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ function M.my_articles(articles)
112112
vim.ui.select(vim.tbl_map(function(article) return article.title end, articles), {
113113
prompt = "My Articles",
114114
}, function(selection)
115-
buffer.open_my_article(articles[selection])
115+
local article = vim.tbl_filter(function(a) return a.title == selection end, articles)[1]
116+
buffer.open_my_article(article)
116117
end)
117118
end
118119

0 commit comments

Comments
 (0)