Closed dbankmann closed 5 years ago
To clarify your feature request:
you want to jump directly to the begin or end of the highest level surrounding environment, most likely with the exception of \begin{document}\end{document}
.
When we consider following example file
\documentclass{article}
\begin{document}
\begin{center}
\begin{align}
a = b (cursor)
\end{align}
\end{center}
\end{document}
you want to navigate directly to the lines with \begin{center}
or \end{center}
.
I have a few thoughts about what you said and what I use:
Do you know that you can extend the selection created by vae
by pressing again ae
? This is much more convenient compared to what you said: vae<Esc>vae<Esc>
vs vaeae...ae<Esc>
.
I often have blank lines around the highest level of surrounding environment, e.g.:
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet.
\begin{table}
\centering
\begin{tabular}{c|c}
CURSOR
\end{tabular}
\caption{<+Caption text+>}
\label{tab:<+label+>}
\end{table}
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet.
I have defined the custom mappings g{
and g}
in the spirit of {
and }
but to place the cursor on the first non-blank line below blank lines:
nnoremap <silent> g}
\ :let old = @/
\ <bar>/^$\n\s*\zs\S<CR>
\ <bar>:nohlsearch
\ <bar>call histdel('/', -1)
\ <bar>let @/ = old<CR>
nnoremap <silent> g{
\ :let old = @/
\ <bar>?\(^$\n\s*\zs\S\)\<bar>\%^<CR>
\ <bar>:nohlsearch
\ <bar>call histdel('/', -1)
\ <bar>let @/ = old<CR>
repmo-vim
Another idea is to use the plugin https://github.com/Houl/repmo-vim. This makes it possible to configure [m
, ]m
, ... so that you can press ;
and ,
to repeat them next to fFtT
.
$MYVIMRC
:
map <expr> ; repmo#LastKey(';')|sunmap ;
map <expr> , repmo#LastRevKey(',')|sunmap ,
for key in [ 'f', 'F', 't', 'T']
execute 'noremap <expr> '.key." repmo#ZapKey('".key."')|sunmap ".key
endfor
~/.vim/after/ftplugin/tex.vim
:
map <expr><buffer> ]] repmo#Key('<plug>(vimtex-]])', '<plug>(vimtex-[[)')|sunmap <buffer> ]]
map <expr><buffer> [[ repmo#Key('<plug>(vimtex-[[)', '<plug>(vimtex-]])')|sunmap <buffer> [[
map <expr><buffer> ][ repmo#Key('<plug>(vimtex-][)', '<plug>(vimtex-[])')|sunmap <buffer> ][
map <expr><buffer> [] repmo#Key('<plug>(vimtex-[])', '<plug>(vimtex-][)')|sunmap <buffer> []
map <expr><buffer> ]m repmo#Key('<plug>(vimtex-]m)', '<plug>(vimtex-[m)')|sunmap <buffer> ]m
map <expr><buffer> [m repmo#Key('<plug>(vimtex-[m)', '<plug>(vimtex-]m)')|sunmap <buffer> [m
map <expr><buffer> ]M repmo#Key('<plug>(vimtex-]M)', '<plug>(vimtex-[M)')|sunmap <buffer> ]M
map <expr><buffer> [M repmo#Key('<plug>(vimtex-[M)', '<plug>(vimtex-]M)')|sunmap <buffer> [M
map <expr><buffer> ]* repmo#Key('<plug>(vimtex-]*)', '<plug>(vimtex-[*)')|sunmap <buffer> ]*
map <expr><buffer> [* repmo#Key('<plug>(vimtex-[*)', '<plug>(vimtex-]*)')|sunmap <buffer> [*
map <expr><buffer> ]/ repmo#Key('<plug>(vimtex-]/)', '<plug>(vimtex-[/)')|sunmap <buffer> ]/
map <expr><buffer> [/ repmo#Key('<plug>(vimtex-[/)', '<plug>(vimtex-]/)')|sunmap <buffer> [/
Now you would press [m;
to reach the line \begin{center}
and ]m;
to reach the line \end{center}
. Repeated pressing of ;
is much more pleasant. Overshooting can be undone with ,
.
Wow, thanks for all the input. There's definitely some stuff I gonna try out. Especially, the repmo
plugin sounds useful.
And no, I didn't really know of extending selections. That's pretty useful, as long as I'm moving forwards.
To clarify your feature request: you want to jump directly to the begin or end of the highest level surrounding environment, most likely with the exception of
\begin{document}\end{document}
.
That's only half of the truth. I want to be able to move between beginnings/ends of different levels of environments (in the current buffer). I guess you would need 3 different movements for each type of movement (forwards/backwards , to the end/beginning of environment), for example for moving to the next endings:
]A
for moving to the next ending of an environment in the current level]B
for moving to the next ending of an environment in the next upper level]C
for moving to the next ending of an environment in the next lower level(I know that the proposed mappings are bad choices, this is just for illustration) Let me show this with your (updated) example:
\documentclass{article}
\begin{document}
\begin{center}
\begin{someenv}
Some text (cursor)
\begin{align}
a = b
\begin{matrix}
a & b\\
c & d
\end{matrix} ]M
\begin{matrix}
a & b\\
c & d
\end{matrix} ]M]M
\end{align} ]C or ]M]M]M
Some text
\begin{align}
\begin{matrix}
a & b\\
c & d
\end{matrix}
a = b
\end{align} ]C]A
\end{someenv} ]A or ]M;;;; with repmo
\end{center} ]B
\end{document}
The extended example is very helpful to understand you better.
I can point you to a few more related motions:
MOVING BASED ON FOLDS [z
]z
zj
zk
]z
moves to the end of the current fold. If you have enabled folding for environments, you can move in your example to the line marked with ]A
by ]z
. However, if there is another type of fold it could interfer.
PLUGIN MATCHUP [%
]%
The plugin vim-matchup
defines [%
and ]%
. This allows you to move in the given example to the line marked with ]A
by pressing ]%
also when folding is disabled. However, if you are within parentheses, brackets, etc, it also requires several presses.
Note if you install vim-matchup, you have to tell it that it should overwrite vimtex:
:h matchup-latex
By default, match-up is disabled for tex files when the plugin |vimtex| is detected. To enable match-up for tex files, use the following in your vimrc:
let g:matchup_override_vimtex = 1
MOTIONS BASED ON INDENTATION Maybe motions based on indentation could be another alternative which offer following plugins:
[%
and ]%
)GENERAL MOTIONS
I am also not sure if you actually want your cursor on the \end{...}
lines eventually (they hardly change). You probably need another motion for your final target anyway. Therefore, consider also other means for navigation, e.g. navigation by searching (/target text
) and the popular plugins
That's getting very close to what I wanted!
At least the mapping for ]C
looks perfectly fine.
The problem I see with the ]z
mappings is that they behave quite differently to the ]m
mappings. The folds are somehow defined by the inner part of an environment, whereas the ]m
mappings use the outer part as well.
For example, pressing ]z
when at a \begin{env}
line will not bring me to the \end{env}
line of that environment. When there is no more nested environments inside env
, ]m
would do that and so would my ideal mapping.
This allows you to move to the line marked with ]A by pressing ]% also when folding is disabled. This does not work for me without
vim-matchup
. This is the mapping without the plugin:]% * :<C-U>call <SNR>77_MultiMatch("W", "n") <CR>
I am also not sure if you actually want your cursor on the \end{...} lines eventually (they hardly change). >You probably need another motion for your final target anyway. Therefore, consider also other means >for navigation, e.g. navigation by searching (/target text) and the popular plugins
- Yes, I 'd like to end on the
\begin/ \end{...}
lines eventually. Then I can start writing my stuff withO\o
- The popular navigation plugins seem to be quite nice, however I would prefer a more systematic/natural approach (sometimes for example, environments of the same type nest or nested environments have similar names (columns vs column))
//Edit: I got a bit confused by all the edits ;) So my answer may not be 100% directed to your latest edit. I'm going to review this later today.
Sorry for the edits. I was getting a little bit too optimistic. However, a water-proof solution needs more than nmap ]A [m%
which you probably could have done yourself anyway.
So I just reduced my comment to the basic ingredients I was considering.
Yes, I 'd like to end on the \begin/ \end{...} lines eventually. Then I can start writing my stuff with O\o
I see.
I am starting to laugh about myself: there is another plugin you might find interesting: vim-ninja-feet
This plugin allows you to enter insert mode before or behind a text object or motion, including the ones from vimtex.
Example:
When we consider again your example, press z]ae
to enter insert mode after \end{someenv}
.
If ae
would operate linewise, a new line would be opened instead of just entering insert mode. Try for example z]]z
which opens a line before ]A
line.
I have played with this as well and extended vim-ninja-feet by Z[
and Z]
to enforce opening always a newline regardless of the nature of the text object. Apply following patch to try Z]ae
for yourself:
❯ g diff
diff --git a/plugin/ninja-feet.vim b/plugin/ninja-feet.vim
index 661a641..1797bf9 100644
--- a/plugin/ninja-feet.vim
+++ b/plugin/ninja-feet.vim
@@ -37,6 +37,16 @@ function! s:ninja_append(mode)
call feedkeys('`]'.op, 'n')
endfunction
+function! s:ninja_open_above(mode)
+ let op = 'O'
+ call feedkeys('`['.op, 'n')
+endfunction
+
+function! s:ninja_open_below(mode)
+ let op = 'o'
+ call feedkeys('`]'.op, 'n')
+endfunction
+
function! s:map_expr(sid, type, direction, count)
let map = ''
let map .= "\<Esc>"
@@ -58,6 +68,8 @@ onoremap <silent> <expr> <Plug>(ninja-right-foot-a) <SID>map_expr("<SID>", '
nnoremap <silent> <Plug>(ninja-insert) :<C-U>set operatorfunc=<SID>ninja_insert<CR>g@
nnoremap <silent> <Plug>(ninja-append) :<C-U>set operatorfunc=<SID>ninja_append<CR>g@
+nnoremap <silent> <Plug>(ninja-open-above) :<C-U>set operatorfunc=<SID>ninja_open_above<CR>g@
+nnoremap <silent> <Plug>(ninja-open-below) :<C-U>set operatorfunc=<SID>ninja_open_below<CR>g@
if !exists('g:ninja_feet_no_mappings')
call s:map('[i', "<Plug>(ninja-left-foot-inner)", 'o')
@@ -67,4 +79,6 @@ if !exists('g:ninja_feet_no_mappings')
call s:map('z[', "<Plug>(ninja-insert)", 'n')
call s:map('z]', "<Plug>(ninja-append)", 'n')
+ call s:map('Z[', "<Plug>(ninja-open-above)", 'n')
+ call s:map('Z]', "<Plug>(ninja-open-below)", 'n')
endif
nmap [C [M%
nmap ]C ]m%
At least the mapping for ]C looks perfectly fine.
Great.
I have tried another version for ]A
and ]B
based on text objects:
nmap [A vaeo<Esc>
nmap ]A vae<Esc>
nmap [B vaeaeo<Esc>
nmap ]B vaeae<Esc>
Could you give it a spin?
A more polished version with a different choice of mappings ([+,[=,[-,]-,]=,]+
) which I would be inclined to use by myself:
~/.vim/after/ftplugin/tex.vim
:
" ===================================================================
" Jump to the start/end of the current/surrounding/nested environment
" ===================================================================
" https://github.com/lervag/vimtex/issues/1299
" uses ae, [M, and ]m from vimtex
" CURRENT SURROUNDING ENVIRONMENT
noremap <buffer><silent> <Plug>(move-begin-current-env) :normal vaeoV<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-current-env) :normal vaeV<CR><Esc>
" PARENT SURROUNDING ENVIRONMENT
noremap <buffer><silent> <Plug>(move-begin-surr-env) :normal vaeaeoV<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-surr-env) :normal vaeaeV<CR><Esc>
" PREV/NEXT NESTED ENVIRONMENT
noremap <buffer><silent> <Plug>(move-begin-prev-nested-env) :normal $[MvaeoV<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-next-nested-env) :normal ]mvaeV<CR><Esc>
" Mappings [+,[=,[-,]-,]=,]+
" choice stolen from indentwise
map <buffer> [= <Plug>(move-begin-current-env)
map <buffer> ]= <Plug>(move-end-current-env)
map <buffer> [+ <Plug>(move-begin-surr-env)
map <buffer> ]+ <Plug>(move-end-surr-env)
map <buffer> [- <Plug>(move-begin-prev-nested-env)
map <buffer> ]- <Plug>(move-end-next-nested-env)
" Repmo (not entirely clear)
map <expr><buffer> [= repmo#Key('<plug>(move-begin-current-env)', '<plug>(move-end-current-env)')|sunmap <buffer> [=
map <expr><buffer> ]= repmo#Key('<plug>(move-end-current-env)', '<plug>(move-begin-current-env)')|sunmap <buffer> ]=
map <expr><buffer> [+ repmo#Key('<plug>(move-begin-surr-env)', '<plug>(vimtex-]m)')|sunmap <buffer> [+
map <expr><buffer> ]+ repmo#Key('<plug>(move-end-surr-env)', '<plug>(vimtex-[M)')|sunmap <buffer> ]+
map <expr><buffer> [- repmo#Key('<plug>(move-begin-prev-nested-env)', '<plug>(move-end-surr-env)')|sunmap <buffer> [-
map <expr><buffer> ]- repmo#Key('<plug>(move-end-next-nested-env)', '<plug>(move-begin-surr-env)')|sunmap <buffer> ]-
\documentclass{article}
\begin{document} % [+[+ (FIX POINT)
\begin{center} % [+
more text to come
\begin{someenv} % [= (FIX POINT)
\begin{align} % [- (FIX POINT)
a = b
\begin{matrix} % [m[m
a & b\\
c & d
\end{matrix}
\begin{matrix} % [m
a & b\\
c & d
\end{matrix} % [M[M
\end{align} % [M
more text
Some text % CURSOR
more text
\begin{align} % ]m
a = b
\begin{matrix} % ]m]m
a & b\\
c & d
\end{matrix} % ]M
\begin{matrix}
a & b\\
c & d
\end{matrix} % ]M]M
\end{align} % ]-
more text
\begin{align}
\begin{matrix}
a & b\\
c & d
\end{matrix}
a = b
\end{align} % ]-]- (FIX POINT)
\end{someenv} % ]= (FIX POINT)
more text to come.
\end{center} % ]+
\end{document} % ]+]+ (FIX POINT)
Try them also with vim-ninja-feet:
z]]=
z]]+
z]]-
However, still some issues, features (e.g. support of counts) and clarifications (e.g. repeat [-
, ]-
with repmo) remain.
I am starting to laugh about myself: there is another plugin you might find interesting: vim-ninja-feet Indeed, an interesting plugin. I'm just wondering, whether its really easier/saving keystrokes vs. motion +
o/O
Thanks a lot for the snippet. I tried it for a bit, and in principle it seems to do the right thing. A few things I noted:
[=
I end up at the b
of the begin{...}
line when the repmo mappings are not used. If I enter the command manually, it works as expected.\end{...}
, so appending [M
might make sense.[=
, ]=
has no effect at the moment.[=
]=
should move over to the next env of the same level (which they currently are not) I'm going to have a deeper look tomorrow.
Indeed, an interesting plugin. I'm just wondering, whether its really easier/saving keystrokes vs. motion +
o/O
I agree. z]
and z[
from vim-ninja-feet are only really useful for situations where there is only a text object not an equivalent motion. Since there is right now no real equivalent for ae
and you also want to open a new line, I think this situation is the perfect candidate for vim-ninja-feet.
This would be even more perfect if vimtex's text object would support counts and targets.vim (if used). See also the end of this comment.
As already pointed out vimtex enables by default folding for environments which means ]z
can move to the end of the current environment. It also accepts counts which is useful to have the motion equivalent of your ]B
. Therefore consider again this:
]A = ]z
]B = 2]z
]C = ]m]z
I also mentioned ]%
from vim-matchup which also accepts counts:
]A = ]%
]B = 2]%
]C = ]m%
I think both options are not too complicated and could help you out in many situations.
repmo-vim
can be used as well to go interactively to the correct level you are interested in:
]B
case: ]z
or ]%
and then followed by as many ;
as you wish]C
case: ]m
and then followed by as many ;
as you wish and finally press %
to go to the end.
vim-matchup
can highlight the \end{}
line already when pressing ;
to be sure that you have reached the correct level. The other direction works equally well.
Back to the new motions:
- When pressing
[=
I end up at theb
of thebegin{...}
line when the repmo mappings are not used. If I enter the command manually, it works as expected.
There was a hidden space in my snippet. Following does not contain a space at the end of line:
map <buffer> [= <Plug>(move-begin-current-env)
- Maybe motions going to the end of an environment could also end at the beginning of
\end{...}
, so appending[M
might make sense.
This is possible by inserting a B
into the expression:
noremap <buffer><silent> <Plug>(move-end-current-env) :normal vaeBV<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-surr-env) :normal vaeaeBV<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-next-nested-env) :normal ]mvaeBV<CR><Esc>
- There is some visual noise caused by going to visual mode for a few milliseconds. I guess there is no easy way to fix this?
I tried to enforce linewise operation by adding V
. Does it help to remove the noise when V
is not appended?
noremap <buffer><silent> <Plug>(move-begin-current-env) :normal vaeo<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-current-env) :normal vaeB<CR><Esc>
noremap <buffer><silent> <Plug>(move-begin-surr-env) :normal vaeaeo<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-surr-env) :normal vaeaeB<CR><Esc>
noremap <buffer><silent> <Plug>(move-begin-prev-nested-env) :normal $[Mvaeo<CR><Esc>
noremap <buffer><silent> <Plug>(move-end-next-nested-env) :normal ]mvaeB<CR><Esc>
- The repmo stuff seems to work. Although [=, ]= has no effect at the moment.
Well, for me pressing ;
and ,
do the same as pressing %
which is also not really helpful.
- I guess, repeating the [= ]= should move over to the next env of the same level (which they currently are not)
This probably needs more logic and an actual function.
Right now I am not up to implement them correctly: there are even more things to consider e.g. they also do not work in visual mode, do not support counts and do not update jump history (maybe easily solved by prepending m`
).
ae
However, I would like to see vimtex improved in following two ways:
n
and l
(next and previous). This is probably more complicated.This would allow you to open new lines at the desired lines with vim-ninja-feet:
z]ae
(for ]A
)z]2ae
(for ]B
)z]ane
(for ]C
)No need to find unoccupied normal mode motion commands which is notoriously difficult without someone complaining about the new mappings.
Hi guys. Sorry for not participating here sooner, life's been very busy lately. I'll read up on the issue when I get the time.
I've added support for counts to the environment text objects (e.g. ie
, i$
and id
). I can probably also add this for sections and perhaps also commands. Not sure how important you feel those TOs are wrt. this feature?
@kiryph Do you know what it would require to support targets.vim for the n
and l
specifiers?
@lervag Thank you for adding support for counts.
Could you mention this in the documentation? In particular, if not all of them accept counts.
I can probably also add this for sections and perhaps also commands. Not sure how important you feel those TOs are wrt. this feature?
I guess it depends on the individual. For instance, I would have said support for i$
is not so important because I rarely nest inline equations like this $a=b \text{$a$ relates to $b$}$
. Nested commands occur very often. The different section levels are nested more or less always.
As long as a feature does not exist I obviously do not use it. For example, the motions [m
are relatively new. I raised the feature request #1147 in June 2018. But I am not suprised that others find them useful as well:
First, I really like the motions [m, [M, etc. . (by dbacc)
Also consistency would be a reason for me to add this. I do not want to recall which ones support counts and which ones do not.
Do you know what it would require to support targets.vim for the
n
andl
specifiers?
I quote https://github.com/wellle/targets.vim/blob/master/plugins.md#plugins
It's possible to extend targets.vim by adding new sources. Text objects implemented as targets.vim plugin will automatically gain all the functionality of the built in ones. Most notably you can use
n
andl
to select next and last one, provide counts to pick a specific one, use seeking (vix
pick current, next or last), growing (vixix
is the same asv2ix
etc.) and skippingvinxinx
is the same asv2inx
).
This extensibility feature of targets.vim is documented via this file https://github.com/wellle/targets.vim/blob/master/plugins.md and the plugin https://github.com/wellle/line-targets.vim serves as a tutorial. The documentation of targets.vim is not relevant and is dedicated to the 'end-user'.
So in order to understand how this works following files should help:
The builtin objects in targets.vim are apparently implemented the same way and could serve as another source to figure things out.
What do you think?
I tried to enforce linewise operation by adding V. Does it help to remove the noise when V is not >appended?
No, it doesn't. I guess that's because of switching to visual mode in general.
Anyway, I can definitely live with the current suggestion, although your last suggestion using targets.vim
and motions sounds very appealing.
Could you mention this in the documentation? In particular, if not all of them accept counts.
Yes, but I'll first finish the implementations. If you have any suggestions for how to best update the docs, that'll be helpful.
I guess it depends on the individual. For instance, I would have said support for i$ is not so important because I rarely nest inline equations like this $a=b \text{$a$ relates to $b$}$. Nested commands occur very often. The different section levels are nested more or less always.
Support for i$
came automatically with support for ie
and id
. But I agree it does not really make sense.
Also consistency would be a reason for me to add this. I do not want to recall which ones support counts and which ones do not.
Agreed, and good point. I'll work on it.
Regarding support for targets.vim, I'm not so sure. I'll look into it if there is an easy way to use/adapt the current code and to use targets.vim if available, though. If it is not so hard, then it seems worth the effort. Thanks for the hints and relevant links.
I'll add for iP/aP
as well when I get the time. Not it should work for all the other text objects.
Support for i$ came automatically with support for ie and id. But I agree it does not really make sense.
I am not sure if makes no sense but as I said I think it occurs rarely.
I'll add for iP/aP as well when I get the time. Note it should work for all the other text objects.
Thanks a lot.
I'm closing this since the remaining task is covered by #1315.
First, I really like the motions [m, [M, etc. . However, sometimes when writing up my latex stuff, they are a bit counter-intuitive. Sometimes, I really have long equation/align environments with lots of subenvironments. It is not really feasible to count all of that subenvironments to simply go to the end of the surrounding environment.
It would be nice to have additional motions that allow me to go to the beginning/end of surrounding environments. In principle you could just do
vae<ESC>
andvae<<ESC>
, but that's a bit cumbersome.