nvim-treesitter / nvim-treesitter-textobjects

Apache License 2.0
2.11k stars 190 forks source link

Jumping to next sibling key in dictionary #183

Open fenuks opened 2 years ago

fenuks commented 2 years ago

Is your feature request related to a problem? Please describe. Following examples are for python, but it applies to many languages.

Let's say I have large nested dictionary, e.g :

a = {
    "item 1": 1,
    "item 2": [
               "big",
               "hairy",
               "list",
               "I",
               "want",
               "to",
               "skim",
               "over"
    ],
    "item 3": 3,
}

and cursor is placed on item 1. require'nvim-treesitter.textobjects.move'.goto_next_start('@parameter.inner') will jump to item 2 key, which is fine, but on next invocation, it will descend into item 2 list. I would like to be able to jump exclusively to next sibling/key, without descending into key's value. I often find myself wanting to jump over keys in JSON file with large values that span over many screens.

Describe the solution you'd like Something similar to @parameter.(inner|outer) that is jumps only to keys on the same level of nesting as one under cursor.

Describe alternatives you've considered % partially works, but it fails with large files. It doesn't do exactly what want (it jumps to the end of the array, not to the next dictionary key), but it's close enough.

Additional context Same problem exists with nested arrays

ar = [
    "level 1 item",
    [
        "l",
        "e",
        "v",
        "e",
        "l",
        "2",
        "i",
        "t",
        "e",
        "m",
        "s"
    ],
    "another level 1 item"
]

Proposed operator, starting from cursor at level 1 item, should jump to beginning of array, but not inside of it, next require'nvim-treesitter.textobjects.move'.goto_next_start call should jump straight to another level 1 item.

I have read query documentation from treesitter site, but I don't still don't know if it's possible to write or not…

fenuks commented 2 years ago

I've read some code here, and it seems that is not possible with query, but I've wrote something that seems to work.

Below code, gets current node, checks if it is of expected type, if not it searches if any ancestors is of this type, and if it is found, gets next sibling of that type, and jumps to it. If you think something like that can be useful for others, I can make it more general and open a PR.

local ts_utils = require "nvim-treesitter.ts_utils"

local function move_sibling(node_type)
  local cur_node = ts_utils.get_node_at_cursor()
  while cur_node and cur_node:type() ~= node_type do
    cur_node = cur_node:parent()
  end

  if cur_node == nil then
    print("Couldn't find node of type " .. node_type)
    return
  end

  local next_node = cur_node:next_sibling()
  while next_node and next_node:type() ~= node_type do
    next_node = next_node:next_sibling()
  end
  if next_node == nil then
    print("Failed to find next node")
  end
  local goto_end = false
  local avoid_set_jump = false
  ts_utils.goto_node(next_node, goto_end, avoid_set_jump)
end

move_sibling("pair")
theHamsta commented 2 years ago

I personally use https://github.com/theHamsta/crazy-node-movement . It should work when you are on the sibling or you want to move up or down the node hierarchy

fenuks commented 2 years ago

Thanks, it looks interesting. I'll have to verify if it works well for all filetypes I use. I wish all treesitter plugins were property tagged – this plugin is quite old already, and I haven't heard of it, even though in general I try to be up to date with new promising plugins.

theHamsta commented 2 years ago

@fenuks it's just my personal config. It we tried to have something like this in nvim-treesitter but it's just to confusing. But maybe one can borrow some of the logic

fenuks commented 2 years ago

Yes, I noticed it after I sent the comment, but still, it's a little gem, that I'm convinced many people would like to know about it. :) Some treesitter plugins are already tagged with nvim-treesitter topic, might want to do that as well. Just a suggestion. :)

BTW, https://github.com/nvim-treesitter/playground has this tag, and this repository does not (it has generic tree-sitter, but not nvim-treesitter). I realise it's small thing, but it helps with discoverability.