cmp-cmdline icon indicating copy to clipboard operation
cmp-cmdline copied to clipboard

"E141: No file name for buffer nn" on attempt to exit

Open hirevue-brent opened this issue 4 years ago • 4 comments

Disclaimer: I'm not super familiar with lua or vimscript or the inner workings of vim. I just use vim a lot.

I recently setup neovim with nvim-cmp (love it! great work!). However, when I enable cmp-cmdline I can no longer exit vim with :wqa. I get the following error:

E141: No file name for buffer nn

Then I essentially have to :q! everything individually until I hit the last buffer which appears to be the options listed for cmp-cmdline.

I wanted to guess that the buffer wasn't set to nofile, but I cannot find where that would even happen. Is very possible its outside this plugin completely. However, when I disable this plugin I have no problem.

Steps to Repro:

  1. Set-up nvim-cmp using the recommended configuration here: https://github.com/hrsh7th/nvim-cmp
  2. Open two files (using :vs or :spl)
  3. Try to exit using :wqa (or :qa or :qa!)

Notice

E141: No file name for buffer 2 is shown

Expected

Vim would exit

hirevue-brent avatar Nov 01 '21 22:11 hirevue-brent

I can't reproduce this issue.

https://user-images.githubusercontent.com/629908/139784957-bfd480bf-76f5-44e8-881f-8acf9c017d74.mp4

hrsh7th avatar Nov 02 '21 04:11 hrsh7th

It seems to be an issue with the following config (I have the lines commented out that cause me trouble):

-- Use cmdline & path source for ':'.
cmp.setup.cmdline(':', {             
  sources = cmp.config.sources({     
    { name = 'path' }                
  -- }, {                            
  --  { name = 'cmdline' }           
  })                                 
})                                   

My minimal init.vim looks like this (just like the suggestion on the website, but with things commented out to avoid problem):

call plug#begin('~/.config/nvim/plugged')            
                                                                                                        
Plug 'neovim/nvim-lspconfig'                         
Plug 'hrsh7th/cmp-nvim-lsp'                          
Plug 'hrsh7th/cmp-buffer'                            
Plug 'hrsh7th/cmp-path'                              
"Plug 'hrsh7th/cmp-cmdline'                          
Plug 'hrsh7th/nvim-cmp'                              
                                                     
Plug 'hrsh7th/cmp-vsnip'                             
Plug 'hrsh7th/vim-vsnip'                             
                                                     
call plug#end()                                      
                                                     
set completeopt=menu,menuone,noselect                

lua <<EOF                                                                                                                              
  -- Setup nvim-cmp.                                                                                                                   
  local cmp = require'cmp'                                                                                                             
                                                                                                                                       
  cmp.setup({                                                                                                                          
    snippet = {                                                                                                                        
      expand = function(args)                                                                                                          
        vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.                                                                     
        -- require('luasnip').lsp_expand(args.body) -- For `luasnip` users.                                                            
        -- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.                                                               
        -- require'snippy'.expand_snippet(args.body) -- For `snippy` users.                                                            
      end,                                                                                                                             
    },                                                                                                                                 
    mapping = {                                                                                                                        
      ['<C-d>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),                                                              
      ['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),                                                               
      ['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),                                                               
      ['<C-y>'] = cmp.config.disable, -- If you want to remove the default `<C-y>` mapping, You can specify `cmp.config.disable` value.
      ['<C-e>'] = cmp.mapping({                                                                                                        
        i = cmp.mapping.abort(),                                                                                                       
        c = cmp.mapping.close(),                                                                                                       
      }),                                                                                                                              
      ['<CR>'] = cmp.mapping.confirm({ select = true }),                                                                               
    },                                                                                                                                 
    sources = cmp.config.sources({                                                                                                     
      { name = 'nvim_lsp' },                                                                                                           
      { name = 'vsnip' }, -- For vsnip users.                                                                                          
      -- { name = 'luasnip' }, -- For luasnip users.                                                                                   
      -- { name = 'ultisnips' }, -- For ultisnips users.                                                                               
      -- { name = 'snippy' }, -- For snippy users.                                                                                     
    }, {                                                                                                                               
      { name = 'buffer' },                                                                                                             
    })                                                                                                                                 
  })                                                                                                                                   
                                                                                                                                       
  -- Use buffer source for `/`.                                                                                                        
  cmp.setup.cmdline('/', {                                                                                                             
    sources = {                                                                                                                        
      { name = 'buffer' }                                                                                                              
    }                                                                                                                                  
  })                                                                                                                                   
                                                                                                                                       
  -- Use cmdline & path source for ':'.                                                                                                
  cmp.setup.cmdline(':', {                                                                                                             
    sources = cmp.config.sources({                                                                                                     
      { name = 'path' }                                                                                                                
    -- }, {                                                                                                                            
    --  { name = 'cmdline' }                                                                                                           
    })                                                                                                                                 
  })                                                                                                                                   
                                                                                                                                       
  -- Setup lspconfig.                                                                                                                  
  local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities())                        
  capabilities.textDocument.completion.completionItem.snippetSupport = true                                                            
  require('lspconfig').tsserver.setup {                                                                                                
    capabilities = capabilities                                                                                                        
  }                                                                                                                                    
  require('lspconfig').html.setup {                                                                                                    
    capabilities = capabilities                                                                                                        
  }                                                                                                                                    
EOF                                                                                                                                    

hirevue-brent avatar Nov 02 '21 15:11 hirevue-brent

I have the same issue with cmp, but not specifically cmp-cmdline. I'll post it here for now because I suspect it's the same underlying issue in cmp. Please let me know if you'd rather I open a new issue elsewhere.

When I :wall as part of my workflow, I get the same E141 re trying to save a buffer without a filename:

E141: No file name for buffer 24

:ls / :buffers does not list it, but :ls! / :buffers! does:

24u h + "[No Name]"                    line 1

I see the u means “unlisted buffers”, which explains why it doesn't list normally. And h is hidden (backgrounded), + is modified, and it has no filename.

When I switch to it with :b24 I see content like this:

func(s string) int
─────────────────────────────────────────────
"Safe" parseint for parsing ANSI instructions

That's the second-level popover describing an auto-complete option from LSP, for example:

image

On this occasion it's Go's gopls, but I have the same issue with all the LSP backends I use (e.g. Go, Ruby, Rust). I think the only unusual part of my workflow is frequent :wall while triggering async tests.

I'm happy to do more debugging, but I'm not very familiar with nvim/cmp internals.

Here's the LSP/cmp relevant part of my init.lua
----------
-- plugins

local lspconfig = require("lspconfig")
local capabilities = require("cmp_nvim_lsp").update_capabilities(vim.lsp.protocol.make_client_capabilities())
for _, server in ipairs({ "gopls", "rust_analyzer", "yamlls", "solargraph" }) do
  lspconfig[server].setup { capabilities = capabilities }
end

-- vim-go
require("lspconfig").gopls.setup{}
vim.g.go_auto_sameids = 1 -- highlight other instances of identifier under cursor
vim.g.go_updatetime = 200 -- delay (ms) for sameids, type_info etc (default 800)
vim.g.go_gopls_complete_unimported = 1 -- include suggestions from unimported packages

-- fzf
vim.api.nvim_set_keymap("n", "<C-p>", ":Files<CR>", {})

-- vim-asm_ca65
vim.g.asm_ca65_wdc = true
vim.cmd "filetype plugin indent on"
vim.cmd [[
  augroup filetypedetect
      autocmd BufEnter *.s setlocal filetype=asm_ca65 colorcolumn=17,41
      autocmd BufEnter *.s highlight ColorColumn ctermbg=232
      autocmd BufLeave *.s highlight ColorColumn ctermbg=0
  augroup END
]]

-- rust.vim
vim.g.rustfmt_autosave = true
require("lspconfig").rust_analyzer.setup{}

-- redhat-developer/yaml-language-store
require("lspconfig").yamlls.setup {
  settings = {
    yaml = {
      {schemaStore = {enable = true}},
    },
  }
}

-- ruby LSP
require("lspconfig").solargraph.setup {}

vim.opt.completeopt = "menu,menuone,noselect"

local cmp = require("cmp")
local luasnip = require("luasnip")
cmp.setup({
  snippet = {
    expand = function(args)
      luasnip.lsp_expand(args.body)
    end,
  },
  mapping = {
    ["<C-p>"] = cmp.mapping.select_prev_item(),
    ["<C-n>"] = cmp.mapping.select_next_item(),
    ["<C-d>"] = cmp.mapping.scroll_docs(-4),
    ["<C-f>"] = cmp.mapping.scroll_docs(4),
    ["<C-Space>"] = cmp.mapping.complete(),
    ["<C-e>"] = cmp.mapping.close(),
    -- ["<CR>"] = cmp.mapping.confirm {
    --   behavior = cmp.ConfirmBehavior.Replace,
    --   select = true,
    -- },
    ['<Tab>'] = function(fallback)
      if cmp.visible() then
        cmp.select_next_item()
      elseif luasnip.expand_or_jumpable() then
        luasnip.expand_or_jump()
      else
        fallback()
      end
    end,
    ['<S-Tab>'] = function(fallback)
      if cmp.visible() then
        cmp.select_prev_item()
      elseif luasnip.jumpable(-1) then
        luasnip.jump(-1)
      else
        fallback()
      end
    end,
  },
  sources = cmp.config.sources({
    { name = "nvim_lsp" },
    { name = 'luasnip' },
    { name = "buffer", option = {
      get_bufnrs = function() return vim.api.nvim_list_bufs() end
    }},
  })
})

pda avatar Aug 04 '22 11:08 pda

Hrmm, I can't reproduce it after restarting vim, but this does hit me most days.

My guess is that an unlisted scratch buffer is somehow losing its buftype=nofile Scratch status, and so it becomes a normal dirty buffer that requires saving before close. I don't know how it would be losing buftype=nofile though. Maybe some kind of race condition?

I had been trying to fix it by :bd 24 the buffer, but finding it stuck again the next time an auto-complete pops up. Having read the :bdelete manual more closely, that makes sense:

Actually, the buffer isn't completely deleted, it is removed from the buffer list |unlisted-buffer| and option values, variables and mappings/abbreviations for the buffer are cleared.

So for an already-unlisted buffer, all it was doing was clearing the unsaved changes, but presumably the same buffer gets reused for the next completion, and it remains in non-scratch state.

I suppose :bwipeout would be the more effective workaround short of restarting neovim.

I'll keep looking around and see what I can figure out.

(And apologies in advance if it turns out to be a problem unrelated to cmp…)

pda avatar Aug 04 '22 11:08 pda