wellle / targets.vim

Vim plugin that provides additional text objects
MIT License
2.57k stars 56 forks source link

[question] Where does targets.vim fit with other plugins? #225

Open bb010g opened 5 years ago

bb010g commented 5 years ago

So, I've been looking at redoing my nvim config to potentially switch back from Doom Emacs, and targets.vim caught my eye once again. The recent #217 seems to have made it extremely capable, but I'm not sure really where it fits in with other plugins I've used in the past or how it approaches extension from the Vim "nature". If you could shed some light on the following questions, it'd be much appreciated, and I think a valuable resource for others trying to figure out their personal Vim configs too.

To start, targets.vim advertises consistency and reliability, which sounds proper, and it does so with text objects proper. Looking at https://github.com/neovim/neovim/issues/8544, https://vim.fandom.com/wiki/Creating_new_text_objects, and kana/vim-textobj-user:autoload/textobj/user.vim though, along with the edge case note in targets.vim's readme, it seems that this is something Vim doesn't make simple.

  1. How does (N)vim's internal representation (if extant or consistent at all) of text objects differ from the Vimscript surface for creating or manipulating them, and what practices must plugins follow to create well behaved text objects on bare Vim?

  2. What differences are there in the approach or philosophy of targets.vim vs. other text object–providing plugins like kana/vim-textobj-user, machakann/vim-sandwich, gcmt/wildfire.vim, or tweekmonster/braceless.vim?

  3. Does (N)vim have built in support for plugin-provided operators or other extensions working naturally with custom text objects, and if so, how much? Composability and reusability of concepts and specific manifestations of those are major factors of why Vim feels so natural, but it seems that plugins don't agree on how to extend in those ways properly. For example, just in the realm of different surround operators and their methods of consistent repetition, there's tpope/vim-surround using tpope/vim-repeat, rhysd/vim-operator-surround (backed by kana/vim-operator-user) using their own implementation (PR'd in #14 & #30 (but still runnning nnoremap <Plug>(operator-surround-repeat) . for some reason?)), and machakann/vim-sandwich using inkarkat/vim-visualrepeat and thus tpope/vim-repeat kinda, but it's also not mentioned in the readme (and the docs only bring it up for visual?) (autoload/operator/sandwitch.vim, various parts of au/o/sandwitch/operator.vim, the design of au/textobj/s/textobj.vim, macros/s/keymap/surround.vim, & plugin/o/sandwitch.vim seem to cover repeat support). For other plugins, there's tyru/caw.vim using kana/vim-repeat (tpope/vim-repeat compatible?), syngan/vim-operator-furround using kana/vim-operator-user & tpope/vim-repeat, and haya14busa/incsearch.vim having a toggle to use a vim-repeat or not. (ky/vim-altrepeat also seems to exist and advertises some amount of vim-repeat compatibility in a comment?) targets.vim, despite being focused on text objects and not operators, still contains a bit of code using vim-repeat for what looks like backwards-compatibility. Also, tommcdo/vim-ninja-feet seems to have trouble accomplishing its goal of creating new motions that interface properly with text objects (#3 comment 348757810).

  4. In the realm of plugins trying to support each other's custom extensions, how much overhead is necessary in modern (N)vim setups to work as smoothly as possible? What approaches would you personally recommend for that substrate, given your work on targets.vim?

Thank you for your time.

wellle commented 5 years ago

@bb010g: Wow, that must be the most well researched issue I've ever received, thanks for putting it all together!

Looking at targets.vim within the general vim plugin landscape, I think I'm in a fairly stable position. Targets.vim doesn't have any hard dependencies on other plugins and doesn't interact directly with other plugins. This means that I'm not at risk of having parts of targets.vim break because other plugins push breaking changes.

As you pointed out, there's a weak dependency on tpope/vim-repeat, but that's only for old Vim versions and gracefully handles the case where vim-repeat is not available.

As you mentioned, most of the pain and complexity comes from Vim itself. Vim is old and has a long history. Features are added and improvements are being made. Trying to support old versions is often a struggle as you have to check which features are available and try to figure out workarounds. This is often annoying as you need to work with the old versions and it can feel as if you implement the same thing for different text editors. I think many plugin authors (including me) just pick a somewhat recent Vim version which supports most of what the plugin needs and don't sweat about supporting older versions. I feel like nowadays it's fine to ask people to upgrade to a somewhat recent Vim version to use your plugin.

But then there's also still missing features in Vim. So this is where you have to find a workaround and start to strongly depend on it. And that doesn't feel great, as there's always the small risk that the hack might stop working in the future.

One current example for this is that Vim doesn't allow a third party text object to select an empty selection, even though Vim's internal text objects do have that capability. The hack I'm using in targets.vim is to actually insert a character into the empty selection and then operate on that character (which is a non empty selection now). I'm meaning to open an issue about this for years now, but just never did.

Another similar example is how Vim's internal text objects had support for motion force, while third party text objects didn't. Both Vim and Neovim added it recently, so third party text objects are compatible with that now too. See https://github.com/wellle/targets.vim/issues/214 and the linked Vim/Neovim issues for details.

Actually, if you look at my comment here: https://github.com/vim/vim/issues/3490#issuecomment-425642966, I mention two other cases which were also affected by this, one of them being a Vim internal text object (gn). So this is an example where one Vim internal text object behaves differently to most other Vim internal text objects. These kinds of inconsistencies are annoying to find and have to deal with. Also in the same issue we do talk about the options plugin authors have to define text objects, and how they seem somewhat limited. Basically the only practical way currently is to use visual mode.

Interestingly, that has other side effects, like https://github.com/wellle/targets.vim/issues/202. Since we use visual mode to select our text objects, we do overwrite the last visual selection. Targets.vim and other plugins could probably do extra work to restore the last selection, but that feels like another thing Vim should fix. I also didn't open a Vim issue about that yet.

Another thing I'm not too fond of is how I'm using expression mappings in targets.vim. See https://github.com/lervag/vimtex/issues/1294#issuecomment-450764878

On that topic, there's another weirdness in Vim. For an expression mapping you have to declare whether it's <silent> or not when you define the mapping, not when it's being executed. If you look at #209 this leads to surprises. To fix this I had to split my expression mappings into one which isn't silent and one which is, and then transfer from one to another by the weird @(targets) mapping. Another thing there's probably no Vim issue about.

Speaking of opening Vim issues for those limitations, I'm usually hesitant to open them as I've seen so many of them not being moved forward. And I can totally understand why that's (not) happening. So I kinda started to accept that sort of state, but seeing the recent activities (thanks to Neovim I guess) maybe I should give them another chance and start opening issues again.

You do a good job of describing how different Vim plugins seem to solve the same issues in different ways and how other plugins depend on some selection of the first ones. I think cases like vim-repeat are a symptom of Vim shortcomings. If Vim's repeat would have been more consistent, or would have been fixed quicker, vim-repeat would probably not have been needed in the first place. There's probably a similar argument for some of the edge case handling you'll find in targets.vim and other text object plugins.

Speaking of how targets.vim compares to similar plugins, let me quote my comment from https://redd.it/9ten8k

Good question! I use some textobj-user plugins myself, like word-column. To me it seems like they have different backgrounds/history. Textobj-user seems to be a text object framework from the get go. It was created to make it easier to add new text objects without every plugin author having to figure out all the ground work and edge cases. I created targets.vim to improve on my gist mentioned in this post: https://redd.it/1w6qs7, which was based on the other gist mentioned there. The main feature was supporting next and last/previous text objects, then came seeking and many more small improvements, including argument text objects and improved quote handling. So in contrast to textobj-user, I started with some concrete text objects in mind, which have certain functionality. And only now (after 4 years) I got it into a shape where I thought I can open it up for other plugin authors to hook into it. In summary I would say creating text objects with textobj-user still seems simpler and more convenient (I haven't tried it myself though). If you want to write a targets.vim plugin, it will be more involved as you have to understand and implement three generator functions. The benefit is that your text object then has all the features of the built in targets.vim objects (and can now even be combined with them). But not all text objects need next/last support or seeking etc. For those I'd definitely still recommend textobj-user.

I definitely don't want to come across as negative about the Vim/Neovim scene. I'm very happy that the ecosystem is making it possible to write plugins like this in the first place, but to be honest it could be made even easier.

Sorry for not really following your questions, but just randomly rambling. If you feel like I left out a big part of your questions, please let me know what you'd like me to get more into detail.

Speaking of other plugins (potentially) using/extending targets.vim, here are two recent examples I've seen, in case that's interesting to you: https://github.com/lervag/vimtex/issues/1308 https://github.com/Houl/repmo-vim/issues/9

Thanks again, Cheers!