142142--- @param _vimcmd string
143143--- @param selected string[]
144144--- @param opts fzf-lua.Config
145- --- @param pcall_vimcmd boolean ?
146145--- @return string ?
147- M .vimcmd_entry = function (_vimcmd , selected , opts , pcall_vimcmd )
146+ M .vimcmd_entry = function (_vimcmd , selected , opts )
148147 for i , sel in ipairs (selected ) do
149148 (function ()
150149 -- Lua 5.1 goto compatiblity hack (function wrap)
@@ -164,45 +163,9 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd)
164163 -- technically we should never get to the `uv.cwd()` fallback
165164 fullpath = path .join ({ opts .cwd or opts ._cwd or uv .cwd (), fullpath })
166165 end
167- -- always open files relative to the current win/tab cwd (#1854)
168- local relpath = path .relative_to (fullpath , uv .cwd ())
169- -- opts.__CTX isn't guaranteed by API users (#1414)
170- local CTX = opts .__CTX or utils .CTX ()
171- local target_equals_current =
172- (entry .bufnr and entry .bufnr == CTX .bufnr or path .equals (fullpath , CTX .bname ))
173- -- we open a new buffer on tabs so target is always different (#1785)
174- and not _vimcmd :match (" ^tabnew" )
175- local vimcmd = (function ()
176- -- Do not execute "edit" commands if we already have the same buffer/file open
177- -- or if we are dealing with a URI as it's open with `vim.lsp.util.show_document`
178- if _vimcmd == " <auto>" and (entry .uri or target_equals_current ) then
179- return nil
180- end
181- -- Same buffer splits and URI entries only execute the split cmd
182- -- after a split we land in the same buffer, remove the piped edit
183- -- e.g. "vsplit | e" -> "vsplit" (#1677)
184- if _vimcmd :match (" | <auto>" ) and (entry .uri or target_equals_current ) then
185- return _vimcmd :gsub (" | <auto>" , " " )
186- end
187- -- Replace "<auto>" based on entry being buffer or filename
188- return _vimcmd :gsub (" <auto>" , entry .bufnr and entry .bufname and " b" or " e" )
189- end )()
190- -- ":b" and ":e" commands replace the current buffer
191- local will_replace_curbuf = vimcmd == " e" or vimcmd == " b"
192- if will_replace_curbuf
193- and not vim .o .hidden
194- and not vim .o .autowriteall
195- and utils .buffer_is_dirty (nil , false , true ) then
196- -- when `:set nohidden`, confirm with the user when trying to switch
197- -- from a dirty buffer, abort if declined, save buffer if requested
198- if utils .save_dialog (nil ) then
199- vimcmd = vimcmd .. " !"
200- else
201- return
202- end
203- end
204- if will_replace_curbuf and utils .wo .winfixbuf
205- then
166+ -- <auto> (without prefix, formerly `:b|e`) replace the current buffer
167+ local vimcmd , will_replace_curbuf = _vimcmd , _vimcmd == " <auto>"
168+ if will_replace_curbuf and utils .wo .winfixbuf then
206169 utils .warn (" 'winfixbuf' is set for current window, will open in a split." )
207170 vimcmd = " split | " .. vimcmd
208171 end
@@ -213,29 +176,53 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd)
213176 vim .cmd (" normal! m`" )
214177 end
215178 if vimcmd then
216- -- Killing term buffers requires "!" (#1078 )
217- if entry . terminal and vimcmd == " bd " then
218- vimcmd = vimcmd .. " ! "
219- end
179+ local cmd , is_buf_edit = vimcmd : gsub ( " |?%s-<auto>$ " , " " )
180+ -- Command could have been "<auto>", in which case do nothing
181+ -- as we only have to load the buffer into the current window
182+ if # cmd > 0 then vim . cmd ( cmd ) end
220183 -- URI entries only execute new buffers (new|vnew|tabnew)
221- if not entry .uri and not target_equals_current then
222- -- Force full paths when `autochdir=true` (#882)
223- vimcmd = string.format (" %s %s" , vimcmd , (function ()
224- -- `:argdel|:argadd` uses only paths
225- -- argdel only accepts relative path (#1949)
226- if vimcmd :match (" ^arg" ) then return path .relative_to (entry .path , uv .cwd ()) end
227- if entry .bufnr then return tostring (entry .bufnr ) end
184+ -- and later use `utils.jump_to_location` to load the buffer
185+ if not entry .uri and is_buf_edit > 0 then
186+ local bufnr = (function ()
187+ -- Is the requested buffer is already loaded by the (split) command?
188+ local curbuf = vim .api .nvim_win_get_buf (0 )
189+ local curbname = vim .api .nvim_buf_get_name (curbuf )
190+ if entry .bufnr == curbuf or path .equals (curbname , fullpath ) then return end
191+ -- Entry always contains bufnr
192+ if entry .bufnr then return entry .bufnr end
193+ -- Always open files relative to the current win/tab cwd (#1854)
228194 -- We normalize the path or Windows will fail with directories starting
229195 -- with special characters, for example "C:\app\(web)" will be translated
230196 -- by neovim to "c:\app(web)" (#1082)
231- return vim .fn .fnameescape (path .normalize (relpath ))
232- end )())
233- end
234- if pcall_vimcmd ~= false then
235- local ok , err = pcall (function () vim .cmd (vimcmd ) end )
236- if not ok then utils .error (" ':%s' failed: %s" , vimcmd , err ) end
237- else
238- vim .cmd (vimcmd )
197+ local relpath = path .normalize (path .relative_to (fullpath , uv .cwd ()))
198+ local bufnr = vim .fn .bufadd (relpath )
199+ if bufnr == 0 and not opts .silent then
200+ utils .warn (" Unable to add buffer %s" , relpath )
201+ return
202+ else
203+ vim .bo [bufnr ].buflisted = true
204+ return bufnr
205+ end
206+ end )()
207+ if tonumber (bufnr ) then
208+ -- If current buffer is an unnamed empty buffer (e.g. "new"), wipe on switch
209+ if will_replace_curbuf
210+ and vim .bo .buftype == " "
211+ and vim .bo .filetype == " "
212+ and vim .api .nvim_buf_line_count (0 ) == 1
213+ and vim .api .nvim_buf_get_lines (0 , 0 , - 1 , false )[1 ] == " "
214+ and vim .api .nvim_buf_get_name (0 ) == " "
215+ then
216+ vim .bo .bufhidden = " wipe"
217+ end
218+ vim .fn .bufload (bufnr )
219+ local ok , _ = pcall (vim .api .nvim_win_set_buf , 0 , bufnr )
220+ -- When `:set nohidden && set confirm`, neovim will invoke the save dialog
221+ -- and confirm with the user when trying to switch from a dirty buffer, if
222+ -- user cancelles the save dialog pcall will fail with:
223+ -- Vim:E37: No write since last change (add ! to override)
224+ if not ok then return end
225+ end
239226 end
240227 end
241228 -- Reload actions from fzf's (buf/arg del, etc) window end here
@@ -468,18 +455,29 @@ M.buf_del = function(selected, opts)
468455 end
469456end
470457
458+ local function arg_exec (cmd , selected , opts )
459+ for _ , sel in ipairs (selected ) do
460+ (function ()
461+ local entry = path .entry_to_file (sel , opts )
462+ local relpath = entry .bufname or entry .path
463+ assert (relpath , " entry doesn't contain filepath" )
464+ if not relpath then return end
465+ if path .is_absolute (relpath ) then
466+ relpath = path .relative_to (relpath , vim .uv .cwd ())
467+ end
468+ vim .cmd (cmd .. " " .. relpath )
469+ end )()
470+ end
471+ end
472+
471473M .arg_add = function (selected , opts )
472- local vimcmd = " argadd"
473- M .vimcmd_entry (vimcmd , selected , opts )
474+ arg_exec (" argadd" , selected , opts )
474475 --- @diagnostic disable-next-line : param-type-mismatch
475476 pcall (vim .cmd , " argdedupe" )
476477end
477478
478479M .arg_del = function (selected , opts )
479- local vimcmd = " argdel"
480- -- since we don't dedup argdel can fail if file is added
481- -- more than once into the arglist
482- M .vimcmd_entry (vimcmd , selected , opts , true )
480+ arg_exec (" argdel" , selected , opts )
483481end
484482
485483M .colorscheme = function (selected , opts )
0 commit comments