Merge pull request #56 from thefux/master

Telescope Plugin
This commit is contained in:
Dheepak Krishnamurthy
2022-03-06 13:44:52 -07:00
committed by GitHub
5 changed files with 336 additions and 129 deletions

View File

@@ -94,3 +94,50 @@ If you have `neovim-remote` and don't want `lazygit.nvim` to use it, you can dis
```vim
let g:lazygit_use_neovim_remote = 0
```
### Telescope Plugin
The Telescope plugin is used to track all git repository visited in one nvim session.
![lazygittelplugin](https://user-images.githubusercontent.com/10464534/156933468-c89abee4-6afb-457c-8b02-55b67913aef2.png)
(background image is not included :smirk:)
**Why a telescope Plugin** ?
Assuming you have one or more submodule(s) in your project and you want to commit changes in both the submodule(s)
and the main repo.
Though switching between submodules and main repo is not straight forward.
A solution at first could be:
1. open a file inside the submodule
2. open lazygit
3. do commit
4. then open a file in the main repo
5. open lazygit
6. do commit
That is really annoying.
Instead, you can open it with telescope.
**How to use**
To load the telescope extension you have to add this line to your configuration:
```lua
require('telescope').load_extension('lazygit')
```
By default the paths of each repo is stored only when lazygit is triggered.
Though, this may not be convenient, so it possible to do something like this:
```vim
autocmd BufEnter * :lua require('lazygit.utils').project_root_dir()
```
That makes sure that any opened buffer which is contained in a git repo will be tracked.
Once you have loaded the extension, you can invoke the plugin using:
```lua
lua require("telescope").extensions.lazygit_telescope.lazygit()
```

View File

@@ -1,62 +1,25 @@
vim = vim
local api = vim.api
local fn = vim.fn
local open_floating_window = require"lazygit.window".open_floating_window
local project_root_dir = require"lazygit.utils".project_root_dir
local is_lazygit_available = require"lazygit.utils".is_lazygit_available
local is_symlink = require"lazygit.utils".is_symlink
local fn = vim.fn
LAZYGIT_BUFFER = nil
LAZYGIT_LOADED = false
vim.g.lazygit_opened = 0
--- Strip leading and lagging whitespace
local function trim(str)
return str:gsub('^%s+', ''):gsub('%s+$', '')
end
--- Check if lazygit is available
local function is_lazygit_available()
return fn.executable('lazygit') == 1
end
local function is_symlink()
local resolved = fn.resolve(fn.expand('%:p'))
return resolved ~= fn.expand('%:p')
end
--- Get project_root_dir for git repository
local function project_root_dir()
-- always use bash on Unix based systems.
local oldshell = vim.o.shell
if vim.fn.has('win32') == 0 then
vim.o.shell = 'bash'
end
-- try symlinked file location instead
local gitdir = fn.system(
'cd "' .. fn.fnamemodify(fn.resolve(fn.expand('%:p')), ':h') .. '" && git rev-parse --show-toplevel')
local isgitdir = fn.matchstr(gitdir, '^fatal:.*') == ''
if isgitdir then
vim.o.shell = oldshell
return trim(gitdir)
end
-- revert to old shell
vim.o.shell = oldshell
-- just return current working directory
return fn.getcwd(0, 0)
end
--- on_exit callback function to delete the open buffer when lazygit exits in a neovim terminal
local function on_exit(job_id, code, event)
if code == 0 then
-- Close the window where the LAZYGIT_BUFFER is
vim.cmd('silent! :q')
LAZYGIT_BUFFER = nil
LAZYGIT_LOADED = false
vim.g.lazygit_opened = 0
vim.cmd('silent! :checktime')
if code ~= 0 then
return
end
vim.cmd('silent! :q')
LAZYGIT_BUFFER = nil
LAZYGIT_LOADED = false
vim.g.lazygit_opened = 0
vim.cmd('silent! :checktime')
end
--- Call lazygit
@@ -69,84 +32,6 @@ local function exec_lazygit_command(cmd)
vim.cmd 'startinsert'
end
--- open floating window with nice borders
local function open_floating_window()
local floating_window_scaling_factor = vim.g.lazygit_floating_window_scaling_factor
-- Why is this required?
-- vim.g.lazygit_floating_window_scaling_factor returns different types if the value is an integer or float
if type(floating_window_scaling_factor) == 'table' then
floating_window_scaling_factor = floating_window_scaling_factor[false]
end
local status, plenary = pcall(require, 'plenary.window.float')
if status and vim.g.lazygit_floating_window_use_plenary and vim.g.lazygit_floating_window_use_plenary ~= 0 then
plenary.percentage_range_window(floating_window_scaling_factor, floating_window_scaling_factor)
return
end
local height = math.ceil(vim.o.lines * floating_window_scaling_factor) - 1
local width = math.ceil(vim.o.columns * floating_window_scaling_factor)
local row = math.ceil(vim.o.lines - height) / 2
local col = math.ceil(vim.o.columns - width) / 2
local border_opts = {
style = 'minimal',
relative = 'editor',
row = row - 1,
col = col - 1,
width = width + 2,
height = height + 2,
}
local opts = { style = 'minimal', relative = 'editor', row = row, col = col, width = width, height = height }
local topleft, topright, botleft, botright
local corner_chars = vim.g.lazygit_floating_window_corner_chars
if type(corner_chars) == 'table' and #corner_chars == 4 then
topleft, topright, botleft, botright = unpack(corner_chars)
else
topleft, topright, botleft, botright = '', '', '', ''
end
local border_lines = { topleft .. string.rep('', width) .. topright }
local middle_line = '' .. string.rep(' ', width) .. ''
for i = 1, height do
table.insert(border_lines, middle_line)
end
table.insert(border_lines, botleft .. string.rep('', width) .. botright)
-- create a unlisted scratch buffer for the border
local border_buffer = api.nvim_create_buf(false, true)
-- set border_lines in the border buffer from start 0 to end -1 and strict_indexing false
api.nvim_buf_set_lines(border_buffer, 0, -1, true, border_lines)
-- create border window
local border_window = api.nvim_open_win(border_buffer, true, border_opts)
vim.cmd('set winhl=Normal:Floating')
-- create a unlisted scratch buffer
if LAZYGIT_BUFFER == nil or vim.fn.bufwinnr(LAZYGIT_BUFFER) == -1 then
LAZYGIT_BUFFER = api.nvim_create_buf(false, true)
else
LAZYGIT_LOADED = true
end
-- create file window, enter the window, and use the options defined in opts
local _ = api.nvim_open_win(LAZYGIT_BUFFER, true, opts)
vim.bo[LAZYGIT_BUFFER].filetype = 'lazygit'
vim.cmd('setlocal bufhidden=hide')
vim.cmd('setlocal nocursorcolumn')
vim.cmd('set winblend=' .. vim.g.lazygit_floating_window_winblend)
-- use autocommand to ensure that the border_buffer closes at the same time as the main buffer
local cmd = [[autocmd WinLeave <buffer> silent! execute 'hide']]
vim.cmd(cmd)
cmd = [[autocmd WinLeave <buffer> silent! execute 'silent bdelete! %s']]
vim.cmd(cmd:format(border_buffer))
end
--- :LazyGit entry point
local function lazygit(path)
@@ -158,6 +43,7 @@ local function lazygit(path)
open_floating_window()
local cmd = 'lazygit'
-- set path to the root path
_ = project_root_dir()
@@ -166,7 +52,9 @@ local function lazygit(path)
path = project_root_dir()
end
else
cmd = cmd .. ' -p ' .. path
if fn.isdirectory(path) then
cmd = cmd .. ' -p ' .. path
end
end
exec_lazygit_command(cmd)

101
lua/lazygit/utils.lua Normal file
View File

@@ -0,0 +1,101 @@
local fn = vim.fn
-- store all git repositories visited in this session
local lazygit_visited_git_repos = {}
-- TODO:check if the repo isa git repo
local function append_git_repo_path(repo_path)
if repo_path == nil or not fn.isdirectory(repo_path) then
return
end
for _, path in ipairs(lazygit_visited_git_repos) do
if path == repo_path then
return
end
end
table.insert(lazygit_visited_git_repos, tostring(repo_path))
end
--- Strip leading and lagging whitespace
local function trim(str)
return str:gsub('^%s+', ''):gsub('%s+$', '')
end
local function get_root()
local cwd = vim.loop.cwd()
local status, job = pcall(require, 'plenary.job')
if not status then
return fn.system('git rev-parse --show-toplevel')
end
local gitroot_job = job:new({
'git',
'rev-parse',
'--show-toplevel',
cwd=cwd
})
local path, code = gitroot_job:sync()
if (code ~= 0) then
return nil
end
return table.concat(path, "")
end
--- Get project_root_dir for git repository
local function project_root_dir()
-- always use bash on Unix based systems.
local oldshell = vim.o.shell
if vim.fn.has('win32') == 0 then
vim.o.shell = 'bash'
end
local root = get_root()
if root == nil then
return nil
end
local cmd = string.format('cd "%s" && git rev-parse --show-toplevel', fn.fnamemodify(fn.resolve(fn.expand('%:p')), ':h'), root)
-- try symlinked file location instead
local gitdir = fn.system(cmd)
local isgitdir = fn.matchstr(gitdir, '^fatal:.*') == ''
if isgitdir then
vim.o.shell = oldshell
append_git_repo_path(gitdir)
return trim(gitdir)
end
-- revert to old shell
vim.o.shell = oldshell
local repo_path = fn.getcwd(0, 0)
append_git_repo_path(repo_path)
-- just return current working directory
return repo_path
end
--- Check if lazygit is available
local function is_lazygit_available()
return fn.executable('lazygit') == 1
end
local function is_symlink()
local resolved = fn.resolve(fn.expand('%:p'))
return resolved ~= fn.expand('%:p')
end
return {
get_root = get_root,
project_root_dir = project_root_dir,
lazygit_visited_git_repos = lazygit_visited_git_repos,
is_lazygit_available = is_lazygit_available,
is_symlink = is_symlink,
}

85
lua/lazygit/window.lua Normal file
View File

@@ -0,0 +1,85 @@
local api = vim.api
--- open floating window with nice borders
local function open_floating_window()
local floating_window_scaling_factor = vim.g.lazygit_floating_window_scaling_factor
-- Why is this required?
-- vim.g.lazygit_floating_window_scaling_factor returns different types if the value is an integer or float
if type(floating_window_scaling_factor) == 'table' then
floating_window_scaling_factor = floating_window_scaling_factor[false]
end
local status, plenary = pcall(require, 'plenary.window.float')
if status and vim.g.lazygit_floating_window_use_plenary and vim.g.lazygit_floating_window_use_plenary ~= 0 then
plenary.percentage_range_window(floating_window_scaling_factor, floating_window_scaling_factor)
return
end
local height = math.ceil(vim.o.lines * floating_window_scaling_factor) - 1
local width = math.ceil(vim.o.columns * floating_window_scaling_factor)
local row = math.ceil(vim.o.lines - height) / 2
local col = math.ceil(vim.o.columns - width) / 2
local border_opts = {
style = 'minimal',
relative = 'editor',
row = row - 1,
col = col - 1,
width = width + 2,
height = height + 2,
}
local opts = { style = 'minimal', relative = 'editor', row = row, col = col, width = width, height = height }
local topleft, topright, botleft, botright
local corner_chars = vim.g.lazygit_floating_window_corner_chars
if type(corner_chars) == 'table' and #corner_chars == 4 then
topleft, topright, botleft, botright = unpack(corner_chars)
else
topleft, topright, botleft, botright = '', '', '', ''
end
local border_lines = { topleft .. string.rep('', width) .. topright }
local middle_line = '' .. string.rep(' ', width) .. ''
for i = 1, height do
table.insert(border_lines, middle_line)
end
table.insert(border_lines, botleft .. string.rep('', width) .. botright)
-- create a unlisted scratch buffer for the border
local border_buffer = api.nvim_create_buf(false, true)
-- set border_lines in the border buffer from start 0 to end -1 and strict_indexing false
api.nvim_buf_set_lines(border_buffer, 0, -1, true, border_lines)
-- create border window
local border_window = api.nvim_open_win(border_buffer, true, border_opts)
vim.cmd('set winhl=Normal:Floating')
-- create a unlisted scratch buffer
if LAZYGIT_BUFFER == nil or vim.fn.bufwinnr(LAZYGIT_BUFFER) == -1 then
LAZYGIT_BUFFER = api.nvim_create_buf(false, true)
else
LAZYGIT_LOADED = true
end
-- create file window, enter the window, and use the options defined in opts
local _ = api.nvim_open_win(LAZYGIT_BUFFER, true, opts)
vim.bo[LAZYGIT_BUFFER].filetype = 'lazygit'
vim.cmd('setlocal bufhidden=hide')
vim.cmd('setlocal nocursorcolumn')
vim.cmd('set winblend=' .. vim.g.lazygit_floating_window_winblend)
-- use autocommand to ensure that the border_buffer closes at the same time as the main buffer
local cmd = [[autocmd WinLeave <buffer> silent! execute 'hide']]
vim.cmd(cmd)
cmd = [[autocmd WinLeave <buffer> silent! execute 'silent bdelete! %s']]
vim.cmd(cmd:format(border_buffer))
end
return {
open_floating_window = open_floating_window,
}

View File

@@ -0,0 +1,86 @@
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local action_set = require("telescope.actions.set")
local action_state = require("telescope.actions.state")
local conf = require("telescope.config").values
local lazygit_utils = require("lazygit.utils")
local function open_lazygit(prompt_buf)
local entry = action_state.get_selected_entry()
vim.fn.execute('cd ' .. entry.value)
local cmd = [[lua require"lazygit".lazygit(nil)]]
vim.api.nvim_command(cmd)
vim.cmd('stopinsert')
vim.cmd([[execute "normal i"]])
vim.fn.feedkeys('j')
vim.api.nvim_buf_set_keymap(0, 't', '<Esc>', '<Esc>', {noremap = true, silent = true})
end
local lazygit_repos = function(opts)
local displayer = require("telescope.pickers.entry_display").create {
separator = "",
-- TODO: make use of telescope geometry
items = {
{width = 4},
{width = 55},
{remaining = true},
},
}
local repos = {}
for _, v in pairs(lazygit_utils.lazygit_visited_git_repos) do
if v == nil then
goto skip
end
local index = #repos + 1
local entry =
{
idx = index,
value = v:gsub("%s", ""),
-- retrieve git repo name
repo_name= v:gsub("%s", ""):match("^.+/(.+)$"),
}
table.insert(repos, index, entry)
::skip::
end
pickers.new(opts or {}, {
prompt_title = "lazygit repos",
finder = finders.new_table {
results = repos,
entry_maker = function(entry)
local make_display = function()
return displayer
{
{entry.idx},
{entry.repo_name},
}
end
return {
value = entry.value,
ordinal = string.format("%s %s", entry.idx, entry.repo_name),
display = make_display,
}
end,
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(_, _)
action_set.select:replace(open_lazygit)
return true
end
}):find()
end
return require("telescope").register_extension({
exports = {
lazygit = lazygit_repos,
}
})