From 670f8e7730b2220811243b054aecb026261ebd09 Mon Sep 17 00:00:00 2001 From: Aaron Hallaert Date: Fri, 5 May 2023 21:48:45 +0200 Subject: [PATCH 1/3] Create commands api Signed-off-by: Aaron Hallaert --- .../{actions/init.lua => actions.lua} | 0 lua/advanced_git_search/commands/find.lua | 116 ++++++++++++++++ lua/advanced_git_search/commands/preview.lua | 104 +++++++++++++++ lua/advanced_git_search/commands/utils.lua | 63 +++++++++ lua/advanced_git_search/finders/init.lua | 126 ------------------ lua/advanced_git_search/fzf/finders/init.lua | 19 +++ lua/advanced_git_search/fzf/init.lua | 6 + lua/advanced_git_search/fzf/pickers/init.lua | 20 +++ .../fzf/previewers/init.lua | 47 +++++++ .../fzf/previewers/utils.lua | 12 ++ lua/advanced_git_search/previewers/init.lua | 121 ----------------- .../telescope/finders/init.lua | 58 ++++++++ .../{ => telescope}/finders/utils.lua | 27 +--- .../{ => telescope}/mappings/init.lua | 4 +- .../{ => telescope/pickers}/init.lua | 14 +- .../telescope/previewers/init.lua | 59 ++++++++ lua/advanced_git_search/utils/git.lua | 35 ----- lua/advanced_git_search/utils/init.lua | 17 +++ .../_extensions/advanced_git_search.lua | 19 ++- 19 files changed, 538 insertions(+), 329 deletions(-) rename lua/advanced_git_search/{actions/init.lua => actions.lua} (100%) create mode 100644 lua/advanced_git_search/commands/find.lua create mode 100644 lua/advanced_git_search/commands/preview.lua create mode 100644 lua/advanced_git_search/commands/utils.lua delete mode 100644 lua/advanced_git_search/finders/init.lua create mode 100644 lua/advanced_git_search/fzf/finders/init.lua create mode 100644 lua/advanced_git_search/fzf/init.lua create mode 100644 lua/advanced_git_search/fzf/pickers/init.lua create mode 100644 lua/advanced_git_search/fzf/previewers/init.lua create mode 100644 lua/advanced_git_search/fzf/previewers/utils.lua delete mode 100644 lua/advanced_git_search/previewers/init.lua create mode 100644 lua/advanced_git_search/telescope/finders/init.lua rename lua/advanced_git_search/{ => telescope}/finders/utils.lua (67%) rename lua/advanced_git_search/{ => telescope}/mappings/init.lua (99%) rename lua/advanced_git_search/{ => telescope/pickers}/init.lua (96%) create mode 100644 lua/advanced_git_search/telescope/previewers/init.lua diff --git a/lua/advanced_git_search/actions/init.lua b/lua/advanced_git_search/actions.lua similarity index 100% rename from lua/advanced_git_search/actions/init.lua rename to lua/advanced_git_search/actions.lua diff --git a/lua/advanced_git_search/commands/find.lua b/lua/advanced_git_search/commands/find.lua new file mode 100644 index 0000000..c03ba55 --- /dev/null +++ b/lua/advanced_git_search/commands/find.lua @@ -0,0 +1,116 @@ +local file = require("advanced_git_search.utils.file") +local git_utils = require("advanced_git_search.utils.git") + +-- Specify shell commands for each finders in table format +local M = {} + +M.git_branches = function() + return { + "git", + "branch", + "--format='%(refname:short)'", + } +end + +---@param prompt string|nil +---@param author string|nil +---@param bufnr number|nil +---@return table +M.git_log_content = function(prompt, author, bufnr) + local command = { + "git", + "log", + "--format='%h %as %an _ %s'", + } + + if author and author ~= "" then + table.insert(command, "--author=" .. author) + end + + if prompt and prompt ~= "" then + table.insert(command, "-G" .. prompt) + table.insert(command, "--pickaxe-all") + end + + if bufnr then + table.insert(command, "--follow") + local filename = file.relative_path(bufnr) + table.insert(command, filename) + end + + return vim.tbl_flatten(command) +end + +---@param prompt string|nil +---@param author string|nil +---@param bufnr number +---@return table +M.git_log_file = function(prompt, author, bufnr) + local filename = file.relative_path(bufnr) + local command = { + "git", + "log", + "--format='%h %as %an _ %s'", + } + + if author and author ~= "" then + table.insert(command, "--author=" .. author) + end + + if prompt and prompt ~= "" then + table.insert(command, "-s") + table.insert(command, "-i") + table.insert(command, "--grep=" .. prompt) + end + + table.insert(command, "--follow") + table.insert(command, filename) + + return vim.tbl_flatten(command) +end + +---@param prompt string|nil +---@param author string|nil +---@param bufnr number +---@param start_line number +---@param end_line number +---@return table +M.git_log_location = function(prompt, author, bufnr, start_line, end_line) + local filename = file.relative_path(bufnr) + local location = string.format("-L%d,%d:%s", start_line, end_line, filename) + local command = { + "git", + "log", + location, + "--no-patch", + "--format='%h %as %an _ %s'", + } + + if author and author ~= "" then + table.insert(command, "--author=" .. author) + end + + if prompt and prompt ~= "" then + table.insert(command, "-s") + table.insert(command, "-i") + table.insert(command, "--grep=" .. prompt) + end + + return vim.tbl_flatten(command) +end + +M.changed_on_branch = function() + vim.tbl_flatten({ + "git", + "--no-pager", + "diff", + "--name-only", + "--cached", + "--diff-filter=ACMR", + "--merge-base", + git_utils.base_branch(), + "--relative", + }) +end + +return M diff --git a/lua/advanced_git_search/commands/preview.lua b/lua/advanced_git_search/commands/preview.lua new file mode 100644 index 0000000..2e6fe0b --- /dev/null +++ b/lua/advanced_git_search/commands/preview.lua @@ -0,0 +1,104 @@ +local file = require("advanced_git_search.utils.file") +local git_utils = require("advanced_git_search.utils.git") +local cmd_utils = require("advanced_git_search.commands.utils") + +local M = {} + +--- Shows a diff of 2 commit hashes containing changes to the current file +---@param first_commit string +---@param second_commit string +---@param bufnr number +M.git_diff_file = function(first_commit, second_commit, bufnr) + local filename_on_head = file.git_relative_path(bufnr) + + local curr_name = + git_utils.file_name_on_commit(first_commit, filename_on_head) + local prev_name = + git_utils.file_name_on_commit(second_commit, filename_on_head) + + if prev_name ~= nil then + return cmd_utils.format_git_diff_command({ + "git", + "diff", + first_commit .. ":" .. prev_name, + second_commit .. ":" .. curr_name, + }) + else + return cmd_utils.format_git_diff_command({ + "git", + "diff", + first_commit, + second_commit, + "--", + file.git_relative_path_to_relative_path(curr_name), + }) + end +end + +--- Shows a diff of the passed file with a calculated base branch +--- @param relative_filename string +M.git_diff_base_branch = function(relative_filename) + return cmd_utils.format_git_diff_command({ + "git", + "diff", + "--diff-filter=ACMR", + "--cached", + "--merge-base", + git_utils.base_branch(), + "--", + relative_filename, + }) +end + +--- Shows a diff of 2 commit hashes and greps on prompt string +--- @param first_commit string +--- @param second_commit string +--- @param prompt string +M.git_diff_content = function(first_commit, second_commit, prompt) + local command = cmd_utils.format_git_diff_command({ + "git", + "diff", + "--color=always", + first_commit, + second_commit, + }) + + if prompt and prompt ~= "" then + table.insert(command, "-G") + table.insert(command, prompt) + end + + return command +end + +--- Shows a diff of branch and the file of the bufnr on HEAD +--- @param branch string +--- @param bufnr number +M.git_diff_branch = function(branch, bufnr) + local current_hash = git_utils.branch_hash("HEAD") + + local branch_filename = git_utils.file_name_on_commit( + git_utils.branch_hash(branch), + file.git_relative_path(bufnr) + ) + + if branch_filename ~= nil then + return cmd_utils.format_git_diff_command({ + "git", + "diff", + branch .. ":" .. branch_filename, + current_hash .. ":" .. file.git_relative_path(bufnr), + }) + else + return cmd_utils.format_git_diff_command({ + "git", + "diff", + branch, + current_hash, + "--", + file.relative_path(bufnr), + }) + end +end + +return M diff --git a/lua/advanced_git_search/commands/utils.lua b/lua/advanced_git_search/commands/utils.lua new file mode 100644 index 0000000..c4b030c --- /dev/null +++ b/lua/advanced_git_search/commands/utils.lua @@ -0,0 +1,63 @@ +local config = require("advanced_git_search.utils.config") +local utils = require("advanced_git_search.utils") + +local M = {} + +--- @param command table +--- @param git_flags_ix number|nil +--- @param git_diff_flags_ix number|nil +--- @return table Command with configured git diff flags +M.format_git_diff_command = function(command, git_flags_ix, git_diff_flags_ix) + git_flags_ix = git_flags_ix or 2 + git_diff_flags_ix = git_diff_flags_ix or 3 + + local git_diff_flags = config.git_diff_flags() + local git_flags = config.git_flags() + + if git_flags_ix > git_diff_flags_ix then + vim.notify( + "git_flags must be inserted before git_diff_flags", + vim.log.levels.ERROR + ) + end + + if git_diff_flags ~= nil and #git_diff_flags > 0 then + for i, flag in ipairs(git_diff_flags) do + table.insert(command, git_diff_flags_ix + i - 1, flag) + end + end + + if git_flags ~= nil and #git_flags > 0 then + for i, flag in ipairs(git_flags) do + table.insert(command, git_flags_ix + i - 1, flag) + end + end + + return command +end + +M.split_query_from_author = function(query) + local author = nil + local prompt = nil + if query ~= nil and query ~= "" then + -- starts with @ + if query:sub(1, 1) == "@" then + author = query:sub(2) + return prompt, author + end + + local split = utils.split_string(query, "@") + prompt = split[1] + + -- remove last space from prompt + if prompt:sub(-1) == " " then + prompt = prompt:sub(1, -2) + end + + author = split[2] + end + + return prompt, author +end + +return M diff --git a/lua/advanced_git_search/finders/init.lua b/lua/advanced_git_search/finders/init.lua deleted file mode 100644 index 34ffce9..0000000 --- a/lua/advanced_git_search/finders/init.lua +++ /dev/null @@ -1,126 +0,0 @@ -local finders = require("telescope.finders") -local file = require("advanced_git_search.utils.file") -local finder_utils = require("advanced_git_search.finders.utils") -local git_utils = require("advanced_git_search.utils.git") - -local M = {} - -M.git_branches_finder = function() - return finders.new_oneshot_job({ - "git", - "branch", - "--format=%(refname:short)", - }) -end - ---- Returns all commits that changed the visual selection in the buffer -M.git_log_location_finder = function(bufnr, start_line, end_line) - local filename = file.relative_path(bufnr) - local location = string.format("-L%d,%d:%s", start_line, end_line, filename) - - return finders.new_job(function(query) - local command = { - "git", - "log", - location, - "--no-patch", - "--format=%C(auto)%h %as %C(green)%an _ %Creset %s", - } - - local prompt, author = finder_utils.split_query_from_author(query) - - if author and author ~= "" then - table.insert(command, "--author=" .. author) - end - - if prompt and prompt ~= "" then - table.insert(command, "-s") - table.insert(command, "-i") - table.insert(command, "--grep=" .. prompt) - end - - finder_utils.set_last_prompt(prompt) - return vim.tbl_flatten(command) - end, finder_utils.git_log_entry_maker) -end - ---- Returns all commits that contains the prompt string in the commit content ---- @param opts table with optional key `bufnr` to filter on the file of the buffer -M.git_log_content_finder = function(opts) - opts = opts or {} - - return finders.new_job(function(query) - local command = { - "git", - "log", - "--format=%C(auto)%h %as %C(green)%an _ %Creset %s", - } - - local prompt, author = finder_utils.split_query_from_author(query) - - if author and author ~= "" then - table.insert(command, "--author=" .. author) - end - - if prompt and prompt ~= "" then - table.insert(command, "-G" .. prompt) - table.insert(command, "--pickaxe-all") - -- table.insert(command, [[-G']] .. prompt .. [[']]) - end - - if opts.bufnr then - table.insert(command, "--follow") - local filename = file.relative_path(opts.bufnr) - table.insert(command, filename) - end - - finder_utils.set_last_prompt(prompt) - return vim.tbl_flatten(command) - end, finder_utils.git_log_entry_maker) -end - ---- Returns all commits that changed the file of the passed buffer -M.git_log_file_finder = function(bufnr) - local filename = file.relative_path(bufnr) - return finders.new_job(function(query) - local command = { - "git", - "log", - "--format=%C(auto)%h %as %C(green)%an _ %Creset %s", - } - - local prompt, author = finder_utils.split_query_from_author(query) - - if author and author ~= "" then - table.insert(command, "--author=" .. author) - end - - if prompt and prompt ~= "" then - table.insert(command, "-s") - table.insert(command, "-i") - table.insert(command, "--grep=" .. prompt) - end - - table.insert(command, "--follow") - table.insert(command, filename) - - finder_utils.set_last_prompt(prompt) - return vim.tbl_flatten(command) - end, finder_utils.git_log_entry_maker) -end - -M.changed_files_on_current_branch_finder = function() - return finders.new_oneshot_job(vim.tbl_flatten({ - "git", - "--no-pager", - "diff", - "--name-only", - "--cached", - "--diff-filter=ACMR", - "--merge-base", - git_utils.base_branch(), - "--relative", - })) -end - -return M diff --git a/lua/advanced_git_search/fzf/finders/init.lua b/lua/advanced_git_search/fzf/finders/init.lua new file mode 100644 index 0000000..e67f376 --- /dev/null +++ b/lua/advanced_git_search/fzf/finders/init.lua @@ -0,0 +1,19 @@ +local preview_utils = require("advanced_git_search.fzf.previewers.utils") +local cmd_utils = require("advanced_git_search.commands.utils") +local finder_cmds = require("advanced_git_search.commands.find") +local utils = require("advanced_git_search.utils") + +local M = {} + +M.git_log_content_finder = function(query) + preview_utils.set_last_query(query) + + local prompt, author = cmd_utils.split_query_from_author(query) + + return table.concat( + finder_cmds.git_log_content(utils.escape_term(prompt), author), + " " + ) +end + +return M diff --git a/lua/advanced_git_search/fzf/init.lua b/lua/advanced_git_search/fzf/init.lua new file mode 100644 index 0000000..7a6f3be --- /dev/null +++ b/lua/advanced_git_search/fzf/init.lua @@ -0,0 +1,6 @@ +local M = {} + +M.search_log_content = + require("advanced_git_search.fzf.pickers").search_log_content() + +return M diff --git a/lua/advanced_git_search/fzf/pickers/init.lua b/lua/advanced_git_search/fzf/pickers/init.lua new file mode 100644 index 0000000..1ca74c5 --- /dev/null +++ b/lua/advanced_git_search/fzf/pickers/init.lua @@ -0,0 +1,20 @@ +local M = {} + +local ags_previewers = require("advanced_git_search.fzf.previewers") +local ags_finders = require("advanced_git_search.fzf.finders") + +M.search_log_content = function() + local opts = { + prompt = "Log> ", + exec_empty_query = false, + func_async_callback = false, + fzf_opts = { + ["--preview"] = ags_previewers.git_diff_content_previewer(), + }, + } + + vim.print("Execute search log content") + require("fzf-lua").fzf_live(ags_finders.git_log_content_finder, opts) +end + +return M diff --git a/lua/advanced_git_search/fzf/previewers/init.lua b/lua/advanced_git_search/fzf/previewers/init.lua new file mode 100644 index 0000000..05b325b --- /dev/null +++ b/lua/advanced_git_search/fzf/previewers/init.lua @@ -0,0 +1,47 @@ +local cmd_utils = require("advanced_git_search.commands.utils") +local fzf_lua = require("fzf-lua") +local preview_utils = require("advanced_git_search.fzf.previewers.utils") +local utils = require("advanced_git_search.utils") +local preview_commands = require("advanced_git_search.commands.preview") +local git_utils = require("advanced_git_search.utils.git") + +local M = {} + +M.git_diff_content_previewer = function() + return fzf_lua.shell.preview_action_cmd(function(items) + local selection = items[1] + local hash = string.sub(selection, 1, 7) + + local prev_commit = git_utils.previous_commit_hash(hash) + -- local preview_command = + -- string.format("git --no-pager diff %s~ %s", hash, hash) + -- + local prompt, _ = + cmd_utils.split_query_from_author(preview_utils.get_last_query()) + + -- preview_command = preview_command .. string.format(" --color=always") + -- + -- -- command + -- if prompt and prompt ~= "" then + -- preview_command = preview_command + -- .. " -G '" + -- .. utils.escape_term(prompt) + -- .. "'" + -- end + -- + local preview_command = table.concat( + preview_commands.git_diff_content(prev_commit, hash, prompt), + " " + ) + + preview_command = preview_command + .. string.format( + " | GREP_COLOR='3;30;105' grep -A 999999 -B 999999 --color=always '%s'", + prompt + ) + + return preview_command + end) +end + +return M diff --git a/lua/advanced_git_search/fzf/previewers/utils.lua b/lua/advanced_git_search/fzf/previewers/utils.lua new file mode 100644 index 0000000..c2ed32d --- /dev/null +++ b/lua/advanced_git_search/fzf/previewers/utils.lua @@ -0,0 +1,12 @@ +local M = {} +local last_query = "" + +M.set_last_query = function(query) + last_query = query +end + +M.get_last_query = function() + return last_query +end + +return M diff --git a/lua/advanced_git_search/previewers/init.lua b/lua/advanced_git_search/previewers/init.lua deleted file mode 100644 index 4a55cf5..0000000 --- a/lua/advanced_git_search/previewers/init.lua +++ /dev/null @@ -1,121 +0,0 @@ -local previewers = require("telescope.previewers") -local file = require("advanced_git_search.utils.file") -local git_utils = require("advanced_git_search.utils.git") - -local M = {} - ---- Shows a diff of the commit in the finder entry, filtered on the file of the current buffer -M.git_diff_commit_file_previewer = function(bufnr) - local filename_on_head = file.git_relative_path(bufnr) - return previewers.new_termopen_previewer({ - title = "Changes on selected commit for: " .. file.file_name(bufnr), - get_command = function(entry) - local commit_hash = entry.opts.commit_hash - - local prev_commit = git_utils.previous_commit_hash(commit_hash) - - local curr_name = - git_utils.file_name_on_commit(commit_hash, filename_on_head) - local prev_name = - git_utils.file_name_on_commit(prev_commit, filename_on_head) - - if prev_name ~= nil then - return git_utils.git_diff_command({ - "git", - "diff", - prev_commit .. ":" .. prev_name, - commit_hash .. ":" .. curr_name, - }) - else - return git_utils.git_diff_command({ - "git", - "diff", - prev_commit, - commit_hash, - "--", - file.git_relative_path_to_relative_path(curr_name), - }) - end - end, - }) -end - ---- Shows a diff of the commit in the finder entry, filtered on the prompt string for the commit content -M.git_diff_content_previewer = function() - return previewers.new_termopen_previewer({ - title = "Changes including prompt string", - get_command = function(entry) - local commit_hash = entry.opts.commit_hash - local prompt = entry.opts.prompt - local command = git_utils.git_diff_command({ - "git", - "diff", - string.format("%s~", commit_hash), - commit_hash, - }) - - if prompt and prompt ~= "" then - table.insert(command, "-G") - table.insert(command, prompt) - end - - return command - end, - }) -end - ---- Shows a diff of the file in the finder entry and the fork point of the current branch -M.changed_files_on_current_branch_previewer = function() - return previewers.new_termopen_previewer({ - title = "Diff of selected file and fork point", - get_command = function(entry) - return git_utils.git_diff_command({ - "git", - "diff", - "--diff-filter=ACMR", - "--cached", - "--merge-base", - git_utils.base_branch(), - "--", - entry.value, - }) - end, - }) -end - ---- Shows a diff of the branch in the finder entry relative to the passed filename -M.git_diff_branch_file_previewer = function(bufnr) - local filename = file.file_name(bufnr) - return previewers.new_termopen_previewer({ - title = "Diff of current buffer and selected branch for: " .. filename, - get_command = function(entry) - local branch = entry.value - local current_hash = git_utils.branch_hash("HEAD") - - local branch_filename = git_utils.file_name_on_commit( - git_utils.branch_hash(branch), - file.git_relative_path(bufnr) - ) - - if branch_filename ~= nil then - return git_utils.git_diff_command({ - "git", - "diff", - branch .. ":" .. branch_filename, - current_hash .. ":" .. file.git_relative_path(bufnr), - }) - else - return git_utils.git_diff_command({ - "git", - "diff", - branch, - current_hash, - "--", - file.relative_path(bufnr), - }) - end - end, - }) -end - -return M diff --git a/lua/advanced_git_search/telescope/finders/init.lua b/lua/advanced_git_search/telescope/finders/init.lua new file mode 100644 index 0000000..8203e88 --- /dev/null +++ b/lua/advanced_git_search/telescope/finders/init.lua @@ -0,0 +1,58 @@ +local finders = require("telescope.finders") +local finder_utils = require("advanced_git_search.telescope.finders.utils") +local cmd_utils = require("advanced_git_search.commands.utils") +local finder_cmds = require("advanced_git_search.commands.find") + +local M = {} + +M.git_branches_finder = function() + return finders.new_oneshot_job(finder_cmds.git_branches()) +end + +--- Returns all commits that changed the visual selection in the buffer +M.git_log_location_finder = function(bufnr, start_line, end_line) + return finders.new_job(function(query) + local prompt, author = cmd_utils.split_query_from_author(query) + + finder_utils.set_last_prompt(prompt) + + return finder_cmds.git_log_location( + prompt, + author, + bufnr, + start_line, + end_line + ) + end, finder_utils.git_log_entry_maker) +end + +--- Returns all commits that contains the prompt string in the commit content +--- @param opts table with optional key `bufnr` to filter on the file of the buffer +M.git_log_content_finder = function(opts) + opts = opts or {} + + return finders.new_job(function(query) + local prompt, author = cmd_utils.split_query_from_author(query) + + finder_utils.set_last_prompt(prompt) + return finder_cmds.git_log_content(prompt, author, opts.bufnr) + end, finder_utils.git_log_entry_maker) +end + +--- Returns all commits that changed the file of the passed buffer +M.git_log_file_finder = function(bufnr) + return finders.new_job(function(query) + local prompt, author = cmd_utils.split_query_from_author(query) + + finder_utils.set_last_prompt(prompt) + return finder_cmds.git_log_file(prompt, author, bufnr) + end, finder_utils.git_log_entry_maker) +end + +M.changed_files_on_current_branch_finder = function() + return finders.new_oneshot_job( + finder_cmds.git_changed_files_on_current_branch() + ) +end + +return M diff --git a/lua/advanced_git_search/finders/utils.lua b/lua/advanced_git_search/telescope/finders/utils.lua similarity index 67% rename from lua/advanced_git_search/finders/utils.lua rename to lua/advanced_git_search/telescope/finders/utils.lua index 039d7a3..56fc722 100644 --- a/lua/advanced_git_search/finders/utils.lua +++ b/lua/advanced_git_search/telescope/finders/utils.lua @@ -3,37 +3,14 @@ local utils = require("advanced_git_search.utils") local M = {} local last_prompt = nil -M.split_query_from_author = function(query) - local author = nil - local prompt = nil - if query ~= nil and query ~= "" then - -- starts with @ - if query:sub(1, 1) == "@" then - author = query:sub(2) - return prompt, author - end - - local split = utils.split_string(query, "@") - prompt = split[1] - - -- remove last space from prompt - if prompt:sub(-1) == " " then - prompt = prompt:sub(1, -2) - end - - author = split[2] - end - - return prompt, author -end - --- Parse "--format=%C(auto)%h %as %C(green)%an _ %Creset %s" to table --- with opts: commit_hash, date, author, message, prompt --- @param entry string M.git_log_entry_maker = function(entry) -- dce3b0743 2022-09-09 author _ message -- FIXME: will break if author contains _ - local split = utils.split_string(entry, "_") + local cleaned = string.gsub(entry, "'", "") + local split = utils.split_string(cleaned, "_") local attrs = utils.split_string(split[1]) local hash = attrs[1] local date = attrs[2] diff --git a/lua/advanced_git_search/mappings/init.lua b/lua/advanced_git_search/telescope/mappings/init.lua similarity index 99% rename from lua/advanced_git_search/mappings/init.lua rename to lua/advanced_git_search/telescope/mappings/init.lua index e35c09a..f18095b 100644 --- a/lua/advanced_git_search/mappings/init.lua +++ b/lua/advanced_git_search/telescope/mappings/init.lua @@ -1,6 +1,8 @@ local actions = require("telescope.actions") -local ags_actions = require("advanced_git_search.actions") local action_state = require("telescope.actions.state") + +local ags_actions = require("advanced_git_search.actions") + local file = require("advanced_git_search.utils.file") local git_utils = require("advanced_git_search.utils.git") local config = require("advanced_git_search.utils.config") diff --git a/lua/advanced_git_search/init.lua b/lua/advanced_git_search/telescope/pickers/init.lua similarity index 96% rename from lua/advanced_git_search/init.lua rename to lua/advanced_git_search/telescope/pickers/init.lua index 4eb9578..c9c7d0d 100644 --- a/lua/advanced_git_search/init.lua +++ b/lua/advanced_git_search/telescope/pickers/init.lua @@ -6,9 +6,10 @@ local config = require("advanced_git_search.utils.config") local pickers = require("telescope.pickers") local sorters = require("telescope.sorters") local finders = require("telescope.finders") -local ags_finders = require("advanced_git_search.finders") -local ags_previewers = require("advanced_git_search.previewers") -local ags_mappings = require("advanced_git_search.mappings") + +local ags_finders = require("advanced_git_search.telescope.finders") +local ags_previewers = require("advanced_git_search.telescope.previewers") +local ags_mappings = require("advanced_git_search.telescope.mappings") local M = {} @@ -269,11 +270,4 @@ M.show_custom_functions = function() }) :find() end - -vim.api.nvim_create_user_command( - "AdvancedGitSearch", - "lua require('telescope').extensions.advanced_git_search.show_custom_functions()", - { range = true } -) - return M diff --git a/lua/advanced_git_search/telescope/previewers/init.lua b/lua/advanced_git_search/telescope/previewers/init.lua new file mode 100644 index 0000000..357e01c --- /dev/null +++ b/lua/advanced_git_search/telescope/previewers/init.lua @@ -0,0 +1,59 @@ +local previewers = require("telescope.previewers") +local file = require("advanced_git_search.utils.file") +local git_utils = require("advanced_git_search.utils.git") +local preview_cmds = require("advanced_git_search.commands.preview") + +local M = {} + +--- Shows a diff of the commit in the finder entry, filtered on the file of the current buffer +M.git_diff_commit_file_previewer = function(bufnr) + return previewers.new_termopen_previewer({ + title = "Changes on selected commit for: " .. file.file_name(bufnr), + get_command = function(entry) + local commit_hash = entry.opts.commit_hash + local prev_commit = git_utils.previous_commit_hash(commit_hash) + return preview_cmds.git_diff_file(prev_commit, commit_hash, bufnr) + end, + }) +end + +--- Shows a diff of the commit in the finder entry, filtered on the prompt string for the commit content +M.git_diff_content_previewer = function() + return previewers.new_termopen_previewer({ + title = "Changes including prompt string", + get_command = function(entry) + local commit_hash = entry.opts.commit_hash + local prompt = entry.opts.prompt + local prev_commit = git_utils.previous_commit_hash(commit_hash) + return preview_cmds.git_diff_content( + prev_commit, + commit_hash, + prompt + ) + end, + }) +end + +--- Shows a diff of the file in the finder entry and the fork point of the current branch +M.changed_files_on_current_branch_previewer = function() + return previewers.new_termopen_previewer({ + title = "Diff of selected file and fork point", + get_command = function(entry) + return preview_cmds.git_diff_base_branch(entry.value) + end, + }) +end + +--- Shows a diff of the branch in the finder entry relative to the passed filename +M.git_diff_branch_file_previewer = function(bufnr) + local filename = file.file_name(bufnr) + return previewers.new_termopen_previewer({ + title = "Diff of current buffer and selected branch for: " .. filename, + get_command = function(entry) + local branch = entry.value + return preview_cmds.git_diff_branch(branch, bufnr) + end, + }) +end + +return M diff --git a/lua/advanced_git_search/utils/git.lua b/lua/advanced_git_search/utils/git.lua index 980e165..aa3982f 100644 --- a/lua/advanced_git_search/utils/git.lua +++ b/lua/advanced_git_search/utils/git.lua @@ -22,41 +22,6 @@ local all_commit_hashes_touching_file = function(git_relative_file_path) return utils.split_string(output, "\n") end ---- @param command table ---- @param git_flags_ix number|nil ---- @param git_diff_flags_ix number|nil ---- @return table Command with configured git diff flags -local git_diff_command = function(command, git_flags_ix, git_diff_flags_ix) - git_flags_ix = git_flags_ix or 2 - git_diff_flags_ix = git_diff_flags_ix or 3 - - local git_diff_flags = config.git_diff_flags() - local git_flags = config.git_flags() - - if git_flags_ix > git_diff_flags_ix then - vim.notify( - "git_flags must be inserted before git_diff_flags", - vim.log.levels.ERROR - ) - end - - if git_diff_flags ~= nil and #git_diff_flags > 0 then - for i, flag in ipairs(git_diff_flags) do - table.insert(command, git_diff_flags_ix + i - 1, flag) - end - end - - if git_flags ~= nil and #git_flags > 0 then - for i, flag in ipairs(git_flags) do - table.insert(command, git_flags_ix + i - 1, flag) - end - end - - return command -end - -M.git_diff_command = git_diff_command - M.previous_commit_hash = function(commit_hash) local command = "git rev-parse " .. commit_hash .. "~" diff --git a/lua/advanced_git_search/utils/init.lua b/lua/advanced_git_search/utils/init.lua index be343c2..da3dd90 100644 --- a/lua/advanced_git_search/utils/init.lua +++ b/lua/advanced_git_search/utils/init.lua @@ -44,4 +44,21 @@ M.escape_chars = function(x) ) end +M.escape_term = function(x) + return ( + x:gsub("%%", "\\%%") + :gsub("^%^", "\\%^") + :gsub("%$$", "\\%$") + :gsub("%(", "\\%(") + :gsub("%)", "\\%)") + :gsub("%.", "\\%.") + :gsub("%[", "\\%[") + :gsub("%]", "\\%]") + :gsub("%*", "\\%*") + :gsub("%+", "\\%+") + :gsub("%-", "\\%-") + :gsub("%?", "\\%?") + ) +end + return M diff --git a/lua/telescope/_extensions/advanced_git_search.lua b/lua/telescope/_extensions/advanced_git_search.lua index e4dc0b6..0acc5d3 100644 --- a/lua/telescope/_extensions/advanced_git_search.lua +++ b/lua/telescope/_extensions/advanced_git_search.lua @@ -1,18 +1,15 @@ -local func = require("advanced_git_search") +local pickers = require("advanced_git_search.telescope.pickers") local config = require("advanced_git_search.utils.config") return require("telescope").register_extension({ setup = function(ext_config, _) config.setup(ext_config) + + vim.api.nvim_create_user_command( + "AdvancedGitSearch", + "lua require('telescope').extensions.advanced_git_search.show_custom_functions()", + { range = true } + ) end, - exports = { - checkout_reflog = func.checkout_reflog, - diff_branch_file = func.diff_branch_file, - diff_commit_file = func.diff_commit_file, - diff_commit_line = func.diff_commit_line, - search_log_content = func.search_log_content, - search_log_content_file = func.search_log_content_file, - show_custom_functions = func.show_custom_functions, - changed_on_branch = func.changed_on_branch, - }, + exports = pickers, }) From 8430f04a176bda111134854a0260bb66c71f4ea5 Mon Sep 17 00:00:00 2001 From: Aaron Hallaert Date: Fri, 5 May 2023 22:21:36 +0200 Subject: [PATCH 2/3] Add fzf-lua support Port search_log_content to fzf Signed-off-by: Aaron Hallaert Port search_log_content_file to fzf Signed-off-by: Aaron Hallaert Port diff_commit_line to fzf Signed-off-by: Aaron Hallaert Port diff_commit_file to fzf Signed-off-by: Aaron Hallaert Transform entries fzf Signed-off-by: Aaron Hallaert Add actions fzf Signed-off-by: Aaron Hallaert Add global picker fzf Signed-off-by: Aaron Hallaert Add changed on branch fzf Signed-off-by: Aaron Hallaert Add checkout reflog fzf Signed-off-by: Aaron Hallaert Rename requires Signed-off-by: Aaron Hallaert Update readme Signed-off-by: Aaron Hallaert Fix git_diff_file Signed-off-by: Aaron Hallaert Fix query inputs and fallbacks for prompt and author Signed-off-by: Aaron Hallaert --- README.md | 126 +++++++++-- lua/advanced_git_search/actions.lua | 45 +++- lua/advanced_git_search/commands/find.lua | 25 ++- lua/advanced_git_search/commands/preview.lua | 15 +- lua/advanced_git_search/commands/utils.lua | 2 + lua/advanced_git_search/fzf/finders/init.lua | 63 +++++- lua/advanced_git_search/fzf/init.lua | 25 ++- lua/advanced_git_search/fzf/mappings/init.lua | 83 +++++++ lua/advanced_git_search/fzf/pickers/init.lua | 204 ++++++++++++++++- lua/advanced_git_search/fzf/pickers/utils.lua | 64 ++++++ .../fzf/previewers/init.lua | 76 +++++-- lua/advanced_git_search/global_picker.lua | 121 ++++++++++ .../telescope/finders/init.lua | 42 ++-- .../telescope/mappings/init.lua | 31 +-- .../telescope/pickers/init.lua | 208 +++++++----------- .../telescope/previewers/init.lua | 21 +- lua/advanced_git_search/utils/git.lua | 7 +- lua/advanced_git_search/utils/init.lua | 2 + 18 files changed, 909 insertions(+), 251 deletions(-) create mode 100644 lua/advanced_git_search/fzf/mappings/init.lua create mode 100644 lua/advanced_git_search/fzf/pickers/utils.lua create mode 100644 lua/advanced_git_search/global_picker.lua diff --git a/README.md b/README.md index 6c557a4..d58341d 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,44 @@ -# Telescope Advanced Git Search +# Advanced Git Search + +An advanced git search extension for `Telescope` and `fzf-lua`. + +Search your git history by commit message, content and author in Neovim ## 🖥️ Usage -[![Demo](https://img.youtube.com/vi/bO0uYLlHtYo/0.jpg)](https://www.youtube.com/watch?v=bO0uYLlHtYo) +- [Demo](https://www.youtube.com/watch?v=bO0uYLlHtYo) ### 📖 Open a picker +#### 🔭 Telescope + ```vim :Telescope advanced_git_search {function_name} ``` -#### or in lua +> or in lua ```lua require('telescope').extensions.advanced_git_search.{function_name}() ``` -#### or through another Telescope picker +> or through another Telescope picker + +execute `:AdvancedGitSearch`, choose your picker and press `` + +#### 🧎 fzf-lua + +```lua +require('advanced-git-search.fzf').{function_name}() +``` + +> or through another picker execute `:AdvancedGitSearch`, choose your picker and press `` ### 🔎 Enter a query -Your usual telescope experience. See the individual commands for the grep behaviour. +Your usual search experience. See the individual commands for the grep behaviour. ### ✏️ Further search on commit author with `@` @@ -33,7 +49,7 @@ the author name. ### 1. search_log_content -- Search in repo log content -Opens a Telescope window with a list of all previous commit. +Opens a window with a list of all previous commit. _Grep behaviour_: filter on added, updated or removed code (log content: `-G` option in git). @@ -46,7 +62,7 @@ _Grep behaviour_: filter on added, updated or removed code (log content: `-G` op ### 2. search_log_content_file -- Search in file log content -Opens a Telescope window with a list of git commits that changed the +Opens a window with a list of git commits that changed the current file (renames included). _Grep behaviour_: filter on added, updated or removed code (log content: `-G` option in git). @@ -60,7 +76,7 @@ _Grep behaviour_: filter on added, updated or removed code (log content: `-G` op ### 3. diff_commit_file -- Diff current file with commit -Opens a Telescope window with a list of git commits that changed the +Opens a window with a list of git commits that changed the current file (renames included). _Grep behaviour_: filter on commit message. @@ -74,19 +90,18 @@ _Grep behaviour_: filter on commit message. ### 4. diff_commit_line -- Diff current file with selected line history -Opens a Telescope window with a list of previous commit logs with respect to +Opens a window with a list of previous commit logs with respect to selected lines _Grep behaviour_: filter on commit message. #### How to use -_The following only applies when you use one of the commands below._ - -```vim -:Telescope advanced_git_search diff_commit_line -:lua require('telescope').extensions.advanced_git_search.diff_commit_line() -``` +> _This workaround only applies when you use the following command. (Telescope)_ +> +> ```vim +> :Telescope advanced_git_search diff_commit_line +> ``` First you have to select the lines in visual mode, then go back to normal mode and execute this command. @@ -107,7 +122,7 @@ vim.api.nvim_set_keymap( ) ``` -No extra setup is needed when you use `:AdvancedGitSearch`. +> No extra setup is needed when you use `:AdvancedGitSearch`. #### _Keymaps_ @@ -118,7 +133,7 @@ No extra setup is needed when you use `:AdvancedGitSearch`. ### 5. diff_branch_file -- Diff file with branch -Opens a Telescope window with a list of local branches +Opens a window with a list of local branches _Grep behaviour_: filter on branch name. @@ -128,7 +143,7 @@ _Grep behaviour_: filter on branch name. ### 6. changed_on_branch -- Changed on current branch (experimental) -Opens a Telescope window with a list of changed files on the current branch (including staged files). +Opens a window with a list of changed files on the current branch (including staged files). The fork point of the current branch is determined with the following command: ```sh @@ -150,7 +165,7 @@ _Grep behaviour_: filter on filename. ### 7. checkout_reflog -- Checkout from reflog -Opens a Telescope window with all reflog entries +Opens a window with all reflog entries #### _Keymaps_ @@ -159,10 +174,12 @@ Opens a Telescope window with all reflog entries ### 8. show_custom_functions A telescope picker for all functions above. -Enable `show_builtin_git_pickers` to additionally show Telescopes builtin git pickers. +Enable `show_builtin_git_pickers` to additionally show builtin git pickers. ## ⚙️ Installation +### Telescope + With Lazy ```lua @@ -243,6 +260,75 @@ With Packer }) ``` +### Fzf-lua + +With Lazy + +```lua + { + "aaronhallaert/advanced-git-search.nvim", + config = function() + -- optional: setup telescope before loading the extension + require("advanced-git-search.fzf").setup{ + -- fugitive or diffview + diff_plugin = "fugitive", + -- customize git in previewer + -- e.g. flags such as { "--no-pager" }, or { "-c", "delta.side-by-side=false" } + git_flags = {}, + -- customize git diff in previewer + -- e.g. flags such as { "--raw" } + git_diff_flags = {}, + -- Show builtin git pickers when executing "show_custom_functions" or :AdvancedGitSearch + show_builtin_git_pickers = false, + } + end, + dependencies = { + "ibhagwan/fzf-lua", + -- to show diff splits and open commits in browser + "tpope/vim-fugitive", + -- to open commits in browser with fugitive + "tpope/vim-rhubarb", + -- OPTIONAL: to replace the diff from fugitive with diffview.nvim + -- (fugitive is still needed to open in browser) + -- "sindrets/diffview.nvim", + }, + } +``` + +With Packer + +```lua + use({ + "aaronhallaert/advanced-git-search.nvim", + config = function() + -- optional: setup telescope before loading the extension + require("advanced-git-search.fzf").setup{ + -- Fugitive or diffview + diff_plugin = "fugitive", + -- Customize git in previewer + -- e.g. flags such as { "--no-pager" }, or { "-c", "delta.side-by-side=false" } + git_flags = {}, + -- Customize git diff in previewer + -- e.g. flags such as { "--raw" } + git_diff_flags = {}, + -- Show builtin git pickers when executing "show_custom_functions" or :AdvancedGitSearch + show_builtin_git_pickers = false, + } + } + end, + requires = { + "ibhagwan/fzf-lua", + -- to show diff splits and open commits in browser + "tpope/vim-fugitive", + -- to open commits in browser with fugitive + "tpope/vim-rhubarb", + -- optional: to replace the diff from fugitive with diffview.nvim + -- (fugitive is still needed to open in browser) + -- "sindrets/diffview.nvim", + }, + }) +``` + ### Prerequisites - git diff --git a/lua/advanced_git_search/actions.lua b/lua/advanced_git_search/actions.lua index 28caf44..c220dc9 100644 --- a/lua/advanced_git_search/actions.lua +++ b/lua/advanced_git_search/actions.lua @@ -2,9 +2,23 @@ local config = require("advanced_git_search.utils.config") local M = {} ---- open diff for current file ---- @param commit string commit or branch to diff with ---- @param file_name string|nil file name to diff +---General action: Open entire commit with fugitive or diffview +---@param commit_hash string +M.open_commit = function(commit_hash) + local diff_plugin = config.diff_plugin() + + if diff_plugin == "diffview" then + vim.api.nvim_command( + ":DiffviewOpen -uno " .. commit_hash .. "~.." .. commit_hash + ) + elseif diff_plugin == "fugitive" then + vim.api.nvim_command(":Gedit " .. commit_hash) + end +end + +---General action: open diff for current file +---@param commit string commit or branch to diff with +---@param file_name string|nil file name to diff M.open_diff_view = function(commit, file_name) local diff_plugin = config.diff_plugin() @@ -25,4 +39,29 @@ M.open_diff_view = function(commit, file_name) end end +---General action: Copy commit hash to system clipboard +---@param commit_hash string +M.copy_to_clipboard = function(commit_hash) + vim.notify( + "Copied commit hash " .. commit_hash .. " to clipboard", + vim.log.levels.INFO, + { title = "Advanced Git Search" } + ) + + vim.fn.setreg("+", commit_hash) + vim.fn.setreg("*", commit_hash) +end + +---General action: Open commit in browser +---@param commit_hash string +M.open_in_browser = function(commit_hash) + vim.api.nvim_command(":GBrowse " .. commit_hash) +end + +---General action: Checkout commit +---@param commit_hash string +M.checkout_commit = function(commit_hash) + vim.api.nvim_command(":!git checkout " .. commit_hash) +end + return M diff --git a/lua/advanced_git_search/commands/find.lua b/lua/advanced_git_search/commands/find.lua index c03ba55..4d4db62 100644 --- a/lua/advanced_git_search/commands/find.lua +++ b/lua/advanced_git_search/commands/find.lua @@ -12,6 +12,14 @@ M.git_branches = function() } end +M.reflog = function() + return { + "git", + "reflog", + "--date=iso", + } +end + ---@param prompt string|nil ---@param author string|nil ---@param bufnr number|nil @@ -23,12 +31,13 @@ M.git_log_content = function(prompt, author, bufnr) "--format='%h %as %an _ %s'", } - if author and author ~= "" then + if author and author ~= "" and author ~= '""' then table.insert(command, "--author=" .. author) end - if prompt and prompt ~= "" then - table.insert(command, "-G" .. prompt) + if prompt and prompt ~= "" and prompt ~= '""' then + table.insert(command, "-G") + table.insert(command, prompt) table.insert(command, "--pickaxe-all") end @@ -53,11 +62,11 @@ M.git_log_file = function(prompt, author, bufnr) "--format='%h %as %an _ %s'", } - if author and author ~= "" then + if author and author ~= "" and author ~= '""' then table.insert(command, "--author=" .. author) end - if prompt and prompt ~= "" then + if prompt and prompt ~= "" and prompt ~= '""' then table.insert(command, "-s") table.insert(command, "-i") table.insert(command, "--grep=" .. prompt) @@ -86,11 +95,11 @@ M.git_log_location = function(prompt, author, bufnr, start_line, end_line) "--format='%h %as %an _ %s'", } - if author and author ~= "" then + if author and author ~= "" and author ~= '""' then table.insert(command, "--author=" .. author) end - if prompt and prompt ~= "" then + if prompt and prompt ~= "" and prompt ~= '""' then table.insert(command, "-s") table.insert(command, "-i") table.insert(command, "--grep=" .. prompt) @@ -100,7 +109,7 @@ M.git_log_location = function(prompt, author, bufnr, start_line, end_line) end M.changed_on_branch = function() - vim.tbl_flatten({ + return vim.tbl_flatten({ "git", "--no-pager", "diff", diff --git a/lua/advanced_git_search/commands/preview.lua b/lua/advanced_git_search/commands/preview.lua index 2e6fe0b..e080142 100644 --- a/lua/advanced_git_search/commands/preview.lua +++ b/lua/advanced_git_search/commands/preview.lua @@ -12,21 +12,23 @@ M.git_diff_file = function(first_commit, second_commit, bufnr) local filename_on_head = file.git_relative_path(bufnr) local curr_name = - git_utils.file_name_on_commit(first_commit, filename_on_head) - local prev_name = git_utils.file_name_on_commit(second_commit, filename_on_head) + local prev_name = + git_utils.file_name_on_commit(first_commit, filename_on_head) - if prev_name ~= nil then + if prev_name ~= nil and curr_name ~= nil then return cmd_utils.format_git_diff_command({ "git", "diff", + "--color=always", first_commit .. ":" .. prev_name, second_commit .. ":" .. curr_name, }) - else + elseif prev_name == nil and curr_name ~= nil then return cmd_utils.format_git_diff_command({ "git", "diff", + "--color=always", first_commit, second_commit, "--", @@ -41,6 +43,7 @@ M.git_diff_base_branch = function(relative_filename) return cmd_utils.format_git_diff_command({ "git", "diff", + "--color=always", "--diff-filter=ACMR", "--cached", "--merge-base", @@ -63,7 +66,7 @@ M.git_diff_content = function(first_commit, second_commit, prompt) second_commit, }) - if prompt and prompt ~= "" then + if prompt and prompt ~= "" and prompt ~= '""' then table.insert(command, "-G") table.insert(command, prompt) end @@ -86,6 +89,7 @@ M.git_diff_branch = function(branch, bufnr) return cmd_utils.format_git_diff_command({ "git", "diff", + "--color=always", branch .. ":" .. branch_filename, current_hash .. ":" .. file.git_relative_path(bufnr), }) @@ -93,6 +97,7 @@ M.git_diff_branch = function(branch, bufnr) return cmd_utils.format_git_diff_command({ "git", "diff", + "--color=always", branch, current_hash, "--", diff --git a/lua/advanced_git_search/commands/utils.lua b/lua/advanced_git_search/commands/utils.lua index c4b030c..9e04c48 100644 --- a/lua/advanced_git_search/commands/utils.lua +++ b/lua/advanced_git_search/commands/utils.lua @@ -57,6 +57,8 @@ M.split_query_from_author = function(query) author = split[2] end + prompt = prompt or "" + author = author or "" return prompt, author end diff --git a/lua/advanced_git_search/fzf/finders/init.lua b/lua/advanced_git_search/fzf/finders/init.lua index e67f376..ec6a759 100644 --- a/lua/advanced_git_search/fzf/finders/init.lua +++ b/lua/advanced_git_search/fzf/finders/init.lua @@ -1,19 +1,66 @@ -local preview_utils = require("advanced_git_search.fzf.previewers.utils") -local cmd_utils = require("advanced_git_search.commands.utils") -local finder_cmds = require("advanced_git_search.commands.find") +local fzf_preview_utils = require("advanced_git_search.fzf.previewers.utils") +local command_utils = require("advanced_git_search.commands.utils") +local finder_commands = require("advanced_git_search.commands.find") local utils = require("advanced_git_search.utils") local M = {} -M.git_log_content_finder = function(query) - preview_utils.set_last_query(query) +---@param query string +---@param bufnr number|nil +---@return string +M.git_log_content_finder = function(query, bufnr) + fzf_preview_utils.set_last_query(query) - local prompt, author = cmd_utils.split_query_from_author(query) + local prompt, author = command_utils.split_query_from_author(query) - return table.concat( - finder_cmds.git_log_content(utils.escape_term(prompt), author), + author = author or "" + local command = table.concat( + finder_commands.git_log_content( + string.format('"%s"', utils.escape_term(prompt)), + string.format('"%s"', author), + bufnr + ), " " ) + + return command +end + +M.git_log_location_finder = function(query, bufnr, s_start, s_end) + fzf_preview_utils.set_last_query(query) + + local prompt, author = command_utils.split_query_from_author(query) + + author = author or "" + local command = table.concat( + finder_commands.git_log_location( + string.format('"%s"', utils.escape_term(prompt)), + string.format('"%s"', author), + bufnr, + s_start, + s_end + ), + " " + ) + + return command +end + +M.git_log_file_finder = function(query, bufnr) + fzf_preview_utils.set_last_query(query) + + local prompt, author = command_utils.split_query_from_author(query) + + local command = table.concat( + finder_commands.git_log_file( + string.format('"%s"', utils.escape_term(prompt)), + string.format('"%s"', author), + bufnr + ), + " " + ) + + return command end return M diff --git a/lua/advanced_git_search/fzf/init.lua b/lua/advanced_git_search/fzf/init.lua index 7a6f3be..3c13f0b 100644 --- a/lua/advanced_git_search/fzf/init.lua +++ b/lua/advanced_git_search/fzf/init.lua @@ -1,6 +1,29 @@ local M = {} +local config = require("advanced_git_search.utils.config") + +M.setup = function(opts) + config.setup(opts) + + vim.api.nvim_create_user_command( + "AdvancedGitSearch", + "lua require('advanced_git_search.fzf').show_custom_functions()", + { range = true } + ) +end M.search_log_content = - require("advanced_git_search.fzf.pickers").search_log_content() + require("advanced_git_search.fzf.pickers").search_log_content + +M.search_log_content_file = + require("advanced_git_search.fzf.pickers").search_log_content_file + +M.diff_commit_line = require("advanced_git_search.fzf.pickers").diff_commit_line + +M.diff_commit_file = require("advanced_git_search.fzf.pickers").diff_commit_file + +M.diff_branch_file = require("advanced_git_search.fzf.pickers").diff_branch_file + +M.show_custom_functions = + require("advanced_git_search.fzf.pickers").show_custom_functions return M diff --git a/lua/advanced_git_search/fzf/mappings/init.lua b/lua/advanced_git_search/fzf/mappings/init.lua new file mode 100644 index 0000000..dd4d148 --- /dev/null +++ b/lua/advanced_git_search/fzf/mappings/init.lua @@ -0,0 +1,83 @@ +local M = {} +local utils = require("advanced_git_search.utils") + +local global_actions = require("advanced_git_search.actions") +local file_utils = require("advanced_git_search.utils.file") +local git_utils = require("advanced_git_search.utils.git") + +---FZF: Opens the selected commit in browser +---@return table +M.open_commit_in_brower = function() + return { + ["ctrl-o"] = function(selected, _) + local selection = selected[1] + local hash = utils.split_string(selection, " ")[1] + + global_actions.open_in_browser(hash) + end, + } +end + +---FZF: Open diff view of passed bufnr with selected commit +---@param bufnr number +---@return table +M.open_diff_buffer_with_selected_commit = function(bufnr) + return { + ["default"] = function(selected, _) + local selection = selected[1] + local commit_hash = utils.split_string(selection, " ")[1] + + global_actions.open_diff_view( + commit_hash, + file_utils.git_relative_path(bufnr) + ) + end, + } +end + +---FZF: Show entire commit in nvim +---@return table +M.show_entire_commit = function() + return { + ["ctrl-e"] = function(selected, _) + local selection = selected[1] + local commit_hash = utils.split_string(selection, " ")[1] + + global_actions.open_commit(commit_hash) + end, + } +end + +---FZF: Open diff view of passed buffer with selected branch +---@param bufnr number +---@return table +M.diff_buffer_with_branch = function(bufnr) + return { + ["default"] = function(selected, _) + local branch = selected[1] + + global_actions.open_diff_view( + branch, + git_utils.file_name_on_commit( + branch, + file_utils.git_relative_path(bufnr) + ) + ) + end, + } +end + +---FZF: Copy the selected commit hash to clipboard +---@return table +M.copy_commit_hash = function() + return { + ["ctrl-y"] = function(selected, _) + local selection = selected[1] + local commit_hash = utils.split_string(selection, " ")[1] + + global_actions.copy_to_clipboard(commit_hash) + end, + } +end + +return M diff --git a/lua/advanced_git_search/fzf/pickers/init.lua b/lua/advanced_git_search/fzf/pickers/init.lua index 1ca74c5..b5ef2e0 100644 --- a/lua/advanced_git_search/fzf/pickers/init.lua +++ b/lua/advanced_git_search/fzf/pickers/init.lua @@ -1,20 +1,214 @@ local M = {} -local ags_previewers = require("advanced_git_search.fzf.previewers") -local ags_finders = require("advanced_git_search.fzf.finders") +local fzf_previewers = require("advanced_git_search.fzf.previewers") +local fzf_finders = require("advanced_git_search.fzf.finders") +local fzf_mappings = require("advanced_git_search.fzf.mappings") +local fzf_picker_utils = require("advanced_git_search.fzf.pickers.utils") +local global_picker = require("advanced_git_search.global_picker") M.search_log_content = function() + local bufnr = vim.fn.bufnr() + local opts = { + prompt = "Log> ", + exec_empty_query = true, + func_async_callback = false, + fzf_opts = { + ["--preview"] = fzf_previewers.git_diff_content_previewer(), + }, + fn_transform = function(x) + return fzf_picker_utils.make_entry(x) + end, + actions = vim.tbl_extend( + "keep", + fzf_mappings.open_commit_in_brower(), + fzf_mappings.open_diff_buffer_with_selected_commit(bufnr), + fzf_mappings.show_entire_commit(), + fzf_mappings.copy_commit_hash() + ), + } + + require("fzf-lua").fzf_live(function(query) + return fzf_finders.git_log_content_finder(query, nil) + end, opts) +end + +M.search_log_content_file = function() + local bufnr = vim.fn.bufnr() + local opts = { prompt = "Log> ", exec_empty_query = false, func_async_callback = false, fzf_opts = { - ["--preview"] = ags_previewers.git_diff_content_previewer(), + ["--preview"] = fzf_previewers.git_diff_content_previewer(), + }, + fn_transform = function(x) + return fzf_picker_utils.make_entry(x) + end, + actions = vim.tbl_extend( + "keep", + fzf_mappings.open_commit_in_brower(), + fzf_mappings.open_diff_buffer_with_selected_commit(bufnr), + fzf_mappings.show_entire_commit(), + fzf_mappings.copy_commit_hash() + ), + } + + require("fzf-lua").fzf_live(function(query) + return fzf_finders.git_log_content_finder(query, bufnr) + end, opts) +end + +M.diff_commit_line = function() + local bufnr = vim.fn.bufnr() + local s_start = vim.fn.getpos("'<")[2] + local s_end = vim.fn.getpos("'>")[2] + + if s_start == 0 or s_end == 0 then + vim.notify( + "No visual selection", + vim.log.levels.WARN, + { title = "Advanced Git Search" } + ) + return + end + + local opts = { + prompt = "Commit message> ", + exec_empty_query = true, + func_async_callback = false, + fzf_opts = { + ["--preview"] = fzf_previewers.git_diff_file_previewer(bufnr), + }, + fn_transform = function(x) + return fzf_picker_utils.make_entry(x) + end, + actions = vim.tbl_extend( + "keep", + fzf_mappings.open_commit_in_brower(), + fzf_mappings.open_diff_buffer_with_selected_commit(bufnr), + fzf_mappings.show_entire_commit(), + fzf_mappings.copy_commit_hash() + ), + } + + require("fzf-lua").fzf_live(function(query) + return fzf_finders.git_log_location_finder(query, bufnr, s_start, s_end) + end, opts) +end + +M.diff_commit_file = function() + local bufnr = vim.fn.bufnr() + + local opts = { + prompt = "Commit message> ", + exec_empty_query = true, + func_async_callback = false, + fzf_opts = { + ["--preview"] = fzf_previewers.git_diff_file_previewer(bufnr), + }, + fn_transform = function(x) + return fzf_picker_utils.make_entry(x) + end, + actions = vim.tbl_extend( + "keep", + fzf_mappings.open_commit_in_brower(), + fzf_mappings.open_diff_buffer_with_selected_commit(bufnr), + fzf_mappings.show_entire_commit(), + fzf_mappings.copy_commit_hash() + ), + } + + require("fzf-lua").fzf_live(function(query) + return fzf_finders.git_log_file_finder(query, bufnr) + end, opts) +end + +M.diff_branch_file = function() + local bufnr = vim.fn.bufnr() + + local opts = { + prompt = "Branch> ", + func_async_callback = false, + fzf_opts = { + ["--preview"] = fzf_previewers.git_diff_branch_file_previewer( + bufnr + ), + }, + actions = vim.tbl_extend( + "keep", + fzf_mappings.open_commit_in_brower(), + fzf_mappings.open_diff_buffer_with_selected_commit(bufnr), + fzf_mappings.copy_commit_hash() + ), + } + + require("fzf-lua").fzf_exec( + table.concat( + require("advanced_git_search.commands.find").git_branches(), + " " + ), + opts + ) +end + +M.changed_on_branch = function() + local opts = { + prompt = "File> ", + func_async_callback = false, + fzf_opts = { + ["--preview"] = fzf_previewers.git_diff_base_branch(), + }, + } + + require("fzf-lua").fzf_exec( + table.concat( + require("advanced_git_search.commands.find").changed_on_branch(), + " " + ), + opts + ) +end + +M.checkout_reflog = function() + local opts = { + func_async_callback = false, + fn_transform = function(x) + return fzf_picker_utils.make_reflog_entry(x) + end, + actions = { + ["default"] = function(selected) + local selection = selected[1] + local commit = string.sub(selection, 1, 7) + + require("advanced_git_search.actions").checkout_commit(commit) + end, + }, + } + + require("fzf-lua").fzf_exec( + table.concat(require("advanced_git_search.commands.find").reflog(), " "), + opts + ) +end + +--- Opens a selector for all advanced git search functions +M.show_custom_functions = function() + local keys = global_picker.keys("telescope") + + local opts = { + prompt = "AdvancedGitSearch> ", + func_async_callback = false, + actions = { + ["default"] = function(selected) + local selection = selected[1] + + global_picker.execute_git_function(selection, "fzf_lua") + end, }, } - vim.print("Execute search log content") - require("fzf-lua").fzf_live(ags_finders.git_log_content_finder, opts) + require("fzf-lua").fzf_exec(keys, opts) end return M diff --git a/lua/advanced_git_search/fzf/pickers/utils.lua b/lua/advanced_git_search/fzf/pickers/utils.lua new file mode 100644 index 0000000..85d1cba --- /dev/null +++ b/lua/advanced_git_search/fzf/pickers/utils.lua @@ -0,0 +1,64 @@ +local color = require("fzf-lua").utils.ansi_codes +local utils = require("advanced_git_search.utils") + +local M = {} + +M.make_entry = function(entry) + if entry == "" or entry == nil then + return + end + -- dce3b0743 2022-09-09 author _ message + -- FIXME: will break if author contains _ + local cleaned = string.gsub(entry, "'", "") + local split = utils.split_string(cleaned, "_") + local attrs = utils.split_string(split[1]) + local hash = attrs[1] + -- local date = attrs[2] + local author = "" + for i = 3, #attrs do + author = author .. attrs[i] .. " " + end + -- join split from second element + local message = split[2] + if #split > 2 then + for i = 3, #split do + message = message .. "_" .. split[i] + end + end + + -- NOTE: make sure the first value is the commit hash + return color.magenta(hash) + .. color.cyan(" @" .. author) + .. color.yellow(message) +end + +M.make_reflog_entry = function(entry) + if entry == "" or entry == nil then + return + end + + local cleaned = string.gsub(entry, "'", "") + local split = utils.split_string(cleaned, " ") + local hash = split[1] + + local rest = split[2] + for i = 3, #split do + rest = rest .. " " .. split[i] + end + + local split_on_double = utils.split_string(rest, ":") + local description = "" + for i = 4, #split_on_double do + description = description .. split_on_double[i] + end + + local meta = "" + for i = 1, 3 do + meta = meta .. split_on_double[i] + end + + -- NOTE: make sure the first value is the commit hash + return color.magenta(hash) .. " " .. meta .. "" .. color.yellow(description) +end + +return M diff --git a/lua/advanced_git_search/fzf/previewers/init.lua b/lua/advanced_git_search/fzf/previewers/init.lua index 05b325b..6cc4445 100644 --- a/lua/advanced_git_search/fzf/previewers/init.lua +++ b/lua/advanced_git_search/fzf/previewers/init.lua @@ -1,6 +1,6 @@ -local cmd_utils = require("advanced_git_search.commands.utils") +local command_utils = require("advanced_git_search.commands.utils") local fzf_lua = require("fzf-lua") -local preview_utils = require("advanced_git_search.fzf.previewers.utils") +local fzf_preview_utils = require("advanced_git_search.fzf.previewers.utils") local utils = require("advanced_git_search.utils") local preview_commands = require("advanced_git_search.commands.preview") local git_utils = require("advanced_git_search.utils.git") @@ -13,35 +13,63 @@ M.git_diff_content_previewer = function() local hash = string.sub(selection, 1, 7) local prev_commit = git_utils.previous_commit_hash(hash) - -- local preview_command = - -- string.format("git --no-pager diff %s~ %s", hash, hash) - -- - local prompt, _ = - cmd_utils.split_query_from_author(preview_utils.get_last_query()) - - -- preview_command = preview_command .. string.format(" --color=always") - -- - -- -- command - -- if prompt and prompt ~= "" then - -- preview_command = preview_command - -- .. " -G '" - -- .. utils.escape_term(prompt) - -- .. "'" - -- end - -- + local prompt, _ = command_utils.split_query_from_author( + fzf_preview_utils.get_last_query() + ) + local preview_command = table.concat( - preview_commands.git_diff_content(prev_commit, hash, prompt), + preview_commands.git_diff_content( + prev_commit, + hash, + string.format('"%s"', utils.escape_term(prompt)) + ), " " ) - preview_command = preview_command - .. string.format( - " | GREP_COLOR='3;30;105' grep -A 999999 -B 999999 --color=always '%s'", - prompt - ) + if prompt and prompt ~= "" and prompt ~= '""' then + preview_command = preview_command + .. string.format( + " | GREP_COLOR='3;30;105' grep -A 999999 -B 999999 --color=always '%s'", + prompt + ) + end return preview_command end) end +M.git_diff_file_previewer = function(bufnr) + return fzf_lua.shell.preview_action_cmd(function(items) + local selection = items[1] + local commit_hash = string.sub(selection, 1, 7) + local prev_commit = git_utils.previous_commit_hash(commit_hash) + + return table.concat( + preview_commands.git_diff_file(prev_commit, commit_hash, bufnr), + " " + ) + end) +end + +M.git_diff_branch_file_previewer = function(bufnr) + return fzf_lua.shell.preview_action_cmd(function(items) + local branch = items[1] + + return table.concat( + preview_commands.git_diff_branch(branch, bufnr), + " " + ) + end) +end + +M.git_diff_base_branch = function() + return fzf_lua.shell.preview_action_cmd(function(items) + local filename = items[1] + + return table.concat( + preview_commands.git_diff_base_branch(filename), + " " + ) + end) +end return M diff --git a/lua/advanced_git_search/global_picker.lua b/lua/advanced_git_search/global_picker.lua new file mode 100644 index 0000000..696fd83 --- /dev/null +++ b/lua/advanced_git_search/global_picker.lua @@ -0,0 +1,121 @@ +local M = {} + +local config = require("advanced_git_search.utils.config") + +---@param finder_plugin "telescope"|"fzf_lua" +---@return table +local custom_git_functions = function(finder_plugin) + local pickers_table = {} + if finder_plugin == "telescope" then + pickers_table = require("advanced_git_search.telescope.pickers") + elseif finder_plugin == "fzf_lua" then + pickers_table = require("advanced_git_search.fzf.pickers") + end + + return { + { + value = "Search in repo log content", + func = pickers_table.search_log_content, + }, + { + value = "Search in file log content", + func = pickers_table.search_log_content_file, + }, + { + value = "Diff current file with commit", + func = pickers_table.diff_commit_file, + }, + { + value = "Diff current file with selected line history", + func = pickers_table.diff_commit_line, + }, + { + value = "Diff file with branch", + func = pickers_table.diff_branch_file, + }, + { + value = "Changed on current branch (experimental)", + func = pickers_table.changed_on_branch, + }, + { + value = "Checkout from reflog", + func = pickers_table.checkout_reflog, + }, + } +end + +---@param finder_plugin "telescope"|"fzf_lua" +---@return table +local builtin_git_functions = function(finder_plugin) + local builtin_functions = {} + if finder_plugin == "telescope" then + builtin_functions = require("telescope.builtin") + elseif finder_plugin == "fzf_lua" then + builtin_functions = require("fzf-lua") + end + + return { + { + value = "Git commits [builtin]", + func = builtin_functions.git_commits, + }, + { + value = "Git branches [builtin]", + func = builtin_functions.git_branches, + }, + { + value = "Git status [builtin]", + func = builtin_functions.git_status, + }, + { + value = "Git stash [builtin]", + func = builtin_functions.git_stash, + }, + } +end + +local function map_item(git_functions_table, f) + local t = {} + for k, v in pairs(git_functions_table) do + t[k] = f(v) + end + return t +end + +---@param finder_plugin "telescope"|"fzf_lua" +---@return table +local git_functions_table = function(finder_plugin) + local t = {} + for _, v in pairs(custom_git_functions(finder_plugin)) do + t[#t + 1] = v + end + + if config.show_builtin_git_pickers() then + for _, v in pairs(builtin_git_functions(finder_plugin)) do + t[#t + 1] = v + end + end + + return t +end + +---@param value any +---@param finder_plugin "telescope"|"fzf_lua" +M.execute_git_function = function(value, finder_plugin) + for _, v in pairs(git_functions_table(finder_plugin)) do + if v["value"] == value then + v["func"]() + return + end + end +end + +---@param finder_plugin "telescope"|"fzf_lua" +---@return table +M.keys = function(finder_plugin) + return map_item(git_functions_table(finder_plugin), function(v) + return v["value"] + end) +end + +return M diff --git a/lua/advanced_git_search/telescope/finders/init.lua b/lua/advanced_git_search/telescope/finders/init.lua index 8203e88..592b025 100644 --- a/lua/advanced_git_search/telescope/finders/init.lua +++ b/lua/advanced_git_search/telescope/finders/init.lua @@ -1,29 +1,31 @@ local finders = require("telescope.finders") -local finder_utils = require("advanced_git_search.telescope.finders.utils") -local cmd_utils = require("advanced_git_search.commands.utils") -local finder_cmds = require("advanced_git_search.commands.find") +local telescope_finder_utils = + require("advanced_git_search.telescope.finders.utils") +local command_utils = require("advanced_git_search.commands.utils") +local finder_commands = require("advanced_git_search.commands.find") +local utils = require("advanced_git_search.utils") local M = {} M.git_branches_finder = function() - return finders.new_oneshot_job(finder_cmds.git_branches()) + return finders.new_oneshot_job(finder_commands.git_branches()) end --- Returns all commits that changed the visual selection in the buffer M.git_log_location_finder = function(bufnr, start_line, end_line) return finders.new_job(function(query) - local prompt, author = cmd_utils.split_query_from_author(query) + local prompt, author = command_utils.split_query_from_author(query) - finder_utils.set_last_prompt(prompt) + telescope_finder_utils.set_last_prompt(prompt) - return finder_cmds.git_log_location( + return finder_commands.git_log_location( prompt, author, bufnr, start_line, end_line ) - end, finder_utils.git_log_entry_maker) + end, telescope_finder_utils.git_log_entry_maker) end --- Returns all commits that contains the prompt string in the commit content @@ -32,27 +34,29 @@ M.git_log_content_finder = function(opts) opts = opts or {} return finders.new_job(function(query) - local prompt, author = cmd_utils.split_query_from_author(query) + local prompt, author = command_utils.split_query_from_author(query) - finder_utils.set_last_prompt(prompt) - return finder_cmds.git_log_content(prompt, author, opts.bufnr) - end, finder_utils.git_log_entry_maker) + telescope_finder_utils.set_last_prompt(utils.escape_term(prompt)) + return finder_commands.git_log_content( + utils.escape_term(prompt), + author, + opts.bufnr + ) + end, telescope_finder_utils.git_log_entry_maker) end --- Returns all commits that changed the file of the passed buffer M.git_log_file_finder = function(bufnr) return finders.new_job(function(query) - local prompt, author = cmd_utils.split_query_from_author(query) + local prompt, author = command_utils.split_query_from_author(query) - finder_utils.set_last_prompt(prompt) - return finder_cmds.git_log_file(prompt, author, bufnr) - end, finder_utils.git_log_entry_maker) + telescope_finder_utils.set_last_prompt(prompt) + return finder_commands.git_log_file(prompt, author, bufnr) + end, telescope_finder_utils.git_log_entry_maker) end M.changed_files_on_current_branch_finder = function() - return finders.new_oneshot_job( - finder_cmds.git_changed_files_on_current_branch() - ) + return finders.new_oneshot_job(finder_commands.changed_on_branch()) end return M diff --git a/lua/advanced_git_search/telescope/mappings/init.lua b/lua/advanced_git_search/telescope/mappings/init.lua index f18095b..4ec6286 100644 --- a/lua/advanced_git_search/telescope/mappings/init.lua +++ b/lua/advanced_git_search/telescope/mappings/init.lua @@ -1,11 +1,10 @@ local actions = require("telescope.actions") local action_state = require("telescope.actions.state") -local ags_actions = require("advanced_git_search.actions") +local global_actions = require("advanced_git_search.actions") -local file = require("advanced_git_search.utils.file") +local file_utils = require("advanced_git_search.utils.file") local git_utils = require("advanced_git_search.utils.git") -local config = require("advanced_git_search.utils.config") -- Map a key to both insert and normal modes local function omnimap(map_func, key, handler) @@ -37,7 +36,7 @@ local diff_current_buffer_with_commit = function(prompt_bufnr) local selection = action_state.get_selected_entry() local commit_hash = selection.opts.commit_hash - ags_actions.open_diff_view(commit_hash) + global_actions.open_diff_view(commit_hash) end --- Open diff view of commmit (from entry) with @@ -47,12 +46,12 @@ end ------------------------------------------------------------------------------- local diff_current_buffer_with_branch = function(prompt_bufnr) - local filename = file.git_relative_path(vim.fn.bufnr()) + local filename = file_utils.git_relative_path(vim.fn.bufnr()) actions.close(prompt_bufnr) local selection = action_state.get_selected_entry() local branch = selection.value - ags_actions.open_diff_view( + global_actions.open_diff_view( branch, git_utils.file_name_on_commit(branch, filename) ) @@ -69,14 +68,7 @@ local open_entire_commit = function(prompt_bufnr) local selection = action_state.get_selected_entry() local commit_hash = selection.opts.commit_hash - local diff_plugin = config.diff_plugin() - if diff_plugin == "diffview" then - vim.api.nvim_command( - ":DiffviewOpen -uno " .. commit_hash .. "~.." .. commit_hash - ) - elseif diff_plugin == "fugitive" then - vim.api.nvim_command(":Gedit " .. commit_hash) - end + global_actions.open_commit(commit_hash) end --- open entire commit diff with @@ -88,14 +80,8 @@ end local copy_commit_hash = function(_) local selection = action_state.get_selected_entry() local commit_hash = selection.opts.commit_hash - vim.notify( - "Copied commit hash " .. commit_hash .. " to clipboard", - vim.log.levels.INFO, - { title = "Advanced Git Search" } - ) - vim.fn.setreg("+", commit_hash) - vim.fn.setreg("*", commit_hash) + global_actions.copy_to_clipboard(commit_hash) end --- copy commit hash to clipboard with @@ -115,7 +101,8 @@ local checkout = function(prompt_bufnr) splitted_reflog_entry[count] = i count = count + 1 end - vim.api.nvim_command(":!git checkout " .. splitted_reflog_entry[1]) + + global_actions.checkout_commit(splitted_reflog_entry[1]) end --- Checkout the selected reflog entry with diff --git a/lua/advanced_git_search/telescope/pickers/init.lua b/lua/advanced_git_search/telescope/pickers/init.lua index c9c7d0d..db17a95 100644 --- a/lua/advanced_git_search/telescope/pickers/init.lua +++ b/lua/advanced_git_search/telescope/pickers/init.lua @@ -1,15 +1,16 @@ local actions = require("telescope.actions") local action_state = require("telescope.actions.state") local git_utils = require("advanced_git_search.utils.git") -local config = require("advanced_git_search.utils.config") +local global_picker = require("advanced_git_search.global_picker") local pickers = require("telescope.pickers") local sorters = require("telescope.sorters") local finders = require("telescope.finders") -local ags_finders = require("advanced_git_search.telescope.finders") -local ags_previewers = require("advanced_git_search.telescope.previewers") -local ags_mappings = require("advanced_git_search.telescope.mappings") +local telescope_ags_finders = require("advanced_git_search.telescope.finders") +local telescope_ags_previewers = + require("advanced_git_search.telescope.previewers") +local telescope_ags_mappings = require("advanced_git_search.telescope.mappings") local M = {} @@ -23,8 +24,8 @@ M.changed_on_branch = function() .. " -> " .. git_utils.current_branch(), sorter = sorters.get_fuzzy_file(), - finder = ags_finders.changed_files_on_current_branch_finder(), - previewer = ags_previewers.changed_files_on_current_branch_previewer(), + finder = telescope_ags_finders.changed_files_on_current_branch_finder(), + previewer = telescope_ags_previewers.changed_files_on_current_branch_previewer(), }) :find() end @@ -39,11 +40,15 @@ M.diff_branch_file = function() .new({ results_title = "Local branches :: *" .. current_branch, prompt_title = "Branch name", - finder = ags_finders.git_branches_finder(), + finder = telescope_ags_finders.git_branches_finder(), sorter = sorters.get_fuzzy_file(), - previewer = ags_previewers.git_diff_branch_file_previewer(bufnr), + previewer = telescope_ags_previewers.git_diff_branch_file_previewer( + bufnr + ), attach_mappings = function(_, map) - ags_mappings.open_diff_view_current_file_selected_branch(map) + telescope_ags_mappings.open_diff_view_current_file_selected_branch( + map + ) return true end, }) @@ -57,20 +62,37 @@ M.diff_commit_line = function() local s_start = vim.fn.getpos("'<")[2] local s_end = vim.fn.getpos("'>")[2] + if s_start == 0 or s_end == 0 then + vim.notify( + "No visual selection", + vim.log.levels.WARN, + { title = "Advanced Git Search" } + ) + return + end + -- git log -L741,751:'app/models/patients/patient.rb'\ -- --format='%C(auto)%h \t %as \t %C(green)%an _ %Creset %s' pickers .new({ results_title = "Commits that affected the selected lines", prompt_title = "Commit message", - finder = ags_finders.git_log_location_finder(bufnr, s_start, s_end), - previewer = ags_previewers.git_diff_commit_file_previewer(bufnr), + finder = telescope_ags_finders.git_log_location_finder( + bufnr, + s_start, + s_end + ), + previewer = telescope_ags_previewers.git_diff_commit_file_previewer( + bufnr + ), sorter = sorters.highlighter_only(), attach_mappings = function(_, map) - ags_mappings.open_diff_view_current_file_selected_commit(map) - ags_mappings.open_selected_commit_in_browser(map) - ags_mappings.copy_commit_hash_to_clipboard(map) - ags_mappings.show_entire_commit(map) + telescope_ags_mappings.open_diff_view_current_file_selected_commit( + map + ) + telescope_ags_mappings.open_selected_commit_in_browser(map) + telescope_ags_mappings.copy_commit_hash_to_clipboard(map) + telescope_ags_mappings.show_entire_commit(map) return true end, }) @@ -87,13 +109,15 @@ M.search_log_content = function() .new({ results_title = "Commits", prompt_title = "Git log content (added, removed or updated text)", - finder = ags_finders.git_log_content_finder({}), - previewer = ags_previewers.git_diff_content_previewer(), + finder = telescope_ags_finders.git_log_content_finder({}), + previewer = telescope_ags_previewers.git_diff_content_previewer(), attach_mappings = function(_, map) - ags_mappings.open_diff_view_current_file_selected_commit(map) - ags_mappings.open_selected_commit_in_browser(map) - ags_mappings.copy_commit_hash_to_clipboard(map) - ags_mappings.show_entire_commit(map) + telescope_ags_mappings.open_diff_view_current_file_selected_commit( + map + ) + telescope_ags_mappings.open_selected_commit_in_browser(map) + telescope_ags_mappings.copy_commit_hash_to_clipboard(map) + telescope_ags_mappings.show_entire_commit(map) return true end, }) @@ -111,16 +135,18 @@ M.search_log_content_file = function() .new({ results_title = "Commits", prompt_title = "Git log content (added, removed or updated text in this file)", - finder = ags_finders.git_log_content_finder({ + finder = telescope_ags_finders.git_log_content_finder({ bufnr = vim.fn.bufnr(), }), - previewer = ags_previewers.git_diff_content_previewer(), + previewer = telescope_ags_previewers.git_diff_content_previewer(), -- sorter = sorters.highlighter_only(), attach_mappings = function(_, map) - ags_mappings.open_diff_view_current_file_selected_commit(map) - ags_mappings.open_selected_commit_in_browser(map) - ags_mappings.copy_commit_hash_to_clipboard(map) - ags_mappings.show_entire_commit(map) + telescope_ags_mappings.open_diff_view_current_file_selected_commit( + map + ) + telescope_ags_mappings.open_selected_commit_in_browser(map) + telescope_ags_mappings.copy_commit_hash_to_clipboard(map) + telescope_ags_mappings.show_entire_commit(map) return true end, @@ -135,14 +161,18 @@ M.diff_commit_file = function() .new({ results_title = "Commits that affected this file (renamed files included)", prompt_title = "Commit message", - finder = ags_finders.git_log_file_finder(bufnr), - previewer = ags_previewers.git_diff_commit_file_previewer(bufnr), + finder = telescope_ags_finders.git_log_file_finder(bufnr), + previewer = telescope_ags_previewers.git_diff_commit_file_previewer( + bufnr + ), sorter = sorters.highlighter_only(), attach_mappings = function(_, map) - ags_mappings.open_diff_view_current_file_selected_commit(map) - ags_mappings.show_entire_commit(map) - ags_mappings.open_selected_commit_in_browser(map) - ags_mappings.copy_commit_hash_to_clipboard(map) + telescope_ags_mappings.open_diff_view_current_file_selected_commit( + map + ) + telescope_ags_mappings.show_entire_commit(map) + telescope_ags_mappings.open_selected_commit_in_browser(map) + telescope_ags_mappings.copy_commit_hash_to_clipboard(map) return true end, @@ -155,103 +185,21 @@ M.checkout_reflog = function() pickers .new({ results_title = "Git Reflog, to checkout", - finder = finders.new_oneshot_job({ "git", "reflog", "--date=iso" }), + finder = finders.new_oneshot_job( + require("advanced_git_search.commands.find").reflog() + ), sorter = sorters.get_fuzzy_file(), attach_mappings = function(_, map) - ags_mappings.checkout_reflog_entry(map) + telescope_ags_mappings.checkout_reflog_entry(map) return true end, }) :find() end -local custom_git_functions = { - { - value = "Search in repo log content", - func = M.search_log_content, - }, - { - value = "Search in file log content", - func = M.search_log_content_file, - }, - { - value = "Diff current file with commit", - func = M.diff_commit_file, - }, - { - value = "Diff current file with selected line history", - func = M.diff_commit_line, - }, - { - value = "Diff file with branch", - func = M.diff_branch_file, - }, - { - value = "Changed on current branch (experimental)", - func = M.changed_on_branch, - }, - { - value = "Checkout from reflog", - func = M.checkout_reflog, - }, -} - -local builtin_git_functions = { - { - value = "Git commits [telescope.builtin]", - func = require("telescope.builtin").git_commits, - }, - { - value = "Git branches [telescope.builtin]", - func = require("telescope.builtin").git_branches, - }, - { - value = "Git status [telescope.builtin]", - func = require("telescope.builtin").git_status, - }, - { - value = "Git stash [telescope.builtin]", - func = require("telescope.builtin").git_stash, - }, -} - -local function map_item(git_functions_table, f) - local t = {} - for k, v in pairs(git_functions_table) do - t[k] = f(v) - end - return t -end - -local git_functions_table = function() - local t = {} - for _, v in pairs(custom_git_functions) do - t[#t + 1] = v - end - - if config.show_builtin_git_pickers() then - for _, v in pairs(builtin_git_functions) do - t[#t + 1] = v - end - end - - return t -end - -local function execute_git_function(value) - for _, v in pairs(git_functions_table()) do - if v["value"] == value then - v["func"]() - return - end - end -end - ---- Opens all a selector for all advanced git search functions +--- Opens a selector for all advanced git search functions M.show_custom_functions = function() - local keys = map_item(git_functions_table(), function(item) - return item["value"] - end) + local keys = global_picker.keys("telescope") pickers .new({ @@ -259,15 +207,23 @@ M.show_custom_functions = function() finder = finders.new_table(keys), sorter = sorters.get_fuzzy_file(), attach_mappings = function(_, map) - ags_mappings.omnimap(map, "", function(prompt_bufnr) - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - execute_git_function(selection.value) - end) + telescope_ags_mappings.omnimap( + map, + "", + function(prompt_bufnr) + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + global_picker.execute_git_function( + selection.value, + "telescope" + ) + end + ) return true end, }) :find() end + return M diff --git a/lua/advanced_git_search/telescope/previewers/init.lua b/lua/advanced_git_search/telescope/previewers/init.lua index 357e01c..4c6a51d 100644 --- a/lua/advanced_git_search/telescope/previewers/init.lua +++ b/lua/advanced_git_search/telescope/previewers/init.lua @@ -1,18 +1,23 @@ local previewers = require("telescope.previewers") -local file = require("advanced_git_search.utils.file") +local file_utils = require("advanced_git_search.utils.file") local git_utils = require("advanced_git_search.utils.git") -local preview_cmds = require("advanced_git_search.commands.preview") +local preview_commands = require("advanced_git_search.commands.preview") local M = {} --- Shows a diff of the commit in the finder entry, filtered on the file of the current buffer M.git_diff_commit_file_previewer = function(bufnr) return previewers.new_termopen_previewer({ - title = "Changes on selected commit for: " .. file.file_name(bufnr), + title = "Changes on selected commit for: " + .. file_utils.file_name(bufnr), get_command = function(entry) local commit_hash = entry.opts.commit_hash local prev_commit = git_utils.previous_commit_hash(commit_hash) - return preview_cmds.git_diff_file(prev_commit, commit_hash, bufnr) + return preview_commands.git_diff_file( + prev_commit, + commit_hash, + bufnr + ) end, }) end @@ -25,7 +30,7 @@ M.git_diff_content_previewer = function() local commit_hash = entry.opts.commit_hash local prompt = entry.opts.prompt local prev_commit = git_utils.previous_commit_hash(commit_hash) - return preview_cmds.git_diff_content( + return preview_commands.git_diff_content( prev_commit, commit_hash, prompt @@ -39,19 +44,19 @@ M.changed_files_on_current_branch_previewer = function() return previewers.new_termopen_previewer({ title = "Diff of selected file and fork point", get_command = function(entry) - return preview_cmds.git_diff_base_branch(entry.value) + return preview_commands.git_diff_base_branch(entry.value) end, }) end --- Shows a diff of the branch in the finder entry relative to the passed filename M.git_diff_branch_file_previewer = function(bufnr) - local filename = file.file_name(bufnr) + local filename = file_utils.file_name(bufnr) return previewers.new_termopen_previewer({ title = "Diff of current buffer and selected branch for: " .. filename, get_command = function(entry) local branch = entry.value - return preview_cmds.git_diff_branch(branch, bufnr) + return preview_commands.git_diff_branch(branch, bufnr) end, }) end diff --git a/lua/advanced_git_search/utils/git.lua b/lua/advanced_git_search/utils/git.lua index aa3982f..ad306e3 100644 --- a/lua/advanced_git_search/utils/git.lua +++ b/lua/advanced_git_search/utils/git.lua @@ -1,6 +1,5 @@ local utils = require("advanced_git_search.utils") local file = require("advanced_git_search.utils.file") -local config = require("advanced_git_search.utils.config") local command_util = require("advanced_git_search.utils.command") local M = {} @@ -102,7 +101,11 @@ local file_name_on_commit = function(commit_hash, git_relative_file_path) local hash = all_hashes[i] -- search the hash in touched_hashes for _, touched_hash in ipairs(touched_hashes) do - if string.sub(touched_hash, 1, 7) == string.sub(hash, 1, 7) then + if + touched_hash ~= nil + and hash ~= nil + and string.sub(touched_hash, 1, 7) == string.sub(hash, 1, 7) + then last_touched_hash = touched_hash break end diff --git a/lua/advanced_git_search/utils/init.lua b/lua/advanced_git_search/utils/init.lua index da3dd90..c2bb999 100644 --- a/lua/advanced_git_search/utils/init.lua +++ b/lua/advanced_git_search/utils/init.lua @@ -28,6 +28,7 @@ M.split_string = function(inputstr, sep) end M.escape_chars = function(x) + x = x or "" return ( x:gsub("%%", "%%%%") :gsub("^%^", "%%^") @@ -45,6 +46,7 @@ M.escape_chars = function(x) end M.escape_term = function(x) + x = x or "" return ( x:gsub("%%", "\\%%") :gsub("^%^", "\\%^") From 7fa3e982d6dd70ca50baca50da289d6351a41669 Mon Sep 17 00:00:00 2001 From: Aaron Hallaert Date: Wed, 10 May 2023 10:40:18 +0200 Subject: [PATCH 3/3] Align telescope highlights with fzf Signed-off-by: Aaron Hallaert --- .../telescope/finders/utils.lua | 28 +++++++++++++++++-- .../telescope/pickers/init.lua | 1 - 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lua/advanced_git_search/telescope/finders/utils.lua b/lua/advanced_git_search/telescope/finders/utils.lua index 56fc722..816e305 100644 --- a/lua/advanced_git_search/telescope/finders/utils.lua +++ b/lua/advanced_git_search/telescope/finders/utils.lua @@ -1,4 +1,5 @@ local utils = require("advanced_git_search.utils") +local entry_display = require("telescope.pickers.entry_display") local M = {} local last_prompt = nil @@ -15,18 +16,39 @@ M.git_log_entry_maker = function(entry) local hash = attrs[1] local date = attrs[2] local author = attrs[3] + for i = 4, #attrs do + author = author .. " " .. attrs[i] + end + -- join split from second element local message = split[2] if #split > 2 then for i = 3, #split do - message = message .. "_" .. split[i] + message = message .. " " .. split[i] end end + local displayer = entry_display.create({ + separator = " ", + items = { + { width = 7 }, + { width = 7 }, + { remaining = true }, + }, + }) + + local make_display = function(display_entry) + return displayer({ + { display_entry.opts.commit_hash, "TelescopeResultsIdentifier" }, + { display_entry.opts.author, "TelescopeResultsVariable" }, + { display_entry.opts.message, "TelescopeResultsConstant" }, + }) + end + return { value = entry, - display = date .. " by " .. author .. " --" .. message, - -- display = hash .. " @ " .. date .. " by " .. author .. " --" .. message, + -- display = date .. " by " .. author .. " --" .. message, + display = make_display, ordinal = author .. " " .. message, preview_title = hash .. " -- " .. message, opts = { diff --git a/lua/advanced_git_search/telescope/pickers/init.lua b/lua/advanced_git_search/telescope/pickers/init.lua index db17a95..e7fd64a 100644 --- a/lua/advanced_git_search/telescope/pickers/init.lua +++ b/lua/advanced_git_search/telescope/pickers/init.lua @@ -139,7 +139,6 @@ M.search_log_content_file = function() bufnr = vim.fn.bufnr(), }), previewer = telescope_ags_previewers.git_diff_content_previewer(), - -- sorter = sorters.highlighter_only(), attach_mappings = function(_, map) telescope_ags_mappings.open_diff_view_current_file_selected_commit( map