Repository navigation
Expand file tree
/
Copy pathinit.lua
More file actions
346 lines (305 loc) · 9.04 KB
/
Copy pathinit.lua
File metadata and controls
346 lines (305 loc) · 9.04 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
if not require("diffview.bootstrap") then
return
end
local hl = require("diffview.hl")
local lazy = require("diffview.lazy")
local arg_parser = lazy.require("diffview.arg_parser") ---@module "diffview.arg_parser"
local config = lazy.require("diffview.config") ---@module "diffview.config"
local debounce = lazy.require("diffview.debounce") ---@module "diffview.debounce"
local lib = lazy.require("diffview.lib") ---@module "diffview.lib"
local utils = lazy.require("diffview.utils") ---@module "diffview.utils"
local vcs = lazy.require("diffview.vcs") ---@module "diffview.vcs"
local api = vim.api
local logger = DiffviewGlobal.logger
local pl = lazy.access(utils, "path") --[[@as PathLib ]]
local M = {}
---@param user_config? DiffviewConfig.user
function M.setup(user_config)
config.setup(user_config or {})
end
function M.init()
-- Fix the strange behavior that "<afile>" expands non-files
-- as file name in some cases.
--
local function get_tabnr(state)
return tonumber(state.file)
end
local au = api.nvim_create_autocmd
-- Set up highlighting
hl.setup()
-- Set up autocommands
M.augroup = api.nvim_create_augroup("diffview_nvim", {})
au("TabEnter", {
group = M.augroup,
pattern = "*",
callback = function(_)
M.emit("tab_enter")
end,
})
-- Throttle `FocusGained` so bursts of focus events can't drive
-- `refresh_files` faster than it can complete.
local refresh_files_throttled = debounce.throttle_trailing(500, true, function()
M.emit("refresh_files")
end)
au("FocusGained", {
group = M.augroup,
pattern = "*",
callback = function(_)
refresh_files_throttled()
end,
})
au("TabLeave", {
group = M.augroup,
pattern = "*",
callback = function(_)
M.emit("tab_leave")
end,
})
au("TabClosed", {
group = M.augroup,
pattern = "*",
callback = function(state)
M.close(get_tabnr(state))
end,
})
au("BufWritePost", {
group = M.augroup,
pattern = "*",
callback = function(_)
M.emit("buf_write_post")
end,
})
au("WinClosed", {
group = M.augroup,
pattern = "*",
callback = function(state)
M.emit("win_closed", get_tabnr(state))
end,
})
au("ColorScheme", {
group = M.augroup,
pattern = "*",
callback = function(_)
M.update_colors()
end,
})
au("User", {
group = M.augroup,
pattern = "FugitiveChanged",
callback = function(_)
M.emit("refresh_files")
end,
})
-- Set up user autocommand emitters
DiffviewGlobal.emitter:on("view_opened", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewViewOpened", modeline = false })
end)
DiffviewGlobal.emitter:on("view_closed", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewViewClosed", modeline = false })
end)
DiffviewGlobal.emitter:on("view_enter", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewViewEnter", modeline = false })
end)
DiffviewGlobal.emitter:on("view_leave", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewViewLeave", modeline = false })
end)
DiffviewGlobal.emitter:on("view_post_layout", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewViewPostLayout", modeline = false })
end)
DiffviewGlobal.emitter:on("diff_buf_read", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewDiffBufRead", modeline = false })
end)
DiffviewGlobal.emitter:on("diff_buf_win_enter", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewDiffBufWinEnter", modeline = false })
end)
DiffviewGlobal.emitter:on("selection_changed", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewSelectionChanged", modeline = false })
end)
DiffviewGlobal.emitter:on("files_staged", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewFilesStaged", modeline = false })
end)
-- Set up completion wrapper used by `vim.ui.input()`
vim.cmd([[
function! Diffview__ui_input_completion(...) abort
return luaeval("DiffviewGlobal.state.current_completer(
\ unpack(vim.fn.eval('a:000')))")
endfunction
]])
end
---@param args string[]
function M.open(args)
local view = lib.diffview_open(args)
if view and not (view.tabpage and api.nvim_tabpage_is_valid(view.tabpage)) then
view:open()
end
end
---@param range? { [1]: integer, [2]: integer }
---@param args string[]
function M.file_history(range, args)
local view = lib.file_history(range, args)
if view then
view:open()
end
end
---@param args string[]
function M.diff_files(args)
local view = lib.diffview_diff_files(args)
if view then
view:open()
end
end
---@param args string[]
function M.merge_files(args)
local view = lib.diffview_merge_files(args)
if view then
view:open()
end
end
---@param args string[]
function M.dir_diff(args)
local view = lib.diffview_dir_diff(args)
if view then
view:open()
end
end
---@param tabpage? integer
---@param opts? diffview.View.CloseOpts # Forwarded to `view:close`. With
---`force = false`, `DiffView` aborts when stage buffers are modified.
---@return boolean closed # `false` if the close was aborted.
function M.close(tabpage, opts)
if tabpage then
vim.schedule(function()
lib.dispose_stray_views()
end)
return true
end
local view = lib.get_current_view()
if view then
local closed = view:close(opts)
if closed == false then
return false
end
lib.dispose_view(view)
end
return true
end
---@param args string[]
function M.toggle(args)
local view = lib.get_current_view()
if view then
M.close(nil, { force = false })
else
M.open(args)
end
end
function M.completion(_, cmd_line, cur_pos)
local ctx = arg_parser.scan(cmd_line, { cur_pos = cur_pos, allow_ex_range = true })
local cmd = ctx.args[1]
if cmd and M.completers[cmd] then
return arg_parser.process_candidates(M.completers[cmd](ctx), ctx)
end
end
---Create a temporary adapter to get relevant completions
---@return VCSAdapter?
function M.get_adapter()
local cfile = pl:vim_expand("%")
local top_indicators =
utils.vec_join(vim.bo.buftype == "" and pl:absolute(cfile) or nil, pl:realpath("."))
local err, adapter = vcs.get_adapter({ top_indicators = top_indicators })
if err then
logger:warn("[completion] Failed to create adapter: " .. err)
end
return adapter
end
M.completers = {
---@param ctx CmdLineContext
DiffviewOpen = function(ctx)
local has_rev_arg = false
local adapter = M.get_adapter()
for i = 2, math.min(#ctx.args, ctx.divideridx) do
if ctx.args[i]:sub(1, 1) ~= "-" and i ~= ctx.argidx then
has_rev_arg = true
break
end
end
local candidates = {}
if ctx.argidx > ctx.divideridx then
if adapter then
utils.vec_extend(candidates, adapter:path_candidates(ctx.arg_lead))
else
utils.vec_extend(candidates, vim.fn.getcompletion(ctx.arg_lead, "file", false))
end
elseif adapter then
if not has_rev_arg and ctx.arg_lead:sub(1, 1) ~= "-" then
utils.vec_extend(candidates, adapter.comp.open:get_all_names())
utils.vec_extend(
candidates,
adapter:rev_candidates(ctx.arg_lead, {
accept_range = true,
})
)
else
utils.vec_extend(
candidates,
adapter.comp.open:get_completion(ctx.arg_lead) or adapter.comp.open:get_all_names()
)
end
end
return candidates
end,
---@param ctx CmdLineContext
DiffviewDiffFiles = function(ctx)
return vim.fn.getcompletion(ctx.arg_lead, "file", false)
end,
---@param ctx CmdLineContext
DiffviewMergeFiles = function(ctx)
return vim.fn.getcompletion(ctx.arg_lead, "file", false)
end,
---@param ctx CmdLineContext
DiffviewDiffDirs = function(ctx)
return vim.fn.getcompletion(ctx.arg_lead, "dir", false)
end,
---@param ctx CmdLineContext
DiffviewFileHistory = function(ctx)
local adapter = M.get_adapter()
local candidates = {}
if adapter then
utils.vec_extend(
candidates,
adapter.comp.file_history:get_completion(ctx.arg_lead)
or adapter.comp.file_history:get_all_names()
)
utils.vec_extend(candidates, adapter:path_candidates(ctx.arg_lead))
else
utils.vec_extend(candidates, vim.fn.getcompletion(ctx.arg_lead, "file", false))
end
return candidates
end,
}
function M.update_colors()
hl.setup()
lib.update_colors()
end
local function _emit(no_recursion, event_name, ...)
local view = lib.get_current_view()
if view and not view.closing:check() then
local that = view.emitter
local fn = no_recursion and that.nore_emit or that.emit
fn(that, event_name, ...)
that = DiffviewGlobal.emitter
fn = no_recursion and that.nore_emit or that.emit
if event_name == "tab_enter" then
fn(that, "view_enter", view)
elseif event_name == "tab_leave" then
fn(that, "view_leave", view)
end
end
end
function M.emit(event_name, ...)
_emit(false, event_name, ...)
end
function M.nore_emit(event_name, ...)
_emit(true, event_name, ...)
end
M.init()
return M