1270 lines
42 KiB
Lua
1270 lines
42 KiB
Lua
local M = {}
|
|
|
|
---@class (exact) oil.Entry
|
|
---@field name string
|
|
---@field type oil.EntryType
|
|
---@field id nil|integer Will be nil if it hasn't been persisted to disk yet
|
|
---@field parsed_name nil|string
|
|
---@field meta nil|table
|
|
|
|
---@alias oil.EntryType "file"|"directory"|"socket"|"link"|"fifo"
|
|
---@alias oil.HlRange { [1]: string, [2]: integer, [3]: integer } A tuple of highlight group name, col_start, col_end
|
|
---@alias oil.HlTuple { [1]: string, [2]: string } A tuple of text, highlight group
|
|
---@alias oil.HlRangeTuple { [1]: string, [2]: oil.HlRange[] } A tuple of text, internal highlights
|
|
---@alias oil.TextChunk string|oil.HlTuple|oil.HlRangeTuple
|
|
---@alias oil.CrossAdapterAction "copy"|"move"
|
|
|
|
---@class (exact) oil.Adapter
|
|
---@field name string The unique name of the adapter (this will be set automatically)
|
|
---@field list fun(path: string, column_defs: string[], cb: fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())) Async function to list a directory.
|
|
---@field is_modifiable fun(bufnr: integer): boolean Return true if this directory is modifiable (allows for directories with read-only permissions).
|
|
---@field get_column fun(name: string): nil|oil.ColumnDefinition If the adapter has any adapter-specific columns, return them when fetched by name.
|
|
---@field get_parent? fun(bufname: string): string Get the parent url of the given buffer
|
|
---@field normalize_url fun(url: string, callback: fun(url: string)) Before oil opens a url it will be normalized. This allows for link following, path normalizing, and converting an oil file url to the actual path of a file.
|
|
---@field get_entry_path? fun(url: string, entry: oil.Entry, callback: fun(path: string)) Similar to normalize_url, but used when selecting an entry
|
|
---@field render_action? fun(action: oil.Action): string Render a mutation action for display in the preview window. Only needed if adapter is modifiable.
|
|
---@field perform_action? fun(action: oil.Action, cb: fun(err: nil|string)) Perform a mutation action. Only needed if adapter is modifiable.
|
|
---@field read_file? fun(bufnr: integer) Used for adapters that deal with remote/virtual files. Read the contents of the file into a buffer.
|
|
---@field write_file? fun(bufnr: integer) Used for adapters that deal with remote/virtual files. Write the contents of a buffer to the destination.
|
|
---@field supported_cross_adapter_actions? table<string, oil.CrossAdapterAction> Mapping of adapter name to enum for all other adapters that can be used as a src or dest for move/copy actions.
|
|
---@field filter_action? fun(action: oil.Action): boolean When present, filter out actions as they are created
|
|
---@field filter_error? fun(action: oil.ParseError): boolean When present, filter out errors from parsing a buffer
|
|
|
|
---Get the entry on a specific line (1-indexed)
|
|
---@param bufnr integer
|
|
---@param lnum integer
|
|
---@return nil|oil.Entry
|
|
M.get_entry_on_line = function(bufnr, lnum)
|
|
local columns = require("oil.columns")
|
|
local parser = require("oil.mutator.parser")
|
|
local util = require("oil.util")
|
|
if vim.bo[bufnr].filetype ~= "oil" then
|
|
return nil
|
|
end
|
|
local adapter = util.get_adapter(bufnr)
|
|
if not adapter then
|
|
return nil
|
|
end
|
|
|
|
local line = vim.api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, true)[1]
|
|
if not line then
|
|
return nil
|
|
end
|
|
local column_defs = columns.get_supported_columns(adapter)
|
|
local result = parser.parse_line(adapter, line, column_defs)
|
|
if result then
|
|
if result.entry then
|
|
local entry = util.export_entry(result.entry)
|
|
entry.parsed_name = result.data.name
|
|
return entry
|
|
else
|
|
return {
|
|
id = result.data.id,
|
|
name = result.data.name,
|
|
type = result.data._type,
|
|
parsed_name = result.data.name,
|
|
}
|
|
end
|
|
end
|
|
-- This is a NEW entry that hasn't been saved yet
|
|
local name = vim.trim(line)
|
|
local entry_type
|
|
if vim.endswith(name, "/") then
|
|
name = name:sub(1, name:len() - 1)
|
|
entry_type = "directory"
|
|
else
|
|
entry_type = "file"
|
|
end
|
|
if name == "" then
|
|
return nil
|
|
else
|
|
return {
|
|
name = name,
|
|
type = entry_type,
|
|
parsed_name = name,
|
|
}
|
|
end
|
|
end
|
|
|
|
---Get the entry currently under the cursor
|
|
---@return nil|oil.Entry
|
|
M.get_cursor_entry = function()
|
|
local lnum = vim.api.nvim_win_get_cursor(0)[1]
|
|
return M.get_entry_on_line(0, lnum)
|
|
end
|
|
|
|
---Discard all changes made to oil buffers
|
|
M.discard_all_changes = function()
|
|
local view = require("oil.view")
|
|
for _, bufnr in ipairs(view.get_all_buffers()) do
|
|
if vim.bo[bufnr].modified then
|
|
view.render_buffer_async(bufnr, {}, function(err)
|
|
if err then
|
|
vim.notify(
|
|
string.format(
|
|
"Error rendering oil buffer %s: %s",
|
|
vim.api.nvim_buf_get_name(bufnr),
|
|
err
|
|
),
|
|
vim.log.levels.ERROR
|
|
)
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
|
|
---Change the display columns for oil
|
|
---@param cols oil.ColumnSpec[]
|
|
M.set_columns = function(cols)
|
|
require("oil.view").set_columns(cols)
|
|
end
|
|
|
|
---Change the sort order for oil
|
|
---@param sort string[][]
|
|
M.set_sort = function(sort)
|
|
require("oil.view").set_sort(sort)
|
|
end
|
|
|
|
---Change how oil determines if the file is hidden
|
|
---@param is_hidden_file fun(filename: string, bufnr: nil|integer): boolean Return true if the file/dir should be hidden
|
|
M.set_is_hidden_file = function(is_hidden_file)
|
|
require("oil.view").set_is_hidden_file(is_hidden_file)
|
|
end
|
|
|
|
---Toggle hidden files and directories
|
|
M.toggle_hidden = function()
|
|
require("oil.view").toggle_hidden()
|
|
end
|
|
|
|
---Get the current directory
|
|
---@return nil|string
|
|
M.get_current_dir = function()
|
|
local config = require("oil.config")
|
|
local fs = require("oil.fs")
|
|
local util = require("oil.util")
|
|
local scheme, path = util.parse_url(vim.api.nvim_buf_get_name(0))
|
|
if config.adapters[scheme] == "files" then
|
|
assert(path)
|
|
return fs.posix_to_os_path(path)
|
|
end
|
|
end
|
|
|
|
---Get the oil url for a given directory
|
|
---@private
|
|
---@param dir nil|string When nil, use the cwd
|
|
---@param use_oil_parent nil|boolean If in an oil buffer, return the parent (default true)
|
|
---@return string The parent url
|
|
---@return nil|string The basename (if present) of the file/dir we were just in
|
|
M.get_url_for_path = function(dir, use_oil_parent)
|
|
if use_oil_parent == nil then
|
|
use_oil_parent = true
|
|
end
|
|
local config = require("oil.config")
|
|
local fs = require("oil.fs")
|
|
local util = require("oil.util")
|
|
if vim.bo.filetype == "netrw" and not dir then
|
|
dir = vim.b.netrw_curdir
|
|
end
|
|
if dir then
|
|
local scheme = util.parse_url(dir)
|
|
if scheme then
|
|
return dir
|
|
end
|
|
local abspath = vim.fn.fnamemodify(dir, ":p")
|
|
local path = fs.os_to_posix_path(abspath)
|
|
return config.adapter_to_scheme.files .. path
|
|
else
|
|
local bufname = vim.api.nvim_buf_get_name(0)
|
|
return M.get_buffer_parent_url(bufname, use_oil_parent)
|
|
end
|
|
end
|
|
|
|
---@private
|
|
---@param bufname string
|
|
---@param use_oil_parent boolean If in an oil buffer, return the parent
|
|
---@return string
|
|
---@return nil|string
|
|
M.get_buffer_parent_url = function(bufname, use_oil_parent)
|
|
local config = require("oil.config")
|
|
local fs = require("oil.fs")
|
|
local pathutil = require("oil.pathutil")
|
|
local util = require("oil.util")
|
|
local scheme, path = util.parse_url(bufname)
|
|
if not scheme then
|
|
local parent, basename
|
|
scheme = config.adapter_to_scheme.files
|
|
if bufname == "" then
|
|
parent = fs.os_to_posix_path(vim.fn.getcwd())
|
|
else
|
|
parent = fs.os_to_posix_path(vim.fn.fnamemodify(bufname, ":p:h"))
|
|
basename = vim.fn.fnamemodify(bufname, ":t")
|
|
end
|
|
local parent_url = util.addslash(scheme .. parent)
|
|
return parent_url, basename
|
|
else
|
|
assert(path)
|
|
if scheme == "term://" then
|
|
---@type string
|
|
path = vim.fn.expand(path:match("^(.*)//")) ---@diagnostic disable-line: assign-type-mismatch
|
|
return config.adapter_to_scheme.files .. util.addslash(path)
|
|
end
|
|
|
|
-- This is some unknown buffer scheme
|
|
if not config.adapters[scheme] then
|
|
return vim.fn.getcwd()
|
|
end
|
|
|
|
if not use_oil_parent then
|
|
return bufname
|
|
end
|
|
local adapter = config.get_adapter_by_scheme(scheme)
|
|
local parent_url
|
|
if adapter and adapter.get_parent then
|
|
local adapter_scheme = config.adapter_to_scheme[adapter.name]
|
|
parent_url = adapter.get_parent(adapter_scheme .. path)
|
|
else
|
|
local parent = pathutil.parent(path)
|
|
parent_url = scheme .. util.addslash(parent)
|
|
end
|
|
if parent_url == bufname then
|
|
return parent_url
|
|
else
|
|
return util.addslash(parent_url), pathutil.basename(path)
|
|
end
|
|
end
|
|
end
|
|
|
|
---Open oil browser in a floating window
|
|
---@param dir nil|string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file
|
|
M.open_float = function(dir)
|
|
local config = require("oil.config")
|
|
local layout = require("oil.layout")
|
|
local util = require("oil.util")
|
|
local view = require("oil.view")
|
|
local parent_url, basename = M.get_url_for_path(dir)
|
|
if not parent_url then
|
|
return
|
|
end
|
|
if basename then
|
|
view.set_last_cursor(parent_url, basename)
|
|
end
|
|
|
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
|
vim.bo[bufnr].bufhidden = "wipe"
|
|
local total_width = vim.o.columns
|
|
local total_height = layout.get_editor_height()
|
|
local width = total_width - 2 * config.float.padding
|
|
if config.float.border ~= "none" then
|
|
width = width - 2 -- The border consumes 1 col on each side
|
|
end
|
|
if config.float.max_width > 0 then
|
|
width = math.min(width, config.float.max_width)
|
|
end
|
|
local height = total_height - 2 * config.float.padding
|
|
if config.float.max_height > 0 then
|
|
height = math.min(height, config.float.max_height)
|
|
end
|
|
local row = math.floor((total_height - height) / 2)
|
|
local col = math.floor((total_width - width) / 2) - 1 -- adjust for border width
|
|
local win_opts = {
|
|
relative = "editor",
|
|
width = width,
|
|
height = height,
|
|
row = row,
|
|
col = col,
|
|
border = config.float.border,
|
|
zindex = 45,
|
|
}
|
|
win_opts = config.float.override(win_opts) or win_opts
|
|
|
|
local original_winid = vim.api.nvim_get_current_win()
|
|
local winid = vim.api.nvim_open_win(bufnr, true, win_opts)
|
|
vim.w[winid].is_oil_win = true
|
|
vim.w[winid].oil_original_win = original_winid
|
|
for k, v in pairs(config.float.win_options) do
|
|
vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid })
|
|
end
|
|
local autocmds = {}
|
|
table.insert(
|
|
autocmds,
|
|
vim.api.nvim_create_autocmd("WinLeave", {
|
|
desc = "Close floating oil window",
|
|
group = "Oil",
|
|
callback = vim.schedule_wrap(function()
|
|
if util.is_floating_win() or vim.fn.win_gettype() == "command" then
|
|
return
|
|
end
|
|
if vim.api.nvim_win_is_valid(winid) then
|
|
vim.api.nvim_win_close(winid, true)
|
|
end
|
|
for _, id in ipairs(autocmds) do
|
|
vim.api.nvim_del_autocmd(id)
|
|
end
|
|
autocmds = {}
|
|
end),
|
|
nested = true,
|
|
})
|
|
)
|
|
|
|
-- Update the window title when we switch buffers
|
|
if vim.fn.has("nvim-0.9") == 1 and config.float.border ~= "none" then
|
|
local function get_title()
|
|
local src_buf = vim.api.nvim_win_get_buf(winid)
|
|
local title = vim.api.nvim_buf_get_name(src_buf)
|
|
local scheme, path = util.parse_url(title)
|
|
if config.adapters[scheme] == "files" then
|
|
assert(path)
|
|
local fs = require("oil.fs")
|
|
title = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":~")
|
|
end
|
|
return title
|
|
end
|
|
table.insert(
|
|
autocmds,
|
|
vim.api.nvim_create_autocmd("BufWinEnter", {
|
|
desc = "Update oil floating window title when buffer changes",
|
|
pattern = "*",
|
|
callback = function(params)
|
|
local winbuf = params.buf
|
|
if not vim.api.nvim_win_is_valid(winid) or vim.api.nvim_win_get_buf(winid) ~= winbuf then
|
|
return
|
|
end
|
|
vim.api.nvim_win_set_config(winid, {
|
|
relative = "editor",
|
|
row = win_opts.row,
|
|
col = win_opts.col,
|
|
width = win_opts.width,
|
|
height = win_opts.height,
|
|
title = get_title(),
|
|
})
|
|
end,
|
|
})
|
|
)
|
|
end
|
|
|
|
vim.cmd.edit({ args = { util.escape_filename(parent_url) }, mods = { keepalt = true } })
|
|
-- :edit will set buflisted = true, but we may not want that
|
|
if config.buf_options.buflisted ~= nil then
|
|
vim.api.nvim_set_option_value("buflisted", config.buf_options.buflisted, { buf = 0 })
|
|
end
|
|
|
|
if vim.fn.has("nvim-0.9") == 0 then
|
|
util.add_title_to_win(winid)
|
|
end
|
|
end
|
|
|
|
---Open oil browser in a floating window, or close it if open
|
|
---@param dir nil|string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file
|
|
M.toggle_float = function(dir)
|
|
if vim.w.is_oil_win then
|
|
M.close()
|
|
else
|
|
M.open_float(dir)
|
|
end
|
|
end
|
|
|
|
---@param oil_bufnr? integer
|
|
local function update_preview_window(oil_bufnr)
|
|
oil_bufnr = oil_bufnr or 0
|
|
local util = require("oil.util")
|
|
util.run_after_load(oil_bufnr, function()
|
|
local cursor_entry = M.get_cursor_entry()
|
|
local preview_win_id = util.get_preview_win()
|
|
if
|
|
cursor_entry
|
|
and preview_win_id
|
|
and cursor_entry.id ~= vim.w[preview_win_id].oil_entry_id
|
|
then
|
|
M.open_preview()
|
|
end
|
|
end)
|
|
end
|
|
|
|
---Open oil browser for a directory
|
|
---@param dir nil|string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file
|
|
M.open = function(dir)
|
|
local config = require("oil.config")
|
|
local util = require("oil.util")
|
|
local view = require("oil.view")
|
|
local parent_url, basename = M.get_url_for_path(dir)
|
|
if not parent_url then
|
|
return
|
|
end
|
|
if basename then
|
|
view.set_last_cursor(parent_url, basename)
|
|
end
|
|
vim.cmd.edit({ args = { util.escape_filename(parent_url) }, mods = { keepalt = true } })
|
|
-- :edit will set buflisted = true, but we may not want that
|
|
if config.buf_options.buflisted ~= nil then
|
|
vim.api.nvim_set_option_value("buflisted", config.buf_options.buflisted, { buf = 0 })
|
|
end
|
|
|
|
-- If preview window exists, update its content
|
|
update_preview_window()
|
|
end
|
|
|
|
---Restore the buffer that was present when oil was opened
|
|
M.close = function()
|
|
-- If we're in a floating oil window, close it and try to restore focus to the original window
|
|
if vim.w.is_oil_win then
|
|
local original_winid = vim.w.oil_original_win
|
|
vim.api.nvim_win_close(0, true)
|
|
if original_winid and vim.api.nvim_win_is_valid(original_winid) then
|
|
vim.api.nvim_set_current_win(original_winid)
|
|
end
|
|
return
|
|
end
|
|
local ok, bufnr = pcall(vim.api.nvim_win_get_var, 0, "oil_original_buffer")
|
|
if ok and vim.api.nvim_buf_is_valid(bufnr) then
|
|
vim.api.nvim_win_set_buf(0, bufnr)
|
|
if vim.w.oil_original_view then
|
|
vim.fn.winrestview(vim.w.oil_original_view)
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Deleting the buffer closes all windows with that buffer open, so navigate to a different
|
|
-- buffer first
|
|
local oilbuf = vim.api.nvim_get_current_buf()
|
|
ok = pcall(vim.cmd.bprev)
|
|
if not ok then
|
|
-- If `bprev` failed, there are no buffers open so we should create a new one with enew
|
|
vim.cmd.enew()
|
|
end
|
|
vim.api.nvim_buf_delete(oilbuf, { force = true })
|
|
end
|
|
|
|
---Preview the entry under the cursor in a split
|
|
---@param opts nil|table
|
|
--- vertical boolean Open the buffer in a vertical split
|
|
--- horizontal boolean Open the buffer in a horizontal split
|
|
--- split "aboveleft"|"belowright"|"topleft"|"botright" Split modifier
|
|
M.open_preview = function(opts, callback)
|
|
opts = opts or {}
|
|
local util = require("oil.util")
|
|
|
|
local function finish(err)
|
|
if err then
|
|
vim.notify(err, vim.log.levels.ERROR)
|
|
end
|
|
if callback then
|
|
callback(err)
|
|
end
|
|
end
|
|
|
|
if not opts.horizontal and opts.vertical == nil then
|
|
opts.vertical = true
|
|
end
|
|
if not opts.split then
|
|
if opts.horizontal then
|
|
opts.split = vim.o.splitbelow and "belowright" or "aboveleft"
|
|
else
|
|
opts.split = vim.o.splitright and "belowright" or "aboveleft"
|
|
end
|
|
end
|
|
if util.is_floating_win() then
|
|
return finish("oil preview doesn't work in a floating window")
|
|
end
|
|
|
|
local entry = M.get_cursor_entry()
|
|
if not entry then
|
|
return finish("Could not find entry under cursor")
|
|
end
|
|
|
|
local preview_win = util.get_preview_win()
|
|
local prev_win = vim.api.nvim_get_current_win()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
|
|
local cmd = preview_win and "buffer" or "sbuffer"
|
|
local mods = {
|
|
vertical = opts.vertical,
|
|
horizontal = opts.horizontal,
|
|
split = opts.split,
|
|
}
|
|
|
|
local is_visual_mode = util.is_visual_mode()
|
|
-- HACK Switching windows takes us out of visual mode.
|
|
-- Switching with nvim_set_current_win causes the previous visual selection (as used by `gv`) to
|
|
-- not get set properly. So we have to switch windows this way instead.
|
|
local hack_set_win = function(winid)
|
|
local winnr = vim.api.nvim_win_get_number(winid)
|
|
vim.cmd.wincmd({ args = { "w" }, count = winnr })
|
|
end
|
|
|
|
if preview_win then
|
|
if is_visual_mode then
|
|
hack_set_win(preview_win)
|
|
else
|
|
vim.api.nvim_set_current_win(preview_win)
|
|
end
|
|
end
|
|
|
|
util.get_edit_path(bufnr, entry, function(normalized_url)
|
|
local filebufnr = vim.fn.bufadd(normalized_url)
|
|
local entry_is_file = not vim.endswith(normalized_url, "/")
|
|
|
|
-- If we're previewing a file that hasn't been opened yet, make sure it gets deleted after
|
|
-- we close the window
|
|
if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then
|
|
vim.bo[filebufnr].bufhidden = "wipe"
|
|
vim.b[filebufnr].oil_preview_buffer = true
|
|
end
|
|
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
local ok, err = pcall(vim.cmd, {
|
|
cmd = cmd,
|
|
args = { filebufnr },
|
|
mods = mods,
|
|
})
|
|
-- Ignore swapfile errors
|
|
if not ok and err and not err:match("^Vim:E325:") then
|
|
vim.api.nvim_echo({ { err, "Error" } }, true, {})
|
|
end
|
|
|
|
vim.api.nvim_set_option_value("previewwindow", true, { scope = "local", win = 0 })
|
|
vim.w.oil_entry_id = entry.id
|
|
vim.w.oil_source_win = prev_win
|
|
if is_visual_mode then
|
|
hack_set_win(prev_win)
|
|
-- Restore the visual selection
|
|
vim.cmd.normal({ args = { "gv" }, bang = true })
|
|
else
|
|
vim.api.nvim_set_current_win(prev_win)
|
|
end
|
|
finish()
|
|
end)
|
|
end
|
|
|
|
---@class (exact) oil.SelectOpts
|
|
---@field vertical? boolean Open the buffer in a vertical split
|
|
---@field horizontal? boolean Open the buffer in a horizontal split
|
|
---@field split? "aboveleft"|"belowright"|"topleft"|"botright" Split modifier
|
|
---@field tab? boolean Open the buffer in a new tab
|
|
---@field close? boolean Close the original oil buffer once selection is made
|
|
|
|
---Select the entry under the cursor
|
|
---@param opts nil|oil.SelectOpts
|
|
---@param callback nil|fun(err: nil|string) Called once all entries have been opened
|
|
M.select = function(opts, callback)
|
|
local cache = require("oil.cache")
|
|
local config = require("oil.config")
|
|
local constants = require("oil.constants")
|
|
local util = require("oil.util")
|
|
local FIELD_META = constants.FIELD_META
|
|
opts = vim.tbl_extend("keep", opts or {}, {})
|
|
|
|
if opts.preview then
|
|
vim.notify_once(
|
|
"Deprecated: do not call oil.select with preview=true. Use oil.open_preview instead.\nThis shim will be removed on 2025-01-01"
|
|
)
|
|
M.open_preview(opts, callback)
|
|
return
|
|
end
|
|
|
|
local function finish(err)
|
|
if err then
|
|
vim.notify(err, vim.log.levels.ERROR)
|
|
end
|
|
if callback then
|
|
callback(err)
|
|
end
|
|
end
|
|
if not opts.split and (opts.horizontal or opts.vertical) then
|
|
if opts.horizontal then
|
|
opts.split = vim.o.splitbelow and "belowright" or "aboveleft"
|
|
else
|
|
opts.split = vim.o.splitright and "belowright" or "aboveleft"
|
|
end
|
|
end
|
|
if opts.tab and opts.split then
|
|
return finish("Cannot use split=true when tab = true")
|
|
end
|
|
local adapter = util.get_adapter(0)
|
|
if not adapter then
|
|
return finish("Not an oil buffer")
|
|
end
|
|
|
|
local visual_range = util.get_visual_range()
|
|
|
|
---@type oil.Entry[]
|
|
local entries = {}
|
|
if visual_range then
|
|
for i = visual_range.start_lnum, visual_range.end_lnum do
|
|
local entry = M.get_entry_on_line(0, i)
|
|
if entry then
|
|
table.insert(entries, entry)
|
|
end
|
|
end
|
|
else
|
|
local entry = M.get_cursor_entry()
|
|
if entry then
|
|
table.insert(entries, entry)
|
|
end
|
|
end
|
|
if vim.tbl_isempty(entries) then
|
|
return finish("Could not find entry under cursor")
|
|
end
|
|
|
|
-- Check if any of these entries are moved from their original location
|
|
local bufname = vim.api.nvim_buf_get_name(0)
|
|
local any_moved = false
|
|
for _, entry in ipairs(entries) do
|
|
-- Ignore entries with ID 0 (typically the "../" entry)
|
|
if entry.id ~= 0 then
|
|
local is_new_entry = entry.id == nil
|
|
local is_moved_from_dir = entry.id and cache.get_parent_url(entry.id) ~= bufname
|
|
local is_renamed = entry.parsed_name ~= entry.name
|
|
local internal_entry = entry.id and cache.get_entry_by_id(entry.id)
|
|
if internal_entry then
|
|
local meta = internal_entry[FIELD_META]
|
|
if meta and meta.display_name then
|
|
is_renamed = entry.parsed_name ~= meta.display_name
|
|
end
|
|
end
|
|
if is_new_entry or is_moved_from_dir or is_renamed then
|
|
any_moved = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if any_moved and config.prompt_save_on_select_new_entry then
|
|
local ok, choice = pcall(vim.fn.confirm, "Save changes?", "Yes\nNo", 1)
|
|
if not ok then
|
|
return finish()
|
|
elseif choice == 1 then
|
|
M.save()
|
|
return finish()
|
|
end
|
|
end
|
|
|
|
local prev_win = vim.api.nvim_get_current_win()
|
|
local oil_bufnr = vim.api.nvim_get_current_buf()
|
|
|
|
-- Async iter over entries so we can normalize the url before opening
|
|
local i = 1
|
|
local function open_next_entry(cb)
|
|
local entry = entries[i]
|
|
i = i + 1
|
|
if not entry then
|
|
return cb()
|
|
end
|
|
if util.is_directory(entry) then
|
|
-- If this is a new directory BUT we think we already have an entry with this name, disallow
|
|
-- entry. This prevents the case of MOVE /foo -> /bar + CREATE /foo.
|
|
-- If you enter the new /foo, it will show the contents of the old /foo.
|
|
if not entry.id and cache.list_url(bufname)[entry.name] then
|
|
return cb("Please save changes before entering new directory")
|
|
end
|
|
else
|
|
-- Close floating window before opening a file
|
|
if vim.w.is_oil_win then
|
|
vim.api.nvim_win_close(0, false)
|
|
end
|
|
end
|
|
|
|
-- Normalize the url before opening to prevent needing to rename them inside the BufReadCmd
|
|
-- Renaming buffers during opening can lead to missed autocmds
|
|
util.get_edit_path(oil_bufnr, entry, function(normalized_url)
|
|
local mods = {
|
|
vertical = opts.vertical,
|
|
horizontal = opts.horizontal,
|
|
split = opts.split,
|
|
keepalt = true,
|
|
}
|
|
local filebufnr = vim.fn.bufadd(normalized_url)
|
|
local entry_is_file = not vim.endswith(normalized_url, "/")
|
|
|
|
-- The :buffer command doesn't set buflisted=true
|
|
-- So do that for normal files or for oil dirs if config set buflisted=true
|
|
if entry_is_file or config.buf_options.buflisted then
|
|
vim.bo[filebufnr].buflisted = true
|
|
end
|
|
|
|
local cmd = "buffer"
|
|
if opts.tab then
|
|
vim.cmd.tabnew({ mods = mods })
|
|
elseif opts.split then
|
|
cmd = "sbuffer"
|
|
end
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
local ok, err = pcall(vim.cmd, {
|
|
cmd = cmd,
|
|
args = { filebufnr },
|
|
mods = mods,
|
|
})
|
|
-- Ignore swapfile errors
|
|
if not ok and err and not err:match("^Vim:E325:") then
|
|
vim.api.nvim_echo({ { err, "Error" } }, true, {})
|
|
end
|
|
|
|
open_next_entry(cb)
|
|
end)
|
|
end
|
|
|
|
open_next_entry(function(err)
|
|
if err then
|
|
return finish(err)
|
|
end
|
|
if
|
|
opts.close
|
|
and vim.api.nvim_win_is_valid(prev_win)
|
|
and prev_win ~= vim.api.nvim_get_current_win()
|
|
then
|
|
vim.api.nvim_win_call(prev_win, function()
|
|
M.close()
|
|
end)
|
|
end
|
|
|
|
update_preview_window()
|
|
|
|
finish()
|
|
end)
|
|
end
|
|
|
|
---@param bufnr integer
|
|
---@return boolean
|
|
local function maybe_hijack_directory_buffer(bufnr)
|
|
local config = require("oil.config")
|
|
local fs = require("oil.fs")
|
|
local util = require("oil.util")
|
|
if not config.default_file_explorer then
|
|
return false
|
|
end
|
|
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
|
if bufname == "" then
|
|
return false
|
|
end
|
|
if util.parse_url(bufname) or vim.fn.isdirectory(bufname) == 0 then
|
|
return false
|
|
end
|
|
local new_name = util.addslash(
|
|
config.adapter_to_scheme.files .. fs.os_to_posix_path(vim.fn.fnamemodify(bufname, ":p"))
|
|
)
|
|
local replaced = util.rename_buffer(bufnr, new_name)
|
|
return not replaced
|
|
end
|
|
|
|
---@private
|
|
M._get_highlights = function()
|
|
return {
|
|
{
|
|
name = "OilDir",
|
|
link = "Directory",
|
|
desc = "Directory names in an oil buffer",
|
|
},
|
|
{
|
|
name = "OilDirIcon",
|
|
link = "OilDir",
|
|
desc = "Icon for directories",
|
|
},
|
|
{
|
|
name = "OilSocket",
|
|
link = "Keyword",
|
|
desc = "Socket files in an oil buffer",
|
|
},
|
|
{
|
|
name = "OilLink",
|
|
link = nil,
|
|
desc = "Soft links in an oil buffer",
|
|
},
|
|
{
|
|
name = "OilLinkTarget",
|
|
link = "Comment",
|
|
desc = "The target of a soft link",
|
|
},
|
|
{
|
|
name = "OilFile",
|
|
link = nil,
|
|
desc = "Normal files in an oil buffer",
|
|
},
|
|
{
|
|
name = "OilCreate",
|
|
link = "DiagnosticInfo",
|
|
desc = "Create action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilDelete",
|
|
link = "DiagnosticError",
|
|
desc = "Delete action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilMove",
|
|
link = "DiagnosticWarn",
|
|
desc = "Move action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilCopy",
|
|
link = "DiagnosticHint",
|
|
desc = "Copy action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilChange",
|
|
link = "Special",
|
|
desc = "Change action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilRestore",
|
|
link = "OilCreate",
|
|
desc = "Restore (from the trash) action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilPurge",
|
|
link = "OilDelete",
|
|
desc = "Purge (Permanently delete a file from trash) action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilTrash",
|
|
link = "OilDelete",
|
|
desc = "Trash (delete a file to trash) action in the oil preview window",
|
|
},
|
|
{
|
|
name = "OilTrashSourcePath",
|
|
link = "Comment",
|
|
desc = "Virtual text that shows the original path of file in the trash",
|
|
},
|
|
}
|
|
end
|
|
|
|
local function set_colors()
|
|
for _, conf in ipairs(M._get_highlights()) do
|
|
if conf.link then
|
|
vim.api.nvim_set_hl(0, conf.name, { default = true, link = conf.link })
|
|
end
|
|
end
|
|
-- TODO can remove this call once we drop support for Neovim 0.8. FloatTitle was introduced as a
|
|
-- built-in highlight group in 0.9, and we can start to rely on colorschemes setting it.
|
|
---@diagnostic disable-next-line: deprecated
|
|
if vim.fn.has("nvim-0.9") == 0 and not pcall(vim.api.nvim_get_hl_by_name, "FloatTitle", true) then
|
|
---@diagnostic disable-next-line: deprecated
|
|
local border = vim.api.nvim_get_hl_by_name("FloatBorder", true)
|
|
---@diagnostic disable-next-line: deprecated
|
|
local normal = vim.api.nvim_get_hl_by_name("Normal", true)
|
|
vim.api.nvim_set_hl(
|
|
0,
|
|
"FloatTitle",
|
|
{ fg = normal.foreground, bg = border.background or normal.background }
|
|
)
|
|
end
|
|
end
|
|
|
|
---Save all changes
|
|
---@param opts nil|table
|
|
--- confirm nil|boolean Show confirmation when true, never when false, respect skip_confirm_for_simple_edits if nil
|
|
---@param cb? fun(err: nil|string) Called when mutations complete.
|
|
---@note
|
|
--- If you provide your own callback function, there will be no notification for errors.
|
|
M.save = function(opts, cb)
|
|
opts = opts or {}
|
|
if not cb then
|
|
cb = function(err)
|
|
if err and err ~= "Canceled" then
|
|
vim.notify(err, vim.log.levels.ERROR)
|
|
end
|
|
end
|
|
end
|
|
local mutator = require("oil.mutator")
|
|
mutator.try_write_changes(opts.confirm, cb)
|
|
end
|
|
|
|
local function restore_alt_buf()
|
|
if vim.bo.filetype == "oil" then
|
|
require("oil.view").set_win_options()
|
|
vim.api.nvim_win_set_var(0, "oil_did_enter", true)
|
|
elseif vim.w.oil_did_enter then
|
|
vim.api.nvim_win_del_var(0, "oil_did_enter")
|
|
-- We are entering a non-oil buffer *after* having been in an oil buffer
|
|
local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, "oil_original_buffer")
|
|
if has_orig and vim.api.nvim_buf_is_valid(orig_buffer) then
|
|
if vim.api.nvim_get_current_buf() ~= orig_buffer then
|
|
-- If we are editing a new file after navigating around oil, set the alternate buffer
|
|
-- to be the last buffer we were in before opening oil
|
|
vim.fn.setreg("#", orig_buffer)
|
|
else
|
|
-- If we are editing the same buffer that we started oil from, set the alternate to be
|
|
-- what it was before we opened oil
|
|
local has_orig_alt, alt_buffer =
|
|
pcall(vim.api.nvim_win_get_var, 0, "oil_original_alternate")
|
|
if has_orig_alt and vim.api.nvim_buf_is_valid(alt_buffer) then
|
|
vim.fn.setreg("#", alt_buffer)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
---@param bufnr integer
|
|
local function load_oil_buffer(bufnr)
|
|
local config = require("oil.config")
|
|
local keymap_util = require("oil.keymap_util")
|
|
local loading = require("oil.loading")
|
|
local util = require("oil.util")
|
|
local view = require("oil.view")
|
|
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
|
local scheme, path = util.parse_url(bufname)
|
|
if config.adapter_aliases[scheme] then
|
|
scheme = config.adapter_aliases[scheme]
|
|
bufname = scheme .. path
|
|
util.rename_buffer(bufnr, bufname)
|
|
end
|
|
|
|
local adapter = assert(config.get_adapter_by_scheme(scheme))
|
|
|
|
if vim.endswith(bufname, "/") then
|
|
-- This is a small quality-of-life thing. If the buffer name ends with a `/`, we know it's a
|
|
-- directory, and can set the filetype early. This is helpful for adapters with a lot of latency
|
|
-- (e.g. ssh) because it will set up the filetype keybinds at the *beginning* of the loading
|
|
-- process.
|
|
vim.bo[bufnr].filetype = "oil"
|
|
keymap_util.set_keymaps(config.keymaps, bufnr)
|
|
end
|
|
loading.set_loading(bufnr, true)
|
|
local winid = vim.api.nvim_get_current_win()
|
|
local function finish(new_url)
|
|
-- If the buffer was deleted while we were normalizing the name, early return
|
|
if not vim.api.nvim_buf_is_valid(bufnr) then
|
|
return
|
|
end
|
|
-- Since this was async, we may have left the window with this buffer. People often write
|
|
-- BufReadPre/Post autocmds with the expectation that the current window is the one that
|
|
-- contains the buffer. Let's then do our best to make sure that that assumption isn't violated.
|
|
winid = util.buf_get_win(bufnr, winid) or vim.api.nvim_get_current_win()
|
|
vim.api.nvim_win_call(winid, function()
|
|
if new_url ~= bufname then
|
|
if util.rename_buffer(bufnr, new_url) then
|
|
-- If the buffer was replaced then don't initialize it. It's dead. The replacement will
|
|
-- have BufReadCmd called for it
|
|
return
|
|
end
|
|
|
|
-- If the renamed buffer doesn't have a scheme anymore, this is a normal file.
|
|
-- Finish setting it up as a normal buffer.
|
|
local new_scheme = util.parse_url(new_url)
|
|
if not new_scheme then
|
|
loading.set_loading(bufnr, false)
|
|
vim.cmd.doautocmd({ args = { "BufReadPre", new_url }, mods = { emsg_silent = true } })
|
|
vim.cmd.doautocmd({ args = { "BufReadPost", new_url }, mods = { emsg_silent = true } })
|
|
return
|
|
end
|
|
|
|
bufname = new_url
|
|
end
|
|
if vim.endswith(bufname, "/") then
|
|
vim.cmd.doautocmd({ args = { "BufReadPre", bufname }, mods = { emsg_silent = true } })
|
|
view.initialize(bufnr)
|
|
vim.cmd.doautocmd({ args = { "BufReadPost", bufname }, mods = { emsg_silent = true } })
|
|
else
|
|
vim.bo[bufnr].buftype = "acwrite"
|
|
adapter.read_file(bufnr)
|
|
end
|
|
restore_alt_buf()
|
|
end)
|
|
end
|
|
|
|
adapter.normalize_url(bufname, finish)
|
|
end
|
|
|
|
local function close_preview_window_if_not_in_oil()
|
|
local util = require("oil.util")
|
|
local preview_win_id = util.get_preview_win()
|
|
if not preview_win_id or not vim.w[preview_win_id].oil_entry_id then
|
|
return
|
|
end
|
|
|
|
local oil_source_win = vim.w[preview_win_id].oil_source_win
|
|
if oil_source_win and vim.api.nvim_win_is_valid(oil_source_win) then
|
|
local src_buf = vim.api.nvim_win_get_buf(oil_source_win)
|
|
if util.is_oil_bufnr(src_buf) then
|
|
return
|
|
end
|
|
end
|
|
|
|
-- This can fail if it's the last window open
|
|
pcall(vim.api.nvim_win_close, preview_win_id, true)
|
|
end
|
|
|
|
local _on_key_ns = 0
|
|
---Initialize oil
|
|
---@param opts oil.setupOpts|nil
|
|
M.setup = function(opts)
|
|
local Ringbuf = require("oil.ringbuf")
|
|
local config = require("oil.config")
|
|
|
|
config.setup(opts)
|
|
set_colors()
|
|
vim.api.nvim_create_user_command("Oil", function(args)
|
|
local util = require("oil.util")
|
|
if args.smods.tab == 1 then
|
|
vim.cmd.tabnew()
|
|
end
|
|
local float = false
|
|
local trash = false
|
|
local i = 1
|
|
while i <= #args.fargs do
|
|
local v = args.fargs[i]
|
|
if v == "--float" then
|
|
float = true
|
|
table.remove(args.fargs, i)
|
|
elseif v == "--trash" then
|
|
trash = true
|
|
table.remove(args.fargs, i)
|
|
elseif v == "--progress" then
|
|
local mutator = require("oil.mutator")
|
|
if mutator.is_mutating() then
|
|
mutator.show_progress()
|
|
else
|
|
vim.notify("No mutation in progress", vim.log.levels.WARN)
|
|
end
|
|
return
|
|
else
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
if not float and (args.smods.vertical or args.smods.split ~= "") then
|
|
if args.smods.vertical then
|
|
vim.cmd.vsplit({ mods = { split = args.smods.split } })
|
|
else
|
|
vim.cmd.split({ mods = { split = args.smods.split } })
|
|
end
|
|
end
|
|
|
|
local method = float and "open_float" or "open"
|
|
local path = args.fargs[1]
|
|
if trash then
|
|
local url = M.get_url_for_path(path, false)
|
|
local _, new_path = util.parse_url(url)
|
|
path = "oil-trash://" .. new_path
|
|
end
|
|
M[method](path)
|
|
end, { desc = "Open oil file browser on a directory", nargs = "*", complete = "dir" })
|
|
local aug = vim.api.nvim_create_augroup("Oil", {})
|
|
|
|
if config.default_file_explorer then
|
|
vim.g.loaded_netrw = 1
|
|
vim.g.loaded_netrwPlugin = 1
|
|
-- If netrw was already loaded, clear this augroup
|
|
if vim.fn.exists("#FileExplorer") then
|
|
vim.api.nvim_create_augroup("FileExplorer", { clear = true })
|
|
end
|
|
end
|
|
|
|
local patterns = {}
|
|
local filetype_patterns = {}
|
|
for scheme in pairs(config.adapters) do
|
|
table.insert(patterns, scheme .. "*")
|
|
filetype_patterns[scheme .. ".*"] = { "oil", { priority = 10 } }
|
|
end
|
|
for scheme in pairs(config.adapter_aliases) do
|
|
table.insert(patterns, scheme .. "*")
|
|
filetype_patterns[scheme .. ".*"] = { "oil", { priority = 10 } }
|
|
end
|
|
local scheme_pattern = table.concat(patterns, ",")
|
|
-- We need to add these patterns to the filetype matcher so the filetype doesn't get overridden
|
|
-- by other patterns. See https://github.com/stevearc/oil.nvim/issues/47
|
|
vim.filetype.add({
|
|
pattern = filetype_patterns,
|
|
})
|
|
|
|
local keybuf = Ringbuf.new(7)
|
|
if _on_key_ns == 0 then
|
|
_on_key_ns = vim.on_key(function(char)
|
|
keybuf:push(char)
|
|
end, _on_key_ns)
|
|
end
|
|
vim.api.nvim_create_autocmd("ColorScheme", {
|
|
desc = "Set default oil highlights",
|
|
group = aug,
|
|
pattern = "*",
|
|
callback = set_colors,
|
|
})
|
|
vim.api.nvim_create_autocmd("BufReadCmd", {
|
|
group = aug,
|
|
pattern = scheme_pattern,
|
|
nested = true,
|
|
callback = function(params)
|
|
load_oil_buffer(params.buf)
|
|
end,
|
|
})
|
|
vim.api.nvim_create_autocmd("BufWriteCmd", {
|
|
group = aug,
|
|
pattern = scheme_pattern,
|
|
nested = true,
|
|
callback = function(params)
|
|
local last_keys = keybuf:as_str()
|
|
local winid = vim.api.nvim_get_current_win()
|
|
-- If the user issued a :wq or similar, we should quit after saving
|
|
local quit_after_save = vim.endswith(last_keys, ":wq\r")
|
|
or vim.endswith(last_keys, ":x\r")
|
|
or vim.endswith(last_keys, "ZZ")
|
|
local quit_all = vim.endswith(last_keys, ":wqa\r")
|
|
or vim.endswith(last_keys, ":wqal\r")
|
|
or vim.endswith(last_keys, ":wqall\r")
|
|
local bufname = vim.api.nvim_buf_get_name(params.buf)
|
|
if vim.endswith(bufname, "/") then
|
|
vim.cmd.doautocmd({ args = { "BufWritePre", params.file }, mods = { silent = true } })
|
|
M.save(nil, function(err)
|
|
if err then
|
|
if err ~= "Canceled" then
|
|
vim.notify(err, vim.log.levels.ERROR)
|
|
end
|
|
elseif winid == vim.api.nvim_get_current_win() then
|
|
if quit_after_save then
|
|
vim.cmd.quit()
|
|
elseif quit_all then
|
|
vim.cmd.quitall()
|
|
end
|
|
end
|
|
end)
|
|
vim.cmd.doautocmd({ args = { "BufWritePost", params.file }, mods = { silent = true } })
|
|
else
|
|
local adapter = config.get_adapter_by_scheme(bufname)
|
|
assert(adapter)
|
|
adapter.write_file(params.buf)
|
|
end
|
|
end,
|
|
})
|
|
vim.api.nvim_create_autocmd("BufLeave", {
|
|
desc = "Save alternate buffer for later",
|
|
group = aug,
|
|
pattern = "*",
|
|
callback = function()
|
|
local util = require("oil.util")
|
|
if not util.is_oil_bufnr(0) then
|
|
vim.w.oil_original_buffer = vim.api.nvim_get_current_buf()
|
|
vim.w.oil_original_view = vim.fn.winsaveview()
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
vim.w.oil_original_alternate = vim.fn.bufnr("#")
|
|
end
|
|
end,
|
|
})
|
|
vim.api.nvim_create_autocmd("BufEnter", {
|
|
desc = "Set/unset oil window options and restore alternate buffer",
|
|
group = aug,
|
|
pattern = "*",
|
|
callback = function()
|
|
local util = require("oil.util")
|
|
local bufname = vim.api.nvim_buf_get_name(0)
|
|
local scheme = util.parse_url(bufname)
|
|
if scheme and config.adapters[scheme] then
|
|
local view = require("oil.view")
|
|
view.maybe_set_cursor()
|
|
-- While we are in an oil buffer, set the alternate file to the buffer we were in prior to
|
|
-- opening oil
|
|
local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, "oil_original_buffer")
|
|
if has_orig and vim.api.nvim_buf_is_valid(orig_buffer) then
|
|
vim.fn.setreg("#", orig_buffer)
|
|
end
|
|
view.set_win_options()
|
|
vim.w.oil_did_enter = true
|
|
elseif vim.fn.isdirectory(bufname) == 0 then
|
|
-- Only run this logic if we are *not* in an oil buffer (and it's not a directory, which
|
|
-- will be replaced by an oil:// url)
|
|
-- Oil buffers have to run it in BufReadCmd after confirming they are a directory or a file
|
|
restore_alt_buf()
|
|
end
|
|
|
|
close_preview_window_if_not_in_oil()
|
|
end,
|
|
})
|
|
|
|
vim.api.nvim_create_autocmd({ "BufWinEnter", "WinNew", "WinEnter" }, {
|
|
desc = "Reset bufhidden when entering a preview buffer",
|
|
group = aug,
|
|
pattern = "*",
|
|
callback = function()
|
|
-- If we have entered a "preview" buffer in a non-preview window, reset bufhidden
|
|
if vim.b.oil_preview_buffer and not vim.wo.previewwindow then
|
|
vim.bo.bufhidden = vim.api.nvim_get_option_value("bufhidden", { scope = "global" })
|
|
vim.b.oil_preview_buffer = nil
|
|
end
|
|
end,
|
|
})
|
|
if not config.silence_scp_warning then
|
|
vim.api.nvim_create_autocmd("BufNew", {
|
|
desc = "Warn about scp:// usage",
|
|
group = aug,
|
|
pattern = "scp://*",
|
|
once = true,
|
|
callback = function()
|
|
vim.notify(
|
|
"If you are trying to browse using Oil, use oil-ssh:// instead of scp://\nSet `silence_scp_warning = true` in oil.setup() to disable this message.\nSee https://github.com/stevearc/oil.nvim/issues/27 for more information.",
|
|
vim.log.levels.WARN
|
|
)
|
|
end,
|
|
})
|
|
end
|
|
vim.api.nvim_create_autocmd("WinNew", {
|
|
desc = "Restore window options when splitting an oil window",
|
|
group = aug,
|
|
pattern = "*",
|
|
nested = true,
|
|
callback = function(params)
|
|
local util = require("oil.util")
|
|
if not util.is_oil_bufnr(params.buf) or vim.w.oil_did_enter then
|
|
return
|
|
end
|
|
-- This new window is a split off of an oil window. We need to transfer the window
|
|
-- variables. First, locate the parent window
|
|
local parent_win
|
|
-- First search windows in this tab, then search all windows
|
|
local winids = vim.list_extend(vim.api.nvim_tabpage_list_wins(0), vim.api.nvim_list_wins())
|
|
for _, winid in ipairs(winids) do
|
|
if vim.api.nvim_win_is_valid(winid) then
|
|
if vim.w[winid].oil_did_enter then
|
|
parent_win = winid
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if not parent_win then
|
|
vim.notify(
|
|
"Oil split could not find parent window. Please try to replicate whatever you just did and report a bug on github",
|
|
vim.log.levels.WARN
|
|
)
|
|
return
|
|
end
|
|
|
|
-- Then transfer over the relevant window vars
|
|
vim.w.oil_did_enter = true
|
|
vim.w.oil_original_buffer = vim.w[parent_win].oil_original_buffer
|
|
vim.w.oil_original_view = vim.w[parent_win].oil_original_view
|
|
vim.w.oil_original_alternate = vim.w[parent_win].oil_original_alternate
|
|
end,
|
|
})
|
|
vim.api.nvim_create_autocmd("BufAdd", {
|
|
desc = "Detect directory buffer and open oil file browser",
|
|
group = aug,
|
|
pattern = "*",
|
|
nested = true,
|
|
callback = function(params)
|
|
maybe_hijack_directory_buffer(params.buf)
|
|
end,
|
|
})
|
|
-- mksession doesn't save oil buffers in a useful way. We have to manually load them after a
|
|
-- session finishes loading. See https://github.com/stevearc/oil.nvim/issues/29
|
|
vim.api.nvim_create_autocmd("SessionLoadPost", {
|
|
desc = "Load oil buffers after a session is loaded",
|
|
group = aug,
|
|
pattern = "*",
|
|
callback = function(params)
|
|
if vim.g.SessionLoad ~= 1 then
|
|
return
|
|
end
|
|
local util = require("oil.util")
|
|
local scheme = util.parse_url(params.file)
|
|
if config.adapters[scheme] and vim.api.nvim_buf_line_count(params.buf) == 1 then
|
|
load_oil_buffer(params.buf)
|
|
end
|
|
end,
|
|
})
|
|
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
if maybe_hijack_directory_buffer(bufnr) and vim.v.vim_did_enter == 1 then
|
|
-- manually call load on a hijacked directory buffer if vim has already entered
|
|
-- (the BufReadCmd will not trigger)
|
|
load_oil_buffer(bufnr)
|
|
end
|
|
end
|
|
|
|
return M
|