Skip to content

Commit

Permalink
fix: path containing space (#250)
Browse files Browse the repository at this point in the history
* lint: file explorer context

* break: move alt-left, alt-right to alt-h, alt-l

* test

* fix: path containing whitespace

* doc: wording

* fix: trim spaces

* WIP

* fix: string_find

* test: string_find

* fix: remove string_rfind

* fix: Mode

* fix: typecheck

* fix: Mode

* fix: echo

* fix: err

* test

* test

* test
  • Loading branch information
linrongbin16 authored Oct 8, 2023
1 parent cf701e8 commit 8fd2bc6
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 90 deletions.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Hi, thanks to your contribute, while please finish below tasks:
Thanks to your contribute, while please finish below tasks:

# Regresion test

Expand Down
235 changes: 176 additions & 59 deletions lua/fzfx/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -555,10 +555,11 @@ end

-- file explorer {

--- @alias FileExplorerPipelineContext {bufnr:integer,winnr:integer,tabnr:integer,cwd:string}
--- @return FileExplorerPipelineContext
local function file_explorer_context_maker()
local temp = vim.fn.tempname()
utils.writefile(temp, vim.fn.getcwd())
--- @type PipelineContext
local context = {
bufnr = vim.api.nvim_get_current_buf(),
winnr = vim.api.nvim_get_current_win(),
Expand All @@ -572,13 +573,12 @@ end
--- @return fun(query:string,context:PipelineContext):string?
local function make_file_explorer_provider(ls_args)
--- @param query string
--- @param context PipelineContext
--- @param context FileExplorerPipelineContext
--- @return string?
local function wrap(query, context)
---@diagnostic disable-next-line: undefined-field
local cwd = utils.readfile(context.cwd)
if not constants.is_windows then
cwd = vim.fn.fnamemodify(cwd, ":~")
cwd = path.reduce2home(cwd)
end
if constants.has_eza then
return vim.fn.executable("echo") > 0
Expand Down Expand Up @@ -613,65 +613,182 @@ local function make_file_explorer_provider(ls_args)
return wrap
end

--- @param delimiter string?
--- @param filename_pos integer?
--- @param lineno_pos integer?
--- @return fun(line:string):string[]|nil
local function make_directory_previewer(delimiter, filename_pos, lineno_pos)
--- @param filename string
--- @return string[]|nil
local function directory_previewer(filename)
if constants.has_eza then
return {
constants.eza,
"--color=always",
"-lha",
"--",
filename,
}
elseif vim.fn.executable("ls") > 0 then
return { "ls", "--color=always", "-lha", "--", filename }
else
log.echo(LogLevels.INFO, "no ls/eza/exa command found.")
return nil
end
end

--- @return fun(line:string,context:FileExplorerPipelineContext):string[]|nil
local function make_file_explorer_previewer()
-- The `eza -lh` (`exa -lh`) in windows output looks like:
--
-- ```
-- Mode Size Date Modified Name
-- d---- - 30 Sep 21:55 deps
-- -a--- 585 22 Jul 14:26 init.vim
-- -a--- 6.4k 30 Sep 21:55 install.ps1
-- -a--- 5.3k 23 Sep 13:43 install.sh
-- ```
--
-- So file name starts from the 5th space.
--
-- While in macOS it looks like:
--
-- ```
-- Permissions Size User Date Modified Name
-- drwxr-xr-x - linrongbin 28 Aug 12:39 autoload
-- drwxr-xr-x - linrongbin 22 Sep 10:11 bin
-- .rw-r--r-- 120 linrongbin 5 Sep 14:14 codecov.yml
-- .rw-r--r-- 1.1k linrongbin 28 Aug 12:39 LICENSE
-- drwxr-xr-x - linrongbin 8 Oct 09:14 lua
-- .rw-r--r-- 28k linrongbin 8 Oct 11:37 README.md
-- drwxr-xr-x - linrongbin 8 Oct 11:44 test
-- .rw-r--r-- 28k linrongbin 8 Oct 12:10 test1-README.md
-- .rw-r--r-- 28k linrongbin 8 Oct 12:10 test2-README.md
-- ```
--
-- File name starts from the 6th space.
--
-- You can see in different platform, there will be different fields: 'Permission', 'User', 'Mode'.
--
-- While the `ls -lh` in both windows and macOS always looks like the same:
--
-- windows:
-- ```
-- total 31K
-- -rwxrwxrwx 1 somebody somegroup 150 Aug 3 21:29 .editorconfig
-- drwxrwxrwx 1 somebody somegroup 0 Oct 8 12:02 .github
-- -rwxrwxrwx 1 somebody somegroup 363 Aug 30 15:51 .gitignore
-- -rwxrwxrwx 1 somebody somegroup 124 Sep 18 23:56 .luacheckrc
-- -rwxrwxrwx 1 somebody somegroup 68 Sep 11 21:58 .luacov
-- ```
--
-- macOS:
-- ```
-- total 184
-- -rw-r--r-- 1 rlin staff 1.0K Aug 28 12:39 LICENSE
-- -rw-r--r-- 1 rlin staff 27K Oct 8 11:37 README.md
-- drwxr-xr-x 3 rlin staff 96B Aug 28 12:39 autoload
-- drwxr-xr-x 4 rlin staff 128B Sep 22 10:11 bin
-- -rw-r--r-- 1 rlin staff 120B Sep 5 14:14 codecov.yml
-- ```
--
-- File name alawys starts from the 8th space for `ls -lh`.

local parse_ls_start_pos = 8
local run_eza_failed = false

--- @return boolean, integer?
local function parse_eza_columns()
local cmd = require("fzfx.cmd")
local run_cmd = cmd.Cmd:run({ constants.eza, "-lh" })
if run_cmd:wrong() then
return false, nil
end
local header = run_cmd.result.stdout[1]
if type(header) ~= "string" or string.len(header) == 0 then
return false, nil
end
local eza_header_words = {
"Mode",
"Permissions",
"Size",
"User",
"Date Modified",
"Name",
}
local columns = 0
for _, hword in ipairs(eza_header_words) do
if utils.string_find(header, hword) ~= nil then
-- log.echo(
-- LogLevels.INFO,
-- "|parse_eza_columns| search hword:%s",
-- vim.inspect(hword)
-- )
columns = columns + 1
end
end
return true, columns + 1
end

if constants.has_eza then
local ok, start_pos_or_err = parse_eza_columns()
-- log.echo(
-- LogLevels.INFO,
-- "|make_file_explorer_previewer| ok:%s, start_pos:%s",
-- vim.inspect(ok),
-- vim.inspect(start_pos)
-- )
if ok then
parse_ls_start_pos = start_pos_or_err --[[@as integer]]
else
log.echo(
LogLevels.WARN,
"failed to run '%s -lh'! %s",
constants.eza,
start_pos_or_err
)
end
end

--- @param line string
--- @param context FileExplorerPipelineContext
--- @return string[]|nil
local function wrap(line)
local function impl(line, context)
if run_eza_failed then
log.echo(LogLevels.INFO, "failed to run 'eza -lh'.")
return nil
end
log.debug(
"|fzfx.config - make_directory_previewer| delimiter:%s, filename_pos:%s, lineno_pos:%s",
vim.inspect(delimiter),
vim.inspect(filename_pos),
vim.inspect(lineno_pos)
"|fzfx.config - make_file_explorer_previewer.impl| parse_ls_start_pos:%s",
vim.inspect(parse_ls_start_pos)
)
line = vim.trim(line)
local cwd = utils.readfile(context.cwd)
local target = line_helpers.parse_ls(line, parse_ls_start_pos)
if
(
utils.string_startswith(target, "'")
and utils.string_endswith(target, "'")
)
or (
utils.string_startswith(target, '"')
and utils.string_endswith(target, '"')
)
then
target = target:sub(2, #target - 1)
end
local p = path.join(cwd, target)
log.debug(
"|fzfx.config - make_directory_previewer| line:%s",
vim.inspect(line)
"|fzfx.config - make_file_explorer_previewer| cwd:%s, target:%s, p:%s",
vim.inspect(cwd),
vim.inspect(target),
vim.inspect(p)
)
local parsed =
line_helpers.PathLine:new(line, delimiter, filename_pos, lineno_pos)
if constants.has_eza then
return {
constants.eza,
"--color=always",
"-lha",
"--",
parsed.filename,
}
elseif vim.fn.executable("ls") > 0 then
return { "ls", "--color=always", "-lha", "--", parsed.filename }
elseif constants.is_windows then
return { "dir", "--", parsed.filename }
if vim.fn.filereadable(p) > 0 then
local preview = make_file_previewer(p)
return preview()
elseif vim.fn.isdirectory(p) > 0 then
return directory_previewer(p)
else
log.echo(LogLevels.INFO, "no ls/dir/eza/exa command found.")
return nil
end
end
return wrap
end

local directory_previewer = make_directory_previewer()

--- @param line string
--- @param context PipelineContext
--- @return string[]|nil
local function file_explorer_previewer(line, context)
---@diagnostic disable-next-line: undefined-field
local cwd = utils.readfile(context.cwd)
local splits = utils.string_split(line, " ")
local p = path.join(cwd, splits[#splits])
if vim.fn.filereadable(p) > 0 then
local filename = line_helpers.parse_find(p, { no_icon = true })
local impl = make_file_previewer(filename)
return impl()
elseif vim.fn.isdirectory(p) > 0 then
return directory_previewer(p)
else
return nil
end
return impl
end

--- @param lines string[]
Expand Down Expand Up @@ -2314,19 +2431,19 @@ local Defaults = {
},
previewers = {
filter_hidden = PreviewerConfig:make({
previewer = file_explorer_previewer,
previewer = make_file_explorer_previewer(),
previewer_type = PreviewerTypeEnum.COMMAND_LIST,
}),
include_hidden = PreviewerConfig:make({
previewer = file_explorer_previewer,
previewer = make_file_explorer_previewer(),
previewer_type = PreviewerTypeEnum.COMMAND_LIST,
}),
},
interactions = {
cd = {
key = "alt-right",
key = "alt-l",
--- @param line string
--- @param context {bufnr:integer,winnr:integer,tabnr:integer,cwd:string}
--- @param context FileExplorerPipelineContext
interaction = function(line, context)
local splits = utils.string_split(line, " ")
local sub = splits[#splits]
Expand All @@ -2339,9 +2456,9 @@ local Defaults = {
reload_after_execute = true,
},
upper = {
key = "alt-left",
key = "alt-h",
--- @param line string
--- @param context {bufnr:integer,winnr:integer,tabnr:integer,cwd:string}
--- @param context FileExplorerPipelineContext
interaction = function(line, context)
local cwd = utils.readfile(context.cwd) --[[@as string]]
local target = vim.fn.fnamemodify(cwd, ":h")
Expand Down
2 changes: 1 addition & 1 deletion lua/fzfx/line_helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ local function parse_ls(line, start_pos)
end
pos = pos + 1
end
return vim.fn.expand(path.normalize(line:sub(pos)))
return vim.fn.expand(path.normalize(vim.trim(line:sub(pos))))
end

--- @param line string
Expand Down
7 changes: 7 additions & 0 deletions lua/fzfx/path.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,19 @@ local function reduce(p)
return vim.fn.fnamemodify(p or vim.fn.getcwd(), ":~:.")
end

--- @param p string?
--- @return string
local function reduce2home(p)
return vim.fn.fnamemodify(p or vim.fn.getcwd(), ":~")
end

local M = {
-- path
normalize = normalize,
join = join,
shorten = shorten,
reduce = reduce,
reduce2home = reduce2home,

-- plugin dir
base_dir = base_dir,
Expand Down
1 change: 0 additions & 1 deletion lua/fzfx/shell_helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ local M = {
GitRootCmd = require("fzfx.cmd").GitRootCmd,
GitBranchCmd = require("fzfx.cmd").GitBranchCmd,
GitCurrentBranchCmd = require("fzfx.cmd").GitCurrentBranchCmd,
string_find = require("fzfx.utils").string_find,
string_rfind = require("fzfx.utils").string_rfind,
string_ltrim = require("fzfx.utils").string_ltrim,
string_rtrim = require("fzfx.utils").string_rtrim,
Expand Down
32 changes: 17 additions & 15 deletions lua/fzfx/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,26 @@ end
--- @param start integer?
--- @return integer?
local function string_find(s, c, start)
-- start = start or 1
-- local result = vim.fn.stridx(s, c, start - 1)
-- return result >= 0 and (result + 1) or nil

start = start or 1
for i = start, #s do
if string.byte(s, i) == string.byte(c) then
return i
local match = true
for j = 1, #c do
if i + j - 1 > #s then
match = false
break
end
local a = string.byte(s, i + j - 1)
local b = string.byte(c, j)
if a ~= b then
match = false
break
end
end
end
return nil
end

--- @param s string
--- @param c string
--- @param rstart integer?
--- @return integer?
local function string_rfind(s, c, rstart)
rstart = rstart or #s
for i = rstart, 1, -1 do
if string.byte(s, i) == string.byte(c) then
if match then
return i
end
end
Expand Down Expand Up @@ -725,7 +728,6 @@ local M = {
string_empty = string_empty,
string_not_empty = string_not_empty,
string_find = string_find,
string_rfind = string_rfind,
string_ltrim = string_ltrim,
string_rtrim = string_rtrim,
string_split = string_split,
Expand Down
5 changes: 5 additions & 0 deletions test/goodbye world/goodbye.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
print("goodbye world")
print("goodbye world")
print("goodbye world")
print("goodbye world")
print("goodbye world")
Loading

0 comments on commit 8fd2bc6

Please sign in to comment.