Autocommit of file /home/julien/.dotfiles/vim/.vim/bundle/vimtodo/ftplugin/todo.vim...
[dotfiles/vim.git] / .vim / bundle / vimtodo / ftplugin / todo.vim
1 " Vim filetype plugin for heirarchical TODO lists
2 " Maintainer:   Mark Harrison <mark@mivok.net>
3 " Last Change:  Nov 27, 2010
4 " License:      ISC - See LICENSE file for details
5
6 " This file has folded functions - Use zR to show all source code if you
7 " aren't familiar with folding in vim.
8
9 " Only load if we haven't already {{{1
10 if exists("b:did_ftplugin")
11     finish
12 endif
13 let b:did_ftplugin = 1
14 "1}}}
15 " Make sure we aren't running in compatible mode {{{1
16 let s:save_cpo = &cpo
17 set cpo&vim
18 "1}}}
19
20 " Utility Functions
21 " s:Map - mapping helper function {{{1
22 function! s:Map(keys, funcname)
23     if !hasmapto('<Plug>Todo'.a:funcname)
24         exe "map <buffer> <silent> <unique> <LocalLeader>".a:keys.
25                     \" <Plug>Todo".a:funcname
26     endif
27     exe "noremap <buffer> <silent> <unique> <script> <Plug>Todo".a:funcname.
28                 \" <SID>".a:funcname
29     exe "noremap <buffer> <silent> <SID>".a:funcname." :call <SID>".
30                 \a:funcname."()<CR>"
31 endfunction
32 "1}}}
33 " s:NewScratchBuffer - Create a new buffer {{{1
34 function! s:NewScratchBuffer(name, split)
35     if a:split
36         split
37     endif
38     " Set the buffer name
39     let name="[".a:name."]"
40     if !has("win32")
41         let name = escape(name, "[]")
42     endif
43     " Switch buffers
44     if has("gui")
45         exec "silent keepjumps drop" name
46     else
47         exec "silent keepjumps hide edit" name
48     endif
49     " Set the new buffer properties to be a scrach buffer
50     setlocal bufhidden=delete
51     setlocal buftype=nofile
52     setlocal modifiable " This needs to be changed once the buffer has stuff in
53     setlocal noswapfile
54     setlocal nowrap     " This can be changed if needed
55 endfunction
56 "1}}}
57 " s:GetState - Gets the state for a line, and its index {{{1
58 function! s:GetState(line)
59     let line=getline(a:line)
60     let regex="\\(^\\s*\\)\\@<=[A-Z]\\+\\(\\s\\|$\\)\\@="
61     let idx=match(line, regex)
62     let state=matchstr(line, regex)
63     return [state, idx]
64 endfunction
65 "1}}}
66 " s:IsDoneState - Tests if a state is considered 'done' {{{1
67 function! s:IsDoneState(state)
68     for group in g:todo_states
69         let idx = index(group, "|")
70         if idx == len(group)
71             continue
72         elseif idx != -1
73             let idx = idx + 1
74         endif
75         " Note, having idx set to -1 (when there is no |) means we will be
76         " looking at the last item, which is the desired behavior.
77         for teststate in group[idx+0:]
78             if vimtodo#TodoParseTaskState(teststate)["state"] == a:state
79                 return 1
80             endif
81         endfor
82     endfor
83     return 0
84 endfunction
85 "1}}}
86 " s:GetDoneStates - Returns a list of all done states {{{1
87 function! s:GetDoneStates()
88     let states = []
89     for group in g:todo_states
90         let idx = index(group, "|")
91         if idx == len(group)
92             continue
93         elseif idx != -1
94             let idx = idx + 1
95         endif
96         for state in group[idx :]
97             call add(states, vimtodo#TodoParseTaskState(state)['state'])
98         endfor
99     endfor
100     return states
101 endfunction
102 "1}}}
103 " s:ParseDate {{{1
104 " Parses A string of the form YYYY-MM-DD into an integer for comparison
105 " purposes. Supports YYYY-M-D formats too
106 function! s:ParseDate(datestr)
107     let ml = matchlist(a:datestr,
108                 \'\(\d\{4\}\)-\(\d\{1,2\}\)-\(\d\{1,2\}\)')
109     if ml == []
110         return 0
111     endif
112     let [y, m, d] = ml[1:3]
113     return str2nr(printf("%d%02d%02d", y,m,d))
114 endfunction
115 " 1}}}
116 " s:GetCurrentTask {{{1
117 " Gets the line numbers for the start and end of the current task given a line
118 " number (the 'current' line).  A task for the purposes of this function
119 " starts at the beginning of the line and stops when the indent goes back to 0
120 function! s:GetCurrentTask(line)
121     let startline = a:line
122     let endline = a:line
123     let bottom = line("$")
124
125     while startline > 1 && indent(startline) > 0
126         let startline -= 1
127     endwhile
128     while endline < bottom && indent(endline + 1) > 0
129         let endline += 1
130     endwhile
131     return [startline, endline]
132 endfunction
133 " 1}}}
134
135 " Drawer Functions
136 " s:FindDrawer {{{1
137 function! s:FindDrawer(name, line)
138     let line=a:line
139     " Strings will evaluate to 0 - so process it with the line function if we
140     " have a string.
141     if line == 0
142         let line = line(line)
143     endif
144     if line == -1
145         " -1 means look for a top-level drawer
146         let topindent = -1
147         let indent = 0
148         let line += 1
149     else
150         " Look for a drawer inside the current entry
151         let topindent = indent(line)
152         let line=line + 1
153         let indent = indent(line)
154     endif
155     while indent(line) > topindent
156         if indent(line) == indent &&
157                     \ match(getline(line), '^\s*:'.toupper(a:name).':') != -1
158             return line
159         endif
160         let line = line + 1
161     endwhile
162     return -1
163 endfunction
164 "1}}}
165 " s:FindOrMakeDrawer {{{1
166 function! s:FindOrMakeDrawer(name, line)
167     let line = s:FindDrawer(a:name, a:line)
168     if line != -1
169         return line
170     endif
171     let topindent = indent(a:line)
172     let indent = indent(a:line + 1)
173     if indent <= topindent
174         let indent = topindent + &shiftwidth
175     endif
176     let indentstr=printf("%".indent."s", "") " generate indent spaces
177     call append(a:line, indentstr.":".toupper(a:name).":")
178     return a:line + 1
179 endfunction
180 "1}}}
181 " s:GetNextProperty {{{1
182 function! s:GetNextProperty(drawerline, propertyline)
183     let indent = indent(a:drawerline)
184     let propindent = indent(a:propertyline)
185     if propindent <= indent
186         " We exited the drawer, return nothing
187         return ["",""]
188     endif
189     let match = matchlist(getline(a:propertyline),
190                 \'^\s\++\([A-Z]\+\):\s\?\(.*\)$')
191     if match != []
192         return match[1:2]
193     else
194         return ["",""]
195     endif
196 endfunction
197 " 1}}}
198 " s:GetProperty {{{1
199 function! s:GetProperty(drawerline, property)
200     let indent = indent(a:drawerline)
201     let linenum = a:drawerline + 1
202     while indent(linenum) >= indent
203         let match = matchlist(getline(linenum),
204                     \'^\s\++'.a:property.':\s\?\(.*\)$')
205         if match != []
206             return [match[1], linenum]
207         endif
208         let linenum += 1
209     endwhile
210     return ["", -1]
211 endfunction
212 " 1}}}
213 " s:SetProperty {{{1
214 function! s:SetProperty(drawerline, property, value)
215     let match = s:GetProperty(a:drawerline, a:property)
216     if match[1] != -1
217         " Property already exists, edit it
218         exe match[1] . "s/:.*/: " . a:value . "/"
219     else
220         " Property doesn't exist, add it from scratch
221         let topindent = indent(a:drawerline)
222         let indent = indent(a:drawerline + 1)
223         if indent <= topindent
224             let indent = topindent + &shiftwidth
225         endif
226         let indentstr=printf("%".indent."s", "") " generate indent spaces
227         call append(a:drawerline, indentstr."+".toupper(a:property).": " .
228             \ a:value)
229     endif
230 endfunction
231 " 1}}}
232
233 " Settings
234 " Load default variables {{{1
235 call vimtodo#SetDefaultVars()
236 "1}}}
237 " Per file variables {{{1
238 let s:PropertyVars = {
239             \'LOGDONE':         'g:todo_log_done',
240             \'LOGDRAWER':       'g:todo_log_into_drawer',
241             \'DONEFILE':        'g:todo_done_file',
242             \'STATES':          'g:todo_states',
243             \'STATECOLORS':     'g:todo_state_colors',
244             \'CHECKBOXSTATES':  'g:todo_checkbox_states',
245             \'TASKURL':         'g:todo_taskurl',
246             \'BROWSER':         'g:todo_browser'
247             \}
248 let s:PropertyTypes = {
249             \'STATES':          'nestedlist',
250             \'STATECOLORS':     'dict',
251             \'CHECKBOXSTATES':  'nestedlist'
252             \}
253 function! s:LoadFileVars()
254     let drawerline=s:FindDrawer("SETTINGS", 0)
255     if drawerline == -1
256         return
257     endif
258     let propertyline=drawerline + 1
259     let [name, val] = s:GetNextProperty(drawerline, propertyline)
260     " Keep track of which variables have already been wiped - list/dict vars
261     " need the original value overwriting for the first settings line, but
262     " then have values appended for subsequent lines
263     let wiped = {}
264     while name != ""
265         " Look up a name to variable mapping
266         if has_key(s:PropertyVars, name)
267             let type = get(s:PropertyTypes, name, "normal")
268             if type == "normal"
269                 exe "let" s:PropertyVars[name]."=val"
270             elseif type == "dict"
271                 if !has_key(wiped, name)
272                     " Wipe the original value if needed
273                     let wiped[name] = 1
274                     exe "let" s:PropertyVars[name]."={}"
275                 endif
276                 let parts = split(val, ',')
277                 for part in parts
278                     let [k,v] = split(part, ':')
279                     " Strip spaces
280                     let k = matchlist(k, '^\s*\(.*\S\)\s*$')[1]
281                     let v = matchlist(v, '^\s*\(.*\S\)\s*$')[1]
282                     exe "let" s:PropertyVars[name]."[k]=v"
283                 endfor
284             elseif type == "nestedlist"
285                 if !has_key(wiped, name)
286                     " Wipe the original value if needed
287                     let wiped[name] = 1
288                     exe "let" s:PropertyVars[name]."=[]"
289                 endif
290                 let parts = split(val, '\s\+')
291                 exe "call add("s:PropertyVars[name].",parts)"
292             elseif type == "list"
293                 if !has_key(wiped, name)
294                     " Wipe the original value if needed
295                     let wiped[name] = 1
296                     exe "let" s:PropertyVars[name]."=[]"
297                 endif
298                 let parts = split(val, '\s\+')
299                 exe "call extend("s:PropertyVars[name].",parts)"
300             endif
301         endif
302         let propertyline += 1
303         let [name, val] = s:GetNextProperty(drawerline, propertyline)
304     endwhile
305 endfunction
306 call s:LoadFileVars()
307 " 1}}}
308 " Folding support {{{1
309 setlocal foldmethod=indent
310 setlocal foldtext=getline(v:foldstart).\"\ ...\"
311 setlocal fillchars+=fold:\ 
312 " 1}}}
313 " Mappings {{{1
314 call s:Map("cb", "InsertCheckbox")
315 call s:Map("cc", "CheckboxToggle")
316 call s:Map("cv", "PromptTaskState")
317 call s:Map("cs", "NextTaskState")
318 call s:Map("ct", "LoadTaskLink")
319 call s:Map("cl", "LoadLink")
320 call s:Map("ca", "ArchiveDone")
321 call s:Map("ce", "UpdateTimeTotal")
322 "1}}}
323
324 " Todo entry macros
325 " ds - Datestamp {{{1
326 iab ds <C-R>=strftime("%Y-%m-%d")<CR>
327 " cn, \cn - New todo entry {{{1
328 exe 'map <LocalLeader>cn o'.vimtodo#TodoParseTaskState(
329             \g:todo_states[0][0])["state"].' ds '
330 exe 'iab cn '.vimtodo#TodoParseTaskState(g:todo_states[0][0])["state"].
331             \' <C-R>=strftime("%Y-%m-%d")<CR>'
332 "1}}}
333
334 " Checkboxes
335 " s:InsertCheckbox {{{1
336 " Make a checkbox at the beginning of the line, removes any preceding bullet
337 " point dash
338 function! s:InsertCheckbox()
339     echo "Insert checkbox"
340     if match(getline('.'), '^\s*\[.\]') == -1
341         let oldpos=getpos(".")
342         s/^\(\s*\)\?\(- \)\?/\1[ ] /
343         call setpos(".", oldpos)
344     endif
345 endfunction
346 "1}}}
347 " s:CheckboxToggle {{{1
348 function! s:CheckboxToggle()
349     echo "Toggle checkbox"
350     let line=getline(".")
351     let idx=match(line, "\\[[^]]\\]")
352     if idx != -1
353         for group in g:todo_checkbox_states
354             let stateidx = 0
355             while stateidx < len(group)
356                 if group[stateidx] == line[idx+1]
357                     let stateidx=stateidx + 1
358                     if stateidx >= len(group)
359                         let stateidx = 0
360                     endif
361                     let val=group[stateidx]
362                     let parts=[line[0:idx],line[idx+2:]]
363                     call setline(".", join(parts, val))
364                     return
365                 endif
366                 let stateidx=stateidx + 1
367             endwhile
368         endfor
369     endif
370 endfunction
371 "1}}}
372
373 " Task status
374 " s:NextTaskState {{{1
375 function! s:NextTaskState()
376     echo "Next task state"
377     let [oldstate, idx] = s:GetState(".")
378     if idx != -1
379         for group in g:todo_states
380             let stateidx = 0
381             while stateidx < len(group)
382                 let teststate = vimtodo#TodoParseTaskState(group[stateidx]
383                     \)["state"]
384                 if teststate == oldstate
385                     let stateidx=(stateidx + 1) % len(group)
386                     " Skip | separator
387                     if group[stateidx] == "|"
388                         let stateidx=(stateidx + 1) % len(group)
389                     endif
390                     let val=vimtodo#TodoParseTaskState(
391                         \group[stateidx])["state"]
392                     call s:SetTaskState(val, oldstate, idx)
393                     return
394                 endif
395                 let stateidx=stateidx + 1
396             endwhile
397         endfor
398     endif
399 endfunction
400 "1}}}
401 " s:PromptTaskState {{{1
402 function! s:PromptTaskState()
403     let [oldstate, idx] = s:GetState(".")
404     call s:NewScratchBuffer("StateSelect", 1)
405     call append(0, "Pick the new task state")
406     let statekeys = {}
407     for group in g:todo_states
408         let promptlist = []
409         for statestr in group
410             if statestr == "|"
411                 continue
412             endif
413             let state = vimtodo#TodoParseTaskState(statestr)
414             if state["key"] != ""
415                 call add(promptlist, state["state"]." (".state["key"].")")
416                 let statekeys[state["key"]] = state["state"]
417             endif
418         endfor
419         if len(promptlist)
420             call append(line("$"), "    ".join(promptlist, ", "))
421         endif
422     endfor
423     echo
424     for key in keys(statekeys)
425         exe "nnoremap <buffer> <silent> ".key.
426                     \" :call <SID>SelectTaskState(\"".statekeys[key]."\"".
427                     \",\"".oldstate."\",".idx.")<CR>"
428     endfor
429     call append(line("$"), "    Press Backspace to remove any existing state")
430     exe "nnoremap <buffer> <silent> <BS> :call <SID>SelectTaskState(".
431                 \'"","'.oldstate.'", '.idx.')<CR>'
432     call append(line("$"), "    Press Space to cancel")
433     nnoremap <buffer> <silent> <Space> :bd<CR>
434     setlocal nomodifiable " Make the buffer read only
435 endfunction
436 "1}}}
437 " s:SelectTaskState {{{1
438 function! s:SelectTaskState(state, oldstate, idx)
439     bdelete
440     call s:SetTaskState(a:state, a:oldstate, a:idx)
441 endfunction
442 "1}}}
443 " s:SetTaskState {{{1
444 function! s:SetTaskState(state, oldstate, idx)
445     let line = getline(".")
446     if a:idx > 0
447         let parts=[line[0:a:idx-1],line[a:idx+len(a:oldstate):]]
448     elseif a:idx == -1
449         let parts=["", " ".line]
450     else
451         let parts=["",line[len(a:oldstate):]]
452     endif
453     if a:state != ""
454         call setline(".", join(parts, a:state))
455     else
456         " Remove the state
457         call setline(".", join(parts, "")[1:])
458     endif
459     " Logging code
460     " Log all states
461     if g:todo_log_into_drawer != ""
462         let log=a:state
463         if log != "" " Don't log removing a state
464             let drawerline = s:FindOrMakeDrawer(g:todo_log_into_drawer,
465                 \line("."))
466             call append(drawerline,
467                         \ matchstr(getline(drawerline), "^\\s\\+").
468                         \repeat(" ", &shiftwidth).
469                         \log.": ".strftime("%Y-%m-%d %H:%M:%S"))
470         endif
471     endif
472     " Logging done time
473     if g:todo_log_done == 1
474         let nextline = line(".") + 1
475         let closedregex = '^\s\+CLOSED:'
476         if s:IsDoneState(a:state)
477             let closedstr = matchstr(getline("."), "^\\s\\+").
478                         \ repeat(" ",&shiftwidth).
479                         \ "CLOSED: ".strftime("%Y-%m-%d %H:%M:%S")
480             " Set the CLOSED: status line
481             if getline(nextline) !~ closedregex
482                 " Preserve whether the fold was open or closed for the
483                 " appended line
484                 let foldclosed = foldclosed(line(".") + 1)
485                 call append(".", closedstr)
486                 if foldclosed == -1
487                     normal jzok
488                 endif
489             else
490                 call setline(nextline, closedstr)
491             endif
492         else
493             " Delete any CLOSED: status line if it exists
494             if getline(nextline) =~ closedregex
495                 if foldclosed(nextline) == -1
496                     " Need to temporarily open the fold if it is closed
497                     normal jddk
498                 else
499                     " Delete next line
500                     normal jzoddzck
501                 endif
502             endif
503         endif
504     endif
505 endfunction
506 "1}}}
507
508 " Task Links
509 " s:LoadTaskLink {{{1
510 "   Provides a link to a web based task manager
511 "   Need to set the todo_taskurl and todo_browser variables in .vimrc
512 "   E.g.
513 "   let todo_browser="gnome-open"
514 "   let todo_taskurl="http://www.example.com/tasks/?id=%s"
515 "   (The %s will be replaced with the task id)
516 function! s:LoadTaskLink()
517     let tid=matchstr(getline("."), "tid\\d\\+")
518     if tid != ""
519         let tid = matchstr(tid, "\\d\\+")
520         let taskurl = substitute(g:todo_taskurl, "%s", tid, "")
521         call system(shellescape(g:todo_browser) . " " . shellescape(taskurl))
522         echo "Loading Task"
523     else
524         echo "No Task ID found"
525     endif
526 endfunction
527 "1}}}
528 " s:LoadLink - URL Opening {{{1
529 " Uses todo_browser
530 function! s:LoadLink()
531     let url=matchstr(getline("."), "https\\?://\\S\\+")
532     if url != ""
533         call system(shellescape(g:todo_browser) . " " . shellescape(url))
534         echo "Loading URL"
535     else
536         echo "No URL Found"
537     endif
538 endfunction
539 "1}}}
540
541 " Task searching
542 " s:TaskSearch {{{1
543 " daterange should be a list - [start, end] where start, end are numbers
544 " relative to today (0 = today, 1 = tomorrow, -1 = yesterday, -7 = this time
545 " last week). Use a blank list to not filter by date.
546 function! s:TaskSearch(daterange, ...)
547     " Get comparable versions of the dates
548     if a:daterange != []
549         let startdate = str2nr(strftime(
550                     \"%Y%m%d", localtime() + a:daterange[0] * 86400))
551         let enddate = str2nr(strftime(
552                     \"%Y%m%d", localtime() + a:daterange[1] * 86400))
553     endif
554     " Use vimgrep to find any task header lines
555     if exists("g:todo_files")
556         " Clear any existing list - we're using vimgrepadd
557         call setloclist(0, [])
558         for f in g:todo_files
559             try
560                 exe 'lvimgrepadd /^\s*[A-Z]\+\s/j '.f
561             catch /^Vim(\a\+):E480:/
562             endtry
563         endfor
564     else
565         try
566             lvimgrep /^\s*[A-Z]\+\s/j %
567         catch /^Vim(\a\+):E480:/
568         endtry
569     endif
570     let results = []
571     " Now filter these
572     for d in getloclist(0)
573         let matched = 1
574         for pat in a:000
575             if match(d.text, pat) == -1
576                 let matched = 0
577             endif
578         endfor
579         if a:daterange != []
580             " Filter by date
581             let date = s:ParseDate(matchstr(d.text,
582                         \'{\d\{4\}-\d\{1,2\}-\d\{1,2\}}'))
583             if date < startdate
584                 let matched = 0
585             endif
586             if date > enddate
587                 let matched = 0
588             endif
589         endif
590         if matched
591             call add(results, d)
592         endif
593     endfor
594     " Replace the results with the filtered results
595     call setloclist(0, results, 'r')
596     lw
597 endfunction
598 " 1}}}
599 " s:ShowDueTasks {{{1
600 function! s:ShowDueTasks(start, end)
601     " Start/end are number of days relative to today
602     " 0 == today, 1 == tomorrow, -1 == yesterday
603     " Make start/end the same number for a single say search
604     " Generate a regex to exclude all done states
605     let donere = '^\s*\('.join(s:GetDoneStates(), '\|').'\)\@!'
606     call s:TaskSearch([a:start, a:end], donere)
607 endfunction
608 "1}}}
609 " ShowDueTasks command definitions {{{1
610 command -buffer Today :call s:ShowDueTasks(0,0)
611 command -buffer Tomorrow :call s:ShowDueTasks(1,1)
612 command -buffer Week :call s:ShowDueTasks(0,7)
613 command -buffer Overdue :call s:ShowDueTasks(-365,-1)
614
615 if !hasmapto(':Today')
616     map <buffer> <unique> <LocalLeader>cd :Today<CR>
617 endif
618 if !hasmapto(':Tomorrow')
619     map <buffer> <unique> <LocalLeader>cf :Tomorrow<CR>
620 endif
621 if !hasmapto(':Week')
622     map <buffer> <unique> <LocalLeader>cw :Week<CR>
623 endif
624 if !hasmapto(':Overdue')
625     map <buffer> <unique> <LocalLeader>cx :Overdue<CR>
626 endif
627 "1}}}
628 " Task filter command definitions {{{1
629 command -buffer -nargs=+ Filter :call s:TaskSearch([], <q-args>)
630 "1}}}
631
632 " Task reorganizing
633 " s:ArchiveDone {{{1
634 function! s:ArchiveDone()
635     let line=0
636     let startline=-1 " Start line of a task
637     let topstate="" " The state for the toplevel task
638     while line < line('$')
639         let line = line+1
640         let [state, idx] = s:GetState(line)
641         if idx == 0 " Start of a new task
642             " Archive the old task if it is relevant
643             if startline != -1 && s:IsDoneState(topstate)
644                 " We removed a chunk of text, set our line number correctly
645                 call s:ArchiveTask(startline, line - 1)
646                 let line=startline
647             endif
648             " Set the state for the new task
649             let topstate=state
650             let startline=line
651         endif
652     endwhile
653     " Deal with the last task
654     if startline != -1 && s:IsDoneState(topstate)
655         call s:ArchiveTask(startline, line)
656     endif
657 endfunction
658 " 1}}}
659 " s:ArchiveTask - Archives a range of lines {{{1
660 function! s:ArchiveTask(startline, endline)
661     if match(g:todo_done_file, '/') == 0 || match(g:todo_done_file, '\~') == 0
662         " Absolute path, don't add the current dir
663         let filename=g:todo_done_file
664     else
665         " Non-absolute path
666         let filename=fnamemodify(expand("%"),":p:h")."/".g:todo_done_file
667     endif
668     exe a:startline.",".a:endline."w! >>".filename
669     exe a:startline.",".a:endline."d"
670 endfunction
671 " 1}}}
672
673 " Automatically filled in fields
674 " s:UpdateTimeTotal {{{1
675 " Updates any total time values for the current task
676 function! s:UpdateTimeTotal()
677     let time_re = '\[\([0-9.]\+\)h\]'
678     let totaltimes = {}
679     let linenum = 1
680     let oldfilelen = line("$")
681     while linenum <= line("$")
682         let m = matchlist(getline(linenum), time_re)
683         if m != []
684             let currtask = s:GetCurrentTask(linenum)
685             let drawerline = s:FindOrMakeDrawer("INFO", currtask[0])
686             let currtotal = get(totaltimes, drawerline, 0)
687             let totaltimes[drawerline] = currtotal + str2float(m[1])
688         endif
689         let linenum += 1
690         " Skip ahead if the file grew in length because we added a drawer
691         let linenum += (line("$") - oldfilelen)
692         let oldfilelen = line("$")
693     endwhile
694     " Update the drawers here (in reverse order as updating will likely change
695     " line numbers)
696     for drawer in reverse(sort(keys(totaltimes)))
697         call s:SetProperty(drawer, "TOTALTIME",
698             \printf("%.2f", totaltimes[drawer]))
699     endfor
700 endfunction
701 " Command definition
702 command -buffer UpdateTimeTotal :call s:UpdateTimeTotal()
703 " 1}}}
704
705 " Restore the old compatible mode setting {{{1
706 let &cpo = s:save_cpo
707 "1}}}
708 " vim:foldmethod=marker