13 Commits

Author SHA1 Message Date
David Beniamine
1cdb39032f Doc updated 2016-05-14 12:15:22 +02:00
David Beniamine
f3c5e7b892 Included Guilherme Victal works on overduedate
See https://github.com/freitass/todo.txt-vim/pull/45
2016-05-14 12:03:55 +02:00
David Beniamine
a21fd1198c Fix missing items in completion
FIX: This commit fix dbeniamine/todo.txt-vim#7 some the last completion item
was not added to the completion list
CHG: This commit also provide a small refactor of todo#Complete
2016-02-09 22:31:00 +01:00
David Beniamine
7515fde8ae Fix bad todo#Complete name
see issue#7
2016-02-09 20:53:58 +01:00
David Beniamine
2e2d39daee Merge branch 'patch-1' of https://github.com/ultrablue/todo.txt-vim 2015-12-18 10:31:42 +01:00
David Beniamine
a03d01e58e Get linescount in a more conventional way
This should solve issue #5 see
https://github.com/dbeniamine/todo.txt-vim/issues/5
2015-12-18 10:17:26 +01:00
David Beniamine
81c2772905 Add debug info in hierarchical sort
ADD: Debug info needed for solving issue #5
FIX: Incomplete group detection in hierarchical sort (should not impact
    issue #5)
2015-12-17 23:23:10 +01:00
David Beniamine
b6d5dc6bb9 Fix issue #6 : typo in the documentation
See https://github.com/dbeniamine/todo.txt-vim/issues/6
2015-12-17 10:56:11 +01:00
David Beniamine
f9a007ac58 Merge branch 'citec-fix_getcurpos_missing' 2015-12-08 10:52:05 +01:00
David Beniamine
45bfb325ae FIX getcurpos incompatibility with old versions
It seems that getcurpos() (used on PrioritizeAdd) appeared on vim 7.4.313
therefore using it was causing troubles to some users ...
2015-12-08 10:51:21 +01:00
David Beniamine
081d9d2e3a Merge branch 'fix_getcurpos_missing' of https://github.com/citec/todo.txt-vim into citec-fix_getcurpos_missing 2015-12-08 10:41:53 +01:00
Greg
4d819f888b Update README.markdown
It looks like there's a typo on line 136; the function appears to be todo#Complete, not todo#complete.
2015-12-02 16:49:23 -07:00
Jaime Alberto Sanchez Hidalgo
cc281c47eb FIX getcurpos invalid expression 2015-10-20 08:43:13 -02:00
25 changed files with 734 additions and 57 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
*.swp *.swp
doc/tags doc/tags
*.pyc

0
.gitmodules vendored Normal file
View File

View File

@@ -28,6 +28,15 @@
## Release notes ## Release notes
v0.7.4 includes the overduedate support from Guilherme Victal (see pull
[request #45 on freitass version](https://github.com/freitass/todo.txt-vim/pull/45)),
it highlight dates in overdue tasks as an Error. It depends on a
Python library, however, and as such will only be able to work if your version
of Vim was compiled with the `+python` option (as most common versions do).
If your Vim installation does **not** have Python support, this plugin **will work just fine** but this feature will be disabled.
Since v0.7.3, `TodoComplete` is replaced by `todo#Complete`, you might need to Since v0.7.3, `TodoComplete` is replaced by `todo#Complete`, you might need to
update your vimrc (see [completion](#completion)). update your vimrc (see [completion](#completion)).
@@ -132,8 +141,8 @@ like this behavior, you can set the default done.txt name:
This plugin provides a nice complete function for project and context, to use This plugin provides a nice complete function for project and context, to use
it add the following lines to your vimrc: it add the following lines to your vimrc:
" Use todo#complete as the omni complete function for todo files " Use todo#Complete as the omni complete function for todo files
au filetype todo setlocal omnifunc=todo#complete 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:
@@ -145,7 +154,7 @@ adding the next lines to your vimrc:
au filetype todo imap <buffer> @ @<C-X><C-O> au filetype todo imap <buffer> @ @<C-X><C-O>
The `todo#complete` 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).
@@ -196,7 +205,7 @@ prevent this behavior, add the following line to your vimrc
+ `<LocalLeader>s` : Sort the file by priority + `<LocalLeader>s` : Sort the file by priority
+ `<LocalLeader>s+` : Sort the file on `+Projects` + `<LocalLeader>s+` : Sort the file on `+Projects`
+ `<LocalLeader>s@` : Sort the file on `@Contexts` + `<LocalLeader>s@` : Sort the file on `@Contexts`
+ `<LocalLeader>s@` : Sort the file on due dates + `<LocalLeader>sd` : Sort the file on due dates
+ `<LocalLeader>sc` : Sort the file by context then by priority + `<LocalLeader>sc` : Sort the file by context then by priority
+ `<LocalLeader>scp` : Sort the file by context, project 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>sp` : Sort the file by project then by priority

View File

@@ -3,7 +3,6 @@
" Author: David Beniamine <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.7.3
" vim: ts=4 sw=4 :help tw=78 cc=80 " vim: ts=4 sw=4 :help tw=78 cc=80
" These two variables are parameters for the successive calls the vim sort " These two variables are parameters for the successive calls the vim sort
@@ -23,6 +22,14 @@ endif
" Functions {{{1 " Functions {{{1
function! todo#GetCurpos()
if exists("*getcurpos")
return getcurpos()
endif
return getpos('.')
endfunction
" Increment and Decrement The Priority " Increment and Decrement The Priority
:set nf=octal,hex,alpha :set nf=octal,hex,alpha
@@ -35,7 +42,7 @@ function! todo#PrioritizeDecrease()
endfunction endfunction
function! todo#PrioritizeAdd (priority) function! todo#PrioritizeAdd (priority)
let oldpos=getcurpos() let oldpos=todo#GetCurpos()
let line=getline('.') let line=getline('.')
if line !~ '^([A-F])' if line !~ '^([A-F])'
:call todo#PrioritizeAddAction(a:priority) :call todo#PrioritizeAddAction(a:priority)
@@ -179,16 +186,28 @@ function! todo#HierarchicalSort(symbol, symbolsub, dolastsort)
let l:sortmodesub=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_second_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) let l:sortmodefinal=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_third_level_sort_mode)
" Count the number of lines " Count the number of lines
let l:position= getpos(".") let l:position= todo#GetCurpos()
execute "silent normal g\<c-g>" execute "silent normal G"
let l:linecount=getpos(".")[1]
if(exists("g:Todo_txt_debug"))
echo "Linescount: ".l:linecount
endif
execute "silent normal gg" execute "silent normal gg"
" Get all the groups names " Get all the groups names
let l:groups=GetGroups(a:symbol,1,l:linecount)
if(exists("g:Todo_txt_debug"))
echo "Groups: "
echo l:groups
echo 'execute sort'.l:sortmode.' /.\{-}\ze'.a:symbol.'/'
endif endif
" Sort by groups " Sort by groups
execute 'sort'.l:sortmode.' /.\{-}\ze'.a:symbol.'/' execute 'sort'.l:sortmode.' /.\{-}\ze'.a:symbol.'/'
for l:g in l:groups for l:g in l:groups
let l:pat=a:symbol.l:g.'.*$'
if(exists("g:Todo_txt_debug"))
echo l:pat
endif endif
normal gg normal gg
" Find the beginning of the group " Find the beginning of the group
@@ -217,6 +236,9 @@ function! todo#HierarchicalSort(symbol, symbolsub, dolastsort)
execute l:subgroupBegin.','.l:subgroupEnd.'sort'.l:sortmodefinal execute l:subgroupBegin.','.l:subgroupEnd.'sort'.l:sortmodefinal
endfor endfor
else else
" Sort by priority
if(exists("g:Todo_txt_debug"))
echo 'execute '.l:groupBegin.','.l:groupEnd.'sort'.l:sortmodefinal
endif endif
execute l:groupBegin.','.l:groupEnd.'sort'.l:sortmodefinal execute l:groupBegin.','.l:groupEnd.'sort'.l:sortmodefinal
endif endif
@@ -231,7 +253,7 @@ function! GetGroups(symbol,begin, end)
function! GetGroups(symbol,begin, end) function! GetGroups(symbol,begin, end)
let l:curline=a:begin let l:curline=a:begin
let l:groups=[] let l:groups=[]
while l:curline <= a:end while l:curline <= a:end
let l:curproj=strpart(matchstr(getline(l:curline),a:symbol.'\S*'),1) let l:curproj=strpart(matchstr(getline(l:curline),a:symbol.'\S*'),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)
@@ -254,7 +276,7 @@ endfunction
" Completion {{{1 " Completion {{{1
" Simple keyword completion on all buffers {{{2 " Simple keyword completion on all buffers {{{2
function! TodoKeywordComplete(base) function! TodoKeywordComplete(base)
" Search for matches " Search for matches
let res = [] let res = []
for bufnr in range(1,bufnr('$')) for bufnr in range(1,bufnr('$'))
@@ -270,6 +292,25 @@ function! TodoKeywordComplete(base)
endfor endfor
return res return res
endfunction endfunction
" Convert an item to the completion format and add it to the completion list
fun! TodoAddToCompletionList(list,item,opp)
" Create the definitive item
let resitem={}
let resitem.word=a:item.word
let resitem.info=a:opp=='+'?"Projects":"Contexts"
let resitem.info.=": ".join(a:item.related, ", ")
\."\nBuffers: ".join(a:item.buffers, ", ")
call add(a:list,resitem)
endfun
fun! TodoCopyTempItem(item)
let ret={}
let ret.word=a:item.word
let ret.related=[a:item.related]
let ret.buffers=[a:item.buffers]
return ret
endfun
" Intelligent completion for projects and Contexts {{{2 " Intelligent completion for projects and Contexts {{{2
fun! todo#Complete(findstart, base) fun! todo#Complete(findstart, base)
@@ -304,10 +345,7 @@ fun! todo#Complete(findstart, base)
call sort(res) call sort(res)
" Here all results are sorted in res, but we need to merge them " Here all results are sorted in res, but we need to merge them
let ret=[] let ret=[]
if res != [] if res != []
let curitem={}
let curitem.word=res[0].word
let curitem.related=[]
let curitem=TodoCopyTempItem(res[0]) let curitem=TodoCopyTempItem(res[0])
for it in res for it in res
if curitem.word==it.word if curitem.word==it.word
@@ -318,19 +356,14 @@ fun! todo#Complete(findstart, base)
if index(curitem.buffers,it.buffers) <0 if index(curitem.buffers,it.buffers) <0
call add(curitem.buffers,it.buffers) call add(curitem.buffers,it.buffers)
endif endif
else else
" Create the definitive item " Add to list
let resitem={}
let resitem.word=curitem.word
let resitem.info=opp=='+'?"Projects":"Contexts"
let resitem.info.=": ".join(curitem.related, ", ")
\."\nBuffers: ".join(curitem.buffers, ", ")
call TodoAddToCompletionList(ret,curitem,opp) call TodoAddToCompletionList(ret,curitem,opp)
" Init new item from it " Init new item from it
let curitem.word=it.word
let curitem.related=[it.related]
let curitem=TodoCopyTempItem(it) let curitem=TodoCopyTempItem(it)
endif endif
endfor
" Don't forget to add the list item
call TodoAddToCompletionList(ret,curitem,opp) call TodoAddToCompletionList(ret,curitem,opp)
endif endif
return ret return ret

123
autoload/todo/txt.vim Normal file
View File

@@ -0,0 +1,123 @@
" File: todo.txt.vim
" Description: Todo.txt filetype detection
" Author: Leandro Freitas <freitass@gmail.com>
" License: Vim license
" Website: http://github.com/freitass/todo.txt-vim
" Version: 0.4
" Export Context Dictionary for unit testing {{{1
function! s:get_SID()
return matchstr(expand('<sfile>'), '<SNR>\d\+_')
endfunction
let s:SID = s:get_SID()
delfunction s:get_SID
function! todo#txt#__context__()
return { 'sid': s:SID, 'scope': s: }
endfunction
" Functions {{{1
function! s:remove_priority()
:s/^(\w)\s\+//ge
endfunction
function! s:get_current_date()
return strftime('%Y-%m-%d')
endfunction
function! todo#txt#prepend_date()
execute 'normal! I' . s:get_current_date() . ' '
endfunction
function! todo#txt#replace_date()
let current_line = getline('.')
if (current_line =~ '^\(([a-zA-Z]) \)\?\d\{2,4\}-\d\{2\}-\d\{2\} ') &&
\ exists('g:todo_existing_date') && g:todo_existing_date == 'n'
return
endif
execute 's/^\(([a-zA-Z]) \)\?\(\d\{2,4\}-\d\{2\}-\d\{2\} \)\?/\1' . s:get_current_date() . ' /'
endfunction
function! todo#txt#mark_as_done()
call s:remove_priority()
call todo#txt#prepend_date()
normal! Ix
endfunction
function! todo#txt#mark_all_as_done()
:g!/^x /:call todo#txt#mark_as_done()
endfunction
function! s:append_to_file(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#txt#remove_completed()
" Check if we can write to done.txt before proceeding.
let l:target_dir = expand('%:p:h')
let l:todo_file = expand('%:p')
let l:done_file = substitute(substitute(l:todo_file, 'todo.txt$', 'done.txt', ''), 'Todo.txt$', 'Done.txt', '')
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:append_to_file(l:done_file, l:completed)
endfunction
function! todo#txt#sort_by_context() range
execute a:firstline . "," . a:lastline . "sort /\\(^\\| \\)\\zs@[^[:blank:]]\\+/ r"
endfunction
function! todo#txt#sort_by_project() range
execute a:firstline . "," . a:lastline . "sort /\\(^\\| \\)\\zs+[^[:blank:]]\\+/ r"
endfunction
function! todo#txt#sort_by_date() range
let l:date_regex = "\\d\\{2,4\\}-\\d\\{2\\}-\\d\\{2\\}"
execute a:firstline . "," . a:lastline . "sort /" . l:date_regex . "/ r"
execute a:firstline . "," . a:lastline . "g!/" . l:date_regex . "/m" . a:lastline
endfunction
function! todo#txt#sort_by_due_date() range
let l:date_regex = "due:\\d\\{2,4\\}-\\d\\{2\\}-\\d\\{2\\}"
execute a:firstline . "," . a:lastline . "sort /" . l:date_regex . "/ r"
execute a:firstline . "," . a:lastline . "g!/" . l:date_regex . "/m" . a:lastline
endfunction
" Increment and Decrement The Priority
:set nf=octal,hex,alpha
function! todo#txt#prioritize_increase()
normal! 0f)h
endfunction
function! todo#txt#prioritize_decrease()
normal! 0f)h
endfunction
function! todo#txt#prioritize_add(priority)
" Need to figure out how to only do this if the first visible letter in a line is not (
:call todo#txt#prioritize_add_action(a:priority)
endfunction
function! todo#txt#prioritize_add_action(priority)
execute 's/^\(([a-zA-Z]) \)\?/(' . a:priority . ') /'
endfunction
" Modeline {{{1
" vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1

View File

@@ -31,6 +31,12 @@ Table of Contents *TodoTxt-Contents* ~
=============================================================================== ===============================================================================
1. Release notes *TodoTxt-ReleaseNotes* ~ 1. Release notes *TodoTxt-ReleaseNotes* ~
v0.7.4 includes the overduedate support from Guilherme Victal (see pull
request #45 on freitass version (https://github.com/freitass/todo.txt-vim/pull/45)),
it highlight dates in overdue tasks as an Error. It depends on a
Python library, however, and as such will only be able to work if your version
of Vim was compiled with the `+python` option (as most common versions do).
Since v0.7.3, `TodoComplete` is replaced by `todo#Complete`, you might need to Since v0.7.3, `TodoComplete` is replaced by `todo#Complete`, you might need to
update your vimrc (see |TodoTxt-Completion|). update your vimrc (see |TodoTxt-Completion|).
@@ -205,7 +211,7 @@ prevent this behavior, add the following line to your vimrc
`<LocalLeader>s@` : Sort the file on @Contexts `<LocalLeader>s@` : Sort the file on @Contexts
`<LocalLeader>s@` : Sort the file on due dates `<LocalLeader>sd` : Sort the file on due dates
`<LocalLeader>sc` : Sort the file by context then by priority `<LocalLeader>sc` : Sort the file by context then by priority

View File

@@ -3,7 +3,7 @@
" Author: David Beniamine <david@beniamine.net>, Leandro Freitas <freitass@gmail.com> " Author: David Beniamine <david@beniamine.net>, Leandro Freitas <freitass@gmail.com>
" 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 " vim: ts=4 sw=4 :help tw=78 cc=80
autocmd BufNewFile,BufRead [Tt]odo.txt set filetype=todo autocmd BufNewFile,BufRead [Tt]odo.txt set filetype=todo
autocmd BufNewFile,BufRead [Tt]odo-\d\\\{4\}-\d\\\{2\}-\d\\\{2\}.txt set filetype=todo autocmd BufNewFile,BufRead [Tt]odo-\d\\\{4\}-\d\\\{2\}-\d\\\{2\}.txt set filetype=todo

View File

@@ -3,13 +3,18 @@
" Author: David Beniamine <David@Beniamine.net>, Leandro Freitas <freitass@gmail.com> " Author: David Beniamine <David@Beniamine.net>, Leandro Freitas <freitass@gmail.com>
" 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
" vim: ts=4 sw=4 :help tw=78 cc=80 " 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
set cpo&vim set cpo&vim
if exists("g:Todo_txt_loaded")
finish
else
let g:Todo_txt_loaded=0.7.4
endif
" General options {{{1 " General options {{{1
" Some options lose their values when window changes. They will be set every " Some options lose their values when window changes. They will be set every
" time this script is invocated, which is whenever a file of this type is " time this script is invocated, which is whenever a file of this type is
@@ -96,4 +101,3 @@ endfunction
" Restore context {{{1 " Restore context {{{1
let &cpo = s:save_cpo let &cpo = s:save_cpo
" Modeline {{{1

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File: __init__.py
# Author: Guilherme Victal <guilherme at victal.eti.br>
# Description: Dateregex library entry point
# License: Vim license
# Website: http://github.com/freitass/todo.txt-vim
# Version: 0.1
from after import regex_date_after
from before import regex_date_before

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File: after.py
# Author: Guilherme Victal <guilherme at victal.eti.br>
# Description: Generates regexes after a certain date
# License: Vim license
# Website: http://github.com/freitass/todo.txt-vim
# Version: 0.1
from datetime import date, timedelta, MAXYEAR
def _year_regex_after(year):
if int(year) > MAXYEAR:
return None
year_regex = r'(\d+\d{%s}' % len(year)
for idx, digit in enumerate(year):
if digit != '9':
regex = '|' + year[0:idx]
regex += '9' if digit == '8' else '[%s-9]' % str(int(digit) + 1)
if idx < len(year) - 1:
regex += '\d{%s}' % (len(year) - (idx + 1))
year_regex += regex
year_regex += ')'
return '-'.join((year_regex, r'\d{2}', r'\d{2}'))
def _month_regex_after(year, month):
if month == '12':
return None
digit1, digit2 = month
if digit1 == '1':
month_regex = r'12' if month == '11' else r'1[12]'
else:
month_regex = r'1[0-2]'
if digit2 != '9':
if digit2 == '8':
month_regex = r'(' + month_regex + r'|09)'
else:
month_regex = r'(' + month_regex + r'|0[%s-9])'
month_regex = month_regex % str(int(digit2) + 1)
return '-'.join((year, month_regex, r'\d{2}'))
def _day_regex_after(year, month, day):
last_month_day = str((date(int(year), (int(month) + 1) % 12, 1) + - date.resolution).day)
if day == last_month_day:
return None
day_regex = r'('
digit1, digit2 = day
last_digit1, last_digit2 = last_month_day
if digit1 == last_digit1:
day_regex = last_month_day if int(digit2) == int(last_digit2) - 1 else last_digit1 + r'[%s-%s]' % (str(int(digit2) + 1), last_digit2)
else:
day_regex = r'('
day_regex += last_digit1 if int(digit1) == int(last_digit1) - 1 else r'[%s-%s]' % (str(int(digit1) + 1), last_digit1)
day_regex +=r'\d'
if digit2 < '9':
day_regex += '|' + digit1
day_regex += '9' if digit2 == '8' else r'[%s-9]' % str(int(digit2) + 1)
day_regex += ')'
return '-'.join((year, month, day_regex))
def regex_date_after(given_date):
year, month, day = given_date.isoformat().split('-')
year_regex = _year_regex_after(year)
month_regex = _month_regex_after(year, month)
day_regex = _day_regex_after(year, month, day)
date_regex = '(' + year_regex if year_regex else '('
date_regex += ('|' + month_regex) if month_regex else ''
date_regex += ('|' + day_regex) if day_regex else ''
date_regex += ')'
return date_regex
def __main():
import re
date_regex = regex_date_after(date(1999,12,31))
print(date_regex)
pattern = re.compile(date_regex)
d = date.today() + date.resolution
assert pattern.match(date.strftime(d, '%Y-%m-%d')) is not None
print(date.strftime(d, '%Y-%m-%d') + ' is okay')
d += date.resolution
if __name__ == '__main__':
__main()

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File: before.py
# Author: Guilherme Victal <guilherme at victal.eti.br>
# Description: Generates regexes before a certain date
# License: Vim license
# Website: http://github.com/freitass/todo.txt-vim
# Version: 0.1
from datetime import date, timedelta, MINYEAR
def _year_regex_before(year):
if int(year) <= MINYEAR:
return None
year_regex = r'('
year_regex += r'\d{1,%s}' % str(len(year) - 1) if len(year) > 1 else ''
for idx, digit in enumerate(year):
if digit != '0':
regex = '|' + year[0:idx]
regex += '0' if digit == '1' else '[0-%s]' % str(int(digit) - 1)
if idx < len(year) - 1:
regex += '\d{%s}' % (len(year) - (idx + 1))
year_regex += regex
year_regex += ')'
return '-'.join((year_regex, r'\d{2}', r'\d{2}'))
def _month_regex_before(year, month):
if month == '01':
return None
digit1, digit2 = month
if digit1 == '0':
month_regex = '01' if month == '02' else r'0[1-%s]' % str(int(digit2) - 1)
elif month == '10':
month_regex = r'0\d'
elif month == '11':
month_regex = r'(0\d|10)'
else:
month_regex = r'(0\d|1[01])'
return '-'.join((year, month_regex, r'\d{2}'))
def _day_regex_before(year, month, day):
if day == '01':
return None
last_month_day = str((date(int(year), (int(month) + 1) % 12, 1) + - date.resolution).day)
last_digit1, last_digit2 = last_month_day
digit1, digit2 = day
if digit1 == '0':
day_regex = '01' if day == '02' else r'0[1-%s]' % str(int(digit2) - 1)
else:
day_regex = r'('
day_regex += '0' if digit1 == '1' else r'[0-%s]' % str(int(digit1) - 1)
day_regex += r'\d'
if digit2 != '0':
day_regex += '|'
day_regex += digit1
day_regex += '0' if digit2 == '1' else r'[0-%s]' % str(int(digit2) - 1)
day_regex += ')'
return '-'.join((year, month, day_regex))
def regex_date_before(given_date):
year, month, day = given_date.isoformat().split('-')
year_regex = _year_regex_before(year)
month_regex = _month_regex_before(year, month)
day_regex = _day_regex_before(year, month, day)
date_regex = '(' + year_regex if year_regex else '('
date_regex += ('|' + month_regex) if month_regex else ''
date_regex += ('|' + day_regex) if day_regex else ''
date_regex += ')'
return date_regex

31
syntax/python/todo.py Normal file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# File: todo.py
# Description: Todo.txt overdue date syntax script
# License: Vim license
# Website: http://github.com/freitass/todo.txt-vim
# Version: 0.1
import vim
import os
import sys
from datetime import date
dateregex_dir = os.path.join(vim.eval('s:script_dir'), 'dateregex')
if os.path.isdir(dateregex_dir):
sys.path.insert(0, dateregex_dir)
def add_due_date_syntax_highlight():
try:
from dateregex import regex_date_before
except ImportError:
print("dateregex module not found. Overdue dates won't be highlighted")
return
regex = regex_date_before(date.today())
regex = r'(^|<)due:%s(>|$)' % regex
vim.command("syntax match OverDueDate '\\v%s'" % regex)
vim.command("highlight default link OverDueDate Error")
add_due_date_syntax_highlight()

View File

@@ -3,39 +3,39 @@
" Author: David Beniamine <David@Beniamine.net>,Leandro Freitas <freitass@gmail.com> " Author: David Beniamine <David@Beniamine.net>,Leandro Freitas <freitass@gmail.com>
" 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 " vim: ts=4 sw=4 :help tw=78 cc=80
if exists("b:current_syntax") if exists("b:current_syntax")
finish finish
endif endif
syntax match TodoDone '^[xX]\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoDone '^[xX]\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityA '^([aA])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityA '^([aA])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityB '^([bB])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityB '^([bB])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityC '^([cC])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityC '^([cC])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityD '^([dD])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityD '^([dD])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityE '^([eE])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityE '^([eE])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityF '^([fF])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityF '^([fF])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityG '^([gG])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityG '^([gG])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityH '^([hH])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityH '^([hH])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityI '^([iI])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityI '^([iI])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityJ '^([jJ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityJ '^([jJ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityK '^([kK])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityK '^([kK])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityL '^([lL])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityL '^([lL])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityM '^([mM])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityM '^([mM])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityN '^([nN])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityN '^([nN])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityO '^([oO])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityO '^([oO])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityP '^([pP])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityP '^([pP])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityQ '^([qQ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityQ '^([qQ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityR '^([rR])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityR '^([rR])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityS '^([sS])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityS '^([sS])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityT '^([tT])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityT '^([tT])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityU '^([uU])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityU '^([uU])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityV '^([vV])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityV '^([vV])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityW '^([wW])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityW '^([wW])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityX '^([xX])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityX '^([xX])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityY '^([yY])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityY '^([yY])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityZ '^([zZ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext syntax match TodoPriorityZ '^([zZ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoDate '\d\{2,4\}-\d\{2\}-\d\{2\}' contains=NONE syntax match TodoDate '\d\{2,4\}-\d\{2\}-\d\{2\}' contains=NONE
syntax match TodoKey '\S*\S:\S\S*' contains=TodoDate syntax match TodoKey '\S*\S:\S\S*' contains=TodoDate
syntax match TodoProject '\(^\|\W\)+[^[:blank:]]\+' contains=NONE syntax match TodoProject '\(^\|\W\)+[^[:blank:]]\+' contains=NONE
@@ -51,4 +51,12 @@ highlight default link TodoDate PreProc
highlight default link TodoProject Special highlight default link TodoProject Special
highlight default link TodoContext Special highlight default link TodoContext Special
if has('python')
let b:curdir = expand('<sfile>:p:h')
let s:script_dir = b:curdir . "/python/"
execute "pyfile " . s:script_dir. "todo.py"
else
echom "Your version of vim has no python support. Overdue dates won't be highlighted"
endif
let b:current_syntax = "todo" let b:current_syntax = "todo"

28
test/tc_date.todo.txt Normal file
View File

@@ -0,0 +1,28 @@
# lorem_ipsum
example task
# end_lorem_ipsum
# date_after_priority
(A) Call Mom
# end_date_after_priority
# date_after_priority_visual
(A) Call Mom
(B) Call Dad
# end_date_after_priority_visual
# existing_date_no_priority
2014-05-06 example task
# end_existing_date_no_priority
# existing_date_after_priority
(A) 2014-05-06 Call Mom
# end_existing_date_after_priority
# existing_date_do_nothing
2014-05-06 example task
# end_existing_date_do_nothing
# non_existing_date_do_nothing
new todo line
# end_non_existing_date_do_nothing

84
test/tc_date.vim Normal file
View File

@@ -0,0 +1,84 @@
let s:here = expand('<sfile>:p:h')
let s:context = todo#txt#__context__()
let s:context['data'] = s:here . '/tc_date.todo.txt'
let s:tc = unittest#testcase#new('Date', s:context)
let s:TODAY = strftime("%Y-%m-%d")
function! s:tc.test_current_date()
call self.assert_equal(s:TODAY, self.call('s:get_current_date', []))
endfunction
let s:DATE_INSERTED = [
\ s:TODAY . ' example task',
\ ]
let s:DATE_INSERTED_AFTER_PRIORITY = [
\ '(A) ' . s:TODAY . ' Call Mom',
\ ]
let s:DATE_INSERTED_AFTER_PRIORITY_VISUAL = [
\ '(A) ' . s:TODAY . ' Call Mom',
\ '(B) ' . s:TODAY . ' Call Dad',
\ ]
let s:DATE_INSERTED_DO_NOTHING = [
\ '2014-05-06 example task',
\ ]
let s:NON_EXISTING_DATE_INSERTED_DO_NOTHING = [
\ s:TODAY . ' new todo line',
\ ]
function! s:tc.test_insert_date_normal_mode()
call self.data.goto('lorem_ipsum')
call todo#txt#replace_date()
call self.assert_equal(s:DATE_INSERTED, self.data.get('lorem_ipsum'))
endfunction
function! s:tc.test_insert_date_insert_mode()
call self.data.goto('lorem_ipsum')
execute 'normal idate '
call self.assert_equal(s:DATE_INSERTED, self.data.get('lorem_ipsum'))
endfunction
function! s:tc.test_insert_date_visual_mode()
call self.data.visual_execute('call todo#txt#replace_date()', 'lorem_ipsum')
call self.assert_equal(s:DATE_INSERTED, self.data.get('lorem_ipsum'))
endfunction
function! s:tc.test_insert_date_after_priority_normal_mode()
call self.data.execute('call todo#txt#replace_date()', 'date_after_priority')
call self.assert_equal(s:DATE_INSERTED_AFTER_PRIORITY, self.data.get('date_after_priority'))
endfunction
function! s:tc.test_insert_date_after_priority_visual_mode()
call self.data.visual_execute('call todo#txt#replace_date()', 'date_after_priority_visual')
call self.assert_equal(s:DATE_INSERTED_AFTER_PRIORITY_VISUAL, self.data.get('date_after_priority_visual'))
endfunction
function! s:tc.test_insert_with_existing_date()
call self.data.execute('call todo#txt#replace_date()', 'existing_date_no_priority')
call self.assert_equal(s:DATE_INSERTED, self.data.get('existing_date_no_priority'))
endfunction
function! s:tc.test_insert_with_existing_date_and_priority()
call self.data.execute('call todo#txt#replace_date()', 'existing_date_after_priority')
call self.assert_equal(s:DATE_INSERTED_AFTER_PRIORITY, self.data.get('existing_date_after_priority'))
endfunction
function! s:tc.test_insert_with_existing_date_and_priority()
let g:todo_existing_date = 'n'
call self.data.execute('call todo#txt#replace_date()', 'existing_date_do_nothing')
call self.assert_equal(s:DATE_INSERTED_DO_NOTHING, self.data.get('existing_date_do_nothing'))
unlet g:todo_existing_date
endfunction
function! s:tc.test_insert_with_existing_date_and_priority()
let g:todo_existing_date = 'n'
call self.data.execute('call todo#txt#replace_date()', 'non_existing_date_do_nothing')
call self.assert_equal(s:NON_EXISTING_DATE_INSERTED_DO_NOTHING, self.data.get('non_existing_date_do_nothing'))
unlet g:todo_existing_date
endfunction
unlet s:tc

View File

@@ -0,0 +1,5 @@
# lorem_ipsum
first task to be marked as done
second task to be marked as done
2015-05-20 third task to be marked as done
# end_lorem_ipsum

36
test/tc_mark_as_done.vim Normal file
View File

@@ -0,0 +1,36 @@
let s:here = expand('<sfile>:p:h')
let s:context = todo#txt#__context__()
let s:context['data'] = s:here . '/tc_mark_as_done.todo.txt'
let s:tc = unittest#testcase#new('Mark As Done', s:context)
let s:TODAY = strftime("%Y-%m-%d")
let s:FIRST_TASK_DONE = [
\ 'x ' . s:TODAY . ' first task to be marked as done',
\ 'second task to be marked as done',
\ '2015-05-20 third task to be marked as done',
\ ]
let s:ALL_TASKS_DONE = [
\ 'x ' . s:TODAY . ' first task to be marked as done',
\ 'x ' . s:TODAY . ' second task to be marked as done',
\ 'x ' . s:TODAY . ' 2015-05-20 third task to be marked as done',
\ ]
function! s:tc.test_mark_as_done()
call self.data.goto('lorem_ipsum')
call todo#txt#mark_as_done()
call self.assert_equal(s:FIRST_TASK_DONE, self.data.get('lorem_ipsum'))
endfunction
function! s:tc.test_mark_range_as_done()
call self.data.execute('call todo#txt#mark_as_done()', 'lorem_ipsum')
call self.assert_equal(s:ALL_TASKS_DONE, self.data.get('lorem_ipsum'))
endfunction
function! s:tc.test_mark_selection_as_done()
call self.data.visual_execute('call todo#txt#mark_as_done()', 'lorem_ipsum')
call self.assert_equal(s:ALL_TASKS_DONE, self.data.get('lorem_ipsum'))
endfunction
unlet s:tc

View File

@@ -0,0 +1,7 @@
# insert_priority
example task
# end_insert_priority
# replace_priority
(A) example task
# end_replace_priority

28
test/tc_priority.vim Normal file
View File

@@ -0,0 +1,28 @@
let s:here = expand('<sfile>:p:h')
let s:context = todo#txt#__context__()
let s:context['data'] = s:here . '/tc_priority.todo.txt'
let s:tc = unittest#testcase#new('Priority', s:context)
let s:TODAY = strftime("%Y-%m-%d")
let s:PRIORITY_INSERTED = [
\ '(A) example task',
\ ]
let s:PRIORITY_REPLACED = [
\ '(C) example task',
\ ]
function! s:tc.test_insert_priority()
call self.data.goto('insert_priority')
call todo#txt#prioritize_add('A')
call self.assert_equal(s:PRIORITY_INSERTED, self.data.get('insert_priority'))
endfunction
function! s:tc.test_replace_priority()
call self.data.goto('replace_priority')
call todo#txt#prioritize_add('C')
call self.assert_equal(s:PRIORITY_REPLACED, self.data.get('replace_priority'))
endfunction
unlet s:tc

View File

@@ -0,0 +1,5 @@
# lorem_ipsum
(B) Linear regression Rnet=Qh@Qle. @cons_emp_model
(B) Review key questions. @benchmarking
(A) simple model first @cons_emp_model
# end_lorem_ipsum

18
test/tc_sort_context.vim Normal file
View File

@@ -0,0 +1,18 @@
let s:here = expand('<sfile>:p:h')
let s:tc = unittest#testcase#new('Sort Context',
\ { 'data': s:here . '/tc_sort_context.todo.txt' })
let s:LEADER = mapleader
let s:SORTED_TASKS = [
\ '(B) Review key questions. @benchmarking',
\ '(B) Linear regression Rnet=Qh@Qle. @cons_emp_model',
\ '(A) simple model first @cons_emp_model',
\ ]
function! s:tc.test_sort_by_context()
call self.data.visual_execute('call todo#txt#sort_by_context()', 'lorem_ipsum')
call self.assert_equal(s:SORTED_TASKS, self.data.get('lorem_ipsum'))
endfunction
unlet s:tc

View File

@@ -0,0 +1,12 @@
# lorem_ipsum
(B) 2013-03-15 2015-03-17
(B) 2012-04-16 2015-04-16
(A) 2013-03-16 2013-03-10
# end_lorem_ipsum
# task_with_no_date
2013-03-15 task with date
task with no date
2013-03-15 task with date
2013-03-15 task with date
task with no date
# end_task_with_no_date

31
test/tc_sort_date.vim Normal file
View File

@@ -0,0 +1,31 @@
let s:here = expand('<sfile>:p:h')
let s:tc = unittest#testcase#new('Sort Date',
\ { 'data': s:here . '/tc_sort_date.todo.txt' })
let s:LEADER = mapleader
let s:SORTED_TASKS = [
\ '(B) 2012-04-16 2015-04-16',
\ '(B) 2013-03-15 2015-03-17',
\ '(A) 2013-03-16 2013-03-10',
\ ]
let s:SORTED_TASKS_WITH_NO_DATE = [
\ '2013-03-15 task with date',
\ '2013-03-15 task with date',
\ '2013-03-15 task with date',
\ 'task with no date',
\ 'task with no date',
\ ]
function! s:tc.test_sort_by_date()
call self.data.visual_execute('call todo#txt#sort_by_date()', 'lorem_ipsum')
call self.assert_equal(s:SORTED_TASKS, self.data.get('lorem_ipsum'))
endfunction
function! s:tc.test_sort_by_date_with_tasks_without_date()
call self.data.visual_execute('call todo#txt#sort_by_date()', 'task_with_no_date')
call self.assert_equal(s:SORTED_TASKS_WITH_NO_DATE, self.data.get('task_with_no_date'))
endfunction
unlet s:tc

View File

@@ -0,0 +1,5 @@
# lorem_ipsum
(B) Linear regression Rnet=Qh+Qle. +cons_emp_model
(B) Review key questions. +benchmarking
(A) simple model first +cons_emp_model
# end_lorem_ipsum

18
test/tc_sort_project.vim Normal file
View File

@@ -0,0 +1,18 @@
let s:here = expand('<sfile>:p:h')
let s:tc = unittest#testcase#new('Sort Project',
\ { 'data': s:here . '/tc_sort_project.todo.txt' })
let s:LEADER = mapleader
let s:SORTED_TASKS = [
\ '(B) Review key questions. +benchmarking',
\ '(B) Linear regression Rnet=Qh+Qle. +cons_emp_model',
\ '(A) simple model first +cons_emp_model',
\ ]
function! s:tc.test_sort_by_project()
call self.data.visual_execute('call todo#txt#sort_by_project()', 'lorem_ipsum')
call self.assert_equal(s:SORTED_TASKS, self.data.get('lorem_ipsum'))
endfunction
unlet s:tc