From 3d07f4144a55c0cb3949524058bccdd9cd756d59 Mon Sep 17 00:00:00 2001 From: TheLeoP Date: Tue, 4 Feb 2025 16:52:20 -0500 Subject: [PATCH] docs: use generated types and better type annotations --- lua/octo/commands.lua | 43 +++++++---- lua/octo/gh/init.lua | 2 +- lua/octo/init.lua | 26 ++++--- lua/octo/model/body-metadata.lua | 4 +- lua/octo/model/comment-metadata.lua | 2 +- lua/octo/model/octo-buffer.lua | 27 ++++--- lua/octo/navigation.lua | 2 +- lua/octo/pickers/fzf-lua/entry_maker.lua | 61 ++++++++++------ .../fzf-lua/pickers/assigned_labels.lua | 13 ++-- .../pickers/fzf-lua/pickers/assignees.lua | 13 ++-- lua/octo/pickers/fzf-lua/pickers/gists.lua | 4 +- lua/octo/pickers/fzf-lua/pickers/issues.lua | 2 +- lua/octo/pickers/fzf-lua/pickers/labels.lua | 2 +- .../fzf-lua/pickers/pending_threads.lua | 2 +- .../fzf-lua/pickers/project_columns.lua | 21 +++--- .../fzf-lua/pickers/project_columns_v2.lua | 21 +++--- lua/octo/pickers/fzf-lua/pickers/prs.lua | 4 +- lua/octo/pickers/fzf-lua/pickers/repos.lua | 2 +- lua/octo/pickers/fzf-lua/pickers/search.lua | 2 +- lua/octo/pickers/fzf-lua/pickers/users.lua | 6 +- lua/octo/pickers/fzf-lua/previewers.lua | 11 +-- lua/octo/pickers/telescope/previewers.lua | 6 +- lua/octo/pickers/telescope/provider.lua | 71 ++++++++++++------- lua/octo/reviews/init.lua | 13 ++-- lua/octo/reviews/layout.lua | 1 + lua/octo/ui/bubbles.lua | 6 ++ lua/octo/ui/writers.lua | 40 ++++++++++- lua/octo/utils.lua | 40 +++++++---- 28 files changed, 294 insertions(+), 153 deletions(-) diff --git a/lua/octo/commands.lua b/lua/octo/commands.lua index 954bba32..53094aa8 100644 --- a/lua/octo/commands.lua +++ b/lua/octo/commands.lua @@ -654,7 +654,7 @@ function M.delete_comment() cb = function(output) -- TODO: deleting the last review thread comment, it deletes the whole thread and review -- In issue buffers, we should hide the thread snippet - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {deletePullRequestReviewComment: octo.gh.DeletePullRequestReviewCommentPayload?}} -- remove comment lines from the buffer if comment.reactionLine then @@ -745,6 +745,10 @@ function M.delete_comment() end end +---@param bufnr integer +---@param thread octo.gh.PullRequestReviewThread +---@param thread_id string +---@param thread_line integer local function update_review_thread_header(bufnr, thread, thread_id, thread_line) local start_line = thread.originalStartLine ~= vim.NIL and thread.originalStartLine or thread.originalLine local end_line = thread.originalLine @@ -788,9 +792,10 @@ function M.resolve_thread() if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {resolveReviewThread: octo.gh.ResolveReviewThreadPayload}} local thread = resp.data.resolveReviewThread.thread - if thread.isResolved then + if thread ~= vim.NIL and thread.isResolved then + ---@cast thread -vim.NIL update_review_thread_header(bufnr, thread, thread_id, thread_line) --vim.cmd(string.format("%d,%dfoldclose", thread_line, thread_line)) end @@ -818,9 +823,10 @@ function M.unresolve_thread() if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {unresolveReviewThread: octo.gh.UnresolveReviewThreadPayload}} local thread = resp.data.unresolveReviewThread.thread - if not thread.isResolved then + if thread ~= vim.NIL and not thread.isResolved then + ---@cast thread -vim.NIL update_review_thread_header(bufnr, thread, thread_id, thread_line) end end @@ -961,7 +967,7 @@ function M.save_issue(opts) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {createIssue: octo.gh.CreateIssuePayload}} require("octo").create_buffer("issue", resp.data.createIssue.issue, opts.repo, true) vim.fn.execute "normal! Gk" vim.fn.execute "startinsert" @@ -1175,7 +1181,7 @@ function M.save_pr(opts) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {createPullRequest: octo.gh.CreatePullRequestPayload}} local pr = resp.data.createPullRequest.pullRequest utils.info(string.format("#%d - `%s` created successfully", pr.number, pr.title)) require("octo").create_buffer("pull", pr, opts.repo, true) @@ -1231,8 +1237,8 @@ function M.pr_checks() if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local max_lengths = {} - local parts = {} + local max_lengths = {} ---@type integer[] + local parts = {} ---@type string[][] for _, l in pairs(vim.split(output, "\n")) do local line_parts = vim.split(l, "\t") for i, p in pairs(line_parts) do @@ -1330,6 +1336,9 @@ function M.show_pr_diff() } end +---@param bufnr integer +---@param extmark integer +---@return integer local function get_reaction_line(bufnr, extmark) local prev_extmark = extmark local mark = vim.api.nvim_buf_get_extmark_by_id(bufnr, constants.OCTO_COMMENT_NS, prev_extmark, { details = true }) @@ -1337,8 +1346,14 @@ local function get_reaction_line(bufnr, extmark) return end_line + 3 end +---@param bufnr integer +---@param buffer OctoBuffer +---@return integer reaction_line +---@return octo.gh.ReactionGroup[] reaction_groups +---@return boolean insert_line +---@return string id local function get_reaction_info(bufnr, buffer) - local reaction_groups, reaction_line, insert_line, id + local reaction_groups, reaction_line, insert_line, id ---@type octo.gh.ReactionGroup[], integer, boolean, string local comment = buffer:get_comment_at_cursor() if comment then -- found a comment at cursor @@ -1379,7 +1394,7 @@ function M.reaction_action(reaction) local reaction_line, reaction_groups, insert_line, id = get_reaction_info(bufnr, buffer) - local action + local action ---@type "add" | "remove" for _, reaction_group in ipairs(reaction_groups) do if reaction_group.content == reaction and reaction_group.viewerHasReacted then action = "remove" @@ -1403,8 +1418,10 @@ function M.reaction_action(reaction) elseif output then local resp = vim.json.decode(output) if action == "add" then + ---@cast resp {data: {addReaction: octo.gh.AddReactionPayload}} reaction_groups = resp.data.addReaction.subject.reactionGroups elseif action == "remove" then + ---@cast resp {data: {removeReaction: octo.gh.RemoveReactionPayload}} reaction_groups = resp.data.removeReaction.subject.reactionGroups end @@ -1527,7 +1544,7 @@ function M.set_project_v2_card() if add_stderr and not utils.is_blank(add_stderr) then utils.error(add_stderr) elseif add_output then - local resp = vim.json.decode(add_output) + local resp = vim.json.decode(add_output) ---@type {data: {addProjectV2ItemById: octo.gh.AddProjectV2ItemByIdPayload}} local update_query = graphql( "update_project_v2_item_mutation", project_id, @@ -1631,7 +1648,7 @@ function M.create_label(label) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {createLabel: octo.gh.CreateLabelPayload}} local label = resp.data.createLabel.label utils.info("Created label: " .. label.name) diff --git a/lua/octo/gh/init.lua b/lua/octo/gh/init.lua index 88739a71..0b1e1243 100644 --- a/lua/octo/gh/init.lua +++ b/lua/octo/gh/init.lua @@ -244,7 +244,7 @@ end ---Run a graphql query ---@param opts table the options for the graphql query ----@return table|nil +---@return string|nil function M.graphql(opts) local run_opts = opts.opts or {} return M.run { diff --git a/lua/octo/init.lua b/lua/octo/init.lua index 28f90137..af44c985 100644 --- a/lua/octo/init.lua +++ b/lua/octo/init.lua @@ -15,8 +15,8 @@ local writers = require "octo.ui.writers" local utils = require "octo.utils" local vim = vim -_G.octo_repo_issues = {} -_G.octo_buffers = {} +_G.octo_repo_issues = {} ---@type table repo -> issues_metadata +_G.octo_buffers = {} ---@type table buffer -> OctoBuffer _G.octo_colors_loaded = false local M = {} @@ -128,9 +128,13 @@ function M.load_buffer(opts) end) end +---@param repo string +---@param kind string +---@param number integer +---@param cb function function M.load(repo, kind, number, cb) local owner, name = utils.split_repo(repo) - local query, key + local query, key ---@type string, string if kind == "pull" then query = graphql("pull_request_query", owner, name, number, _G.octo_pv2_fragment) @@ -184,12 +188,12 @@ function M.on_cursor_hold() if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output) - local reactions = {} + local resp = vim.json.decode(output) ---@type {data: {node: {reactionGroups: octo.gh.ReactionGroup[]}}} + local reactions = {} ---@type table local reactionGroups = resp.data.node.reactionGroups for _, reactionGroup in ipairs(reactionGroups) do local users = reactionGroup.users.nodes - local logins = {} + local logins = {} ---@type string[] for _, user in ipairs(users) do table.insert(logins, user.login) end @@ -220,7 +224,7 @@ function M.on_cursor_hold() if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {user: octo.gh.User}} local user = resp.data.user local popup_bufnr = vim.api.nvim_create_buf(false, true) local lines, max_length = writers.write_user_profile(popup_bufnr, user) @@ -248,7 +252,7 @@ function M.on_cursor_hold() if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local issue = resp.data.repository.issueOrPullRequest local popup_bufnr = vim.api.nvim_create_buf(false, true) local max_length = 80 @@ -263,13 +267,17 @@ function M.on_cursor_hold() } end +---@param kind string +---@param obj {number: integer, id: string} +---@param repo string +---@param create boolean function M.create_buffer(kind, obj, repo, create) if not obj.id then utils.error("Cannot find " .. repo) return end - local bufnr + local bufnr ---@type integer if create then bufnr = vim.api.nvim_create_buf(true, false) vim.api.nvim_set_current_buf(bufnr) diff --git a/lua/octo/model/body-metadata.lua b/lua/octo/model/body-metadata.lua index 861e0293..140de9ce 100644 --- a/lua/octo/model/body-metadata.lua +++ b/lua/octo/model/body-metadata.lua @@ -8,8 +8,8 @@ local M = {} ---@field startLine integer ---@field endLine integer ---@field viewerCanUpdate boolean --- @field reactionGroups table[] --- @field reactionLine integer +---@field reactionGroups octo.gh.ReactionGroup +---@field reactionLine integer local BodyMetadata = {} BodyMetadata.__index = BodyMetadata diff --git a/lua/octo/model/comment-metadata.lua b/lua/octo/model/comment-metadata.lua index 803327a0..38d4eedc 100644 --- a/lua/octo/model/comment-metadata.lua +++ b/lua/octo/model/comment-metadata.lua @@ -10,7 +10,7 @@ local M = {} ---@field startLine integer ---@field endLine integer ---@field namespace integer ----@field reactionGroups table[] +---@field reactionGroups octo.gh.ReactionGroup ---@field reactionLine integer ---@field viewerCanUpdate boolean ---@field viewerCanDelete boolean diff --git a/lua/octo/model/octo-buffer.lua b/lua/octo/model/octo-buffer.lua index dc5e3de1..1668add2 100644 --- a/lua/octo/model/octo-buffer.lua +++ b/lua/octo/model/octo-buffer.lua @@ -22,12 +22,15 @@ local M = {} ---@field bodyMetadata BodyMetadata ---@field commentsMetadata CommentMetadata[] ---@field threadsMetadata ThreadMetadata[] ----@field node table +---@field node octo.gh.Repository ---@field taggable_users string[] +---@field owner string +---@field name string local OctoBuffer = {} OctoBuffer.__index = OctoBuffer ---OctoBuffer constructor. +---@param opts table ---@return OctoBuffer function OctoBuffer:new(opts) local this = { @@ -400,10 +403,12 @@ function OctoBuffer:do_save_title_and_body() vim.api.nvim_err_writeln(stderr) elseif output then local resp = vim.json.decode(output) - local obj + local obj ---@type octo.gh.Issue | octo.gh.PullRequest | vim.NIL if self:isPullRequest() then + ---@cast resp {data: {updatePullRequest: octo.gh.UpdatePullRequestPayload}} obj = resp.data.updatePullRequest.pullRequest elseif self:isIssue() then + ---@cast resp {data: {updateIssue: octo.gh.UpdateIssuePayload}} obj = resp.data.updateIssue.issue end if title_metadata.body == obj.title then @@ -437,7 +442,7 @@ function OctoBuffer:do_add_issue_comment(comment_metadata) if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {addComment: octo.gh.AddCommentPayload}} local respBody = resp.data.addComment.commentEdge.node.body local respId = resp.data.addComment.commentEdge.node.id if utils.trim(comment_metadata.body) == utils.trim(respBody) then @@ -472,9 +477,9 @@ function OctoBuffer:do_add_thread_comment(comment_metadata) if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {addPullRequestReviewComment: octo.gh.AddPullRequestReviewCommentPayload}} local resp_comment = resp.data.addPullRequestReviewComment.comment - local comment_end + local comment_end ---@type integer if utils.trim(comment_metadata.body) == utils.trim(resp_comment.body) then local comments = self.commentsMetadata for i, c in ipairs(comments) do @@ -584,7 +589,7 @@ function OctoBuffer:do_add_new_thread(comment_metadata) if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output).data.addPullRequestReviewThread + local resp = vim.json.decode(output).data.addPullRequestReviewThread ---@type octo.gh.AddPullRequestReviewThreadPayload if not utils.is_blank(resp.thread) then local new_comment = resp.thread.comments.nodes[1] if utils.trim(comment_metadata.body) == utils.trim(new_comment.body) then @@ -682,7 +687,7 @@ function OctoBuffer:do_add_new_thread(comment_metadata) vim.api.nvim_err_writeln(stderr) elseif output then local r = vim.json.decode(output) - local resp = r.data.addPullRequestReviewComment + local resp = r.data.addPullRequestReviewComment ---@type octo.gh.AddPullRequestReviewCommentPayload if not utils.is_blank(resp.comment) then if utils.trim(comment_metadata.body) == utils.trim(resp.comment.body) then local comments = self.commentsMetadata @@ -712,6 +717,7 @@ function OctoBuffer:do_add_new_thread(comment_metadata) end ---Replies a review thread w/o creating a new review +---@param comment_metadata CommentMetadata function OctoBuffer:do_add_pull_request_comment(comment_metadata) local current_review = require("octo.reviews").get_current_review() if not utils.is_blank(current_review) then @@ -775,10 +781,12 @@ function OctoBuffer:do_update_comment(comment_metadata) vim.api.nvim_err_writeln(stderr) elseif output then local resp = vim.json.decode(output) - local resp_comment + local resp_comment ---@type octo.gh.IssueComment | octo.gh.PullRequestReview| octo.gh.PullRequestReviewComment | vim.NIL if comment_metadata.kind == "IssueComment" then + ---@cast resp {data: {updateIssueComment: octo.gh.UpdateIssueCommentPayload}} resp_comment = resp.data.updateIssueComment.issueComment elseif comment_metadata.kind == "PullRequestReviewComment" then + ---@cast resp {data: {updatePullRequestReviewComment: octo.gh.UpdatePullRequestReviewCommentPayload}} resp_comment = resp.data.updatePullRequestReviewComment.pullRequestReviewComment local threads = resp.data.updatePullRequestReviewComment.pullRequestReviewComment.pullRequest.reviewThreads.nodes @@ -787,6 +795,7 @@ function OctoBuffer:do_update_comment(comment_metadata) review:update_threads(threads) end elseif comment_metadata.kind == "PullRequestReview" then + ---@cast resp {data: {updatePullRequestReview: octo.gh.UpdatePullRequestReviewPayload}} resp_comment = resp.data.updatePullRequestReview.pullRequestReview end if resp_comment and utils.trim(comment_metadata.body) == utils.trim(resp_comment.body) then @@ -1019,6 +1028,8 @@ function OctoBuffer:get_reactions_at_cursor() end ---Updates the reactions groups at cursor (if any) +---@param reaction_groups octo.gh.ReactionGroup[] +---@param reaction_line integer function OctoBuffer:update_reactions_at_cursor(reaction_groups, reaction_line) local cursor = vim.api.nvim_win_get_cursor(0) local reactions_count = 0 diff --git a/lua/octo/navigation.lua b/lua/octo/navigation.lua index 1c7cd124..b0220ff1 100644 --- a/lua/octo/navigation.lua +++ b/lua/octo/navigation.lua @@ -123,7 +123,7 @@ function M.go_to_issue() if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local kind = resp.data.repository.issueOrPullRequest.__typename if kind == "Issue" then utils.get_issue(number, repo) diff --git a/lua/octo/pickers/fzf-lua/entry_maker.lua b/lua/octo/pickers/fzf-lua/entry_maker.lua index c13300fd..cacba5ec 100644 --- a/lua/octo/pickers/fzf-lua/entry_maker.lua +++ b/lua/octo/pickers/fzf-lua/entry_maker.lua @@ -3,29 +3,30 @@ local fzf = require "fzf-lua" local M = {} ----@param issue_table table +---@param issue octo.gh.Issue | octo.gh.PullRequest ---@return table|nil -function M.gen_from_issue(issue_table) - if not issue_table or vim.tbl_isempty(issue_table) then +function M.gen_from_issue(issue) + if not issue or vim.tbl_isempty(issue) then return nil end - local kind = issue_table.__typename == "Issue" and "issue" or "pull_request" + local kind = issue.__typename == "Issue" and "issue" or "pull_request" local filename ---@type string if kind == "issue" then - filename = utils.get_issue_uri(issue_table.number, issue_table.repository.nameWithOwner) + filename = utils.get_issue_uri(issue.number, issue.repository.nameWithOwner) else - filename = utils.get_pull_request_uri(issue_table.number, issue_table.repository.nameWithOwner) + filename = utils.get_pull_request_uri(issue.number, issue.repository.nameWithOwner) end return { filename = filename, kind = kind, - value = issue_table.number, - ordinal = issue_table.number .. " " .. issue_table.title, - obj = issue_table, - repo = issue_table.repository.nameWithOwner, + value = issue.number, + ordinal = issue.number .. " " .. issue.title, + obj = issue, + repo = issue.repository.nameWithOwner, } end +---@return table|nil function M.gen_from_git_commits(entry) if not entry then return nil @@ -43,6 +44,7 @@ function M.gen_from_git_commits(entry) } end +---@return table|nil function M.gen_from_git_changed_files(entry) if not entry then return nil @@ -56,7 +58,8 @@ function M.gen_from_git_changed_files(entry) } end -function M.gen_from_review_thread(linenr_length, thread) +---@return table|nil +function M.gen_from_review_thread(thread) if not thread or vim.tbl_isempty(thread) then return nil end @@ -68,6 +71,8 @@ function M.gen_from_review_thread(linenr_length, thread) } end +---@param project octo.gh.Project +---@return table|nil function M.gen_from_project(project) if not project or vim.tbl_isempty(project) then return nil @@ -80,6 +85,8 @@ function M.gen_from_project(project) } end +---@param column octo.gh.ProjectColumn +---@return table|nil function M.gen_from_project_column(column) if not column or vim.tbl_isempty(column) then return nil @@ -91,6 +98,8 @@ function M.gen_from_project_column(column) } end +---@param card octo.gh.ProjectCard +---@return table|nil function M.gen_from_project_card(card) if not card or vim.tbl_isempty(card) then return nil @@ -103,6 +112,8 @@ function M.gen_from_project_card(card) } end +---@param project octo.gh.ProjectV2 +---@return table|nil function M.gen_from_project_v2(project) if not project or vim.tbl_isempty(project) then return nil @@ -124,6 +135,7 @@ function M.gen_from_project_v2(project) } end +---@return table|nil function M.gen_from_project_v2_column(column) if not column or vim.tbl_isempty(column) then return nil @@ -135,6 +147,8 @@ function M.gen_from_project_v2_column(column) } end +---@param label octo.gh.Label +---@return table|nil function M.gen_from_label(label) if not label or vim.tbl_isempty(label) then return nil @@ -147,6 +161,8 @@ function M.gen_from_label(label) } end +---@param team octo.gh.Team +---@return table|nil function M.gen_from_team(team) if not team or vim.tbl_isempty(team) then return nil @@ -159,6 +175,8 @@ function M.gen_from_team(team) } end +---@param user octo.gh.User +---@return table|nil function M.gen_from_user(user) if not user or vim.tbl_isempty(user) then return nil @@ -171,16 +189,15 @@ function M.gen_from_user(user) } end ---[[ - Generates an entry from a raw repo table. - - TODO use these in Phase 2. Repo is not a part of the first change. - - @param max_nameWithOwner Length of longest name + owner string. - @param max_forkCount Length of longest fork count string. - @param max_stargazerCount Length of longest stargazer count string. - @param repo The raw repo table from GitHub. -]] +---Generates an entry from a raw repo table. +--- +--TODO use these in Phase 2. Repo is not a part of the first change. +--@param max_nameWithOwner integer Length of longest name + owner string. +--@param max_forkCount integer Length of longest fork count string. +--@param max_stargazerCount integer Length of longest stargazer count string. +---@param repo octo.gh.Repository The raw repo table from GitHub. +---@return table|nil entry +---@return string|nil entry_str function M.gen_from_repo(repo) if not repo or vim.tbl_isempty(repo) then return nil, nil @@ -220,6 +237,8 @@ function M.gen_from_repo(repo) return entry, entry_str end +---@param gist octo.gh.Gist +---@return table|nil function M.gen_from_gist(gist) if not gist or vim.tbl_isempty(gist) then return diff --git a/lua/octo/pickers/fzf-lua/pickers/assigned_labels.lua b/lua/octo/pickers/fzf-lua/pickers/assigned_labels.lua index fe12dba1..52d34c66 100644 --- a/lua/octo/pickers/fzf-lua/pickers/assigned_labels.lua +++ b/lua/octo/pickers/fzf-lua/pickers/assigned_labels.lua @@ -12,13 +12,11 @@ return function(cb) return end - local query, key + local query ---@type string if buffer:isIssue() then query = graphql("issue_labels_query", buffer.owner, buffer.name, buffer.number) - key = "issue" elseif buffer:isPullRequest() then query = graphql("pull_request_labels_query", buffer.owner, buffer.name, buffer.number) - key = "pullRequest" end local get_contents = function(fzf_cb) @@ -28,8 +26,13 @@ return function(cb) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) - local labels = resp.data.repository[key].labels.nodes + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local labels ---@type octo.gh.Label[] + if buffer:isIssue() then + labels = resp.data.repository.issue.labels.nodes + elseif buffer:isPullRequest() then + labels = resp.data.repository.pullRequest.labels.nodes + end for _, label in ipairs(labels) do local colored_name = picker_utils.color_string_with_hex(label.name, "#" .. label.color) diff --git a/lua/octo/pickers/fzf-lua/pickers/assignees.lua b/lua/octo/pickers/fzf-lua/pickers/assignees.lua index 9186aeeb..c4558bda 100644 --- a/lua/octo/pickers/fzf-lua/pickers/assignees.lua +++ b/lua/octo/pickers/fzf-lua/pickers/assignees.lua @@ -10,13 +10,11 @@ return function(cb) if not buffer then return end - local query, key + local query ---@type string if buffer:isIssue() then query = graphql("issue_assignees_query", buffer.owner, buffer.name, buffer.number) - key = "issue" elseif buffer:isPullRequest() then query = graphql("pull_request_assignees_query", buffer.owner, buffer.name, buffer.number) - key = "pullRequest" end local get_contents = function(fzf_cb) @@ -26,8 +24,13 @@ return function(cb) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) - local assignees = resp.data.repository[key].assignees.nodes + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local assignees ---@type octo.gh.Assignee[] + if buffer:isIssue() then + assignees = resp.data.repository.issue.assignees.nodes + elseif buffer:isPullRequest() then + assignees = resp.data.repository.pullRequest.assignees.nodes + end for _, user in ipairs(assignees) do fzf_cb(string.format("%s %s", user.id, user.login)) diff --git a/lua/octo/pickers/fzf-lua/pickers/gists.lua b/lua/octo/pickers/fzf-lua/pickers/gists.lua index f87fdadf..bf62305e 100644 --- a/lua/octo/pickers/fzf-lua/pickers/gists.lua +++ b/lua/octo/pickers/fzf-lua/pickers/gists.lua @@ -39,7 +39,7 @@ return function(opts) privacy = "ALL" end - local formatted_gists = {} + local formatted_gists = {} ---@type table local get_contents = function(fzf_cb) local query = graphql("gists_query", privacy) @@ -51,7 +51,7 @@ return function(opts) utils.error(stderr) elseif output then local resp = utils.aggregate_pages(output, "data.viewer.gists.nodes") - local gists = resp.data.viewer.gists.nodes + local gists = resp.data.viewer.gists.nodes ---@type octo.gh.Gist[] for _, gist in ipairs(gists) do local entry = entry_maker.gen_from_gist(gist) diff --git a/lua/octo/pickers/fzf-lua/pickers/issues.lua b/lua/octo/pickers/fzf-lua/pickers/issues.lua index 3c18a7ad..ad834256 100644 --- a/lua/octo/pickers/fzf-lua/pickers/issues.lua +++ b/lua/octo/pickers/fzf-lua/pickers/issues.lua @@ -46,7 +46,7 @@ return function(opts) utils.error(err) fzf_cb() elseif data then - local resp = utils.aggregate_pages(data, "data.repository.issues.nodes") + local resp = utils.aggregate_pages(data, "data.repository.issues.nodes") ---@type {data: {repository: octo.gh.Repository}} local issues = resp.data.repository.issues.nodes for _, issue in ipairs(issues) do diff --git a/lua/octo/pickers/fzf-lua/pickers/labels.lua b/lua/octo/pickers/fzf-lua/pickers/labels.lua index 6fc5687b..4c79cc91 100644 --- a/lua/octo/pickers/fzf-lua/pickers/labels.lua +++ b/lua/octo/pickers/fzf-lua/pickers/labels.lua @@ -21,7 +21,7 @@ return function(cb) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local labels = resp.data.repository.labels.nodes for _, label in ipairs(labels) do diff --git a/lua/octo/pickers/fzf-lua/pickers/pending_threads.lua b/lua/octo/pickers/fzf-lua/pickers/pending_threads.lua index 3f075c67..fe1f0e8a 100644 --- a/lua/octo/pickers/fzf-lua/pickers/pending_threads.lua +++ b/lua/octo/pickers/fzf-lua/pickers/pending_threads.lua @@ -15,7 +15,7 @@ return function(threads) local titles = {} for _, thread in ipairs(threads) do - local entry = entry_maker.gen_from_review_thread(max_linenr_length, thread) + local entry = entry_maker.gen_from_review_thread(thread) if entry ~= nil then formatted_threads[entry.ordinal] = entry diff --git a/lua/octo/pickers/fzf-lua/pickers/project_columns.lua b/lua/octo/pickers/fzf-lua/pickers/project_columns.lua index 4981aa6a..562a2c18 100644 --- a/lua/octo/pickers/fzf-lua/pickers/project_columns.lua +++ b/lua/octo/pickers/fzf-lua/pickers/project_columns.lua @@ -12,7 +12,7 @@ return function(cb) return end - local formatted_projects = {} + local formatted_projects = {} ---@type table local common_fzf_opts = vim.tbl_deep_extend("force", picker_utils.dropdown_opts, { fzf_opts = { ["--delimiter"] = "' '", @@ -26,15 +26,18 @@ return function(cb) args = { "api", "graphql", "--paginate", "-f", string.format("query=%s", query) }, cb = function(output) if output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {user: octo.gh.User?, repository: octo.gh.Repository?, organization: octo.gh.Organization?}, errors: unknown} - local projects = {} - local user_projects = resp.data.user and resp.data.user.projects.nodes or {} - local repo_projects = resp.data.repository and resp.data.repository.projects.nodes or {} - local org_projects = not resp.errors and resp.data.organization.projects.nodes or {} - vim.list_extend(projects, repo_projects) - vim.list_extend(projects, user_projects) - vim.list_extend(projects, org_projects) + local projects = {} ---@type octo.gh.Project[] + if resp.data.user then + vim.list_extend(projects, resp.data.user.projects.nodes) + end + if resp.data.repository then + vim.list_extend(projects, resp.data.repository.projects.nodes) + end + if not resp.errors then + vim.list_extend(projects, resp.data.organization.projects.nodes) + end if #projects == 0 then utils.error(string.format("There are no matching projects for %s.", buffer.repo)) diff --git a/lua/octo/pickers/fzf-lua/pickers/project_columns_v2.lua b/lua/octo/pickers/fzf-lua/pickers/project_columns_v2.lua index 246e257a..78eb2e2c 100644 --- a/lua/octo/pickers/fzf-lua/pickers/project_columns_v2.lua +++ b/lua/octo/pickers/fzf-lua/pickers/project_columns_v2.lua @@ -27,17 +27,20 @@ return function(cb) args = { "api", "graphql", "--paginate", "-f", string.format("query=%s", query) }, cb = function(output) if output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {user: octo.gh.User?, repository: octo.gh.Repository?, organization: octo.gh.Organization?}, errors: unknown} - local unsorted_projects = {} - local user_projects = resp.data.user and resp.data.user.projects.nodes or {} - local repo_projects = resp.data.repository and resp.data.repository.projects.nodes or {} - local org_projects = not resp.errors and resp.data.organization.projects.nodes or {} - vim.list_extend(unsorted_projects, repo_projects) - vim.list_extend(unsorted_projects, user_projects) - vim.list_extend(unsorted_projects, org_projects) + local unsorted_projects = {} ---@type octo.gh.Project[] + if resp.data.user then + vim.list_extend(unsorted_projects, resp.data.user.projects.nodes) + end + if resp.data.repository then + vim.list_extend(unsorted_projects, resp.data.repository.projects.nodes) + end + if not resp.errors then + vim.list_extend(unsorted_projects, resp.data.organization.projects.nodes) + end - local projects = {} + local projects = {} ---@type octo.gh.Project[] for _, project in ipairs(unsorted_projects) do if project.closed then table.insert(projects, #projects + 1, project) diff --git a/lua/octo/pickers/fzf-lua/pickers/prs.lua b/lua/octo/pickers/fzf-lua/pickers/prs.lua index e521abe8..59778c23 100644 --- a/lua/octo/pickers/fzf-lua/pickers/prs.lua +++ b/lua/octo/pickers/fzf-lua/pickers/prs.lua @@ -61,7 +61,7 @@ return function(opts) utils.error(err) fzf_cb() elseif data then - local resp = utils.aggregate_pages(data, "data.repository.pullRequests.nodes") + local resp = utils.aggregate_pages(data, "data.repository.pullRequests.nodes") ---@type {data: {repository: octo.gh.Repository}} local pull_requests = resp.data.repository.pullRequests.nodes for _, pull in ipairs(pull_requests) do @@ -69,7 +69,7 @@ return function(opts) if entry ~= nil then formatted_pulls[entry.ordinal] = entry - local highlight + local highlight ---@type string if entry.obj.isDraft then highlight = "OctoSymbol" else diff --git a/lua/octo/pickers/fzf-lua/pickers/repos.lua b/lua/octo/pickers/fzf-lua/pickers/repos.lua index 1030f52a..8c81045a 100644 --- a/lua/octo/pickers/fzf-lua/pickers/repos.lua +++ b/lua/octo/pickers/fzf-lua/pickers/repos.lua @@ -28,7 +28,7 @@ return function(opts) utils.error(stderr) fzf_cb() elseif output then - local resp = utils.aggregate_pages(output, "data.repositoryOwner.repositories.nodes") + local resp = utils.aggregate_pages(output, "data.repositoryOwner.repositories.nodes") ---@type {data: {repositoryOwner: octo.gh.RepositoryOwner}} local repos = resp.data.repositoryOwner.repositories.nodes if #repos == 0 then utils.error(string.format("There are no matching repositories for %s.", opts.login)) diff --git a/lua/octo/pickers/fzf-lua/pickers/search.lua b/lua/octo/pickers/fzf-lua/pickers/search.lua index de8e01c8..3398ae46 100644 --- a/lua/octo/pickers/fzf-lua/pickers/search.lua +++ b/lua/octo/pickers/fzf-lua/pickers/search.lua @@ -59,7 +59,7 @@ return function(opts) return {} end - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {search: {nodes: octo.gh.Issue[]}}} local max_id_length = 1 for _, issue in ipairs(resp.data.search.nodes) do local s = tostring(issue.number) diff --git a/lua/octo/pickers/fzf-lua/pickers/users.lua b/lua/octo/pickers/fzf-lua/pickers/users.lua index 23982123..84d2c945 100644 --- a/lua/octo/pickers/fzf-lua/pickers/users.lua +++ b/lua/octo/pickers/fzf-lua/pickers/users.lua @@ -19,9 +19,9 @@ return function(cb) mode = "sync", } if output then - local users = {} - local orgs = {} - local responses = utils.get_pages(output) + local users = {} ---@type table + local orgs = {} ---@type table + local responses = utils.get_pages(output) ---@type {data: {search: {nodes: (octo.gh.User | octo.gh.Organization)[]}}}[] for _, resp in ipairs(responses) do for _, user in ipairs(resp.data.search.nodes) do if not user.teams then diff --git a/lua/octo/pickers/fzf-lua/previewers.lua b/lua/octo/pickers/fzf-lua/previewers.lua index e941081e..c9c73ca6 100644 --- a/lua/octo/pickers/fzf-lua/previewers.lua +++ b/lua/octo/pickers/fzf-lua/previewers.lua @@ -42,6 +42,7 @@ function M.bufferPreviewer:update_border(title) self.win:update_preview_scrollbar() end +---@param formatted_issues table M.issue = function(formatted_issues) local previewer = M.bufferPreviewer:extend() @@ -73,8 +74,8 @@ M.issue = function(formatted_issues) if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output and self.preview_bufnr == tmpbuf and vim.api.nvim_buf_is_valid(tmpbuf) then - local result = vim.json.decode(output) - local obj + local result = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local obj ---@type octo.gh.Issue | octo.gh.PullRequest | vim.NIL if entry.kind == "issue" then obj = result.data.repository.issue elseif entry.kind == "pull_request" then @@ -135,8 +136,8 @@ M.search = function() if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output and self.preview_bufnr == tmpbuf and vim.api.nvim_buf_is_valid(tmpbuf) then - local result = vim.json.decode(output) - local obj + local result = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local obj ---@type octo.gh.Issue | octo.gh.PullRequest | vim.NIL if kind == "issue" then obj = result.data.repository.issue elseif kind == "pull_request" then @@ -340,7 +341,7 @@ M.repo = function(formatted_repos) -- when the entry changes `preview_bufnr` will also change (due to `set_preview_buf`) -- and `tmpbuf` within this context is already cleared and invalidated if self.preview_bufnr == tmpbuf and vim.api.nvim_buf_is_valid(tmpbuf) then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} buffer.node = resp.data.repository buffer:render_repo() end diff --git a/lua/octo/pickers/telescope/previewers.lua b/lua/octo/pickers/telescope/previewers.lua index 1e9d56aa..ffaf6ba5 100644 --- a/lua/octo/pickers/telescope/previewers.lua +++ b/lua/octo/pickers/telescope/previewers.lua @@ -36,7 +36,7 @@ local discussion = defaulter(function(opts) -- clear the buffer vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {}) - local result = vim.json.decode(output) + local result = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local obj = result.data.repository.discussion writers.write_title(bufnr, tostring(obj.title), 1) @@ -79,8 +79,8 @@ local issue = defaulter(function(opts) if stderr and not utils.is_blank(stderr) then vim.api.nvim_err_writeln(stderr) elseif output and vim.api.nvim_buf_is_valid(bufnr) then - local result = vim.json.decode(output) - local obj + local result = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local obj ---@type octo.gh.Issue | octo.gh.PullRequest | vim.NIL if entry.kind == "issue" then obj = result.data.repository.issue elseif entry.kind == "pull_request" then diff --git a/lua/octo/pickers/telescope/provider.lua b/lua/octo/pickers/telescope/provider.lua index 8841cef0..0685ae32 100644 --- a/lua/octo/pickers/telescope/provider.lua +++ b/lua/octo/pickers/telescope/provider.lua @@ -168,7 +168,7 @@ function M.issues(opts) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = utils.aggregate_pages(output, "data.repository.issues.nodes") + local resp = utils.aggregate_pages(output, "data.repository.issues.nodes") ---@type {data: {repository: octo.gh.Repository}} local issues = resp.data.repository.issues.nodes if #issues == 0 then utils.error(string.format("There are no matching issues in %s.", opts.repo)) @@ -243,7 +243,7 @@ function M.gists(opts) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = utils.aggregate_pages(output, "data.viewer.gists.nodes") + local resp = utils.aggregate_pages(output, "data.viewer.gists.nodes") ---@type {data: {viewer: octo.gh.User}} local gists = resp.data.viewer.gists.nodes opts.preview_title = opts.preview_title or "" opts.prompt_title = opts.prompt_title or "" @@ -315,7 +315,7 @@ function M.pull_requests(opts) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = utils.aggregate_pages(output, "data.repository.pullRequests.nodes") + local resp = utils.aggregate_pages(output, "data.repository.pullRequests.nodes") ---@type {data: {repository: octo.gh.Repository}} local pull_requests = resp.data.repository.pullRequests.nodes if #pull_requests == 0 then utils.error(string.format("There are no matching pull requests in %s.", opts.repo)) @@ -520,6 +520,8 @@ local function get_search_query(prompt) } end +---@param prompt string +---@return string|nil local function get_search_size(prompt) local query = graphql("search_count_query", prompt) return gh.graphql { @@ -564,7 +566,7 @@ function M.search(opts) mode = "sync", } if output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {search: {nodes: octo.gh.Issue[]}}} for _, issue in ipairs(resp.data.search.nodes) do table.insert(results, issue) end @@ -687,13 +689,16 @@ function M.select_target_project_column(cb) cb = function(output) if output then local resp = vim.json.decode(output) - local projects = {} - local user_projects = resp.data.user and resp.data.user.projects.nodes or {} - local repo_projects = resp.data.repository and resp.data.repository.projects.nodes or {} - local org_projects = not resp.errors and resp.data.organization.projects.nodes or {} - vim.list_extend(projects, repo_projects) - vim.list_extend(projects, user_projects) - vim.list_extend(projects, org_projects) + local projects = {} ---@type octo.gh.Project[] + if resp.data.user then + vim.list_extend(projects, resp.data.user.projects.nodes) + end + if resp.data.repository then + vim.list_extend(projects, resp.data.repository.projects.nodes) + end + if not resp.errors then + vim.list_extend(projects, resp.data.organization.projects.nodes) + end if #projects == 0 then utils.error(string.format("There are no matching projects for %s.", buffer.repo)) return @@ -786,7 +791,7 @@ function M.select_label(cb) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local labels = resp.data.repository.labels.nodes pickers .new(opts, { @@ -822,13 +827,11 @@ function M.select_assigned_label(cb) if not buffer then return end - local query, key + local query ---@type string if buffer:isIssue() then query = graphql("issue_labels_query", buffer.owner, buffer.name, buffer.number) - key = "issue" elseif buffer:isPullRequest() then query = graphql("pull_request_labels_query", buffer.owner, buffer.name, buffer.number) - key = "pullRequest" end gh.run { args = { "api", "graphql", "-f", string.format("query=%s", query) }, @@ -836,8 +839,15 @@ function M.select_assigned_label(cb) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) - local labels = resp.data.repository[key].labels.nodes + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local labels ---@type octo.gh.Label[] + + if buffer:isIssue() then + labels = resp.data.repository.issue.labels.nodes + elseif buffer:isPullRequest() then + labels = resp.data.repository.pullRequest.labels.nodes + end + pickers .new(opts, { finder = finders.new_table { @@ -879,13 +889,13 @@ local function get_user_requester() args = { "api", "graphql", "--paginate", "-f", string.format("query=%s", query) }, mode = "sync", } - if output then + if not output then return {} end - local users = {} - local orgs = {} - local responses = utils.get_pages(output) + local users = {} ---@type table + local orgs = {} ---@type table + local responses = utils.get_pages(output) ---@type {data: {search: {nodes: (octo.gh.User | octo.gh.Organization)[]}}}[] for _, resp in ipairs(responses) do for _, user in ipairs(resp.data.search.nodes) do if not user.teams then @@ -925,6 +935,8 @@ local function get_user_requester() end end +---@param query_name string +---@param node_name string local function get_users(query_name, node_name) local repo = utils.get_remote_name() local owner, name = utils.split_repo(repo) @@ -937,12 +949,12 @@ local function get_users(query_name, node_name) return {} end - local responses = utils.get_pages(output) + local responses = utils.get_pages(output) ---@type {data: {repository: octo.gh.Repository}}[] - local users = {} + local users = {} ---@type octo.gh.User[] for _, resp in ipairs(responses) do - local nodes = resp.data.repository[node_name].nodes + local nodes = resp.data.repository[node_name].nodes ---@type octo.gh.User[] for _, user in ipairs(nodes) do table.insert(users, { id = user.id, @@ -1062,8 +1074,13 @@ function M.select_assignee(cb) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) - local assignees = resp.data.repository[key].assignees.nodes + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} + local assignees ---@type octo.gh.User[] + if buffer:isIssue() then + assignees = resp.data.repository.issue.assignees.nodes + elseif buffer:isPullRequest() then + assignees = resp.data.repository.pullRequest.assignees.nodes + end pickers .new(opts, { finder = finders.new_table { @@ -1108,7 +1125,7 @@ function M.repos(opts) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = utils.aggregate_pages(output, "data.repositoryOwner.repositories.nodes") + local resp = utils.aggregate_pages(output, "data.repositoryOwner.repositories.nodes") ---@type {data: {repositoryOwner: octo.gh.RepositoryOwner}} local repos = resp.data.repositoryOwner.repositories.nodes if #repos == 0 then utils.error(string.format("There are no matching repositories for %s.", opts.login)) diff --git a/lua/octo/reviews/init.lua b/lua/octo/reviews/init.lua index 7f7626fe..9e949abd 100644 --- a/lua/octo/reviews/init.lua +++ b/lua/octo/reviews/init.lua @@ -12,7 +12,7 @@ local utils = require "octo.utils" ---@class Review ---@field repo string ---@field number integer ----@field id integer +---@field id string ---@field threads table[] ---@field files FileEntry[] ---@field layout Layout @@ -36,6 +36,7 @@ function Review:new(pull_request) end -- Creates a new review +---@param callback fun(resp: {data: {addPullRequestReview: octo.gh.AddPullRequestReviewPayload}}) function Review:create(callback) local query = graphql("start_review_mutation", self.pull_request.id) gh.run { @@ -44,7 +45,7 @@ function Review:create(callback) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {addPullRequestReview: octo.gh.AddPullRequestReviewPayload}} callback(resp) end end, @@ -62,6 +63,7 @@ function Review:start() end -- Retrieves existing review +---@param callback fun(resp: {data: {repository: octo.gh.Repository}}) function Review:retrieve(callback) local query = graphql("pending_review_threads_query", self.pull_request.owner, self.pull_request.name, self.pull_request.number) @@ -71,7 +73,7 @@ function Review:retrieve(callback) if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} callback(resp) end end, @@ -203,7 +205,7 @@ function Review:discard() if stderr and not utils.is_blank(stderr) then utils.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} if #resp.data.repository.pullRequest.reviews.nodes == 0 then utils.error "No pending reviews found" return @@ -233,6 +235,7 @@ function Review:discard() } end +---@param threads octo.gh.PullRequestReviewThread[] function Review:update_threads(threads) self.threads = {} for _, thread in ipairs(threads) do @@ -477,7 +480,7 @@ end local M = {} -M.reviews = {} +M.reviews = {} ---@type table M.Review = Review diff --git a/lua/octo/reviews/layout.lua b/lua/octo/reviews/layout.lua index cd1fe2ce..d76a46fb 100644 --- a/lua/octo/reviews/layout.lua +++ b/lua/octo/reviews/layout.lua @@ -44,6 +44,7 @@ function Layout:new(opt) return this end +---@param review Review function Layout:open(review) vim.cmd "tab split" self.tabpage = vim.api.nvim_get_current_tabpage() diff --git a/lua/octo/ui/bubbles.lua b/lua/octo/ui/bubbles.lua index daadba56..61ba23c1 100644 --- a/lua/octo/ui/bubbles.lua +++ b/lua/octo/ui/bubbles.lua @@ -7,6 +7,9 @@ local colors = require "octo.ui.colors" -- background. The bubble shape gets especially defined by the outer delimiters. -- An examplary usage in this plugin are for label assigned to an issue. +---@param content string +---@param highlight_group string +---@param opts table local function make_bubble(content, highlight_group, opts) opts = opts or {} local conf = config.values @@ -52,6 +55,9 @@ local function make_user_bubble(name, is_viewer, opts) return make_bubble(content, highlight, opts) end +---@param icon string +---@param includes_viewer boolean +---@param opts table? local function make_reaction_bubble(icon, includes_viewer, opts) local conf = config.values local highlight = includes_viewer and "OctoReactionViewer" or "OctoReaction" diff --git a/lua/octo/ui/writers.lua b/lua/octo/ui/writers.lua index 955ce05a..19d0b042 100644 --- a/lua/octo/ui/writers.lua +++ b/lua/octo/ui/writers.lua @@ -11,13 +11,17 @@ local vim = vim local M = {} +---@param bufnr integer? +---@param lines string|string[] +---@param line integer? +---@param mark boolean? function M.write_block(bufnr, lines, line, mark) bufnr = bufnr or vim.api.nvim_get_current_buf() line = line or vim.api.nvim_buf_line_count(bufnr) + 1 mark = mark or false if type(lines) == "string" then - lines = vim.split(lines, "\n", true) + lines = vim.split(lines, "\n", { trimempty = true }) end -- write content lines @@ -125,6 +129,7 @@ function M.write_discussion_details(bufnr, discussion) M.write_detail_table { bufnr = bufnr, details = details, offset = 3 } end +---@param opts table function M.write_detail_table(opts) local bufnr = opts.bufnr local details = opts.details @@ -158,6 +163,9 @@ function M.write_upvotes(bufnr, obj, line) M.write_virtual_text(bufnr, constants.OCTO_REACTIONS_VT_NS, line, upvotes_vt) end +---@param bufnr integer +---@param obj octo.gh.Discussion | vim.NIL +---@param line integer function M.write_discussion_answer(bufnr, obj, line) local answer = obj.answer @@ -270,6 +278,9 @@ function M.write_repo(bufnr, repo) end end +---@param bufnr integer +---@param title string +---@param line integer function M.write_title(bufnr, title, line) local title_mark = M.write_block(bufnr, { title, "" }, line, true) vim.api.nvim_buf_add_highlight(bufnr, -1, "OctoIssueTitle", 0, 0, -1) @@ -285,6 +296,9 @@ function M.write_title(bufnr, title, line) end end +---@param bufnr integer +---@param state string +---@param number number function M.write_state(bufnr, state, number) bufnr = bufnr or vim.api.nvim_get_current_buf() local buffer = octo_buffers[bufnr] @@ -309,13 +323,16 @@ function M.write_state(bufnr, state, number) vim.api.nvim_buf_set_virtual_text(bufnr, constants.OCTO_TITLE_VT_NS, 0, title_vt, {}) end +---@param bufnr integer +---@param issue octo.gh.Issue | octo.gh.PullRequest | octo.gh.Discussion | vim.NIL +---@param line integer? function M.write_body(bufnr, issue, line) local body = utils.trim(issue.body) if vim.startswith(body, constants.NO_BODY_MSG) or utils.is_blank(body) then body = " " end local description = body:gsub("\r\n", "\n") - local lines = vim.split(description, "\n", true) + local lines = vim.split(description, "\n", { trimempty = true }) vim.list_extend(lines, { "" }) local desc_mark = M.write_block(bufnr, lines, line, true) local buffer = octo_buffers[bufnr] @@ -330,6 +347,10 @@ function M.write_body(bufnr, issue, line) end end +---@param bufnr integer +---@param reaction_groups octo.gh.ReactionGroup[] +---@param line integer +---@return integer|nil function M.write_reactions(bufnr, reaction_groups, line) local reactions_count = utils.count_reactions(reaction_groups) if reactions_count <= 0 then @@ -339,7 +360,7 @@ function M.write_reactions(bufnr, reaction_groups, line) -- clear namespace and set vt vim.api.nvim_buf_clear_namespace(bufnr, constants.OCTO_REACTIONS_VT_NS, line - 1, line + 1) - local reactions_vt = {} + local reactions_vt = {} ---@type {[1]: string, [2]: string}[] for _, group in ipairs(reaction_groups) do if group.users.totalCount > 0 then local icon = utils.reaction_map[group.content] @@ -352,6 +373,9 @@ function M.write_reactions(bufnr, reaction_groups, line) return line end +---@param bufnr integer +---@param issue table +---@param update boolean? function M.write_details(bufnr, issue, update) -- clear virtual texts vim.api.nvim_buf_clear_namespace(bufnr, constants.OCTO_DETAILS_VT_NS, 0, -1) @@ -1081,6 +1105,11 @@ local function chunk_length(max_length, chunk) return math.max(max_length, length) end +---@param bufnr integer +---@param user octo.gh.User +---@param opts table? +---@return integer num_chunks +---@return integer max_lenght function M.write_user_profile(bufnr, user, opts) opts = opts or {} local max_width = opts.max_width or 80 @@ -1739,6 +1768,11 @@ function M.write_threads(bufnr, threads) return comment_end end +---@param bufnr integer +---@param ns integer +---@param line integer +---@param chunks {[1]: string, [2]: string}[] +---@param mode string? function M.write_virtual_text(bufnr, ns, line, chunks, mode) mode = mode or "extmark" if mode == "extmark" then diff --git a/lua/octo/utils.lua b/lua/octo/utils.lua index 35d0a227..82640b0a 100644 --- a/lua/octo/utils.lua +++ b/lua/octo/utils.lua @@ -127,13 +127,16 @@ M.auto_merge_method_map = { SQUASH = "squash", } +---@param str string +---@return string function M.trim(str) if type(vim.fn.trim) == "function" then return vim.fn.trim(str) elseif type(vim.trim) == "function" then return vim.trim(str) else - return str:gsub("^%s*(.-)%s*$", "%1") + local trimmed = str:gsub("^%s*(.-)%s*$", "%1") + return trimmed end end @@ -191,6 +194,8 @@ function table.pack(...) return { n = select("#", ...), ... } end +---@param s nil|vim.NIL|string|table +---@return boolean function M.is_blank(s) return ( s == nil @@ -713,7 +718,7 @@ function M.get_repo_id(repo) args = { "api", "graphql", "-f", string.format("query=%s", query) }, mode = "sync", } - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local id = resp.data.repository.id repo_id_cache[repo] = id return id @@ -739,7 +744,7 @@ function M.get_repo_info(repo) args = { "api", "graphql", "-f", string.format("query=%s", query) }, mode = "sync", } - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local info = resp.data.repository repo_info_cache[repo] = info return info @@ -757,7 +762,7 @@ function M.get_repo_templates(repo) args = { "api", "graphql", "-f", string.format("query=%s", query) }, mode = "sync", } - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local templates = resp.data.repository -- add an option to not use a template @@ -953,7 +958,7 @@ function M.get_file_contents(repo, commit, path, cb) if stderr and not M.is_blank(stderr) then M.error(stderr) elseif output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} local blob = resp.data.repository.object local lines = {} if blob and blob ~= vim.NIL and type(blob.text) == "string" then @@ -998,9 +1003,13 @@ function M.cursor_in_col_range(start_col, end_col) return false end +---@param repo string +---@return string owner +---@return string name function M.split_repo(repo) - local owner = vim.split(repo, "/")[1] - local name = vim.split(repo, "/")[2] + local splitted = vim.split(repo, "/") + local owner = splitted[1] + local name = splitted[2] return owner, name end @@ -1109,6 +1118,8 @@ function M.text_wrap(text, width) return result end +---@param reaction_groups octo.gh.ReactionGroup[] +---@return integer function M.count_reactions(reaction_groups) local reactions_count = 0 for _, group in ipairs(reaction_groups) do @@ -1436,8 +1447,8 @@ function M.get_pull_request_for_current_branch(cb) return end local pr = vim.json.decode(out) - local base_owner - local base_name + local base_owner ---@type string + local base_name ---@type string if pr.number then if pr.isCrossRepository then -- Parsing the pr url is the only way to get the target repo owner if the pr is cross repo @@ -1539,7 +1550,7 @@ function M.get_user_id(login) mode = "sync", } if output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {user: octo.gh.User}} if resp.data.user and resp.data.user ~= vim.NIL then return resp.data.user.id end @@ -1561,7 +1572,7 @@ function M.get_label_id(label) mode = "sync", } if output then - local resp = vim.json.decode(output) + local resp = vim.json.decode(output) ---@type {data: {repository: octo.gh.Repository}} if resp.data.repository.labels.nodes and resp.data.repository.labels.nodes ~= vim.NIL then for _, l in ipairs(resp.data.repository.labels.nodes) do if l.name == label then @@ -1692,12 +1703,13 @@ end --- Logic to determine the state displayed for issue or PR ---@param isIssue boolean ----@param state string ----@param stateReason string | nil +---@param state octo.gh.IssueState | octo.gh.PullRequestState +---@param stateReason octo.gh.IssueStateReason | vim.NIL | nil ---@return string function M.get_displayed_state(isIssue, state, stateReason, isDraft) if isIssue and state == "CLOSED" then - return stateReason or state + ---@cast stateReason -vim.NIL + return (stateReason and stateReason ~= vim.NIL) and stateReason or state end if isDraft then