From 8553dddda4c3a88ff4b8e5ee22185fded256913c Mon Sep 17 00:00:00 2001 From: moyiz <8603313+moyiz@users.noreply.github.com> Date: Fri, 21 Jun 2024 22:31:02 +0300 Subject: [PATCH] feat(telescope): add telescope extension --- README.md | 42 +++++-- lua/git-dev/history.lua | 2 +- lua/git-dev/init.lua | 8 +- lua/telescope/_extensions/git_dev/init.lua | 130 +++++++++++++++++++++ 4 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 lua/telescope/_extensions/git_dev/init.lua diff --git a/README.md b/README.md index d0c7f91..503c369 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ shallow clones automatically. It aims to provide a similar experience to - [Parameters](#parameters) - [:goggles: Toggle UI](#goggles-toggle-ui) - [Parameters](#parameters) + - [:telescope: Telescope](#telescope-telescope) + - [:bone: Recent Repositories](#bone-recent-repositories) - [:gear: Options](#gear-options) - [:spider_web: URL Parsing](#spider_web-url-parsing) - [Supported URLs](#supported-urls) @@ -57,7 +59,6 @@ shallow clones automatically. It aims to provide a similar experience to - [:fox_face: Web browser](#fox_face-web-browser) - [:pencil: Customizing Default URL](#pencil-customizing-default-url) - [:house_with_garden: Private Repositories - Parse HTTP as SSH](#house_with_garden-private-repositories---parse-http-as-ssh) - - [:telescope: Telescope](#telescope-telescope) - [:crystal_ball: Future Plans / Thoughts](#crystal_ball-future-plans--thoughts) - [:scroll: License](#scroll-license) @@ -68,6 +69,7 @@ shallow clones automatically. It aims to provide a similar experience to - Supports most URLs from GitHub, GitLab, Gitea and Codeberg. - Seamless integration with your workflow (e.g. LSP and tree-sitter). - Ephemeral repositories - cleanup when Neovim exits. +- Telescope extension to revisit previously opened repositories. @@ -89,7 +91,7 @@ Lazier (documentation will not be available until first use): { "moyiz/git-dev.nvim", lazy = true, - cmd = { "GitDevOpen", "GitDevCleanAll" }, + cmd = { "GitDevOpen", "GitDevToggleUI", "GitDevRecents", "GitDevCleanAll" }, opts = {}, } ``` @@ -107,7 +109,8 @@ Command: `GitDevOpen` Open the repository in Neovim. #### Parameters -- `repo` - `string` - A partial or full Git URI. +- `repo` - `string` - A partial or full Git URI. Some non-git URIs are also +supported, see [Supported URLS](#supported-urls) for examples. - `ref` - `table` - Target reference to checkout (default: `nil`). Empty `ref` will checkout the default branch. Examples: `{ branch = "..." }|{ tag = "..." }|{ commit = "..." }`. @@ -168,6 +171,20 @@ override default window configuration. - `win_config` - `vim.api.keyset.win_config` - Override window configuration for this call. + +### :telescope: Telescope + +#### :bone: Recent Repositories +Command: `GitDevRecents` + +Revisit previously opened repositories via a telescope extension. + +Opened repositories are tracked in a simple single file KV store. Its only +purpose (currently) is to be queried by the telescope extension for a +convenient way to re-open previously opened repositories. +See `history` in [Options](#gear-options) below. + + ## :gear: Options ```lua M.config = { @@ -217,13 +234,13 @@ M.config = { -- Triggered when a branch, tag or commit is given. checkout_args = "-f --recurse-submodules", }, - -- UI configuration + -- UI configuration. ui = { -- Auto-close window after repository was opened. auto_close = true, -- Delay window closing. close_after_ms = 3000, - -- Window mode. A workaround to remove `relative`. + -- Window mode. -- Options: floating|split mode = "floating", -- Window configuration for floating mode. @@ -240,6 +257,7 @@ M.config = { height = 9, row = 1, col = vim.o.columns, + noautocmd = true, }, -- Window configuration for split mode. -- See `:h nvim_open_win`. @@ -247,9 +265,17 @@ M.config = { split_win_config = { split = "right", width = 79, + noautocmd = true, }, }, - -- Print command outputs. + -- History configuration. + history = { + -- Maximum number of records to keep in history. + n = 32, + -- Store file path. + path = vim.fn.stdpath "data" .. "/git-dev/history.json", + }, + -- More verbosity. verbose = false, } ``` @@ -489,14 +515,10 @@ Then, the parser trims the "domain" and proceeds as usual. Output: } ``` -### :telescope: Telescope -TBD ## :crystal_ball: Future Plans / Thoughts -- Telescope extension to view, open and manage cloned repositories (will -require `ephemeral = false`). - Open repository in visual selection / current "word". ## :scroll: License diff --git a/lua/git-dev/history.lua b/lua/git-dev/history.lua index f807a86..0bb0f33 100644 --- a/lua/git-dev/history.lua +++ b/lua/git-dev/history.lua @@ -1,6 +1,6 @@ local Store = require "git-dev.store" ----@class History +---@class GitDevHistory ---@field path string History file path. ---@field n? number Maximum number of records to keep in history. local History = {} diff --git a/lua/git-dev/init.lua b/lua/git-dev/init.lua index 8fa98a2..32546c4 100644 --- a/lua/git-dev/init.lua +++ b/lua/git-dev/init.lua @@ -333,7 +333,7 @@ M.setup = function(opts) } -- Initialize store - ---@type History + ---@type GitDevHistory M.history = require("git-dev.history"):init(M.config.history) -- Create commands @@ -363,6 +363,12 @@ M.setup = function(opts) end, { desc = "Toggle the window showing git-dev output.", }) + + vim.api.nvim_create_user_command( + "GitDevRecents", + "Telescope git_dev recents", + { desc = "Revisit previously opened repositories." } + ) end return M diff --git a/lua/telescope/_extensions/git_dev/init.lua b/lua/telescope/_extensions/git_dev/init.lua new file mode 100644 index 0000000..0be56c0 --- /dev/null +++ b/lua/telescope/_extensions/git_dev/init.lua @@ -0,0 +1,130 @@ +local pickers = require "telescope.pickers" +local finders = require "telescope.finders" +local conf = require("telescope.config").values +local actions = require "telescope.actions" +local action_state = require "telescope.actions.state" +local entry_display = require "telescope.pickers.entry_display" +local utils = require "telescope.utils" +local telescope = require "telescope" +local previewers = require "telescope.previewers" + +local recents = function(opts) + local repo_url_width = 32 + local ref_width = 9 + + local display_maker = entry_display.create { + separator = " │ ", + separator_hl = "TelescopePreviewHyphen", + items = { + { width = repo_url_width }, + { width = ref_width }, + { remaining = true }, + }, + } + + local function make_ordinal(entry) + local ord = entry.args.repo + for _, v in pairs(entry.parsed) do + ord = ord .. ("|" .. v) + end + return ord + end + + local function truncate_left(s, w, lean_right) + local s_len = vim.fn.strdisplaywidth(s) + if s_len <= w then + local m = (w - s_len) / 2 + local r = lean_right and (w - s_len) % 2 or 0 + return string.rep(" ", m + r) .. s + end + local dots = "…" + local dots_w = vim.fn.strdisplaywidth(dots) + return dots .. s:sub(s_len - w + dots_w + 1) + end + + local entry_maker = function(entry) + return { + value = entry, + display = function(ent) + return display_maker { + { + truncate_left(ent.value.parsed.repo_url, repo_url_width, true), + "TelescopePreviewExecute", + }, + { + truncate_left( + ent.value.args.ref.commit + or ent.value.args.ref.tag + or ent.value.args.ref.branch + or ent.value.parsed.commit + or ent.value.parsed.branch + or "", + ref_width + ), + "TelescopeResultsIdentifier", + }, + { + ent.value.parsed.selected_path + and utils.transform_path({ + path_display = { + -- shorten = { len = 2, exclude = { 1, -1 } }, + }, + }, ent.value.parsed.selected_path) + or "", + "TelescopeResultsFunction", + }, + } + end, + ordinal = make_ordinal(entry), -- used for filtering + } + end + + local function make_preview(entry) + return vim.inspect(entry.value) + end + + pickers + .new(opts or {}, { + prompt_title = "Recently Opened", + finder = finders.new_table { + results = require("git-dev").history:get(), + entry_maker = entry_maker, + }, + sorter = conf.generic_sorter(opts), + previewer = previewers.new_buffer_previewer { + define_preview = function(self, entry) + vim.api.nvim_set_option_value("ft", "hcl", { buf = self.state.bufnr }) + vim.api.nvim_set_option_value( + "wrap", + true, + { win = self.state.winid } + ) + vim.api.nvim_buf_set_lines( + self.state.bufnr, + 0, + -1, + false, + vim.split(make_preview(entry), "\n") + ) + end, + }, + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + if not selection then + return + end + require("git-dev").open(selection.value.args.repo) + end) + return true + end, + }) + :find() +end + +return telescope.register_extension { + exports = { + recents = recents, + }, +}