nvim-treesitter / nvim-treesitter/nvim-treesitter-textobjects

Delete @function.outer deletes more than it should

Open
#575 5 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Tree-sitter Query
Stars
2.8k
Forks
271
Avg merge
8d 8h
Merged PRs (30d)
1

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue in Neovim with the provided nvim-treesitter configuration and Python sample, starting from the @function.outer selection used by daf. Inspect how linewise selection and include_surrounding_whitespace determine the range. Done means deleting lines 17–20 while leaving line 22 intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua, neovim, python
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.