move hierarchical sort to auto start

Note: because of this, TodoComplete is now known as todo#Complete, you might
need to update your vimrc.
This commit is contained in:
David Beniamine
2015-08-22 18:22:57 +02:00
parent ab4ecf5220
commit f9715af4a4
5 changed files with 382 additions and 369 deletions

View File

@@ -1,5 +1,8 @@
# Readme # Readme
**Note:** Since v0.7.3, `TodoComplete` is `todo#Complete`, you might need to
update your vimrc.
## What is this plugin ? ## What is this plugin ?
This plugin is a fork of [freitass This plugin is a fork of [freitass
@@ -83,8 +86,8 @@ see :help sort
We also provide a nice complete function for project and context, to use it We also provide a nice complete function for project and context, to use it
add the following lines to your vimrc: add the following lines to your vimrc:
" Use TodoComplete as the omni complete function for todo files " Use todo#complete as the omni complete function for todo files
au filetype todo setlocal omnifunc=TodoComplete au filetype todo setlocal omnifunc=todo#complete
You can also start automatically the completion when entering '+' or '@' by You can also start automatically the completion when entering '+' or '@' by
adding the next lines to your vimrc: adding the next lines to your vimrc:
@@ -95,7 +98,7 @@ adding the next lines to your vimrc:
" Auto complete contexts " Auto complete contexts
au filetype todo imap <buffer> @ @<C-X><C-O> au filetype todo imap <buffer> @ @<C-X><C-O>
The TodoComplete function is designed to complete projects (starting by '+') The `todo#complete` function is designed to complete projects (starting by '+')
and context (starting by '@'). If you use it on a regular word, it will do a and context (starting by '@'). If you use it on a regular word, it will do a
normal keyword completion (on all buffers). normal keyword completion (on all buffers).
If you try to complete a project, it will propose all projects in all open If you try to complete a project, it will propose all projects in all open

331
autoload/todo.vim Normal file
View File

@@ -0,0 +1,331 @@
" File: autoload/todo.vim
" Description: Todo.txt sorting plugin
" Author: David Beniamine <david@beniamine.net>
" Licence: Vim licence
" Website: http://github.com/dbeniamine/todo.txt.vim
" Version: 0.7.3
" vim: ts=4 sw=4 :help tw=78 cc=80
" These two variables are parameters for the successive calls the vim sort
" '' means no flags
" '! i' means reverse and ignore case
" for more information on flags, see :help sort
if (! exists("g:Todo_txt_first_level_sort_mode"))
let g:Todo_txt_first_level_sort_mode='i'
endif
if (! exists("g:Todo_txt_second_level_sort_mode"))
let g:Todo_txt_second_level_sort_mode='i'
endif
if (! exists("g:Todo_txt_third_level_sort_mode"))
let g:Todo_txt_third_level_sort_mode='i'
endif
" Functions {{{1
" Increment and Decrement The Priority
:set nf=octal,hex,alpha
function! todo#PrioritizeIncrease()
normal! 0f)h
endfunction
function! todo#PrioritizeDecrease()
normal! 0f)h
endfunction
function! todo#PrioritizeAdd (priority)
let oldpos=getcurpos()
let line=getline('.')
if line !~ '^([A-F])'
:call todo#PrioritizeAddAction(a:priority)
let oldpos[2]+=4
else
exec ':s/^([A-F])/('.a:priority.')/'
endif
call setpos('.',oldpos)
endfunction
function! todo#PrioritizeAddAction (priority)
execute "normal! mq0i(".a:priority.") \<esc>`q"
endfunction
function! todo#RemovePriority()
:s/^(\w)\s\+//ge
endfunction
function! todo#PrependDate()
normal! 0"=strftime("%Y-%m-%d ")
P
endfunction
function! todo#ToggleMarkAsDone()
if (getline(".") =~ 'x\s*\d\{4\}')
:call todo#UnMarkAsDone()
else
:call todo#MarkAsDone()
endif
endfunction
function! todo#UnMarkAsDone()
:s/\s*x\s*\d\{4}-\d\{1,2}-\d\{1,2}\s*//g
endfunction
function! todo#MarkAsDone()
call todo#PrependDate()
normal! Ix
endfunction
function! todo#MarkAllAsDone()
:g!/^x /:call todo#MarkAsDone()
endfunction
function! s:AppendToFile(file, lines)
let l:lines = []
" Place existing tasks in done.txt at the beggining of the list.
if filereadable(a:file)
call extend(l:lines, readfile(a:file))
endif
" Append new completed tasks to the list.
call extend(l:lines, a:lines)
" Write to file.
call writefile(l:lines, a:file)
endfunction
function! todo#RemoveCompleted()
" Check if we can write to done.txt before proceeding.
let l:target_dir = expand('%:p:h')
if exists("g:TodoTxtForceDoneName")
let l:done=g:TodoTxtForceDoneName
else
let l:done=substitute(substitute(expand('%:t'),'todo','done',''),'Todo','Done','')
endif
let l:done_file = l:target_dir.'/'.l:done
echo "Writing to ".l:done_file
if !filewritable(l:done_file) && !filewritable(l:target_dir)
echoerr "Can't write to file '".l:done_file."'"
return
endif
let l:completed = []
:g/^x /call add(l:completed, getline(line(".")))|d
call s:AppendToFile(l:done_file, l:completed)
endfunction
function! todo#Sort()
" vim :sort is usually stable
" we sort first on contexts, then on projects and then on priority
if expand('%')=~'[Dd]one.*.txt'
silent! %s/\(x\s*\d\{4}\)-\(\d\{2}\)-\(\d\{2}\)/\1\2\3/g
sort n /^x\s*/
silent! %s/\(x\s*\d\{4}\)\(\d\{2}\)/\1-\2-/g
else
sort /@[a-zA-Z]*/ r
sort /+[a-zA-Z]*/ r
sort /\v\([A-Z]\)/ r
endif
endfunction
function! todo#SortDue()
silent! %s/\([dD][uU][eE]:\d\{4}\)-\(\d\{2}\)-\(\d\{2}\)/\1\2\3/g
" Sort adding entries with due dates add the beginning
sort n /[dD][uU][eE]:/
" Count the number of lines
silent normal gg
execute "/[dD][uU][eE]:"
let l:first=getpos(".")[1]
silent normal N
let l:last=getpos(".")[1]
let l:diff=l:last-l:first+1
" Put the sorted lines at the beginning of the file
execute ':'.l:first
execute ':d'.l:diff
silent normal gg
silent normal P
silent! %s/\([dD][uU][eE]:\d\{4}\)\(\d\{2}\)/\1-\2-/g
" TODO: add time sorting (YYYY-MM-DD HH:MM)
endfunction
" This is a Hierarchical sort designed for todo.txt todo lists, however it
" might be used for other files types
" At the first level, lines are sorted by the word right after the first
" occurence of a:symbol, there must be no space between the symbol and the
" word. At the second level, the same kind of sort is done based on
" a:symbolsub, is a:symbol==' ', the second sort doesn't occurs
" Therefore, according to todo.txt syntaxt, if
" a:symbol is a '+' it sort by the first project
" a:symbol is an '@' it sort by the first context
" The last level of sort is done directly on the line, so according to
" todo.txt syntax, it means by priority. This sort is done if and only if the
" las argument is not 0
function! todo#HierarchicalSort(symbol, symbolsub, dolastsort)
if v:statusmsg =~ '--No lines in buffer--'
"Empty buffer do nothing
return
endif
"if the sort modes doesn't start by '!' it must start with a space
let l:sortmode=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_first_level_sort_mode)
let l:sortmodesub=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_second_level_sort_mode)
let l:sortmodefinal=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_third_level_sort_mode)
" Count the number of lines
let l:position= getpos(".")
execute "silent normal g\<c-g>"
let l:linecount=str2nr(split(v:statusmsg)[7])
" Get all the groups names
let l:groups=GetGroups(a:symbol,1,l:linecount)
" Sort by groups
execute 'sort'.l:sortmode.' /.\{-}\ze'.a:symbol.'/'
for l:g in l:groups
let l:pat=a:symbol.l:g.'.*$'
normal gg
" Find the beginning of the group
let l:groupBegin=search(l:pat,'c')
" Find the end of the group
let l:groupEnd=search(l:pat,'b')
" I'm too lazy to sort groups of one line
if(l:groupEnd==l:groupBegin)
continue
endif
if a:dolastsort
if( a:symbolsub!='')
" Sort by subgroups
let l:subgroups=GetGroups(a:symbolsub,l:groupBegin,l:groupEnd)
" Go before the first line of the group
" Sort the group using the second symbol
for l:sg in l:subgroups
normal gg
let l:pat=a:symbol.l:g.'.*'.a:symbolsub.l:sg.'.*$\|'.a:symbolsub.l:sg.'.*'.a:symbol.l:g.'.*$'
" Find the beginning of the subgroup
let l:subgroupBegin=search(l:pat,'c')
" Find the end of the subgroup
let l:subgroupEnd=search(l:pat,'b')
" Sort by priority
execute l:subgroupBegin.','.l:subgroupEnd.'sort'.l:sortmodefinal
endfor
else
" Sort by priority
execute l:groupBegin.','.l:groupEnd.'sort'.l:sortmodefinal
endif
endif
endfor
" Restore the cursor position
call setpos('.', position)
endfunction
" Returns the list of groups starting by a:symbol between lines a:begin and
" a:end
function! GetGroups(symbol,begin, end)
let l:curline=a:begin
let l:groups=[]
while l:curline <= a:end
let l:curproj=strpart(matchstr(getline(l:curline),a:symbol.'\a*'),1)
if l:curproj != "" && index(l:groups,l:curproj) == -1
let l:groups=add(l:groups , l:curproj)
endif
let l:curline += 1
endwhile
return l:groups
endfunction
" Insert a space if needed (the first char isn't '!' or ' ') in front of
" sort parameters
function! Todo_txt_InsertSpaceIfNeeded(str)
let l:c=strpart(a:str,1,1)
if( l:c != '!' && l:c !=' ')
return " ".a:str
endif
retur a:str
endfunction
" Completion {{{1
" Simple keyword completion on all buffers {{{2
function! TodoKeywordComplete(base)
" Search for matchs
let res = []
for bufnr in range(1,bufnr('$'))
let lines=getbufline(bufnr,1,"$")
for line in lines
if line =~ a:base
" init temporary item
let item={}
let item.word=substitute(line,'.*\('.a:base.'\S*\).*','\1',"")
call add(res,item)
endif
endfor
endfor
return res
endfunction
" Intelligent completion for projects and Contexts {{{2
fun! todo#Complete(findstart, base)
if a:findstart
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] !~ '\s'
let start -= 1
endwhile
return start
else
if a:base !~ '^+' && a:base !~ '^@'
return TodoKeywordComplete(a:base)
endif
" Opposite sign
let opp=a:base=~'+'?'@':'+'
" Search for matchs
let res = []
for bufnr in range(1,bufnr('$'))
let lines=getbufline(bufnr,1,"$")
for line in lines
if line =~ "[x\s0-9\-]*([a-Z]).* ".a:base
" init temporary item
let item={}
let item.word=substitute(line,'.*\('.a:base.'\S*\).*','\1',"")
let item.buffers=bufname(bufnr)
let item.related=substitute(line,'.*\s\('.opp.'\S\S*\).*','\1',"")
call add(res,item)
endif
endfor
endfor
call sort(res)
" Here all results are sorted in res, but we need to merge them
let ret=[]
if res != []
let curitem={}
let curitem.word=res[0].word
let curitem.related=[]
let curitem.buffers=[]
for it in res
if curitem.word==it.word
" Merge results
if index(curitem.related,it.related) <0
call add(curitem.related,it.related)
endif
if index(curitem.buffers,it.buffers) <0
call add(curitem.buffers,it.buffers)
endif
else
" Create the definitive item
let resitem={}
let resitem.word=curitem.word
let resitem.info=opp=='+'?"Projects":"Contexts"
let resitem.info.=": ".join(curitem.related, ", ")
\."\nBuffers: ".join(curitem.buffers, ", ")
call add(ret,resitem)
" Init new item from it
let curitem.word=it.word
let curitem.related=[it.related]
let curitem.buffers=[it.buffers]
endif
endfor
endif
return ret
endif
endfun

View File

@@ -1,5 +1,8 @@
*todo.txt* *todo.txt*
Note: Since v0.7.3, `TodoComplete` is `todo#Complete`, you might need to
update your vimrc.
============================================================================== ==============================================================================
COMMANDS *todo-commands* COMMANDS *todo-commands*
@@ -70,8 +73,8 @@ For more information on the available flags see help :sort
We also provide a nice complete function for project and context, to use it We also provide a nice complete function for project and context, to use it
add the following lines to your vimrc: add the following lines to your vimrc:
> >
" Use TodoComplete as the omni complete for todo files " Use todo#Completete as the omni complete for todo files
au filetype todo setlocal omnifunc=TodoComplete au filetype todo setlocal omnifunc=todo#Complete
< <
You can also start automatically the completion when entering '+' or '@' by You can also start automatically the completion when entering '+' or '@' by
@@ -93,7 +96,7 @@ For more explanations, see |todo-flexibleFileNaming|
=============================================================================== ===============================================================================
COMPLETION *todo-complete* COMPLETION *todo-complete*
The TodoComplete function is designed to complete projects (starting by '+') The `todo#Complete`te function is designed to complete projects (starting by '+')
and context (starting by '@'). If you use it on a regular word, it will do a and context (starting by '@'). If you use it on a regular word, it will do a
normal keyword completion (on all buffers). normal keyword completion (on all buffers).
If you try to complete a project, it will propose all projects in all open If you try to complete a project, it will propose all projects in all open

View File

@@ -4,6 +4,7 @@
" License: Vim license " License: Vim license
" Website: http://github.com/dbeniamine/todo.txt-vim " Website: http://github.com/dbeniamine/todo.txt-vim
" Version: 0.7.2 " Version: 0.7.2
" vim: ts=4 sw=4 :help tw=78 cc=80
" Save context {{{1 " Save context {{{1
let s:save_cpo = &cpo let s:save_cpo = &cpo
@@ -16,110 +17,27 @@ set cpo&vim
setlocal textwidth=0 setlocal textwidth=0
setlocal wrapmargin=0 setlocal wrapmargin=0
" Functions {{{1
function! s:TodoTxtRemovePriority()
:s/^(\w)\s\+//ge
endfunction
function! TodoTxtPrependDate()
normal! 0"=strftime("%Y-%m-%d ")
P
endfunction
function! TodoTxtToggleMarkAsDone()
if (getline(".") =~ 'x\s*\d\{4\}')
:call TodoTxtUnMarkAsDone()
else
:call TodoTxtMarkAsDone()
endif
endfunction
function! TodoTxtUnMarkAsDone()
:s/\s*x\s*\d\{4}-\d\{1,2}-\d\{1,2}\s*//g
endfunction
function! TodoTxtMarkAsDone()
call TodoTxtPrependDate()
normal! Ix
endfunction
function! TodoTxtMarkAllAsDone()
:g!/^x /:call TodoTxtMarkAsDone()
endfunction
function! s:AppendToFile(file, lines)
let l:lines = []
" Place existing tasks in done.txt at the beggining of the list.
if filereadable(a:file)
call extend(l:lines, readfile(a:file))
endif
" Append new completed tasks to the list.
call extend(l:lines, a:lines)
" Write to file.
call writefile(l:lines, a:file)
endfunction
function! TodoTxtRemoveCompleted()
" Check if we can write to done.txt before proceeding.
let l:target_dir = expand('%:p:h')
if exists("g:TodoTxtForceDoneName")
let l:done=g:TodoTxtForceDoneName
else
let l:done=substitute(substitute(expand('%:t'),'todo','done',''),'Todo','Done','')
endif
let l:done_file = l:target_dir.'/'.l:done
echo "Writing to ".l:done_file
if !filewritable(l:done_file) && !filewritable(l:target_dir)
echoerr "Can't write to file '".l:done_file."'"
return
endif
let l:completed = []
:g/^x /call add(l:completed, getline(line(".")))|d
call s:AppendToFile(l:done_file, l:completed)
endfunction
function! TodoTxtSort()
" vim :sort is usually stable
" we sort first on contexts, then on projects and then on priority
if expand('%')=~'[Dd]one.*.txt'
silent! %s/\(x\s*\d\{4}\)-\(\d\{2}\)-\(\d\{2}\)/\1\2\3/g
sort n /^x\s*/
silent! %s/\(x\s*\d\{4}\)\(\d\{2}\)/\1-\2-/g
else
sort /@[a-zA-Z]*/ r
sort /+[a-zA-Z]*/ r
sort /\v\([A-Z]\)/ r
endif
endfunction
function! TodoTxtSortDue()
silent! %s/\([dD][uU][eE]:\d\{4}\)-\(\d\{2}\)-\(\d\{2}\)/\1\2\3/g
" Sort adding entries with due dates add the beginning
sort n /[dD][uU][eE]:/
" Count the number of lines
silent normal gg
execute "/[dD][uU][eE]:"
let l:first=getpos(".")[1]
silent normal N
let l:last=getpos(".")[1]
let l:diff=l:last-l:first+1
" Put the sorted lines at the beginning of the file
execute ':'.l:first
execute ':d'.l:diff
silent normal gg
silent normal P
silent! %s/\([dD][uU][eE]:\d\{4}\)\(\d\{2}\)/\1-\2-/g
" TODO: add time sorting (YYYY-MM-DD HH:MM)
endfunction
" Mappings {{{1 " Mappings {{{1
" Sort todo by (first) context
if !hasmapto("<localleader>sc",'n')
noremap <silent><localleader>sc :call todo#HierarchicalSort('@', '', 1)<CR>
endif
if !hasmapto("<localleader>scp",'n')
noremap <silent><localleader>scp :call todo#HierarchicalSort('@', '+', 1)<CR>
endif
" Sort todo by (first) project
if !hasmapto("<localleader>sp",'n')
noremap <silent><localleader>sp :call todo#HierarchicalSort('+', '',1)<CR>
endif
if !hasmapto("<localleader>spc",'n')
noremap <silent><localleader>spc :call todo#HierarchicalSort('+', '@',1)<CR>
endif
" Sort tasks {{{2 " Sort tasks {{{2
if !hasmapto("<localleader>s",'n') if !hasmapto("<localleader>s",'n')
if !hasmapto("<localleader>s",'n') nnoremap <script> <silent> <buffer> <LocalLeader>s :call todo#Sort()<CR>
endif endif
if !hasmapto("<LocalLeader>s@",'n') if !hasmapto("<LocalLeader>s@",'n')
@@ -130,82 +48,55 @@ if !hasmapto("<LocalLeader>s+",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>s+ :sort /.\{-}\ze+/ <CR> nnoremap <script> <silent> <buffer> <LocalLeader>s+ :sort /.\{-}\ze+/ <CR>
endif endif
" Increment and Decrement The Priority
:set nf=octal,hex,alpha
function! TodoTxtPrioritizeIncrease()
normal! 0f)h
endfunction
function! TodoTxtPrioritizeDecrease()
normal! 0f)h
endfunction
function! TodoTxtPrioritizeAdd (priority)
let oldpos=getcurpos()
let line=getline('.')
if line !~ '^([A-F])'
:call TodoTxtPrioritizeAddAction(a:priority)
let oldpos[2]+=4
else
exec ':s/^([A-F])/('.a:priority.')/'
endif
call setpos('.',oldpos)
endfunction
function! TodoTxtPrioritizeAddAction (priority)
execute "normal! mq0i(".a:priority.") \<esc>`q"
endfunction
if !hasmapto("<LocalLeader>j",'n') if !hasmapto("<LocalLeader>j",'n')
if !hasmapto("<LocalLeader>j",'n') nnoremap <script> <silent> <buffer> <LocalLeader>j :call todo#PrioritizeIncrease()<CR>
endif endif
if !hasmapto("<LocalLeader>j",'v') if !hasmapto("<LocalLeader>j",'v')
if !hasmapto("<LocalLeader>j",'v') vnoremap <script> <silent> <buffer> <LocalLeader>j :call todo#PrioritizeIncrease()<CR>
endif endif
if !hasmapto("<LocalLeader>k",'n') if !hasmapto("<LocalLeader>k",'n')
if !hasmapto("<LocalLeader>k",'n') nnoremap <script> <silent> <buffer> <LocalLeader>k :call todo#PrioritizeDecrease()<CR>
endif endif
if !hasmapto("<LocalLeader>k",'v') if !hasmapto("<LocalLeader>k",'v')
if !hasmapto("<LocalLeader>k",'v') vnoremap <script> <silent> <buffer> <LocalLeader>k :call todo#PrioritizeDecrease()<CR>
endif endif
if !hasmapto("<LocalLeader>a",'n') if !hasmapto("<LocalLeader>a",'n')
if !hasmapto("<LocalLeader>a",'n') nnoremap <script> <silent> <buffer> <LocalLeader>a :call todo#PrioritizeAdd('A')<CR>
endif endif
if !hasmapto("<LocalLeader>a",'i') if !hasmapto("<LocalLeader>a",'i')
if !hasmapto("<LocalLeader>a",'i') inoremap <script> <silent> <buffer> <LocalLeader>a <ESC>:call todo#PrioritizeAdd('A')<CR>i
endif endif
if !hasmapto("<LocalLeader>a",'v') if !hasmapto("<LocalLeader>a",'v')
if !hasmapto("<LocalLeader>a",'v') vnoremap <script> <silent> <buffer> <LocalLeader>a :call todo#PrioritizeAdd('A')<CR>
endif endif
if !hasmapto("<LocalLeader>b",'n') if !hasmapto("<LocalLeader>b",'n')
if !hasmapto("<LocalLeader>b",'n') nnoremap <script> <silent> <buffer> <LocalLeader>b :call todo#PrioritizeAdd('B')<CR>
endif endif
if !hasmapto("<LocalLeader>b",'i') if !hasmapto("<LocalLeader>b",'i')
if !hasmapto("<LocalLeader>b",'i') inoremap <script> <silent> <buffer> <LocalLeader>b <ESC>:call todo#PrioritizeAdd('B')<CR>i
endif endif
if !hasmapto("<LocalLeader>b",'v') if !hasmapto("<LocalLeader>b",'v')
if !hasmapto("<LocalLeader>b",'v') vnoremap <script> <silent> <buffer> <LocalLeader>b :call todo#PrioritizeAdd('B')<CR>
endif endif
if !hasmapto("<LocalLeader>c",'n') if !hasmapto("<LocalLeader>c",'n')
if !hasmapto("<LocalLeader>c",'n') nnoremap <script> <silent> <buffer> <LocalLeader>c :call todo#PrioritizeAdd('C')<CR>
endif endif
if !hasmapto("<LocalLeader>c",'i') if !hasmapto("<LocalLeader>c",'i')
if !hasmapto("<LocalLeader>c",'i') inoremap <script> <silent> <buffer> <LocalLeader>c <ESC>:call todo#PrioritizeAdd('C')<CR>i
endif endif
if !hasmapto("<LocalLeader>c",'v') if !hasmapto("<LocalLeader>c",'v')
if !hasmapto("<LocalLeader>c",'v') vnoremap <script> <silent> <buffer> <LocalLeader>c :call todo#PrioritizeAdd('C')<CR>
endif endif
" Insert date {{{2 " Insert date {{{2
@@ -222,35 +113,35 @@ if !hasmapto("DUE:",'i')
endif endif
if !hasmapto("<localleader>d",'n') if !hasmapto("<localleader>d",'n')
if !hasmapto("<localleader>d",'n') nnoremap <script> <silent> <buffer> <localleader>d :call todo#PrependDate()<CR>
endif endif
if !hasmapto("<localleader>d",'v') if !hasmapto("<localleader>d",'v')
if !hasmapto("<localleader>d",'v') vnoremap <script> <silent> <buffer> <localleader>d :call todo#PrependDate()<CR>
endif endif
" Mark done {{{2 " Mark done {{{2
if !hasmapto("<localleader>x",'n') if !hasmapto("<localleader>x",'n')
if !hasmapto("<localleader>x",'n') nnoremap <script> <silent> <buffer> <localleader>x :call todo#ToggleMarkAsDone()<CR>
endif endif
if !hasmapto("<localleader>x",'v') if !hasmapto("<localleader>x",'v')
if !hasmapto("<localleader>x",'v') vnoremap <script> <silent> <buffer> <localleader>x :call todo#ToggleMarkAsDone()<CR>
endif endif
" Mark all done {{{2 " Mark all done {{{2
if !hasmapto("<localleader>X",'n') if !hasmapto("<localleader>X",'n')
if !hasmapto("<localleader>X",'n') nnoremap <script> <silent> <buffer> <localleader>X :call todo#MarkAllAsDone()<CR>
endif endif
" Remove completed {{{2 " Remove completed {{{2
if !hasmapto("<localleader>D",'n') if !hasmapto("<localleader>D",'n')
if !hasmapto("<localleader>D",'n') nnoremap <script> <silent> <buffer> <localleader>D :call todo#RemoveCompleted()<CR>
endif endif
" Sort by due: date {{{2 " Sort by due: date {{{2
if !hasmapto("<localleader>sd".'n') if !hasmapto("<localleader>sd".'n')
if !hasmapto("<localleader>sd".'n') nnoremap <script> <silent> <buffer> <localleader>sd :call todo#SortDue()<CR>
endif endif
" Folding {{{1 " Folding {{{1
@@ -281,91 +172,6 @@ function! TodoFoldText()
\ . ' Completed tasks ' \ . ' Completed tasks '
endfunction endfunction
" Simple keyword completion on all buffers
function! TodoKeywordComplete(base)
" Search for matchs
let res = []
for bufnr in range(1,bufnr('$'))
let lines=getbufline(bufnr,1,"$")
for line in lines
if line =~ a:base
" init temporary item
let item={}
let item.word=substitute(line,'.*\('.a:base.'\S*\).*','\1',"")
call add(res,item)
endif
endfor
endfor
return res
endfunction
" Intelligent completion for projects and Contexts
fun! TodoComplete(findstart, base)
if a:findstart
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] !~ '\s'
let start -= 1
endwhile
return start
else
if a:base !~ '^+' && a:base !~ '^@'
return TodoKeywordComplete(a:base)
endif
" Opposite sign
let opp=a:base=~'+'?'@':'+'
" Search for matchs
let res = []
for bufnr in range(1,bufnr('$'))
let lines=getbufline(bufnr,1,"$")
for line in lines
if line =~ "[x\s0-9\-]*([a-Z]).* ".a:base
" init temporary item
let item={}
let item.word=substitute(line,'.*\('.a:base.'\S*\).*','\1',"")
let item.buffers=bufname(bufnr)
let item.related=substitute(line,'.*\s\('.opp.'\S\S*\).*','\1',"")
call add(res,item)
endif
endfor
endfor
call sort(res)
" Here all results are sorted in res, but we need to merge them
let ret=[]
if res != []
let curitem={}
let curitem.word=res[0].word
let curitem.related=[]
let curitem.buffers=[]
for it in res
if curitem.word==it.word
" Merge results
if index(curitem.related,it.related) <0
call add(curitem.related,it.related)
endif
if index(curitem.buffers,it.buffers) <0
call add(curitem.buffers,it.buffers)
endif
else
" Create the definitive item
let resitem={}
let resitem.word=curitem.word
let resitem.info=opp=='+'?"Projects":"Contexts"
let resitem.info.=": ".join(curitem.related, ", ")
\."\nBuffers: ".join(curitem.buffers, ", ")
call add(ret,resitem)
" Init new item from it
let curitem.word=it.word
let curitem.related=[it.related]
let curitem.buffers=[it.buffers]
endif
endfor
endif
return ret
endif
endfun
" Restore context {{{1 " Restore context {{{1
let &cpo = s:save_cpo let &cpo = s:save_cpo
" Modeline {{{1 " Modeline {{{1
" Modeline {{{1

View File

@@ -1,130 +0,0 @@
" File: todo.txt.vim
" Description: Todo.txt sorting plugin
" Author: David Beniamine <david@beniamine.net>
" Licence: Vim licence
" Website: http://github.com/dbeniamine/todo.txt.vim
" Version: 0.7.2
" vim: ts=4 sw=4 :help tw=78 cc=80
" These two variables are parameters for the successive calls the vim sort
" '' means no flags
" '! i' means reverse and ignore case
" for more information on flags, see :help sort
if (! exists("g:Todo_txt_first_level_sort_mode"))
let g:Todo_txt_first_level_sort_mode='i'
endif
if (! exists("g:Todo_txt_second_level_sort_mode"))
let g:Todo_txt_second_level_sort_mode='i'
endif
if (! exists("g:Todo_txt_third_level_sort_mode"))
let g:Todo_txt_third_level_sort_mode='i'
endif
" Sort todo by (first) context
if !hasmapto("<localleader>sc",'n')
noremap <localleader>sc :call Todo_txt_HierarchicalSort('@', '', 1)<CR>
endif
if !hasmapto("<localleader>scp",'n')
noremap <localleader>scp :call Todo_txt_HierarchicalSort('@', '+', 1)<CR>
endif
" Sort todo by (first) project
if !hasmapto("<localleader>sp",'n')
noremap <localleader>sp :call Todo_txt_HierarchicalSort('+', '',1)<CR>
endif
if !hasmapto("<localleader>spc",'n')
noremap <localleader>spc :call Todo_txt_HierarchicalSort('+', '@',1)<CR>
endif
" This is a Hierarchical sort designed for todo.txt todo lists, however it
" might be used for other files types
" At the first level, lines are sorted by the word right after the first
" occurence of a:symbol, there must be no space between the symbol and the
" word. At the second level, the same kind of sort is done based on
" a:symbolsub, is a:symbol==' ', the second sort doesn't occurs
" Therefore, according to todo.txt syntaxt, if
" a:symbol is a '+' it sort by the first project
" a:symbol is an '@' it sort by the first context
" The last level of sort is done directly on the line, so according to
" todo.txt syntax, it means by priority. This sort is done if and only if the
" las argument is not 0
function! Todo_txt_HierarchicalSort(symbol, symbolsub, dolastsort)
if v:statusmsg =~ '--No lines in buffer--'
"Empty buffer do nothing
return
endif
"if the sort modes doesn't start by '!' it must start with a space
let l:sortmode=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_first_level_sort_mode)
let l:sortmodesub=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_second_level_sort_mode)
let l:sortmodefinal=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_third_level_sort_mode)
" Count the number of lines
let l:position= getpos(".")
execute "silent normal g\<c-g>"
let l:linecount=str2nr(split(v:statusmsg)[7])
" Get all the groups names
let l:groups=GetGroups(a:symbol,1,l:linecount)
" Sort by groups
execute 'sort'.l:sortmode.' /.\{-}\ze'.a:symbol.'/'
for l:g in l:groups
let l:pat=a:symbol.l:g.'.*$'
normal gg
" Find the beginning of the group
let l:groupBegin=search(l:pat,'c')
" Find the end of the group
let l:groupEnd=search(l:pat,'b')
" I'm too lazy to sort groups of one line
if(l:groupEnd==l:groupBegin)
continue
endif
if a:dolastsort
if( a:symbolsub!='')
" Sort by subgroups
let l:subgroups=GetGroups(a:symbolsub,l:groupBegin,l:groupEnd)
" Go before the first line of the group
" Sort the group using the second symbol
for l:sg in l:subgroups
normal gg
let l:pat=a:symbol.l:g.'.*'.a:symbolsub.l:sg.'.*$\|'.a:symbolsub.l:sg.'.*'.a:symbol.l:g.'.*$'
" Find the beginning of the subgroup
let l:subgroupBegin=search(l:pat,'c')
" Find the end of the subgroup
let l:subgroupEnd=search(l:pat,'b')
" Sort by priority
execute l:subgroupBegin.','.l:subgroupEnd.'sort'.l:sortmodefinal
endfor
else
" Sort by priority
execute l:groupBegin.','.l:groupEnd.'sort'.l:sortmodefinal
endif
endif
endfor
" Restore the cursor position
call setpos('.', position)
endfunction
" Returns the list of groups starting by a:symbol between lines a:begin and
" a:end
function! GetGroups(symbol,begin, end)
let l:curline=a:begin
let l:groups=[]
while l:curline <= a:end
let l:curproj=strpart(matchstr(getline(l:curline),a:symbol.'\a*'),1)
if l:curproj != "" && index(l:groups,l:curproj) == -1
let l:groups=add(l:groups , l:curproj)
endif
let l:curline += 1
endwhile
return l:groups
endfunction
" Insert a space if needed (the first char isn't '!' or ' ') in front of
" sort parameters
function! Todo_txt_InsertSpaceIfNeeded(str)
let l:c=strpart(a:str,1,1)
if( l:c != '!' && l:c !=' ')
return " ".a:str
endif
retur a:str
endfunction