aboutsummaryrefslogtreecommitdiff
path: root/configs/nvim/lua/crupest/nvim.lua
blob: 44c9b5f00018bf1fd749b13f3d306f9331e39ae0 (plain)
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
}