snailed
/
taolf
Archived
2
0
Fork 0

feature(focus_on_open): focus current file when opening lf; refactor(cfg)

This commit is contained in:
Lucas Burns 2022-05-29 15:25:18 -05:00
parent 242912c016
commit a6154bd87c
No known key found for this signature in database
GPG Key ID: C011CBEF6628B679
5 changed files with 148 additions and 101 deletions

View File

@ -54,6 +54,7 @@ require("lf").setup({
height = 0.80, -- height of the *floating* window height = 0.80, -- height of the *floating* window
width = 0.85, -- width of the *floating* window width = 0.85, -- width of the *floating* window
escape_quit = true, -- map escape to the quit command (so it doesn't go into a meta normal mode) escape_quit = true, -- map escape to the quit command (so it doesn't go into a meta normal mode)
focus_on_open = false, -- focus the current file when opening Lf (experimental)
mappings = true, -- whether terminal buffer mapping is enabled mappings = true, -- whether terminal buffer mapping is enabled
tmux = false, -- tmux statusline can be disabled on opening of Lf tmux = false, -- tmux statusline can be disabled on opening of Lf
highlights = { -- highlights passed to toggleterm highlights = { -- highlights passed to toggleterm

View File

@ -26,6 +26,7 @@ end
---@param path string optional path to start in ---@param path string optional path to start in
function M.start(path, cfg) function M.start(path, cfg)
-- Only one argument was given -- Only one argument was given
if path and cfg == nil and type(path) == "table" then if path and cfg == nil and type(path) == "table" then
require("lf.main").Lf:new(path or M._cfg):start(nil) require("lf.main").Lf:new(path or M._cfg):start(nil)
else else

View File

@ -9,6 +9,7 @@
--- @field height number: height of the *floating* window --- @field height number: height of the *floating* window
--- @field width number: width of the *floating* window --- @field width number: width of the *floating* window
--- @field escape_quit boolean: whether escape should be mapped to quit --- @field escape_quit boolean: whether escape should be mapped to quit
--- @field focus_on_open boolean: whether Lf should open focused on current file
--- @field mappings boolean: whether terminal buffer mappings should be set --- @field mappings boolean: whether terminal buffer mappings should be set
--- @field tmux boolean: whether tmux statusline should be changed by this plugin --- @field tmux boolean: whether tmux statusline should be changed by this plugin
--- @field highlights table: highlight table to pass to `toggleterm` --- @field highlights table: highlight table to pass to `toggleterm`
@ -43,6 +44,7 @@ local function init()
height = 0.80, height = 0.80,
width = 0.85, width = 0.85,
escape_quit = true, escape_quit = true,
focus_on_open = true,
mappings = true, mappings = true,
tmux = false, tmux = false,
highlights = {}, highlights = {},
@ -56,7 +58,7 @@ local function init()
}, },
{width = 0.800, height = 0.800}, {width = 0.800, height = 0.800},
{width = 0.950, height = 0.950} {width = 0.950, height = 0.950}
}, }
} }
Config = vim.tbl_deep_extend("keep", lf._cfg or {}, opts) Config = vim.tbl_deep_extend("keep", lf._cfg or {}, opts)
@ -67,31 +69,40 @@ init()
-- local notify = require("lf.utils").notify -- local notify = require("lf.utils").notify
---Verify that configuration options that are numbers are numbers or can be converted to numbers
---@param field string | number: `Config` field to check
---@param default number: Default value to return if the conversion failed
function Config:__check_number(field, default)
if type(field) == "string" then
local res = tonumber(field)
return F.if_nil(res, default)
elseif type(field) == "number" then
return field
end
return default
end
---Set a configuration passed as a function argument (not through `setup`) ---Set a configuration passed as a function argument (not through `setup`)
---@param cfg table configuration options ---@param cfg table configuration options
---@return Config ---@return Config
function Config:set(cfg) function Config:set(cfg)
if cfg and type(cfg) == "table" then if cfg and type(cfg) == "table" then
-- TODO: Maybe verify more options in configuration?
cfg.winblend = self:__check_number(cfg.winblend, self.winblend)
cfg.height = self:__check_number(cfg.height, self.height)
cfg.width = self:__check_number(cfg.width, self.width)
self = vim.tbl_deep_extend("force", self, cfg or {}) self = vim.tbl_deep_extend("force", self, cfg or {})
vim.validate(
{
default_cmd = {self.default_cmd, "s", false},
default_action = {self.default_action, "s", false},
default_actions = {self.default_actions, "t", false},
winblend = {self.winblend, {"n", "s"}, false},
dir = {self.dir, "s", false},
direction = {self.direction, "s", false},
border = {self.border, "s", false},
height = {self.height, {"n", "s"}, false},
width = {self.width, {"n", "s"}, false},
escape_quit = {self.escape_quit, "b", false},
focus_on_open = {self.focus_on_open, "b", false},
mappings = {self.mappings, "b", false},
tmux = {self.tmux, "b", false},
highlights = {self.highlights, "t", false},
-- Layout configurations
layout_mapping = {self.layout_mapping, "s", false},
views = {self.views, "t", false}
}
)
-- Just run `tonumber` on all items that can be strings
-- Checking if each one is a string might take longer
self.winblend = tonumber(self.winblend)
self.height = tonumber(self.height)
self.width = tonumber(self.width)
end end
return self return self

View File

@ -30,6 +30,7 @@ local Job = require("plenary.job")
local Config = require("lf.config") local Config = require("lf.config")
local with = require("plenary.context_manager").with local with = require("plenary.context_manager").with
local open = require("plenary.context_manager").open local open = require("plenary.context_manager").open
local a = require("plenary.async_lib")
--- @class Terminal --- @class Terminal
local Terminal = require("toggleterm.terminal").Terminal local Terminal = require("toggleterm.terminal").Terminal
@ -39,9 +40,11 @@ local Terminal = require("toggleterm.terminal").Terminal
--- @field term Terminal Toggle terminal --- @field term Terminal Toggle terminal
--- @field view_idx number Current index of configuration `views` --- @field view_idx number Current index of configuration `views`
--- @field winid number `Terminal` window id --- @field winid number `Terminal` window id
--- @field lf_tmp string File path with the files to open with `lf` --- @field lf_tmpfile string File path with the files to open with `lf`
--- @field lastdir_tmp string File path with the last directory `lf` was in --- @field lastdir_tmpfile string File path with the last directory `lf` was in
--- @field id_tmp string File path to a file containing `lf`'s id --- @field id_tmpfile string File path to a file containing `lf`'s id
--- @field id number Current Lf session id
--- @field curr_file string|nil File path to the currently opened file
--- @field bufnr number The open file's buffer number --- @field bufnr number The open file's buffer number
--- @field signcolumn string The signcolumn set by the user before the terminal buffer overrides it --- @field signcolumn string The signcolumn set by the user before the terminal buffer overrides it
local Lf = {} local Lf = {}
@ -52,9 +55,9 @@ local function setup_term(highlights)
{ {
size = function(term) size = function(term)
if term.direction == "horizontal" then if term.direction == "horizontal" then
return vim.o.lines * 0.4 return o.lines * 0.4
elseif term.direction == "vertical" then elseif term.direction == "vertical" then
return vim.o.columns * 0.5 return o.columns * 0.5
end end
end, end,
hide_numbers = true, hide_numbers = true,
@ -86,9 +89,11 @@ function Lf:new(config)
self.view_idx = 1 self.view_idx = 1
self.winid = nil self.winid = nil
self.id_tmp = nil self.id_tmpfile = nil
self.id = nil
self.curr_file = nil
self.bufnr = api.nvim_get_current_buf() self.bufnr = api.nvim_get_current_buf()
-- Needed to be grabbed here before the terminal buffer is created -- Needs to be grabbed here before the terminal buffer is created
self.signcolumn = o.signcolumn self.signcolumn = o.signcolumn
setup_term(self.cfg.highlights) setup_term(self.cfg.highlights)
@ -109,8 +114,8 @@ function Lf:__create_term()
close_on_exit = true, close_on_exit = true,
float_opts = { float_opts = {
border = self.cfg.border, border = self.cfg.border,
width = math.floor(vim.o.columns * self.cfg.width), width = math.floor(o.columns * self.cfg.width),
height = math.floor(vim.o.lines * self.cfg.height), height = math.floor(o.lines * self.cfg.height),
winblend = self.cfg.winblend, winblend = self.cfg.winblend,
highlights = {border = "Normal", background = "Normal"} highlights = {border = "Normal", background = "Normal"}
} }
@ -143,7 +148,6 @@ function Lf:start(path)
self:__callback(term) self:__callback(term)
end end
-- NOTE: Maybe pcall here?
self.term:toggle() self.term:toggle()
end end
@ -187,6 +191,7 @@ function Lf:__open_in(path)
end end
self.term.dir = path:absolute() self.term.dir = path:absolute()
self.curr_file = fn.expand("%:p")
return self return self
end end
@ -196,24 +201,23 @@ end
--- ---
---@return Lf ---@return Lf
function Lf:__wrapper() function Lf:__wrapper()
self.lf_tmp = os.tmpname() self.lf_tmpfile = os.tmpname()
self.lastdir_tmp = os.tmpname() self.lastdir_tmpfile = os.tmpname()
self.id_tmp = os.tmpname() self.id_tmpfile = os.tmpname()
-- command lf -command '$printf $id > '"$fid"'' -last-dir-path="$tmp" "$@" -- command lf -command '$printf $id > '"$fid"'' -last-dir-path="$tmp" "$@"
self.term.cmd = self.term.cmd =
([[%s -command='$printf $id > %s' -last-dir-path='%s' -selection-path='%s' %s]]):format( ([[%s -command='$printf $id > %s' -last-dir-path='%s' -selection-path='%s' %s]]):format(
self.term.cmd, self.term.cmd,
self.id_tmp, self.id_tmpfile,
self.lastdir_tmp, self.lastdir_tmpfile,
self.lf_tmp, self.lf_tmpfile,
self.term.dir self.term.dir
) )
return self return self
end end
-- TODO: Figure out a way to open the file with these commands
---On open closure to run in the `Terminal` ---On open closure to run in the `Terminal`
---@param term Terminal ---@param term Terminal
function Lf:__on_open(term) function Lf:__on_open(term)
@ -227,6 +231,30 @@ function Lf:__on_open(term)
map("t", "<Esc>", "<Cmd>q<CR>", {buffer = term.bufnr, desc = "Exit Lf"}) map("t", "<Esc>", "<Cmd>q<CR>", {buffer = term.bufnr, desc = "Exit Lf"})
end end
-- This will not work without deferring the function
-- If the module is reloaded via plenary, then re-required and ran it will work
-- However, if the :Lf command is used, reading the value provides a nil value
vim.defer_fn(
function()
if self.cfg.focus_on_open and self.term.dir == fn.fnamemodify(self.curr_file, ":h") then
local f = assert(io.open(self.id_tmpfile, "r"))
local data = f:read("*a")
f:close()
Job:new(
{
command = "lf",
args = {
"-remote",
("send %d select %s"):format(tonumber(data), fn.fnamemodify(self.curr_file, ":t"))
}
}
):start()
end
end,
20
)
for key, mapping in pairs(self.cfg.default_actions) do for key, mapping in pairs(self.cfg.default_actions) do
map( map(
"t", "t",
@ -234,15 +262,20 @@ function Lf:__on_open(term)
function() function()
-- Change default_action for easier reading in the callback -- Change default_action for easier reading in the callback
self.cfg.default_action = mapping self.cfg.default_action = mapping
-- Set it to a `self` variable in case this is to ever be used again
-- FIX: If this is set above, it doesn't seem to work. The value is nil
-- There is only a need to read the file once
-- Also, if this for block is moved into defer_fn, the value remains nil
self.id = self.id =
tonumber(
with( with(
open(self.id_tmp), open(self.id_tmpfile),
function(r) function(r)
return r:read() return r:read()
end end
)
) )
-- self.id_tmp = nil -- self.id_tmpfile = nil
-- Manually tell `lf` to open the current file -- Manually tell `lf` to open the current file
-- since Neovim has hijacked the binding -- since Neovim has hijacked the binding
@ -268,7 +301,7 @@ function Lf:__on_open(term)
function() function()
api.nvim_win_set_config( api.nvim_win_set_config(
self.winid, self.winid,
M.get_view(self.cfg.views[self.view_idx], self.bufnr, self.signcolumn) utils.get_view(self.cfg.views[self.view_idx], self.bufnr, self.signcolumn)
) )
self.view_idx = self.view_idx < #self.cfg.views and self.view_idx + 1 or 1 self.view_idx = self.view_idx < #self.cfg.views and self.view_idx + 1 or 1
end end
@ -285,11 +318,11 @@ function Lf:__callback(term)
utils.tmux(false) utils.tmux(false)
end end
if (self.cfg.default_action == "cd" or self.cfg.default_action == "lcd") and uv.fs_stat(self.lastdir_tmp) then if (self.cfg.default_action == "cd" or self.cfg.default_action == "lcd") and uv.fs_stat(self.lastdir_tmpfile) then
-- Since plenary is already being used, this is used instead of `io` -- Since plenary is already being used, this is used instead of `io`
local last_dir = local last_dir =
with( with(
open(self.lastdir_tmp), open(self.lastdir_tmpfile),
function(r) function(r)
return r:read() return r:read()
end end
@ -299,10 +332,10 @@ function Lf:__callback(term)
vim.cmd(("%s %s"):format(self.cfg.default_action, last_dir)) vim.cmd(("%s %s"):format(self.cfg.default_action, last_dir))
return return
end end
elseif uv.fs_stat(self.lf_tmp) then elseif uv.fs_stat(self.lf_tmpfile) then
local contents = {} local contents = {}
for line in io.lines(self.lf_tmp) do for line in io.lines(self.lf_tmpfile) do
table.insert(contents, line) table.insert(contents, line)
end end
@ -316,59 +349,6 @@ function Lf:__callback(term)
end end
end end
---Simple rounding function
---@param num number number to round
---@return number
function M.round(num)
return math.floor(num + 0.5)
end
---Get Neovim window height
---@return number
function M.height()
return o.lines - o.cmdheight
end
---Get neovim window width (minus signcolumn)
---@param bufnr number Buffer number from the file that Lf is opened from
---@param signcolumn string Signcolumn option set by the user, not the terminal buffer
---@return number
function M.width(bufnr, signcolumn)
-- This is a rough estimate of the signcolumn
local width = #tostring(api.nvim_buf_line_count(bufnr))
local col = vim.split(signcolumn, ":")
if #col == 2 then
width = width + tonumber(col[2])
end
return signcolumn:match("no") and o.columns or o.columns - width
end
---Get the table that is passed to `api.nvim_win_set_config`
---@param opts table
---@param bufnr number Buffer number from the file that Lf is opened from
---@param signcolumn string Signcolumn option set by the user, not the terminal buffer
---@return table
function M.get_view(opts, bufnr, signcolumn)
opts = opts or {}
local width =
opts.width or math.ceil(math.min(M.width(bufnr, signcolumn), math.max(80, M.width(bufnr, signcolumn) - 20)))
local height = opts.height or math.ceil(math.min(M.height(), math.max(20, M.height() - 10)))
width = fn.float2nr(width * M.width(bufnr, signcolumn))
height = fn.float2nr(M.round(height * M.height()))
local col = fn.float2nr(M.round((M.width(bufnr, signcolumn) - width) / 2))
local row = fn.float2nr(M.round((M.height() - height) / 2))
return {
col = col,
row = row,
relative = "editor",
style = "minimal",
width = width,
height = height
}
end
M.Lf = Lf M.Lf = Lf
return M return M

View File

@ -5,6 +5,7 @@ local M = {}
local fn = vim.fn local fn = vim.fn
local api = vim.api local api = vim.api
local levels = vim.log.levels local levels = vim.log.levels
local o = vim.o
---Echo a message with `nvim_echo` ---Echo a message with `nvim_echo`
---@param msg string message ---@param msg string message
@ -91,4 +92,57 @@ M.tmux = function(disable)
end end
end end
---Simple rounding function
---@param num number number to round
---@return number
function M.round(num)
return math.floor(num + 0.5)
end
---Get Neovim window height
---@return number
function M.height()
return o.lines - o.cmdheight
end
---Get neovim window width (minus signcolumn)
---@param bufnr number Buffer number from the file that Lf is opened from
---@param signcolumn string Signcolumn option set by the user, not the terminal buffer
---@return number
function M.width(bufnr, signcolumn)
-- This is a rough estimate of the signcolumn
local width = #tostring(api.nvim_buf_line_count(bufnr))
local col = vim.split(signcolumn, ":")
if #col == 2 then
width = width + tonumber(col[2])
end
return signcolumn:match("no") and o.columns or o.columns - width
end
---Get the table that is passed to `api.nvim_win_set_config`
---@param opts table
---@param bufnr number Buffer number from the file that Lf is opened from
---@param signcolumn string Signcolumn option set by the user, not the terminal buffer
---@return table
function M.get_view(opts, bufnr, signcolumn)
opts = opts or {}
local width =
opts.width or math.ceil(math.min(M.width(bufnr, signcolumn), math.max(80, M.width(bufnr, signcolumn) - 20)))
local height = opts.height or math.ceil(math.min(M.height(), math.max(20, M.height() - 10)))
width = fn.float2nr(width * M.width(bufnr, signcolumn))
height = fn.float2nr(M.round(height * M.height()))
local col = fn.float2nr(M.round((M.width(bufnr, signcolumn) - width) / 2))
local row = fn.float2nr(M.round((M.height() - height) / 2))
return {
col = col,
row = row,
relative = "editor",
style = "minimal",
width = width,
height = height
}
end
return M return M