diff options
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/denote-fzf-lua.lua | 182 | ||||
| -rw-r--r-- | lua/denote-fzf-lua/config.lua | 1 | ||||
| -rwxr-xr-x | lua/denote-fzf-lua/scripts/fallback_search_files.sh | 8 | ||||
| -rwxr-xr-x | lua/denote-fzf-lua/scripts/search_files.sh | 8 |
4 files changed, 61 insertions, 138 deletions
diff --git a/lua/denote-fzf-lua.lua b/lua/denote-fzf-lua.lua index c2999bb..167ecb3 100644 --- a/lua/denote-fzf-lua.lua +++ b/lua/denote-fzf-lua.lua @@ -5,120 +5,57 @@ local fzflua = require("fzf-lua") local builtin = require("fzf-lua.previewer.builtin") local FIELDS = { "path", "date", "time", "sig", "title", "keywords", "ext" } +local lua_dir = debug.getinfo(1, "S").source:match("@?(.*/)") +local script_dir = lua_dir .. "denote-fzf-lua/scripts/" -local function list_denote_files(dir) - local results = {} - local stack = { vim.fn.expand(dir) } - - while #stack > 0 do - local current = table.remove(stack) - local ok, handle = pcall(vim.loop.fs_scandir, current) - if ok and handle then - while true do - local name, typ = vim.loop.fs_scandir_next(handle) - if not name then break end - local full = current .. "/" .. name - if typ == "directory" then - table.insert(stack, full) - elseif (typ == "file" or typ == "link") and name:match("^%d%d%d%d%d%d%d%dT%d%d%d%d%d%d") then - table.insert(results, full) - end - end - end - end - - return results +local function format_field(field, delim) + if field == "." then return "" end + return delim .. delim .. field:gsub("%s", delim) end -local function parse_denote(basename) - local dt = basename:sub(1, 15) - if not dt:match("^%d%d%d%d%d%d%d%dT%d%d%d%d%d%d$") then return nil end - - local date = dt:sub(1, 4) .. "-" .. dt:sub(5, 6) .. "-" .. dt:sub(7, 8) - local time = dt:sub(10, 11) .. ":" .. dt:sub(12, 13) .. ":" .. dt:sub(14, 15) - - local dot_idx = basename:find("%.", 16, true) - if not dot_idx then return nil end - local ext = basename:sub(dot_idx) - local body = basename:sub(16, dot_idx - 1) - - local sig, title, keywords = "", "", "" - local pos = 1 - - if body:sub(pos, pos + 1) == "==" then - local sig_end = body:find("%-%-", pos + 2) - if sig_end then - sig = body:sub(pos + 2, sig_end - 1) - pos = sig_end - end - end - - if body:sub(pos, pos + 1) == "--" then - local title_end = body:find("__", pos + 2) - if title_end then - title = body:sub(pos + 2, title_end - 1) - pos = title_end - else - title = body:sub(pos + 2) - pos = #body + 1 +function M.format_fzf_with_nth(options) + local indices = {} + for i, field in ipairs(FIELDS) do + if options.search_fields[field] then + table.insert(indices, i) end - else - return nil - end - - if pos <= #body and body:sub(pos) == "__" then - keywords = body:sub(pos + 2) end - - return { - path = "", - date = date, - time = time, - sig = sig ~= "" and sig:gsub("=", " ") or ".", - title = title ~= "" and title:gsub("%-", " ") or ".", - keywords = keywords ~= "" and keywords:gsub("_", " ") or ".", - ext = ext, - } + return table.concat(indices, ",") end -local function format_denote_table(files) - local parsed = {} - for _, filepath in ipairs(files) do - local basename = vim.fn.fnamemodify(filepath, ":t") - local dirpath = vim.fn.fnamemodify(filepath, ":h") .. "/" - local info = parse_denote(basename) - if info then - info.path = dirpath - table.insert(parsed, info) - end +function M.has_prereqs(force_slow) + if vim.fn.executable("fzf") ~= 1 then return "no" end + if force_slow then return "partial" end + for _, cmd in ipairs({ "fd", "sd", "qsv" }) do + if vim.fn.executable(cmd) ~= 1 then return "partial" end end + return "yes" +end - local widths = {} - for i, field in ipairs(FIELDS) do - widths[i] = #field - end - for _, info in ipairs(parsed) do - for i, field in ipairs(FIELDS) do - widths[i] = math.max(widths[i], #info[field]) - end +function M.get_script(force_slow) + local prereqs = M.has_prereqs(force_slow) + if prereqs == "no" then + error("Missing dependency: fzf") + return + elseif prereqs == "yes" then + return script_dir .. "search_files.sh" + else + return script_dir .. "fallback_search_files.sh" end +end - local lines = {} +function M.reconstruct_filename(row) + if not row or row == "" then return "" end + row = row:gsub("%s+$", "") local parts = {} - for i, field in ipairs(FIELDS) do - parts[i] = string.format("%-" .. widths[i] .. "s", field) - end - table.insert(lines, table.concat(parts, " ")) - - for _, info in ipairs(parsed) do - parts = {} - for i, field in ipairs(FIELDS) do - parts[i] = string.format("%-" .. widths[i] .. "s", info[field]) - end - table.insert(lines, table.concat(parts, " ")) - end - - return lines + row = row:gsub("%s%s+", "|") + parts.path, parts.year, parts.month, parts.day, parts.hour, parts.min, parts.sec, parts.sig, parts.title, parts.keywords, parts.ext = + row:match("^(.*/)|(%d%d%d%d)%-(%d%d)%-(%d%d)|(%d%d):(%d%d):(%d%d)|([^|]+)|([^|]+)|([^|]+)|(%..+)") + if not parts.path then return "" end + local sig = format_field(parts.sig, "=") + local title = format_field(parts.title, "-") + local keywords = format_field(parts.keywords, "_") + return parts.path .. parts.year .. parts.month .. parts.day .. "T" .. parts.hour .. parts.min .. parts.sec .. sig .. title .. keywords .. parts.ext end M.reconstruct_previewer = builtin.buffer_or_file:extend() @@ -137,41 +74,9 @@ function M.reconstruct_previewer:parse_entry(entry_str) } end -local function format_field(field, delim) - if field == "." then return "" end - return delim .. delim .. field:gsub("%s", delim) -end - -function M.reconstruct_filename(row) - if not row or row == "" then return "" end - local t = {} - row = row:gsub("%s%s+", "|") - t.path, t.year, t.month, t.day, t.hour, t.min, t.sec, t.sig, t.title, t.keywords, t.ext = - row:match("^(.*/)|(%d%d%d%d)%-(%d%d)%-(%d%d)|(%d%d):(%d%d):(%d%d)|([^|]+)|([^|]+)|([^|]+)|(%..+)") - if not t.path then return "" end - t.sig = format_field(t.sig, "=") - t.title = format_field(t.title, "-") - t.keywords = format_field(t.keywords, "_") - return t.path .. t.year .. t.month .. t.day .. "T" .. t.hour .. t.min .. t.sec .. t.sig .. t.title .. t.keywords .. t.ext -end - -function M.format_fzf_with_nth(options) - local indices = {} - for i, field in ipairs(FIELDS) do - if options.search_fields[field] then - table.insert(indices, i) - end - end - return table.concat(indices, ",") -end - function M.search_files(options) - local files = list_denote_files(options.dir) - if #files == 0 then - vim.notify("denote-fzf-lua: no Denote files found in " .. options.dir, vim.log.levels.WARN) - return - end - local lines = format_denote_table(files) + local script = M.get_script(options.force_slow_mode) + if not script then return end local opts = {} opts.previewer = M.reconstruct_previewer @@ -185,7 +90,8 @@ function M.search_files(options) vim.api.nvim_command("edit " .. vim.fn.fnameescape(filename)) end, } - fzflua.fzf_exec(lines, opts) + local dir = vim.fn.expand(options.dir) + fzflua.fzf_exec(script .. " " .. dir, opts) end function M.search_contents(options) @@ -194,7 +100,7 @@ function M.search_contents(options) return end local opts = {} - opts.cwd = options.dir + opts.cwd = vim.fn.expand(options.dir) opts.previewer = "builtin" opts.fzf_opts = options.fzf_lua_opts.fzf_opts opts.actions = fzflua.defaults.actions.files diff --git a/lua/denote-fzf-lua/config.lua b/lua/denote-fzf-lua/config.lua index cd451e2..04a135f 100644 --- a/lua/denote-fzf-lua/config.lua +++ b/lua/denote-fzf-lua/config.lua @@ -2,6 +2,7 @@ local M = {} M.defaults = { dir = "~/notes", + force_slow_mode = false, search_fields = { path = false, diff --git a/lua/denote-fzf-lua/scripts/fallback_search_files.sh b/lua/denote-fzf-lua/scripts/fallback_search_files.sh new file mode 100755 index 0000000..f6ee4fc --- /dev/null +++ b/lua/denote-fzf-lua/scripts/fallback_search_files.sh @@ -0,0 +1,8 @@ +#!/bin/sh +find "$1" -not -path '*/.*' |\ +sed -E "/^(.*\/)?([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9])(==[^_\.\-]+)?(--[^_\.]+)?(__[^\.]+)?(\.[a-z0-9]+)$/!d" |\ +sed -E "s/^(.*\/)?([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9])(==([^_\.\-]+))?(--([^_\.]+))?(__([^\.]+))?(\.[a-z0-9]+)$/\1,\2,\4,\6,\8,\9/" |\ +tr '\=\-_' ' ' |\ +sed -E 's/([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])T([0-9][0-9])([0-9][0-9])([0-9][0-9])/\1-\2-\3,\4:\5:\6/' |\ +sed 's/,,/,.,/g' |\ +column -t -s "," -N Path,Date,Time,Sig,Title,Keywords,Ext diff --git a/lua/denote-fzf-lua/scripts/search_files.sh b/lua/denote-fzf-lua/scripts/search_files.sh new file mode 100755 index 0000000..4367049 --- /dev/null +++ b/lua/denote-fzf-lua/scripts/search_files.sh @@ -0,0 +1,8 @@ +#!/bin/sh +(echo "Path,Date,Time,Sig,Title,Keywords,Ext"; +fd '^\d{8}T\d{6}(==[a-z0-9=]+)?(\-\-[a-z0-9-]+)?(__[a-z0-9_]+)?\.\w+$' "$1" |\ +sd '(?P<path>\/.*\/)?(?P<datetime>\d{8}T\d{6})(==(?P<sig>[a-z0-9=]+))?(--(?P<title>[a-z0-9-]+))(__(?P<keywords>[a-z0-9_]+))?(?P<ext>\.\w+)' '$path,$datetime,$sig,$title,$keywords,$ext' |\ +tr '\=\-_' ' ' |\ +sd '(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})' '$1-$2-$3,$4:$5:$6') |\ +sd ',,' ',.,' |\ +qsv table |
