feat: first implementation for issues and pull requests
This commit is contained in:
@@ -1,21 +1,243 @@
|
||||
local M = {}
|
||||
local config = require("gitea.config")
|
||||
----------------------------------------------------------------------------
|
||||
-- lua/gitea/init.lua
|
||||
--
|
||||
-- Core plugin logic: reading .git/config, handling tokens, domain detection,
|
||||
-- and an async request() function. Also has the top-level setup().
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local Job = require("plenary.job")
|
||||
local commands = require("gitea.commands")
|
||||
local auth = require("gitea.auth")
|
||||
local highlights = require("gitea.highlights")
|
||||
|
||||
function M.setup(user_opts)
|
||||
-- Load user config (if any), or defaults
|
||||
config.setup(user_opts or {})
|
||||
local M = {}
|
||||
|
||||
-- Ensure token is loaded
|
||||
auth.ensure_token()
|
||||
----------------------------------------------------------------------------
|
||||
-- Configuration / State
|
||||
----------------------------------------------------------------------------
|
||||
M.token_folder = vim.fn.stdpath("data") .. "/gitea_tokens"
|
||||
M.preview_style = "floating"
|
||||
M._cached_base_url = nil
|
||||
M._cached_token = nil
|
||||
M._cached_owner = nil
|
||||
M._cached_repo = nil
|
||||
|
||||
-- Register :Gitea commands
|
||||
commands.register()
|
||||
----------------------------------------------------------------------------
|
||||
-- Internal Utils
|
||||
----------------------------------------------------------------------------
|
||||
local function ensure_dir(dirpath)
|
||||
if vim.fn.isdirectory(dirpath) == 0 then
|
||||
vim.fn.mkdir(dirpath, "p")
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply the default Dracula-like highlights
|
||||
highlights.setup()
|
||||
local function read_git_config_lines()
|
||||
local gitconfig_path = vim.fn.getcwd() .. "/.git/config"
|
||||
local f = io.open(gitconfig_path, "r")
|
||||
if not f then
|
||||
return {}
|
||||
end
|
||||
local lines = {}
|
||||
for line in f:lines() do
|
||||
table.insert(lines, line)
|
||||
end
|
||||
f:close()
|
||||
return lines
|
||||
end
|
||||
|
||||
local function strip_git_suffix(str)
|
||||
return (str:gsub("%.git$", ""))
|
||||
end
|
||||
|
||||
local function parse_git_config_for_domain()
|
||||
local lines = read_git_config_lines()
|
||||
for _, line in ipairs(lines) do
|
||||
local url = line:match("^%s*url%s*=%s*(.+)")
|
||||
if url then
|
||||
-- SSH style: user@host:owner/repo.git
|
||||
local ssh_host = url:match("^[^@]+@([^:]+):")
|
||||
if ssh_host then
|
||||
return ssh_host
|
||||
end
|
||||
-- HTTPS style: https://host/owner/repo(.git)
|
||||
local https_host = url:match("^https?://([^/]+)")
|
||||
if https_host then
|
||||
return https_host
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function M.parse_owner_repo()
|
||||
local lines = read_git_config_lines()
|
||||
for _, line in ipairs(lines) do
|
||||
local url = line:match("^%s*url%s*=%s*(.+)")
|
||||
if url then
|
||||
-- SSH
|
||||
local ssh_host, ssh_path = url:match("^[^@]+@([^:]+):(.+)")
|
||||
if ssh_host and ssh_path then
|
||||
ssh_path = strip_git_suffix(ssh_path)
|
||||
local slash_idx = ssh_path:find("/")
|
||||
if slash_idx then
|
||||
return ssh_path:sub(1, slash_idx - 1),
|
||||
ssh_path:sub(slash_idx + 1)
|
||||
end
|
||||
end
|
||||
|
||||
-- HTTPS
|
||||
local https_path = url:match("^https?://[^/]+/(.+)")
|
||||
if https_path then
|
||||
https_path = strip_git_suffix(https_path)
|
||||
local slash_idx = https_path:find("/")
|
||||
if slash_idx then
|
||||
return https_path:sub(1, slash_idx - 1),
|
||||
https_path:sub(slash_idx + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Token Logic
|
||||
----------------------------------------------------------------------------
|
||||
local function token_file_for_domain(domain)
|
||||
return M.token_folder .. "/" .. domain .. ".token"
|
||||
end
|
||||
|
||||
local function load_token(domain)
|
||||
if not domain or domain == "" then
|
||||
domain = "default"
|
||||
end
|
||||
local token_path = token_file_for_domain(domain)
|
||||
local f = io.open(token_path, "r")
|
||||
if f then
|
||||
local token = f:read("*a")
|
||||
f:close()
|
||||
if token and token ~= "" then
|
||||
return token
|
||||
end
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
vim.cmd(('echo "No Gitea token found for %s"'):format(domain))
|
||||
end)
|
||||
|
||||
local user_input = vim.fn.inputsecret("Enter your Gitea token for " .. domain .. ": ")
|
||||
if not (user_input and user_input ~= "") then
|
||||
return nil
|
||||
end
|
||||
|
||||
ensure_dir(M.token_folder)
|
||||
local fh, err = io.open(token_path, "w")
|
||||
if not fh then
|
||||
error(string.format("[gitea.nvim] Could not open token file for writing (%s). Error: %s",
|
||||
token_path, err or "unknown"))
|
||||
end
|
||||
fh:write(user_input)
|
||||
fh:close()
|
||||
print(string.format("[gitea.nvim] Token written to %s", token_path))
|
||||
return user_input
|
||||
end
|
||||
|
||||
local function ensure_base_url()
|
||||
if M._cached_base_url and M._cached_base_url ~= "" then
|
||||
return M._cached_base_url
|
||||
end
|
||||
local domain = parse_git_config_for_domain()
|
||||
if not domain then
|
||||
error("[gitea.nvim] Could not parse a domain from .git/config.")
|
||||
end
|
||||
if not domain:match("^https?://") then
|
||||
domain = "https://" .. domain
|
||||
end
|
||||
M._cached_base_url = domain
|
||||
return domain
|
||||
end
|
||||
|
||||
local function ensure_token()
|
||||
if M._cached_token and M._cached_token ~= "" then
|
||||
return M._cached_token
|
||||
end
|
||||
local raw_domain = parse_git_config_for_domain() or "default"
|
||||
raw_domain = raw_domain:gsub("^https://", "")
|
||||
raw_domain = raw_domain:gsub("^http://", "")
|
||||
local tok = load_token(raw_domain)
|
||||
if not tok or tok == "" then
|
||||
error("[gitea.nvim] Could not load/create a token for domain '" .. raw_domain .. "'.")
|
||||
end
|
||||
M._cached_token = tok
|
||||
return tok
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Async Requests (Plenary)
|
||||
----------------------------------------------------------------------------
|
||||
local function do_request(method, endpoint, data, callback)
|
||||
local base_url = ensure_base_url()
|
||||
local token = ensure_token()
|
||||
|
||||
local headers = {
|
||||
"Content-Type: application/json",
|
||||
"Authorization: token " .. token
|
||||
}
|
||||
local args = { "-s", "-X", method, base_url .. endpoint, "-H", headers[1], "-H", headers[2] }
|
||||
if data then
|
||||
local json_data = vim.fn.json_encode(data)
|
||||
table.insert(args, "-d")
|
||||
table.insert(args, json_data)
|
||||
end
|
||||
|
||||
Job:new({
|
||||
command = "curl",
|
||||
args = args,
|
||||
on_exit = function(j, return_val)
|
||||
vim.schedule(function()
|
||||
if return_val == 0 then
|
||||
local result = table.concat(j:result(), "\n")
|
||||
local ok, decoded = pcall(vim.fn.json_decode, result)
|
||||
if ok then
|
||||
callback(decoded, nil)
|
||||
else
|
||||
callback(nil, "Failed to parse JSON: " .. result)
|
||||
end
|
||||
else
|
||||
callback(nil, "curl failed (code=" .. return_val .. ")")
|
||||
end
|
||||
end)
|
||||
end
|
||||
}):start()
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Expose to other modules
|
||||
----------------------------------------------------------------------------
|
||||
M.ensure_base_url = ensure_base_url
|
||||
M.ensure_token = ensure_token
|
||||
M.request = do_request
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- setup()
|
||||
----------------------------------------------------------------------------
|
||||
function M.setup(opts)
|
||||
if opts and opts.token_folder then
|
||||
M.token_folder = opts.token_folder
|
||||
end
|
||||
if opts and opts.preview_style then
|
||||
M.preview_style = opts.preview_style
|
||||
end
|
||||
|
||||
local domain = parse_git_config_for_domain()
|
||||
if domain and not domain:match("^https?://") then
|
||||
domain = "https://" .. domain
|
||||
end
|
||||
M._cached_base_url = domain
|
||||
|
||||
local o, r = M.parse_owner_repo()
|
||||
M._cached_owner = o
|
||||
M._cached_repo = r
|
||||
|
||||
commands.setup_commands(M)
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user