--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vim/bundle/nerdcommenter/plugin/NERD_commenter.vim Wed Jun 09 17:53:48 2010 -0400
@@ -0,0 +1,3146 @@
+" ============================================================================
+" File: NERD_commenter.vim
+" Description: vim global plugin that provides easy code commenting
+" Maintainer: Martin Grenfell <martin_grenfell at msn dot com>
+" Version: 2.2.2
+" Last Change: 30th March, 2008
+" License: This program is free software. It comes without any warranty,
+" to the extent permitted by applicable law. You can redistribute
+" it and/or modify it under the terms of the Do What The Fuck You
+" Want To Public License, Version 2, as published by Sam Hocevar.
+" See http://sam.zoy.org/wtfpl/COPYING for more details.
+"
+" ============================================================================
+
+" Section: script init stuff {{{1
+if exists("loaded_nerd_comments")
+ finish
+endif
+if v:version < 700
+ echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
+ finish
+endif
+let loaded_nerd_comments = 1
+
+" Function: s:InitVariable() function {{{2
+" This function is used to initialise a given variable to a given value. The
+" variable is only initialised if it does not exist prior
+"
+" Args:
+" -var: the name of the var to be initialised
+" -value: the value to initialise var to
+"
+" Returns:
+" 1 if the var is set, 0 otherwise
+function s:InitVariable(var, value)
+ if !exists(a:var)
+ exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
+ return 1
+ endif
+ return 0
+endfunction
+
+" Section: space string init{{{2
+" When putting spaces after the left delim and before the right we use
+" s:spaceStr for the space char. This way we can make it add anything after
+" the left and before the right by modifying this variable
+let s:spaceStr = ' '
+let s:lenSpaceStr = strlen(s:spaceStr)
+
+" Section: variable init calls {{{2
+call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
+call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
+call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
+call s:InitVariable("g:NERDCompactSexyComs", 0)
+call s:InitVariable("g:NERDCreateDefaultMappings", 1)
+call s:InitVariable("g:NERDDefaultNesting", 1)
+call s:InitVariable("g:NERDMenuMode", 3)
+call s:InitVariable("g:NERDLPlace", "[>")
+call s:InitVariable("g:NERDUsePlaceHolders", 1)
+call s:InitVariable("g:NERDRemoveAltComs", 1)
+call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
+call s:InitVariable("g:NERDRPlace", "<]")
+call s:InitVariable("g:NERDSpaceDelims", 0)
+call s:InitVariable("g:NERDDelimiterRequests", 1)
+
+
+
+let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
+
+" Section: Comment mapping functions, autocommands and commands {{{1
+" ============================================================================
+" Section: Comment enabler autocommands {{{2
+" ============================================================================
+
+augroup commentEnablers
+
+ "if the user enters a buffer or reads a buffer then we gotta set up
+ "the comment delimiters for that new filetype
+ autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0)
+
+ "if the filetype of a buffer changes, force the script to reset the
+ "delims for the buffer
+ autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1)
+augroup END
+
+
+" Function: s:SetUpForNewFiletype(filetype) function {{{2
+" This function is responsible for setting up buffer scoped variables for the
+" given filetype.
+"
+" These variables include the comment delimiters for the given filetype and calls
+" MapDelimiters or MapDelimitersWithAlternative passing in these delimiters.
+"
+" Args:
+" -filetype: the filetype to set delimiters for
+" -forceReset: 1 if the delimiters should be reset if they have already be
+" set for this buffer.
+"
+function s:SetUpForNewFiletype(filetype, forceReset)
+ "if we have already set the delimiters for this buffer then dont go thru
+ "it again
+ if !a:forceReset && exists("b:NERDLeft") && b:NERDLeft != ''
+ return
+ endif
+
+ let b:NERDSexyComMarker = ''
+
+ "check the filetype against all known filetypes to see if we have
+ "hardcoded the comment delimiters to use
+ if a:filetype ==? ""
+ call s:MapDelimiters('', '')
+ elseif a:filetype ==? "aap"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "abc"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "acedb"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "actionscript"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "ada"
+ call s:MapDelimitersWithAlternative('--','', '-- ', '')
+ elseif a:filetype ==? "ahdl"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "ahk"
+ call s:MapDelimitersWithAlternative(';', '', '/*', '*/')
+ elseif a:filetype ==? "amiga"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "aml"
+ call s:MapDelimiters('/*', '')
+ elseif a:filetype ==? "ampl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "apache"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "apachestyle"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "asciidoc"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "applescript"
+ call s:MapDelimitersWithAlternative('--', '', '(*', '*)')
+ elseif a:filetype ==? "asm68k"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "asm"
+ call s:MapDelimitersWithAlternative(';', '', '#', '')
+ elseif a:filetype ==? "asn"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "aspvbs"
+ call s:MapDelimiters('''', '')
+ elseif a:filetype ==? "asterisk"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "asy"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "atlas"
+ call s:MapDelimiters('C','$')
+ elseif a:filetype ==? "autohotkey"
+ call s:MapDelimiters(';','')
+ elseif a:filetype ==? "autoit"
+ call s:MapDelimiters(';','')
+ elseif a:filetype ==? "ave"
+ call s:MapDelimiters("'",'')
+ elseif a:filetype ==? "awk"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "basic"
+ call s:MapDelimitersWithAlternative("'",'', 'REM ', '')
+ elseif a:filetype ==? "bbx"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "bc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "bib"
+ call s:MapDelimiters('%','')
+ elseif a:filetype ==? "bindzone"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "bst"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "btm"
+ call s:MapDelimiters('::', '')
+ elseif a:filetype ==? "caos"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "calibre"
+ call s:MapDelimiters('//','')
+ elseif a:filetype ==? "catalog"
+ call s:MapDelimiters('--','--')
+ elseif a:filetype ==? "c"
+ call s:MapDelimitersWithAlternative('/*','*/', '//', '')
+ elseif a:filetype ==? "cfg"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "cg"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "ch"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "cl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "clean"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "clipper"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "clojure"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "cmake"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "conkyrc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "cpp"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "crontab"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "cs"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "csp"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "cterm"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "cucumber"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "cvs"
+ call s:MapDelimiters('CVS:','')
+ elseif a:filetype ==? "d"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "dcl"
+ call s:MapDelimiters('$!', '')
+ elseif a:filetype ==? "dakota"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "debcontrol"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "debsources"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "def"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "desktop"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "dhcpd"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "diff"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "django"
+ call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
+ elseif a:filetype ==? "docbk"
+ call s:MapDelimiters('<!--', '-->')
+ elseif a:filetype ==? "dns"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "dosbatch"
+ call s:MapDelimitersWithAlternative('REM ','', '::', '')
+ elseif a:filetype ==? "dosini"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "dot"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "dracula"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "dsl"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "dtml"
+ call s:MapDelimiters('<dtml-comment>','</dtml-comment>')
+ elseif a:filetype ==? "dylan"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? 'ebuild'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "ecd"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? 'eclass'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "eiffel"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "elf"
+ call s:MapDelimiters("'", '')
+ elseif a:filetype ==? "elmfilt"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "erlang"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "eruby"
+ call s:MapDelimitersWithAlternative('<%#', '%>', '<!--', '-->')
+ elseif a:filetype ==? "expect"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "exports"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "factor"
+ call s:MapDelimitersWithAlternative('! ', '', '!# ', '')
+ elseif a:filetype ==? "fgl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "focexec"
+ call s:MapDelimiters('-*', '')
+ elseif a:filetype ==? "form"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "foxpro"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "fstab"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "fvwm"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "fx"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "gams"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "gdb"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "gdmo"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "geek"
+ call s:MapDelimiters('GEEK_COMMENT:', '')
+ elseif a:filetype ==? "genshi"
+ call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
+ elseif a:filetype ==? "gentoo-conf-d"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "gentoo-env-d"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "gentoo-init-d"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "gentoo-make-conf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? 'gentoo-package-keywords'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? 'gentoo-package-mask'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? 'gentoo-package-use'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? 'gitcommit'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? 'gitconfig'
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? 'gitrebase'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "gnuplot"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "groovy"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "gtkrc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "haskell"
+ call s:MapDelimitersWithAlternative('{-','-}', '--', '')
+ elseif a:filetype ==? "hb"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "h"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "haml"
+ call s:MapDelimitersWithAlternative('-#', '', '/', '')
+ elseif a:filetype ==? "hercules"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "hog"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "hostsaccess"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "htmlcheetah"
+ call s:MapDelimiters('##','')
+ elseif a:filetype ==? "htmldjango"
+ call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
+ elseif a:filetype ==? "htmlos"
+ call s:MapDelimiters('#','/#')
+ elseif a:filetype ==? "ia64"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "icon"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "idlang"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "idl"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "inform"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype ==? "inittab"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "ishd"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "iss"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "ist"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "java"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "javacc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "javascript"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "javascript.jquery"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "jess"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "jgraph"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "jproperties"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "jsp"
+ call s:MapDelimiters('<%--', '--%>')
+ elseif a:filetype ==? "kix"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "kscript"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "lace"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "ldif"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "lilo"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "lilypond"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "liquid"
+ call s:MapDelimiters('{%', '%}')
+ elseif a:filetype ==? "lisp"
+ call s:MapDelimitersWithAlternative(';','', '#|', '|#')
+ elseif a:filetype ==? "llvm"
+ call s:MapDelimiters(';','')
+ elseif a:filetype ==? "lotos"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "lout"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "lprolog"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "lscript"
+ call s:MapDelimiters("'", '')
+ elseif a:filetype ==? "lss"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "lua"
+ call s:MapDelimitersWithAlternative('--','', '--[[', ']]')
+ elseif a:filetype ==? "lynx"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "lytex"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "mail"
+ call s:MapDelimiters('> ','')
+ elseif a:filetype ==? "mako"
+ call s:MapDelimiters('##', '')
+ elseif a:filetype ==? "man"
+ call s:MapDelimiters('."', '')
+ elseif a:filetype ==? "map"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "maple"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "markdown"
+ call s:MapDelimiters('<!--', '-->')
+ elseif a:filetype ==? "masm"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "mason"
+ call s:MapDelimiters('<% #', '%>')
+ elseif a:filetype ==? "master"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype ==? "matlab"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "mel"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "mib"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "mkd"
+ call s:MapDelimiters('>', '')
+ elseif a:filetype ==? "mma"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "model"
+ call s:MapDelimiters('$','$')
+ elseif a:filetype =~ "moduala."
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "modula2"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "modula3"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "monk"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "mush"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "named"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "nasm"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "nastran"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype ==? "natural"
+ call s:MapDelimiters('/*', '')
+ elseif a:filetype ==? "ncf"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "newlisp"
+ call s:MapDelimiters(';','')
+ elseif a:filetype ==? "nroff"
+ call s:MapDelimiters('\"', '')
+ elseif a:filetype ==? "nsis"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "ntp"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "objc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "objcpp"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "objj"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "ocaml"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "occam"
+ call s:MapDelimiters('--','')
+ elseif a:filetype ==? "omlet"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "omnimark"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "openroad"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "opl"
+ call s:MapDelimiters("REM", "")
+ elseif a:filetype ==? "ora"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "ox"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "pascal"
+ call s:MapDelimitersWithAlternative('{','}', '(*', '*)')
+ elseif a:filetype ==? "patran"
+ call s:MapDelimitersWithAlternative('$','','/*', '*/')
+ elseif a:filetype ==? "pcap"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "pccts"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "pdf"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "pfmain"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "php"
+ call s:MapDelimitersWithAlternative('//','','/*', '*/')
+ elseif a:filetype ==? "pic"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "pike"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "pilrc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "pine"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "plm"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "plsql"
+ call s:MapDelimitersWithAlternative('--', '', '/*', '*/')
+ elseif a:filetype ==? "po"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "postscr"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "pov"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "povini"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "ppd"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "ppwiz"
+ call s:MapDelimiters(';;', '')
+ elseif a:filetype ==? "processing"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "prolog"
+ call s:MapDelimitersWithAlternative('%','','/*','*/')
+ elseif a:filetype ==? "ps1"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "psf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "ptcap"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "python"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "radiance"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "ratpoison"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "r"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "rc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "rebol"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "registry"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "remind"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "resolv"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "rgb"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype ==? "rib"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "robots"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "sa"
+ call s:MapDelimiters('--','')
+ elseif a:filetype ==? "samba"
+ call s:MapDelimitersWithAlternative(';','', '#', '')
+ elseif a:filetype ==? "sass"
+ call s:MapDelimitersWithAlternative('//','', '/*', '')
+ elseif a:filetype ==? "sather"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "scala"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "scilab"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "scsh"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "sed"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "sgmldecl"
+ call s:MapDelimiters('--','--')
+ elseif a:filetype ==? "sgmllnx"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype ==? "sicad"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "simula"
+ call s:MapDelimitersWithAlternative('%', '', '--', '')
+ elseif a:filetype ==? "sinda"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype ==? "skill"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "slang"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "slice"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "slrnrc"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "sm"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "smarty"
+ call s:MapDelimiters('{*', '*}')
+ elseif a:filetype ==? "smil"
+ call s:MapDelimiters('<!','>')
+ elseif a:filetype ==? "smith"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "sml"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype ==? "snnsnet"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "snnspat"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "snnsres"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "snobol4"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype ==? "spec"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "specman"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "spectre"
+ call s:MapDelimitersWithAlternative('//', '', '*', '')
+ elseif a:filetype ==? "spice"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype ==? "sql"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "sqlforms"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "sqlj"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "sqr"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype ==? "squid"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "st"
+ call s:MapDelimiters('"','')
+ elseif a:filetype ==? "stp"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "systemverilog"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "tads"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "tags"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "tak"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype ==? "tasm"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "tcl"
+ call s:MapDelimiters('#','')
+ elseif a:filetype ==? "texinfo"
+ call s:MapDelimiters("@c ", "")
+ elseif a:filetype ==? "texmf"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "tf"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "tidy"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "tli"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "trasys"
+ call s:MapDelimiters("$", "")
+ elseif a:filetype ==? "tsalt"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "tsscl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "tssgm"
+ call s:MapDelimiters("comment = '","'")
+ elseif a:filetype ==? "txt2tags"
+ call s:MapDelimiters('%','')
+ elseif a:filetype ==? "uc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "uil"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype ==? "vb"
+ call s:MapDelimiters("'","")
+ elseif a:filetype ==? "velocity"
+ call s:MapDelimitersWithAlternative("##","", '#*', '*#')
+ elseif a:filetype ==? "vera"
+ call s:MapDelimitersWithAlternative('/*','*/','//','')
+ elseif a:filetype ==? "verilog"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "verilog_systemverilog"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype ==? "vgrindefs"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "vhdl"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype ==? "vimperator"
+ call s:MapDelimiters('"','')
+ elseif a:filetype ==? "virata"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype ==? "vrml"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "vsejcl"
+ call s:MapDelimiters('/*', '')
+ elseif a:filetype ==? "webmacro"
+ call s:MapDelimiters('##', '')
+ elseif a:filetype ==? "wget"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "Wikipedia"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype ==? "winbatch"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "wml"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "wvdial"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype ==? "xdefaults"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype ==? "xkb"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype ==? "xmath"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "xpm2"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype ==? "xquery"
+ call s:MapDelimiters('(:',':)')
+ elseif a:filetype ==? "z8a"
+ call s:MapDelimiters(';', '')
+
+ else
+
+ "extract the delims from &commentstring
+ let left= substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', '')
+ let right= substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g')
+ call s:MapDelimiters(left,right)
+
+ endif
+endfunction
+
+" Function: s:MapDelimiters(left, right) function {{{2
+" This function is a wrapper for s:MapDelimiters(left, right, leftAlt, rightAlt, useAlt) and is called when there
+" is no alternative comment delimiters for the current filetype
+"
+" Args:
+" -left: the left comment delimiter
+" -right: the right comment delimiter
+function s:MapDelimiters(left, right)
+ call s:MapDelimitersWithAlternative(a:left, a:right, "", "")
+endfunction
+
+" Function: s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt) function {{{2
+" this function sets up the comment delimiter buffer variables
+"
+" Args:
+" -left: the string defining the comment start delimiter
+" -right: the string defining the comment end delimiter
+" -leftAlt: the string for the alternative comment style defining the comment start delimiter
+" -rightAlt: the string for the alternative comment style defining the comment end delimiter
+function s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt)
+ if !exists('g:NERD_' . &filetype . '_alt_style')
+ let b:NERDLeft = a:left
+ let b:NERDRight = a:right
+ let b:NERDLeftAlt = a:leftAlt
+ let b:NERDRightAlt = a:rightAlt
+ else
+ let b:NERDLeft = a:leftAlt
+ let b:NERDRight = a:rightAlt
+ let b:NERDLeftAlt = a:left
+ let b:NERDRightAlt = a:right
+ endif
+endfunction
+
+" Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2
+" This function is used to swap the delimiters that are being used to the
+" alternative delimiters for that filetype. For example, if a c++ file is
+" being edited and // comments are being used, after this function is called
+" /**/ comments will be used.
+"
+" Args:
+" -printMsgs: if this is 1 then a message is echoed to the user telling them
+" if this function changed the delimiters or not
+function s:SwitchToAlternativeDelimiters(printMsgs)
+ "if both of the alternative delimiters are empty then there is no
+ "alternative comment style so bail out
+ if b:NERDLeftAlt == "" && b:NERDRightAlt == ""
+ if a:printMsgs
+ call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
+ endif
+ return 0
+ endif
+
+ "save the current delimiters
+ let tempLeft = b:NERDLeft
+ let tempRight = b:NERDRight
+
+ "swap current delimiters for alternative
+ let b:NERDLeft = b:NERDLeftAlt
+ let b:NERDRight = b:NERDRightAlt
+
+ "set the previously current delimiters to be the new alternative ones
+ let b:NERDLeftAlt = tempLeft
+ let b:NERDRightAlt = tempRight
+
+ "tell the user what comment delimiters they are now using
+ if a:printMsgs
+ let leftNoEsc = b:NERDLeft
+ let rightNoEsc = b:NERDRight
+ call s:NerdEcho("Now using " . leftNoEsc . " " . rightNoEsc . " to delimit comments", 1)
+ endif
+
+ return 1
+endfunction
+
+" Section: Comment delimiter add/removal functions {{{1
+" ============================================================================
+" Function: s:AppendCommentToLine(){{{2
+" This function appends comment delimiters at the EOL and places the cursor in
+" position to start typing the comment
+function s:AppendCommentToLine()
+ let left = s:GetLeft(0,1,0)
+ let right = s:GetRight(0,1,0)
+
+ " get the len of the right delim
+ let lenRight = strlen(right)
+
+ let isLineEmpty = strlen(getline(".")) == 0
+ let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
+
+ "stick the delimiters down at the end of the line. We have to format the
+ "comment with spaces as appropriate
+ execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " "
+
+ " if there is a right delimiter then we gotta move the cursor left
+ " by the len of the right delimiter so we insert between the delimiters
+ if lenRight > 0
+ let leftMoveAmount = lenRight
+ execute ":normal! " . leftMoveAmount . "h"
+ endif
+ startinsert
+endfunction
+
+" Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2
+" This function is used to comment out a region of code. This region is
+" specified as a bounding box by arguments to the function.
+"
+" Args:
+" -top: the line number for the top line of code in the region
+" -bottom: the line number for the bottom line of code in the region
+" -lSide: the column number for the left most column in the region
+" -rSide: the column number for the right most column in the region
+" -forceNested: a flag indicating whether comments should be nested
+function s:CommentBlock(top, bottom, lSide, rSide, forceNested )
+ " we need to create local copies of these arguments so we can modify them
+ let top = a:top
+ let bottom = a:bottom
+ let lSide = a:lSide
+ let rSide = a:rSide
+
+ "if the top or bottom line starts with tabs we have to adjust the left and
+ "right boundaries so that they are set as though the tabs were spaces
+ let topline = getline(top)
+ let bottomline = getline(bottom)
+ if s:HasLeadingTabs(topline, bottomline)
+
+ "find out how many tabs are in the top line and adjust the left
+ "boundary accordingly
+ let numTabs = s:NumberOfLeadingTabs(topline)
+ if lSide < numTabs
+ let lSide = &ts * lSide
+ else
+ let lSide = (lSide - numTabs) + (&ts * numTabs)
+ endif
+
+ "find out how many tabs are in the bottom line and adjust the right
+ "boundary accordingly
+ let numTabs = s:NumberOfLeadingTabs(bottomline)
+ let rSide = (rSide - numTabs) + (&ts * numTabs)
+ endif
+
+ "we must check that bottom IS actually below top, if it is not then we
+ "swap top and bottom. Similarly for left and right.
+ if bottom < top
+ let temp = top
+ let top = bottom
+ let bottom = top
+ endif
+ if rSide < lSide
+ let temp = lSide
+ let lSide = rSide
+ let rSide = temp
+ endif
+
+ "if the current delimiters arent multipart then we will switch to the
+ "alternative delims (if THEY are) as the comment will be better and more
+ "accurate with multipart delims
+ let switchedDelims = 0
+ if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
+ let switchedDelims = 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+ "start the commenting from the top and keep commenting till we reach the
+ "bottom
+ let currentLine=top
+ while currentLine <= bottom
+
+ "check if we are allowed to comment this line
+ if s:CanCommentLine(a:forceNested, currentLine)
+
+ "convert the leading tabs into spaces
+ let theLine = getline(currentLine)
+ let lineHasLeadTabs = s:HasLeadingTabs(theLine)
+ if lineHasLeadTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+
+ "dont comment lines that begin after the right boundary of the
+ "block unless the user has specified to do so
+ if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
+
+ "attempt to place the cursor in on the left of the boundary box,
+ "then check if we were successful, if not then we cant comment this
+ "line
+ call setline(currentLine, theLine)
+ if s:CanPlaceCursor(currentLine, lSide)
+
+ let leftSpaced = s:GetLeft(0,1,0)
+ let rightSpaced = s:GetRight(0,1,0)
+
+ "stick the left delimiter down
+ let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
+
+ if s:Multipart()
+ "stick the right delimiter down
+ let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
+
+ let firstLeftDelim = s:FindDelimiterIndex(b:NERDLeft, theLine)
+ let lastRightDelim = s:LastIndexOfDelim(b:NERDRight, theLine)
+
+ if firstLeftDelim != -1 && lastRightDelim != -1
+ let searchStr = strpart(theLine, 0, lastRightDelim)
+ let searchStr = strpart(searchStr, firstLeftDelim+strlen(b:NERDLeft))
+
+ "replace the outter most delims in searchStr with
+ "place-holders
+ let theLineWithPlaceHolders = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, searchStr)
+
+ "add the right delimiter onto the line
+ let theLine = strpart(theLine, 0, firstLeftDelim+strlen(b:NERDLeft)) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
+ endif
+ endif
+ endif
+ endif
+
+ "restore tabs if needed
+ if lineHasLeadTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ call setline(currentLine, theLine)
+ endif
+
+ let currentLine = currentLine + 1
+ endwhile
+
+ "if we switched delims then we gotta go back to what they were before
+ if switchedDelims == 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+endfunction
+
+" Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
+" This function comments a range of lines.
+"
+" Args:
+" -forceNested: a flag indicating whether the called is requesting the comment
+" to be nested if need be
+" -align: should be "left" or "both" or "none"
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLines(forceNested, align, firstLine, lastLine)
+ " we need to get the left and right indexes of the leftmost char in the
+ " block of of lines and the right most char so that we can do alignment of
+ " the delimiters if the user has specified
+ let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
+ let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
+
+ " gotta add the length of the left delimiter onto the rightAlignIndx cos
+ " we'll be adding a left delim to the line
+ let rightAlignIndx = rightAlignIndx + strlen(s:GetLeft(0,1,0))
+
+ " now we actually comment the lines. Do it line by line
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+
+ " get the next line, check commentability and convert spaces to tabs
+ let theLine = getline(currentLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ if s:CanCommentLine(a:forceNested, currentLine)
+ "if the user has specified forceNesting then we check to see if we
+ "need to switch delimiters for place-holders
+ if a:forceNested && g:NERDUsePlaceHolders
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+
+ " find out if the line is commented using normal delims and/or
+ " alternate ones
+ let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)
+
+ " check if we can comment this line
+ if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
+ if a:align == "left" || a:align == "both"
+ let theLine = s:AddLeftDelimAligned(s:GetLeft(0,1,0), theLine, leftAlignIndx)
+ else
+ let theLine = s:AddLeftDelim(s:GetLeft(0,1,0), theLine)
+ endif
+ if a:align == "both"
+ let theLine = s:AddRightDelimAligned(s:GetRight(0,1,0), theLine, rightAlignIndx)
+ else
+ let theLine = s:AddRightDelim(s:GetRight(0,1,0), theLine)
+ endif
+ endif
+ endif
+
+ " restore leading tabs if appropriate
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ " we are done with this line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
+" This function comments a range of lines in a minimal style. I
+"
+" Args:
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLinesMinimal(firstLine, lastLine)
+ "check that minimal comments can be done on this filetype
+ if !s:HasMultipartDelims()
+ throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
+ endif
+
+ "if we need to use place holders for the comment, make sure they are
+ "enabled for this filetype
+ if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
+ throw 'NERDCommenter.Settings exception: Placeoholders are required but disabled.'
+ endif
+
+ "get the left and right delims to smack on
+ let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
+ let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
+
+ "make sure all multipart delims on the lines are replaced with
+ "placeholders to prevent illegal syntax
+ let currentLine = a:firstLine
+ while(currentLine <= a:lastLine)
+ let theLine = getline(currentLine)
+ let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+ "add the delim to the top line
+ let theLine = getline(a:firstLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let theLine = s:AddLeftDelim(left, theLine)
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:firstLine, theLine)
+
+ "add the delim to the bottom line
+ let theLine = getline(a:lastLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let theLine = s:AddRightDelim(right, theLine)
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:lastLine, theLine)
+endfunction
+
+" Function: s:CommentLinesSexy(topline, bottomline) function {{{2
+" This function is used to comment lines in the 'Sexy' style. eg in c:
+" /*
+" * This is a sexy comment
+" */
+" Args:
+" -topline: the line num of the top line in the sexy comment
+" -bottomline: the line num of the bottom line in the sexy comment
+function s:CommentLinesSexy(topline, bottomline)
+ let left = s:GetSexyComLeft(0, 0)
+ let right = s:GetSexyComRight(0, 0)
+
+ "check if we can do a sexy comment with the available delimiters
+ if left == -1 || right == -1
+ throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
+ endif
+
+ "make sure the lines arent already commented sexually
+ if !s:CanSexyCommentLines(a:topline, a:bottomline)
+ throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
+ endif
+
+
+ let sexyComMarker = s:GetSexyComMarker(0,0)
+ let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
+
+
+ " we jam the comment as far to the right as possible
+ let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
+
+ "check if we should use the compact style i.e that the left/right
+ "delimiters should appear on the first and last lines of the code and not
+ "on separate lines above/below the first/last lines of code
+ if g:NERDCompactSexyComs
+ let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
+
+ "comment the top line
+ let theLine = getline(a:topline)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:topline, theLine)
+
+ "comment the bottom line
+ if a:bottomline != a:topline
+ let theLine = getline(a:bottomline)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+ let theLine = s:AddRightDelim(spaceString . right, theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:bottomline, theLine)
+ else
+
+ " add the left delimiter one line above the lines that are to be commented
+ call cursor(a:topline, 1)
+ execute 'normal! O'
+ let theLine = repeat(' ', leftAlignIndx) . left
+
+ " Make sure tabs are respected
+ if !&expandtab
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:topline, theLine)
+
+ " add the right delimiter after bottom line (we have to add 1 cos we moved
+ " the lines down when we added the left delim
+ call cursor(a:bottomline+1, 1)
+ execute 'normal! o'
+ let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right
+
+ " Make sure tabs are respected
+ if !&expandtab
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:bottomline+2, theLine)
+
+ endif
+
+ " go thru each line adding the sexyComMarker marker to the start of each
+ " line in the appropriate place to align them with the comment delims
+ let currentLine = a:topline+1
+ while currentLine <= a:bottomline + !g:NERDCompactSexyComs
+ " get the line and convert the tabs to spaces
+ let theLine = getline(currentLine)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+
+ " add the sexyComMarker
+ let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
+
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+
+ " set the line and move onto the next one
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
+" Applies "toggle" commenting to the given range of lines
+"
+" Args:
+" -forceNested: a flag indicating whether the called is requesting the comment
+" to be nested if need be
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLinesToggle(forceNested, firstLine, lastLine)
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+
+ " get the next line, check commentability and convert spaces to tabs
+ let theLine = getline(currentLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ if s:CanToggleCommentLine(a:forceNested, currentLine)
+
+ "if the user has specified forceNesting then we check to see if we
+ "need to switch delimiters for place-holders
+ if g:NERDUsePlaceHolders
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+
+ let theLine = s:AddLeftDelim(s:GetLeft(0, 1, 0), theLine)
+ let theLine = s:AddRightDelim(s:GetRight(0, 1, 0), theLine)
+ endif
+
+ " restore leading tabs if appropriate
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ " we are done with this line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2
+" This function comments chunks of text selected in visual mode.
+" It will comment exactly the text that they have selected.
+" Args:
+" -topLine: the line num of the top line in the sexy comment
+" -topCol: top left col for this comment
+" -bottomline: the line num of the bottom line in the sexy comment
+" -bottomCol: the bottom right col for this comment
+" -forceNested: whether the caller wants comments to be nested if the
+" line(s) are already commented
+function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested)
+
+ "switch delims (if we can) if the current set isnt multipart
+ let switchedDelims = 0
+ if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims
+ let switchedDelims = 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+ "if there is only one line in the comment then just do it
+ if a:topLine == a:bottomLine
+ call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
+
+ "there are multiple lines in the comment
+ else
+ "comment the top line
+ call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
+
+ "comment out all the lines in the middle of the comment
+ let topOfRange = a:topLine+1
+ let bottomOfRange = a:bottomLine-1
+ if topOfRange <= bottomOfRange
+ call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange)
+ endif
+
+ "comment the bottom line
+ let bottom = getline(a:bottomLine)
+ let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', ''))
+ call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
+
+ endif
+
+ "stick the cursor back on the char it was on before the comment
+ call cursor(a:topLine, a:topCol + strlen(b:NERDLeft) + g:NERDSpaceDelims)
+
+ "if we switched delims then we gotta go back to what they were before
+ if switchedDelims == 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+endfunction
+
+" Function: s:InvertComment(firstLine, lastLine) function {{{2
+" Inverts the comments on the lines between and including the given line
+" numbers i.e all commented lines are uncommented and vice versa
+" Args:
+" -firstLine: the top of the range of lines to be inverted
+" -lastLine: the bottom of the range of lines to be inverted
+function s:InvertComment(firstLine, lastLine)
+
+ " go thru all lines in the given range
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+ let theLine = getline(currentLine)
+
+ let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
+
+ " if the line is commented normally, uncomment it
+ if s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)
+ call s:UncommentLines(currentLine, currentLine)
+ let currentLine = currentLine + 1
+
+ " check if the line is commented sexually
+ elseif !empty(sexyComBounds)
+ let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
+ call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
+
+ "move to the line after last line of the sexy comment
+ let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
+ let currentLine = bottomBound - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
+
+ " the line isnt commented
+ else
+ call s:CommentLinesToggle(1, currentLine, currentLine)
+ let currentLine = currentLine + 1
+ endif
+
+ endwhile
+endfunction
+
+" Function: NERDComment(isVisual, type) function {{{2
+" This function is a Wrapper for the main commenting functions
+"
+" Args:
+" -isVisual: a flag indicating whether the comment is requested in visual
+" mode or not
+" -type: the type of commenting requested. Can be 'sexy', 'invert',
+" 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm',
+" 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank'
+function! NERDComment(isVisual, type) range
+ " we want case sensitivity when commenting
+ let oldIgnoreCase = &ignorecase
+ set noignorecase
+
+ if a:isVisual
+ let firstLine = line("'<")
+ let lastLine = line("'>")
+ let firstCol = col("'<")
+ let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
+ else
+ let firstLine = a:firstline
+ let lastLine = a:lastline
+ endif
+
+ let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
+
+ let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
+
+ if a:type == 'norm' || a:type == 'nested'
+ if a:isVisual && visualmode() == ""
+ call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
+ elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims()))
+ call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
+ else
+ call s:CommentLines(forceNested, "none", firstLine, lastLine)
+ endif
+
+ elseif a:type == 'alignLeft' || a:type == 'alignBoth'
+ let align = "none"
+ if a:type == "alignLeft"
+ let align = "left"
+ elseif a:type == "alignBoth"
+ let align = "both"
+ endif
+ call s:CommentLines(forceNested, align, firstLine, lastLine)
+
+ elseif a:type == 'invert'
+ call s:InvertComment(firstLine, lastLine)
+
+ elseif a:type == 'sexy'
+ try
+ call s:CommentLinesSexy(firstLine, lastLine)
+ catch /NERDCommenter.Delimiters/
+ call s:CommentLines(forceNested, "none", firstLine, lastLine)
+ catch /NERDCommenter.Nesting/
+ call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0)
+ endtry
+
+ elseif a:type == 'toggle'
+ let theLine = getline(firstLine)
+
+ if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)
+ call s:UncommentLines(firstLine, lastLine)
+ else
+ call s:CommentLinesToggle(forceNested, firstLine, lastLine)
+ endif
+
+ elseif a:type == 'minimal'
+ try
+ call s:CommentLinesMinimal(firstLine, lastLine)
+ catch /NERDCommenter.Delimiters/
+ call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0)
+ catch /NERDCommenter.Settings/
+ call s:NerdEcho("Place holders are required but disabled.", 0)
+ endtry
+
+ elseif a:type == 'toEOL'
+ call s:SaveScreenState()
+ call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
+ call s:RestoreScreenState()
+
+ elseif a:type == 'append'
+ call s:AppendCommentToLine()
+
+ elseif a:type == 'insert'
+ call s:PlaceDelimitersAndInsBetween()
+
+ elseif a:type == 'uncomment'
+ call s:UncommentLines(firstLine, lastLine)
+
+ elseif a:type == 'yank'
+ if a:isVisual
+ normal! gvy
+ elseif countWasGiven
+ execute firstLine .','. lastLine .'yank'
+ else
+ normal! yy
+ endif
+ execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
+ endif
+
+ let &ignorecase = oldIgnoreCase
+endfunction
+
+" Function: s:PlaceDelimitersAndInsBetween() function {{{2
+" This is function is called to place comment delimiters down and place the
+" cursor between them
+function s:PlaceDelimitersAndInsBetween()
+ " get the left and right delimiters without any escape chars in them
+ let left = s:GetLeft(0, 1, 0)
+ let right = s:GetRight(0, 1, 0)
+
+ let theLine = getline(".")
+ let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
+
+ "convert tabs to spaces and adjust the cursors column to take this into
+ "account
+ let untabbedCol = s:UntabbedCol(theLine, col("."))
+ call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
+ call cursor(line("."), untabbedCol)
+
+ " get the len of the right delim
+ let lenRight = strlen(right)
+
+ let isDelimOnEOL = col(".") >= strlen(getline("."))
+
+ " if the cursor is in the first col then we gotta insert rather than
+ " append the comment delimiters here
+ let insOrApp = (col(".")==1 ? 'i' : 'a')
+
+ " place the delimiters down. We do it differently depending on whether
+ " there is a left AND right delimiter
+ if lenRight > 0
+ execute ":normal! " . insOrApp . left . right
+ execute ":normal! " . lenRight . "h"
+ else
+ execute ":normal! " . insOrApp . left
+
+ " if we are tacking the delim on the EOL then we gotta add a space
+ " after it cos when we go out of insert mode the cursor will move back
+ " one and the user wont be in position to type the comment.
+ if isDelimOnEOL
+ execute 'normal! a '
+ endif
+ endif
+ normal! l
+
+ "if needed convert spaces back to tabs and adjust the cursors col
+ "accordingly
+ if lineHasLeadTabs
+ let tabbedCol = s:TabbedCol(getline("."), col("."))
+ call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
+ call cursor(line("."), tabbedCol)
+ endif
+
+ startinsert
+endfunction
+
+" Function: s:RemoveDelimiters(left, right, line) {{{2
+" this function is called to remove the first left comment delimiter and the
+" last right delimiter of the given line.
+"
+" The args left and right must be strings. If there is no right delimiter (as
+" is the case for e.g vim file comments) them the arg right should be ""
+"
+" Args:
+" -left: the left comment delimiter
+" -right: the right comment delimiter
+" -line: the line to remove the delimiters from
+function s:RemoveDelimiters(left, right, line)
+
+ let l:left = a:left
+ let l:right = a:right
+ let lenLeft = strlen(left)
+ let lenRight = strlen(right)
+
+ let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
+
+ let line = a:line
+
+ "look for the left delimiter, if we find it, remove it.
+ let leftIndx = s:FindDelimiterIndex(a:left, line)
+ if leftIndx != -1
+ let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
+
+ "if the user has specified that there is a space after the left delim
+ "then check for the space and remove it if it is there
+ if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr
+ let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
+ endif
+ endif
+
+ "look for the right delimiter, if we find it, remove it
+ let rightIndx = s:FindDelimiterIndex(a:right, line)
+ if rightIndx != -1
+ let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
+
+ "if the user has specified that there is a space before the right delim
+ "then check for the space and remove it if it is there
+ if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart()
+ let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
+ endif
+ endif
+
+ return line
+endfunction
+
+" Function: s:UncommentLines(topLine, bottomLine) {{{2
+" This function uncomments the given lines
+"
+" Args:
+" topLine: the top line of the visual selection to uncomment
+" bottomLine: the bottom line of the visual selection to uncomment
+function s:UncommentLines(topLine, bottomLine)
+ "make local copies of a:firstline and a:lastline and, if need be, swap
+ "them around if the top line is below the bottom
+ let l:firstline = a:topLine
+ let l:lastline = a:bottomLine
+ if firstline > lastline
+ let firstline = lastline
+ let lastline = a:topLine
+ endif
+
+ "go thru each line uncommenting each line removing sexy comments
+ let currentLine = firstline
+ while currentLine <= lastline
+
+ "check the current line to see if it is part of a sexy comment
+ let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
+ if !empty(sexyComBounds)
+
+ "we need to store the num lines in the buf before the comment is
+ "removed so we know how many lines were removed when the sexy com
+ "was removed
+ let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
+
+ call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
+
+ "move to the line after last line of the sexy comment
+ let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
+ let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
+ let currentLine = sexyComBounds[1] - numLinesRemoved + 1
+ let lastline = lastline - numLinesRemoved
+
+ "no sexy com was detected so uncomment the line as normal
+ else
+ call s:UncommentLinesNormal(currentLine, currentLine)
+ let currentLine = currentLine + 1
+ endif
+ endwhile
+
+endfunction
+
+" Function: s:UncommentLinesSexy(topline, bottomline) {{{2
+" This function removes all the comment characters associated with the sexy
+" comment spanning the given lines
+" Args:
+" -topline/bottomline: the top/bottom lines of the sexy comment
+function s:UncommentLinesSexy(topline, bottomline)
+ let left = s:GetSexyComLeft(0,1)
+ let right = s:GetSexyComRight(0,1)
+
+
+ "check if it is even possible for sexy comments to exist with the
+ "available delimiters
+ if left == -1 || right == -1
+ throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
+ endif
+
+ let leftUnEsc = s:GetSexyComLeft(0,0)
+ let rightUnEsc = s:GetSexyComRight(0,0)
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+ let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
+
+ "the markerOffset is how far right we need to move the sexyComMarker to
+ "line it up with the end of the left delim
+ let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
+
+ " go thru the intermediate lines of the sexy comment and remove the
+ " sexy comment markers (eg the '*'s on the start of line in a c sexy
+ " comment)
+ let currentLine = a:topline+1
+ while currentLine < a:bottomline
+ let theLine = getline(currentLine)
+
+ " remove the sexy comment marker from the line. We also remove the
+ " space after it if there is one and if appropriate options are set
+ let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
+ if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
+ endif
+
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+
+ let theLine = s:ConvertLeadingWhiteSpace(theLine)
+
+ " move onto the next line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+ " gotta make a copy of a:bottomline cos we modify the position of the
+ " last line it if we remove the topline
+ let bottomline = a:bottomline
+
+ " get the first line so we can remove the left delim from it
+ let theLine = getline(a:topline)
+
+ " if the first line contains only the left delim then just delete it
+ if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs
+ call cursor(a:topline, 1)
+ normal! dd
+ let bottomline = bottomline - 1
+
+ " topline contains more than just the left delim
+ else
+
+ " remove the delim. If there is a space after it
+ " then remove this too if appropriate
+ let delimIndx = stridx(theLine, leftUnEsc)
+ if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
+ endif
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+ call setline(a:topline, theLine)
+ endif
+
+ " get the last line so we can remove the right delim
+ let theLine = getline(bottomline)
+
+ " if the bottomline contains only the right delim then just delete it
+ if theLine =~ '^[ \t]*' . right . '[ \t]*$'
+ call cursor(bottomline, 1)
+ normal! dd
+
+ " the last line contains more than the right delim
+ else
+ " remove the right delim. If there is a space after it and
+ " if the appropriate options are set then remove this too.
+ let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
+ if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
+ endif
+
+ " if the last line also starts with a sexy comment marker then we
+ " remove this as well
+ if theLine =~ '^[ \t]*' . sexyComMarker
+
+ " remove the sexyComMarker. If there is a space after it then
+ " remove that too
+ let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
+ if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
+ endif
+ endif
+
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+ call setline(bottomline, theLine)
+ endif
+endfunction
+
+" Function: s:UncommentLineNormal(line) {{{2
+" uncomments the given line and returns the result
+" Args:
+" -line: the line to uncomment
+function s:UncommentLineNormal(line)
+ let line = a:line
+
+ "get the comment status on the line so we know how it is commented
+ let lineCommentStatus = s:IsCommentedOuttermost(b:NERDLeft, b:NERDRight, b:NERDLeftAlt, b:NERDRightAlt, line)
+
+ "it is commented with b:NERDLeft and b:NERDRight so remove these delims
+ if lineCommentStatus == 1
+ let line = s:RemoveDelimiters(b:NERDLeft, b:NERDRight, line)
+
+ "it is commented with b:NERDLeftAlt and b:NERDRightAlt so remove these delims
+ elseif lineCommentStatus == 2 && g:NERDRemoveAltComs
+ let line = s:RemoveDelimiters(b:NERDLeftAlt, b:NERDRightAlt, line)
+
+ "it is not properly commented with any delims so we check if it has
+ "any random left or right delims on it and remove the outtermost ones
+ else
+ "get the positions of all delim types on the line
+ let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line)
+ let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line)
+ let indxRight = s:FindDelimiterIndex(b:NERDRight, line)
+ let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line)
+
+ "remove the outter most left comment delim
+ if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1)
+ let line = s:RemoveDelimiters(b:NERDLeft, '', line)
+ elseif indxLeftAlt != -1
+ let line = s:RemoveDelimiters(b:NERDLeftAlt, '', line)
+ endif
+
+ "remove the outter most right comment delim
+ if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1)
+ let line = s:RemoveDelimiters('', b:NERDRight, line)
+ elseif indxRightAlt != -1
+ let line = s:RemoveDelimiters('', b:NERDRightAlt, line)
+ endif
+ endif
+
+
+ let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line)
+ let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line)
+ let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
+
+ let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
+ let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line)
+ let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
+
+ let right = b:NERDRight
+ let left = b:NERDLeft
+ if !s:Multipart()
+ let right = b:NERDRightAlt
+ let left = b:NERDLeftAlt
+ endif
+
+
+ "if there are place-holders on the line then we check to see if they are
+ "the outtermost delimiters on the line. If so then we replace them with
+ "real delimiters
+ if indxLeftPlace != -1
+ if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
+ endif
+ elseif indxRightPlace != -1
+ if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
+ endif
+
+ endif
+
+ let line = s:ConvertLeadingWhiteSpace(line)
+
+ return line
+endfunction
+
+" Function: s:UncommentLinesNormal(topline, bottomline) {{{2
+" This function is called to uncomment lines that arent a sexy comment
+" Args:
+" -topline/bottomline: the top/bottom line numbers of the comment
+function s:UncommentLinesNormal(topline, bottomline)
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+ let line = getline(currentLine)
+ call setline(currentLine, s:UncommentLineNormal(line))
+ let currentLine = currentLine + 1
+ endwhile
+endfunction
+
+
+" Section: Other helper functions {{{1
+" ============================================================================
+
+" Function: s:AddLeftDelim(delim, theLine) {{{2
+" Args:
+function s:AddLeftDelim(delim, theLine)
+ return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
+endfunction
+
+" Function: s:AddLeftDelimAligned(delim, theLine) {{{2
+" Args:
+function s:AddLeftDelimAligned(delim, theLine, alignIndx)
+
+ "if the line is not long enough then bung some extra spaces on the front
+ "so we can align the delim properly
+ let theLine = a:theLine
+ if strlen(theLine) < a:alignIndx
+ let theLine = repeat(' ', a:alignIndx - strlen(theLine))
+ endif
+
+ return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
+endfunction
+
+" Function: s:AddRightDelim(delim, theLine) {{{2
+" Args:
+function s:AddRightDelim(delim, theLine)
+ if a:delim == ''
+ return a:theLine
+ else
+ return substitute(a:theLine, '$', a:delim, '')
+ endif
+endfunction
+
+" Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
+" Args:
+function s:AddRightDelimAligned(delim, theLine, alignIndx)
+ if a:delim == ""
+ return a:theLine
+ else
+
+ " when we align the right delim we are just adding spaces
+ " so we get a string containing the needed spaces (it
+ " could be empty)
+ let extraSpaces = ''
+ let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
+
+ " add the right delim
+ return substitute(a:theLine, '$', extraSpaces . a:delim, '')
+ endif
+endfunction
+
+" Function: s:AltMultipart() {{{2
+" returns 1 if the alternative delims are multipart
+function s:AltMultipart()
+ return b:NERDRightAlt != ''
+endfunction
+
+" Function: s:CanCommentLine(forceNested, line) {{{2
+"This function is used to determine whether the given line can be commented.
+"It returns 1 if it can be and 0 otherwise
+"
+" Args:
+" -forceNested: a flag indicating whether the caller wants comments to be nested
+" if the current line is already commented
+" -lineNum: the line num of the line to check for commentability
+function s:CanCommentLine(forceNested, lineNum)
+ let theLine = getline(a:lineNum)
+
+ " make sure we don't comment lines that are just spaces or tabs or empty.
+ if theLine =~ "^[ \t]*$"
+ return 0
+ endif
+
+ "if the line is part of a sexy comment then just flag it...
+ if s:IsInSexyComment(a:lineNum)
+ return 0
+ endif
+
+ let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
+
+ "if the line isnt commented return true
+ if !isCommented
+ return 1
+ endif
+
+ "if the line is commented but nesting is allowed then return true
+ if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
+ return 1
+ endif
+
+ return 0
+endfunction
+
+" Function: s:CanPlaceCursor(line, col) {{{2
+" returns 1 if the cursor can be placed exactly in the given position
+function s:CanPlaceCursor(line, col)
+ let c = col(".")
+ let l = line(".")
+ call cursor(a:line, a:col)
+ let success = (line(".") == a:line && col(".") == a:col)
+ call cursor(l,c)
+ return success
+endfunction
+
+" Function: s:CanSexyCommentLines(topline, bottomline) {{{2
+" Return: 1 if the given lines can be commented sexually, 0 otherwise
+function s:CanSexyCommentLines(topline, bottomline)
+ " see if the selected regions have any sexy comments
+ let currentLine = a:topline
+ while(currentLine <= a:bottomline)
+ if s:IsInSexyComment(currentLine)
+ return 0
+ endif
+ let currentLine = currentLine + 1
+ endwhile
+ return 1
+endfunction
+" Function: s:CanToggleCommentLine(forceNested, line) {{{2
+"This function is used to determine whether the given line can be toggle commented.
+"It returns 1 if it can be and 0 otherwise
+"
+" Args:
+" -lineNum: the line num of the line to check for commentability
+function s:CanToggleCommentLine(forceNested, lineNum)
+ let theLine = getline(a:lineNum)
+ if (s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)) && !a:forceNested
+ return 0
+ endif
+
+ " make sure we don't comment lines that are just spaces or tabs or empty.
+ if theLine =~ "^[ \t]*$"
+ return 0
+ endif
+
+ "if the line is part of a sexy comment then just flag it...
+ if s:IsInSexyComment(a:lineNum)
+ return 0
+ endif
+
+ return 1
+endfunction
+
+" Function: s:ConvertLeadingSpacesToTabs(line) {{{2
+" This function takes a line and converts all leading tabs on that line into
+" spaces
+"
+" Args:
+" -line: the line whose leading tabs will be converted
+function s:ConvertLeadingSpacesToTabs(line)
+ let toReturn = a:line
+ while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$'
+ let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "")
+ endwhile
+
+ return toReturn
+endfunction
+
+
+" Function: s:ConvertLeadingTabsToSpaces(line) {{{2
+" This function takes a line and converts all leading spaces on that line into
+" tabs
+"
+" Args:
+" -line: the line whose leading spaces will be converted
+function s:ConvertLeadingTabsToSpaces(line)
+ let toReturn = a:line
+ while toReturn =~ '^\( *\)\t'
+ let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "")
+ endwhile
+
+ return toReturn
+endfunction
+
+" Function: s:ConvertLeadingWhiteSpace(line) {{{2
+" Converts the leading white space to tabs/spaces depending on &ts
+"
+" Args:
+" -line: the line to convert
+function s:ConvertLeadingWhiteSpace(line)
+ let toReturn = a:line
+ while toReturn =~ '^ *\t'
+ let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g")
+ endwhile
+
+ if !&expandtab
+ let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
+ endif
+
+ return toReturn
+endfunction
+
+
+" Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2
+" This function counts the number of substrings contained in another string.
+" These substrings are only counted if they are not escaped with escChar
+" Args:
+" -str: the string to look for searchstr in
+" -searchstr: the substring to search for in str
+" -escChar: the escape character which, when preceding an instance of
+" searchstr, will cause it not to be counted
+function s:CountNonESCedOccurances(str, searchstr, escChar)
+ "get the index of the first occurrence of searchstr
+ let indx = stridx(a:str, a:searchstr)
+
+ "if there is an instance of searchstr in str process it
+ if indx != -1
+ "get the remainder of str after this instance of searchstr is removed
+ let lensearchstr = strlen(a:searchstr)
+ let strLeft = strpart(a:str, indx+lensearchstr)
+
+ "if this instance of searchstr is not escaped, add one to the count
+ "and recurse. If it is escaped, just recurse
+ if !s:IsEscaped(a:str, indx, a:escChar)
+ return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
+ else
+ return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
+ endif
+ endif
+endfunction
+" Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
+" Returns 1 if the given block of lines has a delimiter (a:delim) in it
+" Args:
+" -delim: the comment delimiter to check the block for
+" -top: the top line number of the block
+" -bottom: the bottom line number of the block
+function s:DoesBlockHaveDelim(delim, top, bottom)
+ let currentLine = a:top
+ while currentLine < a:bottom
+ let theline = getline(currentLine)
+ if s:FindDelimiterIndex(a:delim, theline) != -1
+ return 1
+ endif
+ let currentLine = currentLine + 1
+ endwhile
+ return 0
+endfunction
+
+" Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
+" Returns 1 if the given block has a >= 1 multipart delimiter in it
+" Args:
+" -top: the top line number of the block
+" -bottom: the bottom line number of the block
+function s:DoesBlockHaveMultipartDelim(top, bottom)
+ if s:HasMultipartDelims()
+ if s:Multipart()
+ return s:DoesBlockHaveDelim(b:NERDLeft, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRight, a:top, a:bottom)
+ else
+ return s:DoesBlockHaveDelim(b:NERDLeftAlt, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRightAlt, a:top, a:bottom)
+ endif
+ endif
+ return 0
+endfunction
+
+
+" Function: s:Esc(str) {{{2
+" Escapes all the tricky chars in the given string
+function s:Esc(str)
+ let charsToEsc = '*/\."&$+'
+ return escape(a:str, charsToEsc)
+endfunction
+
+" Function: s:FindDelimiterIndex(delimiter, line) {{{2
+" This function is used to get the string index of the input comment delimiter
+" on the input line. If no valid comment delimiter is found in the line then
+" -1 is returned
+" Args:
+" -delimiter: the delimiter we are looking to find the index of
+" -line: the line we are looking for delimiter on
+function s:FindDelimiterIndex(delimiter, line)
+
+ "make sure the delimiter isnt empty otherwise we go into an infinite loop.
+ if a:delimiter == ""
+ return -1
+ endif
+
+
+ let l:delimiter = a:delimiter
+ let lenDel = strlen(l:delimiter)
+
+ "get the index of the first occurrence of the delimiter
+ let delIndx = stridx(a:line, l:delimiter)
+
+ "keep looping thru the line till we either find a real comment delimiter
+ "or run off the EOL
+ while delIndx != -1
+
+ "if we are not off the EOL get the str before the possible delimiter
+ "in question and check if it really is a delimiter. If it is, return
+ "its position
+ if delIndx != -1
+ if s:IsDelimValid(l:delimiter, delIndx, a:line)
+ return delIndx
+ endif
+ endif
+
+ "we have not yet found a real comment delimiter so move past the
+ "current one we are lookin at
+ let restOfLine = strpart(a:line, delIndx + lenDel)
+ let distToNextDelim = stridx(restOfLine , l:delimiter)
+
+ "if distToNextDelim is -1 then there is no more potential delimiters
+ "on the line so set delIndx to -1. Otherwise, move along the line by
+ "distToNextDelim
+ if distToNextDelim == -1
+ let delIndx = -1
+ else
+ let delIndx = delIndx + lenDel + distToNextDelim
+ endif
+ endwhile
+
+ "there is no comment delimiter on this line
+ return -1
+endfunction
+
+" Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2
+" This function takes in a line number and tests whether this line number is
+" the top/bottom/middle line of a sexy comment. If it is then the top/bottom
+" lines of the sexy comment are returned
+" Args:
+" -lineNum: the line number that is to be tested whether it is the
+" top/bottom/middle line of a sexy com
+" Returns:
+" A string that has the top/bottom lines of the sexy comment encoded in it.
+" The format is 'topline,bottomline'. If a:lineNum turns out not to be the
+" top/bottom/middle of a sexy comment then -1 is returned
+function s:FindBoundingLinesOfSexyCom(lineNum)
+
+ "find which delimiters to look for as the start/end delims of the comment
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = s:GetLeft(0,0,1)
+ let right = s:GetRight(0,0,1)
+ elseif s:AltMultipart()
+ let left = s:GetLeft(1,0,1)
+ let right = s:GetRight(1,0,1)
+ else
+ return []
+ endif
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+
+ "initialise the top/bottom line numbers of the sexy comment to -1
+ let top = -1
+ let bottom = -1
+
+ let currentLine = a:lineNum
+ while top == -1 || bottom == -1
+ let theLine = getline(currentLine)
+
+ "check if the current line is the top of the sexy comment
+ if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf()
+ let top = currentLine
+ let currentLine = a:lineNum
+
+ "check if the current line is the bottom of the sexy comment
+ elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1
+ let bottom = currentLine
+
+ "the right delimiter is on the same line as the last sexyComMarker
+ elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
+ let bottom = currentLine
+
+ "we have not found the top or bottom line so we assume currentLine is an
+ "intermediate line and look to prove otherwise
+ else
+
+ "if the line doesnt start with a sexyComMarker then it is not a sexy
+ "comment
+ if theLine !~ '^[ \t]*' . sexyComMarker
+ return []
+ endif
+
+ endif
+
+ "if top is -1 then we havent found the top yet so keep looking up
+ if top == -1
+ let currentLine = currentLine - 1
+ "if we have found the top line then go down looking for the bottom
+ else
+ let currentLine = currentLine + 1
+ endif
+
+ endwhile
+
+ return [top, bottom]
+endfunction
+
+
+" Function: s:GetLeft(alt, space, esc) {{{2
+" returns the left/left-alternative delimiter
+" Args:
+" -alt: specifies whether to get left or left-alternative delim
+" -space: specifies whether the delim should be spaced or not
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the delim should be ESCed
+function s:GetLeft(alt, space, esc)
+ let delim = b:NERDLeft
+
+ if a:alt
+ if b:NERDLeftAlt == ''
+ return ''
+ else
+ let delim = b:NERDLeftAlt
+ endif
+ endif
+ if delim == ''
+ return ''
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let delim = delim . s:spaceStr
+ endif
+
+ if a:esc
+ let delim = s:Esc(delim)
+ endif
+
+ return delim
+endfunction
+
+" Function: s:GetRight(alt, space, esc) {{{2
+" returns the right/right-alternative delimiter
+" Args:
+" -alt: specifies whether to get right or right-alternative delim
+" -space: specifies whether the delim should be spaced or not
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the delim should be ESCed
+function s:GetRight(alt, space, esc)
+ let delim = b:NERDRight
+
+ if a:alt
+ if !s:AltMultipart()
+ return ''
+ else
+ let delim = b:NERDRightAlt
+ endif
+ endif
+ if delim == ''
+ return ''
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let delim = s:spaceStr . delim
+ endif
+
+ if a:esc
+ let delim = s:Esc(delim)
+ endif
+
+ return delim
+endfunction
+
+
+" Function: s:GetSexyComMarker() {{{2
+" Returns the sexy comment marker for the current filetype.
+"
+" C style sexy comments are assumed if possible. If not then the sexy comment
+" marker is the last char of the delimiter pair that has both left and right
+" delims and has the longest left delim
+"
+" Args:
+" -space: specifies whether the marker is to have a space string after it
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the marker are to be ESCed
+function s:GetSexyComMarker(space, esc)
+ let sexyComMarker = b:NERDSexyComMarker
+
+ "if there is no hardcoded marker then we find one
+ if sexyComMarker == ''
+
+ "if the filetype has c style comments then use standard c sexy
+ "comments
+ if s:HasCStyleComments()
+ let sexyComMarker = '*'
+ else
+ "find a comment marker by getting the longest available left delim
+ "(that has a corresponding right delim) and taking the last char
+ let lenLeft = strlen(b:NERDLeft)
+ let lenLeftAlt = strlen(b:NERDLeftAlt)
+ let left = ''
+ let right = ''
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let left = b:NERDLeft
+ elseif s:AltMultipart()
+ let left = b:NERDLeftAlt
+ else
+ return -1
+ endif
+
+ "get the last char of left
+ let sexyComMarker = strpart(left, strlen(left)-1)
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let sexyComMarker = sexyComMarker . s:spaceStr
+ endif
+
+ if a:esc
+ let sexyComMarker = s:Esc(sexyComMarker)
+ endif
+
+ return sexyComMarker
+endfunction
+
+" Function: s:GetSexyComLeft(space, esc) {{{2
+" Returns the left delimiter for sexy comments for this filetype or -1 if
+" there is none. C style sexy comments are used if possible
+" Args:
+" -space: specifies if the delim has a space string on the end
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the string are ESCed
+function s:GetSexyComLeft(space, esc)
+ let lenLeft = strlen(b:NERDLeft)
+ let lenLeftAlt = strlen(b:NERDLeftAlt)
+ let left = ''
+
+ "assume c style sexy comments if possible
+ if s:HasCStyleComments()
+ let left = '/*'
+ else
+ "grab the longest left delim that has a right
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let left = b:NERDLeft
+ elseif s:AltMultipart()
+ let left = b:NERDLeftAlt
+ else
+ return -1
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let left = left . s:spaceStr
+ endif
+
+ if a:esc
+ let left = s:Esc(left)
+ endif
+
+ return left
+endfunction
+
+" Function: s:GetSexyComRight(space, esc) {{{2
+" Returns the right delimiter for sexy comments for this filetype or -1 if
+" there is none. C style sexy comments are used if possible.
+" Args:
+" -space: specifies if the delim has a space string on the start
+" (the space string will only be added if NERDSpaceDelims
+" is specified for the current filetype)
+" -esc: specifies whether the tricky chars in the string are ESCed
+function s:GetSexyComRight(space, esc)
+ let lenLeft = strlen(b:NERDLeft)
+ let lenLeftAlt = strlen(b:NERDLeftAlt)
+ let right = ''
+
+ "assume c style sexy comments if possible
+ if s:HasCStyleComments()
+ let right = '*/'
+ else
+ "grab the right delim that pairs with the longest left delim
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let right = b:NERDRight
+ elseif s:AltMultipart()
+ let right = b:NERDRightAlt
+ else
+ return -1
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let right = s:spaceStr . right
+ endif
+
+ if a:esc
+ let right = s:Esc(right)
+ endif
+
+ return right
+endfunction
+
+" Function: s:HasMultipartDelims() {{{2
+" Returns 1 iff the current filetype has at least one set of multipart delims
+function s:HasMultipartDelims()
+ return s:Multipart() || s:AltMultipart()
+endfunction
+
+" Function: s:HasLeadingTabs(...) {{{2
+" Returns 1 if any of the given strings have leading tabs
+function s:HasLeadingTabs(...)
+ for s in a:000
+ if s =~ '^\t.*'
+ return 1
+ end
+ endfor
+ return 0
+endfunction
+" Function: s:HasCStyleComments() {{{2
+" Returns 1 iff the current filetype has c style comment delimiters
+function s:HasCStyleComments()
+ return (b:NERDLeft == '/*' && b:NERDRight == '*/') || (b:NERDLeftAlt == '/*' && b:NERDRightAlt == '*/')
+endfunction
+
+" Function: s:IsCommentedNormOrSexy(lineNum) {{{2
+"This function is used to determine whether the given line is commented with
+"either set of delimiters or if it is part of a sexy comment
+"
+" Args:
+" -lineNum: the line number of the line to check
+function s:IsCommentedNormOrSexy(lineNum)
+ let theLine = getline(a:lineNum)
+
+ "if the line is commented normally return 1
+ if s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)
+ return 1
+ endif
+
+ "if the line is part of a sexy comment return 1
+ if s:IsInSexyComment(a:lineNum)
+ return 1
+ endif
+ return 0
+endfunction
+
+" Function: s:IsCommented(left, right, line) {{{2
+"This function is used to determine whether the given line is commented with
+"the given delimiters
+"
+" Args:
+" -line: the line that to check if commented
+" -left/right: the left and right delimiters to check for
+function s:IsCommented(left, right, line)
+ "if the line isnt commented return true
+ if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart())
+ return 1
+ endif
+ return 0
+endfunction
+
+" Function: s:IsCommentedFromStartOfLine(left, line) {{{2
+"This function is used to determine whether the given line is commented with
+"the given delimiters at the start of the line i.e the left delimiter is the
+"first thing on the line (apart from spaces\tabs)
+"
+" Args:
+" -line: the line that to check if commented
+" -left: the left delimiter to check for
+function s:IsCommentedFromStartOfLine(left, line)
+ let theLine = s:ConvertLeadingTabsToSpaces(a:line)
+ let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', ''))
+ let delimIndx = s:FindDelimiterIndex(a:left, theLine)
+ return delimIndx == numSpaces
+endfunction
+
+" Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
+" Finds the type of the outtermost delims on the line
+"
+" Args:
+" -line: the line that to check if the outtermost comments on it are
+" left/right
+" -left/right: the left and right delimiters to check for
+" -leftAlt/rightAlt: the left and right alternative delimiters to check for
+"
+" Returns:
+" 0 if the line is not commented with either set of delims
+" 1 if the line is commented with the left/right delim set
+" 2 if the line is commented with the leftAlt/rightAlt delim set
+function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line)
+ "get the first positions of the left delims and the last positions of the
+ "right delims
+ let indxLeft = s:FindDelimiterIndex(a:left, a:line)
+ let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
+ let indxRight = s:LastIndexOfDelim(a:right, a:line)
+ let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
+
+ "check if the line has a left delim before a leftAlt delim
+ if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1
+ "check if the line has a right delim after any rightAlt delim
+ if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
+ return 1
+ endif
+
+ "check if the line has a leftAlt delim before a left delim
+ elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1
+ "check if the line has a rightAlt delim after any right delim
+ if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
+ return 2
+ endif
+ else
+ return 0
+ endif
+
+ return 0
+
+endfunction
+
+
+" Function: s:IsDelimValid(delimiter, delIndx, line) {{{2
+" This function is responsible for determining whether a given instance of a
+" comment delimiter is a real delimiter or not. For example, in java the
+" // string is a comment delimiter but in the line:
+" System.out.println("//");
+" it does not count as a comment delimiter. This function is responsible for
+" distinguishing between such cases. It does so by applying a set of
+" heuristics that are not fool proof but should work most of the time.
+"
+" Args:
+" -delimiter: the delimiter we are validating
+" -delIndx: the position of delimiter in line
+" -line: the line that delimiter occurs in
+"
+" Returns:
+" 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
+" 1 otherwise
+function s:IsDelimValid(delimiter, delIndx, line)
+ "get the delimiter without the escchars
+ let l:delimiter = a:delimiter
+
+ "get the strings before and after the delimiter
+ let preComStr = strpart(a:line, 0, a:delIndx)
+ let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
+
+ "to check if the delimiter is real, make sure it isnt preceded by
+ "an odd number of quotes and followed by the same (which would indicate
+ "that it is part of a string and therefore is not a comment)
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\"))
+ return 0
+ endif
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
+ return 0
+ endif
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
+ return 0
+ endif
+
+
+ "if the comment delimiter is escaped, assume it isnt a real delimiter
+ if s:IsEscaped(a:line, a:delIndx, "\\")
+ return 0
+ endif
+
+ "vim comments are so fuckin stupid!! Why the hell do they have comment
+ "delimiters that are used elsewhere in the syntax?!?! We need to check
+ "some conditions especially for vim
+ if &filetype == "vim"
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
+ return 0
+ endif
+
+ "if the delimiter is on the very first char of the line or is the
+ "first non-tab/space char on the line then it is a valid comment delimiter
+ if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$"
+ return 1
+ endif
+
+ let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
+ let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
+
+ "if the quote is inside brackets then assume it isnt a comment
+ if numLeftParen > numRightParen
+ return 0
+ endif
+
+ "if the line has an even num of unescaped "'s then we can assume that
+ "any given " is not a comment delimiter
+ if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\"))
+ return 0
+ endif
+ endif
+
+ return 1
+
+endfunction
+
+" Function: s:IsNumEven(num) {{{2
+" A small function the returns 1 if the input number is even and 0 otherwise
+" Args:
+" -num: the number to check
+function s:IsNumEven(num)
+ return (a:num % 2) == 0
+endfunction
+
+" Function: s:IsEscaped(str, indx, escChar) {{{2
+" This function takes a string, an index into that string and an esc char and
+" returns 1 if the char at the index is escaped (i.e if it is preceded by an
+" odd number of esc chars)
+" Args:
+" -str: the string to check
+" -indx: the index into str that we want to check
+" -escChar: the escape char the char at indx may be ESCed with
+function s:IsEscaped(str, indx, escChar)
+ "initialise numEscChars to 0 and look at the char before indx
+ let numEscChars = 0
+ let curIndx = a:indx-1
+
+ "keep going back thru str until we either reach the start of the str or
+ "run out of esc chars
+ while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar
+
+ "we have found another esc char so add one to the count and move left
+ "one char
+ let numEscChars = numEscChars + 1
+ let curIndx = curIndx - 1
+
+ endwhile
+
+ "if there is an odd num of esc chars directly before the char at indx then
+ "the char at indx is escaped
+ return !s:IsNumEven(numEscChars)
+endfunction
+
+" Function: s:IsInSexyComment(line) {{{2
+" returns 1 if the given line number is part of a sexy comment
+function s:IsInSexyComment(line)
+ return !empty(s:FindBoundingLinesOfSexyCom(a:line))
+endfunction
+
+" Function: s:IsSexyComment(topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns 1 if the lines between and
+" including the given line numbers are a sexy comment. It returns 0 otherwise.
+" Args:
+" -topline: the line that the possible sexy comment starts on
+" -bottomline: the line that the possible sexy comment stops on
+function s:IsSexyComment(topline, bottomline)
+
+ "get the delim set that would be used for a sexy comment
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = b:NERDLeft
+ let right = b:NERDRight
+ elseif s:AltMultipart()
+ let left = b:NERDLeftAlt
+ let right = b:NERDRightAlt
+ else
+ return 0
+ endif
+
+ "swap the top and bottom line numbers around if need be
+ let topline = a:topline
+ let bottomline = a:bottomline
+ if bottomline < topline
+ topline = bottomline
+ bottomline = a:topline
+ endif
+
+ "if there is < 2 lines in the comment it cannot be sexy
+ if (bottomline - topline) <= 0
+ return 0
+ endif
+
+ "if the top line doesnt begin with a left delim then the comment isnt sexy
+ if getline(a:topline) !~ '^[ \t]*' . left
+ return 0
+ endif
+
+ "if there is a right delim on the top line then this isnt a sexy comment
+ if s:FindDelimiterIndex(right, getline(a:topline)) != -1
+ return 0
+ endif
+
+ "if there is a left delim on the bottom line then this isnt a sexy comment
+ if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1
+ return 0
+ endif
+
+ "if the bottom line doesnt begin with a right delim then the comment isnt
+ "sexy
+ if getline(a:bottomline) !~ '^.*' . right . '$'
+ return 0
+ endif
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+
+ "check each of the intermediate lines to make sure they start with a
+ "sexyComMarker
+ let currentLine = a:topline+1
+ while currentLine < a:bottomline
+ let theLine = getline(currentLine)
+
+ if theLine !~ '^[ \t]*' . sexyComMarker
+ return 0
+ endif
+
+ "if there is a right delim in an intermediate line then the block isnt
+ "a sexy comment
+ if s:FindDelimiterIndex(right, theLine) != -1
+ return 0
+ endif
+
+ let currentLine = currentLine + 1
+ endwhile
+
+ "we have not found anything to suggest that this isnt a sexy comment so
+ return 1
+
+endfunction
+
+" Function: s:LastIndexOfDelim(delim, str) {{{2
+" This function takes a string and a delimiter and returns the last index of
+" that delimiter in string
+" Args:
+" -delim: the delimiter to look for
+" -str: the string to look for delim in
+function s:LastIndexOfDelim(delim, str)
+ let delim = a:delim
+ let lenDelim = strlen(delim)
+
+ "set index to the first occurrence of delim. If there is no occurrence then
+ "bail
+ let indx = s:FindDelimiterIndex(delim, a:str)
+ if indx == -1
+ return -1
+ endif
+
+ "keep moving to the next instance of delim in str till there is none left
+ while 1
+
+ "search for the next delim after the previous one
+ let searchStr = strpart(a:str, indx+lenDelim)
+ let indx2 = s:FindDelimiterIndex(delim, searchStr)
+
+ "if we find a delim update indx to record the position of it, if we
+ "dont find another delim then indx is the last one so break out of
+ "this loop
+ if indx2 != -1
+ let indx = indx + indx2 + lenDelim
+ else
+ break
+ endif
+ endwhile
+
+ return indx
+
+endfunction
+
+" Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns the index of the left most
+" char (that is not a space or a tab) on all of these lines.
+" Args:
+" -countCommentedLines: 1 if lines that are commented are to be checked as
+" well. 0 otherwise
+" -countEmptyLines: 1 if empty lines are to be counted in the search
+" -topline: the top line to be checked
+" -bottomline: the bottom line to be checked
+function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
+
+ " declare the left most index as an extreme value
+ let leftMostIndx = 1000
+
+ " go thru the block line by line updating leftMostIndx
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+
+ " get the next line and if it is allowed to be commented, or is not
+ " commented, check it
+ let theLine = getline(currentLine)
+ if a:countEmptyLines || theLine !~ '^[ \t]*$'
+ if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine))
+ " convert spaces to tabs and get the number of leading spaces for
+ " this line and update leftMostIndx if need be
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') )
+ if leadSpaceOfLine < leftMostIndx
+ let leftMostIndx = leadSpaceOfLine
+ endif
+ endif
+ endif
+
+ " move on to the next line
+ let currentLine = currentLine + 1
+ endwhile
+
+ if leftMostIndx == 1000
+ return 0
+ else
+ return leftMostIndx
+ endif
+endfunction
+
+" Function: s:Multipart() {{{2
+" returns 1 if the current delims are multipart
+function s:Multipart()
+ return b:NERDRight != ''
+endfunction
+
+" Function: s:NerdEcho(msg, typeOfMsg) {{{2
+" Args:
+" -msg: the message to echo
+" -typeOfMsg: 0 = warning message
+" 1 = normal message
+function s:NerdEcho(msg, typeOfMsg)
+ if a:typeOfMsg == 0
+ echohl WarningMsg
+ echo 'NERDCommenter:' . a:msg
+ echohl None
+ elseif a:typeOfMsg == 1
+ echo 'NERDCommenter:' . a:msg
+ endif
+endfunction
+
+" Function: s:NumberOfLeadingTabs(s) {{{2
+" returns the number of leading tabs in the given string
+function s:NumberOfLeadingTabs(s)
+ return strlen(substitute(a:s, '^\(\t*\).*$', '\1', ""))
+endfunction
+
+" Function: s:NumLinesInBuf() {{{2
+" Returns the number of lines in the current buffer
+function s:NumLinesInBuf()
+ return line('$')
+endfunction
+
+" Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2
+" This function takes in a string, 2 delimiters in that string and 2 strings
+" to replace these delimiters with.
+"
+" Args:
+" -toReplace1: the first delimiter to replace
+" -toReplace2: the second delimiter to replace
+" -replacor1: the string to replace toReplace1 with
+" -replacor2: the string to replace toReplace2 with
+" -str: the string that the delimiters to be replaced are in
+function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
+ let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
+ let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
+ return line
+endfunction
+
+" Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2
+" This function takes a string and a delimiter and replaces the left most
+" occurrence of this delimiter in the string with a given string
+"
+" Args:
+" -toReplace: the delimiter in str that is to be replaced
+" -replacor: the string to replace toReplace with
+" -str: the string that contains toReplace
+function s:ReplaceLeftMostDelim(toReplace, replacor, str)
+ let toReplace = a:toReplace
+ let replacor = a:replacor
+ "get the left most occurrence of toReplace
+ let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
+
+ "if there IS an occurrence of toReplace in str then replace it and return
+ "the resulting string
+ if indxToReplace != -1
+ let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
+ return line
+ endif
+
+ return a:str
+endfunction
+
+" Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2
+" This function takes a string and a delimiter and replaces the right most
+" occurrence of this delimiter in the string with a given string
+"
+" Args:
+" -toReplace: the delimiter in str that is to be replaced
+" -replacor: the string to replace toReplace with
+" -str: the string that contains toReplace
+"
+function s:ReplaceRightMostDelim(toReplace, replacor, str)
+ let toReplace = a:toReplace
+ let replacor = a:replacor
+ let lenToReplace = strlen(toReplace)
+
+ "get the index of the last delim in str
+ let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
+
+ "if there IS a delimiter in str, replace it and return the result
+ let line = a:str
+ if indxToReplace != -1
+ let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
+ endif
+ return line
+endfunction
+
+"FUNCTION: s:RestoreScreenState() {{{2
+"
+"Sets the screen state back to what it was when s:SaveScreenState was last
+"called.
+"
+function s:RestoreScreenState()
+ if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
+ throw 'NERDCommenter exception: cannot restore screen'
+ endif
+
+ call cursor(t:NERDComOldTopLine, 0)
+ normal! zt
+ call setpos(".", t:NERDComOldPos)
+endfunction
+
+" Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns the index of the right most
+" char on all of these lines.
+" Args:
+" -countCommentedLines: 1 if lines that are commented are to be checked as
+" well. 0 otherwise
+" -countEmptyLines: 1 if empty lines are to be counted in the search
+" -topline: the top line to be checked
+" -bottomline: the bottom line to be checked
+function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
+ let rightMostIndx = -1
+
+ " go thru the block line by line updating rightMostIndx
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+
+ " get the next line and see if it is commentable, otherwise it doesnt
+ " count
+ let theLine = getline(currentLine)
+ if a:countEmptyLines || theLine !~ '^[ \t]*$'
+
+ if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine))
+
+ " update rightMostIndx if need be
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let lineLen = strlen(theLine)
+ if lineLen > rightMostIndx
+ let rightMostIndx = lineLen
+ endif
+ endif
+ endif
+
+ " move on to the next line
+ let currentLine = currentLine + 1
+ endwhile
+
+ return rightMostIndx
+endfunction
+
+"FUNCTION: s:SaveScreenState() {{{2
+"Saves the current cursor position in the current buffer and the window
+"scroll position
+function s:SaveScreenState()
+ let t:NERDComOldPos = getpos(".")
+ let t:NERDComOldTopLine = line("w0")
+endfunction
+
+" Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
+" This function takes a line and swaps the outter most multi-part delims for
+" place holders
+" Args:
+" -line: the line to swap the delims in
+"
+function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
+ " find out if the line is commented using normal delims and/or
+ " alternate ones
+ let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, a:line)
+ let isCommentedAlt = s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, a:line)
+
+ let line2 = a:line
+
+ "if the line is commented and there is a right delimiter, replace
+ "the delims with place-holders
+ if isCommented && s:Multipart()
+ let line2 = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, a:line)
+
+ "similarly if the line is commented with the alternative
+ "delimiters
+ elseif isCommentedAlt && s:AltMultipart()
+ let line2 = s:ReplaceDelims(b:NERDLeftAlt, b:NERDRightAlt, g:NERDLPlace, g:NERDRPlace, a:line)
+ endif
+
+ return line2
+endfunction
+
+" Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
+" This function takes a line and swaps the outtermost place holders for
+" multi-part delims
+" Args:
+" -line: the line to swap the delims in
+"
+function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = b:NERDLeft
+ let right = b:NERDRight
+ elseif s:AltMultipart()
+ let left = b:NERDLeftAlt
+ let right = b:NERDRightAlt
+ endif
+
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
+ return line
+endfunction
+" Function: s:TabbedCol(line, col) {{{2
+" Gets the col number for given line and existing col number. The new col
+" number is the col number when all leading spaces are converted to tabs
+" Args:
+" -line:the line to get the rel col for
+" -col: the abs col
+function s:TabbedCol(line, col)
+ let lineTruncated = strpart(a:line, 0, a:col)
+ let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g')
+ return strlen(lineSpacesToTabs)
+endfunction
+"FUNCTION: s:TabSpace() {{{2
+"returns a string of spaces equal in length to &tabstop
+function s:TabSpace()
+ let tabSpace = ""
+ let spacesPerTab = &tabstop
+ while spacesPerTab > 0
+ let tabSpace = tabSpace . " "
+ let spacesPerTab = spacesPerTab - 1
+ endwhile
+ return tabSpace
+endfunction
+
+" Function: s:UnEsc(str, escChar) {{{2
+" This function removes all the escape chars from a string
+" Args:
+" -str: the string to remove esc chars from
+" -escChar: the escape char to be removed
+function s:UnEsc(str, escChar)
+ return substitute(a:str, a:escChar, "", "g")
+endfunction
+
+" Function: s:UntabbedCol(line, col) {{{2
+" Takes a line and a col and returns the absolute column of col taking into
+" account that a tab is worth 3 or 4 (or whatever) spaces.
+" Args:
+" -line:the line to get the abs col for
+" -col: the col that doesnt take into account tabs
+function s:UntabbedCol(line, col)
+ let lineTruncated = strpart(a:line, 0, a:col)
+ let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g')
+ return strlen(lineTabsToSpaces)
+endfunction
+" Section: Comment mapping setup {{{1
+" ===========================================================================
+
+" switch to/from alternative delimiters
+nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
+
+" comment out lines
+nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
+vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
+
+" toggle comments
+nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
+vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
+
+" minimal comments
+nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
+vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
+
+" sexy comments
+nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
+vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
+
+" invert comments
+nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
+vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
+
+" yank then comment
+nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
+vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
+
+" left aligned comments
+nnoremap <silent> <plug>NERDCommenterAlignLeft :call NERDComment(0, "alignLeft")<cr>
+vnoremap <silent> <plug>NERDCommenterAlignLeft <ESC>:call NERDComment(1, "alignLeft")<cr>
+
+" left and right aligned comments
+nnoremap <silent> <plug>NERDCommenterAlignBoth :call NERDComment(0, "alignBoth")<cr>
+vnoremap <silent> <plug>NERDCommenterAlignBoth <ESC>:call NERDComment(1, "alignBoth")<cr>
+
+" nested comments
+nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
+vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
+
+" uncomment
+nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
+vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
+
+" comment till the end of the line
+nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
+
+" append comments
+nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
+
+" insert comments
+inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
+
+
+function! s:CreateMaps(target, combo)
+ if !hasmapto(a:target, 'n')
+ exec 'nmap ' . a:combo . ' ' . a:target
+ endif
+
+ if !hasmapto(a:target, 'v')
+ exec 'vmap ' . a:combo . ' ' . a:target
+ endif
+endfunction
+
+if g:NERDCreateDefaultMappings
+ call s:CreateMaps('<plug>NERDCommenterComment', ',cc')
+ call s:CreateMaps('<plug>NERDCommenterToggle', ',c<space>')
+ call s:CreateMaps('<plug>NERDCommenterMinimal', ',cm')
+ call s:CreateMaps('<plug>NERDCommenterSexy', ',cs')
+ call s:CreateMaps('<plug>NERDCommenterInvert', ',ci')
+ call s:CreateMaps('<plug>NERDCommenterYank', ',cy')
+ call s:CreateMaps('<plug>NERDCommenterAlignLeft', ',cl')
+ call s:CreateMaps('<plug>NERDCommenterAlignBoth', ',cb')
+ call s:CreateMaps('<plug>NERDCommenterNest', ',cn')
+ call s:CreateMaps('<plug>NERDCommenterUncomment', ',cu')
+ call s:CreateMaps('<plug>NERDCommenterToEOL', ',c$')
+ call s:CreateMaps('<plug>NERDCommenterAppend', ',cA')
+
+ if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
+ nmap ,ca <plug>NERDCommenterAltDelims
+ endif
+endif
+
+
+
+" Section: Menu item setup {{{1
+" ===========================================================================
+"check if the user wants the menu to be displayed
+if g:NERDMenuMode != 0
+
+ let menuRoot = ""
+ if g:NERDMenuMode == 1
+ let menuRoot = 'comment'
+ elseif g:NERDMenuMode == 2
+ let menuRoot = '&comment'
+ elseif g:NERDMenuMode == 3
+ let menuRoot = '&Plugin.&comment'
+ endif
+
+ function! s:CreateMenuItems(target, desc, root)
+ exec 'nmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
+ exec 'vmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
+ endfunction
+ call s:CreateMenuItems("<plug>NERDCommenterComment", 'Comment', menuRoot)
+ call s:CreateMenuItems("<plug>NERDCommenterToggle", 'Toggle', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterMinimal', 'Minimal', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterNest', 'Nested', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.To\ EOL <plug>NERDCommenterToEOL'
+ call s:CreateMenuItems('<plug>NERDCommenterInvert', 'Invert', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterSexy', 'Sexy', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterYank', 'Yank\ then\ comment', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.Append <plug>NERDCommenterAppend'
+ exec 'menu <silent> '. menuRoot .'.-Sep- :'
+ call s:CreateMenuItems('<plug>NERDCommenterAlignLeft', 'Left\ aligned', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot)
+ exec 'menu <silent> '. menuRoot .'.-Sep2- :'
+ call s:CreateMenuItems('<plug>NERDCommenterUncomment', 'Uncomment', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.Switch\ Delimiters <plug>NERDCommenterAltDelims'
+ exec 'imenu <silent> '. menuRoot .'.Insert\ Comment\ Here <plug>NERDCommenterInInsert'
+ exec 'menu <silent> '. menuRoot .'.-Sep3- :'
+ exec 'menu <silent>'. menuRoot .'.Help :help NERDCommenterContents<CR>'
+endif
+" vim: set foldmethod=marker :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vim/bundle/yankring/doc/yankring.txt Wed Jun 09 17:53:48 2010 -0400
@@ -0,0 +1,1412 @@
+*yankring.txt* For Vim version 7.0.
+
+Author: David Fishburn August 29, 2009
+Version: 10.0
+
+For instructions on installing this file, type
+ :help add-local-help |add-local-help| inside Vim.
+
+
+==============================================================================
+1. Contents *yankring* *yankring-contents*
+
+ 1. Contents...............................: |yankring-contents|
+ 2. Description............................: |yankring-description|
+ 3. Configuration..........................: |yankring-configure|
+ 3.1 Global Variables...................: |yankring-globals|
+ 3.2 Default Keys.......................: |yankring-mappings|
+ 3.3 Customizing Maps...................: |yankring-custom-maps|
+ 4. Using the YankRing Window..............: |yankring-window|
+ 5. Commands...............................: |yankring-commands|
+ 5.1 YRToggle..........................: |YRToggle|
+ 5.2 YRClear...........................: |YRClear|
+ 5.3 YRShow............................: |YRShow|
+ 5.5 YRGetElem.........................: |YRGetElem|
+ 5.6 YRGetMultiple.....................: |YRGetMultiple|
+ 5.7 YRPush............................: |YRPush|
+ 5.8 YRPop.............................: |YRPop|
+ 5.9 YRYankCount.......................: |YRYankCount|
+ 5.10 YRYankRange.......................: |YRYankRange|
+ 5.11 YRDeleteRange.....................: |YRDeleteRange|
+ 5.12 YRPaste...........................: |YRPaste|
+ 5.13 YRReplace.........................: |YRReplace|
+ 5.14 YRMapsCreate......................: |YRMapsCreate|
+ 5.15 YRMapsDelete......................: |YRMapsDelete|
+ 5.16 YRSearch..........................: |YRSearch|
+ 5.17 YRRunAfterMaps....................: |yankring-custom-maps|
+ 6. Tutorial...............................: |yankring-tutorial|
+ 6.1 YRShow............................: |YRShow-example|
+ 6.2 YRReplace.........................: |YRReplace-example|
+ 6.3 YRPush............................: |YRPush-example|
+ 6.4 YRClear...........................: |YRClear-example|
+ 6.8 YRPop.............................: |YRPop-example|
+ 6.9 Visual modes......................: |yankring-visual-example|
+ 6.10 Using ranges......................: |YRYankRange-example|
+ 6.11 :global...........................: |global-example|
+ 6.12 YRSearch..........................: |YRSearch-example|
+ 7. History................................: |yankring-history|
+
+==============================================================================
+2. Description *yankring-description*
+
+Vim already maintains a list of numbered registers containing the last 9
+deletes. These previous deletes can be referenced using [register]p, so
+"1p will paste the last delete, "2p the 2nd last delete. For more
+information see |quote_number|.
+
+Vim does not provide any mechanism to reference previously yanked text.
+In Emacs this feature is called the "kill ring".
+
+The YankRing plugin allows the user to configure the number of yanked
+and deleted text. After text has been pasted, it can be replaced with
+a previous value from the yankring.
+
+As of version 3.0, the yankring's content will persist (by default)
+between starting and stopping Vim.
+
+The plugin can be toggled on and off, and supports:
+ Ranges
+ Registers
+ Counts
+ All visual modes
+ All motions
+ All text-objects
+
+If you have any suggestions for the improvement of this plugin, see the
+yankring.vim file for my email address. Suggestions / bug reports are
+always welcome.
+
+For details on the changes between versions see |yankring-history|.
+
+==============================================================================
+3. Configuration *yankring-configure*
+
+The YankRing allows the user to choose which keys are to be assigned to
+the various commands. By default, the YankRing chose keys identical
+with Vim's standard behaviour/keys.
+
+3.1 Global Variables *yankring-globals*
+
+You can customize the YankRing by setting various global variables in
+your |.vimrc|.
+>
+ yankring_max_history
+< Default: 100
+ Controls how many elements to save in the yankring. >
+ let g:yankring_max_history = 100
+ yankring_min_element_length
+< Default: 1
+ If the yanked element has a length less than this value
+ if will not be added to the YankRing. This can be useful if
+ you want to bypass single letter deletes by adding the
+ following to your .vimrc: >
+ let g:yankring_min_element_length = 2
+ yankring_max_element_length
+< Default: 1048576 (1M)
+ Will truncate a new entry to the specified maximum. If
+ g:yankring_max_element_length is set to 0, there is no limit. >
+ let g:yankring_max_element_length = 4194304 " 4M
+ yankring_max_display
+< Default: 500
+ When the YankRing window is opened, each element is displayed on a
+ separate line. Since each yank could be very large, the display of
+ the element is limited to the above default. >
+ let g:yankring_max_display = 70
+ yankring_enabled
+< Default: 1
+ If you do not want to YankRing enabled by default, set this
+ variable in your |vimrc|. >
+ let g:yankring_enabled = 0 " Disables the yankring
+ yankring_persist
+< Default: 1
+ If you have enabled the storing of global variables in the |viminfo|
+ file, the YankRing will be default persist the contents of the ring
+ between starting and stopping Vim. To disable this feature: >
+ let g:yankring_persist = 0
+ yankring_share_between_instances
+< Default: 1
+ By default, any instance of Vim will share the same yankring
+ history file. But if want each instance to have their own history
+ you can set this option to 0. Setting g:yankring_persist = 0 and
+ g:yankring_share_between_instances = 0 will ensure no 2 instances
+ of Vim share the same YankRing history AND the history is not
+ remembered the next time Vim is started. >
+ let g:yankring_share_between_instances = 0
+ yankring_dot_repeat_yank
+< Default: Based on the Vim cpoption setting
+ By default Vim will not repeat (using '.') yanking of text. This can
+ be controlled via the |'cpoptions'| setting. The YankRing now respects
+ the cpoptions setting, if 'y' is included and you press '.', the
+ previous yank command is repeated and added to the yankring.
+ You can also add this behaviour by setting this in your |vimrc|: >
+ let g:yankring_dot_repeat_yank = 1
+ yankring_ignore_duplicate
+< Default: 1
+ Duplicates will not be added to the YankRing by default. If a
+ duplicate is found, that element will be moved to the top of the
+ yankring. This can be controlled by setting this in your |vimrc|: >
+ let g:yankring_ignore_duplicate = 0
+ yankring_map_dot
+< Default: 1
+ If the '.' (repeat) command should be mapped by the yankring. Since
+ most of the normal commands yy,dd,dw,... are mapped by the yankring,
+ if g:yankring_map_dot is false the . operator will not repeat these
+ operations. The YankRing tracks several of the internal Vim registers
+ and decides whether an action was the result of the YankRing or an
+ action outside of it. If the previous action was a result of the
+ yankring, it will be executed again. If it was an action outside of
+ the yankring, it asks Vim to repeat the command. >
+ let g:yankring_map_dot = 1
+ yankring_paste_using_g
+< Default: 1
+ By default [p] and [P] are mapped to interact with the yankring. This
+ option controls whether [gp] and [gP] are also mapped. Setting this
+ option to 0 will not create these maps. >
+ let g:yankring_paste_using_g = 1
+ yankring_window_use_separate
+< Default: 1
+ This is a new feature as of the 2.0 release. The YankRing now uses a
+ separate split buffer to display the yankring. There are many buffer
+ specific maps that allow you to operate over the various elements from
+ within the yankring. Setting this option to 0, uses the 1.0
+ interface. >
+ let g:yankring_window_use_separate = 0
+ yankring_window_auto_close
+< Default: 1
+ By default once you choose an option in the YankRing buffer, the
+ action is performed and the buffer window is closed, returning you to
+ the original buffer. This option can be toggled from within the
+ YankRing buffer by pressing [a]. The YankRing buffer status line
+ visually indicates where auto close is enabled or disabled. There are
+ many times where you need to paste (or delete) many items from the
+ yankring. Pressing [a], disables auto close, allows you to paste many
+ items, and finally you can press [a] to re-enable auto close, followed
+ by [q] to quit the buffer window. >
+ let g:yankring_window_auto_close = 1
+ yankring_window_use_horiz
+< Default: 1
+ When the YankRing window is opened, it uses a horizontal split at the
+ bottom of the Vim window. It can optionally use a vertical split by
+ setting this option to 0. >
+ let g:yankring_window_use_horiz = 0 " Use vertical split
+ yankring_window_height
+< Default: 1
+ If using a horizontal split, this option controls how high to make
+ the window. >
+ let g:yankring_window_height = 8
+ yankring_window_width
+< Default: 1
+ If using a vertical split, this option controls how wide to make the
+ window. >
+ let g:yankring_window_width = 30
+ yankring_window_use_bottom
+< Default: 1
+ If using a horizontal split, this option control whether the window is
+ opened at the top or bottom of the Vim window. Setting this option to
+ 0 forces the window to open at the top of the Vim window. >
+ let g:yankring_window_use_bottom = 1
+ yankring_window_use_right
+< Default: 1
+ If using a vertical split, this option control whether the window is
+ opened on the left or right side of the Vim window. To force the
+ window to open on the left side, set this option to 0. >
+ let g:yankring_window_use_right = 1
+ yankring_window_increment
+< Default: 1
+ If using a vertical split the default width of the vertical window may
+ be too narrow to view enough of the elements. Pressing [<space>] will
+ increase the size of the window by this number of columns. Pressing
+ [<space>] again will toggle it back to the original size. >
+ let g:yankring_window_increment = 50
+ yankring_manage_numbered_reg
+< Default: 0
+ Vim already maintains a list of numbered registers containing the last
+ yanked item and the previous 9 deletes. These items can be referenced
+ using [register]p, so "0p will paste the last yank, "1p will paste the
+ last delete, "2p the 2nd last delete. For more information see
+ |quote_number|.
+ If you wish the YankRing to maintain these numbered registers so
+ the top 10 elements in the YankRing are in the numbered reqisters 0-9
+ you can put the following in your |vimrc| >
+ let g:yankring_manage_numbered_reg = 1
+ yankring_ignore_operator
+< Default: 'g~ gu gU ! = gq g? > < zf g@'
+ There are a number of Vim operations which do not change any
+ registers, and therefore should not be captured by the yankring.
+ This list is used to ignore the appropriate operators.
+ You can put the following in your |vimrc| >
+ let g:yankring_ignore_operator = 'g~ gu gU ! = gq g? > < zf g@'
+ yankring_history_dir
+< Default: $HOME
+ The YankRing stores the text in a file. This global variable
+ allows you to customize where the file(s) will be stored.
+ You can put the following in your |vimrc| >
+ let g:yankring_history_dir = '$VIM'
+ yankring_history_file
+< Default: 'yankring_history'
+ The history filename prefix can be controlled by setting this
+ variable.
+ You can put the following in your |vimrc| >
+ let g:yankring_history_file = 'my_yankring_history_file'
+ yankring_clipboard_monitor
+< Default: 1
+ When flipping between applications I find I often copy text
+ and attempt to use it inside of Vim. This is typically easy
+ by simply using "+p, but there are times when I will repeatedly
+ want to use the same text later on. By default, the YankRing
+ will detect when Vim regains focus and check if the clipboard
+ has changed since it last checked. If so, it will add the contents
+ of the clipboard to the YankRing. To disable this feature
+ you can put the following in your |vimrc| >
+ let g:yankring_clipboard_monitor = 0
+ yankring_paste_check_default_buffer
+< Default: 1
+ If the default register has changed without the YankRing registering
+ the change the YankRing will paste the top item from the history
+ rather than what is currently in the default register.
+ This option allows you to control the behaviour. Plugins can
+ intentionally change the default buffer which the YankRing has
+ no way to noticing. To disable this feature you can put the following
+ in your |vimrc| >
+ let g:yankring_paste_check_default_buffer = 0
+
+<
+3.2 Default Keys *yankring-mappings*
+
+You can choose to override the default keys by creating these global
+variables in your |vimrc|.
+>
+ yankring_n_keys
+< n - normal mode
+ Default Vim 7.2:
+ 'Y D x X'
+ Default Vim 7.1 and below:
+ 'x yy dd yw dw ye de yE dE yiw diw yaw daw y$ d$ Y D yG dG ygg dgg'
+
+ With the introduction of some new features in Vim 7.2 it is no longer
+ necessary to list all cmds which the YankRing will act upon.
+ The yankring_n_keys only lists actions which an omap cannot be used.
+ Using the yankring_separator, the above list is parsed and
+ individual mappings are created. For each of the above normal
+ commands the YankRing will include the text those commands
+ acted upon. There are many ways to accomplish the same result
+ in Vim, if you do not see a common key stroke you regularly use
+ simply add the following to your |vimrc| with the additional
+ keys you wished mapped. >
+ let g:yankring_n_keys = 'Y D x X'
+ yankring_o_keys
+< o - omap mode
+ Default:
+ Standard motions: 'b B w W e E d y $ G ;'
+ Vim text objects: ' iw iW aw aW as is ap ip a] a[ i] i['
+ 'a) a( ab i) i( ib a> a< i> i< at it '
+ 'a} a{ aB i} i{ iB a" a'' a` i" i'' i`'
+
+ As of Vim 7.2 omaps are used to capture changes to the registers
+ in Vim. All of the standard motion commands are captured.
+ New to YankRing 5.0 all default Vim text objects are also
+ captured.
+ Using the yankring_separator, the above list is parsed and
+ individual mappings are created. For each of the above normal
+ commands the YankRing will include the text those commands
+ acted upon. There are many ways to accomplish the same result
+ in Vim, if you do not see a common key stroke you regularly use
+ simply add the following to your |vimrc| with the additional
+ keys you wished mapped. >
+ let g:yankring_o_keys = 'b B w W e E d y $ G ; iw iW aw aW'
+ yankring_zap_keys
+< Default: 'f F t T / ?'
+ omaps are enough for most operations except for f and t.
+ These motions prompt the user for a character or string which
+ they should act upon. These must be treated as a special case
+ in YankRing. >
+ let g:yankring_zap_keys = 'f t'
+ yankring_ignore_operator
+< Default: 'g~ gu gU ! = gq g? > < zf g@'
+ There are certain motions which do not update any registers
+ in Vim. If the registers are not changed, there is nothing
+ the YankRing can capture. This list instructs the YankRing
+ to ignore any action for these keys. >
+ let g:yankring_ignore_operator = 'g~ gu gU'
+ yankring_v_key
+< v - visual mode
+ Default: y
+ Yanks visually select text. >
+ yankring_del_v_key
+< n - normal mode
+ Default: d
+ The visually select text is included in the YankRing and deleted. >
+ yankring_paste_n_bkey
+< n - normal mode
+ b - before
+ Default: P
+ The default Vim paste key will retrieve from the yankring. This
+ will paste the text BEFORE the current position.
+ There is a special check to see if the text in the default paste
+ register is the same as what is in the current position of the
+ yankring. If it is not, we assume the user used some other
+ mechanism to yank text (ie yt<character>). If this is the case
+ we paste the text in the default paste buffer. Using <C-P> the
+ text can be replaced with the current entry from the yankring.
+ Since there are many ways to do things in Vim, this provides
+ the best integration. >
+ yankring_paste_n_akey
+< n - normal mode
+ a - after
+ Default: p
+ The default Vim paste key will retrieve from the yankring. This
+ will paste the text AFTER the current position.
+ There is a special check to see if the text in the default paste
+ register is the same as what is in the current position of the
+ yankring. If it is not, we assume the user used some other
+ mechanism to yank text (ie yt<character>). If this is the case
+ we paste the text in the default paste buffer. Using <C-P> the
+ text can be replaced with the current entry from the yankring.
+ Since there are many ways to do things in Vim, this provides
+ the best integration. >
+ yankring_paste_v_key
+< n - normal mode
+ Default: p
+ This will replace the visually select text with the contents
+ from the yankring. See yankring_paste_n_akey for additional
+ details. >
+ yankring_replace_n_pkey
+< n - normal mode
+ Default: <C-P>
+ If you do not want to open the YankRing window to choose your
+ selection, then you can paste (as usual) then use a YankRing
+ mapping to cycle through items in the YankRing. This is especially
+ useful if you know you recently used the text you are looking for.
+ If you wish to cycle through the yankring, replacing the previously
+ pasted text with the previous yanked text you can repeatedly press
+ <C-P> (or whatever keystroke you choose to map it to). This map
+ moves backwards through the yankring, so you will retrieve your
+ most recent yank.
+
+ I prefer not to use <C-P> since I like using that key to cycle
+ through all the matches in the QuickFix window. You can add
+ something similar to this in your |.vimrc| to get similar
+ functionality.
+
+ On Windows use the ALT-< character to move through the YankRing.
+ To determine what character # these are go into insert mode
+ in a new buffer. Press CTRL-V then ALT and the < key.
+ Leave insert mode, move the cursor onto the character
+ and press ga. This will display the decimal, hex and octal
+ representation of the character. In this case it is 172. >
+ if has('win32')
+ let g:yankring_replace_n_pkey = '<Char-172>'
+ let g:yankring_replace_n_nkey = '<Char-174>'
+ " Instead map these keys to moving through items in the quickfix window.
+ nnoremap <C-P> :cp<cr>
+ nnoremap <C-N> :cn<cr>
+ endif
+< Other users have also stated that this will work: >
+ let g:yankring_replace_n_pkey = '<m-p>'
+ let g:yankring_replace_n_nkey = '<m-n>'
+ yankring_replace_n_nkey
+< n - normal mode
+ Default: <C-N>
+ If you do not want to open the YankRing window to choose your
+ selection, then you can paste (as usual) then use a YankRing
+ mapping to cycle through items in the YankRing. This is especially
+ useful if you know you recently used the text you are looking for.
+ If you wish to cycle through the yankring, replacing the previously
+ pasted text with the next yanked text you can repeatedly press
+ <C-N> (or whatever keystroke you choose to map it to). This map
+ moves forwards through the YankRing, so you will retrieve your
+ most recent yank.
+
+ I prefer not to use <C-N> since I like using that key to cycle
+ through all the matches in the QuickFix window. You can add
+ something similar to this in your |.vimrc| to get similar
+ functionality.
+
+ On Windows use the ALT-> character to move through the YankRing.
+ To determine what character # these are go into insert mode
+ in a new buffer. Press CTRL-V then ALT and the > key.
+ Leave insert mode, move the cursor onto the character
+ and press ga. This will display the decimal, hex and octal
+ representation of the character. In this case it is 174. >
+ if has('win32')
+ let g:yankring_replace_n_pkey = '<Char-172>'
+ let g:yankring_replace_n_nkey = '<Char-174>'
+ " Instead map these keys to moving through items in the quickfix window.
+ nnoremap <C-P> :cp<cr>
+ nnoremap <C-N> :cn<cr>
+ endif
+< Other users have also stated that this will work: >
+ let g:yankring_replace_n_pkey = '<m-p>'
+ let g:yankring_replace_n_nkey = '<m-n>'
+
+3.3 Customizing Maps *yankring-custom-maps*
+
+The YankRing plugin uses the yankring_n_keys global variable to create
+a number of defaults maps. The maps are of the form: >
+ nnoremap Y :<C-U>YRYankCount 'Y'<CR>
+<
+When capital Y is pressed, the YankRing will execute 'Y' and capture the
+output from Vim. But there are cases where you do not want the default
+behaviour of Vim, since you have customized some of these maps.
+
+In this case, I usually map Y to be |y$|, which makes it consistent with
+the |D| and |C| operators. The way yankring_n_keys works does not allow
+me to customize this behaviour. Since many people may like to customize
+the behaviour of these maps the YankRing will check to see if a
+function called YRRunAfterMaps() exists. If it does, it will call
+this function after it has created the maps. So in my case, I created
+the following function in my |vimrc|: >
+ function! YRRunAfterMaps()
+ nnoremap Y :<C-U>YRYankCount 'y$'<CR>
+ endfunction
+<
+You can do anything you need in this function. >
+ nnoremap Y :<C-U>YRYankCount 'y$'<CR>
+<
+This line remaps Y (which the user presses) to the YRYankCount command. The
+YRYankCount tells Vim to execute y$ instead.
+
+
+==============================================================================
+4. Using the YankRing Window: *yankring-window*
+
+This is a new feature as of the 2.0 release. The YankRing uses a
+separate split buffer to display the yankring. There are many buffer
+specific maps that allow you to operate over the various elements from
+within the yankring.
+
+To display the YankRing buffer you can issue the :YRShow command. For
+convience you can map a key, <F11>, to this command: >
+ :nnoremap <silent> <F11> :YRShow<CR>
+
+Status line~
+The first line in the YankRing window is the status line. >
+ AutoClose=1;ClipboardMonitor=1;Cmds:p,P,d,r,s,a,c,u,q,<enter>,<space>;Help=?
+<
+Help=?, pressing [?] will toggle the display of available commands the
+yankring window supports. Pressing [?] again will remove the additional
+items.
+
+AutoClose=1 indicates the window will close when an action is performed
+against elements within the yankring. If you wish to perform multiple
+yankring operations press [a] to toggle the auto close feature off. Use the
+commands below and when finished you can press [a] to toggle auto close on and
+press [q] to close the window. The Cmds displayed are simply reminders of
+the available keys.
+
+ClipboardMonitor=1 indicates the YankRing will monitor the clipboard (+)
+during Focus change events. If the clipboard has changed since the YankRing
+last checked, the contents are added to the YankRing. Pressing [c] allows
+you to quickly toggle this setting since it may not be useful at times.
+
+YankRing window key list~
+The following table lists the description of the keys that can be used
+in the YankRing window.
+
+ Key Description~
+ p Puts text after the cursor. In visual mode, all elements
+ selected will be pasted.
+ P Puts text before the cursor. In visual mode, all elements
+ selected will be pasted.
+ gp Just like "p", but leave the cursor just after the new text.
+ gP Just like "P", but leave the cursor just after the new text.
+ <CR> Just like "p".
+ <Enter> Just like "p".
+ <2-LeftMouse> Just like "p". Normal mode only.
+ d Removes the element from the yankring. In visual mode all
+ elements selected will be removed.
+ r Just like "p", but in visual mode if many lines are selected
+ it will paste these in reverse order.
+ s Prompts you for a regex to search the YankRing and display
+ only matching items.
+ a Toggles the g:yankring_window_auto_close setting.
+ u Updates the YankRing window.
+ q Closes the YankRing window.
+ <Space> Toggles the width of the vertical window by the
+ g:yankring_window_increment setting.
+ ? Toggles the display of the help.
+
+
+
+
+==============================================================================
+5. Commands: *yankring-commands*
+
+The predefined mappings call some specific commands with special parameters.
+If you are going to create additional maps, it is important you mirror
+the same parameters. Most of these commands have been made obsolete by
+the YankRing window, since it incorporates the functionality below, but
+through maps against a buffer, instead of commands. This makes it much easier
+to use.
+
+
+5.1 YRToggle *YRToggle*
+ Allows you to enable and disable the YankRing quickly. This
+ command will remove the default maps and recreate them.
+
+ Examples: >
+ :YRToggle " Toggles it
+ :YRToggle 1 " Enables it
+ :YRToggle 0 " Disables it
+<
+
+5.2 YRClear *YRClear*
+ Clears all elements from the yankring.
+ See also |YRClear-example|.
+
+
+5.3 YRShow *YRShow*
+ Similar to |:register|, will display all the entries in the yankring.
+ The element at the top will be the next element pasted from the
+ yankring.
+
+ Examples: >
+ :YRShow " Shows all entries in the yankring
+
+ --- YankRing ---
+ Elem Content
+ 1 five^@
+ 2 four^@
+ 3 three^@
+ 4 two^@
+ 5 one^@
+<
+
+5.5 YRGetElem *YRGetElem*
+ This command has two modes. If no parameters are provided, it
+ becomes interactive. It uses YRShow to display the list and
+ allows you to choose which element to paste. If a parameter
+ is supplied it will paste that element from the yankring. If the
+ number specified is outside of the YankRing an error is returned.
+ You may want to create a separate mapping for this call. >
+ nnoremap <silent> <Leader>yr :YRGetElem<CR>
+< See also |YRSearch|.
+
+ Examples:
+ Assume there are 10 elements in the YankRing and element 6 is
+ at the top of the ring. >
+ :YRGetElem " Interactive mode, you choose from a list
+ :YRGetElem 4 " Will paste element 5.
+ :YRGetElem 12 " Will paste element 6.
+ :YRGetElem 99 " Error, invalid choice is reported
+ :YRGetElem 0 " Error, invalid choice is reported
+
+
+5.6 YRGetMultiple *YRGetMultiple*
+ Will paste many elements from the YankRing in one command.
+ If the number specified is 1 or less, it is assumed you want
+ just the current element pasted. If the number specified is
+ greater than or equal to the number of elements in the yankring,
+ it is assumed you want all elements pasted. If a ! is included
+ as part of the command, paste the items in reverse order.
+ See the |yankring-tutorial| for more examples.
+
+ Examples:
+ Assume there are 10 elements in the YankRing. >
+ :YRGetMultiple 4 " Will paste elements 1,2,3,4
+ :YRGetMultiple! 4 " Will paste elements 4,3,2,1
+ :YRGetMultiple " Will paste element 1
+ :YRGetMultiple 12 " Will paste elements 1,2,...,10
+ :YRGetMultiple 99 " Will paste elements 1,2,...,10
+ :YRGetMultiple 0 " Will paste element 1
+
+
+5.7 YRPush *YRPush*
+ Allows the user to "push" additional entries into the yankring.
+ If you yanked text via a key mapping which does not use the
+ YankRing (or there is text on the clipboard) you can use this
+ command to add the text to the yankring.
+
+ Examples: >
+ :YRPush " Push the " register's contents
+ :YRPush '*' " Push the "* register's contents (clipboard)
+ :YRPush '+' " Push the "+ register's contents (clipboard)
+ :YRPush 'a' " Push the "a register's contents
+< See also |YRPush-example|.
+
+
+5.8 YRPop *YRPop*
+ Allows you to pop any elements from the yankring. If no parameters
+ are provided, the 1st element is removed from the yankring. The
+ command optionally takes a second parameter to specify how many
+ elements to pop. The default value is 1.
+
+ Examples: >
+ :YRPop " Removes the highest numbered element from the
+ yankring
+ :YRPop 3 " Removes the 3rd element from the yankring
+ :YRPop 3,5 " Removes 5 elements from the YankRing beginning
+ at element 3
+< See also |YRPop-example|.
+
+
+5.9 YRYankCount *YRYankCount*
+ This command has the most mappings created for it. If you are
+ in normal mode and you are not specifying a range, this command
+ will add the text to the yankring.
+
+ The goal of this command is to allow the YankRing to be integrated
+ as seamlessly as possible with Vim. So it supports counts and
+ registers. If you create a mapping to it, you must pass as a
+ parameter the action you want Vim to perform. You could do the
+ following: >
+ nnoremap \test :<C-U>YRYankCount 'dd'<CR>
+< This map is executed when you hit the '\test' keystrokes, but
+ it will actually delete the current line and add it to the
+ yankring.
+
+ The following are the default mappings: >
+ nnoremap yy :<C-U>YRYankCount 'yy'<CR>
+ nnoremap dd :<C-U>YRYankCount 'dd'<CR>
+ nnoremap yw :<C-U>YRYankCount 'yw'<CR>
+ nnoremap dw :<C-U>YRYankCount 'dw'<CR>
+ nnoremap ye :<C-U>YRYankCount 'ye'<CR>
+ nnoremap de :<C-U>YRYankCount 'de'<CR>
+ nnoremap yiw :<C-U>YRYankCount 'yiw'<CR>
+ nnoremap diw :<C-U>YRYankCount 'diw'<CR>
+ nnoremap Y :<C-U>YRYankCount 'Y'<CR>
+ nnoremap D :<C-U>YRYankCount 'D'<CR>
+ nnoremap y$ :<C-U>YRYankCount 'y$'<CR>
+ nnoremap d$ :<C-U>YRYankCount 'd$'<CR>
+ nnoremap yG :<C-U>YRYankCount 'yG'<CR>
+ nnoremap dG :<C-U>YRYankCount 'dG'<CR>
+<
+ Examples:
+ yy - Adds the current line to the yankring.
+ dd - Adds the current line to the YankRing and deletes it.
+ 5yw - Adds 5 words to the yankring.
+ "ade - Deletes the word, and puts it into both the yankring
+ and the "a register.
+ 10"zyy - Places 10 lines into both the YankRing and the "z
+ register.
+ See also |yankring-tutorial|.
+
+
+5.10 YRYankRange *YRYankRange*
+ This command by default is only called in visual mode. All
+ visual modes (|characterwise-visual|, |linewise-visual|,
+ |blockwise-visual|) are supported. Any visually selected text
+ is added to the yankring. You can also call this command
+ directly using a range.
+
+ Examples:
+ Visual mode
+ -----------
+ Press v (to enter visual mode), highlight want you want,
+ press y (to yank the selected area).
+ Repeat using V and Control-V.
+
+ Normal mode
+ ----------- >
+ :5,20YRYankRange " Will yank lines 5-20 into the yankring
+ :5,20YRDeleteRange " Will delete lines 5-20 and add them to
+ the yankring
+< See also |YRYankRange-example|.
+
+
+5.11 YRDeleteRange *YRDeleteRange*
+ This command is identical to YRYankRange, except the range is
+ also deleted.
+
+
+5.12 YRPaste *YRPaste*
+ This command will paste elements from the yankring. By default it has
+ been mapped to p and P to match Vim's native key strokes. The text
+ pasted is exactly what was yanked, including newline characters and
+ blockwise-visual mode behaviours. It supports counts and registers.
+
+ Examples:
+ p " Paste the current element from the YankRing after the cursor
+ P " Paste the current element from the YankRing before the cursor
+ 5p " Paste the current element from the YankRing after the cursor
+ 5 times
+ "ap " Ignore the YankRing and paste the contents of register "a
+ 5"ap " Ignore the YankRing and paste the contents of register "a
+ 5 times
+ See also |yankring-tutorial|.
+
+
+5.13 YRReplace *YRReplace*
+ The purpose of the YankRing is to gain access to previously yanked
+ (or deleted) elements. This command will replace the previously
+ paste with a different entry from the yankring.
+ By default, I choose <C-P> (P for previous) to replace the last paste
+ while moving backwards through the yankring. <C-N> (N for next)
+ replaces the last paste while moving forward through the yankring.
+
+ Examples:
+ See the |yankring-tutorial| for examples.
+
+
+5.14 YRMapsCreate *YRMapsCreate*
+ This public function is responsible for creating the maps which
+ enable the yankring. This function is called by the YRToggle
+ command.
+
+
+5.15 YRMapsDelete *YRMapsDelete*
+ This public function removes the YankRing maps and disables
+ the yankring. This function is called by the YRToggle command.
+
+
+5.16 YRSearch *YRSearch*
+ This command is similar to |YRGetElem|. The command takes
+ one parameter which is a regular expression. Similar to
+ YRGetElem, it will display all items in the YankRing that match
+ the regular expression. It is also interactive, and will
+ prompt you to enter which match you wish pasted.
+ See also |YRSearch-example|.
+
+
+==============================================================================
+6. Tutorial *yankring-tutorial*
+
+To understand how to use the yankring, the following example will
+demonstrate the various features. Assume you have created the following
+mapping: >
+ nnoremap <silent> <F11> :YRShow<CR>
+<
+ Assume we have this buffer: >
+ one
+ two
+ three
+ four
+ five
+< *YRShow-example*
+ Now yank (yy) each line separately starting at line 1.
+ Display the contents of the YankRing by executing the command
+ YRShow, or pressing <F11>. The contents of the YankRing is
+ displayed in a new buffer. The size, location and type of buffer
+ is configurable via various options. See section 3 for more details. >
+ :YRShow or F11
+ --- YankRing ---
+ Elem Content
+ 1 five^@
+ 2 four^@
+ 3 three^@
+ 4 two^@
+ 5 one^@
+< Since we yanked the text starting at line 1 and finishing at
+ line 5, the most current YankRing element is the last one, the
+ contents of line 5. "five^@" is displayed, the "^@" is a
+ newline character (since we issued a "yy").
+
+ *yankring-window-example*
+ At this point, you have two options. You can choose which element
+ from the YankRing you wish to paste and press <CR> or 'p' or 'P'
+ and a variety of other options, see |yankring-window|. After pressing
+ the key, the YankRing window will close (default behaviour). Pressing
+ '?' will display additional help for the commands that are active within
+ the YankRing window. Pressing '?' will toggle the help.
+
+ You do not need to interact with the YankRing using the YankRing window.
+ Using the window makes many tasks must easier, but for speed using some
+ of the other maps can be preferrable if you know what you have yanked /
+ deleted recently. It was designed to work with Vim in the usual manner.
+ You can press, 'p', to paste the last item in yanked or deleted.
+
+ Close the YankRing window by pressing 'q' or F11 (which toggles it).
+
+ *YRReplace-example*
+ Now, go to the end of the file and press 'p'. The resulting
+ buffer appears as: >
+ one
+ two
+ three
+ four
+ five
+ five
+<
+ Assume you did not want 'five", but a different entry from within the
+ yankring. <C-P> moves backwards through the yankring, it will replace
+ the previous pasted text with a different item from the yankring. This
+ allows you to quickly iterate through different elements. <C-P> is the
+ default mapping, this can be user defined. See the following options for
+ more details: >
+ yankring_replace_n_nkey, yankring_replace_n_pkey
+<
+ After pressing <C-P> the buffer results in: >
+ one
+ two
+ three
+ four
+ five
+ four
+< Now press 2<C-P>. This would be the same as pressing
+ <C-P> two times in a row. This results in: >
+ one
+ two
+ three
+ four
+ five
+ two
+< Now press <C-N> to move forwards through the yankring,
+ this results in: >
+ one
+ two
+ three
+ four
+ five
+ three
+< Display the contents of the yankring. >
+ :YRShow
+ --- YankRing ---
+ Elem Content
+ 1 five^@
+ 2 four^@
+ 3 three^@
+ 4 two^@
+ 5 one^@
+<
+ Now lets yank some text with a key stroke that has not been
+ mapped to the yankring. Place your cursor at the start of
+ line 4. Press 'ytr', yank-to-(to the character r), which yanks
+ the 'fou' letters (no newline character). Now press p. Here is
+ the result: >
+ one
+ two
+ three
+ ffouour
+ five
+ three
+< This is good, even though the keys 'ytr' has not been mapped
+ to YRYankCount, the YankRing still pasted the most recently
+ yanked text. Since the text did not have a newline character
+ the 'fou' was inserted after the 'f'.
+
+ Now replace that previous paste with the current element from
+ the YankRing by pressing <C-N>. This is the result: >
+ one
+ two
+ three
+ four
+ one
+ five
+ three
+< The #1 entry in the YankRing is still the line "five@". When
+ choosing the next entry, it wraps around to the last entry in
+ the yankring, element #5. The 'fou' was replaced with 'one^@'.
+ Since it had a newline character in it (when it was yanked) the
+ newline is included when it is pasted.
+
+ *YRPush-example*
+ Assume you need to paste text from the system clipboard, and this
+ is text you will need routinely. We can simulate this by running
+ this command (see |quote+|): >
+ :let @+ = "From the clipboard\n"
+ :echo @+
+
+< With the cursor at the start of the line with the word 'five', press 'p'.
+ We still have pasted the 'fou' which is in the default paste buffer. >
+ one
+ two
+ three
+ four
+ two
+ ffouive
+ three
+< We have the option of getting the text from the clipboard directly
+ with the following. >
+ First undo the previous change - u
+ Next - "+p
+< The line changes since we bypassed the yankring, and specified
+ which register to get the text from: >
+ four
+ five
+ From the clipboard
+ three
+< <C-P> replaces this with the #1 entry in the yankring: >
+ four
+ five
+ five
+ three
+< Now add the contents of the clipboard to the yankring: >
+ :YRPush '+'
+< Move the cursor to the last row 'three' and press 'p'. The result is: >
+ four
+ five
+ one
+ three
+ From the clipboard
+< YRPush '+' adds the value of the register '+' to the yankring, but it
+ also adds its contents to the default Vim paste buffer. So pressing
+ 'p' pasted this text. Adding a new value to the YankRing we have
+ repositioned it which you can see with: >
+ :YRShow or F11
+ --- YankRing ---
+ Elem Content
+ 1 From the clipboard^@
+ 2 five^@
+ 3 four^@
+ 4 three^@
+ 5 two^@
+ 6 one^@
+< *YRClear-example*
+ Now we will clear the yankring, and begin over again. Delete all lines
+ from the buffer and replace them with the original rows: >
+ one
+ two
+ three
+ four
+ five
+< Now run this command to clear the YankRing to start over: >
+ :YRClear
+<
+ Issue a 'yy' on each of the 5 lines. If you run the YRShow command you
+ should see the following: >
+ :YRShow or F11
+ --- YankRing ---
+ Elem Content
+ 1 five^@
+ 2 four^@
+ 3 three^@
+ 4 two^@
+ 5 one^@
+< *any-item-example*
+ If you need to quickly browse the YankRing to determine which element you
+ wish to paste you can simply press 'p' or <CR> or <Enter> on any element
+ displayed in the YankRing window. Press '?' for more detailed description
+ of the commands available.
+
+ Using the YankRing window can be much faster if you do not want to cycle
+ through the YankRing using <C-P> and <C-N> to find the element.
+
+ *multiple-items-example*
+ There are times when you need to move through a buffer capturing many
+ different lines (or snippets of code) and eventually want to switch
+ buffers and paste these elements. With some advance planning you can do
+ this without the YankRing by issuing commands of the form: >
+ "ayy
+ "Ayy
+< When specifying the register using UPPERCASE, Vim appends the yanked text
+ to register "a, instead of replacing it. Many times you forget the
+ advance planning (or didn't even know about this great feature) you can
+ use the YankRing window to do this easily. If this is the current
+ yankring: >
+ :YRShow or F11
+ --- YankRing ---
+ Elem Content
+ 1 five^@
+ 2 four^@
+ 3 three^@
+ 4 two^@
+ 5 one^@
+< The YankRing works in |visual-mode|. To demonstrate move the cursor in
+ the buffer to the line with 'two'. Press 'F11' to display the yankring
+ window. Move the cursor to element 2, press 'V' to enable
+ |linewise-visual| mode and then press 'j' twice. This should have
+ visually highlighted elements 2,3,4. Press 'p' to paste all the
+ highlighted elements: >
+ one
+ two
+ four
+ three
+ two
+ three
+ four
+ five
+< You can see here it has pasted four, three, two after the second line of
+ the buffer. Now press 'u' to undo our last change. Leave the cursor
+ on the second line 'two'. Press 'F11' to show the YankRing again.
+ Visually select the same lines, but this time press 'r' instead of 'p'.
+ 'r' is for reverse, so it will paste the following: >
+ one
+ two
+ two
+ three
+ four
+ three
+ four
+ five
+<
+ *YRGetMultiple-example*
+ The same behaviour listed above (by visually selecting items in the
+ YankRing window) can be achieved using the YRGetMultiple command.
+ Assume there are 10 elements in the YankRing. >
+ :YRGetMultiple 4 " Will paste elements 1,2,3,4
+ :YRGetMultiple! 4 " Will paste elements 4,3,2,1
+ :YRGetMultiple " Will paste element 1
+ :YRGetMultiple 12 " Will paste elements 1,2,...,10
+ :YRGetMultiple 99 " Will paste elements 1,2,...,10
+ :YRGetMultiple 0 " Will paste element 1
+<
+ *YRSearch-example*
+ The default size of the YankRing is 100 elements. It can be
+ tedious searching through the YankRing to find the element you
+ need. YRSearch is similar to YRShow except it will limit the
+ items displayed to only those items matching the regex provided. >
+ :YRShow
+ --- YankRing ---
+ Elem Content
+ 1 Three Mississippi
+ 2 Two Mississippi
+ 3 One Mississippi
+ 4 @", '\\/.*$^~[]' )
+ :YRSearch Mississippi
+ --- YankRing ---
+ Elem Content
+ 1 Three Mississippi
+ 2 Two Mississippi
+ 3 One Mississippi
+< Consider some items which require escaping the search string: >
+ :YRSearch @", '\\
+ --- YankRing ---
+ Elem Content
+ 1 @", '\\/.*$^~[]' )
+< Forward slashes and various other symbols require escapes, in this
+ case the slash was not escaped enough: >
+ :YRSearch @", '\\/
+ --- YankRing ---
+ Elem Content
+< There are enough escapes this time: >
+ :YRSearch @", '\\\\/
+ --- YankRing ---
+ Elem Content
+ 1 @", '\\/.*$^~[]' )
+< Period, star, dollar and so on require one slash: >
+ :YRSearch @", '\\\\/\.\*\$\^\~\[\]
+ --- YankRing ---
+ Elem Content
+ 1 @", '\\/.*$^~[]' )
+
+< *YRPop-example*
+ You can remove any element from the YankRing by pressing pressing 'd' from
+ within the YankRing window. Visual mode is also supported to remove more
+ than one element at a time. >
+ :YRShow
+ --- YankRing ---
+ Elem Content
+ 1 four^@
+ 2 three^@
+ 3 two^@
+ 4 one^@
+< Visually select elements 2,3. Press 'd', the result is: >
+ :YRShow
+ --- YankRing ---
+ Elem Content
+ 1 four^@
+ 2 one^@
+
+< *yankring-visual-example*
+ There are 3 visual modes and all are supported. Any visually selected
+ text is added to the yankring. You can try the various modes. Move
+ the cursor to inside the buffer (not the YankRing window).
+
+ |characterwise-visual|
+ Go to line 1, press 'v' and move using the cursor keys until you have
+ highlighted some text. Then press y to yank the visually selected
+ area. Pressing p with paste the yanked region.
+
+ |linewise-visual|
+ Go to line 2, press 'V' and move using the cursor keys until you have
+ highlighted some text. Notice the entire line is selected (including
+ the carriage returns). Then press y to yank the visually selected
+ area. Pressing p with paste the yanked region.
+
+ |blockwise-visual|
+ Go to line 3 column 4, press CTRL-V and move to the right using the
+ cursor keys until you have highlighted some text. Then press y to
+ yank the visually selected area. Pressing p with paste the yanked
+ region. Notice the pasted text retained its blockwise visual
+ characteristics.
+
+ *YRYankRange-example*
+ YRYankRange is called during visual modes, but it is also possible to
+ use this via the command line. >
+ :1,4YRYankRange
+ :3,$YRDeleteRange
+ :YRShow
+<
+ *global-example*
+ Using Vim's |:global| command can be very useful at times. The example
+ adds all rows (in a buffer) to the YankRing if they have a certain
+ phrase: >
+ :g/addme/YRYankCount 'yy'
+< This is the breakdown for the above command: >
+ :g - for each line in the buffer
+ /addme - check if the string "addme" is in the line
+ /YRYankCount 'yy' - Ask the YankRing to execute the 'yy' command
+
+
+==============================================================================
+7. History *yankring-history*
+
+ 10.0: January 31, 2010
+ NF: Change the buffer name to [YankRing] to resemble other
+ non-user buffers.
+ NF: Added g:yankring_min_element_length which can prevent
+ items from being added to the YankRing if they are too small.
+ For example, single character deletes (Vedran M).
+ BF: When shifting focus back to Vim, the YankRing may incorrectly
+ report: "YR:Failed to change to the yankring buffer,
+ please contact author".
+ BF: When entering Vim for the first time and hitting "p"
+ nothing was pasted (Mark Huiskes).
+ BF: When entering Vim for the first time and the
+ yankring_clipboard_monitor = 1, the clipboard entry
+ was not automatically added to the yankring.
+ BF: When overriding the default and setting
+ g:yankring_window_use_bottom = 0, the YankRing would
+ report the error (Sergey Khorev):
+ E21: Cannot make changes, 'modifiable' is off
+
+ 9.0: August 29, 2009:
+ BF: You cannot execute a macro with ":normal @a". It is still
+ not possible, but you can execute it with ":normal! @a"
+ (A S Budden).
+ BF: When g:yankring_persist = 0 the YankRing could go into
+ an infinite loop (A S Budden).
+ BF: When replaying a macro which used any of the zap
+ keys (f,F,t,T,/,?) you were prompted again for the
+ string to match on (Ovidiu C).
+ BF: When checking the clipboard for changes
+ (g:yankring_clipboard_monitor == 1) only add the item
+ if it is not already in the ring. Previously, the item
+ was moved to the top of the YankRing each time you flipped
+ focus.
+
+ 8.0: December 21, 2008:
+ NF: Changed the implementation of YRGetSearch() (David Liang).
+ BF: Under some unknown circumstances, the yankring can fail
+ to change to the correct buffer. Put in code to double
+ check and abort.
+ BF: Yanking and pasting a line which ends in a backslash
+ resulted in the backslash being replaced by "@@@".
+ BF: When repeating a command (".") which used any of the zap
+ keys (f,F,t,T,/,?) you were prompted again for the
+ string to match on (Vasilii Pascal).
+
+ 7.0: November 14, 2008:
+ NF: Added support for the / and ? motions so that y/search is
+ supported (Vasilii Pascal).
+ NF: When the YankRing window is displayed (or updated) an additional
+ check is made against the default register. If it has changed
+ since the YankRing recorded it, the value will be added to the
+ history.
+ NF: Added support for more motions h, j, k, l, H, M, L, ^, 0, -, +, _.
+ And a pile of g motions g_, g^, gm, g$, gk, gj, gg, ge, gE.
+ NF: The YankRing window will display a message it is operating
+ in a limited mode if not using Vim 7.2 or the correct patch
+ level.
+ BF: Correction to some internal code which could lead to an
+ endless loop (John Beckett).
+ BF: Opening and closing the YankRing window with "set report=0"
+ reported "1 line less" messages (Bill McCarthy).
+ BF: Changed the default value of g:yankring_paste_check_default_buffer
+ to check if the default paste buffer has changed when pressing
+ 'p'. For example, if a plugin has changed the default registers
+ it will be pasted rather than the top item from the YankRing.
+ BF: YRMapsDelete did not remove all the maps created by the YankRing.
+ BF: Under particular circumstances, yanking text with embedded @
+ characters were not properly stored and retrieved from the
+ YankRing (Andrew Long).
+ BF: Changed to use xmaps instead of vmaps so that the maps only work
+ in visual mode and not select mode (David Liang).
+
+ 6.1: October 31, 2008:
+ BF: If the g:yankring_history_dir contains spaces (default on
+ Windows) an error was reported. A simple work around was to
+ let g:yankring_history_dir = 'c:\Vim' or no spaces (Matt).
+
+ 6.0: October 25, 2008:
+ NF: The YankRing now maintains the history in a file. This means
+ if you are running multiple instances of Vim, they all see
+ the same yankring.
+ NF: The location and name of the file is configurable by the user.
+ NF: The g:yankring_separator is no longer used and has been removed.
+ NF: The g:yankring_max_element_length can be used to limit the size
+ of an element in the yankring.
+ NF: The g:yankring_share_between_instances can be used to indicate
+ whether each instance of Vim running on a machine should share
+ the history file or whether each should have their own
+ individual history file.
+ NF: The g:yankring_clipboard_monitor can be used to indicate
+ whether changes to the system clipboard should be added to the
+ YankRing (default is on).
+ NF: The YankRing window can toggle the clipboard monitor by pressing
+ 'c'. See the help in the window by pressing ?.
+ NF: Added some highlighting to the YankRing window (Marty Grenfell).
+
+ 5.0: September 21, 2008:
+ NF: The YankRing can recognize certain Vim commands which do not
+ change the contents of a buffer and not attempt to capture it.
+ NF: The global variables which allow you to customize the behaviour
+ are now space separated instead of comma separated. This
+ provides greater flexibility but will require you to modify
+ your vimrc (if you have customized it). (Andy Wokula)
+ BF: If using <C-O> from within insert mode, the YankRing inserted
+ characters into the buffer instead of capturing the changes,
+ this was fixed by Andy Wokula (Agathoklis Hatzimanikas).
+ BF: The YankRing did not properly account for all the different
+ forms of counts "5yy" worked but "y5y" did not (Edwin Shao).
+
+ 4.1: August 9, 2008:
+ NF: The YankRing now allows you to override which operators should
+ be ignored (yankring_ignore_operator). By default this is
+ set for the standard Vim operators which do not modify any
+ registers (Examples: = and gu) (Andy Wokula).
+ NF: The YankRing did not map v_x (Matt Tolton).
+ BF: The expression register (quote=) was not accounted for correctly
+ (Agathoklis Hatzimanikas).
+ BF: Using the v:operator variable must be escaped when used in
+ a regular expression.
+
+ 4.0: June 24, 2008:
+ NF: The YankRing by default now captures all |text-objects| and
+ all motions (|motion.txt|) which Vim supports. Version 3.0 only
+ supported a subset of the basic motion commands.
+ NF: Prior to this version only predefined maps triggered the
+ capture of data into the yankring. These maps only supported
+ yanks and deletes. The YankRing now also supports
+ operator-pending mode, which allows a greater range of operations
+ to be automatically captured and added to the yankring.
+ Operating pending mode functionality requires Vim 7.2 or Vim 7.1
+ with patch #205. If using Vim 7.1 you can determine this with:
+ echo has("patch205")
+ NF: Prior to this version only yanks and deletes were registered
+ in the yankring. Changes are now also captured into the
+ yankring.
+ NF: The YankRing will also capture the system cliboard when focus is
+ returned to the vim window. This is useful if you copy text
+ between applications.
+ NF: The YankRing window always opened bottom horizontal. Now it
+ can be opened top or bottom and horizontal or vertically.
+ This can be controlled via variables in your .vimrc.
+ BF: The YankRing has an option to persist between instances
+ of Vim by storing the values in global variables within
+ the viminfo. This has led to some unusual ordering of
+ items in the ring from conflicts between instances.
+ This option has been turn off by default.
+ BF: Their was an issue with yanking using y$.
+
+ 3.1: September 10, 2007:
+ NF: YRClear will now unlet all global variables it uses to store
+ the data if the persist storage is specified (the default).
+ Large values in the viminfo file could possibly affect other
+ applications.
+
+ 3.0: September 7, 2007:
+ NF: Converted the YankRing to use the new Vim7's List object which
+ means it is no longer compatible with Vim6.
+ NF: By default the YankRing will now maintain the yankring's items
+ persistently by default. It does this via the |viminfo| file.
+ This means the contents of the YankRing rely on the internal
+ variables of only 1 Vim instance.
+ BF: YRToggle was not unmapping 'gp' and 'gP'.
+ BF: YRSearch prompted the user for a regex even if one was provided
+ on the command line.
+ BF: If g:yankring_manage_numbered_reg is enabled, the "." operator
+ did not correctly repeat the previous action (Pedro DeRose).
+
+ 2.2: November 1, 2005:
+ NF: Added 'x' to the list of yankring_n_keys. This is very useful
+ in visual mode since it can delete a lot of characters.
+
+ 2.2: October 19, 2005:
+ BF: If you pressed '?' to toggle the display of the help in the
+ YankRing window, the window would close. This also applied to
+ 'a', which allowed you to toggle the autoclose feature.
+
+ 2.1: October 11, 2005:
+ NF: Added the ability for the YankRing to override Vim's numbered
+ registers. Instead of the numbered registers holding the last
+ yanked value, and the 9 previous deletes, they will now reflect
+ the top 10 items in the yankring. This allows you to reference
+ them directly with "5p.
+
+ 2.0: August 20, 2005:
+ NF: Much improved usability, the YankRing now has a "GUI" to service
+ the yankring. If YRShow or YRSearch is used, a split buffer is
+ opened which displays all the elements in the yankring. There
+ are a number of maps that allow you to interact with the
+ contents. The window can be positioned vertically or
+ horizontally as well as being sized all through options
+ specified in your vimrc.
+ NF: YRPop can now delete any items from the yankring, rather
+ that just from the top.
+ NF: YRSetTop has been removed, it is no longer required as the
+ internal representation of the YankRing has changed.
+ BF: If g:yankring_ignore_duplicate is set (which is the default)
+ you could get some unpredicable results when moving
+ backwards and forwards (<C-P> and <C-N>) through the
+ previous values.
+
+ 1.7: June 10, 2005:
+ BF: The expression register support added in version 1.6 used
+ getreg('='), which has the side effect of executing the
+ expression register. Depending on what was in the register
+ this could have unusual results. Changed to use histget().
+
+ 1.6: April 20, 2005:
+ NF: YRSearch is similar to YRGetElem. Given a regular expression
+ it will interactively display all the elements in the yankring
+ that match the regular expression. You can enter the number
+ of the element to paste it. If you have many elements within
+ the yankring, this can help you identify them more easily.
+ NF: Updated the default history size from 30 to 100, which is
+ partially the reason for the YRSearch command.
+ NF: By default it supports "gp" and "gP", in addition to "p" and "P".
+ NF: Added support for the expression register (:h quote=). Here
+ is an example of how it is used:
+ "="X"<CR>P
+
+ 1.5: March 30, 2005:
+ NF: The YankRing now respects the cpoptions setting, if 'y' is
+ included and you press '.', the previous yank command is executed
+ and added to the yankring. You can also add this behaviour by
+ setting this in your |vimrc|: >
+ let g:yankring_dot_repeat_yank = 1
+< NF: Duplicates will not be added to the YankRing by default. If
+ a duplicate is found, the element will be moved to the top
+ of the yankring. This can be controlled by setting this in
+ your |vimrc|: >
+ let g:yankring_ignore_duplicate = 0 (1 is default)
+< BF: Regression from version 1.4, the '.' operator may incorrectly
+ insert garbage.
+
+ 1.4: March 28, 2005:
+ NF: YRToggle has been updated. If you toggle the YankRing off
+ (disable) the maps it creates are removed. Calling YRToggle
+ again will recreate the maps. This truly disables the yankring,
+ where the previous version attempted to do this via code.
+ BF: Using the '.' operator was not correctly replaying operations
+ that did not move text in some way (g~t_) changed the case
+ of the text but a '.' did not replay it.
+ BF: When replacing previously pasted text the YankRing did not
+ respect what key was used to paste the text originally.
+ All replaced items were pasted using 'p', even if you had
+ originally pasted the text with 'P'.
+
+ 1.3: March 16, 2005:
+ BF: The '.' operator did not handle the <<, >> shift operator.
+ Pressing '.' would result in the previous YankRing operation
+ instead of repeating the shift.
+
+ 1.2: March 14, 2005:
+ NF: Added support for '.' operator to repeat the last change.
+ NF: Changed YRGetElem to show the contents of the yankring
+ and allow you to choose which element you want pasted.
+ It is only interactive if you do not provide a parameter.
+ NF: Added 'ygg,dgg' default maps by extending the yankring_n_keys
+ variable.
+
+ 1.1: March 09, 2005:
+ NF: Added support for the black hole register |quote_|.
+ NF: Custom Maps allows the user to more finely tune the yankring
+ maps to perform whatever action they require. This function,
+ YRRunAfterMaps(), is run automatically after the YankRing
+ creates it's default mappings. See |yankring-custom-maps|.
+ NF: Added some more default maps by extending the yankring_n_keys
+ variable. It now contains:
+ yy,dd,yw,dw,ye,de,yE,dE,yiw,diw,yaw,daw,y$,d$,Y,D,yG,dG
+ NOTE: You can easily extend these default mappings by
+ creating this global variable in your |vimrc|, you do not
+ have to wait for the plugin to be updated.
+ NF: Added support for Dr. Chips GetLatestVimScripts plugin.
+ BF: The check for g:yankring_n_keys was incorrect, so it was not
+ possible to override the default maps.
+
+ 1.0: March 08, 2005:
+ NF: Initial release.
+
+vim: ts=4 ft=help tw=78
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vim/bundle/yankring/plugin/yankring.vim Wed Jun 09 17:53:48 2010 -0400
@@ -0,0 +1,2461 @@
+" yankring.vim - Yank / Delete Ring for Vim
+" ---------------------------------------------------------------
+" Version: 10.0
+" Authors: David Fishburn <dfishburn.vim@gmail.com>
+" Last Modified: 2010 Jan 24
+" Script: http://www.vim.org/scripts/script.php?script_id=1234
+" Based On: Mocked up version by Yegappan Lakshmanan
+" http://groups.yahoo.com/group/vim/post?act=reply&messageNum=34406
+" License: GPL (Gnu Public License)
+" GetLatestVimScripts: 1234 1 :AutoInstall: yankring.vim
+
+if exists('loaded_yankring') || &cp
+ finish
+endif
+
+if v:version < 700
+ echomsg 'yankring: You need at least Vim 7.0'
+ finish
+endif
+
+let loaded_yankring = 100
+
+let s:yr_has_voperator = 0
+if v:version > 701 || ( v:version == 701 && has("patch205") )
+ let s:yr_has_voperator = 1
+endif
+
+if !exists('g:yankring_history_dir')
+ let g:yankring_history_dir = expand('$HOME')
+else
+ let g:yankring_history_dir = expand(g:yankring_history_dir)
+endif
+
+if !exists('g:yankring_history_file')
+ let g:yankring_history_file = 'yankring_history'
+endif
+
+" Allow the user to override the # of yanks/deletes recorded
+if !exists('g:yankring_max_history')
+ let g:yankring_max_history = 100
+elseif g:yankring_max_history < 0
+ let g:yankring_max_history = 100
+endif
+
+" Specify the minimum length of 1 entry
+if !exists('g:yankring_min_element_length')
+ let g:yankring_min_element_length = 1
+endif
+
+" Specify the maximum length of 1 entry (1MB default)
+if !exists('g:yankring_max_element_length')
+ let g:yankring_max_element_length = 1048576
+endif
+
+" Allow the user to specify if the plugin is enabled or not
+if !exists('g:yankring_enabled')
+ let g:yankring_enabled = 1
+endif
+
+" Specify max display length for each element for YRShow
+if !exists('g:yankring_max_display')
+ let g:yankring_max_display = 0
+endif
+
+" Check if yankring should persist between Vim instances
+if !exists('g:yankring_persist')
+ let g:yankring_persist = 1
+endif
+
+" Check if yankring share 1 file between all instances of Vim
+if !exists('g:yankring_share_between_instances')
+ let g:yankring_share_between_instances = 1
+endif
+
+" Specify whether the results of the ring should be displayed
+" in a separate buffer window instead of the use of echo
+if !exists('g:yankring_window_use_separate')
+ let g:yankring_window_use_separate = 1
+endif
+
+" Specifies whether the window is closed after an action
+" is performed
+if !exists('g:yankring_window_auto_close')
+ let g:yankring_window_auto_close = 1
+endif
+
+" When displaying the buffer, how many lines should it be
+if !exists('g:yankring_window_height')
+ let g:yankring_window_height = 8
+endif
+
+" When displaying the buffer, how many lines should it be
+if !exists('g:yankring_window_width')
+ let g:yankring_window_width = 30
+endif
+
+" When displaying the buffer, where it should be placed
+if !exists('g:yankring_window_use_horiz')
+ let g:yankring_window_use_horiz = 1
+endif
+
+" When displaying the buffer, where it should be placed
+if !exists('g:yankring_window_use_bottom')
+ let g:yankring_window_use_bottom = 1
+endif
+
+" When displaying the buffer, where it should be placed
+if !exists('g:yankring_window_use_right')
+ let g:yankring_window_use_right = 1
+endif
+
+" If the user presses <space>, toggle the width of the window
+if !exists('g:yankring_window_increment')
+ let g:yankring_window_increment = 50
+endif
+
+" Controls whether the . operator will repeat yank operations
+" The default is based on cpoptions: |cpo-y|
+" y A yank command can be redone with ".".
+if !exists('g:yankring_dot_repeat_yank')
+ let g:yankring_dot_repeat_yank = (&cpoptions=~'y'?1:0)
+endif
+
+" Only adds unique items to the yankring.
+" If the item already exists, that element is set as the
+" top of the yankring.
+if !exists('g:yankring_ignore_duplicate')
+ let g:yankring_ignore_duplicate = 1
+endif
+
+" Vim automatically manages the numbered registers:
+" 0 - last yanked text
+" 1-9 - last deleted items
+" If this option is turned on, the yankring will manage the
+" values in them.
+if !exists('g:yankring_manage_numbered_reg')
+ let g:yankring_manage_numbered_reg = 0
+endif
+
+" Allow the user to specify what characters to use for the mappings.
+if !exists('g:yankring_n_keys')
+ " 7.1.patch205 introduces the v:operator function which was essential
+ " to gain the omap support.
+ if s:yr_has_voperator == 1
+ " Use omaps for the rest of the functionality
+ let g:yankring_n_keys = 'Y D x X'
+ else
+ let g:yankring_n_keys = 'x yy dd yw dw ye de yE dE yiw diw yaw daw y$ d$ Y D yG dG ygg dgg'
+ endif
+endif
+
+" Allow the user to specify what operator pending motions to map
+if !exists('g:yankring_o_keys')
+ " o-motions and text objects, without zap-to-char motions
+ let g:yankring_o_keys = 'b B w W e E d h j k l H M L y G ^ 0 $ , ;'
+ let g:yankring_o_keys .= ' g_ g^ gm g$ gk gj gg ge gE - + _ '
+ let g:yankring_o_keys .= ' iw iW aw aW as is ap ip a] a[ i] i[ a) a( ab i) i( ib a> a< i> i< at it a} a{ aB i} i{ iB a" a'' a` i" i'' i`'
+endif
+
+if !exists('g:yankring_zap_keys')
+ let g:yankring_zap_keys = 'f F t T / ? @'
+endif
+
+" Allow the user to specify what operator pending motions to map
+if !exists('g:yankring_ignore_operator')
+ let g:yankring_ignore_operator = 'g~ gu gU ! = gq g? > < zf g@'
+endif
+let g:yankring_ignore_operator = ' '.g:yankring_ignore_operator.' '
+
+" Whether we should map the . operator
+if !exists('g:yankring_map_dot')
+ let g:yankring_map_dot = 1
+endif
+
+" Whether we sould map the "g" paste operators
+if !exists('g:yankring_paste_using_g')
+ let g:yankring_paste_using_g = 1
+endif
+
+if !exists('g:yankring_v_key')
+ let g:yankring_v_key = 'y'
+endif
+
+if !exists('g:yankring_del_v_key')
+ let g:yankring_del_v_key = 'd x'
+endif
+
+if !exists('g:yankring_paste_n_bkey')
+ let g:yankring_paste_n_bkey = 'P'
+endif
+
+if !exists('g:yankring_paste_n_akey')
+ let g:yankring_paste_n_akey = 'p'
+endif
+
+if !exists('g:yankring_paste_v_bkey')
+ let g:yankring_paste_v_bkey = 'P'
+endif
+
+if !exists('g:yankring_paste_v_akey')
+ let g:yankring_paste_v_akey = 'p'
+endif
+
+if !exists('g:yankring_paste_check_default_buffer')
+ let g:yankring_paste_check_default_buffer = 1
+endif
+
+if !exists('g:yankring_replace_n_pkey')
+ let g:yankring_replace_n_pkey = '<C-P>'
+endif
+
+if !exists('g:yankring_replace_n_nkey')
+ let g:yankring_replace_n_nkey = '<C-N>'
+endif
+
+if !exists('g:yankring_clipboard_monitor')
+ let g:yankring_clipboard_monitor = (has('clipboard')?1:0)
+endif
+
+if !exists('g:yankring_default_menu_mode')
+ let g:yankring_default_menu_mode = 3
+endif
+
+" Script variables for the yankring buffer
+let s:yr_buffer_name = '[YankRing]'
+let s:yr_buffer_last_winnr = -1
+let s:yr_buffer_last = -1
+let s:yr_buffer_id = -1
+let s:yr_search = ''
+let s:yr_remove_omap_dot = 0
+let s:yr_history_version = 'v2'
+let s:yr_history_v1_nl = '@@@'
+let s:yr_history_v1_nl_pat = '\%(\\\)\@<!@@@'
+let s:yr_history_v2_nl = "\2" " Use double quotes for a special character
+let s:yr_history_v2_nl_pat = "\2"
+let s:yr_history_last_upd = 0
+let s:yr_history_file_v1 =
+ \ g:yankring_history_dir.'/'.
+ \ g:yankring_history_file.
+ \ (g:yankring_share_between_instances==1?'':'_'.v:servername).
+ \ '.txt'
+let s:yr_history_file_v2 =
+ \ g:yankring_history_dir.'/'.
+ \ g:yankring_history_file.
+ \ (g:yankring_share_between_instances==1?'':'_'.v:servername).
+ \ '_v2.txt'
+
+
+" Vim window size is changed by the yankring plugin or not
+let s:yr_winsize_chgd = 0
+let s:yr_maps_created = 0
+let s:yr_maps_created_zap = 0
+
+" Enables or disables the yankring
+function! s:YRToggle(...)
+ " Default the current state to toggle
+ let new_state = ((g:yankring_enabled == 1) ? 0 : 1)
+
+ " Allow the user to specify if enabled
+ if a:0 > 0
+ let new_state = ((a:1 == 1) ? 1 : 0)
+ endif
+
+ " YRToggle accepts an integer value to specify the state
+ if new_state == g:yankring_enabled
+ return
+ elseif new_state == 1
+ call s:YRMapsCreate()
+ else
+ call s:YRMapsDelete()
+ endif
+endfunction
+
+
+" Enables or disables the yankring
+function! s:YRDisplayElem(disp_nbr, script_var)
+ if g:yankring_max_display == 0
+ if g:yankring_window_use_separate == 1
+ let max_display = 500
+ else
+ let max_display = g:yankring_window_width +
+ \ g:yankring_window_increment -
+ \ 12
+ endif
+ else
+ let max_display = g:yankring_max_display
+ endif
+
+ let elem = matchstr(a:script_var, '^.*\ze,.*$')
+ if s:yr_history_version == 'v1'
+ " v1
+ " let elem = substitute(elem, '\%(\\\)\@<!@@@', '\\n', 'g')
+ " v2
+ let elem = substitute(elem, s:yr_history_v1_nl_pat, '\\n', 'g')
+ let elem = substitute(elem, '\\@', '@', 'g')
+ else
+ let elem = substitute(elem, s:yr_history_v2_nl_pat, '\\n', 'g')
+ endif
+ let length = strlen(elem)
+ " Fancy trick to align them all regardless of how many
+ " digits the element # is
+ return a:disp_nbr.
+ \ strtrans(
+ \ strpart(" ",0,(6-strlen(a:disp_nbr+1))).
+ \ (
+ \ (length>max_display)?
+ \ (strpart(elem,0,max_display).
+ \ '...'):
+ \ elem
+ \ )
+ \ )
+
+ return ""
+endfunction
+
+
+" Enables or disables the yankring
+function! s:YRShow(...)
+ " If no parameter was provided assume the user wants to
+ " toggle the display.
+ let toggle = 1
+ if a:0 > 0
+ let toggle = matchstr(a:1, '\d\+')
+ endif
+
+ if toggle == 1
+ if bufwinnr(s:yr_buffer_id) > -1
+ " If the YankRing window is already open close it
+ exec bufwinnr(s:yr_buffer_id) . "wincmd w"
+ hide
+
+ " Switch back to the window which the YankRing
+ " window was opened from
+ if bufwinnr(s:yr_buffer_last) != -1
+ " If the buffer is visible, switch to it
+ exec s:yr_buffer_last_winnr . "wincmd w"
+ endif
+
+ return
+ endif
+ endif
+
+ " Reset the search string, since this is automatically called
+ " if the yankring window is open. A previous search must be
+ " cleared since we do not want to show new items. The user can
+ " always run the search again.
+ let s:yr_search = ""
+
+ " It is possible for registers to be changed outside of the
+ " maps of the YankRing. Perform this quick check when we
+ " show the contents (or when it is refreshed).
+ if g:yankring_paste_check_default_buffer == 1
+ let save_reg = 0
+ let register = ((&clipboard=='unnamed')?'+':'"')
+
+ if &clipboard == 'unnamed' && getreg('+') != s:yr_prev_clipboard
+ let save_reg = 1
+ endif
+ if register == '"' && getreg('"') != s:yr_prev_reg_unnamed
+ let save_reg = 1
+ endif
+
+ if save_reg == 1
+ " The user has performed a yank / delete operation
+ " outside of the yankring maps. Add this
+ " value to the yankring.
+ call YRRecord(register)
+ endif
+ endif
+
+ " List is shown in order of replacement
+ " assuming using previous yanks
+ let output = "--- YankRing ---\n"
+ let output = output . "Elem Content\n"
+
+ call s:YRHistoryRead()
+ let disp_item_nr = 1
+ for elem in s:yr_history_list
+ let output = output . s:YRDisplayElem(disp_item_nr, elem) . "\n"
+ let disp_item_nr += 1
+ endfor
+
+ if g:yankring_window_use_separate == 1
+ call s:YRWindowOpen(output)
+ else
+ echo output
+ endif
+endfunction
+
+
+" Used in omaps if a following character is required
+" like with motions (f,t)
+function! s:YRGetChar()
+ let msg = "YR:Enter character:"
+ echomsg msg
+ let c = getchar()
+ if c =~ '^\d\+$'
+ let c = nr2char(c)
+ echomsg msg.c
+ endif
+ return c
+endfunction
+
+
+" Used in omaps if a following string is required
+" like with motions (/,?)
+" function! s:YRGetSearch()
+" " let msg = "YR:Enter string:"
+" " echomsg msg
+" let str = input("YR:Enter string:")
+" " let str = ''
+" " while 1==1
+" " let c = getchar()
+" " if c =~ '^\d\+$'
+" " let c = nr2char(c)
+" " if c == "\<C-C>"
+" " return c
+" " endif
+" " if c == "\<CR>"
+" " break
+" " endif
+" " let str = str.c
+" " echomsg msg.str
+" " else
+" " break
+" " endif
+" " endwhile
+" return str
+" endfunction
+
+
+" Paste a certain item from the yankring
+" If no parameter is provided, this function becomes interactive. It will
+" display the list (using YRShow) and allow the user to choose an element.
+function! s:YRGetElem(...)
+ if s:yr_count == 0
+ call s:YRWarningMsg('YR: yankring is empty')
+ return -1
+ endif
+
+ let default_buffer = ((&clipboard=='unnamed')?'+':'"')
+
+ let direction = 'p'
+ if a:0 > 1
+ " If the user indicated to paste above or below
+ " let direction = ((a:2 ==# 'P') ? 'P' : 'p')
+ if a:2 =~ '\(p\|gp\|P\|gP\)'
+ let direction = a:2
+ endif
+ endif
+
+ " Check to see if a specific value has been provided
+ let elem = 0
+ if a:0 > 0
+ " Ensure we get only the numeric value (trim it)
+ let elem = matchstr(a:1, '\d\+')
+ let elem = elem - 1
+ else
+ " If no parameter was supplied display the yankring
+ " and prompt the user to enter the value they want pasted.
+ call s:YRShow(0)
+
+ if g:yankring_window_use_separate == 1
+ " The window buffer is used instead of command line
+ return
+ endif
+
+ let elem = input("Enter # to paste:")
+
+ " Ensure we get only the numeric value (trim it)
+ let elem = matchstr(elem, '\d\+')
+
+ if elem == ''
+ " They most likely pressed enter without entering a value
+ return
+ endif
+
+ let elem = elem - 1
+ endif
+
+ if elem < 0 || elem >= s:yr_count
+ call s:YRWarningMsg("YR: Invalid choice:".elem)
+ return -1
+ endif
+
+ let default_buffer = ((&clipboard=='unnamed')?'+':'"')
+ call setreg(default_buffer
+ \ , s:YRGetValElemNbr((elem), 'v')
+ \ , s:YRGetValElemNbr((elem), 't')
+ \ )
+ exec "normal! ".direction
+
+ " Set the previous action as a paste in case the user
+ " press . to repeat
+ call s:YRSetPrevOP('p', '', default_buffer, 'n')
+
+endfunction
+
+
+" Starting the top of the ring it will paste x items from it
+function! s:YRGetMultiple(reverse_order, ...)
+ if s:yr_count == 0
+ call s:YRWarningMsg('YR: yankring is empty')
+ return
+ endif
+
+ " If the user provided a range, exit after that many
+ " have been displayed
+ let max = 1
+ if a:0 == 1
+ " If no yank command has been supplied, assume it is
+ " a full line yank
+ let max = matchstr(a:1, '\d\+')
+ endif
+ if max > s:yr_count
+ " Default to all items if they specified a very high value
+ let max = s:yr_count
+ endif
+
+ " Base the increment on the sort order of the results
+ let increment = ((a:reverse_order==0)?(1):(-1))
+ if a:reverse_order == 0
+ let increment = 1
+ let elem = 0
+ else
+ let increment = -1
+ let elem = (max - 1)
+ endif
+
+ if a:0 > 1
+ let iter = 1
+ while iter <= a:0
+ let elem = (a:{iter} - 1)
+ call s:YRGetElem(elem)
+ let iter = iter + 1
+ endwhile
+ else
+ while max > 0
+ " Paste the first item, and move on to the next.
+ " digits the element # is
+ call s:YRGetElem(elem)
+ let elem = elem + increment
+ let max = max - 1
+ endwhile
+ endif
+endfunction
+
+
+" Given a regular expression, check each element within
+" the yankring, display only the matching items and prompt
+" the user for which item to paste
+function! s:YRSearch(...)
+ if s:yr_count == 0
+ call s:YRWarningMsg('YR: yankring is empty')
+ return
+ endif
+
+ let s:yr_search = ""
+ " If the user provided a range, exit after that many
+ " have been displayed
+ if a:0 == 0 || (a:0 == 1 && a:1 == "")
+ let s:yr_search = input('Enter [optional] regex:')
+ else
+ let s:yr_search = a:1
+ endif
+
+ if s:yr_search == ""
+ " Show the entire yankring
+ call s:YRShow(0)
+ return
+ endif
+
+ " List is shown in order of replacement
+ " assuming using previous yanks
+ let output = "--- YankRing ---\n"
+ let output = output . "Elem Content\n"
+ let valid_choices = []
+
+ let search_result = filter(copy(s:yr_history_list), "v:val =~ '".s:yr_search."'")
+
+ let disp_item_nr = 1
+
+ for elem in s:yr_history_list
+ if elem =~ s:yr_search
+ let output = output . s:YRDisplayElem(disp_item_nr, elem) . "\n"
+ call add(valid_choices, disp_item_nr.'')
+ endif
+ let disp_item_nr += 1
+ endfor
+
+ if len(valid_choices) == 0
+ let output = output . "Search for [".s:yr_search."] did not match any items "
+ endif
+
+ if g:yankring_window_use_separate == 1
+ call s:YRWindowOpen(output)
+ else
+ if len(valid_choices) > 0
+ echo output
+ let elem = input("Enter # to paste:")
+
+ " Ensure we get only the numeric value (trim it)
+ let elem = matchstr(elem, '\d\+')
+
+ if elem == ''
+ " They most likely pressed enter without entering a value
+ return
+ endif
+
+ if index(valid_choices, elem) != -1
+ exec 'YRGetElem ' . elem
+ else
+ " User did not choose one of the elements that were found
+ " Remove leading ,
+ call s:YRWarningMsg( "YR: Item[" . elem . "] not found, only valid choices are[" .
+ \ join(valid_choices, ',') .
+ \ "]"
+ \ )
+ return -1
+ endif
+
+ else
+ call s:YRWarningMsg( "YR: The pattern [" .
+ \ s:yr_search .
+ \ "] does not match any items in the yankring"
+ \ )
+ endif
+ endif
+
+endfunction
+
+
+" Resets the common script variables for managing the ring.
+function! s:YRReset()
+ let s:yr_history_list = []
+ " Update the history file
+ call s:YRHistorySave()
+endfunction
+
+
+" Clears the yankring by simply setting the # of items in it to 0.
+" There is no need physically unlet each variable.
+function! s:YRInit(...)
+ let s:yr_next_idx = 0
+ let s:yr_last_paste_idx = 0
+ let s:yr_count = 0
+ let s:yr_history_last_upd = 0
+ let s:yr_history_list = []
+ let s:yr_paste_dir = 'p'
+
+ " For the . op support
+ let s:yr_prev_op_code = ''
+ let s:yr_prev_op_mode = 'n'
+ let s:yr_prev_count = ''
+ let s:yr_prev_reg = ''
+ let s:yr_prev_reg_unnamed = ''
+ let s:yr_prev_reg_small = ''
+ let s:yr_prev_reg_insert = ''
+ let s:yr_prev_reg_expres = ''
+ let s:yr_prev_clipboard = ''
+ let s:yr_prev_vis_lstart = 0
+ let s:yr_prev_vis_lend = 0
+ let s:yr_prev_vis_cstart = 0
+ let s:yr_prev_vis_cend = 0
+ let s:yr_prev_changenr = 0
+ let s:yr_prev_repeating = 0
+
+ " This is used to determine if the visual selection should be
+ " reset prior to issuing the YRReplace
+ let s:yr_prev_vis_mode = 0
+
+ if a:0 == 0 && g:yankring_persist == 0
+ " The user wants the yankring reset each time Vim is started
+ call s:YRClear()
+ endif
+
+ call s:YRHistoryRead()
+endfunction
+
+
+" Clears the yankring by simply setting the # of items in it to 0.
+" There is no need physically unlet each variable.
+function! s:YRClear()
+ call s:YRReset()
+ call s:YRInit('DoNotClear')
+
+ " If the yankring window is open, refresh it
+ call s:YRWindowUpdate()
+endfunction
+
+
+" Determine which register the user wants to use
+" For example the 'a' register: "ayy
+function! s:YRRegister()
+ " v:register can be blank in some (unknown) cases
+ " so test for this condition and return the
+ " default register
+ let user_register = ((v:register=='')?('"'):(v:register))
+ if &clipboard == 'unnamed' && user_register == '"'
+ let user_register = '+'
+ endif
+ return user_register
+endfunction
+
+
+" Allows you to push a new item on the yankring. Useful if something
+" is in the clipboard and you want to add it to the yankring.
+" Or if you yank something that is not mapped.
+function! s:YRPush(...)
+ let user_register = s:YRRegister()
+
+ if a:0 > 0
+ " If no yank command has been supplied, assume it is
+ " a full line yank
+ let user_register = ((a:1 == '') ? user_register : a:1)
+ endif
+
+ " If we are pushing something on to the yankring, add it to
+ " the default buffer as well so the next item pasted will
+ " be the item pushed
+ let default_buffer = ((&clipboard=='unnamed')?'+':'"')
+ call setreg(default_buffer, getreg(user_register),
+ \ getregtype(user_register))
+
+ call s:YRSetPrevOP('', '', '', 'n')
+ call YRRecord(user_register)
+endfunction
+
+
+" Allows you to pop off any element from the yankring.
+" If no parameters are provided the first element is removed.
+" If a vcount is provided, that many elements are removed
+" from the top.
+function! s:YRPop(...)
+ if s:yr_count == 0
+ call s:YRWarningMsg('YR: yankring is empty')
+ return
+ endif
+
+ let v_count = 1
+ if a:0 > 1
+ let v_count = a:2
+ endif
+
+ " If the user provided a parameter, remove that element
+ " from the yankring.
+ " If no parameter was provided assume the first element.
+ let elem_index = 0
+ if a:0 > 0
+ " Get the element # from the parameter
+ let elem_index = matchstr(a:1, '\d\+')
+ let elem_index = elem_index - 1
+ endif
+
+ " If the user entered a count, then remove that many
+ " elements from the ring.
+ while v_count > 0
+ call s:YRMRUDel('s:yr_history_list', elem_index)
+ let v_count = v_count - 1
+ endwhile
+
+ " If the yankring window is open, refresh it
+ call s:YRWindowUpdate()
+endfunction
+
+
+" Adds this value to the yankring.
+function! YRRecord(...)
+
+ let register = '"'
+ if a:0 > 0
+ " If no yank command has been supplied, assume it is
+ " a full line yank
+ let register = ((a:1 == '') ? register : a:1)
+ endif
+
+ " v:register can be blank in some (unknown) cases
+ " if v:register == '' || v:register == '_'
+ if v:register == '_'
+ " Black hole register, ignore recording the operation
+ return ""
+ endif
+
+ let register = ((&clipboard=='unnamed')?'+':register)
+
+ " let s:yr_prev_changenr = changenr()
+ if register == '"'
+ " If the change has occurred via an omap, we must delay
+ " the capture of the default register until this event
+ " since register updates are not reflected until the
+ " omap function completes
+ let s:yr_prev_reg_unnamed = getreg('"')
+ let s:yr_prev_reg_small = getreg('-')
+ endif
+
+ " Add item to list
+ " This will also account for duplicates.
+ call s:YRMRUAdd( 's:yr_history_list'
+ \ , getreg(register)
+ \ , getregtype(register)
+ \ )
+
+ if register =~ '[+*]'
+ let s:yr_prev_clipboard = @+
+ endif
+
+ " If the yankring window is open, refresh it
+ call s:YRWindowUpdate()
+
+ " Manage the numbered registers
+ if g:yankring_manage_numbered_reg == 1
+ call s:YRSetNumberedReg()
+ endif
+
+ return ""
+endfunction
+
+
+" Adds this value to the yankring.
+function! YRRecord3()
+ let register = '"'
+
+ " v:register can be blank in some (unknown) cases
+ " if v:register == '' || v:register == '_'
+ if v:register == '_'
+ " Black hole register, ignore recording the operation
+ return ""
+ endif
+
+ let register = ((&clipboard=='unnamed')?'+':register)
+
+ if register == '"'
+ " If the change has occurred via an omap, we must delay
+ " the capture of the default register until this event
+ " since register updates are not reflected until the
+ " omap function completes
+ let s:yr_prev_reg_unnamed = getreg('"')
+ let s:yr_prev_reg_small = getreg('-')
+ endif
+
+ if s:yr_remove_omap_dot == 1
+ call s:YRMapsCreate('add_only_zap_keys')
+ endif
+
+ " Add item to list
+ " This will also account for duplicates.
+ call s:YRMRUAdd( 's:yr_history_list'
+ \ , getreg(register)
+ \ , getregtype(register)
+ \ )
+
+ if register =~ '[+*]'
+ let s:yr_prev_clipboard = @+
+ endif
+
+ " If the yankring window is open, refresh it
+ call s:YRWindowUpdate()
+
+ " Manage the numbered registers
+ if g:yankring_manage_numbered_reg == 1
+ call s:YRSetNumberedReg()
+ endif
+
+ return ""
+endfunction
+
+
+" Record the operation for the dot operator
+function! s:YRSetPrevOP(op_code, count, reg, mode)
+ let s:yr_prev_op_code = a:op_code
+ let s:yr_prev_op_mode = a:mode
+ let s:yr_prev_count = a:count
+ let s:yr_prev_changenr = changenr()
+ let s:yr_prev_reg = a:reg
+ let s:yr_prev_reg_unnamed = getreg('"')
+ let s:yr_prev_reg_small = getreg('-')
+ let s:yr_prev_reg_insert = getreg('.')
+ let s:yr_prev_vis_lstart = line("'<")
+ let s:yr_prev_vis_lend = line("'>")
+ let s:yr_prev_vis_cstart = col("'<")
+ let s:yr_prev_vis_cend = col("'>")
+ let s:yr_prev_reg_expres = histget('=', -1)
+
+ if a:mode == 'n'
+ " In normal mode, the change has already
+ " occurred, therefore we can mark the
+ " actual position of the change.
+ let s:yr_prev_chg_lstart = line("'[")
+ let s:yr_prev_chg_lend = line("']")
+ let s:yr_prev_chg_cstart = col("'[")
+ let s:yr_prev_chg_cend = col("']")
+ else
+ " If in operator pending mode, the change
+ " has not yet occurred. Therefore we cannot
+ " use the '[ and ]' markers. But we can
+ " store the current line position.
+ let s:yr_prev_chg_lstart = line(".")
+ let s:yr_prev_chg_lend = line(".")
+ let s:yr_prev_chg_cstart = col(".")
+ let s:yr_prev_chg_cend = col(".")
+ endif
+
+ " If storing the last change position (using '[, '])
+ " is not good enough, then another option is to:
+ " Use :redir on the :changes command
+ " and grab the last item. Store this value
+ " and compare it is YRDoRepeat.
+endfunction
+
+
+" Adds this value to the yankring.
+function! s:YRDoRepeat()
+ let dorepeat = 0
+
+ if s:yr_has_voperator == 1
+ " Let Vim handle the repeat, just capture the updates
+ " as usual.
+ return 0
+ endif
+
+ if s:yr_prev_op_code =~ '^c'
+ " You cannot repeat change operations, let Vim's
+ " standard mechanism handle these, or the user will
+ " be prompted again, instead of repeating the
+ " previous change.
+ return 0
+ endif
+
+ if g:yankring_manage_numbered_reg == 1
+ " When resetting the numbered register we are
+ " must ignore the comparision of the " register.
+ if s:yr_prev_reg_small == getreg('-') &&
+ \ s:yr_prev_reg_insert == getreg('.') &&
+ \ s:yr_prev_reg_expres == histget('=', -1) &&
+ \ s:yr_prev_vis_lstart == line("'<") &&
+ \ s:yr_prev_vis_lend == line("'>") &&
+ \ s:yr_prev_vis_cstart == col("'<") &&
+ \ s:yr_prev_vis_cend == col("'>") &&
+ \ s:yr_prev_chg_lstart == line("'[") &&
+ \ s:yr_prev_chg_lend == line("']") &&
+ \ s:yr_prev_chg_cstart == col("'[") &&
+ \ s:yr_prev_chg_cend == col("']")
+ let dorepeat = 1
+ endif
+ else
+ " Check the previously recorded value of the registers
+ " if they are the same, we need to reissue the previous
+ " yankring command.
+ " If any are different, the user performed a command
+ " command that did not involve the yankring, therefore
+ " we should just issue the standard "normal! ." to repeat it.
+ if s:yr_prev_reg_unnamed == getreg('"') &&
+ \ s:yr_prev_reg_small == getreg('-') &&
+ \ s:yr_prev_reg_insert == getreg('.') &&
+ \ s:yr_prev_reg_expres == histget('=', -1) &&
+ \ s:yr_prev_vis_lstart == line("'<") &&
+ \ s:yr_prev_vis_lend == line("'>") &&
+ \ s:yr_prev_vis_cstart == col("'<") &&
+ \ s:yr_prev_vis_cend == col("'>")
+ let dorepeat = 1
+ endif
+ if dorepeat == 1 && s:yr_prev_op_mode == 'n'
+ " Hmm, not sure why I was doing this now
+ " so I will remove it
+ " let dorepeat = 0
+ " if s:yr_prev_chg_lstart == line("'[") &&
+ " \ s:yr_prev_chg_lend == line("']") &&
+ " \ s:yr_prev_chg_cstart == col("'[") &&
+ " \ s:yr_prev_chg_cend == col("']")
+ " let dorepeat = 1
+ " endif
+ elseif dorepeat == 1 && s:yr_prev_op_mode == 'o'
+ " Hmm, not sure why I was doing this now
+ " so I will remove it
+ " let dorepeat = 0
+ " if s:yr_prev_chg_lstart == line("'[") &&
+ " \ s:yr_prev_chg_lend == line("']") &&
+ " \ s:yr_prev_chg_cstart == col("'[") &&
+ " \ s:yr_prev_chg_cend == col("']")
+ " let dorepeat = 1
+ " endif
+ endif
+ endif
+
+ " " If another change has happened that was not part of the
+ " " yankring we cannot replay it (from the yankring). Use
+ " " the standard ".".
+ " " If the previous op was a change, do not use the yankring
+ " " to repeat it.
+ " " changenr() is buffer specific, so anytime you move to
+ " " a different buffer you will definitely perform a
+ " " standard "."
+ " " Any previous op that was a change, must be replaced using "."
+ " " since we do not want the user prompted to enter text again.
+ " if s:yr_prev_changenr == changenr() && s:yr_prev_op_code !~ '^c'
+ " let dorepeat = 1
+ " endif
+
+ " If we are going to repeat check to see if the
+ " previous command was a yank operation. If so determine
+ " if yank operations are allowed to be repeated.
+ if dorepeat == 1 && s:yr_prev_op_code =~ '^y'
+ " This value be default is set based on cpoptions.
+ if g:yankring_dot_repeat_yank == 0
+ let dorepeat = 0
+ endif
+ endif
+ return dorepeat
+endfunction
+
+
+" Manages the Vim's numbered registers
+function! s:YRSetNumberedReg()
+
+ let i = 1
+
+ while i <= 10
+ if i > s:yr_count
+ break
+ endif
+
+ call setreg( (i-1)
+ \ , s:YRGetValElemNbr((i-1),'v')
+ \ , s:YRGetValElemNbr((i-1),'t')
+ \ )
+ let i += 1
+ endwhile
+endfunction
+
+
+" This internal function will add and subtract values from a starting
+" point and return the correct element number. It takes into account
+" the circular nature of the yankring.
+function! s:YRGetNextElem(start, iter)
+
+ let needed_elem = a:start + a:iter
+
+ " The yankring is a ring, so if an element is
+ " requested beyond the number of elements, we
+ " must wrap around the ring.
+ if needed_elem > s:yr_count
+ let needed_elem = needed_elem % s:yr_count
+ endif
+
+ if needed_elem == 0
+ " Can happen at the end or beginning of the ring
+ if a:iter == -1
+ " Wrap to the bottom of the ring
+ let needed_elem = s:yr_count
+ else
+ " Wrap to the top of the ring
+ let needed_elem = 1
+ endif
+ elseif needed_elem < 1
+ " As we step backwards through the ring we could ask for a negative
+ " value, this will wrap it around to the end
+ let needed_elem = s:yr_count
+ endif
+
+ return needed_elem
+
+endfunction
+
+
+" Lets Vim natively perform the operation and then stores what
+" was yanked (or deleted) into the yankring.
+" Supports this for example - 5"ayy
+"
+" This is a legacy function now since the release of Vim 7.2
+" and the use of omaps with YankRing 5.0 and above.
+" If Vim 7.1 has patch205, then the new omaps and the v:operator
+" variable is used instead.
+function! s:YRYankCount(...) range
+
+ let user_register = s:YRRegister()
+ let v_count = v:count
+
+ " Default yank command to the entire line
+ let op_code = 'yy'
+ if a:0 > 0
+ " If no yank command has been supplied, assume it is
+ " a full line yank
+ let op_code = ((a:1 == '') ? op_code : a:1)
+ endif
+
+ if op_code == '.'
+ if s:YRDoRepeat() == 1
+ if s:yr_prev_op_code != ''
+ let op_code = s:yr_prev_op_code
+ let v_count = s:yr_prev_count
+ let user_register = s:yr_prev_reg
+ endif
+ else
+ " Set this flag so that YRRecord will
+ " ignore repeats
+ let s:yr_prev_repeating = 1
+ exec "normal! ."
+ return
+ endif
+ else
+ let s:yr_prev_repeating = 0
+ endif
+
+ " Supports this for example - 5"ayy
+ " A delete operation will still place the items in the
+ " default registers as well as the named register
+ exec "normal! ".
+ \ ((v_count > 0)?(v_count):'').
+ \ (user_register=='"'?'':'"'.user_register).
+ \ op_code
+
+ if user_register == '_'
+ " Black hole register, ignore recording the operation
+ return
+ endif
+
+ call s:YRSetPrevOP(op_code, v_count, user_register, 'n')
+
+ call YRRecord(user_register)
+endfunction
+
+
+" Handles ranges. There are visual ranges and command line ranges.
+" Visual ranges are easy, since we pass through and let Vim deal
+" with those directly.
+" Command line ranges means we must yank the entire line, and not
+" just a portion of it.
+function! s:YRYankRange(do_delete_selection, ...) range
+
+ let user_register = s:YRRegister()
+ let default_buffer = ((&clipboard=='unnamed')?'+':'"')
+
+ " Default command mode to normal mode 'n'
+ let cmd_mode = 'n'
+ if a:0 > 0
+ " Change to visual mode, if command executed via
+ " a visual map
+ let cmd_mode = ((a:1 == 'v') ? 'v' : 'n')
+ endif
+
+ if cmd_mode == 'v'
+ " We are yanking either an entire line, or a range
+ exec "normal! gv".
+ \ (user_register==default_buffer?'':'"'.user_register).
+ \ 'y'
+ if a:do_delete_selection == 1
+ exec "normal! gv".
+ \ (user_register==default_buffer?'':'"'.user_register).
+ \ 'd'
+ endif
+ else
+ " In normal mode, always yank the complete line, since this
+ " command is for a range. YRYankCount is used for parts
+ " of a single line
+ if a:do_delete_selection == 1
+ exec a:firstline . ',' . a:lastline . 'delete '.user_register
+ else
+ exec a:firstline . ',' . a:lastline . 'yank ' . user_register
+ endif
+ endif
+
+ if user_register == '_'
+ " Black hole register, ignore
+ return
+ endif
+
+ call s:YRSetPrevOP('', '', user_register, 'n')
+ call YRRecord(user_register)
+endfunction
+
+
+" Paste from either the yankring or from a specified register
+" Optionally a count can be provided, so paste the same value 10 times
+function! s:YRPaste(replace_last_paste_selection, nextvalue, direction, ...)
+ " Disabling the yankring removes the default maps.
+ " But there are some maps the user can create on their own, and
+ " these would most likely call this function. So place an extra
+ " check and display a message.
+ if g:yankring_enabled == 0
+ call s:YRWarningMsg(
+ \ 'YR: The yankring is currently disabled, use YRToggle.'
+ \ )
+ return
+ endif
+
+
+ let user_register = s:YRRegister()
+ let default_buffer = ((&clipboard == 'unnamed')?'+':'"')
+ let v_count = v:count
+
+ " Default command mode to normal mode 'n'
+ let cmd_mode = 'n'
+ if a:0 > 0
+ " Change to visual mode, if command executed via
+ " a visual map
+ let cmd_mode = ((a:1 == 'v') ? 'v' : 'n')
+ endif
+
+ " User has decided to bypass the yankring and specify a specific
+ " register
+ if user_register != default_buffer
+ if a:replace_last_paste_selection == 1
+ call s:YRWarningMsg( 'YR: A register cannot be specified in replace mode' )
+ return
+ else
+ " Check for the expression register, in this special case
+ " we must copy it's evaluation into the default buffer and paste
+ if user_register == '='
+ " Save the default register since Vim will only
+ " allow the expression register to be pasted once
+ " and will revert back to the default buffer
+ let save_default_reg = @"
+ call setreg(default_buffer, eval(histget('=', -1)) )
+ else
+ let user_register = '"'.user_register
+ endif
+ exec "normal! ".
+ \ ((cmd_mode=='n') ? "" : "gv").
+ \ ((v_count > 0)?(v_count):'').
+ \ ((user_register=='=')?'':user_register).
+ \ a:direction
+ if user_register == '='
+ let @" = save_default_reg
+ endif
+ " In this case, we have bypassed the yankring
+ " If the user hits next or previous we want the
+ " next item pasted to be the top of the yankring.
+ let s:yr_last_paste_idx = 0
+ endif
+ let s:yr_paste_dir = a:direction
+ let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
+ return
+ endif
+
+ " Try to second guess the user to make these mappings less intrusive.
+ " If the user hits paste, compare the contents of the paste register
+ " to the current entry in the yankring. If they are different, lets
+ " assume the user wants the contents of the paste register.
+ " So if they pressed [yt ] (yank to space) and hit paste, the yankring
+ " would not have the word in it, so assume they want the word pasted.
+ if a:replace_last_paste_selection != 1
+ if s:yr_count > 0 || (default_buffer == '+' && len(@+) == 0)
+ " Only check the default buffer is the user wants us to.
+ " This was necessary prior to version 4.0 since we did not
+ " capture as many items as 4.0 and above does. (A. Budden)
+ if g:yankring_paste_check_default_buffer == 1 &&
+ \ getreg(default_buffer) != s:yr_prev_reg_unnamed
+ " The user has performed a yank / delete operation
+ " outside of the yankring maps. First, add this
+ " value to the yankring.
+ call YRRecord(default_buffer)
+ " Now, use the most recently yanked text, rather than the
+ " value from the yankring.
+ exec "normal! ".
+ \ ((cmd_mode=='n') ? "" : "gv").
+ \ ((v_count > 0)?(v_count):'').
+ \ a:direction
+ let s:yr_paste_dir = a:direction
+ let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
+
+ " In this case, we have bypassed the yankring
+ " If the user hits next or previous we want the
+ " next item pasted to be the top of the yankring.
+ let s:yr_last_paste_idx = 0
+ return
+ endif
+ else
+ exec "normal! ".
+ \ ((cmd_mode=='n') ? "" : "gv").
+ \ ((v_count > 0)?(v_count):'').
+ \ a:direction
+ let s:yr_paste_dir = a:direction
+ let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
+ return
+ endif
+ endif
+
+ if s:yr_count == 0 || (default_buffer == '+' && len(@+) == 0)
+ " Nothing to paste
+ return
+ endif
+
+ if a:replace_last_paste_selection == 1
+ " Replacing the previous put
+ let start = line("'[")
+ let end = line("']")
+
+ if start != line('.')
+ call s:YRWarningMsg( 'YR: You must paste text first, before you can replace' )
+ return
+ endif
+
+ if start == 0 || end == 0
+ return
+ endif
+
+ " If a count was provided (ie 5<C-P>), multiply the
+ " nextvalue accordingly and position the next paste index
+ let which_elem = a:nextvalue * ((v_count > 0)?(v_count):1) * -1
+ let s:yr_last_paste_idx = s:YRGetNextElem(
+ \ s:yr_last_paste_idx, which_elem
+ \ )
+
+ let save_reg = getreg(default_buffer)
+ let save_reg_type = getregtype(default_buffer)
+ call setreg( default_buffer
+ \ , s:YRGetValElemNbr((s:yr_last_paste_idx-1),'v')
+ \ , s:YRGetValElemNbr((s:yr_last_paste_idx-1),'t')
+ \ )
+
+ " First undo the previous paste
+ exec "normal! u"
+ " Check if the visual selection should be reselected
+ " Next paste the correct item from the ring
+ " This is done as separate statements since it appeared that if
+ " there was nothing to undo, the paste never happened.
+ exec "normal! ".
+ \ ((s:yr_prev_vis_mode==0) ? "" : "gv").
+ \ s:yr_paste_dir
+ call setreg(default_buffer, save_reg, save_reg_type)
+ call s:YRSetPrevOP('', '', '', 'n')
+ else
+ " User hit p or P
+ " Supports this for example - 5"ayy
+ " And restores the current register
+ let save_reg = getreg(default_buffer)
+ let save_reg_type = getregtype(default_buffer)
+ let s:yr_last_paste_idx = 1
+ call setreg(default_buffer
+ \ , s:YRGetValElemNbr(0,'v')
+ \ , s:YRGetValElemNbr(0,'t')
+ \ )
+ exec "normal! ".
+ \ ((cmd_mode=='n') ? "" : "gv").
+ \ (
+ \ ((v_count > 0)?(v_count):'').
+ \ a:direction
+ \ )
+ call setreg(default_buffer, save_reg, save_reg_type)
+ call s:YRSetPrevOP(
+ \ a:direction
+ \ , v_count
+ \ , default_buffer
+ \ , 'n'
+ \ )
+ let s:yr_paste_dir = a:direction
+ let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
+ endif
+
+endfunction
+
+
+" Handle any omaps
+function! YRMapsExpression(sid, motion, ...)
+ let cmds = a:motion
+ " echomsg "YRMapsE:".localtime()
+ " echomsg "YRMapsE 1:".cmds.":".v:operator.":".s:yr_maps_created_zap
+
+ if (a:motion =~ '\.' && s:yr_remove_omap_dot == 1) || a:motion =~ '@'
+ " If we are repeating a series of commands we must
+ " unmap the _zap_ keys so that the user is not
+ " prompted when a command is replayed.
+ " These maps must be re-instated in YRRecord3()
+ " after the action of the replay is completed.
+ call s:YRMapsDelete('remove_only_zap_keys')
+ endif
+
+ " Check if we are in operator-pending mode
+ if a:motion =~ '\('.substitute(g:yankring_zap_keys, ' ', '\\|', 'g').'\)'
+ if a:motion =~ '\(/\|?\)'
+ let zapto = (a:0==0 ? "" : input("YR:Enter string:"))
+ if zapto != ""
+ let zapto = zapto . "\<CR>"
+ else
+ let zapto = "\<C-C>"
+ endif
+ else
+ let zapto = (a:0==0 ? "" : s:YRGetChar())
+ endif
+
+ if zapto == "\<C-C>"
+ " Abort if the user hits Control C
+ call s:YRWarningMsg( "YR:Aborting command:".v:operator.a:motion )
+ return "\<C-C>"
+ endif
+
+ let cmds = cmds . zapto
+ endif
+
+ " There are a variety of commands which do not change the
+ " registers, so these operators should be ignored when
+ " determining which operations to record
+ " Simple example is '=' which simply formats the
+ " the selected text.
+ if ' \('.escape(join(split(g:yankring_ignore_operator), '\|'), '/.*~$^[]' ).'\) ' !~ escape(v:operator, '/.*~$^[]')
+ " Check if we are performing an action that will
+ " take us into insert mode
+ if '[cCsS]' !~ escape(v:operator, '/.*~$^[]') && a:motion !~ '@'
+ " if '[cCsS]' !~ escape(v:operator, '/.*~$^[]')
+ " If we have not entered insert mode, feed the call
+ " to record the current change when the function ends.
+ " This is necessary since omaps do not update registers
+ " until the function completes.
+ " The InsertLeave event will handle the motions
+ " that place us in insert mode and record the
+ " changes when insert mode ends.
+ let cmds .= a:sid. "yrrecord"
+ endif
+ endif
+
+ " echomsg "YRMapsE 5:".a:motion.":'".cmds."':".s:yr_maps_created_zap
+ return cmds
+
+endfunction
+
+
+" Handle any the @
+function! s:YRMapsMacro(bang, ...) range
+ " If we are repeating a series of commands we must
+ " unmap the _zap_ keys so that the user is not
+ " prompted when a command is replayed.
+ " These maps must be re-instated in YRRecord3()
+ " after the action of the replay is completed.
+ call s:YRMapsDelete('remove_only_zap_keys')
+
+ " let zapto = (a:0==0 ? "" : s:YRGetChar())
+ let zapto = s:YRGetChar()
+
+ if zapto == "\<C-C>"
+ " Abort if the user hits Control C
+ call s:YRWarningMsg( "YR:Aborting command:".v:operator.a:motion )
+ return ""
+ endif
+
+ let v_count = v:count
+ " If no count was specified it will have a value of 0
+ " so set it to at least 1
+ let v_count = ((v_count > 0)?(v_count):'')
+
+ let range = ''
+ if a:firstline != a:lastline
+ let rannge = a:firstline.','.a:lastline
+ endif
+
+ let cmd = range."normal! ".v_count.'@'.zapto
+ " DEBUG
+ " echomsg cmd
+ exec cmd
+
+ call s:YRMapsCreate('add_only_zap_keys')
+endfunction
+
+
+" Create the default maps
+function! s:YRMapsCreate(...)
+ " 7.1.patch205 introduces the v:operator function which was
+ " essential to gain the omap support.
+ if s:yr_has_voperator == 1
+ let s:yr_remove_omap_dot = 1
+ for key in split(g:yankring_zap_keys)
+ try
+ if key != '@'
+ exec 'omap <expr>' key 'YRMapsExpression("<SID>", "'. key. '", 1)'
+ endif
+ catch
+ endtry
+ endfor
+ endif
+
+ silent! nmap <expr> @ YRMapsExpression("<SID>", "@", "1")
+
+ let s:yr_maps_created_zap = 1
+
+ if a:0 > 0
+ " We have only removed the _zap_ keys temporarily
+ " so abandon further changes.
+ return
+ endif
+
+ " 7.1.patch205 introduces the v:operator function which was essential
+ " to gain the omap support.
+ if s:yr_has_voperator == 1
+ let s:yr_remove_omap_dot = 1
+ " Set option to add and remove _zap_ keys when
+ " repeating commands
+ let o_maps = split(g:yankring_o_keys)
+ " Loop through and prompt the user for all buffer connection parameters.
+ for key in o_maps
+ exec 'omap <expr>' key 'YRMapsExpression("<SID>", "'. escape(key,'\"'). '")'
+ endfor
+ endif
+
+ " Iterate through a space separated list of mappings and create
+ " calls to the YRYankCount function
+ let n_maps = split(g:yankring_n_keys)
+ " Loop through and prompt the user for all buffer connection parameters.
+ for key in n_maps
+ " exec 'nnoremap <silent>'.key." :<C-U>YRYankCount '".key."'<CR>"
+ " exec 'nnoremap <silent>'.key." :<C-U>YRYankCount '".key."'<CR>"
+ " Andy Wokula's suggestion
+ exec 'nmap' key key."<SID>yrrecord"
+ endfor
+
+ if g:yankring_map_dot == 1
+ if s:yr_has_voperator == 1
+ nmap <expr> . YRMapsExpression("<SID>", ".")
+ else
+ nnoremap <silent> . :<C-U>YRYankCount '.'<CR>
+ endif
+ endif
+
+ if g:yankring_v_key != ''
+ exec 'xnoremap <silent>'.g:yankring_v_key." :YRYankRange 'v'<CR>"
+ endif
+ if g:yankring_del_v_key != ''
+ for v_map in split(g:yankring_del_v_key)
+ if strlen(v_map) > 0
+ try
+ exec 'xnoremap <silent>'.v_map." :YRDeleteRange 'v'<CR>"
+ catch
+ endtry
+ endif
+ endfor
+ endif
+ if g:yankring_paste_n_bkey != ''
+ exec 'nnoremap <silent>'.g:yankring_paste_n_bkey." :<C-U>YRPaste 'P'<CR>"
+ if g:yankring_paste_using_g == 1
+ exec 'nnoremap <silent> g'.g:yankring_paste_n_bkey." :<C-U>YRPaste 'gP'<CR>"
+ endif
+ endif
+ if g:yankring_paste_n_akey != ''
+ exec 'nnoremap <silent>'.g:yankring_paste_n_akey." :<C-U>YRPaste 'p'<CR>"
+ if g:yankring_paste_using_g == 1
+ exec 'nnoremap <silent> g'.g:yankring_paste_n_akey." :<C-U>YRPaste 'gp'<CR>"
+ endif
+ endif
+ if g:yankring_paste_v_bkey != ''
+ exec 'xnoremap <silent>'.g:yankring_paste_v_bkey." :<C-U>YRPaste 'P', 'v'<CR>"
+ endif
+ if g:yankring_paste_v_akey != ''
+ exec 'xnoremap <silent>'.g:yankring_paste_v_akey." :<C-U>YRPaste 'p', 'v'<CR>"
+ endif
+ if g:yankring_replace_n_pkey != ''
+ exec 'nnoremap <silent>'.g:yankring_replace_n_pkey." :<C-U>YRReplace '-1', 'P'<CR>"
+ endif
+ if g:yankring_replace_n_nkey != ''
+ exec 'nnoremap <silent>'.g:yankring_replace_n_nkey." :<C-U>YRReplace '1', 'p'<CR>"
+ endif
+
+ let g:yankring_enabled = 1
+ let s:yr_maps_created = 1
+endfunction
+
+
+" Create the default maps
+function! s:YRMapsDelete(...)
+
+ let o_maps = split(g:yankring_zap_keys)
+ for key in o_maps
+ try
+ if key != '@'
+ silent! exec 'ounmap' key
+ endif
+ catch
+ endtry
+ endfor
+
+ let s:yr_maps_created_zap = 0
+
+ if a:0 > 0
+ " We have only removed the _zap_ keys temporarily
+ " so abandon further changes.
+ return
+ endif
+
+ " Iterate through a space separated list of mappings and create
+ " calls to an appropriate YankRing function
+ let n_maps = split(g:yankring_n_keys)
+ " Loop through and prompt the user for all buffer connection parameters.
+ for key in n_maps
+ try
+ silent! exec 'nunmap' key
+ catch
+ endtry
+ endfor
+
+ let o_maps = split(g:yankring_o_keys)
+ for key in o_maps
+ try
+ silent! exec 'ounmap' key
+ catch
+ endtry
+ endfor
+
+ if g:yankring_map_dot == 1
+ exec "nunmap ."
+ endif
+ if g:yankring_v_key != ''
+ exec 'vunmap '.g:yankring_v_key
+ endif
+ if g:yankring_del_v_key != ''
+ for v_map in split(g:yankring_del_v_key)
+ if strlen(v_map) > 0
+ try
+ exec 'vunmap '.v_map
+ catch
+ endtry
+ endif
+ endfor
+ endif
+ if g:yankring_paste_n_bkey != ''
+ exec 'nunmap '.g:yankring_paste_n_bkey
+ if g:yankring_paste_using_g == 1
+ exec 'nunmap g'.g:yankring_paste_n_bkey
+ endif
+ endif
+ if g:yankring_paste_n_akey != ''
+ exec 'nunmap '.g:yankring_paste_n_akey
+ if g:yankring_paste_using_g == 1
+ exec 'nunmap g'.g:yankring_paste_n_akey
+ endif
+ endif
+ if g:yankring_paste_v_bkey != ''
+ exec 'vunmap '.g:yankring_paste_v_bkey
+ endif
+ if g:yankring_paste_v_akey != ''
+ exec 'vunmap '.g:yankring_paste_v_akey
+ endif
+ if g:yankring_replace_n_pkey != ''
+ exec 'nunmap '.g:yankring_replace_n_pkey
+ endif
+ if g:yankring_replace_n_nkey != ''
+ exec 'nunmap '.g:yankring_replace_n_nkey
+ endif
+
+ let g:yankring_enabled = 0
+ let s:yr_maps_created = 0
+endfunction
+
+function! s:YRGetValElemNbr( position, type )
+
+ let needed_elem = a:position
+
+ " The List which contains the items in the yankring
+ " history is also ordered, most recent at the top
+ let elem = s:YRMRUGet('s:yr_history_list', needed_elem)
+
+ if elem >= 0
+ if a:type == 't'
+ return matchstr(elem, '^.*,\zs.*$')
+ else
+ let elem = matchstr(elem, '^.*\ze,.*$')
+ if s:yr_history_version == 'v1'
+ " Match three @@@ in a row as long as it is not
+ " preceeded by a @@@
+ " v1
+ let elem = substitute(elem, s:yr_history_v1_nl_pat, "\n", 'g')
+ let elem = substitute(elem, '\\@', '@', 'g')
+ else
+ let elem = substitute(elem, s:yr_history_v2_nl_pat, "\n", 'g')
+ endif
+ return elem
+ endif
+ else
+ return -1
+ endif
+
+ return ""
+endfunction
+
+function! s:YRMRUReset( mru_list )
+
+ let {a:mru_list} = []
+
+ return 1
+endfunction
+
+function! s:YRMRUSize( mru_list )
+ return len({a:mru_list})
+endfunction
+
+function! s:YRMRUElemFormat( element, element_type )
+ let elem = a:element
+ if g:yankring_max_element_length != 0
+ let elem = strpart(a:element, 0, g:yankring_max_element_length)
+ endif
+ if s:yr_history_version == 'v1'
+ let elem = escape(elem, '@')
+ let elem = substitute(elem, "\n", s:yr_history_v1_nl, 'g')
+ else
+ let elem = substitute(elem, "\n", s:yr_history_v2_nl, 'g')
+ endif
+ " Append the regtype to the end so we have it available
+ let elem = elem.",".a:element_type
+
+ return elem
+endfunction
+
+function! s:YRMRUHas( mru_list, find_str )
+ " This function will find a string and return the element #
+ let find_idx = index({a:mru_list}, a:find_str)
+
+ return find_idx
+endfunction
+
+function! s:YRMRUGet( mru_list, position )
+ " This function will return the value of the item at a:position
+ " Find the value of one element
+ let value = get({a:mru_list}, a:position, -2)
+
+ return value
+endfunction
+
+function! s:YRMRUAdd( mru_list, element, element_type )
+ " Only add new items if they do not already exist in the MRU.
+ " If the item is found, move it to the start of the MRU.
+ let found = -1
+ " let elem = a:element
+ " if g:yankring_max_element_length != 0
+ " let elem = strpart(a:element, 0, g:yankring_max_element_length)
+ " endif
+ " if s:yr_history_version == 'v1'
+ " let elem = escape(elem, '@')
+ " let elem = substitute(elem, "\n", s:yr_history_v1_nl, 'g')
+ " else
+ " let elem = substitute(elem, "\n", s:yr_history_v2_nl, 'g')
+ " endif
+ " " Append the regtype to the end so we have it available
+ " let elem = elem.",".a:element_type
+
+ if strlen(a:element) < g:yankring_min_element_length
+ return 1
+ endif
+
+ let elem = s:YRMRUElemFormat(a:element, a:element_type)
+
+ " Refresh the List
+ call s:YRHistoryRead()
+
+ let found = s:YRMRUHas(a:mru_list, elem)
+
+ " Special case for efficiency, if it is first item in the
+ " List, do nothing
+ if found != 0
+ if found != -1
+ " Remove found item since we will add it to the top
+ call remove({a:mru_list}, found)
+ endif
+ call insert({a:mru_list}, elem, 0)
+ call s:YRHistorySave()
+ endif
+
+ return 1
+endfunction
+
+function! s:YRMRUDel( mru_list, elem_nbr )
+
+ if a:elem_nbr >= 0 && a:elem_nbr < s:yr_count
+ call remove({a:mru_list}, a:elem_nbr)
+ call s:YRHistorySave()
+ endif
+
+ return 1
+endfunction
+
+function! s:YRHistoryRead()
+ let refresh_needed = 1
+ let yr_history_list = []
+ let yr_filename = s:yr_history_file_{s:yr_history_version}
+
+ if filereadable(yr_filename)
+ let last_upd = getftime(yr_filename)
+
+ if s:yr_history_last_upd != 0 && last_upd <= s:yr_history_last_upd
+ let refresh_needed = 0
+ endif
+
+ if refresh_needed == 1
+ let s:yr_history_list = readfile(yr_filename)
+ let s:yr_history_last_upd = last_upd
+ let s:yr_count = len(s:yr_history_list)
+ return
+ else
+ return
+ endif
+ else
+ if s:yr_history_version == 'v2'
+ " Check to see if an upgrade is required
+ " else, let the empty yr_history_list be returned.
+ if filereadable(s:yr_history_file_v1)
+ " Perform upgrade to v2 of the history file
+ call s:YRHistoryUpgrade('v1')
+ return
+ endif
+ endif
+ endif
+
+ let s:yr_history_list = yr_history_list
+ call s:YRHistorySave()
+
+endfunction
+
+function! s:YRHistorySave()
+ if len(s:yr_history_list) > g:yankring_max_history
+ " Remove items which exceed the max # specified
+ call remove(s:yr_history_list, g:yankring_max_history)
+ endif
+
+ let rc = writefile(s:yr_history_list, s:yr_history_file_{s:yr_history_version})
+
+ if rc == 0
+ let s:yr_history_last_upd = getftime(s:yr_history_file_{s:yr_history_version})
+ let s:yr_count = len(s:yr_history_list)
+ else
+ call s:YRErrorMsg(
+ \ 'YRHistorySave: Unable to save yankring history file: '.
+ \ s:yr_history_file_{s:yr_history_version}
+ \ )
+ endif
+endfunction
+
+function! s:YRHistoryUpgrade(version)
+ if a:version == 'v1'
+ if filereadable(s:yr_history_file_v1)
+ let v1_list = readfile(s:yr_history_file_v1)
+ let v2_list = []
+ for elem in v1_list
+ " Restore from version 1
+ let elem = substitute(elem, s:yr_history_v1_nl_pat, "\n", 'g')
+ let elem = substitute(elem, '\\@', '@', 'g')
+ " Encode to version 2
+ let elem = substitute(elem, "\n", s:yr_history_v2_nl, 'g')
+ call add(v2_list, elem)
+ endfor
+ let s:yr_history_list = v2_list
+ call s:YRHistorySave()
+ call s:YRWarningMsg(
+ \ "YR:History file:".
+ \ s:yr_history_file_v1.
+ \ ' has been upgraded.'
+ \ )
+ endif
+ endif
+endfunction
+
+" YRWindowUpdate
+" Checks if the yankring window is already open.
+" If it is, it will refresh it.
+function! s:YRWindowUpdate()
+ let orig_win_bufnr = bufwinnr('%')
+
+ " Switch to the yankring buffer
+ " only if it is already visible
+ if bufwinnr(s:yr_buffer_id) != -1
+ call s:YRShow(0)
+ " Switch back to the original buffer
+ exec orig_win_bufnr . "wincmd w"
+ endif
+endfunction
+
+" YRWindowStatus
+" Displays a brief command list and option settings.
+" It also will toggle the Help text.
+function! s:YRWindowStatus(show_help)
+ let full_help = 0
+ let orig_win_bufnr = bufwinnr('%')
+ let yr_win_bufnr = bufwinnr(s:yr_buffer_id)
+
+ if yr_win_bufnr == -1
+ " Do not update the window status since the
+ " yankring is not currently displayed.
+ return ""
+ endif
+ " Switch to the yankring buffer
+ if orig_win_bufnr != yr_win_bufnr
+ " If the buffer is visible, switch to it
+ exec yr_win_bufnr . "wincmd w"
+ endif
+
+ let msg = 'AutoClose='.g:yankring_window_auto_close.
+ \ ';ClipboardMonitor='.g:yankring_clipboard_monitor.
+ \ ';Cmds:<enter>,[g]p,[g]P,d,r,s,a,c,u,q,<space>;Help=?'.
+ \ (s:yr_search==""?"":';SearchRegEx='.s:yr_search)
+
+ if s:yr_has_voperator == 0
+ let msg = msg . "\nYankRing has limited functionality without Vim 7.2 or higher"
+ endif
+
+ " Toggle help by checking the first line of the buffer
+ if a:show_help == 1 && getline(1) !~ 'selection'
+ let full_help = 1
+ let msg =
+ \ '" <enter> : [p]aste selection'."\n".
+ \ '" double-click : [p]aste selection'."\n".
+ \ '" [g]p : [g][p]aste selection'."\n".
+ \ '" [g]P : [g][P]aste selection'."\n".
+ \ '" r : [p]aste selection in reverse order'."\n".
+ \ '" s : [s]earch the yankring for text'."\n".
+ \ '" u : [u]pdate display'."\n".
+ \ '" a : toggle [a]utoclose setting'."\n".
+ \ '" c : toggle [c]lipboard monitor setting'."\n".
+ \ '" q : [q]uit / close the yankring window'."\n".
+ \ '" ? : Remove help text'."\n".
+ \ '" <space> : toggles the width of the window'."\n".
+ \ '" Visual mode is supported for above commands'."\n".
+ \ msg
+ endif
+
+ let saveMod = &modifiable
+
+ " Go to the top of the buffer and remove any previous status
+ " Use the blackhole register so it does not affect the yankring
+ setlocal modifiable
+ exec 0
+ silent! exec 'norm! "_d/^---'."\n"
+ call histdel("search", -1)
+
+ silent! 0put =msg
+
+ " Erase it's contents to the blackhole
+ silent! exec '%g/^\s*$/delete _'
+ call histdel("search", -1)
+
+ call cursor(1,1)
+ if full_help == 0
+ call search('^\d', 'W')
+ endif
+
+ let &modifiable = saveMod
+
+ if orig_win_bufnr != s:yr_buffer_id
+ exec orig_win_bufnr . "wincmd w"
+ endif
+endfunction
+
+" YRWindowOpen
+" Display the Most Recently Used file list in a temporary window.
+function! s:YRWindowOpen(results)
+
+ " Setup the cpoptions properly for the maps to work
+ let old_cpoptions = &cpoptions
+ set cpoptions&vim
+ setlocal cpoptions-=a,A
+
+ " Save the current buffer number. The yankring will switch back to
+ " this buffer when an action is taken.
+ let s:yr_buffer_last = bufnr('%')
+ let s:yr_buffer_last_winnr = winnr()
+
+ if bufwinnr(s:yr_buffer_id) == -1
+ if g:yankring_window_use_horiz == 1
+ if g:yankring_window_use_bottom == 1
+ let location = 'botright'
+ else
+ let location = 'topleft'
+ " Creating the new window will offset all other
+ " window numbers. Account for that so we switch
+ " back to the correct window.
+ let s:yr_buffer_last_winnr = s:yr_buffer_last_winnr + 1
+ endif
+ let win_size = g:yankring_window_height
+ else
+ " Open a horizontally split window. Increase the window size, if
+ " needed, to accomodate the new window
+ if g:yankring_window_width &&
+ \ &columns < (80 + g:yankring_window_width)
+ " one extra column is needed to include the vertical split
+ let &columns = &columns + g:yankring_window_width + 1
+ let s:yr_winsize_chgd = 1
+ else
+ let s:yr_winsize_chgd = 0
+ endif
+
+ if g:yankring_window_use_right == 1
+ " Open the window at the rightmost place
+ let location = 'botright vertical'
+ else
+ " Open the window at the leftmost place
+ let location = 'topleft vertical'
+ " Creating the new window will offset all other
+ " window numbers. Account for that so we switch
+ " back to the correct window.
+ let s:yr_buffer_last_winnr = s:yr_buffer_last_winnr + 1
+ endif
+ let win_size = g:yankring_window_width
+ endif
+
+ " Special consideration was involved with these sequence
+ " of commands.
+ " First, split the current buffer.
+ " Second, edit a new file.
+ " Third record the buffer number.
+ " If a different sequence is followed when the yankring
+ " buffer is closed, Vim's alternate buffer is the yanking
+ " instead of the original buffer before the yankring
+ " was shown.
+ let cmd_mod = ''
+ if v:version >= 700
+ let cmd_mod = 'keepalt '
+ endif
+ exec 'silent! ' . cmd_mod . location . ' ' . win_size . 'split '
+
+ " Using :e and hide prevents the alternate buffer
+ " from being changed.
+ exec ":e " . escape(s:yr_buffer_name, ' ')
+ " Save buffer id
+ let s:yr_buffer_id = bufnr('%') + 0
+ else
+ " If the buffer is visible, switch to it
+ exec bufwinnr(s:yr_buffer_id) . "wincmd w"
+ endif
+
+ " Perform a double check to ensure we have entered the correct
+ " buffer since we don't want to do the %d_ in the wrong buffer!
+ if (bufnr('%') + 0) != s:yr_buffer_id
+ call s:YRWarningMsg(
+ \ "YR:Failed to change to the yankring buffer, please contact author id:".
+ \ s:yr_buffer_id.
+ \ ' last:'.s:yr_buffer_last
+ \ )
+ return -1
+ endif
+
+ " Mark the buffer as scratch
+ setlocal buftype=nofile
+ setlocal bufhidden=hide
+ setlocal noswapfile
+ setlocal nowrap
+ setlocal nonumber
+ setlocal nobuflisted
+ setlocal noreadonly
+ setlocal modifiable
+
+ " set up syntax highlighting
+ syn match yankringTitle #^--- YankRing ---$#hs=s+4,he=e-4
+ syn match yankringHeaders #^Elem Content$#
+ syn match yankringItemNumber #^\d\+#
+
+ syn match yankringKey #^AutoClose.*<enter>#hs=e-6
+ syn match yankringKey #^AutoClose.*\[g\]p#hs=e-3 contains=yankringKey
+ syn match yankringKey #^AutoClose.*\[p\]P#hs=e-3 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,d,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,r,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,s,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,a,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,c,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,u,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*,q,#hs=e-1,he=e-1 contains=yankringKey
+ syn match yankringKey #^AutoClose.*<space>#hs=e-6 contains=yankringKey
+ syn match yankringKey #^AutoClose.*?$#hs=e contains=yankringKey
+
+ syn match yankringKey #^".*:#hs=s+1,he=e-1
+ syn match yankringHelp #^".*$# contains=yankringKey
+
+ hi link yankringTitle directory
+ hi link yankringHeaders keyword
+ hi link yankringItemNumber constant
+ hi link yankringKey identifier
+ hi link yankringHelp string
+
+ " Clear all existing maps for this buffer
+ " We should do this for all maps, but I am not sure how to do
+ " this for this buffer/window only without affecting all the
+ " other buffers.
+ mapclear <buffer>
+ " Create a mapping to act upon the yankring
+ nnoremap <buffer> <silent> <2-LeftMouse> :call <SID>YRWindowActionN('p' ,'n')<CR>
+ nnoremap <buffer> <silent> <CR> :call <SID>YRWindowActionN('p' ,'n')<CR>
+ xnoremap <buffer> <silent> <CR> :call <SID>YRWindowAction ('p' ,'v')<CR>
+ nnoremap <buffer> <silent> p :call <SID>YRWindowActionN('p' ,'n')<CR>
+ xnoremap <buffer> <silent> p :call <SID>YRWindowAction ('p' ,'v')<CR>
+ nnoremap <buffer> <silent> P :call <SID>YRWindowActionN('P' ,'n')<CR>
+ xnoremap <buffer> <silent> P :call <SID>YRWindowAction ('P' ,'v')<CR>
+ nnoremap <buffer> <silent> gp :call <SID>YRWindowActionN('gp','n')<CR>
+ xnoremap <buffer> <silent> gp :call <SID>YRWindowAction ('gp','v')<CR>
+ nnoremap <buffer> <silent> gP :call <SID>YRWindowActionN('gP','n')<CR>
+ xnoremap <buffer> <silent> gP :call <SID>YRWindowAction ('gP','v')<CR>
+ nnoremap <buffer> <silent> d :call <SID>YRWindowActionN('d' ,'n')<CR>
+ xnoremap <buffer> <silent> d :call <SID>YRWindowAction ('d' ,'v')<CR>
+ xnoremap <buffer> <silent> r :call <SID>YRWindowAction ('r' ,'v')<CR>
+ nnoremap <buffer> <silent> s :call <SID>YRWindowAction ('s' ,'n')<CR>
+ nnoremap <buffer> <silent> a :call <SID>YRWindowAction ('a' ,'n')<CR>
+ nnoremap <buffer> <silent> c :call <SID>YRWindowAction ('c' ,'n')<CR>
+ nnoremap <buffer> <silent> ? :call <SID>YRWindowAction ('?' ,'n')<CR>
+ nnoremap <buffer> <silent> u :call <SID>YRWindowAction ('u' ,'n')<CR>
+ nnoremap <buffer> <silent> q :call <SID>YRWindowAction ('q' ,'n')<CR>
+ nnoremap <buffer> <silent> <space> \|:silent exec 'vertical resize '.
+ \ (
+ \ g:yankring_window_use_horiz!=1 && winwidth('.') > g:yankring_window_width
+ \ ?(g:yankring_window_width)
+ \ :(winwidth('.') + g:yankring_window_increment)
+ \ )<CR>
+
+ " Erase it's contents to the blackhole
+ silent! exec '%delete _'
+
+ " Display the status line / help
+ call s:YRWindowStatus(0)
+ exec 'normal! G'
+
+ " Display the contents of the yankring
+ silent! put =a:results
+
+ if getline('$') == ''
+ " Erase last blank line
+ silent! exec '$delete _'
+ endif
+
+ " Move the cursor to the first line with an element
+ exec 0
+ call search('^\d','W')
+
+ setlocal nomodifiable
+ "
+ " Restore the previous cpoptions settings
+ let &cpoptions = old_cpoptions
+
+endfunction
+
+function! s:YRWindowActionN(op, cmd_mode)
+ let v_count = v:count
+ " If no count was specified it will have a value of 0
+ " so set it to at least 1
+ let v_count = ((v_count > 0)?(v_count):1)
+
+ if v_count > 1
+ if !exists("b:yankring_show_range_error")
+ let b:yankring_show_range_error = v_count
+ else
+ let b:yankring_show_range_error = b:yankring_show_range_error - 1
+ endif
+
+ if b:yankring_show_range_error == 1
+ call s:YRWarningMsg("YR:Use visual mode if you need to specify a count")
+ unlet b:yankring_show_range_error
+ endif
+ return
+ endif
+
+ call s:YRWindowAction(a:op, a:cmd_mode)
+ let v_count = v_count - 1
+
+ if g:yankring_window_auto_close == 1 && v_count == 0 && a:op != 'd'
+ " If autoclose is set close the window unless
+ " you are removing items from the YankRing
+ exec 'bdelete '.s:yr_buffer_id
+ return ""
+ endif
+
+ return ""
+endfunction
+
+function! s:YRWindowAction(op, cmd_mode) range
+ let default_buffer = ((&clipboard=='unnamed')?'+':'"')
+ let opcode = a:op
+ let lines = []
+ let v_count = v:count
+ let cmd_mode = a:cmd_mode
+ let firstline = a:firstline
+ let lastline = a:lastline
+
+ if a:lastline < a:firstline
+ let firstline = a:lastline
+ let lastline = a:firstline
+ endif
+
+ if cmd_mode == 'n'
+ let v_count = 1
+ " If a count was provided (5p), we want to repeat the paste
+ " 5 times, but this also alters the a:firstline and a:lastline
+ " ranges, which while in normal mode we do not want
+ let lastline = firstline
+ endif
+ " If no count was specified it will have a value of 0
+ " so set it to at least 1
+ let v_count = ((v_count > 0)?(v_count):1)
+
+ if '[dr]' =~ opcode
+ " Reverse the order of the lines to act on
+ let begin = lastline
+ while begin >= firstline
+ call add(lines, getline(begin))
+ let begin = begin - 1
+ endwhile
+ else
+ " Process the selected items in order
+ let begin = firstline
+ while begin <= lastline
+ call add(lines, getline(begin))
+ let begin = begin + 1
+ endwhile
+ endif
+
+ if opcode ==# 'q'
+ " Close the yankring window
+ if s:yr_winsize_chgd == 1
+ " Adjust the Vim window width back to the width
+ " it was before we showed the yankring window
+ let &columns= &columns - (g:yankring_window_width)
+ endif
+
+ " Hide the YankRing window
+ hide
+
+ if bufwinnr(s:yr_buffer_last) != -1
+ " If the buffer is visible, switch to it
+ exec s:yr_buffer_last_winnr . "wincmd w"
+ endif
+
+ return
+ elseif opcode ==# 's'
+ " Switch back to the original buffer
+ exec s:yr_buffer_last_winnr . "wincmd w"
+
+ call s:YRSearch()
+ return
+ elseif opcode ==# 'u'
+ " Switch back to the original buffer
+ exec s:yr_buffer_last_winnr . "wincmd w"
+
+ call s:YRShow(0)
+ return
+ elseif opcode ==# 'a'
+ let l:curr_line = line(".")
+ " Toggle the auto close setting
+ let g:yankring_window_auto_close =
+ \ (g:yankring_window_auto_close == 1?0:1)
+ " Display the status line / help
+ call s:YRWindowStatus(0)
+ call cursor(l:curr_line,0)
+ return
+ elseif opcode ==# 'c'
+ let l:curr_line = line(".")
+ " Toggle the clipboard monitor setting
+ let g:yankring_clipboard_monitor =
+ \ (g:yankring_clipboard_monitor == 1?0:1)
+ " Display the status line / help
+ call s:YRWindowStatus(0)
+ call cursor(l:curr_line,0)
+ return
+ elseif opcode ==# '?'
+ " Display the status line / help
+ call s:YRWindowStatus(1)
+ return
+ endif
+
+ " Switch back to the original buffer
+ exec s:yr_buffer_last_winnr . "wincmd w"
+
+ " Intentional case insensitive comparision
+ if opcode =~? 'p'
+ let cmd = 'YRGetElem '
+ let parms = ", '".opcode."' "
+ elseif opcode ==? 'r'
+ let opcode = 'p'
+ let cmd = 'YRGetElem '
+ let parms = ", 'p' "
+ elseif opcode ==# 'd'
+ let cmd = 'YRPop '
+ let parms = ""
+ endif
+
+ " Only execute this code if we are operating on elements
+ " within the yankring
+ if '[auq?]' !~# opcode
+ while v_count > 0
+ " let iter = 0
+ " let index = 0
+ for line in lines
+ let elem = matchstr(line, '^\d\+')
+ if elem > 0
+ if elem > 0 && elem <= s:yr_count
+ " if iter > 0 && opcode =~# 'p'
+ if opcode =~# 'p'
+ " Move to the end of the last pasted item
+ " only if pasting after (not above)
+ " ']
+ endif
+ exec cmd . elem . parms
+ " let iter += 1
+ endif
+ endif
+ endfor
+ let v_count = v_count - 1
+ endwhile
+
+ if opcode ==# 'd'
+ call s:YRShow(0)
+ return ""
+ endif
+
+ if g:yankring_window_auto_close == 1 && cmd_mode == 'v'
+ exec 'bdelete '.s:yr_buffer_id
+ return ""
+ endif
+
+ endif
+
+ return ""
+
+endfunction
+
+function! s:YRWarningMsg(msg)
+ echohl WarningMsg
+ echomsg a:msg
+ echohl None
+endfunction
+
+function! s:YRErrorMsg(msg)
+ echohl ErrorMsg
+ echomsg a:msg
+ echohl None
+endfunction
+
+function! s:YRWinLeave()
+ " Track which window we are last in. We will use this information
+ " to determine where we need to paste any contents, or which
+ " buffer to return to.
+
+ if s:yr_buffer_id < 0
+ " The yankring window has never been activated
+ return
+ endif
+
+ if winbufnr(winnr()) == s:yr_buffer_id
+ " Ignore leaving the yankring window
+ return
+ endif
+
+ if bufwinnr(s:yr_buffer_id) != -1
+ " YankRing window is visible, so save off the previous buffer ids
+ let s:yr_buffer_last_winnr = winnr()
+ let s:yr_buffer_last = winbufnr(s:yr_buffer_last_winnr)
+ " else
+ " let s:yr_buffer_last_winnr = -1
+ " let s:yr_buffer_last = -1
+ endif
+endfunction
+
+function! s:YRFocusGained()
+ if g:yankring_clipboard_monitor == 1
+ " If the clipboard has changed record it inside the yankring
+ " echomsg "YRFocusGained[".len(@+)."][".@+.']['.s:yr_prev_clipboard.']'
+ if len(@+) > 0 && @+ != s:yr_prev_clipboard
+ let elem = s:YRMRUElemFormat(
+ \ getreg('+')
+ \ , getregtype('+')
+ \ )
+ let found = s:YRMRUHas('s:yr_history_list', elem)
+
+ " Only add the item to the "top" of the ring if it is
+ " not in the ring already.
+ if found == -1
+ call YRRecord("+")
+ " silent! call YRRecord("+")
+ endif
+ endif
+
+ " If the yankring window is open, refresh it
+ call s:YRWindowUpdate()
+ endif
+endfunction
+
+function! s:YRInsertLeave()
+ " The YankRing uses omaps to execute the prescribed motion
+ " and then appends to the motion a call to a YankRing
+ " function to record the contents of the changed register.
+ "
+ " We cannot append a function call to the end of a motion
+ " that results in Insert mode. For example, any command
+ " like 'cw' enters insert mode. Appending a function call
+ " after the w, simply writes out the call as if the user
+ " typed it.
+ "
+ " Using the InsertLeave event, allows us to capture the
+ " contents of any changed register after it completes.
+
+ call YRRecord(s:YRRegister())
+
+ " When performing a change (not a yank or delete)
+ " it is not possible to call <SID>yrrecord at the end
+ " of the command (or it's contents will be inserted
+ " into the buffer instead of executed).
+ " So, when using ".", we have to remove the _zap_
+ " keys and then re-add them back again after we
+ " record the updates.
+ if s:yr_remove_omap_dot == 1
+ call s:YRMapsCreate('add_only_zap_keys')
+ endif
+
+endfunction
+
+" Deleting autocommands first is a good idea especially if we want to reload
+" the script without restarting vim.
+" Call YRFocusGained to check if the clipboard has been updated
+augroup YankRing
+ autocmd!
+ autocmd VimEnter * :if has('clipboard') | call <SID>YRFocusGained() | endif
+ autocmd WinLeave * :call <SID>YRWinLeave()
+ autocmd FocusGained * :if has('clipboard') | call <SID>YRFocusGained() | endif
+ autocmd InsertLeave * :call <SID>YRInsertLeave()
+augroup END
+
+
+" copy register
+inoremap <script> <SID>YRGetChar <c-r>=YRGetChar()<CR>
+" inoremap <script> <SID>YRGetSearch <c-r>=YRGetSearch()<CR>
+nnoremap <silent> <SID>yrrecord :call YRRecord3()<cr>
+inoremap <silent> <SID>yrrecord <C-R>=YRRecord3()<cr>
+
+
+" Public commands
+command! YRClear call s:YRClear()
+command! -nargs=0 YRMapsCreate call s:YRMapsCreate()
+command! -nargs=0 YRMapsDelete call s:YRMapsDelete()
+command! -range -bang -nargs=? YRDeleteRange <line1>,<line2>call s:YRYankRange(<bang>1, <args>)
+command! -nargs=* YRGetElem call s:YRGetElem(<args>)
+command! -bang -nargs=? YRGetMultiple call s:YRGetMultiple(<bang>0, <args>)
+command! -count -register -nargs=* YRPaste call s:YRPaste(0,1,<args>)
+command! -nargs=? YRPop <line1>,<line2>call s:YRPop(<args>)
+command! -register -nargs=? YRPush call s:YRPush(<args>)
+command! -count -register -nargs=* YRReplace call s:YRPaste(1,<args>)
+command! -nargs=? YRSearch call s:YRSearch(<q-args>)
+command! -nargs=? YRShow call s:YRShow(<args>)
+command! -nargs=? YRToggle call s:YRToggle(<args>)
+command! -count -register -nargs=* YRYankCount call s:YRYankCount(<args>)
+command! -range -bang -nargs=? YRYankRange <line1>,<line2>call s:YRYankRange(<bang>0, <args>)
+" command! -range -bang -nargs=0 YRMapsMacro <line1>,<line2>call s:YRMapsMacro(<bang>0, <args>)
+
+" Menus
+if has("gui_running") && has("menu") && g:yankring_default_menu_mode != 0
+ if g:yankring_default_menu_mode == 1
+ let menuRoot = 'YankRing'
+ elseif g:yankring_default_menu_mode == 2
+ let menuRoot = '&YankRing'
+ else
+ let menuRoot = '&Plugin.&YankRing'
+ endif
+
+ exec 'noremenu <script> '.menuRoot.'.YankRing\ Window :YRShow<CR>'
+ exec 'noremenu <script> '.menuRoot.'.YankRing\ Search :YRSearch<CR>'
+ exec 'noremenu <script> '.menuRoot.'.Replace\ with\ Previous :YRReplace ''-1'', ''P''<CR>'
+ exec 'noremenu <script> '.menuRoot.'.Replace\ with\ Next :YRReplace ''1'', ''P''<CR>'
+ exec 'noremenu <script> '.menuRoot.'.Clear :YRClear<CR>'
+ exec 'noremenu <script> '.menuRoot.'.Toggle :YRToggle<CR>'
+endif
+
+if g:yankring_enabled == 1
+ " Create YankRing Maps
+ call s:YRMapsCreate()
+endif
+
+if exists('*YRRunAfterMaps')
+ " This will allow you to override the default maps if necessary
+ call YRRunAfterMaps()
+endif
+
+call s:YRInit()
+call s:YRHistoryRead()
+
+" vim:fdm=marker:nowrap:ts=4:expandtab: