|
1 | | -local Path = require("plenary.path") |
2 | | -local utils = require("neo-tree.utils") |
3 | | -local log = require("neo-tree.log") |
4 | | - |
5 | | -local os_sep = Path.path.sep |
6 | | - |
7 | | -local M = {} |
8 | | - |
9 | | -local function execute_command(cmd) |
10 | | - local result = vim.fn.systemlist(cmd) |
11 | | - |
12 | | - -- An empty result is ok |
13 | | - if vim.v.shell_error ~= 0 or (#result > 0 and vim.startswith(result[1], "fatal:")) then |
14 | | - return false, {} |
15 | | - else |
16 | | - return true, result |
17 | | - end |
18 | | -end |
19 | | - |
20 | | -local function windowize_path(path) |
21 | | - return path:gsub("/", "\\") |
22 | | -end |
23 | | - |
24 | | -M.get_repository_root = function(path) |
25 | | - local cmd = "git rev-parse --show-toplevel" |
26 | | - if utils.truthy(path) then |
27 | | - cmd = "git -C " .. path .. " rev-parse --show-toplevel" |
28 | | - end |
29 | | - local ok, git_root = execute_command(cmd) |
30 | | - if not ok then |
31 | | - return nil |
32 | | - end |
33 | | - git_root = git_root[1] |
34 | | - |
35 | | - if utils.is_windows then |
36 | | - git_root = windowize_path(git_root) |
37 | | - end |
38 | | - |
39 | | - return git_root |
40 | | -end |
41 | | - |
42 | | -local function get_simple_git_status_code(status) |
43 | | - -- Prioritze M then A over all others |
44 | | - if status:match("U") or status == "AA" or status == "DD" then |
45 | | - return "U" |
46 | | - elseif status:match("M") then |
47 | | - return "M" |
48 | | - elseif status:match("[ACR]") then |
49 | | - return "A" |
50 | | - elseif status:match("!$") then |
51 | | - return "!" |
52 | | - elseif status:match("?$") then |
53 | | - return "?" |
54 | | - else |
55 | | - local len = #status |
56 | | - while len > 0 do |
57 | | - local char = status:sub(len, len) |
58 | | - if char ~= " " then |
59 | | - return char |
60 | | - end |
61 | | - len = len - 1 |
62 | | - end |
63 | | - return status |
64 | | - end |
65 | | -end |
66 | | - |
67 | | -local function get_priority_git_status_code(status, other_status) |
68 | | - if not status then |
69 | | - return other_status |
70 | | - elseif not other_status then |
71 | | - return status |
72 | | - elseif status == "U" or other_status == "U" then |
73 | | - return "U" |
74 | | - elseif status == "?" or other_status == "?" then |
75 | | - return "?" |
76 | | - elseif status == "M" or other_status == "M" then |
77 | | - return "M" |
78 | | - elseif status == "A" or other_status == "A" then |
79 | | - return "A" |
80 | | - else |
81 | | - return status |
82 | | - end |
83 | | -end |
84 | | - |
85 | | ----Parse "git status" output for the current working directory. |
86 | | ----@return table table Table with the path as key and the status as value. |
87 | | -M.status = function(exclude_directories) |
88 | | - local git_root = M.get_repository_root() |
89 | | - if not git_root then |
90 | | - return {} |
91 | | - end |
92 | | - local ok, result = execute_command("git status --porcelain=v1") |
93 | | - if not ok then |
94 | | - return {} |
95 | | - end |
96 | | - |
97 | | - local git_status = {} |
98 | | - for _, line in ipairs(result) do |
99 | | - local status = line:sub(1, 2) |
100 | | - local relative_path = line:sub(4) |
101 | | - local arrow_pos = relative_path:find(" -> ") |
102 | | - if arrow_pos ~= nil then |
103 | | - relative_path = line:sub(arrow_pos + 5) |
104 | | - end |
105 | | - -- remove any " due to whitespace in the path |
106 | | - relative_path = relative_path:gsub('^"', ""):gsub('$"', "") |
107 | | - if utils.is_windows == true then |
108 | | - relative_path = windowize_path(relative_path) |
109 | | - end |
110 | | - local absolute_path = string.format("%s%s%s", git_root, os_sep, relative_path) |
111 | | - git_status[absolute_path] = status |
112 | | - |
113 | | - if not exclude_directories then |
114 | | - -- Now bubble this status up to the parent directories |
115 | | - local file_status = get_simple_git_status_code(status) |
116 | | - local parents = Path:new(absolute_path):parents() |
117 | | - for i = #parents, 1, -1 do |
118 | | - local path = parents[i] |
119 | | - local path_status = git_status[path] |
120 | | - git_status[path] = get_priority_git_status_code(path_status, file_status) |
121 | | - end |
122 | | - end |
123 | | - end |
124 | | - |
125 | | - return git_status, git_root |
126 | | -end |
127 | | - |
128 | | -M.load_ignored_per_directory = function(path) |
129 | | - if type(path) ~= "string" then |
130 | | - log.error("load_ignored_per_directory: path must be a string") |
131 | | - return {} |
132 | | - end |
133 | | - path = utils.path_join(path, "*") |
134 | | - local cmd = 'git check-ignore "' .. path .. '"' |
135 | | - local result = vim.fn.systemlist(cmd) |
136 | | - if vim.v.shell_error == 128 then |
137 | | - if utils.truthy(result) and vim.startswith(result[1], "fatal: not a git repository") then |
138 | | - return {} |
139 | | - end |
140 | | - log.error("Failed to load ignored files for ", path, ": ", result) |
141 | | - return {} |
142 | | - end |
143 | | - return result |
144 | | -end |
145 | | - |
146 | | -M.load_ignored = function(path) |
147 | | - local git_root = M.get_repository_root(path) |
148 | | - if not git_root then |
149 | | - return {} |
150 | | - end |
151 | | - local ok, result = execute_command( |
152 | | - "git --no-optional-locks status --porcelain=v1 --ignored=matching --untracked-files=normal" |
153 | | - ) |
154 | | - if not ok then |
155 | | - return {} |
156 | | - end |
157 | | - |
158 | | - local ignored = {} |
159 | | - for _, v in ipairs(result) do |
160 | | - -- git ignore format: |
161 | | - -- !! path/to/file |
162 | | - -- !! path/to/path/ |
163 | | - -- with paths relative to the repository root |
164 | | - if v:sub(1, 2) == "!!" then |
165 | | - local entry = v:sub(4) |
166 | | - -- remove any " due to whitespace in the path |
167 | | - entry = entry:gsub('^"', ""):gsub('$"', "") |
168 | | - if utils.is_windows then |
169 | | - entry = windowize_path(entry) |
170 | | - end |
171 | | - -- use the absolute path |
172 | | - table.insert(ignored, string.format("%s%s%s", git_root, os_sep, entry)) |
173 | | - end |
174 | | - end |
175 | | - |
176 | | - return ignored |
177 | | -end |
178 | | - |
179 | | -M.is_ignored = function(ignored, path, _type) |
180 | | - path = _type == "directory" and (path .. os_sep) or path |
181 | | - for _, v in ipairs(ignored) do |
182 | | - if v:sub(-1) == os_sep then |
183 | | - -- directory ignore |
184 | | - if vim.startswith(path, v) then |
185 | | - return true |
186 | | - end |
187 | | - else |
188 | | - -- file ignore |
189 | | - if path == v then |
190 | | - return true |
191 | | - end |
192 | | - end |
193 | | - end |
194 | | -end |
| 1 | +local status = require("neo-tree.git.status") |
| 2 | +local ignored = require("neo-tree.git.ignored") |
| 3 | +local git_utils = require("neo-tree.git.utils") |
| 4 | + |
| 5 | +local M = { |
| 6 | + get_repository_root = git_utils.get_repository_root, |
| 7 | + is_ignored = ignored.is_ignored, |
| 8 | + load_ignored = ignored.load_ignored, |
| 9 | + load_ignored_per_directory = ignored.load_ignored_per_directory, |
| 10 | + status = status.status, |
| 11 | + status_async = status.status_async, |
| 12 | +} |
195 | 13 |
|
196 | 14 | return M |
0 commit comments