Skip to content

Commit a234df1

Browse files
committed
refactor(cont)!: continue content stringify
1 parent 773cba6 commit a234df1

20 files changed

Lines changed: 340 additions & 580 deletions

File tree

lua/fzf-lua/config.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ function M.normalize_opts(opts, globals, __resume_key)
879879
opts.process1 = opts.process1 == nil and true or opts.process1
880880
-- We also want to store the cached extensions/filenames in the main thread
881881
-- which we do in "make_entry.postprocess"
882-
opts.__mt_postprocess = opts.multiprocess
882+
opts.fn_postprocess = opts.multiprocess
883883
and [[return require("fzf-lua.make_entry").postprocess]]
884884
-- NOTE: we don't need to update mini when running on main thread
885885
-- or require("fzf-lua.make_entry").postprocess
@@ -892,7 +892,7 @@ function M.normalize_opts(opts, globals, __resume_key)
892892
elseif opts.line_query then
893893
utils.map_set(opts, "winopts.preview.winopts.cursorline", true)
894894
utils.map_set(opts, "keymap.fzf.change",
895-
"transform:" .. FzfLua.shell.raw_action(function(q, _, _)
895+
"transform:" .. FzfLua.shell.stringify_data(function(q, _, _)
896896
local lnum = q[1]:match(":(%d+)$")
897897
local new_q, subs = q[1]:gsub(":%d*$", "")
898898
-- No subs made, no ":" at end of string, do nothing
@@ -906,7 +906,7 @@ function M.normalize_opts(opts, globals, __resume_key)
906906
trans = string.format("%s+change-preview-window(%s:%s)", trans, optstr, offset)
907907
end
908908
return trans
909-
end, "{q}", opts.debug))
909+
end, opts, "{q}"))
910910
end
911911

912912
if type(opts.enrich) == "function" then

lua/fzf-lua/core.lua

Lines changed: 24 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ local actions = require "fzf-lua.actions"
77
local win = require "fzf-lua.win"
88
local libuv = require "fzf-lua.libuv"
99
local shell = require "fzf-lua.shell"
10-
local make_entry = require "fzf-lua.make_entry"
11-
local base64 = require "fzf-lua.lib.base64"
12-
local serpent = require "fzf-lua.lib.serpent"
1310

1411
local M = {}
1512

@@ -161,48 +158,22 @@ M.fzf_exec = function(contents, opts)
161158
opts.fn_selected = opts.fn_selected or function(selected, o)
162159
actions.act(selected, o)
163160
end
164-
-- Contents sent to fzf can only be nil or a shell command (string)
165-
-- the API accepts both tables and functions which we "stringify"
166-
if not opts.fn_reload then
167-
opts.__contents = contents
168-
contents = shell.stringify(opts)
169-
end
170-
assert(contents == nil or type(contents) == "string", "contents must be of type string")
171-
-- setup as "live": disables fuzzy matching and reload the content
172-
-- every keystroke (query changed), utilizes fzf's 'change:reload'
173-
-- event trigger or skim's "interactive" mode
174-
if type(opts.fn_reload) == "string" then
175-
if not opts.fn_transform then
176-
-- TODO: add support for 'fn_transform' using 'mt_cmd_wrapper'
177-
-- functions can be stored using 'config.bytecode' which uses
178-
-- 'string.dump' to convert from function code to bytes
179-
opts.fn_reload = M.mt_cmd_wrapper(opts) or opts.fn_reload
180-
opts = M.setup_fzf_interactive_native(opts.fn_reload, opts)
181-
contents = opts.__fzf_init_cmd
182-
else
183-
-- the caller requested to transform, we need to convert
184-
-- to a function that returns string so that libuv.spawn
185-
-- is called
186-
local cmd = opts.fn_reload --[[@as string]]
187-
opts.fn_reload = function(q)
188-
if cmd:match(M.fzf_query_placeholder) then
189-
return cmd:gsub(M.fzf_query_placeholder, q or "")
190-
else
191-
return string.format("%s %s", cmd, q or "")
192-
end
193-
end
194-
end
195-
end
196-
if type(opts.fn_reload) == "function" then
197-
opts.__fn_transform = opts.fn_transform
198-
opts.__fn_reload = function(query)
199-
config.resume_set("query", query, opts)
200-
return opts.fn_reload(query)
201-
end
202-
opts = M.setup_fzf_interactive_wrap(opts)
161+
if opts.fn_reload then
162+
-- AKA "live": fzf acts as a selector only (fuzzy matching is disabled)
163+
-- each keypress reloads fzf's input usually based on the typed query
164+
-- utilizes fzf's 'change:reload' event or skim's "interactive" mode
165+
opts.fn_reload = shell.stringify(opts.fn_reload, opts)
166+
opts = M.setup_fzf_interactive_native(opts.fn_reload, opts)
203167
contents = opts.__fzf_init_cmd
168+
elseif contents then
169+
-- Contents sent to fzf can only be nil or a shell command (string)
170+
-- the API accepts both tables and functions which we "stringify"
171+
-- We also send string commands as stringify is also responsible
172+
-- for multiprocess wrapping of shell commands with processing
173+
contents = shell.stringify(contents, opts) or nil
204174
end
205-
return M.fzf_wrap(opts, contents)
175+
assert(contents == nil or type(contents) == "string", "contents must be of type string")
176+
return M.fzf_wrap(contents, opts)
206177
end
207178

208179
---@param contents string|fun(query: string): string|string[]|function
@@ -229,11 +200,11 @@ M.fzf_resume = function(opts)
229200
M.fzf_exec(config.__resume_data.contents, config.__resume_data.opts)
230201
end
231202

232-
---@param opts table
233203
---@param contents string?
204+
---@param opts table
234205
---@param fn_selected function?
235206
---@return thread
236-
M.fzf_wrap = function(opts, contents, fn_selected)
207+
M.fzf_wrap = function(contents, opts, fn_selected)
237208
opts = opts or {}
238209
local _co
239210
coroutine.wrap(function()
@@ -456,7 +427,7 @@ M.fzf = function(contents, opts)
456427
-- reminder: this doesn't get called with 'live_grep' when using skim
457428
-- due to a bug where '--print-query --interactive' combo is broken:
458429
-- skim always prints an empty line where the typed query should be.
459-
-- see additional note above 'opts.fn_post_fzf' inside 'live_grep_mt'
430+
-- see additional note above 'opts.fn_post_fzf' inside 'live_grep'
460431
config.resume_set("query", selected[1], opts)
461432
end
462433
table.remove(selected, 1)
@@ -625,7 +596,7 @@ M.create_fzf_binds = function(opts)
625596
v = v[1]
626597
elseif type(v) == "function" then
627598
if utils.has(opts, "fzf") then
628-
v = "execute-silent:" .. shell.raw_action(v, nil, opts.debug)
599+
v = "execute-silent:" .. shell.stringify_data(v, opts)
629600
else
630601
v = nil
631602
end
@@ -682,7 +653,7 @@ M.build_fzf_cli = function(opts, fzf_win)
682653
local preview_cmd
683654
local preview_spec = opts.fzf_opts["--preview"]
684655
if type(preview_spec) == "function" then
685-
preview_cmd = shell.raw_action(preview_spec, "{}", opts.debug)
656+
preview_cmd = shell.stringify_data(preview_spec, opts, "{}")
686657
elseif type(preview_spec) == "table" then
687658
preview_spec = vim.tbl_extend("keep", preview_spec, {
688659
fn = preview_spec.fn or preview_spec[1],
@@ -691,10 +662,9 @@ M.build_fzf_cli = function(opts, fzf_win)
691662
field_index = "{}",
692663
})
693664
if preview_spec.type == "cmd" then
694-
preview_cmd = shell.raw_preview_action_cmd(
695-
preview_spec.fn, preview_spec.field_index, opts.debug)
665+
preview_cmd = shell.stringify_cmd(preview_spec.fn, opts, preview_spec.field_index)
696666
else
697-
preview_cmd = shell.raw_action(preview_spec.fn, preview_spec.field_index, opts.debug)
667+
preview_cmd = shell.stringify_data(preview_spec.fn, opts, preview_spec.field_index)
698668
end
699669
end
700670
if preview_cmd then
@@ -785,132 +755,6 @@ M.build_fzf_cli = function(opts, fzf_win)
785755
return cli_args
786756
end
787757

788-
---@param opts table
789-
---@return string?
790-
M.mt_cmd_wrapper = function(opts)
791-
assert(opts and opts.cmd)
792-
---@param o table<string, unknown>
793-
---@return table
794-
local filter_opts = function(o)
795-
local names = {
796-
"debug",
797-
"profile",
798-
"process1",
799-
"silent",
800-
"argv_expr",
801-
"cmd",
802-
"cwd",
803-
"stdout",
804-
"stderr",
805-
"stderr_to_stdout",
806-
"formatter",
807-
"multiline",
808-
"git_dir",
809-
"git_worktree",
810-
"git_icons",
811-
"file_icons",
812-
"color_icons",
813-
"path_shorten",
814-
"strip_cwd_prefix",
815-
"exec_empty_query",
816-
"file_ignore_patterns",
817-
"rg_glob",
818-
"_base64",
819-
utils.__IS_WINDOWS and "__FZF_VERSION" or nil,
820-
}
821-
-- caller requested rg with glob support
822-
if o.rg_glob then
823-
table.insert(names, "glob_flag")
824-
table.insert(names, "glob_separator")
825-
end
826-
local t = {}
827-
for _, name in ipairs(names) do
828-
if o[name] ~= nil then
829-
t[name] = o[name]
830-
end
831-
end
832-
t.g = {}
833-
for k, v in pairs({
834-
["_fzf_lua_server"] = vim.g.fzf_lua_server,
835-
-- [NOTE] No longer needed, we use RPC for icons
836-
-- ["_devicons_path"] = devicons.plugin_path(),
837-
-- ["_devicons_setup"] = config._devicons_setup,
838-
["_EOL"] = opts.multiline and "\0" or "\n",
839-
["_debug"] = opts.debug,
840-
}) do
841-
t.g[k] = v
842-
end
843-
return t
844-
end
845-
846-
---@param obj table|string
847-
---@return string
848-
local serialize = function(obj)
849-
local str = type(obj) == "table"
850-
and serpent.line(obj, { comment = false, sortkeys = false })
851-
or tostring(obj)
852-
if opts._base64 ~= false then
853-
-- by default, base64 encode all arguments
854-
return "[==[" .. base64.encode(str) .. "]==]"
855-
else
856-
-- if not encoding, don't string wrap the table
857-
return type(obj) == "table" and str
858-
or "[==[" .. str .. "]==]"
859-
end
860-
end
861-
862-
if not opts.requires_processing
863-
and not opts.git_icons
864-
and not opts.file_icons
865-
and not opts.file_ignore_patterns
866-
and not opts.path_shorten
867-
and not opts.formatter
868-
and not opts.multiline
869-
then
870-
-- command does not require any processing, we also reset `argv_expr`
871-
-- to keep `setup_fzf_interactive_flags::no_query_condi` in the command
872-
opts.argv_expr = nil
873-
return opts.cmd
874-
elseif opts.multiprocess then
875-
assert(not opts.__mt_transform or type(opts.__mt_transform) == "string")
876-
assert(not opts.__mt_preprocess or type(opts.__mt_preprocess) == "string")
877-
assert(not opts.__mt_postprocess or type(opts.__mt_postprocess) == "string")
878-
if opts.argv_expr then
879-
-- Since the `rg` command will be wrapped inside the shell escaped
880-
-- '--headless .. --cmd', we won't be able to search single quotes
881-
-- as it will break the escape sequence. So we use a nifty trick:
882-
-- * replace the placeholder with {argv1}
883-
-- * re-add the placeholder at the end of the command
884-
-- * preprocess then replace it with vim.fn.argv(1)
885-
-- NOTE: since we cannot guarantee the positional index
886-
-- of arguments (#291), we use the last argument instead
887-
opts.cmd = opts.cmd:gsub(M.fzf_query_placeholder, "{argvz}")
888-
end
889-
local cmd = libuv.wrap_spawn_stdio(
890-
serialize(filter_opts(opts)),
891-
serialize(opts.__mt_transform or [[return require("fzf-lua.make_entry").file]]),
892-
serialize(opts.__mt_preprocess or [[return require("fzf-lua.make_entry").preprocess]]),
893-
serialize(opts.__mt_postprocess or "nil")
894-
)
895-
if opts.argv_expr then
896-
-- prefix the query with `--` so we can support `--fixed-strings` (#781)
897-
cmd = string.format("%s -- %s", cmd, M.fzf_query_placeholder)
898-
end
899-
return cmd
900-
else
901-
assert(not opts.__fn_transform or type(opts.__fn_transform) == "function")
902-
assert(not opts.__fn_preprocess or type(opts.__fn_preprocess) == "function")
903-
assert(not opts.__fn_postprocess or type(opts.__fn_postprocess) == "function")
904-
opts.__fn_transform = opts.__fn_transform == nil
905-
and function(x) return make_entry.file(x, opts) end
906-
or opts.__fn_transform
907-
opts.__fn_preprocess = opts.__fn_preprocess == nil
908-
and function(o) return make_entry.preprocess(o) end
909-
or opts.__fn_preprocess
910-
return nil
911-
end
912-
end
913-
914758
-- given the default delimiter ':' this is the
915759
-- fzf expression field index for the line number
916760
-- when entry format is 'file:line:col: text'
@@ -1136,7 +980,7 @@ local patch_shell_action = function(v, opts)
1136980
overide_f_idx = true
1137981
end
1138982
-- replace the action with shell cmd proxy to the original action
1139-
return shell.raw_action(function(items, _, _)
983+
return shell.stringify_data(function(items, _, _)
1140984
assert(field_index:match("^{q} {n}"))
1141985
local query, idx = unpack(items, 1, 2)
1142986
config.resume_set("query", query, opts)
@@ -1158,7 +1002,7 @@ local patch_shell_action = function(v, opts)
11581002
items = (zero_matched and zero_selected) and {} or items
11591003
end
11601004
v.fn(items, opts)
1161-
end, field_index, opts.debug)
1005+
end, opts, field_index)
11621006
end
11631007

11641008
-- converts actions defined with "reload=true" to use fzf's `reload` bind
@@ -1244,8 +1088,7 @@ M.convert_reload_actions = function(reload_cmd, opts)
12441088
-- NOTE: this fixes existence of both load as function and rebind, e.g. git_status with:
12451089
-- setup({ keymap = { fzf = { true, load = function() _G._fzf_load_called = true end } } }
12461090
if type(opts.keymap.fzf.load) == "function" then
1247-
opts.keymap.fzf.load = "execute-silent:" ..
1248-
shell.raw_action(opts.keymap.fzf.load, nil, opts.debug)
1091+
opts.keymap.fzf.load = "execute-silent:" .. shell.stringify_data(opts.keymap.fzf.load, opts)
12491092
end
12501093
if rebind and type(opts.keymap.fzf.load) == "string" then
12511094
return string.format("%s+%s", rebind, opts.keymap.fzf.load)
@@ -1411,18 +1254,6 @@ M.fzf_field_expression = function(opts)
14111254
return opts and opts.field_index or opts._is_skim and [["{}"]] or "{q}"
14121255
end
14131256

1414-
-- Sets up the flags and commands required for running a "live" interface
1415-
-- @param fn_reload :function called for reloading contents
1416-
-- @param fn_transform :function to transform entries when using shell cmd
1417-
M.setup_fzf_interactive_wrap = function(opts)
1418-
assert(opts and opts.__fn_reload)
1419-
1420-
-- neovim shell wrapper for parsing the query and loading contents
1421-
local fzf_field_expression = M.fzf_field_expression(opts)
1422-
local command = shell.stringify(opts, fzf_field_expression)
1423-
return M.setup_fzf_interactive_flags(command, fzf_field_expression, opts)
1424-
end
1425-
14261257
M.setup_fzf_interactive_native = function(command, opts)
14271258
local fzf_field_expression = M.fzf_field_expression(opts)
14281259

0 commit comments

Comments
 (0)