diff options
| author | DefaultGen <gravel.justness270@slmail.me> | 2024-06-20 03:06:14 -0400 |
|---|---|---|
| committer | DefaultGen <gravel.justness270@slmail.me> | 2024-06-20 03:06:14 -0400 |
| commit | b8b17b0402a5996144dc099748ea4c18f576ac1b (patch) | |
| tree | f481fededc59985df6b8f3e4103221adfd142df6 /lua | |
| parent | 23a89932e57b50a8e9064b9c7ba329e62c88bc44 (diff) | |
| download | denote-fzf-lua-b8b17b0402a5996144dc099748ea4c18f576ac1b.tar.gz | |
Working file and rg searches
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/denote-fzf-lua.lua | 99 | ||||
| -rw-r--r-- | lua/denote-fzf-lua/config.lua | 65 | ||||
| -rwxr-xr-x | lua/denote-fzf-lua/scripts/fallback_search_files.sh | 49 | ||||
| -rwxr-xr-x | lua/denote-fzf-lua/scripts/rg.sh | 4 | ||||
| -rwxr-xr-x | lua/denote-fzf-lua/scripts/search_files.sh | 36 |
5 files changed, 147 insertions, 106 deletions
diff --git a/lua/denote-fzf-lua.lua b/lua/denote-fzf-lua.lua index 1013afb..3e68c40 100644 --- a/lua/denote-fzf-lua.lua +++ b/lua/denote-fzf-lua.lua @@ -3,29 +3,30 @@ local M = {} local config = require("denote-fzf-lua.config") local fzflua = require('fzf-lua') - +---@param options table of user options --- Check for dependencies and optional dependencies -function M.has_prereqs() +function M.has_prereqs(options) if vim.fn.executable('fzf') ~= 1 then return "no" end - if vim.fn.executable('rg') ~= 1 then return "no" end + if options.force_slow_mode then return "partial" end if vim.fn.executable('fd') ~= 1 then return "partial" end if vim.fn.executable('sd') ~= 1 then return "partial" end - if vim.fn.executable('xsv') ~= 1 then return "partial" end + if vim.fn.executable('qsv') ~= 1 then return "partial" end return "yes" end ----Returns the full path of the appropriate script -function M.get_script_path() +---@param options table of user options +--- Sets the full path of the appropriate search script (regular or fallback) +function M.set_script_path(options) local lua_file_path = debug.getinfo(1, "S").source:sub(2) local lua_file_dir = vim.fn.fnamemodify(lua_file_path, ":h") local script_path = lua_file_dir .. "/denote-fzf-lua/scripts/" - local dependencies = M.has_prereqs() + local dependencies = M.has_prereqs(options) if dependencies == "yes" then script_path = script_path .. "search_files.sh" elseif dependencies == "partial" then script_path = script_path .. "fallback_search_files.sh" else - error("Missing dependencies: fzf and rg") + error("Missing dependency: fzf") return false end return script_path @@ -44,8 +45,8 @@ function M.format_fzf_with_nth(options) return fzf_with_nth:sub(1, -2) end --- TODO: This is absolutely wrecked -function M.open_file(filename) +---@param filename chopped up string with fields separated by | +function M.recombine_filename(filename) local t = {} filename = filename:gsub("%s%s+", "|") t.path, t.year, t.month, t.day, t.hour, t.min, t.sec, t.sig, t.title, t.tags, t.ext = @@ -65,33 +66,86 @@ function M.open_file(filename) else t.tags = "__" .. t.tags:gsub("%s", "_") end - local file = t.path .. t.year .. t.month .. t.day .. "T" .. t.hour .. t.min .. t.sec .. t.sig .. t.title .. t.tags .. t.ext - vim.api.nvim_command('edit ' .. file) + return t.path .. t.year .. t.month .. t.day .. "T" .. t.hour .. t.min .. t.sec .. t.sig .. t.title .. t.tags .. t.ext +end + +--- Sets fzf preview to bat or cat depending on program availability +function M.set_preview_program() + if vim.fn.executable('bat') == 1 then + return "xargs bat -p --color=always" + else + return "xargs cat" + end +end + +-- Sets fzf preview for contents search. $file is the filename, $line is the rg match line. +function M.set_rg_preview() + if vim.fn.executable('bat') == 1 then + return "bat $file -p --color=always --highlight-line=$line" + else + return "cat $file" + end end ---@param options table of user options ---Opens a window to search filenames -function M.files(options) - local script_path = M.get_script_path() +function M.search_files(options) + script_path = M.set_script_path(options) if not script_path then return end options.fzf.opts["--with-nth"] = M.format_fzf_with_nth(options) + options.fzf.opts['--header-lines'] = 1 fzflua.fzf_exec(script_path .. " " .. options.dir, { - preview = options.fzf.preview, - actions = options.fzf.actions, + preview = options.fzf.preview .. M.set_preview_program(), + -- selected[1] is the chopped up filename with 2+ spaces between fields + actions = { ['default'] = function(selected, opts) + local filename = M.recombine_filename(selected[1]) + vim.api.nvim_command('edit ' .. filename) + end}, fzf_opts = options.fzf.opts, }) - -- local fzf_args = M.format_fzf_with_nth(options) .. " " .. options.fzf.args - -- vim.api.nvim_command('edit ' .. stdout) +end + +---@param f string returned from rg. "/path/filename:line..." +function M.open_file_at_line(f) + local filename, line = f:match("^(.-):(%d+)") + vim.api.nvim_command('edit +' .. line .. " " .. filename) +end + +---@param options table +function M.search_contents(options) + local r = fzflua.fzf_live("rg " .. options.rg.opts .. " -- <query> " .. options.dir .. " 2>/dev/null", + { + preview = options.rg.fzf.preview .. M.set_rg_preview(), + actions = { ['default'] = function(selected, opts) + local filename_line = selected[1] + filename_line = filename_line .. ":1" --Default :1 in case no line returned + M.open_file_at_line(filename_line) + end}, + fzf_opts = options.rg.fzf.opts, + }) +end + +function M.search2(options) + opts = {} + opts.prompt = "> " + opts.actions = fzflua.defaults.actions.files + opts.previewer = "builtin" + opts.cwd = options.dir + opts.fzf_opts = options.rg.fzf.opts + return fzflua.fzf_live(function(q) + return "rg --column --color=always -- " .. vim.fn.shellescape(q or '') + end, opts) end ---@param options table of user options +---Creates Neovim command :DenoteSearch function M.load_cmd(options) vim.api.nvim_create_user_command("DenoteSearch", function(opts) if opts.fargs[1] == "files" then - M.files(options) + M.search_files(options) elseif opts.fargs[1] == "contents" then - M.conents(options) + M.search2(options) else error("Unsupported operation " .. opts.fargs[1]) end @@ -105,8 +159,9 @@ end ---@param options? table user configuration function M.setup(options) - config.options = vim.tbl_deep_extend("force", config.defaults, options or {}) - M.load_cmd(config.options) + options = vim.tbl_deep_extend("force", config.defaults, options or {}) + fzflua.setup({ winopts = options.winopts }) + M.load_cmd(options) end return M diff --git a/lua/denote-fzf-lua/config.lua b/lua/denote-fzf-lua/config.lua index 6520ef8..8d466ba 100644 --- a/lua/denote-fzf-lua/config.lua +++ b/lua/denote-fzf-lua/config.lua @@ -1,13 +1,18 @@ local M = {} M.defaults = { - dir = "~/notes", - window = { - width_percent = 80, - height_percent = 80, - x_offset = 0, - y_offset = 0, + dir = "~/notes", + force_slow_mode = false, -- Disables optional dependencies + + -- Set any fzf-lua winopts here (See fzf-lua documentation) + winopts = { + height = 0.85, + width = 0.80, + row = 0.35, + col = 0.50, }, + + -- Options sent to fzf (only relevant for filename search) fzf = { opts = { ['--reverse'] = true, @@ -16,9 +21,9 @@ M.defaults = { ['--no-hscroll'] = true, ['--preview-window'] = "bottom:50%", ['-i'] = true, - ['--delimiter'] = "\\s{2,}", - ['--header-lines'] = 1 + ['--delimiter'] = "\\s{2,}", -- Don't change this, change search_fields. }, + -- Which Denote fields are displayed in the search results search_fields = { path = false, date = true, @@ -28,23 +33,33 @@ M.defaults = { tags = true, ext = false, }, - -- This recombines the chopped up filename from ./scripts/search_files.sh and outputs it to cat - -- TODO: Rewrite this with a lua function - preview = [[\ -sig={4}; sig=$(echo $sig | sd "\W" "" | sd " " "="); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ -title={5}; title=$(echo $title | tr -d '.' | tr ' ' '-'); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ -tags={6}; tags=$(echo $tags | tr -d '.' | tr ' ' '_'); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ -ext={7}; \ -echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} | \ -sd "(?P<path>\/.*\/)?\|(?P<d1>\d\d\d\d)-(?P<d2>\d\d)-(?P<d3>\d\d)\|(?P<t1>\d\d):(?P<t2>\d\d):(?P<t3>\d\d)\|.*" "\$path\$d1\$d2\${d3}T\$t1\$t2\$t3$sig$title$tags$ext" |\ -xargs cat]], - -- selected[1] is the chopped up filename with 2+ spaces between fields - actions = { - ['default'] = function(selected, opts) - require'denote-fzf-lua'.open_file(selected[1]) - end - } - } + -- This recombines the chopped up filename from ./scripts/search_files.sh. The output needs to be piped to xargs bat or xargs cat. + preview = [[date={2};time={3}; datetime=$(echo ${date}T${time} | tr -d '\-:'); \ + sig={4}; sig=$(echo $sig | tr -d '.' | tr " " "="); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ + title={5}; title=$(echo $title | tr -d '.' | tr ' ' '-'); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ + tags={6}; tags=$(echo $tags | tr -d '.' | tr ' ' '_'); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ + ext={7}; \ + echo {1}${datetime}${sig}${title}${tags}${ext} | ]], + }, + -- Options for ripgrep (Only relevant for contents search) + rg = { + opts = "--column --color=always", + fzf = { + opts = { + ['--reverse'] = true, + ['--no-info'] = true, + ['--no-separator'] = true, + ['--no-hscroll'] = true, + ['--preview-window'] = 'bottom:50%', + ['-i'] = true, + }, + -- Checks if $line=$file in case rg --files is used and doesn't return a line number + -- This currently does nothing until I figure out if there's a good way to chop up filenames in the rg search + preview = "file=$(echo {} | cut -d ':' -f1); \ + line=$(echo {} | cut -d ':' -f2); \ + if [ \"$line\" = \"$file\" ] ; then line=0; fi;", + }, + }, } M.options = M.defaults diff --git a/lua/denote-fzf-lua/scripts/fallback_search_files.sh b/lua/denote-fzf-lua/scripts/fallback_search_files.sh index a617b64..9bc8135 100755 --- a/lua/denote-fzf-lua/scripts/fallback_search_files.sh +++ b/lua/denote-fzf-lua/scripts/fallback_search_files.sh @@ -1,36 +1,31 @@ #!/usr/bin/sh find $1 |\ -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/" |\ +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,Tags,Ext |\ -fzf --delimiter='\s{2,}' --header-lines=1 -i $2 --preview='\ -sig={4}; sig=$(echo $sig | tr -d . | tr " " =); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ -title={5}; title=$(echo $title | tr -d . | tr " " -); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ -tags={6}; tags=$(echo $tags | tr -d . | tr " " _); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ -ext={7}; \ -echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} |\ -sed -E "s/^(.*\/)?\|([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])\|([0-9][0-9]):([0-9][0-9]):([0-9][0-9])\|.*/\1\2\3\4T\5\6\7$sig$title$tags$ext/" |\ -xargs cat' \ ---bind='enter:become(\ -sig={4}; sig=$(echo $sig | tr -d . | tr " " =); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ -title={5}; title=$(echo $title | tr -d . | tr " " -); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ -tags={6}; tags=$(echo $tags | tr -d . | tr " " _); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ -ext={7}; \ -echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} | \ -sed -E "s/^(.*\/)?\|([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])\|([0-9][0-9]):([0-9][0-9]):([0-9][0-9])\|.*/\1\2\3\4T\5\6\7$sig$title$tags$ext/")+abort' +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,Tags,Ext +# fzf --delimiter='\s{2,}' --header-lines=1 -i $2 --preview='\ +# sig={4}; sig=$(echo $sig | tr -d . | tr " " =); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ +# title={5}; title=$(echo $title | tr -d . | tr " " -); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ +# tags={6}; tags=$(echo $tags | tr -d . | tr " " _); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ +# ext={7}; \ +# echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} |\ +# sed -E "s/^(.*\/)?\|([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])\|([0-9][0-9]):([0-9][0-9]):([0-9][0-9])\|.*/\1\2\3\4T\5\6\7$sig$title$tags$ext/" |\ +# xargs cat' \ +# --bind='enter:become(\ +# sig={4}; sig=$(echo $sig | tr -d . | tr " " =); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ +# title={5}; title=$(echo $title | tr -d . | tr " " -); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ +# tags={6}; tags=$(echo $tags | tr -d . | tr " " _); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ +# ext={7}; \ +# echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} | \ +# sed -E "s/^(.*\/)?\|([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])\|([0-9][0-9]):([0-9][0-9]):([0-9][0-9])\|.*/\1\2\3\4T\5\6\7$sig$title$tags$ext/")+abort' -# I am sorry for this. If I learn an equally fast, more readable way to implement this in Lua I will. # 1. find everything in directory # 2. sed deletes every line that isn't a Denote note (can't do this with find alone because -regex can't match optional capture groups) -# 3. sed splits the Denote filename into | delimited fields +# 3. sed splits the Denote filename into , delimited fields (pa # 4. tr replaces sig, title, tags special characters with spaces # 5. sed splits the date and time nicely -# 6. sed replaces blank fields with a period (column doesn't work with null fields) +# 6. sed replaces blank fields with a period # 7. column pretty prints the filenames in a table -# 8. fzf --delimiter breaks the table up into fields on 2+ space -# fzf --nth and --with-nth (args passed in $2) determine which fields are shown -# fzf --preview takes all the fzf fields {1}..{7} and recombines them into a filename, passed to cat -# fzf --bind recombines the filename and just outputs it diff --git a/lua/denote-fzf-lua/scripts/rg.sh b/lua/denote-fzf-lua/scripts/rg.sh deleted file mode 100755 index 2cfc400..0000000 --- a/lua/denote-fzf-lua/scripts/rg.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/sh -rg --color=always --line-number --no-heading --smart-case "${@:1:$#-1}" ${*: -1} - - diff --git a/lua/denote-fzf-lua/scripts/search_files.sh b/lua/denote-fzf-lua/scripts/search_files.sh index 67367af..3b0379c 100755 --- a/lua/denote-fzf-lua/scripts/search_files.sh +++ b/lua/denote-fzf-lua/scripts/search_files.sh @@ -1,36 +1,16 @@ #/usr/bin/sh +(echo "Path,Date,Time,Sig,Title,Tags,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<tags>[a-z0-9_]+))?(?P<ext>\.\w+)' '$path,$datetime,$sig,$title,$tags,$ext' |\ tr '\=\-_' ' ' |\ -sd '(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})' '$1-$2-$3,$4:$5:$6' |\ +sd '(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})' '$1-$2-$3,$4:$5:$6') |\ sd ',,' ',.,' |\ -column -t -s "," -N Path,Date,Time,Sig,Title,Tags,Ext -# fzf --delimiter='\s{2,}' --header-lines=1 -i $2 --preview='\ -# sig={4}; sig=$(echo $sig | sd "\W" "" | sd " " "="); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ -# title={5}; title=$(echo $title | sd " " "-"); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ -# tags={6}; tags=$(echo $tags | sd "\." "" | sd " " "_"); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ -# ext={7}; \ -# echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} | \ -# sd "(?P<path>\/.*\/)?\|(?P<d1>\d\d\d\d)-(?P<d2>\d\d)-(?P<d3>\d\d)\|(?P<t1>\d\d):(?P<t2>\d\d):(?P<t3>\d\d)\|.*" "\$path\$d1\$d2\${d3}T\$t1\$t2\$t3$sig$title$tags$ext" |\ -# xargs cat' \ -# --bind='enter:become(\ -# sig={4}; sig=$(echo $sig | sd "\W" "" | sd " " "="); if [ ! -z ${sig} ] ; then sig="==${sig}"; fi; \ -# title={5}; title=$(echo $title | sd " " "-"); if [ ! -z ${title} ] ; then title="--${title}"; fi; \ -# tags={6}; tags=$(echo $tags | sd "\." "" | sd " " "_"); if [ ! -z ${tags} ] ; then tags="__${tags}"; fi; \ -# ext={7}; \ -# echo {1}\|{2}\|{3}\|{4}\|{5}\|{6}\|{7} | \ -# sd "(?P<prefix>\/.*\/)?\|(?P<d1>\d\d\d\d)-(?P<d2>\d\d)-(?P<d3>\d\d)\|(?P<t1>\d\d):(?P<t2>\d\d):(?P<t3>\d\d)\|.*" "\$prefix\$d1\$d2\${d3}T\$t1\$t2\$t3$sig$title$tags$ext")+abort' -# -# I am sorry for this. If I learn an equally fast, more readable way to implement this in Lua I will. -# 1. echo table headers (for xsv) -# 2. fd all Denote files in $1 directory +qsv table + +# 1. echo the table headers +# 2. fd only Denote files in $1 directory (and subdirectories) # 3. sd chops the Denote filename fields into a CSV # 4. tr replaces special characters in sig, title, and tags with spaces # 5. sd formats the date and time as YYYY-MM-DD HH:MM:SS -# 6. sd replaces blank fields with . (ensures fzf can count fields correctly) -# 7. xsv to print the fields in tabular format -# 8. fzf the resulting table including $2 args list -# 9 fzf --delimiter breaks the table up into fields on 2+ space -# fzf --nth and --with-nth (args passed in $2) determine which fields are shown -# fzf --preview takes all the fzf fields {1}..{7} and recombines them into a filename, passed to cat -# fzf --bind recombines the filename and just outputs it +# 6. sd replaces blank fields with . (fzf can't handle blank fields) +# 7. qsv to print the fields in tabular format |
