Another option here is to search for the matching [
that starts the JSON array you're inside. That isn't exactly what you asked (“nearest upward smaller level of indentation”), but in a way it can be better since it doesn't depend on proper indentation of the JSON contents.
Vim has the [{
command to find the nearest unmatched {
. For the nearest [
, there's not a ready-made command you can use directly ([[
is used to navigate "sections" which is something different), but you can build your own using the searchpair()
function.
At the simplest, you can use the following command to find the nearest unmatched [
:
:call searchpair('\[', '', '\]', 'b')
You can make this more robust, by passing searchpair()
an extra {skip}
argument to skip matches that happen inside strings (in which case, you can use the JSON syntax elements to determine whether a match is inside a string), and pass some extra flags s
to mark the spot before the jump (so you can use Ctrl-O
to quickly jump back) and W
to prevent wrapping around the other end of the file.
You can then create mappings for the command, in both directions:
nnoremap <buffer> <silent> [[ :call searchpair('\[', '', '\]', 'bsW', 'synIDattr(synID(line("."), col("."), 0), "name") =~# "^\\(jsonKeyword\\|jsonString\\)"')<CR>
nnoremap <buffer> <silent> ]] :call searchpair('\[', '', '\]', 'sW', 'synIDattr(synID(line("."), col("."), 0), "name") =~# "^\\(jsonKeyword\\|jsonString\\)"')<CR>
These are <buffer>
mappings, so you can add them to a file ~/.vim/ftplugin/json.vim
and they'll be available in JSON files only.
There are possible improvements to these mappings. For example, [{
takes a count to find the Nth unmatched {
and these mappings don't take one (and that can be useful, for instance 99[{
will typically take you to the outermost unmatched {
.) You could implement that in a function that calls searchpair()
repeatedly up to v:count
times.
These mappings also don't work in Visual mode, and they might be useful there if you want to select the whole block (e.g. v[{o]}
will select the block delimited by curly braces.)
But hopefully the knowledge of searchpair()
and the skip expression and the sample naïve mappings will get you started on finding ways to improve on it that will get you the exact features you need.
va[
to select the whole[]
afterfirst
, then use%
to jump to[
and useEsc
to exit visual mode.%
will usually get where you want to go quickly enough. From your highlighted position,%j%
will get you to the line withfirst
, and^
will get you to the start. Starting from the previous item in the list, you would do%j%j%^
- obviously this doesn't scale great if the json or the motion is very complicated.