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
" Description: Todo.txt sorting plugin
" Author: Leandro Freitas <david@beniamine.net>
" Author: David Beniamine <david@beniamine.net>
" Licence: Vim licence
" Website: http://github.com/dbeniamine/todo.txt.vim
" 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
" sort function
" 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"
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"
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
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
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
" 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 an '@' it sort by the first context
" The second level of sort is done direcetly on the line, so according to
" todo.txt syntax, it means sort by priority
function! Todo_txt_TwoLevelsSort(symbol)
"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: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>"
" 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: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=[]
while l:curline <= l:linecount
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
" 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)
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 !=' ')