samer@3
|
1 " File: imaps.vim
|
samer@3
|
2 " Authors: Srinath Avadhanula <srinath AT fastmail.fm>
|
samer@3
|
3 " Benji Fisher <benji AT member.AMS.org>
|
samer@3
|
4 "
|
samer@3
|
5 " WWW: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/vim-latex/vimfiles/plugin/imaps.vim?only_with_tag=MAIN
|
samer@3
|
6 "
|
samer@3
|
7 " Description: insert mode template expander with cursor placement
|
samer@3
|
8 " while preserving filetype indentation.
|
samer@3
|
9 "
|
samer@3
|
10 " $Id: imaps.vim 997 2006-03-20 09:45:45Z srinathava $
|
samer@3
|
11 "
|
samer@3
|
12 " Documentation: {{{
|
samer@3
|
13 "
|
samer@3
|
14 " Motivation:
|
samer@3
|
15 " this script provides a way to generate insert mode mappings which do not
|
samer@3
|
16 " suffer from some of the problem of mappings and abbreviations while allowing
|
samer@3
|
17 " cursor placement after the expansion. It can alternatively be thought of as
|
samer@3
|
18 " a template expander.
|
samer@3
|
19 "
|
samer@3
|
20 " Consider an example. If you do
|
samer@3
|
21 "
|
samer@3
|
22 " imap lhs something
|
samer@3
|
23 "
|
samer@3
|
24 " then a mapping is set up. However, there will be the following problems:
|
samer@3
|
25 " 1. the 'ttimeout' option will generally limit how easily you can type the
|
samer@3
|
26 " lhs. if you type the left hand side too slowly, then the mapping will not
|
samer@3
|
27 " be activated.
|
samer@3
|
28 " 2. if you mistype one of the letters of the lhs, then the mapping is
|
samer@3
|
29 " deactivated as soon as you backspace to correct the mistake.
|
samer@3
|
30 "
|
samer@3
|
31 " If, in order to take care of the above problems, you do instead
|
samer@3
|
32 "
|
samer@3
|
33 " iab lhs something
|
samer@3
|
34 "
|
samer@3
|
35 " then the timeout problem is solved and so is the problem of mistyping.
|
samer@3
|
36 " however, abbreviations are only expanded after typing a non-word character.
|
samer@3
|
37 " which causes problems of cursor placement after the expansion and invariably
|
samer@3
|
38 " spurious spaces are inserted.
|
samer@3
|
39 "
|
samer@3
|
40 " Usage Example:
|
samer@3
|
41 " this script attempts to solve all these problems by providing an emulation
|
samer@3
|
42 " of imaps wchich does not suffer from its attendant problems. Because maps
|
samer@3
|
43 " are activated without having to press additional characters, therefore
|
samer@3
|
44 " cursor placement is possible. furthermore, file-type specific indentation is
|
samer@3
|
45 " preserved, because the rhs is expanded as if the rhs is typed in literally
|
samer@3
|
46 " by the user.
|
samer@3
|
47 "
|
samer@3
|
48 " The script already provides some default mappings. each "mapping" is of the
|
samer@3
|
49 " form:
|
samer@3
|
50 "
|
samer@3
|
51 " call IMAP (lhs, rhs, ft)
|
samer@3
|
52 "
|
samer@3
|
53 " Some characters in the RHS have special meaning which help in cursor
|
samer@3
|
54 " placement.
|
samer@3
|
55 "
|
samer@3
|
56 " Example One:
|
samer@3
|
57 "
|
samer@3
|
58 " call IMAP ("bit`", "\\begin{itemize}\<cr>\\item <++>\<cr>\\end{itemize}<++>", "tex")
|
samer@3
|
59 "
|
samer@3
|
60 " This effectively sets up the map for "bit`" whenever you edit a latex file.
|
samer@3
|
61 " When you type in this sequence of letters, the following text is inserted:
|
samer@3
|
62 "
|
samer@3
|
63 " \begin{itemize}
|
samer@3
|
64 " \item *
|
samer@3
|
65 " \end{itemize}<++>
|
samer@3
|
66 "
|
samer@3
|
67 " where * shows the cursor position. The cursor position after inserting the
|
samer@3
|
68 " text is decided by the position of the first "place-holder". Place holders
|
samer@3
|
69 " are special characters which decide cursor placement and movement. In the
|
samer@3
|
70 " example above, the place holder characters are <+ and +>. After you have typed
|
samer@3
|
71 " in the item, press <C-j> and you will be taken to the next set of <++>'s.
|
samer@3
|
72 " Therefore by placing the <++> characters appropriately, you can minimize the
|
samer@3
|
73 " use of movement keys.
|
samer@3
|
74 "
|
samer@3
|
75 " NOTE: Set g:Imap_UsePlaceHolders to 0 to disable placeholders altogether.
|
samer@3
|
76 " Set
|
samer@3
|
77 " g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd
|
samer@3
|
78 " to something else if you want different place holder characters.
|
samer@3
|
79 " Also, b:Imap_PlaceHolderStart and b:Imap_PlaceHolderEnd override the values
|
samer@3
|
80 " of g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd respectively. This is
|
samer@3
|
81 " useful for setting buffer specific place hoders.
|
samer@3
|
82 "
|
samer@3
|
83 " Example Two:
|
samer@3
|
84 " You can use the <C-r> command to insert dynamic elements such as dates.
|
samer@3
|
85 " call IMAP ('date`', "\<c-r>=strftime('%b %d %Y')\<cr>", '')
|
samer@3
|
86 "
|
samer@3
|
87 " sets up the map for date` to insert the current date.
|
samer@3
|
88 "
|
samer@3
|
89 "--------------------------------------%<--------------------------------------
|
samer@3
|
90 " Bonus: This script also provides a command Snip which puts tearoff strings,
|
samer@3
|
91 " '----%<----' above and below the visually selected range of lines. The
|
samer@3
|
92 " length of the string is chosen to be equal to the longest line in the range.
|
samer@3
|
93 " Recommended Usage:
|
samer@3
|
94 " '<,'>Snip
|
samer@3
|
95 "--------------------------------------%<--------------------------------------
|
samer@3
|
96 " }}}
|
samer@3
|
97
|
samer@3
|
98 " line continuation used here.
|
samer@3
|
99 let s:save_cpo = &cpo
|
samer@3
|
100 set cpo&vim
|
samer@3
|
101
|
samer@3
|
102 " ==============================================================================
|
samer@3
|
103 " Script Options / Variables
|
samer@3
|
104 " ==============================================================================
|
samer@3
|
105 " Options {{{
|
samer@3
|
106 if !exists('g:Imap_StickyPlaceHolders')
|
samer@3
|
107 let g:Imap_StickyPlaceHolders = 1
|
samer@3
|
108 endif
|
samer@3
|
109 if !exists('g:Imap_DeleteEmptyPlaceHolders')
|
samer@3
|
110 let g:Imap_DeleteEmptyPlaceHolders = 1
|
samer@3
|
111 endif
|
samer@3
|
112 " }}}
|
samer@3
|
113 " Variables {{{
|
samer@3
|
114 " s:LHS_{ft}_{char} will be generated automatically. It will look like
|
samer@3
|
115 " s:LHS_tex_o = 'fo\|foo\|boo' and contain all mapped sequences ending in "o".
|
samer@3
|
116 " s:Map_{ft}_{lhs} will be generated automatically. It will look like
|
samer@3
|
117 " s:Map_c_foo = 'for(<++>; <++>; <++>)', the mapping for "foo".
|
samer@3
|
118 "
|
samer@3
|
119 " }}}
|
samer@3
|
120
|
samer@3
|
121 " ==============================================================================
|
samer@3
|
122 " functions for easy insert mode mappings.
|
samer@3
|
123 " ==============================================================================
|
samer@3
|
124 " IMAP: Adds a "fake" insert mode mapping. {{{
|
samer@3
|
125 " For example, doing
|
samer@3
|
126 " IMAP('abc', 'def' ft)
|
samer@3
|
127 " will mean that if the letters abc are pressed in insert mode, then
|
samer@3
|
128 " they will be replaced by def. If ft != '', then the "mapping" will be
|
samer@3
|
129 " specific to the files of type ft.
|
samer@3
|
130 "
|
samer@3
|
131 " Using IMAP has a few advantages over simply doing:
|
samer@3
|
132 " imap abc def
|
samer@3
|
133 " 1. with imap, if you begin typing abc, the cursor will not advance and
|
samer@3
|
134 " long as there is a possible completion, the letters a, b, c will be
|
samer@3
|
135 " displayed on on top of the other. using this function avoids that.
|
samer@3
|
136 " 2. with imap, if a backspace or arrow key is pressed before completing
|
samer@3
|
137 " the word, then the mapping is lost. this function allows movement.
|
samer@3
|
138 " (this ofcourse means that this function is only limited to
|
samer@3
|
139 " left-hand-sides which do not have movement keys or unprintable
|
samer@3
|
140 " characters)
|
samer@3
|
141 " It works by only mapping the last character of the left-hand side.
|
samer@3
|
142 " when this character is typed in, then a reverse lookup is done and if
|
samer@3
|
143 " the previous characters consititute the left hand side of the mapping,
|
samer@3
|
144 " the previously typed characters and erased and the right hand side is
|
samer@3
|
145 " inserted
|
samer@3
|
146
|
samer@3
|
147 " IMAP: set up a filetype specific mapping.
|
samer@3
|
148 " Description:
|
samer@3
|
149 " "maps" the lhs to rhs in files of type 'ft'. If supplied with 2
|
samer@3
|
150 " additional arguments, then those are assumed to be the placeholder
|
samer@3
|
151 " characters in rhs. If unspecified, then the placeholder characters
|
samer@3
|
152 " are assumed to be '<+' and '+>' These placeholder characters in
|
samer@3
|
153 " a:rhs are replaced with the users setting of
|
samer@3
|
154 " [bg]:Imap_PlaceHolderStart and [bg]:Imap_PlaceHolderEnd settings.
|
samer@3
|
155 "
|
samer@3
|
156 function! IMAP(lhs, rhs, ft, ...)
|
samer@3
|
157
|
samer@3
|
158 " Find the place holders to save for IMAP_PutTextWithMovement() .
|
samer@3
|
159 if a:0 < 2
|
samer@3
|
160 let phs = '<+'
|
samer@3
|
161 let phe = '+>'
|
samer@3
|
162 else
|
samer@3
|
163 let phs = a:1
|
samer@3
|
164 let phe = a:2
|
samer@3
|
165 endif
|
samer@3
|
166
|
samer@3
|
167 let hash = s:Hash(a:lhs)
|
samer@3
|
168 let s:Map_{a:ft}_{hash} = a:rhs
|
samer@3
|
169 let s:phs_{a:ft}_{hash} = phs
|
samer@3
|
170 let s:phe_{a:ft}_{hash} = phe
|
samer@3
|
171
|
samer@3
|
172 " Add a:lhs to the list of left-hand sides that end with lastLHSChar:
|
samer@3
|
173 let lastLHSChar = a:lhs[strlen(a:lhs)-1]
|
samer@3
|
174 let hash = s:Hash(lastLHSChar)
|
samer@3
|
175 if !exists("s:LHS_" . a:ft . "_" . hash)
|
samer@3
|
176 let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\')
|
samer@3
|
177 else
|
samer@3
|
178 let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\') .'\|'. s:LHS_{a:ft}_{hash}
|
samer@3
|
179 endif
|
samer@3
|
180
|
samer@3
|
181 " map only the last character of the left-hand side.
|
samer@3
|
182 if lastLHSChar == ' '
|
samer@3
|
183 let lastLHSChar = '<space>'
|
samer@3
|
184 end
|
samer@3
|
185 exe 'inoremap <silent>'
|
samer@3
|
186 \ escape(lastLHSChar, '|')
|
samer@3
|
187 \ '<C-r>=<SID>LookupCharacter("' .
|
samer@3
|
188 \ escape(lastLHSChar, '\|"') .
|
samer@3
|
189 \ '")<CR>'
|
samer@3
|
190 endfunction
|
samer@3
|
191
|
samer@3
|
192 " }}}
|
samer@3
|
193 " IMAP_list: list the rhs and place holders corresponding to a:lhs {{{
|
samer@3
|
194 "
|
samer@3
|
195 " Added mainly for debugging purposes, but maybe worth keeping.
|
samer@3
|
196 function! IMAP_list(lhs)
|
samer@3
|
197 let char = a:lhs[strlen(a:lhs)-1]
|
samer@3
|
198 let charHash = s:Hash(char)
|
samer@3
|
199 if exists("s:LHS_" . &ft ."_". charHash) && a:lhs =~ s:LHS_{&ft}_{charHash}
|
samer@3
|
200 let ft = &ft
|
samer@3
|
201 elseif exists("s:LHS__" . charHash) && a:lhs =~ s:LHS__{charHash}
|
samer@3
|
202 let ft = ""
|
samer@3
|
203 else
|
samer@3
|
204 return ""
|
samer@3
|
205 endif
|
samer@3
|
206 let hash = s:Hash(a:lhs)
|
samer@3
|
207 return "rhs = " . s:Map_{ft}_{hash} . " place holders = " .
|
samer@3
|
208 \ s:phs_{ft}_{hash} . " and " . s:phe_{ft}_{hash}
|
samer@3
|
209 endfunction
|
samer@3
|
210 " }}}
|
samer@3
|
211 " LookupCharacter: inserts mapping corresponding to this character {{{
|
samer@3
|
212 "
|
samer@3
|
213 " This function extracts from s:LHS_{&ft}_{a:char} or s:LHS__{a:char}
|
samer@3
|
214 " the longest lhs matching the current text. Then it replaces lhs with the
|
samer@3
|
215 " corresponding rhs saved in s:Map_{ft}_{lhs} .
|
samer@3
|
216 " The place-holder variables are passed to IMAP_PutTextWithMovement() .
|
samer@3
|
217 function! s:LookupCharacter(char)
|
samer@3
|
218 if IMAP_GetVal('Imap_FreezeImap', 0) == 1
|
samer@3
|
219 return a:char
|
samer@3
|
220 endif
|
samer@3
|
221 let charHash = s:Hash(a:char)
|
samer@3
|
222
|
samer@3
|
223 " The line so far, including the character that triggered this function:
|
samer@3
|
224 let text = strpart(getline("."), 0, col(".")-1) . a:char
|
samer@3
|
225 " Prefer a local map to a global one, even if the local map is shorter.
|
samer@3
|
226 " Is this what we want? Do we care?
|
samer@3
|
227 " Use '\V' (very no-magic) so that only '\' is special, and it was already
|
samer@3
|
228 " escaped when building up s:LHS_{&ft}_{charHash} .
|
samer@3
|
229 if exists("s:LHS_" . &ft . "_" . charHash)
|
samer@3
|
230 \ && text =~ "\\C\\V\\(" . s:LHS_{&ft}_{charHash} . "\\)\\$"
|
samer@3
|
231 let ft = &ft
|
samer@3
|
232 elseif exists("s:LHS__" . charHash)
|
samer@3
|
233 \ && text =~ "\\C\\V\\(" . s:LHS__{charHash} . "\\)\\$"
|
samer@3
|
234 let ft = ""
|
samer@3
|
235 else
|
samer@3
|
236 " If this is a character which could have been used to trigger an
|
samer@3
|
237 " abbreviation, check if an abbreviation exists.
|
samer@3
|
238 if a:char !~ '\k'
|
samer@3
|
239 let lastword = matchstr(getline('.'), '\k\+$', '')
|
samer@3
|
240 call IMAP_Debug('getting lastword = ['.lastword.']', 'imap')
|
samer@3
|
241 if lastword != ''
|
samer@3
|
242 " An extremeley wierd way to get around the fact that vim
|
samer@3
|
243 " doesn't have the equivalent of the :mapcheck() function for
|
samer@3
|
244 " abbreviations.
|
samer@3
|
245 let _a = @a
|
samer@3
|
246 exec "redir @a | silent! iab ".lastword." | redir END"
|
samer@3
|
247 let abbreviationRHS = matchstr(@a."\n", "\n".'i\s\+'.lastword.'\s\+@\?\zs.*\ze'."\n")
|
samer@3
|
248
|
samer@3
|
249 call IMAP_Debug('getting abbreviationRHS = ['.abbreviationRHS.']', 'imap')
|
samer@3
|
250
|
samer@3
|
251 if @a =~ "No abbreviation found" || abbreviationRHS == ""
|
samer@3
|
252 let @a = _a
|
samer@3
|
253 return a:char
|
samer@3
|
254 endif
|
samer@3
|
255
|
samer@3
|
256 let @a = _a
|
samer@3
|
257 let abbreviationRHS = escape(abbreviationRHS, '\<"')
|
samer@3
|
258 exec 'let abbreviationRHS = "'.abbreviationRHS.'"'
|
samer@3
|
259
|
samer@3
|
260 let lhs = lastword.a:char
|
samer@3
|
261 let rhs = abbreviationRHS.a:char
|
samer@3
|
262 let phs = IMAP_GetPlaceHolderStart()
|
samer@3
|
263 let phe = IMAP_GetPlaceHolderEnd()
|
samer@3
|
264 else
|
samer@3
|
265 return a:char
|
samer@3
|
266 endif
|
samer@3
|
267 else
|
samer@3
|
268 return a:char
|
samer@3
|
269 endif
|
samer@3
|
270 endif
|
samer@3
|
271 " Find the longest left-hand side that matches the line so far.
|
samer@3
|
272 " matchstr() returns the match that starts first. This automatically
|
samer@3
|
273 " ensures that the longest LHS is used for the mapping.
|
samer@3
|
274 if !exists('lhs') || !exists('rhs')
|
samer@3
|
275 let lhs = matchstr(text, "\\C\\V\\(" . s:LHS_{ft}_{charHash} . "\\)\\$")
|
samer@3
|
276 let hash = s:Hash(lhs)
|
samer@3
|
277 let rhs = s:Map_{ft}_{hash}
|
samer@3
|
278 let phs = s:phs_{ft}_{hash}
|
samer@3
|
279 let phe = s:phe_{ft}_{hash}
|
samer@3
|
280 endif
|
samer@3
|
281
|
samer@3
|
282 if strlen(lhs) == 0
|
samer@3
|
283 return a:char
|
samer@3
|
284 endif
|
samer@3
|
285 " enough back-spaces to erase the left-hand side; -1 for the last
|
samer@3
|
286 " character typed:
|
samer@3
|
287 let bs = substitute(strpart(lhs, 1), ".", "\<bs>", "g")
|
samer@3
|
288 return bs . IMAP_PutTextWithMovement(rhs, phs, phe)
|
samer@3
|
289 endfunction
|
samer@3
|
290
|
samer@3
|
291 " }}}
|
samer@3
|
292 " IMAP_PutTextWithMovement: returns the string with movement appended {{{
|
samer@3
|
293 " Description:
|
samer@3
|
294 " If a:str contains "placeholders", then appends movement commands to
|
samer@3
|
295 " str in a way that the user moves to the first placeholder and enters
|
samer@3
|
296 " insert or select mode. If supplied with 2 additional arguments, then
|
samer@3
|
297 " they are assumed to be the placeholder specs. Otherwise, they are
|
samer@3
|
298 " assumed to be '<+' and '+>'. These placeholder chars are replaced
|
samer@3
|
299 " with the users settings of [bg]:Imap_PlaceHolderStart and
|
samer@3
|
300 " [bg]:Imap_PlaceHolderEnd.
|
samer@3
|
301 function! IMAP_PutTextWithMovement(str, ...)
|
samer@3
|
302
|
samer@3
|
303 " The placeholders used in the particular input string. These can be
|
samer@3
|
304 " different from what the user wants to use.
|
samer@3
|
305 if a:0 < 2
|
samer@3
|
306 let phs = '<+'
|
samer@3
|
307 let phe = '+>'
|
samer@3
|
308 else
|
samer@3
|
309 let phs = escape(a:1, '\')
|
samer@3
|
310 let phe = escape(a:2, '\')
|
samer@3
|
311 endif
|
samer@3
|
312
|
samer@3
|
313 let text = a:str
|
samer@3
|
314
|
samer@3
|
315 " The user's placeholder settings.
|
samer@3
|
316 let phsUser = IMAP_GetPlaceHolderStart()
|
samer@3
|
317 let pheUser = IMAP_GetPlaceHolderEnd()
|
samer@3
|
318
|
samer@3
|
319 " Problem: depending on the setting of the 'encoding' option, a character
|
samer@3
|
320 " such as "\xab" may not match itself. We try to get around this by
|
samer@3
|
321 " changing the encoding of all our strings. At the end, we have to
|
samer@3
|
322 " convert text back.
|
samer@3
|
323 let phsEnc = s:Iconv(phs, "encode")
|
samer@3
|
324 let pheEnc = s:Iconv(phe, "encode")
|
samer@3
|
325 let phsUserEnc = s:Iconv(phsUser, "encode")
|
samer@3
|
326 let pheUserEnc = s:Iconv(pheUser, "encode")
|
samer@3
|
327 let textEnc = s:Iconv(text, "encode")
|
samer@3
|
328 if textEnc != text
|
samer@3
|
329 let textEncoded = 1
|
samer@3
|
330 else
|
samer@3
|
331 let textEncoded = 0
|
samer@3
|
332 endif
|
samer@3
|
333
|
samer@3
|
334 let pattern = '\V\(\.\{-}\)' .phs. '\(\.\{-}\)' .phe. '\(\.\*\)'
|
samer@3
|
335 " If there are no placeholders, just return the text.
|
samer@3
|
336 if textEnc !~ pattern
|
samer@3
|
337 call IMAP_Debug('Not getting '.phs.' and '.phe.' in '.textEnc, 'imap')
|
samer@3
|
338 return text
|
samer@3
|
339 endif
|
samer@3
|
340 " Break text up into "initial <+template+> final"; any piece may be empty.
|
samer@3
|
341 let initialEnc = substitute(textEnc, pattern, '\1', '')
|
samer@3
|
342 let templateEnc = substitute(textEnc, pattern, '\2', '')
|
samer@3
|
343 let finalEnc = substitute(textEnc, pattern, '\3', '')
|
samer@3
|
344
|
samer@3
|
345 " If the user does not want to use placeholders, then remove all but the
|
samer@3
|
346 " first placeholder.
|
samer@3
|
347 " Otherwise, replace all occurences of the placeholders here with the
|
samer@3
|
348 " user's choice of placeholder settings.
|
samer@3
|
349 if exists('g:Imap_UsePlaceHolders') && !g:Imap_UsePlaceHolders
|
samer@3
|
350 let finalEnc = substitute(finalEnc, '\V'.phs.'\.\{-}'.phe, '', 'g')
|
samer@3
|
351 else
|
samer@3
|
352 let finalEnc = substitute(finalEnc, '\V'.phs.'\(\.\{-}\)'.phe,
|
samer@3
|
353 \ phsUserEnc.'\1'.pheUserEnc, 'g')
|
samer@3
|
354 endif
|
samer@3
|
355
|
samer@3
|
356 " The substitutions are done, so convert back, if necessary.
|
samer@3
|
357 if textEncoded
|
samer@3
|
358 let initial = s:Iconv(initialEnc, "decode")
|
samer@3
|
359 let template = s:Iconv(templateEnc, "decode")
|
samer@3
|
360 let final = s:Iconv(finalEnc, "decode")
|
samer@3
|
361 else
|
samer@3
|
362 let initial = initialEnc
|
samer@3
|
363 let template = templateEnc
|
samer@3
|
364 let final = finalEnc
|
samer@3
|
365 endif
|
samer@3
|
366
|
samer@3
|
367 " Build up the text to insert:
|
samer@3
|
368 " 1. the initial text plus an extra character;
|
samer@3
|
369 " 2. go to Normal mode with <C-\><C-N>, so it works even if 'insertmode'
|
samer@3
|
370 " is set, and mark the position;
|
samer@3
|
371 " 3. replace the extra character with tamplate and final;
|
samer@3
|
372 " 4. back to Normal mode and restore the cursor position;
|
samer@3
|
373 " 5. call IMAP_Jumpfunc().
|
samer@3
|
374 let template = phsUser . template . pheUser
|
samer@3
|
375 " Old trick: insert and delete a character to get the same behavior at
|
samer@3
|
376 " start, middle, or end of line and on empty lines.
|
samer@3
|
377 let text = initial . "X\<C-\>\<C-N>:call IMAP_Mark('set')\<CR>\"_s"
|
samer@3
|
378 let text = text . template . final
|
samer@3
|
379 let text = text . "\<C-\>\<C-N>:call IMAP_Mark('go')\<CR>"
|
samer@3
|
380 let text = text . "i\<C-r>=IMAP_Jumpfunc('', 1)\<CR>"
|
samer@3
|
381
|
samer@3
|
382 call IMAP_Debug('IMAP_PutTextWithMovement: text = ['.text.']', 'imap')
|
samer@3
|
383 return text
|
samer@3
|
384 endfunction
|
samer@3
|
385
|
samer@3
|
386 " }}}
|
samer@3
|
387 " IMAP_Jumpfunc: takes user to next <+place-holder+> {{{
|
samer@3
|
388 " Author: Luc Hermitte
|
samer@3
|
389 " Arguments:
|
samer@3
|
390 " direction: flag for the search() function. If set to '', search forwards,
|
samer@3
|
391 " if 'b', then search backwards. See the {flags} argument of the
|
samer@3
|
392 " |search()| function for valid values.
|
samer@3
|
393 " inclusive: In vim, the search() function is 'exclusive', i.e we always goto
|
samer@3
|
394 " next cursor match even if there is a match starting from the
|
samer@3
|
395 " current cursor position. Setting this argument to 1 makes
|
samer@3
|
396 " IMAP_Jumpfunc() also respect a match at the current cursor
|
samer@3
|
397 " position. 'inclusive'ness is necessary for IMAP() because a
|
samer@3
|
398 " placeholder string can occur at the very beginning of a map which
|
samer@3
|
399 " we want to select.
|
samer@3
|
400 " We use a non-zero value only in special conditions. Most mappings
|
samer@3
|
401 " should use a zero value.
|
samer@3
|
402 function! IMAP_Jumpfunc(direction, inclusive)
|
samer@3
|
403
|
samer@3
|
404 " The user's placeholder settings.
|
samer@3
|
405 let phsUser = IMAP_GetPlaceHolderStart()
|
samer@3
|
406 let pheUser = IMAP_GetPlaceHolderEnd()
|
samer@3
|
407
|
samer@3
|
408 let searchString = ''
|
samer@3
|
409 " If this is not an inclusive search or if it is inclusive, but the
|
samer@3
|
410 " current cursor position does not contain a placeholder character, then
|
samer@3
|
411 " search for the placeholder characters.
|
samer@3
|
412 if !a:inclusive || strpart(getline('.'), col('.')-1) !~ '\V\^'.phsUser
|
samer@3
|
413 let searchString = '\V'.phsUser.'\_.\{-}'.pheUser
|
samer@3
|
414 endif
|
samer@3
|
415
|
samer@3
|
416 " If we didn't find any placeholders return quietly.
|
samer@3
|
417 if searchString != '' && !search(searchString, a:direction)
|
samer@3
|
418 return ''
|
samer@3
|
419 endif
|
samer@3
|
420
|
samer@3
|
421 " Open any closed folds and make this part of the text visible.
|
samer@3
|
422 silent! foldopen!
|
samer@3
|
423
|
samer@3
|
424 " Calculate if we have an empty placeholder or if it contains some
|
samer@3
|
425 " description.
|
samer@3
|
426 let template =
|
samer@3
|
427 \ matchstr(strpart(getline('.'), col('.')-1),
|
samer@3
|
428 \ '\V\^'.phsUser.'\zs\.\{-}\ze\('.pheUser.'\|\$\)')
|
samer@3
|
429 let placeHolderEmpty = !strlen(template)
|
samer@3
|
430
|
samer@3
|
431 " If we are selecting in exclusive mode, then we need to move one step to
|
samer@3
|
432 " the right
|
samer@3
|
433 let extramove = ''
|
samer@3
|
434 if &selection == 'exclusive'
|
samer@3
|
435 let extramove = 'l'
|
samer@3
|
436 endif
|
samer@3
|
437
|
samer@3
|
438 " Select till the end placeholder character.
|
samer@3
|
439 let movement = "\<C-o>v/\\V".pheUser."/e\<CR>".extramove
|
samer@3
|
440
|
samer@3
|
441 " First remember what the search pattern was. s:RemoveLastHistoryItem will
|
samer@3
|
442 " reset @/ to this pattern so we do not create new highlighting.
|
samer@3
|
443 let g:Tex_LastSearchPattern = @/
|
samer@3
|
444
|
samer@3
|
445 " Now either goto insert mode or select mode.
|
samer@3
|
446 if placeHolderEmpty && g:Imap_DeleteEmptyPlaceHolders
|
samer@3
|
447 " delete the empty placeholder into the blackhole.
|
samer@3
|
448 return movement."\"_c\<C-o>:".s:RemoveLastHistoryItem."\<CR>"
|
samer@3
|
449 else
|
samer@3
|
450 return movement."\<C-\>\<C-N>:".s:RemoveLastHistoryItem."\<CR>gv\<C-g>"
|
samer@3
|
451 endif
|
samer@3
|
452
|
samer@3
|
453 endfunction
|
samer@3
|
454
|
samer@3
|
455 " }}}
|
samer@3
|
456 " Maps for IMAP_Jumpfunc {{{
|
samer@3
|
457 "
|
samer@3
|
458 " These mappings use <Plug> and thus provide for easy user customization. When
|
samer@3
|
459 " the user wants to map some other key to jump forward, he can do for
|
samer@3
|
460 " instance:
|
samer@3
|
461 " nmap ,f <plug>IMAP_JumpForward
|
samer@3
|
462 " etc.
|
samer@3
|
463
|
samer@3
|
464 " jumping forward and back in insert mode.
|
samer@3
|
465 imap <silent> <Plug>IMAP_JumpForward <c-r>=IMAP_Jumpfunc('', 0)<CR>
|
samer@3
|
466 imap <silent> <Plug>IMAP_JumpBack <c-r>=IMAP_Jumpfunc('b', 0)<CR>
|
samer@3
|
467
|
samer@3
|
468 " jumping in normal mode
|
samer@3
|
469 nmap <silent> <Plug>IMAP_JumpForward i<c-r>=IMAP_Jumpfunc('', 0)<CR>
|
samer@3
|
470 nmap <silent> <Plug>IMAP_JumpBack i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
|
samer@3
|
471
|
samer@3
|
472 " deleting the present selection and then jumping forward.
|
samer@3
|
473 vmap <silent> <Plug>IMAP_DeleteAndJumpForward "_<Del>i<c-r>=IMAP_Jumpfunc('', 0)<CR>
|
samer@3
|
474 vmap <silent> <Plug>IMAP_DeleteAndJumpBack "_<Del>i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
|
samer@3
|
475
|
samer@3
|
476 " jumping forward without deleting present selection.
|
samer@3
|
477 vmap <silent> <Plug>IMAP_JumpForward <C-\><C-N>i<c-r>=IMAP_Jumpfunc('', 0)<CR>
|
samer@3
|
478 vmap <silent> <Plug>IMAP_JumpBack <C-\><C-N>`<i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
|
samer@3
|
479
|
samer@3
|
480 " }}}
|
samer@3
|
481 " Default maps for IMAP_Jumpfunc {{{
|
samer@3
|
482 " map only if there is no mapping already. allows for user customization.
|
samer@3
|
483 " NOTE: Default mappings for jumping to the previous placeholder are not
|
samer@3
|
484 " provided. It is assumed that if the user will create such mappings
|
samer@3
|
485 " hself if e so desires.
|
samer@3
|
486 if !hasmapto('<Plug>IMAP_JumpForward', 'i')
|
samer@3
|
487 imap <C-J> <Plug>IMAP_JumpForward
|
samer@3
|
488 endif
|
samer@3
|
489 if !hasmapto('<Plug>IMAP_JumpForward', 'n')
|
samer@3
|
490 nmap <C-J> <Plug>IMAP_JumpForward
|
samer@3
|
491 endif
|
samer@3
|
492 if exists('g:Imap_StickyPlaceHolders') && g:Imap_StickyPlaceHolders
|
samer@3
|
493 if !hasmapto('<Plug>IMAP_JumpForward', 'v')
|
samer@3
|
494 vmap <C-J> <Plug>IMAP_JumpForward
|
samer@3
|
495 endif
|
samer@3
|
496 else
|
samer@3
|
497 if !hasmapto('<Plug>IMAP_DeleteAndJumpForward', 'v')
|
samer@3
|
498 vmap <C-J> <Plug>IMAP_DeleteAndJumpForward
|
samer@3
|
499 endif
|
samer@3
|
500 endif
|
samer@3
|
501 " }}}
|
samer@3
|
502
|
samer@3
|
503 nmap <silent> <script> <plug><+SelectRegion+> `<v`>
|
samer@3
|
504
|
samer@3
|
505 " ==============================================================================
|
samer@3
|
506 " enclosing selected region.
|
samer@3
|
507 " ==============================================================================
|
samer@3
|
508 " VEnclose: encloses the visually selected region with given arguments {{{
|
samer@3
|
509 " Description: allows for differing action based on visual line wise
|
samer@3
|
510 " selection or visual characterwise selection. preserves the
|
samer@3
|
511 " marks and search history.
|
samer@3
|
512 function! VEnclose(vstart, vend, VStart, VEnd)
|
samer@3
|
513
|
samer@3
|
514 " its characterwise if
|
samer@3
|
515 " 1. characterwise selection and valid values for vstart and vend.
|
samer@3
|
516 " OR
|
samer@3
|
517 " 2. linewise selection and invalid values for VStart and VEnd
|
samer@3
|
518 if (visualmode() == 'v' && (a:vstart != '' || a:vend != '')) || (a:VStart == '' && a:VEnd == '')
|
samer@3
|
519
|
samer@3
|
520 let newline = ""
|
samer@3
|
521 let _r = @r
|
samer@3
|
522
|
samer@3
|
523 let normcmd = "normal! \<C-\>\<C-n>`<v`>\"_s"
|
samer@3
|
524
|
samer@3
|
525 exe "normal! \<C-\>\<C-n>`<v`>\"ry"
|
samer@3
|
526 if @r =~ "\n$"
|
samer@3
|
527 let newline = "\n"
|
samer@3
|
528 let @r = substitute(@r, "\n$", '', '')
|
samer@3
|
529 endif
|
samer@3
|
530
|
samer@3
|
531 " In exclusive selection, we need to select an extra character.
|
samer@3
|
532 if &selection == 'exclusive'
|
samer@3
|
533 let movement = 8
|
samer@3
|
534 else
|
samer@3
|
535 let movement = 7
|
samer@3
|
536 endif
|
samer@3
|
537 let normcmd = normcmd.
|
samer@3
|
538 \ a:vstart."!!mark!!".a:vend.newline.
|
samer@3
|
539 \ "\<C-\>\<C-N>?!!mark!!\<CR>v".movement."l\"_s\<C-r>r\<C-\>\<C-n>"
|
samer@3
|
540
|
samer@3
|
541 " this little if statement is because till very recently, vim used to
|
samer@3
|
542 " report col("'>") > length of selected line when `> is $. on some
|
samer@3
|
543 " systems it reports a -ve number.
|
samer@3
|
544 if col("'>") < 0 || col("'>") > strlen(getline("'>"))
|
samer@3
|
545 let lastcol = strlen(getline("'>"))
|
samer@3
|
546 else
|
samer@3
|
547 let lastcol = col("'>")
|
samer@3
|
548 endif
|
samer@3
|
549 if lastcol - col("'<") != 0
|
samer@3
|
550 let len = lastcol - col("'<")
|
samer@3
|
551 else
|
samer@3
|
552 let len = ''
|
samer@3
|
553 endif
|
samer@3
|
554
|
samer@3
|
555 " the next normal! is for restoring the marks.
|
samer@3
|
556 let normcmd = normcmd."`<v".len."l\<C-\>\<C-N>"
|
samer@3
|
557
|
samer@3
|
558 " First remember what the search pattern was. s:RemoveLastHistoryItem
|
samer@3
|
559 " will reset @/ to this pattern so we do not create new highlighting.
|
samer@3
|
560 let g:Tex_LastSearchPattern = @/
|
samer@3
|
561
|
samer@3
|
562 silent! exe normcmd
|
samer@3
|
563 " this is to restore the r register.
|
samer@3
|
564 let @r = _r
|
samer@3
|
565 " and finally, this is to restore the search history.
|
samer@3
|
566 execute s:RemoveLastHistoryItem
|
samer@3
|
567
|
samer@3
|
568 else
|
samer@3
|
569
|
samer@3
|
570 exec 'normal! `<O'.a:VStart."\<C-\>\<C-n>"
|
samer@3
|
571 exec 'normal! `>o'.a:VEnd."\<C-\>\<C-n>"
|
samer@3
|
572 if &indentexpr != ''
|
samer@3
|
573 silent! normal! `<kV`>j=
|
samer@3
|
574 endif
|
samer@3
|
575 silent! normal! `>
|
samer@3
|
576 endif
|
samer@3
|
577 endfunction
|
samer@3
|
578
|
samer@3
|
579 " }}}
|
samer@3
|
580 " ExecMap: adds the ability to correct an normal/visual mode mapping. {{{
|
samer@3
|
581 " Author: Hari Krishna Dara <hari_vim@yahoo.com>
|
samer@3
|
582 " Reads a normal mode mapping at the command line and executes it with the
|
samer@3
|
583 " given prefix. Press <BS> to correct and <Esc> to cancel.
|
samer@3
|
584 function! ExecMap(prefix, mode)
|
samer@3
|
585 " Temporarily remove the mapping, otherwise it will interfere with the
|
samer@3
|
586 " mapcheck call below:
|
samer@3
|
587 let myMap = maparg(a:prefix, a:mode)
|
samer@3
|
588 exec a:mode."unmap ".a:prefix
|
samer@3
|
589
|
samer@3
|
590 " Generate a line with spaces to clear the previous message.
|
samer@3
|
591 let i = 1
|
samer@3
|
592 let clearLine = "\r"
|
samer@3
|
593 while i < &columns
|
samer@3
|
594 let clearLine = clearLine . ' '
|
samer@3
|
595 let i = i + 1
|
samer@3
|
596 endwhile
|
samer@3
|
597
|
samer@3
|
598 let mapCmd = a:prefix
|
samer@3
|
599 let foundMap = 0
|
samer@3
|
600 let breakLoop = 0
|
samer@3
|
601 echon "\rEnter Map: " . mapCmd
|
samer@3
|
602 while !breakLoop
|
samer@3
|
603 let char = getchar()
|
samer@3
|
604 if char !~ '^\d\+$'
|
samer@3
|
605 if char == "\<BS>"
|
samer@3
|
606 let mapCmd = strpart(mapCmd, 0, strlen(mapCmd) - 1)
|
samer@3
|
607 endif
|
samer@3
|
608 else " It is the ascii code.
|
samer@3
|
609 let char = nr2char(char)
|
samer@3
|
610 if char == "\<Esc>"
|
samer@3
|
611 let breakLoop = 1
|
samer@3
|
612 else
|
samer@3
|
613 let mapCmd = mapCmd . char
|
samer@3
|
614 if maparg(mapCmd, a:mode) != ""
|
samer@3
|
615 let foundMap = 1
|
samer@3
|
616 let breakLoop = 1
|
samer@3
|
617 elseif mapcheck(mapCmd, a:mode) == ""
|
samer@3
|
618 let mapCmd = strpart(mapCmd, 0, strlen(mapCmd) - 1)
|
samer@3
|
619 endif
|
samer@3
|
620 endif
|
samer@3
|
621 endif
|
samer@3
|
622 echon clearLine
|
samer@3
|
623 echon "\rEnter Map: " . mapCmd
|
samer@3
|
624 endwhile
|
samer@3
|
625 if foundMap
|
samer@3
|
626 if a:mode == 'v'
|
samer@3
|
627 " use a plug to select the region instead of using something like
|
samer@3
|
628 " `<v`> to avoid problems caused by some of the characters in
|
samer@3
|
629 " '`<v`>' being mapped.
|
samer@3
|
630 let gotoc = "\<plug><+SelectRegion+>"
|
samer@3
|
631 else
|
samer@3
|
632 let gotoc = ''
|
samer@3
|
633 endif
|
samer@3
|
634 exec "normal ".gotoc.mapCmd
|
samer@3
|
635 endif
|
samer@3
|
636 exec a:mode.'noremap '.a:prefix.' '.myMap
|
samer@3
|
637 endfunction
|
samer@3
|
638
|
samer@3
|
639 " }}}
|
samer@3
|
640
|
samer@3
|
641 " ==============================================================================
|
samer@3
|
642 " helper functions
|
samer@3
|
643 " ==============================================================================
|
samer@3
|
644 " Strntok: extract the n^th token from a list {{{
|
samer@3
|
645 " example: Strntok('1,23,3', ',', 2) = 23
|
samer@3
|
646 fun! <SID>Strntok(s, tok, n)
|
samer@3
|
647 return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
|
samer@3
|
648 endfun
|
samer@3
|
649
|
samer@3
|
650 " }}}
|
samer@3
|
651 " s:RemoveLastHistoryItem: removes last search item from search history {{{
|
samer@3
|
652 " Description: Execute this string to clean up the search history.
|
samer@3
|
653 let s:RemoveLastHistoryItem = ':call histdel("/", -1)|let @/=g:Tex_LastSearchPattern'
|
samer@3
|
654
|
samer@3
|
655 " }}}
|
samer@3
|
656 " s:Hash: Return a version of a string that can be used as part of a variable" {{{
|
samer@3
|
657 " name.
|
samer@3
|
658 " Converts every non alphanumeric character into _{ascii}_ where {ascii} is
|
samer@3
|
659 " the ASCII code for that character...
|
samer@3
|
660 fun! s:Hash(text)
|
samer@3
|
661 return substitute(a:text, '\([^[:alnum:]]\)',
|
samer@3
|
662 \ '\="_".char2nr(submatch(1))."_"', 'g')
|
samer@3
|
663 endfun
|
samer@3
|
664 "" }}}
|
samer@3
|
665 " IMAP_GetPlaceHolderStart and IMAP_GetPlaceHolderEnd: "{{{
|
samer@3
|
666 " return the buffer local placeholder variables, or the global one, or the default.
|
samer@3
|
667 function! IMAP_GetPlaceHolderStart()
|
samer@3
|
668 if exists("b:Imap_PlaceHolderStart") && strlen(b:Imap_PlaceHolderEnd)
|
samer@3
|
669 return b:Imap_PlaceHolderStart
|
samer@3
|
670 elseif exists("g:Imap_PlaceHolderStart") && strlen(g:Imap_PlaceHolderEnd)
|
samer@3
|
671 return g:Imap_PlaceHolderStart
|
samer@3
|
672 else
|
samer@3
|
673 return "<+"
|
samer@3
|
674 endfun
|
samer@3
|
675 function! IMAP_GetPlaceHolderEnd()
|
samer@3
|
676 if exists("b:Imap_PlaceHolderEnd") && strlen(b:Imap_PlaceHolderEnd)
|
samer@3
|
677 return b:Imap_PlaceHolderEnd
|
samer@3
|
678 elseif exists("g:Imap_PlaceHolderEnd") && strlen(g:Imap_PlaceHolderEnd)
|
samer@3
|
679 return g:Imap_PlaceHolderEnd
|
samer@3
|
680 else
|
samer@3
|
681 return "+>"
|
samer@3
|
682 endfun
|
samer@3
|
683 " }}}
|
samer@3
|
684 " s:Iconv: a wrapper for iconv()" {{{
|
samer@3
|
685 " Problem: after
|
samer@3
|
686 " let text = "\xab"
|
samer@3
|
687 " (or using the raw 8-bit ASCII character in a file with 'fenc' set to
|
samer@3
|
688 " "latin1") if 'encoding' is set to utf-8, then text does not match itself:
|
samer@3
|
689 " echo text =~ text
|
samer@3
|
690 " returns 0.
|
samer@3
|
691 " Solution: When this happens, a re-encoded version of text does match text:
|
samer@3
|
692 " echo iconv(text, "latin1", "utf8") =~ text
|
samer@3
|
693 " returns 1. In this case, convert text to utf-8 with iconv().
|
samer@3
|
694 " TODO: Is it better to use &encoding instead of "utf8"? Internally, vim
|
samer@3
|
695 " uses utf-8, and can convert between latin1 and utf-8 even when compiled with
|
samer@3
|
696 " -iconv, so let's try using utf-8.
|
samer@3
|
697 " Arguments:
|
samer@3
|
698 " a:text = text to be encoded or decoded
|
samer@3
|
699 " a:mode = "encode" (latin1 to utf8) or "decode" (utf8 to latin1)
|
samer@3
|
700 " Caution: do not encode and then decode without checking whether the text
|
samer@3
|
701 " has changed, becuase of the :if clause in encoding!
|
samer@3
|
702 function! s:Iconv(text, mode)
|
samer@3
|
703 if a:mode == "decode"
|
samer@3
|
704 return iconv(a:text, "utf8", "latin1")
|
samer@3
|
705 endif
|
samer@3
|
706 if a:text =~ '\V\^' . escape(a:text, '\') . '\$'
|
samer@3
|
707 return a:text
|
samer@3
|
708 endif
|
samer@3
|
709 let textEnc = iconv(a:text, "latin1", "utf8")
|
samer@3
|
710 if textEnc !~ '\V\^' . escape(a:text, '\') . '\$'
|
samer@3
|
711 call IMAP_Debug('Encoding problems with text '.a:text.' ', 'imap')
|
samer@3
|
712 endif
|
samer@3
|
713 return textEnc
|
samer@3
|
714 endfun
|
samer@3
|
715 "" }}}
|
samer@3
|
716 " IMAP_Debug: interface to Tex_Debug if available, otherwise emulate it {{{
|
samer@3
|
717 " Description:
|
samer@3
|
718 " Do not want a memory leak! Set this to zero so that imaps always
|
samer@3
|
719 " starts out in a non-debugging mode.
|
samer@3
|
720 if !exists('g:Imap_Debug')
|
samer@3
|
721 let g:Imap_Debug = 0
|
samer@3
|
722 endif
|
samer@3
|
723 function! IMAP_Debug(string, pattern)
|
samer@3
|
724 if !g:Imap_Debug
|
samer@3
|
725 return
|
samer@3
|
726 endif
|
samer@3
|
727 if exists('*Tex_Debug')
|
samer@3
|
728 call Tex_Debug(a:string, a:pattern)
|
samer@3
|
729 else
|
samer@3
|
730 if !exists('s:debug_'.a:pattern)
|
samer@3
|
731 let s:debug_{a:pattern} = a:string
|
samer@3
|
732 else
|
samer@3
|
733 let s:debug_{a:pattern} = s:debug_{a:pattern}.a:string
|
samer@3
|
734 endif
|
samer@3
|
735 endif
|
samer@3
|
736 endfunction " }}}
|
samer@3
|
737 " IMAP_DebugClear: interface to Tex_DebugClear if avaialable, otherwise emulate it {{{
|
samer@3
|
738 " Description:
|
samer@3
|
739 function! IMAP_DebugClear(pattern)
|
samer@3
|
740 if exists('*Tex_DebugClear')
|
samer@3
|
741 call Tex_DebugClear(a:pattern)
|
samer@3
|
742 else
|
samer@3
|
743 let s:debug_{a:pattern} = ''
|
samer@3
|
744 endif
|
samer@3
|
745 endfunction " }}}
|
samer@3
|
746 " IMAP_PrintDebug: interface to Tex_DebugPrint if avaialable, otherwise emulate it {{{
|
samer@3
|
747 " Description:
|
samer@3
|
748 function! IMAP_PrintDebug(pattern)
|
samer@3
|
749 if exists('*Tex_PrintDebug')
|
samer@3
|
750 call Tex_PrintDebug(a:pattern)
|
samer@3
|
751 else
|
samer@3
|
752 if exists('s:debug_'.a:pattern)
|
samer@3
|
753 echo s:debug_{a:pattern}
|
samer@3
|
754 endif
|
samer@3
|
755 endif
|
samer@3
|
756 endfunction " }}}
|
samer@3
|
757 " IMAP_Mark: Save the cursor position (if a:action == 'set') in a" {{{
|
samer@3
|
758 " script-local variable; restore this position if a:action == 'go'.
|
samer@3
|
759 let s:Mark = "(0,0)"
|
samer@3
|
760 let s:initBlanks = ''
|
samer@3
|
761 function! IMAP_Mark(action)
|
samer@3
|
762 if a:action == 'set'
|
samer@3
|
763 let s:Mark = "(" . line(".") . "," . col(".") . ")"
|
samer@3
|
764 let s:initBlanks = matchstr(getline('.'), '^\s*')
|
samer@3
|
765 elseif a:action == 'go'
|
samer@3
|
766 execute "call cursor" s:Mark
|
samer@3
|
767 let blanksNow = matchstr(getline('.'), '^\s*')
|
samer@3
|
768 if strlen(blanksNow) > strlen(s:initBlanks)
|
samer@3
|
769 execute 'silent! normal! '.(strlen(blanksNow) - strlen(s:initBlanks)).'l'
|
samer@3
|
770 elseif strlen(blanksNow) < strlen(s:initBlanks)
|
samer@3
|
771 execute 'silent! normal! '.(strlen(s:initBlanks) - strlen(blanksNow)).'h'
|
samer@3
|
772 endif
|
samer@3
|
773 endif
|
samer@3
|
774 endfunction "" }}}
|
samer@3
|
775 " IMAP_GetVal: gets the value of a variable {{{
|
samer@3
|
776 " Description: first checks window local, then buffer local etc.
|
samer@3
|
777 function! IMAP_GetVal(name, ...)
|
samer@3
|
778 if a:0 > 0
|
samer@3
|
779 let default = a:1
|
samer@3
|
780 else
|
samer@3
|
781 let default = ''
|
samer@3
|
782 endif
|
samer@3
|
783 if exists('w:'.a:name)
|
samer@3
|
784 return w:{a:name}
|
samer@3
|
785 elseif exists('b:'.a:name)
|
samer@3
|
786 return b:{a:name}
|
samer@3
|
787 elseif exists('g:'.a:name)
|
samer@3
|
788 return g:{a:name}
|
samer@3
|
789 else
|
samer@3
|
790 return default
|
samer@3
|
791 endif
|
samer@3
|
792 endfunction " }}}
|
samer@3
|
793
|
samer@3
|
794 " ==============================================================================
|
samer@3
|
795 " A bonus function: Snip()
|
samer@3
|
796 " ==============================================================================
|
samer@3
|
797 " Snip: puts a scissor string above and below block of text {{{
|
samer@3
|
798 " Desciption:
|
samer@3
|
799 "-------------------------------------%<-------------------------------------
|
samer@3
|
800 " this puts a the string "--------%<---------" above and below the visually
|
samer@3
|
801 " selected block of lines. the length of the 'tearoff' string depends on the
|
samer@3
|
802 " maximum string length in the selected range. this is an aesthetically more
|
samer@3
|
803 " pleasing alternative instead of hardcoding a length.
|
samer@3
|
804 "-------------------------------------%<-------------------------------------
|
samer@3
|
805 function! <SID>Snip() range
|
samer@3
|
806 let i = a:firstline
|
samer@3
|
807 let maxlen = -2
|
samer@3
|
808 " find out the maximum virtual length of each line.
|
samer@3
|
809 while i <= a:lastline
|
samer@3
|
810 exe i
|
samer@3
|
811 let length = virtcol('$')
|
samer@3
|
812 let maxlen = (length > maxlen ? length : maxlen)
|
samer@3
|
813 let i = i + 1
|
samer@3
|
814 endwhile
|
samer@3
|
815 let maxlen = (maxlen > &tw && &tw != 0 ? &tw : maxlen)
|
samer@3
|
816 let half = maxlen/2
|
samer@3
|
817 exe a:lastline
|
samer@3
|
818 " put a string below
|
samer@3
|
819 exe "norm! o\<esc>".(half - 1)."a-\<esc>A%<\<esc>".(half - 1)."a-"
|
samer@3
|
820 " and above. its necessary to put the string below the block of lines
|
samer@3
|
821 " first because that way the first line number doesnt change...
|
samer@3
|
822 exe a:firstline
|
samer@3
|
823 exe "norm! O\<esc>".(half - 1)."a-\<esc>A%<\<esc>".(half - 1)."a-"
|
samer@3
|
824 endfunction
|
samer@3
|
825
|
samer@3
|
826 com! -nargs=0 -range Snip :<line1>,<line2>call <SID>Snip()
|
samer@3
|
827 " }}}
|
samer@3
|
828
|
samer@3
|
829 let &cpo = s:save_cpo
|
samer@3
|
830
|
samer@3
|
831 " vim:ft=vim:ts=4:sw=4:noet:fdm=marker:commentstring=\"\ %s:nowrap
|