mini.nvim
mini.nvim copied to clipboard
Beta-testing 'mini.ai'
Please leave your feedback about new 'mini.ai' module here. Feel free to either add new comment or positively upvote existing one.
Some things I am interested to find out (obviously, besides bugs):
- Are configuration and function names intuitive enough?
- Are default values of settings convenient for you?
- Is documentation and examples clear enough?
- What is your opinion about default textobjects (for punctuation, digits, and whitespace)? At the moment it mimics 'targets.vim' idea about separator textobject - the
a
variant includes only one of the edges (the maximum right ones, to be precise). Although useful in many cases (like_
in snake case variables allowsda_
to delete word while preserving snake case), it might be not useful for some characters in most situations (like|
seems to rarely serve as separator and more like surrounding). I see at least three ways to solve this:-
Leave it as is. It means that users are encouraged to manually define custom textobjects to include both edges in
a
textobject. It is what currently is done with at least three different ways to achieve this. This is the way if there is little consensus about what character should be treated as surrounding by default. -
Add new builtin surrounding to include both edges in
a
textobject. This is the way, if there is a strong consensus about certain character (like|
) being more of a surrounding instead of separator and of which type (balanced or non-balanced). -
Add new
default
builtin surrounding to act by default. Maybe some people like include both edges by default (I know I was at first, but then changed my mind because of how useful including only right edge is). Completely not opposed to this, but any options should be considered carefully. This is the way of adding new option.
-
Leave it as is. It means that users are encouraged to manually define custom textobjects to include both edges in
Thanks!
Thanks for your plugin! I have dreamed about lua textobject plugin for so long. I have come from reddit and some people were requesting 'next' and 'last' operator types. You were saying that they're rarely used but, as for me and, I suppose, for community too, it's a must have feature. I'm a long time user so I have mastered it and it's really cool to edit something far away with a few keystrokes without even jumping to location. Editing feels like magic! Hope you will overthink your decision about not adding these types of operators!
Thanks for your plugin! I have dreamed about lua textobject plugin for so long. I have come from reddit and some people were requesting 'next' and 'last' operator types. You were saying that they're rarely used but, as for me and, I suppose, for community too, it's a must have feature. I'm a long time user so I have mastered it and it's really cool to edit something far away with a few keystrokes without even jumping to location. Editing feels like magic! Hope you will overthink your decision about not adding this issue!
Thanks!
As I said on Reddit, I've never even once used that feature and didn't feel like missing much. I did got some use cases from comments. It feels that most of the time it is about enabling dot-repeated editing in one direction. This is supported with default v:count
without needing to type extra n
.
So with 'targets.vim' foo("bar", 2, [])
after typing ^cina100<esc>..
will become foo(100, 100, 100)
. With 'mini.ai' it is possible with ^cia100<Esc>
followed by c2ia100<Esc>.
Is it something that you'll find acceptable?
I'll be really grateful if you could provide another examples of how you use il
/al
/in
/an
. It can help me understand the requirements better.
Thanks for your plugin! I have dreamed about lua textobject plugin for so long. I have come from reddit and some people were requesting 'next' and 'last' operator types. You were saying that they're rarely used but, as for me and, I suppose, for community too, it's a must have feature. I'm a long time user so I have mastered it and it's really cool to edit something far away with a few keystrokes without even jumping to location. Editing feels like magic! Hope you will overthink your decision about not adding this issue!
Thanks!
As I said on Reddit, I've never even once used that feature and didn't feel like missing much. I did got some use cases from comments. It feels that most of the time it is about enabling dot-repeated editing in one direction. This is supported with default
v:count
without needing to type extran
.So with 'targets.vim'
foo("bar", 2, [])
after typing^cina100<esc>..
will becomefoo(100, 100, 100)
. With 'mini.ai' it is possible with^cia100<Esc>
followed byc2ia100<Esc>.
Is it something that you'll find acceptable?I'll be really grateful if you could provide another examples of how you use
il
/al
/in
/an
. It can help me understand the requirements better.
Yes, you're right. It's mostly about convenient dot repeat. But I also use it to quickly edit, for example, object contents. Suppose you have a function:
vim.tbl_extend('error',
{
a1 = b,
a2 = c,
s1 = 3
}, {
s2 = 4
})
And I usually edit it with a help of textobject: firstly I use ci{
to change contents of a first list while inside of it, then issue cin{
to edit second list without moving to it. Of course it works backwards (from second to first with cil{
).
Unfortunately, what you have shown is barely acceptable: well, it does work, but you:
- Waste a lot of keystrokes (after all this plugin is all about saving them).
- Have to count a number beforehand which distracts fluid experience.
- Works only if the contents of a both changes are the same, otherwise, you have to move. In my example objects can be completely different.
Of course, your work is splendid, you're free develop your plugin in whatever direction you think is better but for me advanced configuration features are not as important as these basic operators.
Thanks so much for feedback and example. That really helps!
I think I might have found a way to make work in a coherent way by introducing new search methods prev
and next
(maybe even add nearest
for good measure): they won't give preference to covering region, only selecting closest previous or next region. With this, it will be easy to add those.
Thanks so much for feedback and example. That really helps!
I think I might have found a way to make work in a coherent way by introducing new search methods
prev
andnext
(maybe even addnearest
for good measure): they won't give preference to covering region, only selecting closest previous or next region. With this, it will be easy to add those.
I wish you good luck! You've been asking about criteria - I have also remembered that you can add count before operator, so in the previous example you would be able to jump from first to third object with a c2in{
.
I already uses mini.ai
now. Compared to targets.vim, it works pretty better in some text objects like aa
, ia
, etc
and even a}
, i}
, sometimes targets doesn't recognize text objects across multiple lines well.
I never think AI
is useful. So did for nl
once. And not until read the reddit thread did I realize that how can one utilize the potential of nl
. But I do agree that nl
may be useful now after reading those threads.
I already uses
mini.ai
now. Compared to targets.vim, it works pretty better in some text objects likeaa
,ia
, etc and evena}
,i}
, sometimes targets doesn't recognize text objects across long line well. I never thinkAI
is useful. So did fornl
once. And not until read the reddit thread did I realize that how can one utilize the potential ofnl
. But I do agree thatnl
may be useful now after reading those threads.
Thanks for the feedback, this is really helpful. And totally aligns with my experience about both AI
and nl
(and the usefulness of the latter). I am already working on nl
.
(Offtopic: that is some seriously evolved Neovim config you've got there! Although, I am not sure about using cover_or_nearest
: I added it for completeness sake, but don't really like its usability. After you've used it, could you please share your thoughts about it?)
I
I already uses
mini.ai
now. Compared to targets.vim, it works pretty better in some text objects likeaa
,ia
, etc and evena}
,i}
, sometimes targets doesn't recognize text objects across long line well. I never thinkAI
is useful. So did fornl
once. And not until read the reddit thread did I realize that how can one utilize the potential ofnl
. But I do agree thatnl
may be useful now after reading those threads.Thanks for the feedback, this is really helpful. And totally aligns with my experience about both
AI
andnl
(and the usefulness of the latter). I am already working onnl
.(Offtopic: that is some seriously evolved Neovim config you've got there! Although, I am not sure about using
cover_or_nearest
: I added it for completeness sake, but don't really like its usability. After you've used it, could you please share your thoughts about it?)
I do haha, just find this option is interesting and simply want to give it a try. Will try to find some interesting scenario.
@DeadlySquad13, @milanglacier, I've added support for an
/in
/al
/il
mappings. They are basically a
/i
textobjects but with temporarily set search method to new next
/prev
.
Even during this limited time of testing I indeed found it useful to use cina
to edit next argument (instead of not-so-intuitive c2ia
which also doesn't quite work outside function call).
@echasnovski the prev operator works great - it can be dot repeated no problem. But if we run: dina : https://user-images.githubusercontent.com/13521338/181919302-9921ff71-0242-4018-88dd-7ae1f201b2f4.mp4 mini ai skips next arg, and jumps 2x forward. Cool addition. btw. What would be fastest way to add additional mapping : A - which would work as aa (around arg, without removing aa) ?
@echasnovski the prev operator works great - it can be dot repeated no problem. But if we run: dina : https://user-images.githubusercontent.com/13521338/181919302-9921ff71-0242-4018-88dd-7ae1f201b2f4.mp4 mini ai skips next arg, and jumps 2x forward. Cool addition.
Well, this happens because the second time cursor is already on the (previously) second argument and dina
skips it. Imagine you didn't make dina
beforehand and just put cursor there, what would your expectation be after hitting dina
? I think dia
in this case has the same effect (with default search method, of course).
I would expect to be able to . repeat dina - without skipping args: https://user-images.githubusercontent.com/13521338/181919547-ef71ac20-22f6-4676-a671-3b8baccd738f.mp4 I think this is how it worked in targets.vim ? Ah, ok I can see now - if I nudge cursor to left, after first dina, then dot repeat works as expected
btw. What would be fastest way to add additional mapping : A - which would work as aa (around arg, without removing aa) ?
Using mapping without noremap
seems to be the way to go here:
vim.api.nvim_set_keymap('x', 'A', 'aa', { noremap = false })
vim.api.nvim_set_keymap('o', 'A', 'aa', { noremap = false })
However, you loose A
in Virtual-Block mode.
Hey, thanks for your work ! I would like to configure mini.ai to behave like target with a custom config :
autocmd User targets#mappings#user call targets#mappings#extend({
\ 'b': {'argument': [{'o': '(', 'c': ')', 's': ','}]},
\ 'a': {'argument': [{'o': '\[', 'c': '\]', 's': ','}]},
\ 'o': {'argument': [{'o': '{', 'c': '}', 's': ','}]},
\ 'B': {'pair': [{'o':'(', 'c':')'}]},
\ 'A': {'pair': [{'o':'[', 'c':']'}]},
\ 'O': {'pair': [{'o':'{', 'c':'}'}]},
\ 'Q': {'quote': [{'d': '`'}]}
\ })
Is it possible to achieve this with mini.ai ? Thanks
targets.vim
allows me to do ci/
, which is incredibly useful for adjusting only/one/section/in/a/path
. How can do this with ai?
Hey, thanks for your work ! I would like to configure mini.ai to behave like target with a custom config :
autocmd User targets#mappings#user call targets#mappings#extend({ \ 'b': {'argument': [{'o': '(', 'c': ')', 's': ','}]}, \ 'a': {'argument': [{'o': '\[', 'c': '\]', 's': ','}]}, \ 'o': {'argument': [{'o': '{', 'c': '}', 's': ','}]}, \ 'B': {'pair': [{'o':'(', 'c':')'}]}, \ 'A': {'pair': [{'o':'[', 'c':']'}]}, \ 'O': {'pair': [{'o':'{', 'c':'}'}]}, \ 'Q': {'quote': [{'d': '`'}]} \ })
Is it possible to achieve this with mini.ai ?
My pleasure!
Customization is possible with config.custom_textobjects
. Here is everything apart from argument:
require('mini.ai').setup({
custom_textobjects = {
B = { '%b()', '^.().*().$' },
A = { '%b[]', '^.().*().$' },
O = { '%b{}', '^.().*().$' },
Q = { '%b``', '^.().*().$' },
},
})
Argument textobject a
will work with all of those brackets, but I assume you want it to be more targeted, so to speak :) Not possible at the moment, unfortunately. But your are not the first one to request customization of argument textobject, so I am thinking about the best way to do that.
targets.vim
allows me to doci/
, which is incredibly useful for adjustingonly/one/section/in/a/path
. How can do this with ai?
Sure: ci/
will remove between /
and start Insert mode; di/
will remove block with only right /
which results in proper path. This works for any punctuation (ci,
, di_
, etc.), digit, or whitespace (di<Space>
, di\t
). These type of operations were one of the main goals before writing 'mini.ai'.
I just pushed an implementation of MiniAi.gen_spec
. It is a table with specification generators for common textobjects: pair, argument, function call.
@Runeword, now your 'targets.vim' config can be fully achieved with:
local gen_spec = require('mini.ai').gen_spec
require('mini.ai').setup({
custom_textobjects = {
b = gen_spec.argument({ brackets = { '%b()' } }),
a = gen_spec.argument({ brackets = { '%b[]' } }),
o = gen_spec.argument({ brackets = { '%b{}' } }),
B = gen_spec.pair('(', ')', { type = 'balanced' }),
A = gen_spec.pair('[', ']', { type = 'balanced' }),
O = gen_spec.pair('{', '}', { type = 'balanced' }),
Q = gen_spec.pair('`', '`', { type = 'balanced' }),
},
})
local gen_spec = require('mini.ai').gen_spec require('mini.ai').setup({ custom_textobjects = { b = gen_spec.argument({ brackets = { '%b()' } }), a = gen_spec.argument({ brackets = { '%b[]' } }), o = gen_spec.argument({ brackets = { '%b{}' } }), B = gen_spec.pair('(', ')', { type = 'balanced' }), A = gen_spec.pair('[', ']', { type = 'balanced' }), O = gen_spec.pair('{', '}', { type = 'balanced' }), Q = gen_spec.pair('`', '`', { type = 'balanced' }), }, })
Just updated my config, I have switched to mini.ai ! Thanks !
I just pushed an implementation of
MiniAi.gen_spec
. It is a table with specification generators for common textobjects: pair, argument, function call.@Runeword, now your 'targets.vim' config can be fully achieved with:
local gen_spec = require('mini.ai').gen_spec require('mini.ai').setup({ custom_textobjects = { b = gen_spec.argument({ brackets = { '%b()' } }), a = gen_spec.argument({ brackets = { '%b[]' } }), o = gen_spec.argument({ brackets = { '%b{}' } }), B = gen_spec.pair('(', ')', { type = 'balanced' }), A = gen_spec.pair('[', ']', { type = 'balanced' }), O = gen_spec.pair('{', '}', { type = 'balanced' }), Q = gen_spec.pair('`', '`', { type = 'balanced' }), }, })
To be honest, I don't quite understand what does brackets = {'%b()'}
mean in the first example.
But I don't bother by the custom textobjs, I used mini.ai
with default settings and just find it is great, fewer false positives than targets.vim
in many scenerio.
To be honest, I don't quite understand what does
brackets = {'%b()'}
mean in the first example.
It makes argument textobject be recognized only inside paired ()
(like in (aa, bb)
but not [aa, bb]
).
hello!
im testing case from doc:
| b | Alias for | [( *a {bb} )] | | | | |
| | ), ], or } | | | | | |
and using following example:
local str = "this (will {have} a [lot of]) <'surrounding'> `pairs`"
if i put cursor somewhere on 'have' word and do vab
i would expect it to select {have}
, but instead it selecting (will {have} a [lot of])
can you please explain this behaviour?
Hi!
if i put cursor somewhere on 'have' word and do vab i would expect it to select {have}, but instead it selecting (will {have} a [lot of])
Your expectation is absolutely correct. When I execute same steps, I get {have}
selected, so can not reproduce.
Possible reasons why you have (...)
selected:
- For some reason,
require('mini.ai').setup()
was not called. It should be called somewhere within your 'init.lua' (or other files called inside of it) in order to make appropriate mappings. In this case,ab
will refer to Neovim's builtin textobject which coincidentally describes text within()
block. - There is another mapping
ab
for Visual mode resulting in observed selection. If typed quickly (within 'timeoutlen' option), it will take precedence overa
mapping which 'mini.ai' is using.
To eliminate both assumptions, type :xmap a
. It should have line x a * v:lua.MiniAi.expr_textobject('x', 'a')
and not have any line for ab
mapping.
I would absolutely love to see support for goto_next/prev
-functionality, which is something I'm missing quite a bit after switching from treesitter-textobjects
.
I would absolutely love to see support for
goto_next/prev
-functionality, which is something I'm missing quite a bit after switching fromtreesitter-textobjects
.
There is already g[
and g]
which go to left and right end of "current" textobject respectively. So g[{
will go to left side of balanced {}
, while g]{
- to the right. It only respects global search method though, so g[{
with default will jump to next {}
if outside of one.
If you need a closer replication of next
/prev
textobjects, then you can create custom mappings with help of MiniAi.move_cursor()
and passing appropriate textobject id and {search_method = 'next'}
. So something like this:
for _, mode in ipairs({ 'n', 'x', 'o' }) do
vim.api.nvim_set_keymap(
mode, '[{', [[<Cmd>lua MiniAi.move_cursor('left', 'a', '{', { search_method = 'prev' })<CR>]], {}
)
end
Seems to not be an exact replication, but might work.
At this point I am hesitant to add more mappings or options in favor of documenting possible solutions.
Hi!
if i put cursor somewhere on 'have' word and do vab i would expect it to select {have}, but instead it selecting (will {have} a [lot of])
Your expectation is absolutely correct. When I execute same steps, I get
{have}
selected, so can not reproduce.Possible reasons why you have
(...)
selected:
- For some reason,
require('mini.ai').setup()
was not called. It should be called somewhere within your 'init.lua' (or other files called inside of it) in order to make appropriate mappings. In this case,ab
will refer to Neovim's builtin textobject which coincidentally describes text within()
block.- There is another mapping
ab
for Visual mode resulting in observed selection. If typed quickly (within 'timeoutlen' option), it will take precedence overa
mapping which 'mini.ai' is using.To eliminate both assumptions, type
:xmap a
. It should have linex a * v:lua.MiniAi.expr_textobject('x', 'a')
and not have any line forab
mapping.
thank you for rapid and specific answer, there was a conflict in my config. it is working now <3
Glad I could help. Would you mind sharing what it was? If it is not something very custom, it might be helpful for future references.
im sorry but i won't be able to share exact details, because it was a chaos of re-compiling, debugging multiple plugins, and at some point it just started to work after i've reloaded zsh session 🤦🏻
With release of version 0.5.0, 'mini.ai' is now out of beta-testing. Thank you all for your insight!