Reputation: 65
I'm setting up my .vimrc
for writing some HTML and currently have these lines:
abb <buffer> <h1> <h1></h1><ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
abb <buffer> <h2> <h2></h2><ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
abb <buffer> <h3> <h3></h3><ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
abb <buffer> <h4> <h4></h4><ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
abb <buffer> <h5> <h5></h5><ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
abb <buffer> <h6> <h6></h6><ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
Which automatically adds a closing tag to any opening h-tag I write, moves the cursor to the middle of them and gets rid of the whitespace with the function from :helpgrep Eatchar
My qestion is, if there is a more elgant way of doing this, by telling vim to take take <h[1-6]> and adding a closing tag with the same number, instead of having to define each case specifically? Or for that matter, is there a way to define this whole process of adding a closing tag and moving the cursor back as a function and then just specifying all the tags I want it to be applied to? Because below this I have a quite a few lines for a bunch of other tags that look almost identical.
Upvotes: 0
Views: 179
Reputation: 1764
I've written a function to satisfy my similar requirement recently. This feature can be found in other tools like VSCode.
When I type >
, it'll try to look back to check if >
is in a tag like <div>
. If so, it will complete it and set cursor at <div>|</div>
.
Compared with emmet or snippets, this way feels more straightforward.
function! CompleteTag()
let line = getline('.')
let end = col('.') - 1
let begin = end - 1
let tagname_regexp = '[a-zA-Z0-9-]'
while begin > 0
if line[begin] !~ tagname_regexp
break
endif
let begin -= 1
endwhile
if line[begin] == '<'
let tagname = line[begin+1:end-1]
let move = MoveBack(len(tagname)+3)
return '></'.tagname.'>'.move
endif
return '>'
endfunction
function! MoveBack(n)
let move = ''
for i in range(0, a:n-1)
let move .= "\<Left>"
endfor
return move
endfunction
autocmd FileType jsx,html,vue,svelte inoremap<buffer> > <c-r>=CompleteTag()<cr>
autocmd FileType jsx,html,vue,svelte inoremap<buffer> <c-cr> <cr><esc>O
Upvotes: 2
Reputation: 196546
Neither :help abbreviations
nor :help mapping
can use a wildcard on the left hand side. One solution to that kind of problem is to loop over heading levels and create your abbreviations programatically:
for level in range(1, 6)
execute "abbreviate <buffer> <h" .. level .. "> <h" .. level .. "></h" .. level .. "><ESC>?<<CR>i<C-R>=Eatchar('\\m\\s\\<bar>/')<CR>"
endfor
It certainly is a tad more clever but I wonder if the loss of legibility is really worth it.
Upvotes: 2
Reputation: 531165
I'm not sure how to parameterize a single abbreviation; I suspect you'll need to delve into functions for that. You can, however, define a map consisting of the trailing part:
inoremap nowsp <ESC>?<<CR>i<C-R>=Eatchar('\m\s\<bar>/')<CR>
then use that map in your abbreviations
abb <buffer> <h1> <h1></h1>nowsp
abb <buffer> <h2> <h2></h2>nowsp
" etc
Upvotes: 1