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
|
local fs = require("crupest.system.fs")
local function list_listed_bufs()
local bufs = vim.api.nvim_list_bufs()
local result = {}
for _, v in ipairs(bufs) do
if vim.fn.buflisted(v) ~= 0 then
table.insert(result, v)
end
end
return result
end
local function get_previous_buffer(buf)
local bufs = list_listed_bufs()
-- no buffers at all
if #bufs == 0 then return nil end
-- find the buf in bufs
local index = 0
for i, v in ipairs(bufs) do
if buf == v then
index = i
break
end
end
-- it's the only one
if #bufs == 1 and index == 1 then
return nil
end
-- it's the first one
if index == 1 then
return bufs[2]
end
return bufs[index - 1]
end
-- list the windows that are currently editing the given buffer
local function list_wins_editing_buf(buf)
local wins = vim.api.nvim_list_wins()
local result = {}
for _, win in ipairs(wins) do
if vim.api.nvim_win_get_buf(win) == buf then
table.insert(result, win)
end
end
return result
end
local function buf_is_normal(buf)
return vim.fn.bufexists(buf) ~= 0 and vim.fn.buflisted(buf) ~= 0
end
-- Delete current buffer and jump back.
-- If no previous jump, switch to previous buffer.
-- If no previous buffer (no other buffers), create a unnamed one. (So the window does not quit.)
local function win_close_buf()
local buf = vim.api.nvim_get_current_buf()
if not buf_is_normal(buf) then
return
end
local jumps_info = vim.fn.getjumplist()
local old_jumps = { unpack(jumps_info[1], 1, jumps_info[2]) }
while #old_jumps ~= 0 do
local last_jump = old_jumps[#old_jumps]
if last_jump.bufnr ~= buf and vim.fn.bufexists(last_jump.bufnr) ~= 0 and vim.fn.buflisted(last_jump.bufnr) ~= 0 then
break
end
table.remove(old_jumps, #old_jumps)
end
if #old_jumps ~= 0 then
local last_jump = old_jumps[#old_jumps]
vim.api.nvim_win_set_buf(0, last_jump.bufnr)
vim.api.nvim_win_set_cursor(0, {last_jump.lnum, last_jump.col})
else
local previous_buf = get_previous_buffer(buf)
if previous_buf then
vim.api.nvim_win_set_buf(0, previous_buf)
else
local new_buf = vim.api.nvim_create_buf(true, false)
vim.api.nvim_win_set_buf(0, new_buf)
end
end
local wins = list_wins_editing_buf(buf)
if #wins == 0 then
vim.api.nvim_buf_delete(buf, {})
end
end
local function close_float()
local wins = vim.api.nvim_list_wins()
for _, v in ipairs(wins) do
if vim.api.nvim_win_get_config(v).relative ~= '' then
vim.api.nvim_win_close(v, false)
end
end
end
local function full_path(name)
return vim.fn.fnamemodify(name, ":p:gs?\\?/?")
end
local function coerce_path_for_dir(old, new)
if fs.isdir(new) then
return new .. "/" .. vim.fn.fnamemodify(old, ":t")
end
return new
end
local function do_mv_file(old, new, overwrite)
new = coerce_path_for_dir(old, new)
if full_path(old) == full_path(new) then
vim.notify("Paths are identical. Do nothing.", vim.log.levels.WARN)
return false
end
if not fs.isfile(old) then
vim.notify("Not exists or not a file. Can't move.", vim.log.levels.ERROR)
return false
end
if not overwrite and fs.exist(new) then
vim.notify("Target path exists.", vim.log.levels.ERROR)
return false
end
fs.move(old, new)
vim.notify("File moved.")
return new
end
local function mv_file(old, new, overwrite)
new = do_mv_file(old, new, overwrite)
if not new then return end
local bufs = list_listed_bufs()
for _, b in ipairs(bufs) do
if full_path(vim.api.nvim_buf_get_name(b)) == full_path(old) then
vim.api.nvim_buf_set_name(b, new)
end
end
end
local function mv_buf_file(buf, new, overwrite)
if not buf_is_normal(buf) then
vim.notify("Buf is not a normal buffer, can't move it.", vim.log.levels.ERROR)
return
end
local name = vim.api.nvim_buf_get_name(buf)
new = do_mv_file(name, new, overwrite)
if not new then return end
vim.api.nvim_buf_set_name(buf, new)
end
local function mv_dir(old_dir, new_dir, overwrite)
new_dir = coerce_path_for_dir(old_dir, new_dir)
if full_path(old_dir) == full_path(new_dir) then
vim.notify("Paths are identical. Do nothing.", vim.log.levels.WARN)
return
end
if not fs.isdir(old_dir) then
vim.notify("Not exist or not a dir. Can't move.", vim.log.levels.ERROR)
end
if not overwrite and fs.exist(new_dir) then
vim.notify("Target path exists.", vim.log.levels.ERROR)
return
end
if fs.isdir(old_dir) then
fs.move(old_dir, new_dir)
vim.notify("Dir moved.")
end
local bufs = list_listed_bufs()
for _, buf in ipairs(bufs) do
local name = vim.api.nvim_buf_get_name(buf)
local full_name = full_path(name)
local old_dir_full = full_path(old_dir)
if string.find(full_name, old_dir_full, 1, true) == 1 then
local new_name = new_dir .. string.sub(full_name, #old_dir_full + 1)
vim.api.nvim_buf_set_name(buf, new_name)
end
end
end
local function rename_file(old, new, overwrite)
local dir = vim.fn.fnamemodify(old, ":h")
mv_file(old, dir .. "/" .. new, overwrite)
end
local function rename_buf_file(buf, new_name, overwrite)
local old_path = vim.api.nvim_buf_get_name(buf)
local dir = vim.fn.fnamemodify(old_path, ":h")
mv_buf_file(buf, dir .. "/" .. new_name, overwrite)
end
return {
list_listed_bufs = list_listed_bufs,
get_previous_buffer = get_previous_buffer,
list_wins_editing_buf = list_wins_editing_buf,
win_close_buf = win_close_buf,
close_float = close_float,
mv_file = mv_file,
mv_buf_file = mv_buf_file,
mv_dir = mv_dir,
rename_file = rename_file,
rename_buf_file = rename_buf_file
}
|