2 " Authors: Srinath Avadhanula <srinath AT fastmail.fm>
3 " Benji Fisher <benji AT member.AMS.org>
5 " WWW: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/vim-latex/vimfiles/plugin/imaps.vim?only_with_tag=MAIN
7 " Description: insert mode template expander with cursor placement
8 " while preserving filetype indentation.
10 " $Id: imaps.vim,v 1.1.1.1 2006/03/31 18:55:13 arrow Exp $
15 " this script provides a way to generate insert mode mappings which do not
16 " suffer from some of the problem of mappings and abbreviations while allowing
17 " cursor placement after the expansion. It can alternatively be thought of as
18 " a template expander.
20 " Consider an example. If you do
24 " then a mapping is set up. However, there will be the following problems:
25 " 1. the 'ttimeout' option will generally limit how easily you can type the
26 " lhs. if you type the left hand side too slowly, then the mapping will not
28 " 2. if you mistype one of the letters of the lhs, then the mapping is
29 " deactivated as soon as you backspace to correct the mistake.
31 " If, in order to take care of the above problems, you do instead
35 " then the timeout problem is solved and so is the problem of mistyping.
36 " however, abbreviations are only expanded after typing a non-word character.
37 " which causes problems of cursor placement after the expansion and invariably
38 " spurious spaces are inserted.
41 " this script attempts to solve all these problems by providing an emulation
42 " of imaps wchich does not suffer from its attendant problems. Because maps
43 " are activated without having to press additional characters, therefore
44 " cursor placement is possible. furthermore, file-type specific indentation is
45 " preserved, because the rhs is expanded as if the rhs is typed in literally
48 " The script already provides some default mappings. each "mapping" is of the
51 " call IMAP (lhs, rhs, ft)
53 " Some characters in the RHS have special meaning which help in cursor
58 " call IMAP ("bit`", "\\begin{itemize}\<cr>\\item <++>\<cr>\\end{itemize}<++>", "tex")
60 " This effectively sets up the map for "bit`" whenever you edit a latex file.
61 " When you type in this sequence of letters, the following text is inserted:
67 " where * shows the cursor position. The cursor position after inserting the
68 " text is decided by the position of the first "place-holder". Place holders
69 " are special characters which decide cursor placement and movement. In the
70 " example above, the place holder characters are <+ and +>. After you have typed
71 " in the item, press <C-j> and you will be taken to the next set of <++>'s.
72 " Therefore by placing the <++> characters appropriately, you can minimize the
73 " use of movement keys.
75 " NOTE: Set g:Imap_UsePlaceHolders to 0 to disable placeholders altogether.
77 " g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd
78 " to something else if you want different place holder characters.
79 " Also, b:Imap_PlaceHolderStart and b:Imap_PlaceHolderEnd override the values
80 " of g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd respectively. This is
81 " useful for setting buffer specific place hoders.
84 " You can use the <C-r> command to insert dynamic elements such as dates.
85 " call IMAP ('date`', "\<c-r>=strftime('%b %d %Y')\<cr>", '')
87 " sets up the map for date` to insert the current date.
89 "--------------------------------------%<--------------------------------------
90 " Bonus: This script also provides a command Snip which puts tearoff strings,
91 " '----%<----' above and below the visually selected range of lines. The
92 " length of the string is chosen to be equal to the longest line in the range.
95 "--------------------------------------%<--------------------------------------
98 " ==============================================================================
99 " Script Options / Variables
100 " ==============================================================================
102 if !exists('g:Imap_StickyPlaceHolders')
103 let g:Imap_StickyPlaceHolders = 1
105 if !exists('g:Imap_DeleteEmptyPlaceHolders')
106 let g:Imap_DeleteEmptyPlaceHolders = 1
110 " s:LHS_{ft}_{char} will be generated automatically. It will look like
111 " s:LHS_tex_o = 'fo\|foo\|boo' and contain all mapped sequences ending in "o".
112 " s:Map_{ft}_{lhs} will be generated automatically. It will look like
113 " s:Map_c_foo = 'for(<++>; <++>; <++>)', the mapping for "foo".
117 " ==============================================================================
118 " functions for easy insert mode mappings.
119 " ==============================================================================
120 " IMAP: Adds a "fake" insert mode mapping. {{{
122 " IMAP('abc', 'def' ft)
123 " will mean that if the letters abc are pressed in insert mode, then
124 " they will be replaced by def. If ft != '', then the "mapping" will be
125 " specific to the files of type ft.
127 " Using IMAP has a few advantages over simply doing:
129 " 1. with imap, if you begin typing abc, the cursor will not advance and
130 " long as there is a possible completion, the letters a, b, c will be
131 " displayed on on top of the other. using this function avoids that.
132 " 2. with imap, if a backspace or arrow key is pressed before completing
133 " the word, then the mapping is lost. this function allows movement.
134 " (this ofcourse means that this function is only limited to
135 " left-hand-sides which do not have movement keys or unprintable
137 " It works by only mapping the last character of the left-hand side.
138 " when this character is typed in, then a reverse lookup is done and if
139 " the previous characters consititute the left hand side of the mapping,
140 " the previously typed characters and erased and the right hand side is
143 " IMAP: set up a filetype specific mapping.
145 " "maps" the lhs to rhs in files of type 'ft'. If supplied with 2
146 " additional arguments, then those are assumed to be the placeholder
147 " characters in rhs. If unspecified, then the placeholder characters
148 " are assumed to be '<+' and '+>' These placeholder characters in
149 " a:rhs are replaced with the users setting of
150 " [bg]:Imap_PlaceHolderStart and [bg]:Imap_PlaceHolderEnd settings.
152 function! IMAP(lhs, rhs, ft, ...)
154 " Find the place holders to save for IMAP_PutTextWithMovement() .
163 let hash = s:Hash(a:lhs)
164 let s:Map_{a:ft}_{hash} = a:rhs
165 let s:phs_{a:ft}_{hash} = phs
166 let s:phe_{a:ft}_{hash} = phe
168 " Add a:lhs to the list of left-hand sides that end with lastLHSChar:
169 let lastLHSChar = a:lhs[strlen(a:lhs)-1]
170 let hash = s:Hash(lastLHSChar)
171 if !exists("s:LHS_" . a:ft . "_" . hash)
172 let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\')
174 let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\') .'\|'. s:LHS_{a:ft}_{hash}
177 " map only the last character of the left-hand side.
178 if lastLHSChar == ' '
179 let lastLHSChar = '<space>'
181 exe 'inoremap <silent>'
182 \ escape(lastLHSChar, '|')
183 \ '<C-r>=<SID>LookupCharacter("' .
184 \ escape(lastLHSChar, '\|"') .
189 " IMAP_list: list the rhs and place holders corresponding to a:lhs {{{
191 " Added mainly for debugging purposes, but maybe worth keeping.
192 function! IMAP_list(lhs)
193 let char = a:lhs[strlen(a:lhs)-1]
194 let charHash = s:Hash(char)
195 if exists("s:LHS_" . &ft ."_". charHash) && a:lhs =~ s:LHS_{&ft}_{charHash}
197 elseif exists("s:LHS__" . charHash) && a:lhs =~ s:LHS__{charHash}
202 let hash = s:Hash(a:lhs)
203 return "rhs = " . s:Map_{ft}_{hash} . " place holders = " .
204 \ s:phs_{ft}_{hash} . " and " . s:phe_{ft}_{hash}
207 " LookupCharacter: inserts mapping corresponding to this character {{{
209 " This function extracts from s:LHS_{&ft}_{a:char} or s:LHS__{a:char}
210 " the longest lhs matching the current text. Then it replaces lhs with the
211 " corresponding rhs saved in s:Map_{ft}_{lhs} .
212 " The place-holder variables are passed to IMAP_PutTextWithMovement() .
213 function! s:LookupCharacter(char)
214 let charHash = s:Hash(a:char)
216 " The line so far, including the character that triggered this function:
217 let text = strpart(getline("."), 0, col(".")-1) . a:char
218 " Prefer a local map to a global one, even if the local map is shorter.
219 " Is this what we want? Do we care?
220 " Use '\V' (very no-magic) so that only '\' is special, and it was already
221 " escaped when building up s:LHS_{&ft}_{charHash} .
222 if exists("s:LHS_" . &ft . "_" . charHash)
223 \ && text =~ '\V\(' . s:LHS_{&ft}_{charHash} . '\)\$'
225 elseif exists("s:LHS__" . charHash)
226 \ && text =~ '\V\(' . s:LHS__{charHash} . '\)\$'
229 " If this is a character which could have been used to trigger an
230 " abbreviation, check if an abbreviation exists.
232 let lastword = matchstr(getline('.'), '\k\+$', '')
234 " An extremeley wierd way to get around the fact that vim
235 " doesn't have the equivalent of the :mapcheck() function for
238 exec "redir @a | silent! iab ".lastword." | redir END"
239 let abbreviationRHS = matchstr(@a."\n", "\n".'i\s\+'.lastword.'\+\s\+@\?\zs.*\ze'."\n")
241 if @a =~ "No abbreviation found" || abbreviationRHS == ""
247 let abbreviationRHS = escape(abbreviationRHS, '\<"')
248 exec 'let abbreviationRHS = "'.abbreviationRHS.'"'
250 let lhs = lastword.a:char
251 let rhs = abbreviationRHS.a:char
252 let phs = IMAP_GetPlaceHolderStart()
253 let phe = IMAP_GetPlaceHolderEnd()
261 " Find the longest left-hand side that matches the line so far.
262 " matchstr() returns the match that starts first. This automatically
263 " ensures that the longest LHS is used for the mapping.
264 if !exists('lhs') || !exists('rhs')
265 let lhs = matchstr(text, '\V\(' . s:LHS_{ft}_{charHash} . '\)\$')
266 let hash = s:Hash(lhs)
267 let rhs = s:Map_{ft}_{hash}
268 let phs = s:phs_{ft}_{hash}
269 let phe = s:phe_{ft}_{hash}
275 " enough back-spaces to erase the left-hand side; -1 for the last
277 let bs = substitute(strpart(lhs, 1), ".", "\<bs>", "g")
278 return bs . IMAP_PutTextWithMovement(rhs, phs, phe)
282 " IMAP_PutTextWithMovement: returns the string with movement appended {{{
284 " If a:str contains "placeholders", then appends movement commands to
285 " str in a way that the user moves to the first placeholder and enters
286 " insert or select mode. If supplied with 2 additional arguments, then
287 " they are assumed to be the placeholder specs. Otherwise, they are
288 " assumed to be '<+' and '+>'. These placeholder chars are replaced
289 " with the users settings of [bg]:Imap_PlaceHolderStart and
290 " [bg]:Imap_PlaceHolderEnd.
291 function! IMAP_PutTextWithMovement(str, ...)
293 " The placeholders used in the particular input string. These can be
294 " different from what the user wants to use.
299 let phs = escape(a:1, '\')
300 let phe = escape(a:2, '\')
305 " The user's placeholder settings.
306 let phsUser = IMAP_GetPlaceHolderStart()
307 let pheUser = IMAP_GetPlaceHolderEnd()
309 " Problem: depending on the setting of the 'encoding' option, a character
310 " such as "\xab" may not match itself. We try to get around this by
311 " changing the encoding of all our strings. At the end, we have to
313 let phsEnc = s:Iconv(phs, "encode")
314 let pheEnc = s:Iconv(phe, "encode")
315 let phsUserEnc = s:Iconv(phsUser, "encode")
316 let pheUserEnc = s:Iconv(pheUser, "encode")
317 let textEnc = s:Iconv(text, "encode")
324 let pattern = '\V\(\.\{-}\)' .phs. '\(\.\{-}\)' .phe. '\(\.\*\)'
325 " If there are no placeholders, just return the text.
326 if textEnc !~ pattern
327 call IMAP_Debug('Not getting '.phs.' and '.phe.' in '.textEnc, 'imap')
330 " Break text up into "initial <+template+> final"; any piece may be empty.
331 let initialEnc = substitute(textEnc, pattern, '\1', '')
332 let templateEnc = substitute(textEnc, pattern, '\2', '')
333 let finalEnc = substitute(textEnc, pattern, '\3', '')
335 " If the user does not want to use placeholders, then remove all but the
337 " Otherwise, replace all occurences of the placeholders here with the
338 " user's choice of placeholder settings.
339 if exists('g:Imap_UsePlaceHolders') && !g:Imap_UsePlaceHolders
340 let finalEnc = substitute(finalEnc, '\V'.phs.'\.\{-}'.phe, '', 'g')
342 let finalEnc = substitute(finalEnc, '\V'.phs.'\(\.\{-}\)'.phe,
343 \ phsUserEnc.'\1'.pheUserEnc, 'g')
346 " The substitutions are done, so convert back, if necessary.
348 let initial = s:Iconv(initialEnc, "decode")
349 let template = s:Iconv(templateEnc, "decode")
350 let final = s:Iconv(finalEnc, "decode")
352 let initial = initialEnc
353 let template = templateEnc
357 " Build up the text to insert:
358 " 1. the initial text plus an extra character;
359 " 2. go to Normal mode with <C-\><C-N>, so it works even if 'insertmode'
360 " is set, and mark the position;
361 " 3. replace the extra character with tamplate and final;
362 " 4. back to Normal mode and restore the cursor position;
363 " 5. call IMAP_Jumpfunc().
364 let template = phsUser . template . pheUser
365 " Old trick: insert and delete a character to get the same behavior at
366 " start, middle, or end of line and on empty lines.
367 let text = initial . "X\<C-\>\<C-N>:call IMAP_Mark('set')\<CR>\"_s"
368 let text = text . template . final
369 let text = text . "\<C-\>\<C-N>:call IMAP_Mark('go')\<CR>"
370 let text = text . "i\<C-r>=IMAP_Jumpfunc('', 1)\<CR>"
376 " IMAP_Jumpfunc: takes user to next <+place-holder+> {{{
377 " Author: Luc Hermitte
379 " direction: flag for the search() function. If set to '', search forwards,
380 " if 'b', then search backwards. See the {flags} argument of the
381 " |search()| function for valid values.
382 " inclusive: In vim, the search() function is 'exclusive', i.e we always goto
383 " next cursor match even if there is a match starting from the
384 " current cursor position. Setting this argument to 1 makes
385 " IMAP_Jumpfunc() also respect a match at the current cursor
386 " position. 'inclusive'ness is necessary for IMAP() because a
387 " placeholder string can occur at the very beginning of a map which
389 " We use a non-zero value only in special conditions. Most mappings
390 " should use a zero value.
391 function! IMAP_Jumpfunc(direction, inclusive)
393 " The user's placeholder settings.
394 let phsUser = IMAP_GetPlaceHolderStart()
395 let pheUser = IMAP_GetPlaceHolderEnd()
397 let searchString = ''
398 " If this is not an inclusive search or if it is inclusive, but the
399 " current cursor position does not contain a placeholder character, then
400 " search for the placeholder characters.
401 if !a:inclusive || strpart(getline('.'), col('.')-1) !~ '\V\^'.phsUser
402 let searchString = '\V'.phsUser.'\_.\{-}'.pheUser
405 " If we didn't find any placeholders return quietly.
406 if searchString != '' && !search(searchString, a:direction)
410 " Open any closed folds and make this part of the text visible.
413 " Calculate if we have an empty placeholder or if it contains some
416 \ matchstr(strpart(getline('.'), col('.')-1),
417 \ '\V\^'.phsUser.'\zs\.\{-}\ze\('.pheUser.'\|\$\)')
418 let placeHolderEmpty = !strlen(template)
420 " If we are selecting in exclusive mode, then we need to move one step to
423 if &selection == 'exclusive'
427 " Select till the end placeholder character.
428 let movement = "\<C-o>v/\\V".pheUser."/e\<CR>".extramove
430 " First remember what the search pattern was. s:RemoveLastHistoryItem will
431 " reset @/ to this pattern so we do not create new highlighting.
432 let g:Tex_LastSearchPattern = @/
434 " Now either goto insert mode or select mode.
435 if placeHolderEmpty && g:Imap_DeleteEmptyPlaceHolders
436 " delete the empty placeholder into the blackhole.
437 return movement."\"_c\<C-o>:".s:RemoveLastHistoryItem."\<CR>"
439 return movement."\<C-\>\<C-N>:".s:RemoveLastHistoryItem."\<CR>gv\<C-g>"
445 " Maps for IMAP_Jumpfunc {{{
447 " These mappings use <Plug> and thus provide for easy user customization. When
448 " the user wants to map some other key to jump forward, he can do for
450 " nmap ,f <plug>IMAP_JumpForward
453 " jumping forward and back in insert mode.
454 imap <silent> <Plug>IMAP_JumpForward <c-r>=IMAP_Jumpfunc('', 0)<CR>
455 imap <silent> <Plug>IMAP_JumpBack <c-r>=IMAP_Jumpfunc('b', 0)<CR>
457 " jumping in normal mode
458 nmap <silent> <Plug>IMAP_JumpForward i<c-r>=IMAP_Jumpfunc('', 0)<CR>
459 nmap <silent> <Plug>IMAP_JumpBack i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
461 " deleting the present selection and then jumping forward.
462 vmap <silent> <Plug>IMAP_DeleteAndJumpForward "_<Del>i<c-r>=IMAP_Jumpfunc('', 0)<CR>
463 vmap <silent> <Plug>IMAP_DeleteAndJumpBack "_<Del>i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
465 " jumping forward without deleting present selection.
466 vmap <silent> <Plug>IMAP_JumpForward <C-\><C-N>i<c-r>=IMAP_Jumpfunc('', 0)<CR>
467 vmap <silent> <Plug>IMAP_JumpBack <C-\><C-N>`<i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
470 " Default maps for IMAP_Jumpfunc {{{
471 " map only if there is no mapping already. allows for user customization.
472 " NOTE: Default mappings for jumping to the previous placeholder are not
473 " provided. It is assumed that if the user will create such mappings
474 " hself if e so desires.
475 if !hasmapto('<Plug>IMAP_JumpForward', 'i')
476 imap <C-J> <Plug>IMAP_JumpForward
478 if !hasmapto('<Plug>IMAP_JumpForward', 'n')
479 nmap <C-J> <Plug>IMAP_JumpForward
481 if exists('g:Imap_StickyPlaceHolders') && g:Imap_StickyPlaceHolders
482 if !hasmapto('<Plug>IMAP_JumpForward', 'v')
483 vmap <C-J> <Plug>IMAP_JumpForward
486 if !hasmapto('<Plug>IMAP_DeleteAndJumpForward', 'v')
487 vmap <C-J> <Plug>IMAP_DeleteAndJumpForward
492 nmap <silent> <script> <plug><+SelectRegion+> `<v`>
494 " ==============================================================================
495 " enclosing selected region.
496 " ==============================================================================
497 " VEnclose: encloses the visually selected region with given arguments {{{
498 " Description: allows for differing action based on visual line wise
499 " selection or visual characterwise selection. preserves the
500 " marks and search history.
501 function! VEnclose(vstart, vend, VStart, VEnd)
503 " its characterwise if
504 " 1. characterwise selection and valid values for vstart and vend.
506 " 2. linewise selection and invalid values for VStart and VEnd
507 if (visualmode() == 'v' && (a:vstart != '' || a:vend != '')) || (a:VStart == '' && a:VEnd == '')
512 let normcmd = "normal! \<C-\>\<C-n>`<v`>\"_s"
514 exe "normal! \<C-\>\<C-n>`<v`>\"ry"
517 let @r = substitute(@r, "\n$", '', '')
520 " In exclusive selection, we need to select an extra character.
521 if &selection == 'exclusive'
526 let normcmd = normcmd.
527 \ a:vstart."!!mark!!".a:vend.newline.
528 \ "\<C-\>\<C-N>?!!mark!!\<CR>v".movement."l\"_s\<C-r>r\<C-\>\<C-n>"
530 " this little if statement is because till very recently, vim used to
531 " report col("'>") > length of selected line when `> is $. on some
532 " systems it reports a -ve number.
533 if col("'>") < 0 || col("'>") > strlen(getline("'>"))
534 let lastcol = strlen(getline("'>"))
536 let lastcol = col("'>")
538 if lastcol - col("'<") != 0
539 let len = lastcol - col("'<")
544 " the next normal! is for restoring the marks.
545 let normcmd = normcmd."`<v".len."l\<C-\>\<C-N>"
547 " First remember what the search pattern was. s:RemoveLastHistoryItem
548 " will reset @/ to this pattern so we do not create new highlighting.
549 let g:Tex_LastSearchPattern = @/
552 " this is to restore the r register.
554 " and finally, this is to restore the search history.
555 execute s:RemoveLastHistoryItem
559 exec 'normal! `<O'.a:VStart."\<C-\>\<C-n>"
560 exec 'normal! `>o'.a:VEnd."\<C-\>\<C-n>"
562 silent! normal! `<kV`>j=
569 " ExecMap: adds the ability to correct an normal/visual mode mapping. {{{
570 " Author: Hari Krishna Dara <hari_vim@yahoo.com>
571 " Reads a normal mode mapping at the command line and executes it with the
572 " given prefix. Press <BS> to correct and <Esc> to cancel.
573 function! ExecMap(prefix, mode)
574 " Temporarily remove the mapping, otherwise it will interfere with the
575 " mapcheck call below:
576 let myMap = maparg(a:prefix, a:mode)
577 exec a:mode."unmap ".a:prefix
579 " Generate a line with spaces to clear the previous message.
583 let clearLine = clearLine . ' '
587 let mapCmd = a:prefix
590 echon "\rEnter Map: " . mapCmd
595 let mapCmd = strpart(mapCmd, 0, strlen(mapCmd) - 1)
597 else " It is the ascii code.
598 let char = nr2char(char)
602 let mapCmd = mapCmd . char
603 if maparg(mapCmd, a:mode) != ""
606 elseif mapcheck(mapCmd, a:mode) == ""
607 let mapCmd = strpart(mapCmd, 0, strlen(mapCmd) - 1)
612 echon "\rEnter Map: " . mapCmd
616 " use a plug to select the region instead of using something like
617 " `<v`> to avoid problems caused by some of the characters in
618 " '`<v`>' being mapped.
619 let gotoc = "\<plug><+SelectRegion+>"
623 exec "normal ".gotoc.mapCmd
625 exec a:mode.'noremap '.a:prefix.' '.myMap
630 " ==============================================================================
632 " ==============================================================================
633 " Strntok: extract the n^th token from a list {{{
634 " example: Strntok('1,23,3', ',', 2) = 23
635 fun! <SID>Strntok(s, tok, n)
636 return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
640 " s:RemoveLastHistoryItem: removes last search item from search history {{{
641 " Description: Execute this string to clean up the search history.
642 let s:RemoveLastHistoryItem = ':call histdel("/", -1)|let @/=g:Tex_LastSearchPattern'
645 " s:Hash: Return a version of a string that can be used as part of a variable" {{{
647 " Converts every non alphanumeric character into _{ascii}_ where {ascii} is
648 " the ASCII code for that character...
650 return substitute(a:text, '\([^[:alnum:]]\)',
651 \ '\="_".char2nr(submatch(1))."_"', 'g')
654 " IMAP_GetPlaceHolderStart and IMAP_GetPlaceHolderEnd: "{{{
655 " return the buffer local placeholder variables, or the global one, or the default.
656 function! IMAP_GetPlaceHolderStart()
657 if exists("b:Imap_PlaceHolderStart") && strlen(b:Imap_PlaceHolderEnd)
658 return b:Imap_PlaceHolderStart
659 elseif exists("g:Imap_PlaceHolderStart") && strlen(g:Imap_PlaceHolderEnd)
660 return g:Imap_PlaceHolderStart
664 function! IMAP_GetPlaceHolderEnd()
665 if exists("b:Imap_PlaceHolderEnd") && strlen(b:Imap_PlaceHolderEnd)
666 return b:Imap_PlaceHolderEnd
667 elseif exists("g:Imap_PlaceHolderEnd") && strlen(g:Imap_PlaceHolderEnd)
668 return g:Imap_PlaceHolderEnd
673 " s:Iconv: a wrapper for iconv()" {{{
676 " (or using the raw 8-bit ASCII character in a file with 'fenc' set to
677 " "latin1") if 'encoding' is set to utf-8, then text does not match itself:
680 " Solution: When this happens, a re-encoded version of text does match text:
681 " echo iconv(text, "latin1", "utf8") =~ text
682 " returns 1. In this case, convert text to utf-8 with iconv().
683 " TODO: Is it better to use &encoding instead of "utf8"? Internally, vim
684 " uses utf-8, and can convert between latin1 and utf-8 even when compiled with
685 " -iconv, so let's try using utf-8.
687 " a:text = text to be encoded or decoded
688 " a:mode = "encode" (latin1 to utf8) or "decode" (utf8 to latin1)
689 " Caution: do not encode and then decode without checking whether the text
690 " has changed, becuase of the :if clause in encoding!
691 function! s:Iconv(text, mode)
692 if a:mode == "decode"
693 return iconv(a:text, "utf8", "latin1")
695 if a:text =~ '\V\^' . escape(a:text, '\') . '\$'
698 let textEnc = iconv(a:text, "latin1", "utf8")
699 if textEnc !~ '\V\^' . escape(a:text, '\') . '\$''
700 call IMAP_Debug('Encoding problems with text '.a:text.' ', 'imap')
705 " IMAP_Debug: interface to Tex_Debug if available, otherwise emulate it {{{
707 " Do not want a memory leak! Set this to zero so that imaps always
708 " starts out in a non-debugging mode.
709 if !exists('g:Imap_Debug')
712 function! IMAP_Debug(string, pattern)
716 if exists('*Tex_Debug')
717 call Tex_Debug(a:string, a:pattern)
719 if !exists('s:debug_'.a:pattern)
720 let s:debug_{a:pattern} = a:string
722 let s:debug_{a:pattern} = s:debug_{a:pattern}.a:string
726 " IMAP_DebugClear: interface to Tex_DebugClear if avaialable, otherwise emulate it {{{
728 function! IMAP_DebugClear(pattern)
729 if exists('*Tex_DebugClear')
730 call Tex_DebugClear(a:pattern)
732 let s:debug_{a:pattern} = ''
735 " IMAP_DebugPrint: interface to Tex_DebugPrint if avaialable, otherwise emulate it {{{
737 function! IMAP_DebugPrint(pattern)
738 if exists('*Tex_DebugPrint')
739 call Tex_DebugPrint(a:pattern)
741 if exists('s:debug_'.a:pattern)
742 let s:debug_{a:pattern} = ''
744 echo s:debug_{a:pattern}
748 " IMAP_Mark: Save the cursor position (if a:action == 'set') in a" {{{
749 " script-local variable; restore this position if a:action == 'go'.
751 function! IMAP_Mark(action)
753 let s:Mark = "(" . line(".") . "," . col(".") . ")"
754 elseif a:action == 'go'
755 execute "call cursor" s:Mark
759 " ==============================================================================
760 " A bonus function: Snip()
761 " ==============================================================================
762 " Snip: puts a scissor string above and below block of text {{{
764 "-------------------------------------%<-------------------------------------
765 " this puts a the string "--------%<---------" above and below the visually
766 " selected block of lines. the length of the 'tearoff' string depends on the
767 " maximum string length in the selected range. this is an aesthetically more
768 " pleasing alternative instead of hardcoding a length.
769 "-------------------------------------%<-------------------------------------
770 function! <SID>Snip() range
773 " find out the maximum virtual length of each line.
774 while i <= a:lastline
776 let length = virtcol('$')
777 let maxlen = (length > maxlen ? length : maxlen)
780 let maxlen = (maxlen > &tw && &tw != 0 ? &tw : maxlen)
784 exe "norm! o\<esc>".(half - 1)."a-\<esc>A%<\<esc>".(half - 1)."a-"
785 " and above. its necessary to put the string below the block of lines
786 " first because that way the first line number doesnt change...
788 exe "norm! O\<esc>".(half - 1)."a-\<esc>A%<\<esc>".(half - 1)."a-"
791 com! -nargs=0 -range Snip :<line1>,<line2>call <SID>Snip()
794 " vim:ft=vim:ts=4:sw=4:noet:fdm=marker:commentstring=\"\ %s:nowrap