CHG: Hierachical sort can now have1 to 3 levels

This allow for example to sort the wall list by context, then each context by
project and each project by priority.
The sort is very flexible, the only constraint is that the sort by priority
(if we decide to do it) is the last sort.
This commit is contained in:
David Beniamine
2014-10-10 17:38:37 +02:00
parent 2f64c2ff21
commit c0a6726696

View File

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