GithubHelp home page GithubHelp logo

mfussenegger / nvim-treehopper Goto Github PK

View Code? Open in Web Editor NEW
400.0 6.0 16.0 26 KB

Region selection with hints on the AST nodes of a document powered by treesitter

License: GNU General Public License v3.0

Lua 95.93% Vim Script 4.07%
neovim neovim-plugin tree-sitter nvim-treesitter

nvim-treehopper's Introduction

Treehopper πŸ‡

Syntax trees + hop = Treehopper

A Plugin that provides region selection using hints on the abstract syntax tree of a document.

Demo

Requirements

  • Neovim 0.7.2+

Treehopper operates on syntax trees. It uses tree-sitter to retrieve the tree if a parser is available, otherwise it tries to use the built-in LSP client in Neovim (using the selectionRange functionality).

You can install tree-sitter parsers either via:

Installation

  • Install it like any other neovim plugin:
    • If using vim-plug: Plug mfussenegger/nvim-treehopper
    • If using packer.nvim: use mfussenegger/nvim-treehopper

Usage

Selecting a region

Define two mappings:

omap     <silent> m :<C-U>lua require('tsht').nodes()<CR>
xnoremap <silent> m :lua require('tsht').nodes()<CR>

You can configure which keys are used for hint labels, the first N characters will be taken from the hint_keys and then after that it will restart from a-zA-Z

require("tsht").config.hint_keys = { "h", "j", "f", "d", "n", "v", "s", "l", "a" }

Moving

Moving depends on hop.nvim

If you want to move to the start or end of a syntax node you can use require('tsht').move({ side = "start" }).

The parameter is optional and defaults to start. Use side = "end" if you want to move to the end of a node.

Credits

nvim-treehopper's People

Contributors

atusy avatar debugloop avatar indianboy42 avatar jemag avatar mfussenegger avatar okuramasafumi avatar swarn avatar xeluxee avatar yioneko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

nvim-treehopper's Issues

Recommended keymaps feel unnecessarily complex

I was trying out the plugin and couldn't get it to work with either

local tsht = require('tsht')
vim.keymap.set("o", "<Space>", tsht.nodes)
vim.keymap.set("x", "<Space>", tsht.nodes, { noremap = true })

or

vim.cmd([[ omap     <silent> <Space> :<C-U>lua require('tsht').nodes()<Cr> ]])
vim.cmd([[ xnoremap <silent> <Space> :     lua require('tsht').nodes()<Cr> ]])

However, simply doing this works just fine:

vim.keymap.set('n', '<Space>', tsht.nodes, { noremap = true })

Which leaves me with the following questions:
What's the point of all this fuss about Visual/Select (mapmode-x) modes ?
By extension, why use Operator-pending (mapmode-o) ?
Finally, why all this ceremony while simply just calling tsht.nodes() in Normal Just Worksβ„’ ?

Side note: Despite years of daily (Neo)Vim and constant ricing of it, I never knew Operator-pending existed; or seen it in a config for that matter. This by itself could end up being very confusing to a lot of users, as it feels highly unconventional. πŸ€”

I want to set a callback to run after the execute

When I use hrargs.nvim it highlights where I used the argument, but it remains highlighted when I run treehopper's nodes.
https://github.com/m-demare/hlargs.nvim

CleanShot 2022-08-31 at 15 32 07

I have disabled hlargs when using treehopper for fold, but there is no way to enable it after the move.
Is it possible to issue a User event after completion or pass a callback when treehopper runs?

" current settings
function! s:tree_hopper_fold() abort
  lua require('hlargs').disable()
  lua require('tsht').nodes()
  normal! zf
endfunction
nmap <silent> zf <Cmd>call <SID>tree_hopper_fold()<CR>

" I want to do this setup.
autocmd User TreeHopperEnter lua require('hlargs').disable()
autocmd User TreeHopperLeave lua require('hlargs').enable()

This plugin should deserve more attention.

I have been using your plugins such as ndap series plugins. These plugins have given me an excellent development experience and productivity. This plugin provides a better experience than nvim-treesitter-textobjects, I have put this plugin into the wiki page of nvim-treesitter, and I think this plugin should be put into your github home page readme.md. Last but not least, thank you for your continuous contributions to the nvim plugin.

Feature request: Goto textobject with hints

Im imagining essentially a mix of easymotion/hop but using treesitter to identify places to jump to.

I don't know if this is necessarily the right place for this functionality, but i think it already has the infrastructure for displaying hints, and identifying relevant text objects from treesitter.

How hard do you think adding this would be? I could give it a go trying to implement it

Moving (not selecting)

Apologies if I'm asking about a feature that isn't yet implemented. I can't quite tell whether or not this is possible.

Currently I have the following mapping:

vim.api.nvim_set_keymap("n", "m", "<cmd>lua require('tsht').nodes()<CR>", opts)

I can successfully initiate the search:

Screen Shot 2021-10-17 at 10 46 26 AM

And can successfully select a given node (in this case by pressing a):

Screen Shot 2021-10-17 at 10 46 37 AM

But what if I just want to move my cursor to the node start / end? How might this be accomplished? Is this possible?

Thank you!

Add default opts in hop call

Hop has a new fork that contain fixes and more features.
However, this new fork requires always passing opts to the function call.

When calling treehopper, I receive the following error:

E5108: Error executing lua: ...ugel/.local/share/nvim/lazy/nvim-treehopper/lua/tsht.lua:301: ...rugel/.local/share/nvim/lazy/hop.nvim/lua/hop/window.lua:74: attempt to index local 'opts' (a nil value)
stack traceback:
	[builtin#36]: at 0x01047bc61c
	...ugel/.local/share/nvim/lazy/nvim-treehopper/lua/tsht.lua:301: in function 'move'
	/Users/bruno.krugel/.config/nvim/lua/custom/mappings.lua:405: in function </Users/bruno.krugel/.config/nvim/lua/custom/mappings.lua:404>

I opened an issue at the smoka7/hop.nvim and the author pointed where the treehopper calls hop without opts.

Do you think we can have a fix so treehopper works with the fork from smoka7?

No parser for `typescriptreact` language (when treesitter parser name is different from filetype)

When trying to use nvim-treehopper in a tsx file, I get the following error:

E5108: Error executing lua ...local/share/nvim/runtime/lua/vim/treesitter/language.lua:25: no parser for
 'typescriptreact' language, see :help treesitter-parsers
stack traceback:
        [C]: in function 'error'
        ...local/share/nvim/runtime/lua/vim/treesitter/language.lua:25: in function 'require_language'
        /usr/local/share/nvim/runtime/lua/vim/treesitter.lua:39: in function '_create_parser'
        /usr/local/share/nvim/runtime/lua/vim/treesitter.lua:98: in function 'get_parser'
        ...nvim/site/pack/packer/start/nvim-treehopper/lua/tsht.lua:53: in function 'nodes'
        [string ":lua"]:1: in main chunk
Press ENTER or type command to continue
Peek.2022-06-11.11-02.mp4

This seems to be caused by the treesitter parser for the typescriptreact filetype being named tsx. nvim-treehopper tries to use the parser with the same name as the filetype, which is not the case for quite a few filetypes, as shown in nvim-treesitter.

I have decided to report this issue separately from my attempt at solving it (#14), since the progress on that PR has stifled while the issue remains.

<cmd> doesn't work for visual mappings

xnoremap <silent> m :lua require('tsht').nodes()<CR>

works as expected but

xnoremap <silent> m <cmd>lua require('tsht').nodes()<CR>

does not expand the visual selection

Cursor position outside buffer

I have only tested the operator mode bind, which in my case I have set to m. The error occurs when the selected hint is on the first row and first column as demonstrated in the gif below.

ts-hint

Error:

E5108: Error executing lua ...ite/pack/packer/opt/nvim-ts-hint-textobject/lua/tsht.lua:73: 
Cursor position outside of buffer

Edit:
The issue occurs that when end_col equals 0 and/or end_row equals the amount of lines in the buffer. The following is my not so elegant way of solving this issue.

diff --git a/lua/tsht.lua b/lua/tsht.lua
index a3540f9..45272d6 100644
--- a/lua/tsht.lua
+++ b/lua/tsht.lua
@@ -70,7 +70,14 @@ function M.nodes()
         local start_row, start_col, end_row, end_col = node:range()
         api.nvim_win_set_cursor(0, { start_row + 1, start_col })
         vim.cmd('normal! v')
-        api.nvim_win_set_cursor(0, { end_row + 1, end_col - 1 })
+        local line_count = api.nvim_buf_line_count(0)
+        if end_row < line_count then
+          end_row = end_row + 1
+        end
+        if end_col > 0 then
+          end_col = end_col - 1
+        end
+        api.nvim_win_set_cursor(0, { end_row, end_col })
         api.nvim_buf_clear_namespace(0, ns, 0, -1)
         break
       else

Include trailing seperators/whitespace on `c` or `d`

First, thanks for your work on this plugin, I use it habitually at this point.

There's one thing I'm missing though, but I have no idea if it's possible.

With this keybind

onoremap m :lua require('tsht').nodes<cr>

Consider this line

local cursor_node = root:descendant_for_range(lnum, col, lnum, col)
                                  cursor here ^

Here, let's say I'd like to delete lnum under the cursor with dma in normal mode, I get this

local cursor_node = root:descendant_for_range(, col, lnum, col)
                                  cursor here ^

But what I'd really like, is deleting all the way up to the next argument like this

local cursor_node = root:descendant_for_range(col, lnum, col)
                                  cursor here ^

I might give this a shot myself, but an approach could be to pass an argument to the nodes function, as to whether or not it should delete only around the current or up to the next node

Feature Suggestion: Hints for objects *outside* nodes containing the cursor

I just stumbled upon this plugin and I must say, I find it's concept very intriguing.

Having played around with it for a bit, I noticed that this plugin restricts the hints and therefore actionable area to nodes containing the cursor. When in a big, deeply nested node like in the demo in the readme, that makes sense, but when in areas with a long sequence of non-nested nodes like an array, this makes the plugin rather unuseful:
CleanShot 2023-04-01 at 14 56 06

So my idea is to introduce options to change the area actionable (= getting hints) from the plugin:

  • currently, we can action on nodes containing the cursor
  • one option could be nodes not containing the cursor, i.e. inverting the actionable area. This could be interesting, since you can often select things that contain the cursor via other text objects already. However, objects at a distance are far more limited to interact with (apart from the forward-seeking from plugins like targets.vim)
  • or one could simply enable hints for all nodes, or all nodes after/before the cursor?

Recommend x instead of v mapping

A lot of users will often use the "select" mode for snippets. The current recommendations will trigger in select mode:

vnoremap <silent> m :lua require('tsht').nodes()<CR>

meaning someone writing "m" while filling their snippets, will have the plugin trigger.

I believe most users would probably prefer to use visual only:

xnoremap <silent> m :lua require('tsht').nodes()<CR>

Pluggable target selection engine

Specifically thinking about Leap, besides Hop.

It would be win-win for everyone:

  • This plugin could focus on one thing - there would be no need to reinvent the wheel, i.e. hinting and the selection of targets, which is supposed to be more robust/flexible in Leap/Hop, since that is the very focus of the aforementioned plugins.
  • Both groups of users could be directed to this plugin, and there would be no need to develop/maintain e.g. leap-ast.nvim.

I'm a bit confused about the current state of things though: Treehopper depends on Hop for jumping, but why is Hop necessary for what is basically an api.nvim_win_set_cursor call? On the other hand, if Hop is a dependency, why not use Hop for hinting - why a redundant implementation for Visual mode?

Anyway, integrating with Leap would be super simple, you simply get the node positions (optionally sort them in a preferred order), and feed it to Leap that takes care of the rest. You can also give it a custom action callback, that can be a wrapper around the range selection functionality already implemented here for Visual/OP mode.

If we'd want to show the same label in multiple places (start & end of the node), that would require some tweaks in the Leap API, but obviously doable. Also, there is no need to respect the "global" defaults of Leap, the highlights (or anything else) can be customized for treehopping, via autocommands. (Check https://github.com/ggandor/leap.nvim#extending-leap.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.