From f86de7aa6bddcfcb6bb0befe1dee6974775b38f0 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 14 Mar 2022 16:11:34 -0700 Subject: [PATCH] new option 'grep.rg_glob': default to rg glob parsing (closes #365) --- README.md | 8 +++- doc/fzf-lua.txt | 8 +++- lua/fzf-lua/actions.lua | 3 ++ lua/fzf-lua/make_entry.lua | 22 ++++++--- lua/fzf-lua/providers/grep.lua | 86 +++++++++++++++++----------------- lua/fzf-lua/providers/tags.lua | 3 ++ 6 files changed, 75 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index f36a599..e372c76 100644 --- a/README.md +++ b/README.md @@ -563,9 +563,13 @@ require'fzf-lua'.setup { -- otherwise auto-detect prioritizes `rg` over `grep` -- default options are controlled by 'rg|grep_opts' -- cmd = "rg --vimgrep", - rg_opts = "--column --line-number --no-heading --color=always --smart-case --max-columns=512", grep_opts = "--binary-files=without-match --line-number --recursive --color=auto --perl-regexp", - -- 'live_grep_glob' options: + rg_opts = "--column --line-number --no-heading --color=always --smart-case --max-columns=512", + -- set to 'true' to always parse globs in both 'grep' and 'live_grep' + -- search strings will be split using the 'glob_separator' and translated + -- to '--iglob=' arguments, requires 'rg' + -- can still be used when 'false' by calling 'live_grep_glob' directly + rg_glob = false, -- always parse for globs with glob_flag = "--iglob", -- for case sensitive globs use '--glob' glob_separator = "%s%-%-" -- query separator pattern (lua): ' --' actions = { diff --git a/doc/fzf-lua.txt b/doc/fzf-lua.txt index 7e5a6d6..5eb6de4 100644 --- a/doc/fzf-lua.txt +++ b/doc/fzf-lua.txt @@ -609,9 +609,13 @@ Consult the list below for available settings: -- otherwise auto-detect prioritizes `rg` over `grep` -- default options are controlled by 'rg|grep_opts' -- cmd = "rg --vimgrep", - rg_opts = "--column --line-number --no-heading --color=always --smart-case --max-columns=512", grep_opts = "--binary-files=without-match --line-number --recursive --color=auto --perl-regexp", - -- 'live_grep_glob' options: + rg_opts = "--column --line-number --no-heading --color=always --smart-case --max-columns=512", + -- set to 'true' to always parse globs in both 'grep' and 'live_grep' + -- search strings will be split using the 'glob_separator' and translated + -- to '--iglob=' arguments, requires 'rg'. + -- can still be used when 'false' by calling 'live_grep_glob' directly + rg_glob = false, -- always parse for globs with glob_flag = "--iglob", -- for case sensitive globs use '--glob' glob_separator = "%s%-%-" -- query separator pattern (lua): ' --' actions = { diff --git a/lua/fzf-lua/actions.lua b/lua/fzf-lua/actions.lua index a67cd66..17c0622 100644 --- a/lua/fzf-lua/actions.lua +++ b/lua/fzf-lua/actions.lua @@ -542,6 +542,9 @@ M.grep_lgrep = function(_, opts) search = false, continue_last_search = true, continue_last_search_default = '', + rg_glob = opts.rg_glob or opts.__call_opts.rg_glob, + -- globs always require command processing with 'multiprocess' + requires_processing = opts.rg_glob or opts.__call_opts.rg_glob, }, opts.__call_opts or {}) if opts.__FNCREF__ then diff --git a/lua/fzf-lua/make_entry.lua b/lua/fzf-lua/make_entry.lua index 75e6de8..ea8fe86 100644 --- a/lua/fzf-lua/make_entry.lua +++ b/lua/fzf-lua/make_entry.lua @@ -194,6 +194,19 @@ M.get_diff_files = function(opts) return diff_files end +M.glob_parse = function(opts, query) + if not query or not query:find(opts.glob_separator) then + return query, nil + end + local glob_args = "" + local search_query, glob_str = query:match("(.*)"..opts.glob_separator.."(.*)") + for _, s in ipairs(utils.strsplit(glob_str, "%s")) do + glob_args = glob_args .. ("%s %s ") + :format(opts.glob_flag, vim.fn.shellescape(s)) + end + return search_query, glob_args +end + M.preprocess = function(opts) if opts.cwd_only and not opts.cwd then opts.cwd = vim.loop.cwd() @@ -232,13 +245,8 @@ M.preprocess = function(opts) -- mannipulation needs to be done before the argv hack if opts.rg_glob then local query = argv() - if query and query:find(opts.glob_separator) then - local glob_args = "" - local search_query, glob_str = query:match("(.*)"..opts.glob_separator.."(.*)") - for _, s in ipairs(utils.strsplit(glob_str, "%s")) do - glob_args = glob_args .. ("%s %s ") - :format(opts.glob_flag, vim.fn.shellescape(s)) - end + local search_query, glob_args = M.glob_parse(opts, query) + if glob_args then -- gsub doesn't like single % on rhs search_query = search_query:gsub("%%", "%%%%") -- reset argvz so it doesn't get replaced again below diff --git a/lua/fzf-lua/providers/grep.lua b/lua/fzf-lua/providers/grep.lua index f433952..5c68add 100644 --- a/lua/fzf-lua/providers/grep.lua +++ b/lua/fzf-lua/providers/grep.lua @@ -3,6 +3,7 @@ local core = require "fzf-lua.core" local utils = require "fzf-lua.utils" local config = require "fzf-lua.config" local libuv = require "fzf-lua.libuv" +local make_entry = require "fzf-lua.make_entry" local function get_last_search(opts) if opts.__MODULE__ and opts.__MODULE__.get_last_search then @@ -34,9 +35,6 @@ end local M = {} local get_grep_cmd = function(opts, search_query, no_esc) - if opts.cmd_fn and type(opts.cmd_fn) == 'function' then - return opts.cmd_fn(opts, search_query, no_esc) - end if opts.raw_cmd and #opts.raw_cmd>0 then return opts.raw_cmd end @@ -49,6 +47,27 @@ local get_grep_cmd = function(opts, search_query, no_esc) command = string.format("grep %s", opts.grep_opts) end + if opts.rg_glob and not command:match("^rg") then + opts.rg_glob = false + utils.warn("'--glob|iglob' flags require 'rg', ignoring 'rg_glob' option.") + end + + if opts.rg_glob then + local new_query, glob_args = make_entry.glob_parse(opts, search_query) + if glob_args then + -- since the search string mixes both the query and + -- glob separators we cannot used unescaped strings + if not (no_esc or opts.no_esc) then + new_query = utils.rg_escape(new_query) + opts.no_esc = true + opts.search = ("%s%s"):format(new_query, + search_query:match(opts.glob_separator..".*")) + end + search_query = new_query + command = ("%s %s"):format(command, glob_args) + end + end + -- filename takes precedence over directory -- filespec takes precedence over all and doesn't shellescape -- this is so user can send a file populating command instead @@ -99,19 +118,17 @@ M.grep = function(opts) opts.search = vim.fn.input(opts.input_prompt) or '' end - --[[ if not opts.search or #opts.search == 0 then - utils.info("Please provide a valid search string") - return - end ]] - -- search query in header line opts = core.set_header(opts) - -- save the search query so the use can - -- call the same search again + -- get the grep command before saving the last search + -- incase the search string is overwritten by 'rg_glob' + opts.cmd = get_grep_cmd(opts, opts.search, no_esc) + + -- save the search query so we + -- can call the same search again set_last_search(opts, opts.search, no_esc or opts.no_esc) - opts.cmd = get_grep_cmd(opts, opts.search, no_esc) local contents = core.mt_cmd_wrapper(opts) -- by redirecting the error stream to stdout -- we make sure a clear error message is displayed @@ -319,44 +336,16 @@ M.live_grep_mt = function(opts) end M.live_grep_glob_st = function(opts) - if not opts then opts = {} end + if vim.fn.executable("rg") ~= 1 then utils.warn("'--glob|iglob' flags requires 'rg' (https://github.com/BurntSushi/ripgrep)") return end - opts.cmd_fn = function(o, query, no_esc) - local glob_arg, glob_str = "", "" - local search_query = query or "" - if query:find(o.glob_separator) then - search_query, glob_str = query:match("(.*)"..o.glob_separator.."(.*)") - for _, s in ipairs(utils.strsplit(glob_str, "%s")) do - glob_arg = glob_arg .. (" %s %s") - :format(o.glob_flag, vim.fn.shellescape(s)) - end - end - - -- copied over from get_grep_cmd - local search_path = '' - if o.filespec and #o.filespec>0 then - search_path = o.filespec - elseif o.filename and #o.filename>0 then - search_path = vim.fn.shellescape(o.filename) - end - - if not (no_esc or o.no_esc) then - search_query = utils.rg_escape(search_query) - end - - -- do not escape at all - if not (no_esc == 2 or o.no_esc == 2) then - search_query = libuv.shellescape(search_query) - end - - local cmd = ("rg %s %s -- %s %s") - :format(o.rg_opts, glob_arg, search_query, search_path) - return cmd - end + -- 'rg_glob = true' enables glob + -- processsing in 'get_grep_cmd' + opts = opts or {} + opts.rg_glob = true return M.live_grep_st(opts) end @@ -383,6 +372,12 @@ M.live_grep_native = function(opts) opts = opts or {} opts.git_icons = false opts.file_icons = false + opts.rg_glob = false + -- disable ctrl-g switch by default + if not opts.actions or not opts.actions["ctrl-g"] then + opts.actions = opts.actions or {} + opts.actions["ctrl-g"] = false + end opts.__FNCREF__ = utils.__FNCREF__() return M.live_grep_mt(opts) end @@ -461,6 +456,9 @@ end M.grep_curbuf = function(opts) if not opts then opts = {} end + -- rg globs are meaningless here since we searching + -- a single file + opts.rg_glob = false opts.rg_opts = config.globals.grep.rg_opts .. " --with-filename" opts.grep_opts = config.globals.grep.grep_opts .. " --with-filename" if opts.exec_empty_query == nil then diff --git a/lua/fzf-lua/providers/tags.lua b/lua/fzf-lua/providers/tags.lua index 41fdaa3..96de7c9 100644 --- a/lua/fzf-lua/providers/tags.lua +++ b/lua/fzf-lua/providers/tags.lua @@ -87,6 +87,9 @@ local function tags(opts) if opts.lgrep then -- live_grep requested by caller ('tags_live_grep') + -- rg globs are meaningless here since we searching + -- a single file + opts.rg_glob = false opts.filename = opts._ctags_file if opts.multiprocess then return require'fzf-lua.providers.grep'.live_grep_mt(opts)