-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make quote text objects more intuitive #11976
base: master
Are you sure you want to change the base?
Conversation
ec7cf7a
to
d5ed4a5
Compare
Codecov Report
@@ Coverage Diff @@
## master #11976 /- ##
==========================================
- Coverage 81.93% 81.45% -0.48%
==========================================
Files 164 164
Lines 193978 193858 -120
Branches 43811 43756 -55
==========================================
- Hits 158927 157914 -1013
- Misses 22211 23150 939
Partials 12840 12794 -46
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
# Problem
If you have the following text with `|` indicating the cursor
'string' |stuff 'string'
now in normal mode if you press `vi'` the region demarcated with `*` is selected
'string'* stuff *'string'
But we can agree that `stuff` is not part of any string, but the help
says that it will always select a "quoted string"
You cannot decide what is a string without looking in surrounding lines.
You appear to assume that strings can't cross a line break. That is not
always the case.
I'm not sure your changes are an improvement or just different. Looking
at the first changed test case, I would say it's actually wrong:
- call assert_equal("xxxxxxxxxxxx'piep'", getline('.'), e)
call assert_equal("'foo' xxxxxx'piep'", getline('.'), e)
This changed result also looks wrong:
- call assert_equal('voo "zzzzzzzzzzzzzzzzzzzzzzzzzzzzsd', getline('.'), e)
call assert_equal('voo "zzz" sdf " asdf" sdf " sdf" sd', getline('.'), e)
The existing behavior extends the Visual area, your changed behavior
appears to keep only the last selected object. I do not see that as an
improvement.
You have also changed the input for some test cases. That makes it
difficult to see what the changes are from previous behavior. Instead
of changing the existing test case, please add a new one.
- Select the nearest "balanced" quote object (always selecting
forwards but backwards if there is nothing forwards)
I don't think you really means "nearest", that would be counting the
number of characters forward/backward. That would be too unpredictable
and hardly ever what the user expects.
I'm not sure if selecting an object backwards is a good idea. This also
makes it a bit unpredictable.
- Choose to select the string forwards or backwards (using `vhi'` or
`vli'` for example).
This makes it complicated. The user could move the cursor before
selecting the object. It's often better to have more than one simple
command than one complicated one.
- The repeat behaviour is not very obvious, I am open to suggestions
but I thought the following made sense:
- `vi'i'` includes the quotes
- after doing `vi'i'` the next `i'` selects the next string
obeying the rules of `i'`
Isn't this how it is already working?
- `v2i'` selects the 2nd string (so selecting the nth quote object
using `vni'`)
Generally a count means repeating the command, thus "2i'" would do the
same as "i'i'". Doing otherwise is unexpected. Is there a really good
reason to do something else in this case?
- repeating `a'` always selects the next string
One caveat is that some languages leverage unbalanced quotes in their
grammar (vimscript quotes, rust lifetimes).
Its tricky to handle those cases. My proposal is:
- An even number of quotes are always balanced.
- In case of an odd number of quotes if the user is already inside a
_percieved_ balanced string, then select it.
more precisely if the cursor is after the end of a balanced quote
and there is a partial quote present after it, then
region between the end of the balanced quote and partial quote is selected.
(`*` marks selection `|` is cursor)
```
v balanced quote end
" comment "*string|*"
^ start ^ start but no end
```
This makes sense. But what if the cursor is in the "comment" text, it
would select something else? Then it isn't different from the existing
behavior, is it?
This also somewhat simplifies the code by not having too many special cases.
This is certainly not perfect, ideally we would want syntax based text
objects, but as a default I think this is much better and an
improvement over the current behaviour.
I think we need to try this out on many corner cases to be able to judge
that. Also, it's not just about selecting the right thing, but also
making sure it is predictable. The user can move the cursor to another
location to make the selection cover the right text.
…--
"Computers in the future may weigh no more than 1.5 tons."
Popular Mechanics, 1949
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
But we say that the a" *v_aquote* *aquote*
a' *v_a'* *a'*
a` *v_a`* *a`*
"a quoted string". Selects the text from the previous
quote until the next quote. The 'quoteescape' option
is used to skip escaped quotes.
Only works within one line.
Personally I find selecting quoted strings to be much more helpful than extending the area to the next quoted string. I cannot think of where it would be useful of the top of my head and that's why I changed it like that.
Say the case is like the following
With this patch only in such cases when unambigously when there is no quoted string forwards and there is a quoted string backwards do I chose to select it backwards, otherwise it always chooses forwards like how it does now.
That's the current behaviour though. I was just listing out what the quote object should do (including existing and new additions)
No,
the ability for
Yes, the behaviour only differs when there are an even number of quotes in a line.
And this patch enables you do to that? I am not sure I understand this comment |
> You cannot decide what is a string without looking in surrounding lines.
> You appear to assume that strings can't cross a line break. That is not
> always the case.
But we say that the `i{quote}` and `a{quote}` text object only
operates on a line, so that is a reasonable assumption
The text object only works within one line, but that doesn't mean
the quoted strings are restricted to one line. It does mean that it
won't work well if strings a line boundary.
> The existing behavior extends the Visual area, your changed behavior
> appears to keep only the last selected object. I do not see that as an
> improvement.
Personally I find selecting quoted strings to be much more helpful
than extending the area to the next quoted string. I cannot think of
where it would be useful of the top of my head and that's why I
changed it like that.
This is how all text objects work. And it is useful in a list of
strings, for example.
> I'm not sure if selecting an object backwards is a good idea. This also
> makes it a bit unpredictable.
Say the case is like the following
```
"string" stuff|
```
With this patch only in such cases when unambigously when there is no
quoted string forwards and there is a quoted string backwards do I
chose to select it backwards, otherwise it always chooses forwards
like how it does now.
This may seem like a good idea for the example, but if a long text
follows, the user would have to look through it for any quoted strings
before the user can predict what will happen. I would rather see it
fail, then it's clear there is no quoted string after the cursor. That
the user used the command it must have looked like there was one.
Anyway, you will have understood by now that I have my doubts whether
the change is an improvement. I wonder what others are thinking. You
will have to spend time on convincing us that it works better and
doesn't break what users are used to.
…--
~
~
~
".signature" 4 lines, 50 characters written
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
But, here's where this new behaviour of operating on the next string is useful, Say you're on a long line:
now say you're inside the first string and want to select the second one, you So, naturally while editing you go This is helpful while not only editing prose but while editing code as well, take the parsed = map(lambda line: map(partial(parser, prefix="0b") , line.split()), with_iter(open("./file.txt")).readlines()) and now say that you're on parsed = map(lambda line: map(lambda word: "text"|"./file.txt")).readlines()) I hope you will agree that that is not very helpful. parsed = map(lambda line: map(partial(parser, prefix="0b") , line.split()), with_iter(open("|")).readlines()) It operated the Say a person in some case does want to select that region, then they can do Infact it is documented as I found the following entry in the Line 1864 in 1a64764
I am not sure if they meant this behaviour, but perhaps this new behaviour I am proposing is more logical? |
The issue that led to the aforementioned todo entry was probably the following mail by Ben Fritz
This seems to be different from what you try to solve/change. Apart from that I think you are restricting your view to much on source code, where quoted text spanning multiple lines is quite seldom. But if you edit natural language and write quoted speech, you will soon have quotes spanning multiple lines where it is hard to find the opening quote without understanding the text. That's an inherent disadvantage of having identical opening and closing symbols. In my opinion Vim's rule to act on the |
Would you mind giving this PR a go and seeing where it causes unpredictable behaviour? |
Problem
If you have the following text with
|
indicating the cursornow in normal mode if you press
vi'
the region demarcated with*
is selectedBut we can agree that
stuff
is not part of any string, but the help says that it will always select a "quoted string"Visual mode gets some more nice (special cased) behaviours as well, taking the same example as above, if we do
vli'
orvhi'
we properly select the left or right string. butdi'
orci'
don't get just niceties.There also exists no way to select the nth string by doing
vni'
(somewhat akin tovnib
).I propose the following behaviour for the
i{quote}
anda{quote}
textobjects.vhi'
orvli'
for example).vi'i'
includes the quotesvi'i'
the nexti'
selects the next string obeying the rules ofi'
v2i'
selects the 2nd string (so selecting the nth quote object usingvni'
)a'
always selects the next stringOne caveat is that some languages leverage unbalanced quotes in their grammar (vimscript quotes, rust lifetimes).
Its tricky to handle those cases. My proposal is:
more precisely if the cursor is after the end of a balanced quote and there is a partial quote present after it, then
region between the end of the balanced quote and partial quote is selected.
(
*
marks selection|
is cursor)This also somewhat simplifies the code by not having too many special cases.
This is certainly not perfect, ideally we would want syntax based text objects, but as a default I think this is much better and an improvement over the current behaviour.