7 Commits

Author SHA1 Message Date
David Beniamine
3089527c71 Documentation re written
Cleaner documentation
2015-09-22 16:59:36 +02:00
David Beniamine
7fdf0427a8 use <localleader>C for cancel as c is used for priority 2015-09-22 15:46:09 +02:00
David Beniamine
644b6d6628 Cancel tasks with <localleader>c 2015-09-16 17:02:42 +02:00
David Beniamine
d3b011b718 Vizardry install 2015-09-16 16:22:37 +02:00
David Beniamine
f9715af4a4 move hierarchical sort to auto start
Note: because of this, TodoComplete is now known as todo#Complete, you might
need to update your vimrc.
2015-08-22 18:39:59 +02:00
David Beniamine
ab4ecf5220 FIX: sort done.txt 2015-07-08 11:04:55 +02:00
David Beniamine
dc4bb8e856 Fix: vimscript is not bash 2015-07-08 11:00:54 +02:00
5 changed files with 778 additions and 573 deletions

View File

@@ -1,90 +1,139 @@
# Readme
# Todo.txt-vim
## What is this plugin ?
##### # #
# #### ##### #### ##### # # ##### # # # # #
# # # # # # # # # # # # # # ## ##
# # # # # # # # ## # ### # # # # ## #
# # # # # # # # ## # # # # # #
# # # # # # # ## # # # # # # # # #
# #### ##### #### ## # # # # # # # #
Efficient Todo.txt management in vim
## Table of Contents
1. [Release notes](#release-notes)
2. [Introduction](#introduction)
1. [Todo.txt rules](#todo.txt-rules)
2. [Why this Fork ?](#Why-this-fork-?)
3. [Installation](#installation)
3. [TodoTxt Files](#todotxt-files)
4. [Completion](#completion)
5. [Hierarchical Sort](#hierarchical-sort)
6. [Mappings](#mappings)
1. [Sort](#sort)
2. [Priorities](#priorities)
3. [Dates](#dates)
4. [Done](#done)
## Release notes
Since v0.7.3, `TodoComplete` is replaced by `todo#Complete`, you might need to
update your vimrc (see [completion](#completion)).
## Introduction
Todo.txt-vim is a plugin to manage todo.txt files it was initially designed by
[Freitass](https://github.com/freitass/todo.txt-vim) then forked and improved
by David Beniamine.
### Todo.txt rules
Todo.txt is a standard human readable todo notes file defined [here](http://todotxt.com):
"The todo.txt format is a simple set of
[rules](https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format)
that make todo.txt both human and machine-readable. The format supports
priorities, creation and completion dates, projects and contexts. That's
all you need to be productive. See an example Todo.txt file":
(A) Call Mom @Phone +Family
(A) Schedule annual checkup +Health
(B) Outline chapter 5 +FamilyNovel @Computer
(C) Add cover sheets @ComputerOffice +FamilyTPSReports
Plan backyard herb garden @ComputerHome
Pick up milk @ComputerGroceryStore
Research self-publishing services +FamilyNovel @ComputerComputer
x Download Todo.txt mobile app @ComputerPhone
### Why this fork ?
This plugin is a fork of [freitass
todo.txt](https://github.com/freitass/todo.txt-vim). It add severals
functionalities including a [hierarchical sort](#sort), a
[complete](#completion) function, some stuff to handle [due
dates](#due-dates), a more [flexible file naming](#flexible-file-naming), and
others stuff see [new features](#new-features).
todo.txt-vim](https://github.com/freitass/todo.txt-vim). It add severals cool
functionalities including:
Freitass announced on october 30th 2014 that he is not going to merge his version.
+ [Hierarchical sort](##hierarchical-sort)
+ [A completion function](#completion)
+ [A proper handling of due dates](#dates)
+ [A Flexible file naming](#todotxt-files).
+ Syntax Highlight for couples key:value.
+ `<LocalLeader>x` is a toggle which allow you to unmark a task as done.
+ `<LocalLeader>C` Toggle Mark a task cancelled
+ If the current buffer is a done.txt file, the basic sort sorts on
completion date.
+ ...
## Install
### Installation
### Quick install
#### Vizardry
git clone https://github.com/dbeniamine/todo.txt-vim.git
cd todo.txt-vim
cp -r ./* ~/.vim
If you have [Vizardry](https://github.com/dbeniamine/vizardry) installed,
you can run from vim:
:Invoke -u dbeniamine todo.txt-vim
#### Pathogen install
git clone https://github.com/dbeniamine/todo.txt-vim.git ~/.vim/bundle/todo.txt-vim
Then from vim: `:Helptags` to update the doc
#### Quick install
git clone https://github.com/dbeniamine/todo.txt-vim.git
cd todo.txt-vim
cp -r ./* ~/.vim
If you want the help installed, run `:helptags ~/.vim/doc` inside vim after
having copied the files. Then you will be able to get the commands help with:
`:h todo.txt`
### Pathogen install
## TodoTxt Files
git clone https://github.com/dbeniamine/todo.txt-vim.git ~/.vim/bundle/todo.txt-vim
This plugin provides a Flexible file naming for todo.txt, all the following
names are recognized as todo:
Then from vim: `:Helptags` to update the doc
YYYY-MM-[Tt]odo.txt
YYYY-MM-DD[Tt]odo.txt
[Tt]odo-YYYY-MM.txt
[Tt]odo-YYYY-MM-DD.txt
[Tt]odo.txt
[Tt]oday.txt
## Features included in Freitass version
And obviously the same are recognize as done:
This plugin gives syntax highlighting to [todo.txt](http://todotxt.com/) files. It also defines a few mappings, to help with editing these files:
YYYY-MM-[Dd]one.txt
YYYY-MM-DD[Dd]one.txt
[Dd]one-YYYY-MM.txt
[Dd]one-YYYY-MM-DD.txt
[Dd]one.txt
[Dd]one-[Tt]oday.txt
`<LocalLeader>s` : Sort the file
Moreover, `<LocalLeader>D` moves the task under the cursor to the done.txt
file corresponding to the current todo.txt, aka if you are editing
2015-07-07-todo.txt, the done file while be 2015-07-07-done.txt. If you don't
like this behavior, you can set the default done.txt name:
`<LocalLeader>s+` : Sort the file on +Projects
let g:TodoTxtForceDoneName='done.txt'
`<LocalLeader>s@` : Sort the file on @Contexts
## Completion
`<LocalLeader>j` : Lower the priority of the current line
This plugin provides a nice complete function for project and context, to use
it add the following lines to your vimrc:
`<LocalLeader>k` : Increase the priority of the current line
`<LocalLeader>a` : Add the priority (A) to the current line
`<LocalLeader>b` : Add the priority (B) to the current line
`<LocalLeader>c` : Add the priority (C) to the current line
`<LocalLeader>d` : Insert the current date
`date<tab>` : (Insert mode) Insert the current date
`<LocalLeader>x` : Toggle mark task as done (inserts current date as completion date)
`<LocalLeader>X` : Mark all tasks as completed
`<leader>-D` : Move completed tasks to done.txt
## New features
### Sort
This fork provides a hierarchical sorting function designed to do by project
and/or by context sorts and a priority sort.
`<LocalLeader>sc` : Sort the file by context then by priority
`<LocalLeader>scp` : Sort the file by context, project then by priority
`<LocalLeader>sp` : Sort the file by project then by priority
`<LocalLeader>spc` : Sort the file by project, context then by priority
The user can give argument for the two call to vim sort function by changing
the following variables in its vimrc:
see :help sort
let g:Todo_txt_first_level_sort_mode="! i"
let g:Todo_txt_second_level_sort_mode="i"
### Completion
We also provide a nice complete function for project and context, to use it
add the following lines to your vimrc:
" Use TodoComplete as the omni complete function for todo files
au filetype todo setlocal omnifunc=TodoComplete
" Use todo#complete as the omni complete function for todo files
au filetype todo setlocal omnifunc=todo#complete
You can also start automatically the completion when entering '+' or '@' by
adding the next lines to your vimrc:
@@ -95,66 +144,80 @@ adding the next lines to your vimrc:
" Auto complete contexts
au filetype todo imap <buffer> @ @<C-X><C-O>
The TodoComplete function is designed to complete projects (starting by '+')
and context (starting by '@'). If you use it on a regular word, it will do a
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
normal keyword completion (on all buffers).
If you try to complete a project, it will propose all projects in all open
buffers and for each of them, it will show their context and the name of the
buffers in which they appears in the preview window.
TodoCompelte does the same thing for context except that it gives in the
preview the list of projects existing in each existing contexts.
buffers in which they appears in the preview window. It does the same thing
for context except that it gives in the preview the list of projects existing
in each existing contexts.
### Due dates
## Hierarchical sort
I've integrated the [work from
durcheinandr](https://github.com/durcheinandr/todo.txt-vim/) concerning due
dates + some little improvements:
This fork provides a hierarchical sorting function designed to do by project
and/or by context sorts and a priority sort.
Accorrding to the todo.txt rules, one can define due dates using `due:date` or
`DUE:date` or any other `key:value` combination. This plugins handle dates at
the format `YYYY-MM-DD` and the key `due` can be spell using any combination
of lower and upper case letters. The following mappings are provided:
`<LocalLeader>sc` : Sort the file by context then by priority
`<LocalLeader>scp` : Sort the file by context, project then by priority
`<LocalLeader>sp` : Sort the file by project then by priority
`<LocalLeader>spc` : Sort the file by project, context then by priority
`<leader>-sd` : Sort the file by due-date. Entries with a due date appears
The user can give argument for the two calls to vim sort function by changing
the following variables:
g:Todo_txt_first_level_sort_mode
g:Todo_txt_second_level_sort_mode
Defaults values are:
g:Todo_txt_first_level_sort_mode="i"
g:Todo_txt_second_level_sort_mode="i"
For more information on the available flags see `help :sort`
## Mappings
`<LocalLeader>` is \ by default, so ̀`<LocaLeader>-s` means you type \s
### Sort
+ `<LocalLeader>s` : Sort the file by priority
+ `<LocalLeader>s+` : Sort the file on `+Projects`
+ `<LocalLeader>s@` : Sort the file on `@Contexts`
+ `<LocalLeader>s@` : Sort the file on due dates
+ `<LocalLeader>sc` : Sort the file by context then by priority
+ `<LocalLeader>scp` : Sort the file by context, project then by priority
+ `<LocalLeader>sp` : Sort the file by project then by priority
+ `<LocalLeader>spc` : Sort the file by project, context then by priority
+ `<leader>-sd` : Sort the file by due-date. Entries with a due date appears
sorted by at the beginning of the file, the rest of the file is not modified.
`due:` : (Insert mode) Insert `due:` followed by the current date
### Priorities
`DUE:` : (Insert mode) Insert `DUE:` followed by the current date
+ `<LocalLeader>j` : Lower the priority of the current line
+ `<LocalLeader>k` : Increase the priority of the current line
+ `<LocalLeader>a` : Add the priority (A) to the current line
+ `<LocalLeader>b` : Add the priority (B) to the current line
+ `<LocalLeader>c` : Add the priority (C) to the current line
### Flexible File naming
### Dates
This plugin provides a Flexible file naming for todo.txt, all the following
names are recognized as todo:
+ `<LocalLeader>d` : Insert the current date
+ `date<tab>` : (Insert mode) Insert the current date
+ `due:` : (Insert mode) Insert `due:` followed by the current date
+ `DUE:` : (Insert mode) Insert `DUE:` followed by the current date
YYYY-MM-[Tt]odo.txt
YYYY-MM-DD[Tt]odo.txt
[Tt]odo-YYYY-MM.txt
[Tt]odo-YYYY-MM-DD.txt
[Tt]odo.txt
[Tt]oday.txt
### Done
And obviously the same are recognize as done:
YYYY-MM-[Dd]one.txt
YYYY-MM-DD[Dd]one.txt
[Dd]one-YYYY-MM.txt
[Dd]one-YYYY-MM-DD.txt
[Dd]one.txt
[Dd]one-[Tt]oday.txt
Moreover, remove complete tasks `<LocalLeader>D` moves the task to the
done.txt file corresponding to the current todo.txt, aka if you are editing
2015-07-07-todo.txt, the done file while be 2015-07-07-done.txt. If you don't
like this behavior, you can set the default done.txt name:
let g:TodoTxtForceDoneName='done.txt'
### Others
`<LocalLeader>x` is a toggle which allow you to unmark a task as done.
Syntax highlighting for couples key:value
If the current buffer is a done.txt file, the basic sort sorts on completion
date.
+ `<LocalLeader>x` : Toggle mark task as done (inserts or remove current
+ date as completion date)
+ `<LocalLeader>C` : Toggle mark task cancelled
+ `<LocalLeader>X` : Mark all tasks as completed
+ `<LocalLeader>D` : Move completed tasks to done file, see [TodoTxt
Files](#todotxt-files)

339
autoload/todo.vim Normal file
View File

@@ -0,0 +1,339 @@
" 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(status)
if (getline(".") =~ 'x\s*\d\{4\}')
:call todo#UnMarkAsDone(a:status)
else
:call todo#MarkAsDone(a:status)
endif
endfunction
function! todo#UnMarkAsDone(status)
if a:status==''
let pat=''
else
let pat=' '.a:status
endif
exec ':s/\s*x\s*\d\{4}-\d\{1,2}-\d\{1,2}'.pat.'\s*//g'
endfunction
function! todo#MarkAsDone(status)
if a:status!=''
exec 'normal! I'.a:status.' '
endif
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,109 +1,111 @@
*todo.txt*
*Todo.txt-vim*
==============================================================================
COMMANDS *todo-commands*
##### # #
# #### ##### #### ##### # # ##### # # # # #
# # # # # # # # # # # # # # ## ##
# # # # # # # # ## # ### # # # # ## #
# # # # # # # # ## # # # # # #
# # # # # # # ## # # # # # # # # #
# #### ##### #### ## # # # # # # # #
`<LocalLeader>s` : Sort the file by priority
Efficient Todo.txt management in vim
`<LocalLeader>s+` : Sort the file on +Projects
`<LocalLeader>s@` : Sort the file on @Contexts
`<LocalLeader>s@` : Sort the file on due dates
`<LocalLeader>sc` : Sort the file by context then by priority
`<LocalLeader>scp` : Sort the file by context, project then by priority
`<LocalLeader>sp` : Sort the file by project then by priority
`<LocalLeader>spc` : Sort the file by project, context then by priority
`<leader>-sd` : Sort the file by due-date. Entries with a due date appears
sorted by at the beginning of the file, the rest of the file is not modified.
`<LocalLeader>j` : Lower the priority of the current line
`<LocalLeader>k` : Increase the priority of the current line
`<LocalLeader>a` : Add the priority (A) to the current line
`<LocalLeader>b` : Add the priority (B) to the current line
`<LocalLeader>c` : Add the priority (C) to the current line
`<LocalLeader>d` : Insert the current date
`date<tab>` : (Insert mode) Insert the current date
`due:` : (Insert mode) Insert `due:` followed by the current date
`DUE:` : (Insert mode) Insert `DUE:` followed by the current date
`<LocalLeader>x` : Toggle mark task as done (inserts or remove current date as
completion date)
`<LocalLeader>X` : Mark all tasks as completed
`<LocalLeader>D` : Move completed tasks to done file, see |todo-flexibleFileNaming|
`<LocalLeader>` is \ by default, so ̀`<LocaLeader>-s` means you type \s
===============================================================================
CONFIGURATION *todo-configuration*
Table of Contents *TodoTxt-Contents* ~
The user can give argument for the two calls to vim sort function by changing
the following variables:
g:Todo_txt_first_level_sort_mode
g:Todo_txt_second_level_sort_mode
Defaults values are:
>
g:Todo_txt_first_level_sort_mode="i"
g:Todo_txt_second_level_sort_mode="i"
<
For more information on the available flags see help :sort
We also provide a nice complete function for project and context, to use it
add the following lines to your vimrc:
>
" Use TodoComplete as the omni complete for todo files
au filetype todo setlocal omnifunc=TodoComplete
<
You can also start automatically the completion when entering '+' or '@' by
adding the next lines to your vimrc:
>
" Auto complete projects
au filetype todo imap <buffer> + +<C-X><C-O>
" Auto complete contexts
au filetype todo imap <buffer> @ @<C-X><C-O>
<
To force completed task to be moved to a file independently from the current
file name, add the following to your vimrc:
>
let g:TodoTxtForceDoneName='done.txt'
<
For more explanations, see |todo-flexibleFileNaming|
1. Release notes.................................|TodoTxt-ReleaseNotes|
2. Introduction..................................|TodoTxt-Introduction|
2.1 Todo.txt rules...........................|TodoTxt-Rules|
2.2 Why this Fork............................|TodoTxt-Fork|
2.3 Installation.............................|TodoTxt-Installation|
3. TodoTxt Files.................................|TodoTxt-Files|
4. Completion....................................|TodoTxt-Completion|
5. Hierarchical Sort.............................|TodoTxt-HierarchicalSort|
6. Mappings......................................|TodoTxt-Mappings|
6.1 Sort.....................................|TodoTxt-Sort|
6.2 Priorities...............................|TodoTxt-Priorities|
6.3 Dates....................................|TodoTxt-Dates|
6.4 Done.txt.................................|TodoTxt-Done|
===============================================================================
COMPLETION *todo-complete*
1. Release notes *TodoTxt-ReleaseNotes* ~
The TodoComplete function is designed to complete projects (starting by '+')
and context (starting by '@'). If you use it on a regular word, it will do a
normal keyword completion (on all buffers).
If you try to complete a project, it will propose all projects in all open
buffers and for each of them, it will show their context and the name of the
buffers in which they appears in the preview window.
TodoCompelte does the same thing for context except that it gives in the
preview the list of projects existing in each existing contexts.
Since v0.7.3, `TodoComplete` is replaced by `todo#Complete`, you might need to
update your vimrc (see |TodoTxt-Completion|).
===============================================================================
FLEXIBLE FILE NAMING *todo-flexibleFileNaming*
2. Introduction *TodoTxt-Introduction* ~
Todo.txt-vim is a plugin to manage todo.txt files it was initially designed by
Freitass (https://github.com/freitass/todo.txt-vim) then forked and improved
by David Beniamine.
2.1 Todo.txt rules *TodoTxt-Rules*
Todo.txt is a standard human readable todo notes file defined here:
http://todotxt.com
"The todo.txt format is a simple set of
rules(https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format)
that make todo.txt both human and machine-readable. The format supports
priorities, creation and completion dates, projects and contexts. That's
all you need to be productive. See an example Todo.txt file":
>
(A) Call Mom @Phone +Family
(A) Schedule annual checkup +Health
(B) Outline chapter 5 +FamilyNovel @Computer
(C) Add cover sheets @ComputerOffice +FamilyTPSReports
Plan backyard herb garden @ComputerHome
Pick up milk @ComputerGroceryStore
Research self-publishing services +FamilyNovel @ComputerComputer
x Download Todo.txt mobile app @ComputerPhone
<
2.2 Why this fork ? *TodoTxt-Fork*
This plugin is a fork of freitass todo.txt-vim
(https://github.com/freitass/todo.txt-vim). It add severals cool
functionalities including:
+ Hierarchical sort: |TodoTxt-Sort| and |TodoTxt-HierarchicalSort|.
+ A completion function: |TodoTxt-Completion|.
+ A proper handling of due dates: |TodoTxt-Dates|
+ A Flexible file naming: |TodoTxt-Files|.
+ Syntax Highlight for couples key:value.
+ `<LocalLeader>x` is a toggle which allow you to unmark a task as done.
+ `<LocalLeader>C` Toggle Mark a task cancelled
+ If the current buffer is a done.txt file, the basic sort sorts on
completion date.
+ ...
2.3 Installation *TodoTxt-Installation*
+ Vizardry
If you have Vizardry(https://github.com/dbeniamine/vizardry) installed,
you can run from vim:
>
:Invoke -u dbeniamine todo.txt-vim
<
+ Pathogen install
>
git clone https://github.com/dbeniamine/todo.txt-vim.git ~/.vim/bundle/todo.txt-vim
<
Then from vim: `:Helptags` to update the doc
+ Quick install
>
git clone https://github.com/dbeniamine/todo.txt-vim.git
cd todo.txt-vim
cp -r ./* ~/.vim
<
If you want the help installed, run `:helptags ~/.vim/doc` inside vim
after having copied the files. Then you will be able to get the commands
help with: `:h todo.txt`
===============================================================================
3. TodoTxt Files *TodoTxt-Files* ~
This plugin provides a Flexible file naming for todo.txt, all the following
names are recognized as todo:
@@ -124,10 +126,124 @@ And obviously the same are recognize as done:
[Dd]one.txt
[Dd]one-[Tt]oday.txt
<
Moreover, remove complete tasks `<LocalLeader>D` moves the task to the
done.txt file corresponding to the current todo.txt, aka if you are editing
Moreover, `<LocalLeader>D` moves the task under the cursor to the done.txt
file corresponding to the current todo.txt, aka if you are editing
2015-07-07-todo.txt, the done file while be 2015-07-07-done.txt. If you don't
like this behavior, you can set the default done.txt name:
>
let g:TodoTxtForceDoneName='done.txt'
<
===============================================================================
4. Completion *TodoTxt-Completion* ~
This plugin provides a nice complete function for project and context, to use
it add the following lines to your vimrc:
>
" Use todo#complete as the omni complete function for todo files
au filetype todo setlocal omnifunc=todo#complete
<
You can also start automatically the completion when entering '+' or '@' by
adding the next lines to your vimrc:
>
" Auto complete projects
au filetype todo imap <buffer> + +<C-X><C-O>
" Auto complete contexts
au filetype todo imap <buffer> @ @<C-X><C-O>
<
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
normal keyword completion (on all buffers).
If you try to complete a project, it will propose all projects in all open
buffers and for each of them, it will show their context and the name of the
buffers in which they appears in the preview window. It does the same thing
for context except that it gives in the preview the list of projects existing
in each existing contexts.
===============================================================================
5. Hierarchical sort *TodoTxt-HierarchicalSort* ~
This fork provides a hierarchical sorting function designed to do by project
and/or by context sorts and a priority sort.
`<LocalLeader>sc` : Sort the file by context then by priority
`<LocalLeader>scp` : Sort the file by context, project then by priority
`<LocalLeader>sp` : Sort the file by project then by priority
`<LocalLeader>spc` : Sort the file by project, context then by priority
The user can give argument for the two calls to vim sort function by changing
the following variables:
>
g:Todo_txt_first_level_sort_mode
g:Todo_txt_second_level_sort_mode
<
Defaults values are:
>
g:Todo_txt_first_level_sort_mode="i"
g:Todo_txt_second_level_sort_mode="i"
<
For more information on the available flags see |:sort|
===============================================================================
6. Mappings *TodoTxt-Mappings* ~
6.1 Sort *TodoTxt-Sort*
`<LocalLeader>s` : Sort the file by priority
`<LocalLeader>s+` : Sort the file on +Projects
`<LocalLeader>s@` : Sort the file on @Contexts
`<LocalLeader>s@` : Sort the file on due dates
`<LocalLeader>sc` : Sort the file by context then by priority
`<LocalLeader>scp` : Sort the file by context, project then by priority
`<LocalLeader>sp` : Sort the file by project then by priority
`<LocalLeader>spc` : Sort the file by project, context then by priority
`<leader>-sd` : Sort the file by due-date. Entries with a due date appears
sorted by at the beginning of the file, the rest of the file is not modified.
6.2 Priorities *TodoTxt-Priorities*
`<LocalLeader>j` : Lower the priority of the current line
`<LocalLeader>k` : Increase the priority of the current line
`<LocalLeader>a` : Add the priority (A) to the current line
`<LocalLeader>b` : Add the priority (B) to the current line
`<LocalLeader>c` : Add the priority (C) to the current line
6.3 Dates *TodoTxt-Dates*
`<LocalLeader>d` : Insert the current date
`date<tab>` : (Insert mode) Insert the current date
`due:` : (Insert mode) Insert `due:` followed by the current date
`DUE:` : (Insert mode) Insert `DUE:` followed by the current date
6.4 Done *TodoTxt-Done*
`<LocalLeader>x` : Toggle mark task as done (inserts or remove current
date as completion date)
`<LocalLeader>C` : Toggle mark task cancelled
`<LocalLeader>X` : Mark all tasks as completed
`<LocalLeader>D` : Move completed tasks to done file, see |TodoTxt-Files|
`<LocalLeader>` is \ by default, so ̀`<LocaLeader>-s` means you type \s

View File

@@ -4,6 +4,7 @@
" License: Vim license
" Website: http://github.com/dbeniamine/todo.txt-vim
" Version: 0.7.2
" vim: ts=4 sw=4 :help tw=78 cc=80
" Save context {{{1
let s:save_cpo = &cpo
@@ -16,110 +17,27 @@ set cpo&vim
setlocal textwidth=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','')
fi
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 'done.txt'"
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('%')=~'done.*.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
" 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
if !hasmapto("<localleader>s",'n')
if !hasmapto("<localleader>s",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>s :call todo#Sort()<CR>
endif
if !hasmapto("<LocalLeader>s@",'n')
@@ -130,82 +48,55 @@ if !hasmapto("<LocalLeader>s+",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>s+ :sort /.\{-}\ze+/ <CR>
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')
nnoremap <script> <silent> <buffer> <LocalLeader>j :call todo#PrioritizeIncrease()<CR>
endif
if !hasmapto("<LocalLeader>j",'v')
if !hasmapto("<LocalLeader>j",'v')
vnoremap <script> <silent> <buffer> <LocalLeader>j :call todo#PrioritizeIncrease()<CR>
endif
if !hasmapto("<LocalLeader>k",'n')
if !hasmapto("<LocalLeader>k",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>k :call todo#PrioritizeDecrease()<CR>
endif
if !hasmapto("<LocalLeader>k",'v')
if !hasmapto("<LocalLeader>k",'v')
vnoremap <script> <silent> <buffer> <LocalLeader>k :call todo#PrioritizeDecrease()<CR>
endif
if !hasmapto("<LocalLeader>a",'n')
if !hasmapto("<LocalLeader>a",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>a :call todo#PrioritizeAdd('A')<CR>
endif
if !hasmapto("<LocalLeader>a",'i')
if !hasmapto("<LocalLeader>a",'i')
inoremap <script> <silent> <buffer> <LocalLeader>a <ESC>:call todo#PrioritizeAdd('A')<CR>i
endif
if !hasmapto("<LocalLeader>a",'v')
if !hasmapto("<LocalLeader>a",'v')
vnoremap <script> <silent> <buffer> <LocalLeader>a :call todo#PrioritizeAdd('A')<CR>
endif
if !hasmapto("<LocalLeader>b",'n')
if !hasmapto("<LocalLeader>b",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>b :call todo#PrioritizeAdd('B')<CR>
endif
if !hasmapto("<LocalLeader>b",'i')
if !hasmapto("<LocalLeader>b",'i')
inoremap <script> <silent> <buffer> <LocalLeader>b <ESC>:call todo#PrioritizeAdd('B')<CR>i
endif
if !hasmapto("<LocalLeader>b",'v')
if !hasmapto("<LocalLeader>b",'v')
vnoremap <script> <silent> <buffer> <LocalLeader>b :call todo#PrioritizeAdd('B')<CR>
endif
if !hasmapto("<LocalLeader>c",'n')
if !hasmapto("<LocalLeader>c",'n')
nnoremap <script> <silent> <buffer> <LocalLeader>c :call todo#PrioritizeAdd('C')<CR>
endif
if !hasmapto("<LocalLeader>c",'i')
if !hasmapto("<LocalLeader>c",'i')
inoremap <script> <silent> <buffer> <LocalLeader>c <ESC>:call todo#PrioritizeAdd('C')<CR>i
endif
if !hasmapto("<LocalLeader>c",'v')
if !hasmapto("<LocalLeader>c",'v')
vnoremap <script> <silent> <buffer> <LocalLeader>c :call todo#PrioritizeAdd('C')<CR>
endif
" Insert date {{{2
@@ -222,35 +113,46 @@ if !hasmapto("DUE:",'i')
endif
if !hasmapto("<localleader>d",'n')
if !hasmapto("<localleader>d",'n')
nnoremap <script> <silent> <buffer> <localleader>d :call todo#PrependDate()<CR>
endif
if !hasmapto("<localleader>d",'v')
if !hasmapto("<localleader>d",'v')
vnoremap <script> <silent> <buffer> <localleader>d :call todo#PrependDate()<CR>
endif
" Mark done {{{2
if !hasmapto("<localleader>x",'n')
if !hasmapto("<localleader>x",'n')
nnoremap <script> <silent> <buffer> <localleader>x :call todo#ToggleMarkAsDone('')<CR>
endif
if !hasmapto("<localleader>x",'v')
if !hasmapto("<localleader>x",'v')
vnoremap <script> <silent> <buffer> <localleader>x :call todo#ToggleMarkAsDone('')<CR>
endif
" Mark done {{{2
if !hasmapto("<localleader>C",'n')
nnoremap <script> <silent> <buffer> <localleader>C :call todo#ToggleMarkAsDone('Cancelled')<CR>
endif
if !hasmapto("<localleader>C",'v')
vnoremap <script> <silent> <buffer> <localleader>C :call todo#ToggleMarkAsDone('Cancelled')<CR>
endif
" Mark all done {{{2
if !hasmapto("<localleader>X",'n')
if !hasmapto("<localleader>X",'n')
nnoremap <script> <silent> <buffer> <localleader>X :call todo#MarkAllAsDone('')<CR>
endif
" Remove completed {{{2
if !hasmapto("<localleader>D",'n')
if !hasmapto("<localleader>D",'n')
nnoremap <script> <silent> <buffer> <localleader>D :call todo#RemoveCompleted()<CR>
endif
" Sort by due: date {{{2
if !hasmapto("<localleader>sd".'n')
if !hasmapto("<localleader>sd".'n')
nnoremap <script> <silent> <buffer> <localleader>sd :call todo#SortDue()<CR>
endif
" Folding {{{1
@@ -281,91 +183,6 @@ function! TodoFoldText()
\ . ' Completed tasks '
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
let &cpo = s:save_cpo
" 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