nvim-treesitter-textobjects icon indicating copy to clipboard operation
nvim-treesitter-textobjects copied to clipboard

Swap operands

Open znd4 opened this issue 2 years ago • 4 comments

Is your feature request related to a problem? Please describe. imagine you write out something like this

df["column_1"] - df["long_column_name"].a_couple().of_transformations()

But you realize that you actually want to swap these.

you've gotten okay at vim motions, so you F-D0P, but then realize you've still got a ways to go:

- df["long_column_name"].a_couple().of_transformations()df["column_1"] 

Thankfully your cursor's in a convenient place, so you can easily add a minus sign in the middle:

- df["long_column_name"].a_couple().of_transformations()-df["column_1"] 

You've still got to 0dw to clear up the leading - . Finally, you're in a state where your format-on-save hooks will clean things up:

df["long_column_name"].a_couple().of_transformations()-df["column_1"] 

Describe the solution you'd like I'd like to be able to add an @operand mapping to my swap configuration, e.g.:

		swap = {
			enable = true,
			swap_next = {
				["<leader>o"] = "@operand",
			},
			swap_previous = {
				["<leader>O"] = "@operand",
			},
		},

Describe alternatives you've considered

I guess there might be a swapping-specific plugin that I could look for. If it doesn't exist, I suppose I could try to implement it, although I'd rather try to implement it in this project if it's possible (I don't know what's involved in creating a textobject for treesitter)

Additional context nil

znd4 avatar Oct 17 '22 16:10 znd4

I love this idea, I've been wanting it for a while. Not sure I'll be able to implement it for every language we support, but I'll try 😃

HungryJoe avatar Dec 30 '22 20:12 HungryJoe

I've run into some unexpected behavior when swapping operands within chained associative operations.

The Problem

To see what I mean, consider the following expression:

1 + 2 + 3

Treesitter parses this into an AST with two binary_expression's. They look like:

binary_expression (1 + 2 + 3)
left: integer (1)
right: binary_expression (2 + 3)

and

binary_expression (2 + 3)
left: integer (2)
right: integer (3)

So there are two swaps that I can make, corresponding to the two binary_expression's:

  • 1 and 2 + 3
  • 2 and 3

However, as a user, I want to imagine this expression as a list of integer's joined by +, where any two adjacent elements can be swapped. In this case, the second possible swap stays the same, but the first one changes:

  • 1 and 2 <- different from above
  • 2 and 3

Proposed Solutions

  1. We ask that users change their expectations to match treesitter's.
    1. This would probably require people to use unnecessary parentheses so that they're on the same page as treesitter about what the operands are in a given situation.
    2. Example: 1 + (2 + 3)
  2. We make treesitter match my (and probably most users') expectations.
    1. This would require treesitter-textobjects to check that two nodes share a common ancestor that's a binary_expression, rather than just a common parent like it does now.
    2. This would be a large refactor as far as I can tell.
  3. We disable swapping, or the capturing of the operand textobject, for nested binary_expression's that all have the same operator.
    1. This would also be a large refactor to my knowledge.
  4. We don't implement this feature, disappointing users like @zdog234 and I.

@zdog234 @theHamsta, what do you make of these options?

HungryJoe avatar Dec 31 '22 00:12 HungryJoe

Hi, any news on this feature?

fmorroni avatar Jul 24 '24 04:07 fmorroni

sorry @HungryJoe I missed you question :/

fwiw, I do agree that 2 is the most intuitive behavior. If it'd require a major refactor for this project, it seems like this might be a good opportunity for a dedicated plugin

znd4 avatar Jul 24 '24 16:07 znd4