Skip to content

[mini.operators] some operators have issues with newlines at start/end of textobject #2247

@TheLeoP

Description

@TheLeoP

Contributing guidelines

Module(s)

mini.operators

Neovim version

0.11.x

Description

Using both mini.ai (not required, but allows better control/knowledge of how the textobjects for the operators are selected) and mini.operators default configuration, given the buffer

foo(
  a,
  b,
  c
)

, and with the cursor above a, doing yi) and then gri) results in the buffer

foo
  a,
  b,
  c

)

while I would expect it to result in the same buffer. Similar results can be seen with the multiply operator. gmi) results in

foo(
  a,
  b,
  c(
  a,
  b,
  c
)

note the ( after c that should not be part of the textobject.

This happens because in

if data.mode == 'visual' and vim.o.selection == 'exclusive' then
keys = ('`' .. mark_from) .. submode .. ('`' .. mark_to) .. ('"' .. register .. operator)
else
keys = ('`' .. mark_from) .. ('"' .. register .. operator .. submode) .. ('`' .. mark_to)
end

keys ends up being something similar to `["_dv`]. Then, when Neovim moves the cursor to the [ mark, since it isn't on visual mode and virtualedit default value is empty, instead of putting the cursor on the newline after (, the cursor is placed on the parenthesis itself.

This issue can be (partially) solved by temporarily changing virtualedit to onemore inside of

H.do_between_marks = function(operator, data)

(like it is already done on mini.ai for selecting a textobject). After that change, the first example no longer deletes the (, but it still duplicates the newline after c. So the end result is

foo(
  a,
  b,
  c

)

I've been look at it for a while, but I'm not sure as to why. Yanking (yi)) includes the trailing newline after c and mini.ai tries to move the cursor to {4, 4} when selecting the textobject. But, replacing gri)does not include the trailing newline after c when deleting the text. vim.api.nvim_buf_get_mark(0, ']') returns {4, 2} and `] moves the cursor up to c. So, my guess is that this second part of the issue may have something to do with Neovim internals (?

Reproduction

  1. Create separate 'nvim-repro' config directory:

    • '~/.config/nvim-repro/' on Unix
    • '~/AppData/Local/nvim-repro/' on Windows
  2. Inside 'nvim-repro' directory create a file named 'init.lua'.
    Populate it with the following content:

    -- Clone latest 'mini.nvim' (requires Git CLI installed)
    vim.cmd('echo "Installing `mini.nvim`" | redraw')
    local mini_path = vim.fn.stdpath("data") .. "/site/pack/deps/start/mini.nvim"
    local clone_cmd = { "git", "clone", "--depth=1", "https://github.com/nvim-mini/mini.nvim", mini_path }
    vim.fn.system(clone_cmd)
    vim.cmd('echo "`mini.nvim` is installed" | redraw')
    
    -- Make sure 'mini.nvim' is available
    vim.cmd("packadd mini.nvim")
    require("mini.deps").setup()
    
    -- Add extra setup steps needed to reproduce the behavior
    -- Use `MiniDeps.add('user/repo')` to install another plugin from GitHub
    
    require("mini.ai").setup()
    require("mini.operators").setup()
  3. Run NVIM_APPNAME=nvim-repro nvim (i.e. execute nvim with NVIM_APPNAME environment variable set to "nvim-repro").
    Wait for all dependencies to install.

  4. Insert the following text in the buffer

foo(
  a,
  b,
  c
)
  1. Put the cursor above a, yi) and gri)

The resulting buffer will be

foo
  a,
  b,
  c

)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions