Skip to content

Conversation

JonLD
Copy link

@JonLD JonLD commented Jul 30, 2025

Overview

Implements the vim style inner and around (i and a) text objects for:

  • word bound to w (a sequence of letters, digits and underscores, separated with white space)
  • WORD W (a sequence of non-blank characters, separated with white space)
  • brackets bound to b (any of ( ), [ ], { })
  • quote bound to q (any of " ", ' ', ``)
  • prior "pair" motion for specific matching pairs (e.g. di( or ci") extended for around versions that cover the pair characters

This addresses most of #848 although it doesn't add paragraph text object, that would be fairly straightforward to add later.

Additionally, the pair motions will now jump to the next pair if non are found within search range. For symmetric pairs like quotes searching is restricted to the current line. For asymmetric pairs like brackets search is multi-line across the whole buffer. Symmetric pairs searching does not do any parsing or matching of pairs based on language/groupings. It simply searches for the previous and next matching characters (this is consistently with vim but could be improved, perhaps using tree sitter).

Repeats

While it might not be the intend to achieve identical behaviour as vim I thought it useful to compare to the default vim behaviour of repeats.
Around brackets:
In the current implementation repeat motions for around text objects will cause a jump to the next bracket.
e.g. 2daw on "(first)between(second)" while in the first bracket will delete both the first and second bracket, included the parentheses themselves, and move the cursor to the end "between".
Vim works around this by not letting you do repeats for "around" motions unless inside a nested bracket.
Inner words:
Repeat motions for words also differ from default vim behaviour for repeated word text objects. In vim a 2diw performs a single around diw command and then the repeat command is dw. The difference in behaviour is that in the reedline implementation 2daw on delete th|is word will result in delete|word whereas in vim it would be delete |word.

This could perhaps be worked around by adding a method of passing an alternate command for repeats to the command module which could be made in a future change. I think the current behaviour is satisfactory for most use cases.

Word identification

Currently due to using the unicode-segmentation crate for splitting at word word boundaries word does not have the same meaning as Vi/Vim. This means diw on not.a..wo|rd will delete the whole WORD rather than just the word under the cursor.

JonLD added 13 commits July 22, 2025 01:25
…tespace

Note a buffer full of whitespace is not properly considered and still
causing incorrect behaviour. TODO fix this.
…eatures

- Now handles jumps to next open/close or equal symbol pairs if not in a
pair already
- Searching only on current line for equal symbol pairs e.g. quotes
- Correctly handles graphemes
- Refactor the structure of the methods to get ranges, don't need to
pass in depth unecessarily, high level functions don't require cursor
passed in.
- Now two seperate functions for ranges, one "next" and one "current"
range that gets you either the range inside next text object or inside
current one depending on position of cursor.
- Finilise logic to correctly handle graphemes (not byte sized chars)

TODO Update unit tests
- Improve some text object ranges to use iterators rather than complex
logic
- Clean up documentation, add consts etc
- Look through and refactor some editor functions
@JonLD JonLD changed the title Add vi mode text objects for words, brackets and quotes Vi mode text objects for word, WORD, brackets and quotes Jul 31, 2025
@JonLD JonLD marked this pull request as ready for review July 31, 2025 19:15
@JonLD JonLD marked this pull request as draft July 31, 2025 20:39
@JonLD JonLD marked this pull request as ready for review July 31, 2025 20:39
Copy link
Contributor

@ayax79 ayax79 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been wanting this for a while. This much better than the hack a while back.
The code looks clean and seems to work fine in nushell (minus a couple minor changes).

Great work!

@JonLD
Copy link
Author

JonLD commented Aug 9, 2025

I have been wanting this for a while. This much better than the hack a while back. The code looks clean and seems to work fine in nushell (minus a couple minor changes).

Great work!

@ayax79 Glad to help! These motions are so hard coded into my brain it felt clunky trying to edit without them haha.
Is there anything more I can do to help get this merged? Does it need a Nushell PR merging along side it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants