-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathgit.lua
More file actions
119 lines (102 loc) · 2.96 KB
/
git.lua
File metadata and controls
119 lines (102 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
local M = {}
local repo_root_cache = {}
---@param filepath? string
---@return string?
function M.get_repo_root(filepath)
local dir = vim.fn.fnamemodify(filepath, ':h')
if repo_root_cache[dir] ~= nil then
return repo_root_cache[dir]
end
local result = vim.fn.systemlist({ 'git', '-C', dir, 'rev-parse', '--show-toplevel' })
if vim.v.shell_error ~= 0 then
return nil
end
repo_root_cache[dir] = result[1]
return result[1]
end
---@param revision string
---@param filepath string
---@return string[]?, string?
function M.get_file_content(revision, filepath)
local repo_root = M.get_repo_root(filepath)
if not repo_root then
return nil, 'not in a git repository'
end
local rel_path = vim.fn.fnamemodify(filepath, ':.')
if vim.startswith(filepath, repo_root) then
rel_path = filepath:sub(#repo_root + 2)
end
local result = vim.fn.systemlist({ 'git', '-C', repo_root, 'show', revision .. ':' .. rel_path })
if vim.v.shell_error ~= 0 then
return nil, 'failed to get file at revision: ' .. revision
end
return result, nil
end
---@param filepath string
---@return string?
function M.get_relative_path(filepath)
local repo_root = M.get_repo_root(filepath)
if not repo_root then
return nil
end
if vim.startswith(filepath, repo_root) then
return filepath:sub(#repo_root + 2)
end
return vim.fn.fnamemodify(filepath, ':.')
end
---@param filepath string
---@return string[]?, string?
function M.get_index_content(filepath)
local repo_root = M.get_repo_root(filepath)
if not repo_root then
return nil, 'not in a git repository'
end
local rel_path = M.get_relative_path(filepath)
if not rel_path then
return nil, 'could not determine relative path'
end
local result = vim.fn.systemlist({ 'git', '-C', repo_root, 'show', ':0:' .. rel_path })
if vim.v.shell_error ~= 0 then
return nil, 'file not in index'
end
return result, nil
end
---@param filepath string
---@return string[]?, string?
function M.get_working_content(filepath)
if vim.fn.filereadable(filepath) ~= 1 then
return nil, 'file not readable'
end
local lines = vim.fn.readfile(filepath)
return lines, nil
end
---@param filepath string
---@return boolean
function M.file_exists_in_index(filepath)
local repo_root = M.get_repo_root(filepath)
if not repo_root then
return false
end
local rel_path = M.get_relative_path(filepath)
if not rel_path then
return false
end
vim.fn.system({ 'git', '-C', repo_root, 'ls-files', '--stage', '--', rel_path })
return vim.v.shell_error == 0
end
---@param revision string
---@param filepath string
---@return boolean
function M.file_exists_at_revision(revision, filepath)
local repo_root = M.get_repo_root(filepath)
if not repo_root then
return false
end
local rel_path = M.get_relative_path(filepath)
if not rel_path then
return false
end
vim.fn.system({ 'git', '-C', repo_root, 'cat-file', '-e', revision .. ':' .. rel_path })
return vim.v.shell_error == 0
end
return M