R-nvim / cmp-r

Completion source for nvim-cmp using R.nvim as backend.
GNU General Public License v3.0
19 stars 1 forks source link

latest update to nvim-cmp causes stack overflow crash #12

Closed PMassicotte closed 2 weeks ago

PMassicotte commented 3 weeks ago

I am getting a stack overflow when I am trying to use completion since the latest update of nvim-cmp (https://github.com/hrsh7th/nvim-cmp/commits/main/).

...e/.local/share/nvim/lazy/nvim-cmp/lua/cmp/utils/misc.lua:177: stack overflow

Peek 2024-10-22 15-30

I am not sure how to debug that. Any ideas?

jalvesaq commented 3 weeks ago

I can't replicate it.

jalvesaq commented 3 weeks ago

I have this in my ~/.Rprofile:

# Disable completion from the language server
options(languageserver.server_capabilities =
        list(completionProvider = FALSE,
             completionItemResolve = FALSE))
PMassicotte commented 3 weeks ago

I have the same. I will investigate.

PMassicotte commented 3 weeks ago

I have found that the overflow occurs in misc.lua in nvim-cmp.

---Copy table
---@generic T
---@param tbl T
---@return T
misc.copy = function(tbl)
  if type(tbl) ~= 'table' then
    return tbl
  end

  if islist(tbl) then
    local copy = {}
    for i, value in ipairs(tbl) do
      copy[i] = misc.copy(value)
    end
    return copy
  end

  local copy = {}
  for key, value in pairs(tbl) do
    copy[key] = misc.copy(value)
  end
  return copy
end

This loops infinitely with this table:

 :messages                                                                                                                  
{                                                                                                                          
  kind = "markdown",                                                                                                       
  value = 'function graphics::plot\n\n**The Default Scatterplot Function**\n\nDraw a scatter plot with decorations such as 
axes and titles in the active graphics window.\n\n---\n```r\nplot(x, y = NULL, type = "p", xlim = NULL, ylim = NULL, log = 
"", main = NULL, sub = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), axes = TRUE,\n  frame.plot, panel.first = NULL, pa
nel.last = NULL, asp = NA, xgap.axis = NA, ygap.axis = NA, ...)\n```\n'                                                    
}                                                                                                                          
copy                                                                                                                       
<1>{                                                                                                                       
  cls = "(",                                                                                                               
  documentation = {                                                                                                        
    kind = "markdown",                                                                                                     
    value = 'function graphics::plot\n\n**The Default Scatterplot Function**\n\nDraw a scatter plot with decorations such a
s axes and titles in the active graphics window.\n\n---\n```r\nplot(x, y = NULL, type = "p", xlim = NULL, ylim = NULL, log 
= "", main = NULL, sub = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), axes = TRUE,\n  frame.plot, panel.first = NULL, 
panel.last = NULL, asp = NA, xgap.axis = NA, ygap.axis = NA, ...)\n```\n'                                                  
  },                                                                                                                       
  env = "graphics",                                                                                                        
  items = { <table 1> },                                                                                                   
  kind = 3,                                                                                                                
  label = "plot",                                                                                                          
  sortText = "9",                                                                                                          
  textEdit = {                                                                                                             
    newText = "plot",                                                                                                      
    range = {                                                                                                              
      ["end"] = {                                                                                                          
        character = 1,                                                                                                     
        line = 0                                                                                                           
      },                                                                                                                   
      start = {                                                                                                            
        character = 0,                                                                                                     
        line = 0                                                                                                           
      }                                                                                                                    
    }                                                                                                                      
  }                                                                                                                        
}                                                                                                                          
copy                                                                                                                       
{                                                                                                                          
  kind = "markdown",                                                                                                       
  value = 'function graphics::plot\n\n**The Default Scatterplot Function**\n\nDraw a scatter plot with decorations such as 
axes and titles in the active graphics window.\n\n---\n```r\nplot(x, y = NULL, type = "p", xlim = NULL, ylim = NULL, log = 
"", main = NULL, sub = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), axes = TRUE,\n  frame.plot, panel.first = NULL, pa
nel.last = NULL, asp = NA, xgap.axis = NA, ygap.axis = NA, ...)\n```\n'                                                    
}                                                                                                                          
copy                                                                                                                       
<1>{                                                                                                                       
  cls = "(",                                                                                                               
  documentation = {                                                                                                        
    kind = "markdown",                                                                                                     
    value = 'function graphics::plot\n\n**The Default Scatterplot Function**\n\nDraw a scatter plot with decorations such a
s axes and titles in the active graphics window.\n\n---\n```r\nplot(x, y = NULL, type = "p", xlim = NULL, ylim = NULL, log 
= "", main = NULL, sub = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), axes = TRUE,\n  frame.plot, panel.first = NULL, 
panel.last = NULL, asp = NA, xgap.axis = NA, ygap.axis = NA, ...)\n```\n'                                                  
  },  

I am not sure what is going on. All other lsp (python, etc.) still work fine.

PMassicotte commented 3 weeks ago

More investigation.

At some point nvim-cmp receive this from cmp_r

Vim(lua):E5108: Error executing lua .../filoche/.local/share/nvim/lazy/cmp-r/lua/cmp_r/init.lua:552: bad argument #1 to 'gs
ub' (string expected, got nil)                                                                                             
stack traceback:                                                                                                           
^I[C]: in function 'gsub'                                                                                                  
^I.../filoche/.local/share/nvim/lazy/cmp-r/lua/cmp_r/init.lua:552: in function 'complete_cb'                               
^I[string ":lua"]:1: in main chunk                                                                                         
^I[C]: in function 'execute'                                                                                               
^I/home/filoche/.local/share/nvim/lazy/R.nvim/lua/r/job.lua:48: in function 'exec_stdout_cmd'                              
^I/home/filoche/.local/share/nvim/lazy/R.nvim/lua/r/job.lua:69: in function </home/filoche/.local/share/nvim/lazy/R.nvim/lu
a/r/job.lua:58>                                                                                                            
stack traceback:                                                                                                           
^I[C]: in function 'execute'                                                                                               
^I/home/filoche/.local/share/nvim/lazy/R.nvim/lua/r/job.lua:48: in function 'exec_stdout_cmd'                              
^I/home/filoche/.local/share/nvim/lazy/R.nvim/lua/r/job.lua:69: in function </home/filoche/.local/share/nvim/lazy/R.nvim/lu
a/r/job.lua:58>                                                                                                                                                                                                                            
PMassicotte commented 3 weeks ago

I found the problematic commit:

https://github.com/hrsh7th/nvim-cmp/commit/1a1d7ecb7355f1b2681182686b37d637c134651e

using this fixes the issue for now

    "hrsh7th/nvim-cmp",
    commit = "ae644feb7b67bf1ce4260c231d1d4300b19c6f30",
jalvesaq commented 3 weeks ago

plot appears twice in the completion list (one as a function of base and the other as part of graphics). Looking at problematic commit, the only thing that looks strange to me is lines 74-76 of lua/cmp/entry.lua:

    for k, v in pairs(completion_item) do
      self.completion_item[k] = v or self.completion_item[k]
    end

I have no familiarity with nvim-cmp code, but it seems that if v is nil, an old item will be used.

Anyway, I can't replicate the bug on my side.

jalvesaq commented 2 weeks ago

I fixed two bugs in the C code in the last commit.

After starting R and opening the Object Browser, the bugs could be replicated with the following code:

ddd <- data.frame(aa = 1, bb = 2)
rm(ddd)
x <- 1

Bug 1: The Object Browser wasn't updated after rm(ddd).

Bug 2: Invalid string received by lua/r/browser.lua after x <- 1.

Maybe the second bug was causing the stack overflow crash in cmp...

PMassicotte commented 2 weeks ago

ah nice, i am actively trying to debug this for the past hour. Have you created a branch?

PMassicotte commented 2 weeks ago

No luck, still having this when I hit enter on a completion selection

...e/.local/share/nvim/lazy/nvim-cmp/lua/cmp/utils/misc.lua:177: stack overflow    

I am trying to make a reproducible example with this

https://github.com/hrsh7th/nvim-cmp/blob/main/utils/vimrc.vim

PMassicotte commented 2 weeks ago

I am able to reproduce with this vimrc.vim

if has('vim_starting')
  set encoding=utf-8
endif
scriptencoding utf-8

if &compatible
  set nocompatible
endif

let s:plug_dir = expand('/tmp/plugged/vim-plug')
if !filereadable(s:plug_dir .. '/plug.vim')
  execute printf('!curl -fLo %s/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim', s:plug_dir)
endif

execute 'set runtimepath+=' . s:plug_dir
call plug#begin(s:plug_dir)

" Plugin list
Plug 'hrsh7th/nvim-cmp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/vim-vsnip'
Plug 'neovim/nvim-lspconfig'
Plug 'R-nvim/cmp-r'
Plug 'R-nvim/R.nvim'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}

call plug#end()
PlugInstall | quit

" Setup nvim-cmp
lua << EOF
local cmp = require("cmp")
cmp.setup {
  snippet = {
    expand = function(args)
      vim.fn["vsnip#anonymous"](args.body)
    end,
  },
  mapping = cmp.mapping.preset.insert({
   ["<C-n>"] = cmp.mapping.select_next_item(),
                    ["<C-p>"] = cmp.mapping.select_prev_item(),
                    ["<C-d>"] = cmp.mapping.scroll_docs(-4),
                    ["<C-f>"] = cmp.mapping.scroll_docs(4),
                    ["<C-Space>"] = cmp.mapping.complete({}),
                    ["<CR>"] = cmp.mapping.confirm({
                        behavior = cmp.ConfirmBehavior.insert,
                        select = false,
                    }),
                    ["<Tab>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.select_next_item()
                        -- elseif luasnip.expand_or_locally_jumpable() then
                        --     luasnip.expand_or_jump()
                        else
                            fallback()
                        end
                    end, { "i", "s" }),
                    ["<S-Tab>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.select_prev_item()
                        -- elseif luasnip.locally_jumpable(-1) then
                        --     luasnip.jump(-1)
                        else
                            fallback()
                        end
                    end, { "i", "s" }),
  }),
  sources = cmp.config.sources({
    { name = "nvim_lsp" },
    { name = "buffer" },
    { name = "cmp_r" },
  })
}

-- Configure cmp-r
require("cmp_r").setup({})
-- require("R.nvim").setup({})

-- Set up LSP with cmp capabilities
local capabilities = require('cmp_nvim_lsp').default_capabilities()

EOF

" Setup Treesitter
lua << EOF
require'nvim-treesitter.configs'.setup {
 ensure_installed = { "markdown", "markdown_inline", "r", "rnoweb", "yaml", "vim"},
  highlight = {
    enable = true, -- Enable syntax highlighting
  },
}
EOF

Then open a file like this

nvim -u ./vimrc.vim test.R
jalvesaq commented 2 weeks ago

Still no bug on my side with your vimrc.vim. Does it make any difference to delete the R.nvim cache?

cd ~/.cache
rm -rf R.nvim
PMassicotte commented 2 weeks ago

No luck either. With my minimal example, do you get any completion at all? And no crash?

jalvesaq commented 2 weeks ago

Yes, the completion works normally, and there is no crash.

PMassicotte commented 2 weeks ago

Very strange. This is starting nvim with nothing else. Maybe my nvim version? I will explore this.

PMassicotte commented 2 weeks ago

I tried both stable and nightly and same issue.

jalvesaq commented 2 weeks ago

A similar bug was already reported, but not reproducible https://github.com/hrsh7th/nvim-cmp/issues/1347

PMassicotte commented 2 weeks ago

I am updating lua, just in case, I am out of ideas.

jalvesaq commented 2 weeks ago

As far as I know, bugs such "stack overflow" or "buffer overflow" should only happen in languages with low-level access to memory management, such as C or C++. Other programming languages (Java, R, Python, Lua, etc...) protect their users from these bugs (they don't give users the power to create them).

Can you replicate the bug on a different machine?

PMassicotte commented 2 weeks ago

Can you replicate the bug on a different machine?

Yes. Both on at home and at job. Both on linux.

PMassicotte commented 2 weeks ago

As far as I know, bugs such "stack overflow" or "buffer overflow" should only happen in languages with low-level access to memory management, such as C or C++. Other programming languages (Java, R, Python, Lua, etc...) protect their users from these bugs (they don't give users the power to create them).

Makes sense.

The issue is that the table received here https://github.com/R-nvim/cmp-r/issues/12#issuecomment-2432002125 seems to contain indefinite number of entries and the copy function eventually crashes.

PMassicotte commented 2 weeks ago

More info.

The error originate from the call to copy here:

https://github.com/hrsh7th/nvim-cmp/blob/29fb4854573355792df9e156cb779f0d31308796/lua/cmp/core.lua#L436

  local completion_item = misc.copy(e.completion_item)

If I add a print statement

 print("confirm", vim.inspect(e.completion_item))
 local completion_item = misc.copy(e.completion_item)

I am getting this output (when I select lm from the completion menu).

 {                                                                                                               
  cls = "(",                                                                                                               
  documentation = {                                                                                                        
    kind = "markdown",                                                                                                     
    value = 'function stats::lm\n\n**Fitting Linear Models**\n\n`lm` is used to fit linear models, including multivariate o
nes. It can be used to carry out regression, single stratum analysis of variance and\nanalysis of covariance (although `aov
` may provide a more convenient interface for these).\n\n---\n```r\nlm(formula, data, subset, weights, na.action, method = 
"qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL,\n  offset, ...)\n```\n'         
  },                                                                                                                       
  env = "stats",                                                                                                           
  items = { <table 1> },                                                                                                   
  kind = 3,                                                                                                                
  label = "lm",                                                                                                            
  sortText = "9",                                                                                                          
  textEdit = {                                                                                                             
    newText = "lm",                                                                                                        
    range = {                                                                                                              
      ["end"] = {                                                                                                          
        character = 1,                                                                                                     
        line = 0                                                                                                           
      },                                                                                                                   
      start = {                                                                                                            
        character = 0,                                                                                                     
        line = 0                                                                                                           
      }                                                                                                                    
    }                                                                                                                      
  }                                                                                                                        
} 

This seems ok, the received table is only of length 1.

Now in https://github.com/hrsh7th/nvim-cmp/blob/29fb4854573355792df9e156cb779f0d31308796/lua/cmp/utils/misc.lua#L169,

misc.copy = function(tbl)
    if type(tbl) ~= "table" then
        return tbl
    end

    if islist(tbl) then
        local copy = {}
        -- print the length of the table
        print("Reveived table in misc.copy\n" .. vim.inspect(tbl))
        for i, value in ipairs(tbl) do
            copy[i] = misc.copy(value)
        end
        return copy
    end

    local copy = {}
    for key, value in pairs(tbl) do
        copy[key] = misc.copy(value)
    end
    return copy
end

If I print the content of the reveived tbl I have this that repeats indfinetly.

Reveived table in misc.copy                                                                                                
<1>{ {                                                                                                                     
    cls = "(",                                                                                                             
    documentation = {                                                                                                      
      kind = "markdown",                                                                                                   
      value = 'function stats::lm\n\n**Fitting Linear Models**\n\n`lm` is used to fit linear models, including multivariate
 ones. It can be used to carry out regression, single stratum analysis of variance and\nanalysis of covariance (although `a
ov` may provide a more convenient interface for these).\n\n---\n```r\nlm(formula, data, subset, weights, na.action, method 
= "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL,\n  offset, ...)\n```\n'       
    },                                                                                                                     
    env = "stats",                                                                                                         
    items = <table 1>,                                                                                                     
    kind = 3,                                                                                                              
    label = "lm",                                                                                                          
    sortText = "9",                                                                                                        
    textEdit = {                                                                                                           
      newText = "lm",                                                                                                      
      range = {                                                                                                            
        ["end"] = {                                                                                                        
          character = 2,                                                                                                   
          line = 0                                                                                                         
        },                                                                                                                 
        start = {                                                                                                          
          character = 0,                                                                                                   
          line = 0                                                                                                         
        }                                                                                                                  
      }                                                                                                                    
    }                                                                                                                      
  } }                                                                                                                      
Reveived table in misc.copy                                                                                                
<1>{ {                                                                                                                     
    cls = "(",                                                                                                             
    documentation = {                                                                                                      
      kind = "markdown",                                                                                                   
      value = 'function stats::lm\n\n**Fitting Linear Models**\n\n`lm` is used to fit linear models, including multivariate
 ones. It can be used to carry out regression, single stratum analysis of variance and\nanalysis of covariance (although `a
ov` may provide a more convenient interface for these).\n\n---\n```r\nlm(formula, data, subset, weights, na.action, method 
= "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL,\n  offset, ...)\n```\n'       
    },                                                                                                                     
    env = "stats",                                                                                                         
    items = <table 1>,                                                                                                     
    kind = 3,                                                                                                              
    label = "lm",                                                                                                          
    sortText = "9",                                                                                                        
    textEdit = {                                                                                                           
      newText = "lm",                                                                                                      
      range = {                                                                                                            
        ["end"] = {                                                                                                        
          character = 2,                                                                                                   
          line = 0                                                                                                         
        },                                                                                                                 
        start = {                                                                                                          
          character = 0,                                                                                                   
          line = 0  
          ....
          ...
          ...
jalvesaq commented 2 weeks ago

I can't imagine the infinite loop coming from the rnvimserver because it would exhaust the RAM and crash before sending the string to cmp. So, I think somehow cmp itself is creating the infinite loop. Could you try different cmp sort methods? I'm using this:

                sorting = {
                    comparators = {
                        cmp.config.compare.order,
                    },
                },
PMassicotte commented 2 weeks ago

I replaced my config with yours and still the same (but now the order is different).

Added 2 print statements here and I never receive the "Done copy" message.

    feedkeys.call("", "n", function()
        local ctx = context.new()
        print("confirm", vim.inspect(e.completion_item))
        local completion_item = misc.copy(e.completion_item)
        print("Done copy")
        if not completion_item.textEdit then
            completion_item.textEdit = {}
            local insertText = completion_item.insertText
            if misc.empty(insertText) then
                insertText = nil
            end
            completion_item.textEdit.newText = insertText or completion_item.word or completion_item.label
        end
        local behavior = option.behavior or config.get().confirmation.default_behavior
        if behavior == types.cmp.ConfirmBehavior.Replace then
            completion_item.textEdit.range = e.replace_range
        else
            completion_item.textEdit.range = e.insert_range
        end

        local diff_before = math.max(0, e.context.cursor.col - (completion_item.textEdit.range.start.character + 1))
        local diff_after = math.max(0, (completion_item.textEdit.range["end"].character + 1) - e.context.cursor.col)
        local new_text = completion_item.textEdit.newText
        completion_item.textEdit.range.start.line = ctx.cursor.line
        completion_item.textEdit.range.start.character = (ctx.cursor.col - 1) - diff_before
        completion_item.textEdit.range["end"].line = ctx.cursor.line
        completion_item.textEdit.range["end"].character = (ctx.cursor.col - 1) + diff_after
        if api.is_insert_mode() then
            if false then
                --To use complex expansion debug.
                vim.print({ -- luacheck: ignore
                    item = e.completion_item,
                    diff_before = diff_before,
                    diff_after = diff_after,
                    new_text = new_text,
                    text_edit_new_text = completion_item.textEdit.newText,
                    range_start = completion_item.textEdit.range.start.character,
                    range_end = completion_item.textEdit.range["end"].character,
                    original_range_start = e.completion_item.textEdit.range.start.character,
                    original_range_end = e.completion_item.textEdit.range["end"].character,
                    cursor_line = ctx.cursor_line,
                    cursor_col0 = ctx.cursor.col - 1,
                })
            end
            local is_snippet = completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet
            if is_snippet then
                completion_item.textEdit.newText = ""
            end
            vim.lsp.util.apply_text_edits({ completion_item.textEdit }, ctx.bufnr, "utf-8")

            local texts = vim.split(completion_item.textEdit.newText, "\n")
            vim.api.nvim_win_set_cursor(0, {
                completion_item.textEdit.range.start.line + #texts,
                (#texts == 1 and (completion_item.textEdit.range.start.character + #texts[1]) or #texts[#texts]),
            })
            if is_snippet then
                config.get().snippet.expand({
                    body = new_text,
                    insert_text_mode = completion_item.insertTextMode,
                })
            end
        else
            local keys = {}
            table.insert(
                keys,
                keymap.backspace(
                    ctx.cursor_line:sub(completion_item.textEdit.range.start.character + 1, ctx.cursor.col - 1)
                )
            )
            table.insert(
                keys,
                keymap.delete(ctx.cursor_line:sub(ctx.cursor.col, completion_item.textEdit.range["end"].character))
            )
            table.insert(keys, new_text)
            feedkeys.call(table.concat(keys, ""), "in")
        end
    end)

Ccing @yioneko and @hrsh7th just in case they have some ideas.

jalvesaq commented 2 weeks ago

Maybe this was caused by the bug fixed in the last R.nvim commit...

PMassicotte commented 2 weeks ago

No luck. Maybe I can close this if it is only me with this issue.

PMassicotte commented 2 weeks ago

I have added that to my init.lua

vim.cmd("set verbosefile=~/.config/nvim/nvimlog")
vim.cmd("set verbose=3")

I am getting this information on crash:

continuing in nvim_exec2() called at LspAttach Autocommands for "*":0-- INSERT --

 -- INSERT --
not found in runtime path: "ftplugin/cmp_menu[.]{vim,lua} ftplugin/cmp_menu_*.{vim,lua} ftplugin/cmp_menu/*.{vim,lua}"
not found in runtime path: "indent/cmp_menu[.]{vim,lua}"
not found in runtime path: "parser/cmp_menu.*"-- INSERT --

-- INSERT --
not found in runtime path: "ftplugin/cmp_docs[.]{vim,lua} ftplugin/cmp_docs_*.{vim,lua} ftplugin/cmp_docs/*.{vim,lua}"
not found in runtime path: "indent/cmp_docs[.]{vim,lua}"
not found in runtime path: "parser/cmp_docs.*"
line 0: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/lsp_markdown.vim"
line 8: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/markdown.vim"
line 21: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/html.vim"
line 23: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/xml.vim"
line 301: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/dtd.vim"
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/dtd.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/xml.vim
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/xml.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/html.vim
line 273: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/javascript.vim"
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/javascript.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/html.vim
line 298: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/vb.vim"
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/vb.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/html.vim
line 308: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/css.vim"
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/css.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/html.vim
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/html.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/markdown.vim
line 142: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/yaml.vim"
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/yaml.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/markdown.vim
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/markdown.vim
continuing in /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/lsp_markdown.vim
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/lsp_markdown.vim
continuing in nvim_exec2()
line 0: sourcing "/home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/r.vim"
finished sourcing /home/filoche/.local/share/bob/v0.10.2/share/nvim/runtime/syntax/r.vim
continuing in nvim_exec2()-- INSERT --

vim/shared.lua:0: stack overflow-- INSERT --
jalvesaq commented 2 weeks ago

We can't the issue before it's fixed. Did you try using the minimal configuration from the Wiki?

PMassicotte commented 2 weeks ago

We can't the issue before it's fixed. Did you try using the minimal configuration from the Wiki?

Not yet. I made my own for eventually open an issue on nvim-cmp. I will try it and see if I have the same issue.

PMassicotte commented 2 weeks ago

Same issue with the minimal config.

Peek 2024-10-30 09-23

emeralit commented 2 weeks ago

@PMassicotte you are not alone. I have the same bug and I use your workaround for now.

jalvesaq commented 2 weeks ago

You can try making these changes:

diff --git a/lua/cmp_r/init.lua b/lua/cmp_r/init.lua
index 9670b90..8b8a770 100644
--- a/lua/cmp_r/init.lua
+++ b/lua/cmp_r/init.lua
@@ -531,6 +531,7 @@ end
 ---the data to rnvimserver which calls back this function.
 ---@param txt string The text almost ready to be displayed.
 source.resolve_cb = function(txt)
+    vim.fn.writefile({ "", vim.inspect(txt) }, "/tmp/cmp_r_resolve_log", "a")
     local s = fix_doc(txt)
     if last_compl_item.def then
         s = last_compl_item.label .. fix_doc(last_compl_item.def) .. "\n---\n" .. s
@@ -546,6 +547,7 @@ end
 ---@param compl table The completion data.
 source.complete_cb = function(cid, compl)
     if cid ~= compl_id then return nil end
+    vim.fn.writefile({ "", vim.inspect(compl) }, "/tmp/cmp_r_complete_log", "a")

     local resp = {}
     for _, v in pairs(compl) do

Then, look at the log files and try to find something strange. To follow the log files as more lines are appended:

tail -f /tmp/cmp_r_resolve_log
PMassicotte commented 2 weeks ago

When I try to complete with selecting lm()

cmp_r_complete_log.txt cmp_r_resolve_log.txt

jalvesaq commented 2 weeks ago

After replacing \@ with \r and formatting, cmp_r_complete_log.txt becomes:

{
    { cls = "(", env = "nvimcom", label = "etags2ctags" },
    { cls = "(", env = "nvimcom", label = "nvim.interlace.rmd" },
    { cls = "(", env = "nvimcom", label = "nvim.interlace.rnoweb" },
   --- 2552 lines omitted
    { cls = "(", env = "base", label = "xtfrm.POSIXlt" },
    { cls = "(", env = "base", label = "xzfile" },
    { cls = "(", env = "base", label = "zapsmall" }
}

No visible problem.

After replacing \20 with \r and formatting, cmp_r_resolve_log.txt becomes the following text wrapped by single quotes:

function stats::lm

**Fitting Linear Models**

`lm` is used to fit linear models, including multivariate ones. It can be used to carry out regression, single stratum analysis of variance and
analysis of covariance (although `aov` may provide a more convenient interface for these).

---
```r
lm(formula, data, subset, weights, na.action, method = "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL,
  offset, ...)


It's just a valid Markdown text. The `---` line is replaced with a horizontal line by `nvim-cmp`.
jalvesaq commented 2 weeks ago

In the Lua table from cmp_r_complete_log.txt, the following labels are repeated:

My guess is that nvim-cmp is failing in some systems (perhaps depending on the Lua engine installed) when there are repeated labels, and the reason would be what I said on https://github.com/R-nvim/cmp-r/issues/12#issuecomment-2432659229

In the past, BSD users have fixed bugs in the C code of nvimcom that only affected them because BSD has a somewhat more secure system, and it seems that macOS inherits some BSD features. So, perhaps some Lua engines are less tolerant of repeated labels than others.

But if repeated labels were the problem, there should be no stack overflow when completing lm because there is no repeated label beginning with the letter "L".

Conclusion: "I know that I know nothing".

PMassicotte commented 2 weeks ago

That seems to be a not so easy issue to fix. Thank you for looking at it. I will continue to investigate and report back if I find a solution.

hrsh7th commented 2 weeks ago

IMO, this issue should be fixed with this.

https://github.com/hrsh7th/nvim-cmp/pull/2076

emeralit commented 2 weeks ago

Thanks you @hrsh7th. The last commit solved the issue.

PMassicotte commented 2 weeks ago

IMO, this issue should be fixed with this.

hrsh7th/nvim-cmp#2076

Thank you very much @hrsh7th , this solved it. Thank for the great plugin.