Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete @function.outer deletes more than it should #575

Open
SamuelLarkin opened this issue Feb 27, 2024 · 5 comments
Open

Delete @function.outer deletes more than it should #575

SamuelLarkin opened this issue Feb 27, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@SamuelLarkin
Copy link

SamuelLarkin commented Feb 27, 2024

Describe the bug
After configuring daf to delete outer function lines, more than the function is deleted.

To Reproduce
Given LazyVim and the following snippet configuration

return {
  {
    -- [Linewise selections should include all empty lines below](https://github.com/nvim-treesitter/nvim-treesitter-textobjects/issues/307)
    -- [Treesitter text objects mapping not working or being overwritten](https://www.reddit.com/r/neovim/comments/12x8mbf/treesitter_text_objects_mapping_not_working_or/)
    -- [example config](https://github.com/augustocdias/dotfiles/blob/main/.config/nvim/lua/setup/treesitter.lua)
    "nvim-treesitter/nvim-treesitter",
    opts = {
      textobjects = {
        select = {
          enable = true,

          -- Automatically jump forward to textobj, similar to targets.vim
          lookahead = true,
          keymaps = {
            -- You can use the capture groups defined in textobjects.scm
            -- You can optionally set descriptions to the mappings (used in the desc parameter of
            -- nvim_buf_set_keymap) which plugins like which-key display
            ["aZ"] = "@function.outer",
            ["af"] = "@function.outer",
            ["if"] = "@function.inner",
            ["ac"] = "@class.outer",
            ["ic"] = { query = "@class.inner", desc = "Select inner part of a class region" },
            ["au"] = "@comment.outer",
            ["iu"] = "@comment.inner",
            ["ab"] = "@block.outer",
            ["ib"] = "@block.inner",
          },
          -- You can choose the select mode (default is charwise 'v')
          --
          -- Can also be a function which gets passed a table with the keys
          -- * query_string: eg '@function.inner'
          -- * method: eg 'v' or 'o'
          -- and should return the mode ('v', 'V', or '<c-v>') or a table
          -- mapping query_strings to modes.
          selection_modes = {
            ["@parameter.outer"] = "v", -- charwise
            ["@function.inner"] = "V", -- linewise
            ["@function.outer"] = "V", -- linewise
            ["@class.inner"] = "V", -- blockwise
            ["@class.outer"] = "V", -- blockwise
          },
          -- If you set this to `true` (default is `false`) then any textobject is
          -- extended to include preceding or succeeding whitespace. Succeeding
          -- whitespace has priority in order to act similarly to eg the built-in
          -- `ap`.
          --
          -- Can also be a function which gets passed a table with the keys
          -- * query_string: eg '@function.inner'
          -- * selection_mode: eg 'v'
          -- and should return true of false
          include_surrounding_whitespace = true,
        },
      },
    },
  },
}

And the following sample code

     1  #!/usr/bin/env python3
     2
     3
     4  class A:
     5      def a(self):
     6          pass
     7
     8
     9  def f1(a: int):
    10      a = 1
    11      pass
    12
    13
    14  def f2(a: int):
    15      a = 2
    16
    17      def ff2(b: int):
    18          b = 2
    19
    20          pass
    21
    22      pass
    23
    24
    25  if __name__ == "__main__":
    26      f1(1)
    27      f2(2)

if you go online :18 and press daf, you will delete

    17      def ff2(b: int):
    18          b = 2
    19
    20          pass
    21
    22      pass

Expected behavior
I'm expecting to delete exactly

    17      def ff2(b: int):
    18          b = 2
    19
    20          pass

the pass on line 22 should still be there after dap.

Output of :checkhealth nvim-treesitter

──────────────────────────────────────────────────────────────────────────────
nvim-treesitter: require("nvim-treesitter.health").check()

Installation

  • WARNING tree-sitter executable not found (parser generator, only needed for :TSInstallFromGrammar, not required for :TSInstall)
  • OK node found v21.1.0 (only needed for :TSInstallFromGrammar)
  • OK git executable found.
  • OK cc executable found. Selected from { vim.NIL, "cc", "gcc", "clang", "cl", "zig" }
    Version: cc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
  • OK Neovim was compiled with tree-sitter runtime ABI version 14 (required >=13). Parsers must be compatible with runtime ABI.

OS Info:
{
machine = "x86_64",
release = "5.4.0-132-generic",
sysname = "Linux",
version = "#148-Ubuntu SMP Mon Oct 17 16:02:06 UTC 2022"
}

Parser/Features H L F I J
- bash ✓ ✓ ✓ . ✓
- c ✓ ✓ ✓ ✓ ✓
- diff ✓ . . . .
- html ✓ ✓ ✓ ✓ ✓
- javascript ✓ ✓ ✓ ✓ ✓
- jsdoc ✓ . . . .
- json ✓ ✓ ✓ ✓ .
- jsonc ✓ ✓ ✓ ✓ ✓
- lua ✓ ✓ ✓ ✓ ✓
- luadoc ✓ . . . .
- luap ✓ . . . .
- markdown ✓ . ✓ ✓ ✓
- markdown_inline ✓ . . . ✓
- python ✓ ✓ ✓ ✓ ✓
- query ✓ ✓ ✓ ✓ ✓
- regex ✓ . . . .
- toml ✓ ✓ ✓ ✓ ✓
- tsx ✓ ✓ ✓ ✓ ✓
- typescript ✓ ✓ ✓ ✓ ✓
- vim ✓ ✓ ✓ . ✓
- vimdoc ✓ . . . ✓
- yaml ✓ ✓ ✓ ✓ ✓

Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections
       +) multiple parsers found, only one will be used
       x) errors found in the query, try to run :TSUpdate {lang}

Output of nvim --version

NVIM v0.9.5
Build type: Release
LuaJIT 2.1.1692716794

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/__w/neovim/neovim/build/nvim.AppDir/usr/share/nvim"

Run :checkhealth for more info

Additional context
Add any other context about the problem here.

@SamuelLarkin SamuelLarkin added the bug Something isn't working label Feb 27, 2024
@kiyoon
Copy link
Collaborator

kiyoon commented Feb 28, 2024

The problem is, if you set include_surrounding_whitespace = true and then use linewise mode, then it will try to include the whitespace before pass and then it will change into a line selection mode. That way the pass also gets deleted.

@kiyoon
Copy link
Collaborator

kiyoon commented Feb 28, 2024

A possible solution is to change the include_surrounding_whitespace mode to activate only when it is a char-wise selection mode.

@Akimcx
Copy link

Akimcx commented Mar 15, 2024

Another option would be to set the selection_modes of @function.outer to charwise, as it is the default. Therefore, it can be removed from the table. I encountered the same issue, and not only did this change fix it, but it also worked very well. If you set include_surrounding_whitespace to false, it will select the function from def to the first pass. Conversely, if you set it to true, it will select until the start of the second pass.

For reference
include_surrounding_whitespace = false

  |def ff2(b: int):
    b = 2
    
    pass|

include_surrounding_whitespace = true

  |def ff2(b: int):
    b = 2
  
    pass
    
  |pass

@mtrajano
Copy link

Changing @function.outer to charwise works for most operations (delete, yank, etc..) but it doesn't work with commenting actions (gc) since the cursor is still on the beginning of the next line and ends up commenting it out, for example (indentiation is important here) doing gcaf in fun1 (whether it's charwise or linewise):

    def fun1(self):
        pass

    def fun2(self):
        pass

becomes:

    # def fun1(self):
    #     pass

    # def fun2(self):
        pass

@mtrajano
Copy link

It is also better to yank/delete a method linewise to move it around. Yanking/deleteting it charwise results in weird indentation issues if you're not accounting for that. I have gotten it to work by adding a check if the selection mode is linewise to update the column end position to 0 before the update.selection call. Realize it's not the best solution but it seems to work well. I can get a pr out for this if the solution seems decent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants