wincent / command-t

⌨️ Fast file navigation for Neovim and Vim
BSD 2-Clause "Simplified" License
2.74k stars 317 forks source link

🆕 Command-T 6.0.0 release — compendium issue #393

Open wincent opened 1 year ago

wincent commented 1 year ago

Command-T 6.0.0

Now, this is a beta release (see |command-t-known-issues|), a total rewrite, subject to change, incompletely documented, with known bugs and feature gaps. But, because the entire world installs Neovim plugins by pointing at HEAD of main, people are probably going to end up trying this whether they intend to or not.

So, this feedback issue is to gather together common questions and bug reports. I also created this discussion thread for folks who prefer that format.

Information to include when reporting issues

Summary

packer.nvim set-up

use {
  'wincent/command-t',
  run = 'cd lua/wincent/commandt/lib && make',
  setup = function ()
    vim.g.CommandTPreferredImplementation = 'lua'
  end,
  config = function()
    require('wincent.commandt').setup()
  end,
}

Via comment.

deathmaz commented 1 year ago

Hi, i tried to install new version with packer but having issues:

    use {
      'wincent/command-t',
      run = 'cd lua/wincent/commandt/lib && make',
      config = function()
        vim.g.CommandTPreferredImplementation = 'lua'
        require('wincent.commandt').setup({})
      end
    }

:checkhealth wincent.commandt

wincent.commandt: require("wincent.commandt.health").check()
========================================================================
  - INFO: Command-T version: 6.0.0-a.0

## Checking that C library has been built
  - INFO: Build directory is:
    /home/maz/.local/share/nvim/site/pack/packer/start/command-t/lua/wincent/commandt/lib
  - OK: library can be `require`-ed and functions called

## Checking for optional external dependencies
  - OK: (optional) `watchman` binary found
  - OK: (optional) `git` binary found
  - OK: (optional) `find` binary found
  - OK: (optional) `rg` binary found

but when i open neovim i get this message:

packer.nvim: Error running config for command-t: ...ack/packer/start/command-t/lua/wincent/commandt/init.lua:343: bad argument #1 to 'pairs' (table expected, got nil)

When calling :CommandT i get this:

Error executing Lua callback: .../start/command-t/lua/wincent/commandt/private/window.lua:131: Vim(let):E716: Key not present in Dictionary: "rhs"                                              
stack traceback:                                                                                                                                                                                
        [C]: in function 'nvim_set_current_win'                                                                                                                                                 
        .../start/command-t/lua/wincent/commandt/private/window.lua:131: in function 'focus'                                                                                                    
        .../start/command-t/lua/wincent/commandt/private/prompt.lua:148: in function 'show'                                                                                                     
        ...cker/start/command-t/lua/wincent/commandt/private/ui.lua:133: in function 'show'                                                                                                     
        ...ack/packer/start/command-t/lua/wincent/commandt/init.lua:113: in function 'file_finder'                                                                                              
        ...im/site/pack/packer/start/command-t/plugin/command-t.lua:36: in function <...im/site/pack/packer/start/command-t/plugin/command-t.lua:35>

My neovim is on https://github.com/neovim/neovim/commit/09c6ce8c4e4c6415cca9b834539ed0df461373f6

wincent commented 1 year ago

Thanks for the report @deathmaz; it doesn't like the empty table passed to setup(). This is a bug, which I'll push a fix for presently. In the meantime, you can work around it by inserting a finders key into the setup; eg:

require('wincent.commandt').setup({finders = {}})
wincent commented 1 year ago

Should be fixed in e59f7406a565b574caabb77ec8079e0ed180e3a9.

deathmaz commented 1 year ago

Thank you, it fixed the packer issue, but

Error executing Lua callback: .../start/command-t/lua/wincent/commandt/private/window.lua:131: Vim(let):E716: Key not present in Dictionary: "rhs"                                              
stack traceback:                                                                                                                                                                                
        [C]: in function 'nvim_set_current_win'                                                                                                                                                 
        .../start/command-t/lua/wincent/commandt/private/window.lua:131: in function 'focus'                                                                                                    
        .../start/command-t/lua/wincent/commandt/private/prompt.lua:148: in function 'show'                                                                                                     
        ...cker/start/command-t/lua/wincent/commandt/private/ui.lua:133: in function 'show'                                                                                                     
        ...ack/packer/start/command-t/lua/wincent/commandt/init.lua:113: in function 'file_finder'                                                                                              
        ...im/site/pack/packer/start/command-t/plugin/command-t.lua:36: in function <...im/site/pack/packer/start/command-t/plugin/command-t.lua:35>                                            

still remains

EDIT: this happens right after i call :CommandT

wincent commented 1 year ago

Going to grab a fresher build of Neovim and see if I can repro. I'll keep you posted @deathmaz.

wincent commented 1 year ago

I got a new build (after a bit of help here) but it doesn't repro for me with HEAD of Neovim's master, so it's not version-related.

I think the stack trace may be a bit misleading here because an error message like:

E716: Key not present in Dictionary: "rhs"

is the kind of thing you would expect to see when accessing a missing key in a Vimscript dictionary, like this:

:echo {}['rhs']

But that's obviously not happening here directly (there are no Vimscript calls). What I suspect is happening is that the topmost line in the stack trace is causing a new window to gain focus:

vim.api.nvim_set_current_win(self._main_window)

and then some autocmd is firing, and that's where the error is being thrown. The kinds of failure mode you expect from a bad call to nvim_set_current_win() are more like this:

:lua vim.api.nvim_set_current_win('garbage')
E5108: Error executing lua [string ":lua"]:1: Expected Lua number
:lua vim.api.nvim_set_current_win(nil)
E5108: Error executing lua [string ":lua"]:1: Expected Lua number
:lua vim.api.nvim_set_current_win({wat=true})
E5108: Error executing lua [string ":lua"]:1: Expected Lua number
:lua vim.api.nvim_set_current_win(100000000)
E5108: Error executing lua [string ":lua"]:1: Invalid window id: 100000000

@deathmaz do you have a copy of your dotfiles anywhere public so that I could try and repro this further locally?

deathmaz commented 1 year ago

no unfortunately, but i was able to find that https://github.com/jiangmiao/auto-pairs is causing the issue. If i disable the plugin, the issue is gone. I don't have any settings for the plugin, just use 'jiangmiao/auto-pairs' to install it

wincent commented 1 year ago

Interesting @deathmaz. I haven't reproduced this yet, but my working theory is that it's happening here in auto-pairs:

let info = maparg('<CR>', 'i', 0, 1)
if empty(info)
  let old_cr = '<CR>'
  let is_expr = 0
else
  let old_cr = info['rhs']
  " ... etc

It sees the <CR> mapping that Command-T sets up (insert mode), and that mapping doesn't have 'rhs' because it's actually a Lua callback. Passing in Lua callbacks to Neovim's vim.keymap.set() API is legit, so this seems like a bug in auto-pairs.

As a workaround, it may be possible to provide an override to the default mapping. But first, do something like this to confirm the theory:

require('wincent.commandt').setup({
  mappings = {
    i = {
      ['<CR>'] = false,
    },
  },
})

That will prevent the standard <CR> mapping from being created. You should be able to open :CommandT without it blowing up, although you won't be able to open a file; it will at least prove that the hypothesis is correct though. Then the challenge is to come up with an alternative mapping that has the same effect without using a Lua callback and therefore avoids triggering the bug in auto-pairs. This might be a bit tricky because the code that's doing the actual opening at the moment is private and can't be called externally... 🤔

In the meantime, you could assign a different mapping to open, just to see it working, like, for example:

require('wincent.commandt').setup({
  mappings = {
    i = {
      ['<CR>'] = false,
      ['<C-o>'] = 'open',
    },
  },
})
deathmaz commented 1 year ago

But first, do something like this to confirm the theory:

require('wincent.commandt').setup({
  mappings = {
    i = {
      ['<CR>'] = false,
    },
  },
})

yes, it worked indeed, I don't have the error any more

wincent commented 1 year ago

i guess you meant

Yes, I did. Thanks, @deathmaz.

Anyway, I did a little refactoring in 25ff997799bfc708d8c5d3a3198f78a67bc20fe8 that will allow you to work around the problem in auto-pairs by using a private API:

require('wincent.commandt').setup({
  mappings = {
    i = {
      ['<CR>'] = "<C-o>:lua require('wincent.commandt.private.ui').open('edit')<CR>",
    },
  },
})

Hopefully auto-pairs can be updated at some point so that this hack won't be needed any more (and that's why I'm not making this into an official API, as I don't want to permanently increase the API surface area; but FWIW, the internals probably aren't going to change that much — at least, I'll do my best not to change them). It's probably worth filing a bug report upstream in any case.

deathmaz commented 1 year ago

thank you, it seems that the plugin is not supported any more https://github.com/jiangmiao/auto-pairs/issues/309, i switched to https://github.com/windwp/nvim-autopairs instead. I think there's no need to produce workarounds in this case.

I have another question: each time i run :PackerCompile command i'm getting this message:

commandt.setup():                                                                                                                                                                               
  `commandt.setup()` was called after Ruby plugin setup has already run 
wincent commented 1 year ago

@deathmaz: These two files are in the plug-in:

  1. plugin/command-t.vim
  2. plugin/command-t.lua

Neovim will load them in that order — Vimscript always comes before Lua. So, in order to force the Lua to take precedence over the Ruby, you need call require('wincent.commandt').setup() before the Ruby has a chance to load. I would suggest moving your:

vim.g.CommandTPreferredImplementation = 'lua'

outside of the packer use callback, early on in your ~/.config/nvim/init.lua, but that's not quite enough... you would need to move the setup() call too, and I get why you can't do that without breaking from packer's intended usage patterns.

So, I think I need to soften this check:

https://github.com/wincent/command-t/blob/5390172818b6b582027e6803ad7602627dfa786e/lua/wincent/commandt/init.lua#L181-L186

🤔 — I think I can actually just drop it. As long as you hoist the vim.g.CommandTPreferredImplementation = 'lua' statement up outside of the packer callback, there won't be any unwanted messages, and everything should get initialized in the right way (ie. preferring Lua over Ruby).

Made that change in 05b434a7dd3e2963bf03d521da73e1ee20f2ce1c.

deathmaz commented 1 year ago

according to docs, packer has setup callback:

setup = string or function,  -- Specifies code to run before this plugin is loaded.

will it be fine to do like this:

    use {
      'wincent/command-t',
      run = 'cd lua/wincent/commandt/lib && make',
      setup = function ()
        vim.g.CommandTPreferredImplementation = 'lua'
      end,
      config = function()
        require('wincent.commandt').setup()
      end,
    }

or is it better to move vim.g.CommandTPreferredImplementation = 'lua' even before packer was initialised?

wincent commented 1 year ago

@deathmaz: You can try it from the setup callback and see if it works. If it doesn't work, you'll know because :CommandT will show the old Ruby UI instead of the Lua one, which is very visually different.

Hoisting the statement up is also fine, because all it is doing is setting a global variable with no immediate side-effects, which is basically "free" and won't slow down start-up in any measurable way (it probably takes about a microsecond to evaluate that statement, so there is not much benefit in deferring it).

deathmaz commented 1 year ago

thank you for the explanation, works fine with setup callback

vinitkumar commented 1 year ago

Hi @wincent.

I get this error:

Error detected while processing /Users/vinitkumar/.config/nvim/init.lua:
E5113: Error while calling lua chunk: /Users/vinitkumar/.config/nvim/lua/base.lua:43: module 'wincent.commandt' not found:
        no field package.preload['wincent.commandt']
        no file './wincent/commandt.lua'
        no file '/opt/homebrew/Cellar/luajit-openresty/2.1-20220411/share/luajit-2.1.0-beta3/wincent/commandt.lua'
        no file '/usr/local/share/lua/5.1/wincent/commandt.lua'
        no file '/usr/local/share/lua/5.1/wincent/commandt/init.lua'
        no file '/opt/homebrew/Cellar/luajit-openresty/2.1-20220411/share/lua/5.1/wincent/commandt.lua'
        no file '/opt/homebrew/Cellar/luajit-openresty/2.1-20220411/share/lua/5.1/wincent/commandt/init.lua'
        no file './wincent/commandt.so'
        no file '/usr/local/lib/lua/5.1/wincent/commandt.so'
        no file '/opt/homebrew/Cellar/luajit-openresty/2.1-20220411/lib/lua/5.1/wincent/commandt.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
        no file './wincent.so'
        no file '/usr/local/lib/lua/5.1/wincent.so'
        no file '/opt/homebrew/Cellar/luajit-openresty/2.1-20220411/lib/lua/5.1/wincent.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
        [C]: in function 'require'
        /Users/vinitkumar/.config/nvim/lua/base.lua:43: in main chunk
        [C]: in function 'require'
        /Users/vinitkumar/.config/nvim/init.lua:1: in main chunk
Press ENTER or type command to continue

Any ideas how to fix this?

This is how I installed it

diff --git a/lua/plugins.lua b/lua/plugins.lua
index 5655c32..898147c 100644
--- a/lua/plugins.lua
+++ b/lua/plugins.lua
@@ -43,5 +43,16 @@ packer.startup(function(use)
   use 'lewis6991/gitsigns.nvim'
   use 'dinhhuy258/git.nvim' -- For git blame & browse
        use 'tpope/vim-commentary'
+       use "ellisonleao/gruvbox.nvim"
+       use {
+               'wincent/command-t',
+               run = 'cd lua/wincent/commandt/lib && make',
+               setup = function ()
+                       vim.g.CommandTPreferredImplementation = 'lua'
+               end,
+               config = function()
+                       require('wincent.commandt').setup()
+               end,
+       }
 end)
wincent commented 1 year ago

Not a Packer user myself but that config looks right to me. I'm not familiar with how you're supposed to use it but the stack trace shows that it's looking for wincent.commandt in a bunch of places and finding it nowhere — is there some Packer command you have to run to get it to actually pull down the latest HEAD of main/master? (Like :PackerUpdate or something?)

@vinitkumar, can you verify that the file you're trying to require really is on the filesystem? Specifically lua/wincent/commandt/init.lua.

wincent commented 1 year ago

FWIW @vinitkumar, I just installed Packer in a VM and see the same error as you do if I run :PackerCompile. But if I run :PackerInstall, I see it download the Command-T source code and it works.

vinitkumar commented 1 year ago

Turns out I was loading in another file require('wincent.commandt').setup(), and that was causing the error.

Thanks for taking the time and effort to help out. I will test it out on my prod codebases and report bugs. Thanks 🙇🏼

deathmaz commented 1 year ago

Hi @wincent ,when i press Ctrl-w in nvim buffer in insert mode, it will delete the word, the same goes for example when i use https://github.com/ibhagwan/fzf-lua. But this is not the case for command-t. Should it be explicitly defined somehow?

wincent commented 1 year ago

when i press Ctrl-w in nvim buffer in insert mode, it will delete the word, the same goes for example when i use https://github.com/ibhagwan/fzf-lua. But this is not the case for command-t. Should it be explicitly defined somehow?

I'm not sure. This is because the prompt window in Command-T uses :set buftype=prompt. Try setting that in a normal Vim window and you'll see that <C-w> isn't mapped in that kind of window. Quoting :h prompt-buffer:

The CTRL-W key can be used to start a window command, such as CTRL-W w to
switch to the next window.  This also works in Insert mode (use Shift-CTRL-W
to delete a word). When leaving the window Insert mode will be stopped.  When
coming back to the prompt window Insert mode will be restored.

So... we could try to set up an override for the behavior that Vim wants, but I am not sure whether that would be a good idea or not. Would Shift-CTRL-W work for you @deathmaz?

deathmaz commented 1 year ago

thank you for the explanation. The thing is that i'm using kitty terminal and by default Shift-CTRL-W is mapped to close current kitty window. I checked how it's implemented in telescope and it seems they mapped <C-w> to execute <c-s-w>. I tried this for command-t:

        require('wincent.commandt').setup({
          mappings = {
            i = {
              ["<C-w>"] = "<c-s-w>"
            }
          }
        })

and it works fine at first sight

wincent commented 1 year ago

I tried this for command-t

Yep @deathmaz, I was going to suggest something like that. Not sure if we should make it the default or not, but I am leading towards "yes, we should".

yujinyuz commented 1 year ago

I had a similar issue with neo-tree and applied the fix inside nvim-autopairs.. it's quite weird though https://github.com/nvim-neo-tree/neo-tree.nvim/pull/376

wincent commented 1 year ago

Ok @deathmaz, @yujinyuz; seems reasonable; added to the default mappings in https://github.com/wincent/command-t/commit/1d40403af6ded306967024d0badf0fe7dba4b9b3.

vheon commented 1 year ago

If you try to run :CommandTGit in a directory which is not a git repo you get something like this

image

I guess in the old version it would fallback to the files scanner so now is a little uglier.

wincent commented 1 year ago

Yep, this is a known issue @vheon. There is no fallback implemented yet for any of these things. Possible failure modes include:

I had been postponing figuring out a solution for this because I wasn't sure what the best approach was. The problem is that the scanners all degrade "gracefully"; instead of returning errors, they effectively just return empty lists. As such, there are a number of main options, not necessarily mutually exclusive of one another:

  1. We teach the scanner_t type to include a status member that allows us to communicate something back to the callers.
  2. We teach the callers to interpret an empty result list as a cue to try again using a fallback mechanism; in an empty directory this would give a false negative but a relatively harmless one (ie. you might run :CommandTRipgrep in an empty folder, and Command-T would take that as a cue to try again with the standard scanner, which would of course also return an empty list).
  3. If we do "2", and maybe even if we don't, we may also want to swallow stderr so it doesn't leak back in any visible way (ie. that would mean changing a call to git ... into git ... 2> /dev/null etc). The only catch is that this may make trouble-shooting harder (users could edit out or change the redirect, I guess).
  4. We teach the callers to be a bit smarter before even trying to run a command that will definitely fail; eg. we might check to see if rg exists before trying to run it.

I haven't thought deeply on it, but I feel like "2" + "3" sound like a reasonable idea, for starters. We might later want to do "4". I don't find "1" very appealing at this stage.

wincent commented 1 year ago

I pushed https://github.com/wincent/command-t/commit/005b695588630b06f2cf15444858f3b4dd320242 to implement a couple of those fallback ideas (specifically "2" and "3", like I said). Not sure if it's the best approach, but it's worth a shot. 🤷

vheon commented 1 year ago

My initial thoughts were simply to not let the error be displayed like that and maybe push a message through vim.notify, but before reading the code I thought that you were spawning the process from Lua through the job api and then send the candidates to the C code through the slab but I'm seeing now that your're calling the command in the C code directly so it wouldn't be that easy.

Anyway I'll give it a spin tomorrow at work, thanks for the quick response and fix!

vheon commented 1 year ago

@wincent before discovering the problem with scanners.git.untracked #405 I was puzzled because it was using the fallback to the find scanner but the title in the Prompt window was kept as git. Do you think command-t should signal somehow that the candidates I'm seeing are not coming from the scanner I asked for but that it fallback to something else?

wincent commented 1 year ago

@vheon: I had thought about that while implementing the fallback, but didn't want to make any hasty decisions. Like, should the title include the word "fallback" to make it clear why the "wrong" scanner is being used? Would an :echomsg be better? Should it be displayed in some other way? I agree with you that we should say something, but I wasn't sure what the best way to do that might be.

vheon commented 1 year ago

In an ideal world probably a user might want the title to say something like:

CommandT [ find (fall-backed from git) ]

So that I know what I ended up with and what I actually wanted to with a vim.notify saying why the first scanner wasn't usable. This way the notification about the error can be read if found relevant but the fact that we fall-backed is kept persistent in the Prompt title. Considering, however, that in a properly configured environment the fallback is rare to happen and that as you mentioned early the scanner is launched in the C code and we should have then a mechanism to pass the error to the Lua code I'm not sure if the whole notification is worth the trouble. I mean, yes it would be a much complete experience but the ROI isn't there I think.

wincent commented 1 year ago

@vheon Current proposal for communicating that a fallback happened is up in c16b2721fdad1d0bb108dc373c7d8977c7a6a5d6 — it just shows "fallback" in the end because I figure that we can't show complete diagnostic info in the title area, so there's not much value in saying more than that — it's just a cue that something didn't work. We can definitely looking at providing more detail via vim.notify() in the future though.

vinitkumar commented 1 year ago

@wincent Enjoying this plugin with my neovim. One small gripe(mostly because I couldn't find it in documentation), how do I make it ignore directories (e.g: node_modules)? It slows massively because it also indexes node_modules from my project.

vinitkumar commented 1 year ago

@wincent Enjoying this plugin with my neovim. One small gripe(mostly because I couldn't find it in documentation), how do I make it ignore directories (e.g: node_modules)? It slows massively because it also indexes node_modules from my project.

Alright, I think vim.cmd[[ let g:CommandTFileScanner = "git"]] is the way to go, or is there a better way for this?

wincent commented 1 year ago

@vinitkumar: If you're using the older Ruby implementation, there are a number of ways to ignore files. Using the git scanner is one of them (that's what your command does). If you have/use Watchman, using the watchman scanner is another option (depending on how it is configured it may or may not index node_modules, but the whole point of Watchman is to be fast regardless). Another is to configure g:CommandTWildIgnore or Vim's own 'wildignore' setting (as described in command-t-wildignore).

In the newer Lua implementation, similar story — you can use :CommandTGit or :CommandTRipgrep (which will all ignore similar files), or :CommandTWatchman (which is supposed to be fast by design). In general, the Lua implementation should be faster anyway — perhaps fast enough that you don't care about the cost of indexing/searching in node_modules. I haven't (yet) added any ignore-related settings in the Lua implementation; I might if there is demand for them (but my preference is to keep things simple — using the Git finder is a simple way to search only "noteworthy" files).

vinitkumar commented 1 year ago

@vinitkumar: If you're using the older Ruby implementation, there are a number of ways to ignore files. Using the git scanner is one of them (that's what your command does). If you have/use Watchman, using the watchman scanner is another option (depending on how it is configured it may or may not index node_modules, but the whole point of Watchman is to be fast regardless). Another is to configure g:CommandTWildIgnore or Vim's own 'wildignore' setting (as described in command-t-wildignore).

In the newer Lua implementation, similar story — you can use :CommandTGit or :CommandTRipgrep (which will all ignore similar files), or :CommandTWatchman (which is supposed to be fast by design). In general, the Lua implementation should be faster anyway — perhaps fast enough that you don't care about the cost of indexing/searching in node_modules. I haven't (yet) added any ignore-related settings in the Lua implementation; I might if there is demand for them (but my preference is to keep things simple — using the Git finder is a simple way to search only "noteworthy" files).

I am using lua implementation. Perhaps, I will peek into your nvim config and see what you have done?

wincent commented 1 year ago

@vinitkumar

I am using lua implementation. Perhaps, I will peek into your nvim config and see what you have done?

Ah, there is nothing to configure if you want to use the Git finder. Just invoke :CommandTGit instead of :CommandT. If you want to set up a mapping for that, something like this would do:

vim.keymap.set('n', '<Leader>t', '<Plug>(CommandTGit)')

This is (kind of) documented here.

vheon commented 1 year ago

@wincent I'm not sure if this is actually a bug or if simply I'm not used to the sorter engine of Command-T:

I'm "working" on my dotfiles (https://github.com/vheon/home) using the git scanner with this configuration https://github.com/vheon/home/blob/137693a1866da57f026231b55b4423efdffee81b/roles/neovim/files/nvim/lua/plugins.lua#L175-L180

If in the root directory I run :CommandTGit and search for tmux this is what I get

image

but if I search for .tmux this is what I get

image

Is it on purpose?

wincent commented 1 year ago

@vheon Yes, dotfiles are ignored by default. There are two settings that change this behavior:

With these defaults, you don't see the dotfiles unless your query includes the dot. With always_show_dot_files = true, you will see them regardless of the query. With never_show_dot_files = true, you won't see them even if your query includes a dot. Setting both to true doesn't make any sense, and Command-T will print an error if you try to do so.

vheon commented 1 year ago

As usual the RTFM would have solved my confusion without making noise here 😞 Thanks @wincent!

LunarWatcher commented 7 months ago

Interesting [@]deathmaz. I haven't reproduced this yet, but my working theory is that it's happening here in auto-pairs:

let info = maparg('<CR>', 'i', 0, 1)
if empty(info)
  let old_cr = '<CR>'
  let is_expr = 0
else
  let old_cr = info['rhs']
  " ... etc

It sees the <CR> mapping that Command-T sets up (insert mode), and that mapping doesn't have 'rhs' because it's actually a Lua callback. Passing in Lua callbacks to Neovim's vim.keymap.set() API is legit, so this seems like a bug in auto-pairs.

@wincent For the record, you were mostly correct.

I stumbled into this independently a while ago (I maintain a fork of jiangmiao/auto-pairs, where the bug was triggered by lsp-zero), and opened an issue about it in the nvim repo. Strictly speaking, it's neovim that's at fault here. Yes, mapping Lua callbacks is valid, but Neovim mishandles how the callbacks are represented in a different API call, and also failed to document it. Nvim can either fix it to make the return values consistent, or document the actual behaviour of maparg() in nvim (the latter of which would be an incompatibility that's incredibly annoying to integrate into a plugin that isn't exclusively for nvim, but whatever; problem for future me if the issue ever gets handled).

Because an existing API function's return values isn't respected (nor is the outlier documented, making workarounds annoying on a good day), and lua function mappings don't return a value compatible with maparg()'s docs, the function explodes. Until the exact behaviour is documented (i.e. the behaviour is documented so the function can be considered stable again), or maparg is fixed, the bug is in Neovim, just elsewhere. I doubt it's going to be fixed any time soon though.

There are a few workarounds though, one of which you've already found; mapping it to something other than a lua function is fine, because that returns a valid value from maparg.

However, due to the nature of command-t, I'll argue disabling auto-pairs, or at least the cr map, in the command-t buffer is a good strategy. No mapping means no weird return values, and I doubt command-t benefits from the <cr> map in auto-pairs anyway.

With jiangmiao, I'd recommend running let b:autopairs_map_cr = 0 . If not in command-t itself, an autocmd FileType for the end-user also works fine. It just needs to be executed before auto-pairs is run[^1]. Using let b:autopairs_loaded = 1 is also an option, and this fully prevents the plugin from loading.

My fork (which has the same problem) has a buffer filetype blacklist as well:

let g:AutoPairsFiletypeBlacklist = ["<insert command-T filetype here>"]

and works similarly to setting b:autopairs_loaded. The main advantage is that it can be set without waiting for the buffer to load, so no weird init order problems, if any exist. That said, my fork will complain loudly and explicitly (with some solutions) if rhs isn't present, so it's at least slightly more clear about the problem.

Anyway, welcome to the world of trying to map common keys (cr, space, tab, and backspace) in Vim - it sucks :p

[^1]: If command-t executes after auto-pairs, I assume it'll override <CR> instead, which is fine. The problem only appears when command-t, or any other plugin, maps a lua callback before auto-pairs tries to map <CR>. If the execution order is the other way around, it's not a problem.