简体   繁体   中英

using wildcards in vimrc abbreviations

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.

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM