dot_vim
This commit is contained in:
parent
f0510126ba
commit
7a7c647c22
212 changed files with 30625 additions and 30625 deletions
327
dot_vim/closetag.vim
Normal file
327
dot_vim/closetag.vim
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
" File: closetag.vim
|
||||
" Summary: Functions and mappings to close open HTML/XML tags
|
||||
" Uses: <C-_> -- close matching open tag
|
||||
" Author: Steven Mueller <diffusor@ugcs.caltech.edu>
|
||||
" Last Modified: Tue May 24 13:29:48 PDT 2005
|
||||
" Version: 0.9.1
|
||||
" XXX - breaks if close attempted while XIM is in preedit mode
|
||||
" TODO - allow usability as a global plugin -
|
||||
" Add g:unaryTagsStack - always contains html tags settings
|
||||
" and g:closetag_default_xml - user should define this to default to xml
|
||||
" When a close is attempted but b:unaryTagsStack undefined,
|
||||
" use b:closetag_html_style to determine if the file is to be treated
|
||||
" as html or xml. Failing that, check the filetype for xml or html.
|
||||
" Finally, default to g:closetag_html_style.
|
||||
" If the file is html, let b:unaryTagsStack=g:unaryTagsStack
|
||||
" otherwise, let b:unaryTagsStack=""
|
||||
" TODO - make matching work for all comments
|
||||
" -- kinda works now, but needs syn sync minlines to be very long
|
||||
" -- Only check whether in syntax in the beginning, then store comment tags
|
||||
" in the tagstacks to determine whether to move into or out of comment mode
|
||||
" TODO - The new normal mode mapping clears recent messages with its <ESC>, and
|
||||
" it doesn't fix the null-undo issue for vim 5.7 anyway.
|
||||
" TODO - make use of the following neat features:
|
||||
" -- the ternary ?: operator
|
||||
" -- :echomsg and :echoerr
|
||||
" -- curly brace expansion for variables and function name definitions?
|
||||
" -- check up on map <blah> \FuncName
|
||||
"
|
||||
" Description:
|
||||
" This script eases redundant typing when writing html or xml files (even if
|
||||
" you're very good with ctrl-p and ctrl-n :). Hitting ctrl-_ will initiate a
|
||||
" search for the most recent open tag above that is not closed in the
|
||||
" intervening space and then insert the matching close tag at the cursor. In
|
||||
" normal mode, the close tag is inserted one character after cursor rather than
|
||||
" at it, as if a<C-_> had been used. This allows putting close tags at the
|
||||
" ends of lines while in normal mode, but disallows inserting them in the
|
||||
" first column.
|
||||
"
|
||||
" For HTML, a configurable list of tags are ignored in the matching process.
|
||||
" By default, the following tags will not be matched and thus not closed
|
||||
" automatically: area, base, br, dd, dt, hr, img, input, link, meta, and
|
||||
" param.
|
||||
"
|
||||
" For XML, all tags must have a closing match or be terminated by />, as in
|
||||
" <empty-element/>. These empty element tags are ignored for matching.
|
||||
"
|
||||
" Comment checking is now handled by vim's internal syntax checking. If tag
|
||||
" closing is initiated outside a comment, only tags outside of comments will
|
||||
" be matched. When closing tags in comments, only tags within comments will
|
||||
" be matched, skipping any non-commented out code (wee!). However, the
|
||||
" process of determining the syntax ID of an arbitrary position can still be
|
||||
" erroneous if a comment is not detected because the syntax highlighting is
|
||||
" out of sync, or really slow if syn sync minlines is large.
|
||||
" Set the b:closetag_disable_synID variable to disable this feature if you
|
||||
" have really big chunks of comment in your code and closing tags is too slow.
|
||||
"
|
||||
" If syntax highlighting is not enabled, comments will not be handled very
|
||||
" well. Commenting out HTML in certain ways may cause a "tag mismatch"
|
||||
" message and no completion. For example, '<!--a href="blah">link!</a-->'
|
||||
" between the cursor and the most recent unclosed open tag above causes
|
||||
" trouble. Properly matched well formed tags in comments don't cause a
|
||||
" problem.
|
||||
"
|
||||
" Install:
|
||||
" To use, place this file in your standard vim scripts directory, and source
|
||||
" it while editing the file you wish to close tags in. If the filetype is not
|
||||
" set or the file is some sort of template with embedded HTML, you may force
|
||||
" HTML style tag matching by first defining the b:closetag_html_style buffer
|
||||
" variable. Otherwise, the default is XML style tag matching.
|
||||
"
|
||||
" Example:
|
||||
" :let b:closetag_html_style=1
|
||||
" :source ~/.vim/scripts/closetag.vim
|
||||
"
|
||||
" For greater convenience, load this script in an autocommand:
|
||||
" :au Filetype html,xml,xsl source ~/.vim/scripts/closetag.vim
|
||||
"
|
||||
" Also, set noignorecase for html files or edit b:unaryTagsStack to match your
|
||||
" capitalization style. You may set this variable before or after loading the
|
||||
" script, or simply change the file itself.
|
||||
"
|
||||
" Configuration Variables:
|
||||
"
|
||||
" b:unaryTagsStack Buffer local string containing a whitespace
|
||||
" seperated list of element names that should be
|
||||
" ignored while finding matching closetags. Checking
|
||||
" is done according to the current setting of the
|
||||
" ignorecase option.
|
||||
"
|
||||
" b:closetag_html_style Define this (as with let b:closetag_html_style=1)
|
||||
" and source the script again to set the
|
||||
" unaryTagsStack to its default value for html.
|
||||
"
|
||||
" b:closetag_disable_synID Define this to disable comment checking if tag
|
||||
" closing is too slow. This can be set or unset
|
||||
" without having to source again.
|
||||
"
|
||||
" Changelog:
|
||||
" May 24, 2005 Tuesday
|
||||
" * Changed function names to be script-local to avoid conflicts with other
|
||||
" scripts' stack implementations.
|
||||
"
|
||||
" June 07, 2001 Thursday
|
||||
" * Added comment handling. Currently relies on synID, so if syn sync
|
||||
" minlines is small, the chance for failure is high, but if minlines is
|
||||
" large, tagclosing becomes rather slow...
|
||||
"
|
||||
" * Changed normal mode closetag mapping to use <C-R> in insert mode
|
||||
" rather than p in normal mode. This has 2 implications:
|
||||
" - Tag closing no longer clobbers the unnamed register
|
||||
" - When tag closing fails or finds no match, no longer adds to the undo
|
||||
" buffer for recent vim 6.0 development versions.
|
||||
" - However, clears the last message when closing tags in normal mode
|
||||
"
|
||||
" * Changed the closetag_html_style variable to be buffer-local rather than
|
||||
" global.
|
||||
"
|
||||
" * Expanded documentation
|
||||
|
||||
"------------------------------------------------------------------------------
|
||||
" User configurable settings
|
||||
"------------------------------------------------------------------------------
|
||||
|
||||
" if html, don't close certain tags. Works best if ignorecase is set.
|
||||
" otherwise, capitalize these elements according to your html editing style
|
||||
if !exists("b:unaryTagsStack") || exists("b:closetag_html_style")
|
||||
if &filetype == "html" || exists("b:closetag_html_style")
|
||||
let b:unaryTagsStack="area base br dd dt hr img input link meta param"
|
||||
else " for xsl and xsl
|
||||
let b:unaryTagsStack=""
|
||||
endif
|
||||
endif
|
||||
|
||||
" Has this already been loaded?
|
||||
if exists("loaded_closetag")
|
||||
finish
|
||||
endif
|
||||
let loaded_closetag=1
|
||||
|
||||
" set up mappings for tag closing
|
||||
inoremap <C-_> <C-R>=GetCloseTag()<CR>
|
||||
map <C-_> a<C-_><ESC>
|
||||
|
||||
"------------------------------------------------------------------------------
|
||||
" Tag closer - uses the stringstack implementation below
|
||||
"------------------------------------------------------------------------------
|
||||
|
||||
" Returns the most recent unclosed tag-name
|
||||
" (ignores tags in the variable referenced by a:unaryTagsStack)
|
||||
function! GetLastOpenTag(unaryTagsStack)
|
||||
" Search backwards through the file line by line using getline()
|
||||
" Overall strategy (moving backwards through the file from the cursor):
|
||||
" Push closing tags onto a stack.
|
||||
" On an opening tag, if the tag matches the stack top, discard both.
|
||||
" -- if the tag doesn't match, signal an error.
|
||||
" -- if the stack is empty, use this tag
|
||||
let linenum=line(".")
|
||||
let lineend=col(".") - 1 " start: cursor position
|
||||
let first=1 " flag for first line searched
|
||||
let b:TagStack="" " main stack of tags
|
||||
let startInComment=s:InComment()
|
||||
|
||||
let tagpat='</\=\(\k\|[-:]\)\+\|/>'
|
||||
" Search for: closing tags </tag, opening tags <tag, and unary tag ends />
|
||||
while (linenum>0)
|
||||
" Every time we see an end-tag, we push it on the stack. When we see an
|
||||
" open tag, if the stack isn't empty, we pop it and see if they match.
|
||||
" If no, signal an error.
|
||||
" If yes, continue searching backwards.
|
||||
" If stack is empty, return this open tag as the one that needs closing.
|
||||
let line=getline(linenum)
|
||||
if first
|
||||
let line=strpart(line,0,lineend)
|
||||
else
|
||||
let lineend=strlen(line)
|
||||
endif
|
||||
let b:lineTagStack=""
|
||||
let mpos=0
|
||||
let b:TagCol=0
|
||||
" Search the current line in the forward direction, pushing any tags
|
||||
" onto a special stack for the current line
|
||||
while (mpos > -1)
|
||||
let mpos=matchend(line,tagpat)
|
||||
if mpos > -1
|
||||
let b:TagCol=b:TagCol+mpos
|
||||
let tag=matchstr(line,tagpat)
|
||||
|
||||
if exists("b:closetag_disable_synID") || startInComment==s:InCommentAt(linenum, b:TagCol)
|
||||
let b:TagLine=linenum
|
||||
call s:Push(matchstr(tag,'[^<>]\+'),"b:lineTagStack")
|
||||
endif
|
||||
"echo "Tag: ".tag." ending at position ".mpos." in '".line."'."
|
||||
let lineend=lineend-mpos
|
||||
let line=strpart(line,mpos,lineend)
|
||||
endif
|
||||
endwhile
|
||||
" Process the current line stack
|
||||
while (!s:EmptystackP("b:lineTagStack"))
|
||||
let tag=s:Pop("b:lineTagStack")
|
||||
if match(tag, "^/") == 0 "found end tag
|
||||
call s:Push(tag,"b:TagStack")
|
||||
"echo linenum." ".b:TagStack
|
||||
elseif s:EmptystackP("b:TagStack") && !s:Instack(tag, a:unaryTagsStack) "found unclosed tag
|
||||
return tag
|
||||
else
|
||||
let endtag=s:Peekstack("b:TagStack")
|
||||
if endtag == "/".tag || endtag == "/"
|
||||
call s:Pop("b:TagStack") "found a open/close tag pair
|
||||
"echo linenum." ".b:TagStack
|
||||
elseif !s:Instack(tag, a:unaryTagsStack) "we have a mismatch error
|
||||
echohl Error
|
||||
echon "\rError:"
|
||||
echohl None
|
||||
echo " tag mismatch: <".tag."> doesn't match <".endtag.">. (Line ".linenum." Tagstack: ".b:TagStack.")"
|
||||
return ""
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
let linenum=linenum-1 | let first=0
|
||||
endwhile
|
||||
" At this point, we have exhausted the file and not found any opening tag
|
||||
echo "No opening tags."
|
||||
return ""
|
||||
endfunction
|
||||
|
||||
" Returns closing tag for most recent unclosed tag, respecting the
|
||||
" current setting of b:unaryTagsStack for tags that should not be closed
|
||||
function! GetCloseTag()
|
||||
let tag=GetLastOpenTag("b:unaryTagsStack")
|
||||
if tag == ""
|
||||
return ""
|
||||
else
|
||||
return "</".tag.">"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" return 1 if the cursor is in a syntactically identified comment field
|
||||
" (fails for empty lines: always returns not-in-comment)
|
||||
function! s:InComment()
|
||||
return synIDattr(synID(line("."), col("."), 0), "name") =~ 'Comment'
|
||||
endfunction
|
||||
|
||||
" return 1 if the position specified is in a syntactically identified comment field
|
||||
function! s:InCommentAt(line, col)
|
||||
return synIDattr(synID(a:line, a:col, 0), "name") =~ 'Comment'
|
||||
endfunction
|
||||
|
||||
"------------------------------------------------------------------------------
|
||||
" String Stacks
|
||||
"------------------------------------------------------------------------------
|
||||
" These are strings of whitespace-separated elements, matched using the \< and
|
||||
" \> patterns after setting the iskeyword option.
|
||||
"
|
||||
" The sname argument should contain a symbolic reference to the stack variable
|
||||
" on which method should operate on (i.e., sname should be a string containing
|
||||
" a fully qualified (ie: g:, b:, etc) variable name.)
|
||||
|
||||
" Helper functions
|
||||
function! s:SetKeywords()
|
||||
let g:IsKeywordBak=&iskeyword
|
||||
let &iskeyword="33-255"
|
||||
endfunction
|
||||
|
||||
function! s:RestoreKeywords()
|
||||
let &iskeyword=g:IsKeywordBak
|
||||
endfunction
|
||||
|
||||
" Push el onto the stack referenced by sname
|
||||
function! s:Push(el, sname)
|
||||
if !s:EmptystackP(a:sname)
|
||||
exe "let ".a:sname."=a:el.' '.".a:sname
|
||||
else
|
||||
exe "let ".a:sname."=a:el"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Check whether the stack is empty
|
||||
function! s:EmptystackP(sname)
|
||||
exe "let stack=".a:sname
|
||||
if match(stack,"^ *$") == 0
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Return 1 if el is in stack sname, else 0.
|
||||
function! s:Instack(el, sname)
|
||||
exe "let stack=".a:sname
|
||||
call s:SetKeywords()
|
||||
let m=match(stack, "\\<".a:el."\\>")
|
||||
call s:RestoreKeywords()
|
||||
if m < 0
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Return the first element in the stack
|
||||
function! s:Peekstack(sname)
|
||||
call s:SetKeywords()
|
||||
exe "let stack=".a:sname
|
||||
let top=matchstr(stack, "\\<.\\{-1,}\\>")
|
||||
call s:RestoreKeywords()
|
||||
return top
|
||||
endfunction
|
||||
|
||||
" Remove and return the first element in the stack
|
||||
function! s:Pop(sname)
|
||||
if s:EmptystackP(a:sname)
|
||||
echo "Error! Stack ".a:sname." is empty and can't be popped."
|
||||
return ""
|
||||
endif
|
||||
exe "let stack=".a:sname
|
||||
" Find the first space, loc is 0-based. Marks the end of 1st elt in stack.
|
||||
call s:SetKeywords()
|
||||
let loc=matchend(stack,"\\<.\\{-1,}\\>")
|
||||
exe "let ".a:sname."=strpart(stack, loc+1, strlen(stack))"
|
||||
let top=strpart(stack, match(stack, "\\<"), loc)
|
||||
call s:RestoreKeywords()
|
||||
return top
|
||||
endfunction
|
||||
|
||||
function! s:Clearstack(sname)
|
||||
exe "let ".a:sname."=''"
|
||||
endfunction
|
||||
Loading…
Add table
Add a link
Reference in a new issue