I am writing a mapping to autocomplete tags
Pattern: <.*?>
, matches complete HTML tags only.
The goal is to lookbehind and see if there exists a text like <html>
.
Mapping: inoremap <expr> <leader>< TagComplete()
func! TagComplete() {
let match=search('<.*?>', 'b', '.')
return match
}
Once I run the Mapping in insert mode after typing <html>
, on execution of function TagComplete
, if the pattern is matched, the match
variable should have value <html>
and at the cursor position <\html> should be inserted. Once done the editor should be in insert mode, keeping the cursor between the tags.
I am having difficulty in returning the match
applying search()
.
Also vim does not understand non-greedy ?
in pattern.
EDIT:
I am able to print closing tag:
inoremap <expr> <C-V> AutoCompleteTag()
func! AutoCompleteTag()
let l:match = search('<[^/].\{-}>', 'bn', line("."))
let l:pat="<\zs\/.\{-}\ze>"
if l:match > 0
let l:lastMatch=MatchStrLast(getline(l:match), '<\zs.\{-}\ze>')
if l:lastMatch!~"\/.*"
return '</'.l:lastMatch.'>'
endif
endif
endfunc
" use the {count} parameter for matchstr() to increment your way through the
" string
function! MatchStrLast(expr, pat, ...)
let start = a:0 ? a:1 : 0
let last = ''
let cnt = 1
let found = match(a:expr, a:pat, start, cnt)
while found != -1
let last=matchstr(a:expr, a:pat, start, cnt)
let cnt += 1
let found = match(a:expr, a:pat, start, cnt)
endwhile
return last
endfunction
Explanation:
search('<[^/].\{-}>', 'bn', line("."))
, I am searching to see if a valid tag pattern exits on current line. If yes, store line number inl:match
. Is there a way to search backwards from cursor position and match the opening tag.MatchStrLast(getline(l:match), '<\zs.\{-}\ze>')
, gets the name of the tag.
Concerns:
I am not able to find a way to move the cursor so that it is in the middle of the tags.
Once the mapping is run, it prints a 0 if the match is not found. How not to print anything in case the regexp does not match the pattern?
Also, in if condition if l:lastMatch!~"\/.*"
, I tried the pattern <\zs\/.\{-}\ze>
in place of \/.*
, that I expected to match string "/S.Component", but it did not. Reason?.
Since, I am new to vimscript, I appreciate anyone pointing out an anti-pattern and please suggest improvements.
.*?
is not a valid vim regex pattern, have a look at:h non-greedy
for the correct way of non-greedy patterns.<.*>\{-}
for non greedy match? With this pattern it just matched entire tags with content included<[^>]*>
to match complete tags?\/\?\zs\a\+\ze[ >]
. But I can't get it to match a tag name "S.Container" in<S.Container>
, but it does match "container" in<container>