55 Commits

Author SHA1 Message Date
David Beniamine
c8fbe04351 Release several bug fix 2019-02-10 18:32:41 +01:00
David Beniamine
9d1443b663 Silence all sorts 2019-02-10 18:29:59 +01:00
Risto Saarelma
00ecbeb8b7 Add setting for dropping priority metadata
The default behavior of todo.txt is to add priority metadata to done
items with priority tags so that the priority can be restored when the
item is marked as undone. If you want to have cleaner done items and
just remove the priority information when the item is set as done, set

    let g:TodoTxtStripDoneItemPriority=1
2019-02-10 18:16:27 +01:00
David Beniamine
739d58ec8c Revert "Change top repo command to fix CI"
This reverts commit cfc6000948.
2019-01-23 12:19:21 +01:00
David Beniamine
74ea6248dd Fix sheebang 2019-01-23 12:16:36 +01:00
David Beniamine
cfc6000948 Change top repo command to fix CI 2019-01-23 12:12:18 +01:00
David Beniamine
8554880297 Fix gitlab ci 2019-01-23 12:07:28 +01:00
David Beniamine
224986ab96 Add gitlab ci 2019-01-23 12:06:53 +01:00
David Beniamine
a2090399fb Keep cursor pos on sorting see #33 2019-01-23 11:00:28 +01:00
David Beniamine
93480dd2c7 Save "/ buffer, fix #35 2018-12-23 16:49:16 +01:00
David Beniamine
259125d9ef Move tasks without priority before done on sort
Closes #32
2018-05-25 18:08:55 +02:00
David Beniamine
2483961aaf Merge branch 'master' of https://github.com/fretep/todo.txt-vim 2018-04-19 23:45:48 +02:00
David Beniamine
7b0262ae84 Do not override fold_char and use fold_char x for tests 2018-04-19 23:45:09 +02:00
fretep
f23b1c2cac Update mappings to be more consistent
in use of map arguments, and also move the <Plug> mappings outside of
the Todo_txt_do_not_map block
2018-04-19 21:37:53 +10:00
fretep
aa5a702057 Use setlocal for nrformats 2018-04-19 21:16:07 +10:00
David Beniamine
7d70e30aae Add Possibility to fold on context or project
Closes #30

Folds now works the following way:

+ At initialisation, if all completed tasks are at the end, folds are
based on completed tasks only, else they are based on context
+ After a hierarchichal sort, folds are set by the first level between project and context
+ After a "normal" sort, folds are set only on completed tasks (as
before)

This work is greatly inspired from the snipped provided by @arecarn
2018-04-18 17:55:15 +02:00
fretep
d6256bcfe3 Add support for recurring tasks ("rec:" keyword) 2017-10-20 22:48:50 +11:00
fretep
f982b9c581 Merge branch 'master' of https://github.com/dbeniamine/todo.txt-vim 2017-10-14 18:43:19 +11:00
fretep
5f2497d3fa Adding postpone due date mapping and functions 2017-10-14 18:27:21 +11:00
David Beniamine
ea7eb42d62 Merge branch 'master' of https://github.com/fretep/todo.txt-vim 2017-10-05 11:43:47 +02:00
fretep
678c3b8680 Bug fix in todo#todo#GetDateRegexForPastDates
For dates in October.
2017-10-01 12:07:07 +11:00
David Beniamine
0744fdf45b Merge branch 'master' of https://github.com/fretep/todo.txt-vim 2017-09-27 19:05:18 +02:00
fretep
7160425fa8 Prefix creation date when opening a new line 2017-09-27 22:56:17 +10:00
David Beniamine
8cb1a76eed Removed useless files from original version 2017-09-26 14:59:12 +02:00
David Beniamine
87f94ef7bd Removed redundant test 2017-09-26 14:58:15 +02:00
David Beniamine
25fa5dcf15 Fix priority on canceleld tasks + tests 2017-09-26 14:57:48 +02:00
fretep
f35bcabcea Correct a bug in todo#Complete
where the entire lines were being shown as related
2017-09-24 23:02:26 +10:00
fretep
21908548d4 Fix exception in todo#MarkAsDone and todo#UnMarkAsDone 2017-09-22 23:33:18 +10:00
fretep
6777558646 Fix case sensitivity folding complete tasks 2017-09-20 15:19:45 +02:00
David Beniamine
ebdde99ac4 Fix #21
Better handling of priority on done tasks
Also added <localleader>ff to fix format. this will remove leading
whitespaces and convert old (wrong) done tasks to the correct format
2017-09-20 13:28:07 +02:00
David Beniamine
c6e472c048 Fix #23 2017-09-20 12:43:22 +02:00
fretep
c8092640df Fix for <Leader>x and other minor issues
Fixed a bug in <Leader>x (todo#PrependDate) introduced last commit.
Fixed case sensitivity bug in todo#ToggleMarkAsDone() and todo#UnMarkAsDone()
Fixed errors being reported for repeat#set if vim-repeat plugin is not installed.
Fixed modeline in .vim files to work (only works on first/last 5 lines of file), and made the modelines consistent across all files.
New unit tests for todo#ToggleMarkAsDone()
Minor fixes for README.md and man page
Fix anchoring of RegExp in todo#ToggleMarkAsDone
Fixed a bug in overdue highlighting that resulted in the current date being matched on round dates like the 20th and 30th.
Added more unit tests for overdue date highlighting.
Corrected RegExp anchoring on today date highlighting.
Added a few bash scripts to make running unit tests easier and more reliable, including testing with ignorecase user preference set.
2017-09-20 01:32:59 +10:00
David Beniamine
c2ad4bc58b make sort case insensitive 2017-09-15 13:02:57 +02:00
David Beniamine
68e407af22 Merge branch 'vadertests' of https://github.com/fretep/todo.txt-vim 2017-09-15 12:27:09 +02:00
David Beniamine
22fb99260e fix bad indent 2017-09-15 12:27:01 +02:00
fretep
f39504bea8 Added myself to author line 2017-09-15 18:44:08 +10:00
fretep
08d3ed88d9 Major refactor to be cleaner and test more cases 2017-09-15 18:36:50 +10:00
Peter
4119ff026f Merge branch 'master' into SortDueFixes 2017-09-14 01:18:42 +10:00
fretep
ff533b85f5 Bug fixes for case sensitivity and cursor positioning 2017-09-14 01:06:59 +10:00
David Beniamine
774d4da4e9 Conforming to todo rules
Priorities must be uppercase
Completed task marker is lowercase
2017-09-12 16:38:41 +02:00
fretep
0ed7d4848e Fix sorting bugs with 'due:' at the start of the line, and properly handle completed tasks with lastdue and notoverdue post sort cursor preferences 2017-09-12 23:50:56 +10:00
David Beniamine
7bebc01020 Fix issue #17 2017-09-12 15:44:25 +02:00
fretep
f5050663c6 Added tests and notes for issue #17 and #18 2017-09-12 21:49:38 +10:00
fretep
b8fa774606 Merge branch 'master' into vadertests 2017-09-12 20:32:41 +10:00
David Beniamine
35810c388d Micro release 2017-09-11 13:34:49 +02:00
fretep
311761e327 Added TodoDueToday syntax highlight 2017-09-11 13:32:07 +02:00
David Beniamine
71505569c0 Vestion 0.8
Fix and close #14 and #15
Merge PR#13 and PR#16
2017-09-10 12:13:26 +02:00
David Beniamine
6d1d2d035a Do not consider done tasks when sorting by due date 2017-09-10 12:13:25 +02:00
David Beniamine
491c3c7fba Remove python dependency 2017-09-10 12:13:25 +02:00
fretep
70b05c2c76 Modified SortDue() to fix error if every line of the todo.txt had a
due:date specified, also allow setting a global variable to specify
the line the cursor should be place on after the sort
2017-09-10 12:13:25 +02:00
fretep
30f112a8ac Vader tests 2017-09-09 21:14:27 +10:00
fretep
a778ef5590 Fix case sensitivity with "due:" in overdue date highlighting 2017-09-09 20:35:44 +10:00
fretep
03fe8bb167 Added native vim function to highlight overdue dates 2017-09-09 13:22:07 +10:00
David Beniamine
aa618973e2 Do not highlight overdue when marked done 2017-09-05 10:48:06 +02:00
David Beniamine
7b9c9815a4 Integrating sietse's work, version 0.7.6 2017-08-15 12:22:21 +02:00
18 changed files with 2567 additions and 492 deletions

17
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,17 @@
test-vim-latest:
image: thinca/vim:v7.4
script:
- cd tests
- bash runtests.sh
test-vim-7.4:
image: thinca/vim:v7.4
script:
- cd tests
- bash runtests.sh
test-neovim:
image: lambdalisue/neovim-ci
script:
- cd tests
- bash runtests.sh

View File

@@ -28,6 +28,13 @@
## Release notes
+ V0.8.1 Incorporates yet another Fretep work : highlighting for tasks due today.
+ v0.8 Incorporates Fretep's work on overdue dates (PR#13 and PR#16) which
removes python dependency, allow to control the cursor position after a sort by
todo (see (sort)[#sort] and/or issue #15) and fixes bug when sorting a file
containing only lines with due:date (issue #14).
+ v0.7.6 Incorporates [Sietse's work](https://github.com/sietse/todo.txt-vim/commit/57d45200c8b033d31c9191ee0eb0711c801cdb1d) to make cancel and mark as done mapping repeatable using [vim-repeat](https://github.com/tpope/vim-repeat).
+ v0.7.5 Incorporates [Fievel's work](https://github.com/fievel/todo.txt-vim/commit/0863e1434e9a89ace06c4856b6cb32ba9906e3de) to make overduedates work on python3.
+ v0.7.4 includes the overduedate support from Guilherme Victal (see pull
@@ -53,7 +60,7 @@ by David Beniamine.
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)
[rules](https://github.com/todotxt/todotxt/)
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":
@@ -70,7 +77,7 @@ all you need to be productive. See an example Todo.txt file":
### Why this fork ?
This plugin is a fork of [freitass
todo.txt-vim](https://github.com/freitass/todo.txt-vim). It add severals cool
todo.txt-vim](https://github.com/freitass/todo.txt-vim). It add several cool
functionalities including:
+ [Hierarchical sort](##hierarchical-sort)
@@ -112,7 +119,7 @@ having copied the files. Then you will be able to get the commands help with:
## TodoTxt Files
This plugin provides a Flexible file naming for todo.txt, all the following
This plugin provides flexible file naming for todo.txt, all the following
names are recognized as todo:
YYYY-MM-[Tt]odo.txt
@@ -166,6 +173,17 @@ 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.
If you don't want the preview window to open when performing completion, add the
following lines to your vimrc:
au filetype todo setlocal completeopt-=preview
If you would like the preview window to open even if there is only one match for
a completion, then add the following lines to your vimrc:
au filetype todo setlocal completeopt+=menuone
## Hierarchical sort
This fork provides a hierarchical sorting function designed to do by project
@@ -191,9 +209,29 @@ Defaults values are:
For more information on the available flags see `help :sort`
## Recurrence
By adding a `rec:` tag to your task, when you complete (`<LocalLeader>x`) or
postpone (`<LocalLeader>p`) the task, a new recurrence will be created due after
the specified amount of time.
The format is:
`rec:[+][count][d|w|m|y]`
Where:
d = days, w = weeks, m = months, y = years
The optional `+` specifies strict recurrence (see below)
Examples:
* `rec:2w` - Recurs two weeks after the task is completed.
* `rec:3d` - Recurs three days after the task is completed.
* `rec:+1w` - Recurs one week from the due date (strict)
This is a non-standard but widely adopted keyword.
## Mappings
By default todo-txt.vim set all the mappings secribed in this section. To
By default todo-txt.vim sets all the mappings described in this section. To
prevent this behavior, add the following line to your vimrc
let g:Todo_txt_do_not_map=1
@@ -207,13 +245,26 @@ prevent this behavior, add the following line to your vimrc
+ `<LocalLeader>s` : Sort the file by priority
+ `<LocalLeader>s+` : Sort the file on `+Projects`
+ `<LocalLeader>s@` : Sort the file on `@Contexts`
+ `<LocalLeader>sd` : 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>sd` : Sort the file on due dates. Entries with a due date appear
sorted by at the beginning of the file, completed tasks are moved to the bottom and
the rest of the file is not modified.
When you sort by due dates, at the end of the sort, your cursor will be placed
at the top of the file. This behavior can be set with the following global
variable :
let g:TodoTxtSortDueDateCursorPos = "top"
Possible values are :
+ `top` (default): The first line of the buffer, i.e. your most outstanding task
+ `lastdue`: The last task with a due:date set
+ `notoverdue`: The first task that is not overdue (requires #13)
+ `bottom`: The last line of the buffer
### Priorities
@@ -226,10 +277,18 @@ sorted by at the beginning of the file, the rest of the file is not modified.
### Dates
+ `<LocalLeader>d` : Insert the current date
+ `<LocalLeader>p` : Postpone the due date (accepts a count)
+ `<LocalLeader>P` : Decrement the due date (accepts a count)
+ `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
If you would like the creation date (today) prefixed on new lines, add the
following to your vimrc:
let g:Todo_txt_prefix_creation_date=1
### Done
@@ -239,3 +298,7 @@ sorted by at the beginning of the file, the rest of the file is not modified.
+ `<LocalLeader>X` : Mark all tasks as completed
+ `<LocalLeader>D` : Move completed tasks to done file, see [TodoTxt
Files](#todotxt-files)
### Format
+ `<LocalLeader>ff` : Try to fix todo.txt format

View File

@@ -1,9 +1,8 @@
" File: autoload/todo.vim
" Description: Todo.txt sorting plugin
" Author: David Beniamine <david@beniamine.net>
" Author: David Beniamine <david@beniamine.net>, Peter (fretep) <githib.5678@9ox.net>
" Licence: Vim licence
" Website: http://github.com/dbeniamine/todo.txt.vim
" 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
@@ -30,9 +29,6 @@ function! todo#GetCurpos()
return getpos('.')
endfunction
" Increment and Decrement The Priority
:set nf=octal,hex,alpha
function! todo#PrioritizeIncrease()
normal! 0f)h
endfunction
@@ -65,16 +61,33 @@ function! todo#PrependDate()
if (getline(".") =~ '\v^\(')
execute "normal! 0f)a\<space>\<esc>l\"=strftime(\"%Y-%m-%d\")\<esc>P"
else
normal! 0"=strftime("%Y-%m-%d ")
normal! I=strftime("%Y-%m-%d ")
endif
endfunction
function todo#SaveRegisters()
let s:last_search=@/
endfunction
function todo#RestoreRegisters()
let @/=s:last_search
endfunction
function! todo#ToggleMarkAsDone(status)
function! todo#ToggleMarkAsDone(status)
call todo#SaveRegisters()
if (getline(".") =~ '\C^x\s*\d\{4\}')
:call todo#UnMarkAsDone(a:status)
else
:call todo#MarkAsDone(a:status)
endif
call todo#RestoreRegisters()
endfunction
function! todo#FixFormat()
" Remove heading space
silent! %s/\C^\s*//
" Remove priority from done tasks
silent! %s/\C^x (\([A-Z]\)) \(.*\)/x \2 pri:\1/
endfunction
function! todo#UnMarkAsDone(status)
@@ -83,15 +96,26 @@ function! todo#UnMarkAsDone(status)
else
let pat=' '.a:status
endif
endif
exec ':s/\C^x\s*\d\{4}-\d\{1,2}-\d\{1,2}'.pat.'\s*//g'
silent s/\C\(.*\) pri:\([A-Z]\)/(\2) \1/e
endfunction
function! todo#MarkAsDone(status)
call todo#CreateNewRecurrence(1)
if get(g:, 'TodoTxtStripDoneItemPriority', 0)
exec ':s/\C^(\([A-Z]\))\(.*\)/\2/e'
else
exec ':s/\C^(\([A-Z]\))\(.*\)/\2 pri:\1/e'
endif
if a:status!=''
exec 'normal! I'.a:status.' '
endif
call todo#PrependDate()
if (getline(".") =~ '^ ')
normal! gIx
else
normal! Ix
endif
endfunction
function! todo#MarkAllAsDone()
@@ -133,15 +157,19 @@ function! todo#RemoveCompleted()
call s:AppendToFile(l:done_file, l:completed)
endfunction
function! todo#Sort(type)
" vim :sort is usually stable
" we sort first on contexts, then on projects and then on priority
" we sort first on contexts, then on projects and then on priority
let g:Todo_fold_char='x'
let oldcursor=todo#GetCurpos()
if(a:type != "")
exec ':sort /.\{-}\ze'.a:type.'/'
elseif expand('%')=~'[Dd]one.*.txt'
" FIXME: Put some unit tests around this, and fix case sensitivity if ignorecase is set.
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
else
silent normal gg
let l:first=search('^\s*x')
if l:first != 0
@@ -151,38 +179,97 @@ function! todo#Sort()
let l:last=search('^\s*x','b')
let l:diff=l:last-l:first+1
" Cut the done lines
" Cut the done lines
silent execute ':'.l:first.'d a '.l:diff
endif
silent sort /@[a-zA-Z]*/ r
silent sort /+[a-zA-Z]*/ r
silent sort /\v\([A-Z]\)/ r
"Now tasks without priority are at beggining, move them to the end
silent normal gg
let l:firstP=search('^\s*([A-Z])', 'cn')
if l:firstP != 1
let num=l:firstP-1
" Sort normal
silent execute ':1 d b'.num
silent normal G"bp
endif
endif
sort /@[a-zA-Z]*/ r
sort /+[a-zA-Z]*/ r
if l:first != 0
silent normal G"ap
silent normal G"ap
execute ':'.l:first.','.l:last.'sort /@[a-zA-Z]*/ r'
execute ':'.l:first.','.l:last.'sort /+[a-zA-Z]*/ r'
silent execute ':'.l:first.','.l:last.'sort /@[a-zA-Z]*/ r'
silent execute ':'.l:first.','.l:last.'sort /+[a-zA-Z]*/ r'
silent execute ':'.l:first.','.l:last.'sort /\v([A-Z])/ r'
endif
endif
endif
call setpos('.', oldcursor)
endfunction
function! todo#SortDue()
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]
" Check how many lines have a due:date on them
let l:tasksWithDueDate = 0
silent! %global/\v\c<due:\d{4}-\d{2}-\d{2}>/let l:tasksWithDueDate += 1
if l:tasksWithDueDate == 0
" No tasks with a due:date: No need to modify the buffer at all
" Also means we don't need to cater for no matches on searches below
return
endif
" FIXME: There is a small chance that due:\d{8} might legitimately exist in the buffer
" We modify due:yyyy-mm-dd to yyyymmdd which would then mean we would alter the buffer
" in an unexpected way, altering user data. Not sure how to deal with this at the moment.
" I'm going to throw an exception, and if this is a problem we can revisit.
silent %global/\v\c<due:\d{8}>/throw "Text matching 'due:\\d\\{8\\}' exists in the buffer, this function cannot sort your buffer"
" Turn the due:date from due:yyyy-mm-dd to due:yyyymmdd so we can do a numeric sort
silent! %substitute/\v<(due:\d{4})\-(\d{2})\-(\d{2})>/\1\2\3/ei
" Sort all the lines with due: by numeric yyyymmdd, they will end up in ascending order at the bottom of the buffer
sort in /\v\c<due:\ze\d{8}>/
" Determine the line number of the first task with a due:date
let l:firstLineWithDue = line("$") - l:tasksWithDueDate + 1
" Put the sorted lines at the beginning of the file
" Put the sorted lines at the beginning of the file
execute ':'.l:first
execute ':d'.l:diff
silent normal gg
silent normal P
if l:firstLineWithDue > 1
" ...but only if the whole file didn't get sorted.
execute "silent " . l:firstLineWithDue . ",$move 0"
endif
" Change the due:yyyymmdd back to due:yyyy-mm-dd.
silent! %substitute/\v<(due:\d{4})(\d{2})(\d{2})>/\1-\2-\3/ei
silent global/\C^x /move$
" Let's check a global for a user preference on the cursor position.
if exists("g:TodoTxtSortDueDateCursorPos")
if g:TodoTxtSortDueDateCursorPos ==? "top"
normal gg
elseif g:TodoTxtSortDueDateCursorPos ==? "lastdue" || g:TodoTxtSortDueDateCursorPos ==? "notoverdue"
silent normal G
" Sorry for the crazy RegExp. The next command should put cursor at at the top of the completed tasks,
" or the bottom of the buffer. This is done by searching backwards for any line not starting with
" "x " (x, space) which is important to distinguish from "xample task" for instance, which the more
" simple "^[^x]" would match. More info: ":help /\@!". Be sure to enforce case sensitivity on "x".
:silent! ?\v\C^(x )@!?+1
let l:overduePat = todo#GetDateRegexForPastDates()
let l:lastwrapscan = &wrapscan
set nowrapscan
try
if g:TodoTxtSortDueDateCursorPos ==? "lastdue"
" This searches backwards for the last due task
:?\v\c<due:\d{4}\-\d{2}\-\d{2}>
" Try a forward search in case the last line of the buffer was a due:date task, don't match done
" Be sure to enforce case sensitivity on "x" while allowing mixed case on "due:"
:silent! /\v\C^(x )@!&.*<[dD][uU][eE]:\d{4}\-\d{2}\-\d{2}>
elseif g:TodoTxtSortDueDateCursorPos ==? "notoverdue"
" This searches backwards for the last overdue task, and positions the cursor on the following line
execute ":?\\v\\c<due:" . l:overduePat . ">?+1"
endif
catch
" Might fail if there are no active (or overdue) due:date tasks. Requires nowrapscan
" This code path always means we want to be at the top of the buffer
normal gg
finally
let &wrapscan = l:lastwrapscan
endtry
elseif g:TodoTxtSortDueDateCursorPos ==? "bottom"
silent normal G
endif
else
" Default: Top of the document
normal gg
endif
" TODO: add time sorting (YYYY-MM-DD HH:MM)
endfunction
@@ -203,6 +290,7 @@ function! todo#HierarchicalSort(symbol, symbolsub, dolastsort)
"Empty buffer do nothing
return
endif
let g:Todo_fold_char=a: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:sortmodesub=Todo_txt_InsertSpaceIfNeeded(g:Todo_txt_second_level_sort_mode)
@@ -295,6 +383,365 @@ function! Todo_txt_InsertSpaceIfNeeded(str)
retur a:str
endfunction
" function todo#CreateNewRecurrence {{{2
function! todo#CreateNewRecurrence(triggerOnNonStrict)
" Given a line with a rec:timespan, create a new task based off the
" recurrence and move the recurring tasks due:date to the next occurrence.
"
" This is implemented by a few other systems, so we will try to be as
" compatible as possible with the existing specifications.
"
" Other example implementations:
" <http://swiftodoapp.com/>
" <https://github.com/bram85/todo.txt-tools/wiki/Recurrence>
"
let l:currentline = getline('.')
" Don't operate on complete tasks
if l:currentline =~# '^x '
return
endif
let l:rec_date_rex = '\v\c(^|\s)rec:(\+)?(\d+)([dwmy])(\s|$)'
let l:rec_parts = matchlist(l:currentline, l:rec_date_rex)
" Don't operate on tasks without a valid "rec:" keyword.
if empty(l:rec_parts)
" If a "rec:" keyword exists, but it didn't match our expectations, warn
" the user, and abort whatever is happening otherwise a recurring task
" might be marked complete without a new recurrence being created.
if l:currentline =~? '\v\c(^|\s)rec:'
throw "Recurrence pattern is invalid. Aborting operation."
endif
return
endif
" Operations like postponing a task should not trigger the task to be
" duplicated, non-strict mode allows the changing of the due date.
let l:is_strict = l:rec_parts[2] ==# "+"
if ! a:triggerOnNonStrict && ! l:is_strict
return
endif
let l:units = str2nr(l:rec_parts[3])
if l:units < 1
let l:units = 1
endif
let l:unit_type = l:rec_parts[4]
" If we had a space on both sides of the "rec:" that we are removing, then
" we need to insert a space, otherwise, not.
if l:rec_parts[1] ==# ' ' && l:rec_parts[5] ==# ' '
let l:replace_string = ' '
else
let l:replace_string = ''
endif
" New task should have the rec: keyword stripped
let l:newline = substitute(l:currentline, l:rec_date_rex, l:replace_string, '')
" Insert above current line
let l:new_task_line_num = line('.')
if append(l:new_task_line_num - 1, l:newline) != 0
throw "Failed at append line"
endif
" At this point, we need to change the due date of the recurring task.
" Modes:
" Strict mode: From the existing due date
" Non-Strict mode: From the current date
" So, we don't need to do anything for strict mode. Non-strict mode requires
" setting the current date.
if l:is_strict
call todo#ChangeDueDate(l:units, l:unit_type, '')
else
call todo#ChangeDueDate(l:units, l:unit_type, strftime('%Y-%m-%d'))
endif
" Move onto the copied task
call cursor(l:new_task_line_num, col('.'))
if l:new_task_line_num != line('.')
throw "Failed to move cursor"
endif
endfunction
" function todo#ChangeDueDate {{{2
function! todo#ChangeDueDate(units, unit_type, from_reference)
" Change the due:date on the current line by a number of days, months or
" years
"
" units The number of unit_type to add or subtract, integer
" values only
" unit_type May be one of 'd' (days), 'm' (months) or 'y' (years),
" as handled by todo#DateAdd
" from_reference Allows passing a different date to base the calculation
" on, ignoring the existing due date in the line. Leave as
" an empty string to use the due:date in the line,
" otherwise a date as a string in the form "YYYY-MM-DD".
let l:currentline = getline('.')
" Don't operate on complete tasks
if l:currentline =~# '^x '
return
endif
let l:dueDateRex = '\v\c(^|\s)due:\zs\d{4}\-\d{2}\-\d{2}\ze(\s|$)'
let l:duedate = matchstr(l:currentline, l:dueDateRex)
if l:duedate ==# ''
" No due date on current line, then add the due date as an offset from
" current date. I.e. a v:count of 1 is due tomorrow, etc
if l:currentline =~? '\v\c(^|\s)due:'
" Has an invalid due: keyword, so don't add another, and don't
" change the line
return
endif
let l:duedate = strftime('%Y-%m-%d')
let l:currentline .= ' due:' . l:duedate
endif
" If a valid reference has been passed, let's use it.
if a:from_reference =~# '\v^\d{4}\-\d{2}\-\d{2}$'
let l:duedate = a:from_reference
endif
let l:duedate = todo#DateStringAdd(l:duedate, v:count1 * a:units, a:unit_type)
if setline('.', substitute(l:currentline, l:dueDateRex, l:duedate, '')) != 0
throw "Failed to set line"
endif
endfunction "}}}
" General date calculation functions {{{1
" function todo#GetDaysInMonth {{{2
function! todo#GetDaysInMonth(month, year)
" Given a month and year, returns the number of days in the month, taking
" leap years into consideration.
if index([1, 3, 5, 7, 8, 10, 12], a:month) >= 0
return 31
elseif index([4, 6, 9, 11], a:month) >= 0
return 30
else
" February, leap year fun.
if a:year % 4 != 0
return 28
elseif a:year % 100 != 0
return 29
elseif a:year % 400 != 0
return 28
else
return 29
endif
endif
endfunction
" function todo#DateAdd {{{2
function! todo#DateAdd(year, month, day, units, unit_type)
" Add or subtract days, months or years from a date
"
" Date must be passed in components of year, month and day, all integers
" units is the number of unit_type to add or subtract, integer values only
" unit_type may be one of:
" d days
" w weeks, 7 days
" m months, keeps the day of the month static except in the case
" that the day is the last day in the month or the day is higher
" than the number of days in the resultant month, where the result
" will stick to the end of the month. Examples:
" 2017-01-15 +1m 2017-02-15 +1m 2017-03-15 +1m 2017-04-15
" 2017-01-31 +1m 2017-02-28 +1m 2017-03-31 +1m 2017-04-30
" 2017-01-30 +1m 2017-02-28 +1m 2017-03-31
" 2017-01-30 +2m 2017-03-30
" y years, 12 months
" It is my understanding that VIM does not have date math functionality
" built in. Given we only have to deal with dates, and not times, it isn't
" all that scary to roll our own - we just need to watch out for leap years.
" Check and clean up input
if index(["d", "D", "w", "W", "m", "M", "y", "Y"], a:unit_type) < 0
throw 'Invalid unit "'. a:unit_type . '" passed to todo#DateAdd()'
endif
let l:d = str2nr(a:day)
let l:m = str2nr(a:month)
let l:y = str2nr(a:year)
let l:i = str2nr(a:units)
" Years can be handled simply as 12 x months, weeks as 7 x days
if a:unit_type ==? "y"
let l:utype = "m"
let l:i = l:i * 12
elseif a:unit_type ==? "w"
let l:utype = "d"
let l:i = l:i * 7
else
let l:utype = a:unit_type
endif
" Check and clean up input
if l:m < 1
if l:m == 0
let l:m = str2nr(strftime('%m'))
else
let l:m = 1
endif
endif
if l:m > 12
if l:i < 0 && l:utype ==? "m"
" Subtracting an invalid (high) month
" See comments for passing a high day below. Same reason for this.
let l:m = 13
else
let l:m = 12
endif
endif
if l:y < 1900 " See end of function for rationale
if l:y == 0
let l:y = str2nr(strftime('%Y'))
else
let l:y = 1900
endif
endif
" Grab number of days in the month specified
let l:daysInMonth = todo#GetDaysInMonth(l:m, l:y)
" Check and clean up input
if l:d < 1
if l:d == 0
let l:d = str2nr(strftime('%d'))
else
let l:d = 1
endif
endif
" Allow passing a high day, this allows subtraction to be more sane when
" the day is out of bounds, i.e. 2017-04-80 should probably come out as
" 2017-04-30 not 2017-04-29. Addition deals with days being out of
" bounds (high) fine, and if days are untouched, out of bounds user
" input is caught at the end of the function.
" if l:d > l:daysInMonth
" let l:d = l:daysInMonth
" endif
if l:utype ==? "d"
" Adding DAYS
while l:i > 0
let l:d += 1
if l:d > l:daysInMonth
let l:d = 1
let l:m += 1
if l:m > 12
let l:m = 1
let l:y += 1
endif
let l:daysInMonth = todo#GetDaysInMonth(l:m, l:y)
endif
let l:i -= 1
endwhile
" Subtracting DAYS
while l:i < 0
let l:d -= 1
if l:d < 1
let l:m -= 1
if l:m < 1
if l:y > 1900
let l:m = 12
let l:y -= 1
else
let l:d = 1
let l:m = 1
break
endif
endif
let l:daysInMonth = todo#GetDaysInMonth(l:m, l:y)
let l:d = l:daysInMonth
endif
let l:i += 1
endwhile
elseif l:utype ==? "m"
if l:d >= l:daysInMonth
let l:wasLastDayOfMonth = 1
else
let l:wasLastDayOfMonth = 0
endif
" Adding MONTHS
while l:i > 0
let l:m += 1
if l:m > 12
let l:m = 1
let l:y += 1
endif
let l:i -= 1
endwhile
" Subtracting MONTHS
while l:i < 0
let l:m -= 1
if l:m < 1
if l:y > 1900
let l:m = 12
let l:y -= 1
else
let l:m = 1
endif
endif
let l:i += 1
endwhile
let l:daysInMonth = todo#GetDaysInMonth(l:m, l:y)
if l:wasLastDayOfMonth
let l:d = l:daysInMonth
endif
endif
" Enforce some limits beyond which, I don't want to support.
if l:y < 1900
" Seeing as the date is going to be converted back to a string, dates
" less that 1000 are bound to cause bugs. Given this is an app for tasks
" you are doing in the here and now, I'm not supporting way back in the
" past.
let l:y = 1900
let l:daysInMonth = todo#GetDaysInMonth(l:m, l:y)
endif
" If we mess with the year (just above), or the user passes a day higher
" than the month, catch it here.
if l:d > l:daysInMonth
let l:d = l:daysInMonth
endif
return [l:y, l:m, l:d]
endfunction
" function todo#DateStringAdd {{{2
function! todo#DateStringAdd(date, units, unit_type)
" A very thin overload of todo#DateAdd() that takes and returns the date as
" a string rather than in [year, month, day] component form.
"
" Date must be passed in "YYYY-MM-DD" format, and is returned in this form
" also.
let [l:year, l:month, l:day] = todo#ParseDate(a:date)
let [l:year, l:month, l:day] = todo#DateAdd(l:year, l:month, l:day, a:units, a:unit_type)
let l:resulting_date = printf('%04d', l:year) . '-' . printf('%02d', l:month) . '-' . printf('%02d', l:day)
return l:resulting_date
endfunction
" function todo#ParseDate {{{2
function! todo#ParseDate(datestring)
" Given a date as a string in the format "YYYY-MM-DD", split the date into a
" list [year, month, day]
"
" Does not check if the date is valid other than being digits. Will throw an
" exception if the text does not match the expected date format.
if a:datestring !~? '\v^(\d{4})\-(\d{2})\-(\d{2})$'
throw "Invalid date passed '" . a:datestring . "'."
endif
let l:year = str2nr(strpart(a:datestring, 0, 4))
let l:month = str2nr(strpart(a:datestring, 5, 2))
let l:day = str2nr(strpart(a:datestring, 8, 2))
return [l:year, l:month, l:day]
endfunction "}}}
" Completion {{{1
" Simple keyword completion on all buffers {{{2
@@ -329,7 +776,11 @@ endfun
fun! TodoCopyTempItem(item)
let ret={}
let ret.word=a:item.word
if has_key(a:item, "related")
let ret.related=[a:item.related]
else
let ret.related=[]
endif
let ret.buffers=[a:item.buffers]
return ret
endfun
@@ -359,7 +810,9 @@ fun! todo#Complete(findstart, base)
let item={}
let item.word=substitute(line,'.*\('.a:base.'\S*\).*','\1',"")
let item.buffers=bufname(bufnr)
if line =~ '.*\s\('.opp.'\S\S*\).*'
let item.related=substitute(line,'.*\s\('.opp.'\S\S*\).*','\1',"")
endif
call add(res,item)
endif
endfor
@@ -372,7 +825,7 @@ fun! todo#Complete(findstart, base)
for it in res
if curitem.word==it.word
" Merge results
" Merge results
if has_key(it, "related") && index(curitem.related,it.related) <0
call add(curitem.related,it.related)
endif
if index(curitem.buffers,it.buffers) <0
@@ -392,4 +845,4 @@ fun! todo#Complete(findstart, base)
endif
endfun
" vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab foldmethod=marker

View File

@@ -1,123 +0,0 @@
" 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

@@ -22,15 +22,24 @@ Table of Contents *TodoTxt-Contents* ~
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|
6. Recurrence....................................|TodoTxt-Recurrence|
7. Mappings......................................|TodoTxt-Mappings|
7.1 Sort.....................................|TodoTxt-Sort|
7.2 Priorities...............................|TodoTxt-Priorities|
7.3 Dates....................................|TodoTxt-Dates|
7.4 Done.txt.................................|TodoTxt-Done|
7.5 Format...................................|TodoTxt-Format|
===============================================================================
1. Release notes *TodoTxt-ReleaseNotes* ~
V0.8.1 Incorporates yet another Fretep work : highlighting for tasks due today.
v0.8 Incorporates Fretep's work on overdue dates (PR#13 and PR#16) which removes
python dependency, allow to control the cursor position after a sort by todo
(see |TodoTxt-Sort| and/or issue #15) and fixes bug when sorting a file
containing only lines with due:date (issue #14).
v0.7.6 Incorporates [Sietse's work](https://github.com/sietse/todo.txt-vim/commit/57d45200c8b033d31c9191ee0eb0711c801cdb1d) to make cancel and mark as done mapping repeatable using [vim-repeat](https://github.com/tpope/vim-repeat).
v0.7.5 Incorporates Fievel's work
@@ -59,7 +68,7 @@ by David Beniamine.
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)
rules(https://github.com/todotxt/todotxt/)
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":
@@ -76,7 +85,7 @@ by David Beniamine.
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
(https://github.com/freitass/todo.txt-vim). It add several cool
functionalities including:
+ Hierarchical sort: |TodoTxt-Sort| and |TodoTxt-HierarchicalSort|.
@@ -119,7 +128,7 @@ by David Beniamine.
===============================================================================
3. TodoTxt Files *TodoTxt-Files* ~
This plugin provides a Flexible file naming for todo.txt, all the following
This plugin provides a flexible file naming for todo.txt, all the following
names are recognized as todo:
>
YYYY-MM-[Tt]odo.txt
@@ -174,6 +183,18 @@ 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.
If you don't want the preview window to open when performing completion, add the
following lines to your vimrc:
>
au filetype todo setlocal completeopt-=preview
<
If you would like the preview window to open even if there is only one match for
a completion, then add the following lines to your vimrc:
>
au filetype todo setlocal completeopt+=menuone
<
===============================================================================
5. Hierarchical sort *TodoTxt-HierarchicalSort* ~
@@ -199,17 +220,36 @@ Defaults values are:
<
For more information on the available flags see |:sort|
===============================================================================
6. Mappings *TodoTxt-Mappings* ~
6. Recurrence *TodoTxt-Recurrence* ~
By default todo-txt.vim set all the mappings secribed in this section. To
By adding a "rec:" tag to your task, when you complete (`<LocalLeader>x`) or
postpone (`<LocalLeader>p`) the task, a new recurrence will be created due after
the specified amount of time.
The format is:
`rec:[+][count][d|w|m|y]`
Where:
d = days, w = weeks, m = months, y = years
The optional `+` specifies strict recurrence (see below)
Examples:
* `rec:2w` - Recurs two weeks after the task is completed.
* `rec:3d` - Recurs three days after the task is completed.
* `rec:+1w` - Recurs one week from the due date (strict)
This is a non-standard but widely adopted keyword.
===============================================================================
7. Mappings *TodoTxt-Mappings* ~
By default todo-txt.vim set all the mappings described in this section. To
prevent this behavior, add the following line to your vimrc
>
let g:Todo_txt_do_not_map=1
<
6.1 Sort *TodoTxt-Sort*
7.1 Sort *TodoTxt-Sort*
`<LocalLeader>s` : Sort the file by priority
@@ -217,8 +257,6 @@ prevent this behavior, add the following line to your vimrc
`<LocalLeader>s@` : Sort the file on @Contexts
`<LocalLeader>sd` : 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
@@ -227,10 +265,24 @@ prevent this behavior, add the following line to your vimrc
`<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>sd` : Sort the file on due dates. Entries with a due date appear
sorted by at the beginning of the file, completed tasks are moved to the bottom and
the rest of the file is not modified.
6.2 Priorities *TodoTxt-Priorities*
When you sort by due dates, at the end of the sort, your cursor will be placed
at the top of the file. This behavior can be set with the following global
variable :
let g:TodoTxtSortDueDateCursorPos = "top"
Possible values are :
+ `top` (default): The first line of the buffer, i.e. your most outstanding task
+ `lastdue`: The last task with a due:date set
+ `notoverdue`: The first task that is not overdue (requires #13)
+ `bottom`: The last line of the buffer
7.2 Priorities *TodoTxt-Priorities*
`<LocalLeader>j` : Lower the priority of the current line
@@ -242,17 +294,27 @@ prevent this behavior, add the following line to your vimrc
`<LocalLeader>c` : Add the priority (C) to the current line
6.3 Dates *TodoTxt-Dates*
7.3 Dates *TodoTxt-Dates*
`<LocalLeader>d` : Insert the current date
`<LocalLeader>p` : Postpone the due date (accepts a count)
`<LocalLeader>P` : Decrement the due date (accepts a count)
`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*
If you would like the creation date (today) prefixed on new lines, add the
following to your vimrc:
>
let g:Todo_txt_prefix_creation_date=1
<
7.4 Done *TodoTxt-Done*
`<LocalLeader>x` : Toggle mark task as done (inserts or remove current
@@ -265,3 +327,7 @@ prevent this behavior, add the following line to your vimrc
`<LocalLeader>D` : Move completed tasks to done file, see |TodoTxt-Files|
`<LocalLeader>` is \ by default, so ̀`<LocaLeader>-s` means you type \s
7.5 Format *TodoTxt-format*
`<LocalLeader>ff` : Try to fix todo.txt format

View File

@@ -3,7 +3,6 @@
" Author: David Beniamine <david@beniamine.net>, Leandro Freitas <freitass@gmail.com>
" License: Vim license
" Website: http://github.com/dbeniamine/todo.txt-vim
" vim: ts=4 sw=4 :help tw=78 cc=80
autocmd BufNewFile,BufRead [Tt]odo.txt set filetype=todo
autocmd BufNewFile,BufRead [Tt]odo-\d\\\{4\}-\d\\\{2\}-\d\\\{2\}.txt set filetype=todo
@@ -17,3 +16,5 @@ autocmd BufNewFile,BufRead [Dd]one-\d\\\{4\}-\d\\\{2\}.txt set filetype=todo
autocmd BufNewFile,BufRead \d\\\{4\}-\d\\\{2\}-\d\\\{2\}-[Dd]one.txt set filetype=todo
autocmd BufNewFile,BufRead \d\\\{4\}-\d\\\{2\}-[Dd]one.txt set filetype=todo
autocmd BufNewFile,BufRead [Dd]one-[Tt]oday.txt set filetype=todo
" vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab foldmethod=marker

View File

@@ -3,49 +3,66 @@
" Author: David Beniamine <David@Beniamine.net>, Leandro Freitas <freitass@gmail.com>
" License: Vim license
" Website: http://github.com/dbeniamine/todo.txt-vim
" vim: ts=4 sw=4 :help tw=78 cc=80
if exists("g:Todo_txt_loaded")
finish
else
let g:Todo_txt_loaded=0.8.2
endif
" Save context {{{1
let s:save_cpo = &cpo
set cpo&vim
if exists("g:Todo_txt_loaded")
finish
else
let g:Todo_txt_loaded=0.7.6
endif
" General options {{{1
" 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 invoked, which is whenever a file of this type is
" created or edited.
setlocal textwidth=0
setlocal wrapmargin=0
" Increment and decrement the priority use <C-A> and <C-X> on alpha
setlocal nrformats+=alpha
" Mappings {{{1
if !exists("g:Todo_txt_do_not_map")
" Sort todo by (first) context
noremap <silent><localleader>sc :call todo#HierarchicalSort('@', '', 1)<CR>
" <Plug> mappings that users can map alternate keys to {{{2
" if they choose not to map default keys (or otherwise)
nnoremap <script> <silent> <buffer> <Plug>TodotxtIncrementDueDateNormal :<C-u>call <SID>ChangeDueDateWrapper(1, "\<Plug>TodotxtIncrementDueDateNormal")<CR>
vnoremap <script> <silent> <buffer> <Plug>TodotxtIncrementDueDateVisual :call <SID>ChangeDueDateWrapper(1, "\<Plug>TodotxtIncrementDueDateVisual")<CR>
nnoremap <script> <silent> <buffer> <Plug>TodotxtDecrementDueDateNormal :<C-u>call <SID>ChangeDueDateWrapper(-1, "\<Plug>TodotxtDecrementDueDateNormal")<CR>
vnoremap <script> <silent> <buffer> <Plug>TodotxtDecrementDueDateVisual :call <SID>ChangeDueDateWrapper(-1, "\<Plug>TodotxtDecrementDueDateVisual")<CR>
noremap <silent><localleader>scp :call todo#HierarchicalSort('@', '+', 1)<CR>
" Sort todo by (first) project
noremap <silent><localleader>sp :call todo#HierarchicalSort('+', '',1)<CR>
noremap <silent><localleader>spc :call todo#HierarchicalSort('+', '@',1)<CR>
noremap <script> <silent> <buffer> <Plug>DoToggleMarkAsDone :call todo#ToggleMarkAsDone('')<CR>
\:silent! call repeat#set("\<Plug>DoToggleMarkAsDone")<CR>
noremap <script> <silent> <buffer> <Plug>DoCancel :call todo#ToggleMarkAsDone('Cancelled')<CR>
\:silent! call repeat#set("\<Plug>DoCancel")<CR>
" Sort tasks {{{2
nnoremap <script> <silent> <buffer> <LocalLeader>s :call todo#Sort()<CR>
nnoremap <script> <silent> <buffer> <LocalLeader>s@ :sort /.\{-}\ze@/ <CR>
nnoremap <script> <silent> <buffer> <LocalLeader>s+ :sort /.\{-}\ze+/ <CR>
" Priorities {{{2
noremap <script> <silent> <buffer> <LocalLeader>j :call todo#PrioritizeIncrease()<CR>
noremap <script> <silent> <buffer> <LocalLeader>k :call todo#PrioritizeDecrease()<CR>
" Default key mappings {{{2
if !exists("g:Todo_txt_do_not_map") || ! g:Todo_txt_do_not_map
" Sort todo by (first) context {{{3
noremap <script> <silent> <buffer> <localleader>sc :call todo#HierarchicalSort('@', '', 1)<CR>
noremap <script> <silent> <buffer> <localleader>scp :call todo#HierarchicalSort('@', '+', 1)<CR>
noremap <script> <silent> <buffer> <LocalLeader>a :call todo#PrioritizeAdd('A')<CR>
noremap <script> <silent> <buffer> <LocalLeader>b :call todo#PrioritizeAdd('B')<CR>
noremap <script> <silent> <buffer> <LocalLeader>c :call todo#PrioritizeAdd('C')<CR>
" Sort todo by (first) project {{{3
noremap <script> <silent> <buffer> <localleader>sp :call todo#HierarchicalSort('+', '',1)<CR>
noremap <script> <silent> <buffer> <localleader>spc :call todo#HierarchicalSort('+', '@',1)<CR>
" Insert date {{{2
" Sort tasks {{{3
nnoremap <script> <silent> <buffer> <localleader>s :call todo#Sort("")<CR>
nnoremap <script> <silent> <buffer> <localleader>s@ :call todo#Sort("@")<CR>
nnoremap <script> <silent> <buffer> <localleader>s+ :call todo#Sort("+")<CR>
" Priorities {{{3
" TODO: Make vim-repeat work on inc/dec priority
noremap <script> <silent> <buffer> <localleader>j :call todo#PrioritizeIncrease()<CR>
noremap <script> <silent> <buffer> <localleader>k :call todo#PrioritizeDecrease()<CR>
noremap <script> <silent> <buffer> <localleader>a :call todo#PrioritizeAdd('A')<CR>
noremap <script> <silent> <buffer> <localleader>b :call todo#PrioritizeAdd('B')<CR>
noremap <script> <silent> <buffer> <localleader>c :call todo#PrioritizeAdd('C')<CR>
" Insert date {{{3
inoremap <script> <silent> <buffer> date<Tab> <C-R>=strftime("%Y-%m-%d")<CR>
inoremap <script> <silent> <buffer> due: due:<C-R>=strftime("%Y-%m-%d")<CR>
@@ -53,54 +70,105 @@ if !exists("g:Todo_txt_do_not_map")
noremap <script> <silent> <buffer> <localleader>d :call todo#PrependDate()<CR>
" Mark done {{{2
noremap <script> <silent> <buffer> <Plug>DoToggleMarkAsDone :call todo#ToggleMarkAsDone('')<CR>
\:call repeat#set("\<Plug>DoToggleMarkAsDone")<CR>
nmap <localleader>x <Plug>DoToggleMarkAsDone
" noremap <script> <silent> <buffer> <localleader>x :call todo#ToggleMarkAsDone('')<CR>
" Mark done {{{3
nmap <silent> <buffer> <localleader>x <Plug>DoToggleMarkAsDone
" Mark done {{{2
noremap <script> <silent> <buffer> <Plug>DoCancel :call todo#ToggleMarkAsDone('Cancelled')<CR>
\:call repeat#set("\<Plug>DoCancel")<CR>
nmap <localleader>C <Plug>DoCancel
" Mark cancelled {{{3
nmap <silent> <buffer> <localleader>C <Plug>DoCancel
" Mark all done {{{2
" Mark all done {{{3
noremap <script> <silent> <buffer> <localleader>X :call todo#MarkAllAsDone()<CR>
" Remove completed {{{2
" Remove completed {{{3
nnoremap <script> <silent> <buffer> <localleader>D :call todo#RemoveCompleted()<CR>
" Sort by due: date {{{2
" Sort by due: date {{{3
nnoremap <script> <silent> <buffer> <localleader>sd :call todo#SortDue()<CR>
" try fix format {{{3
nnoremap <script> <silent> <buffer> <localleader>ff :call todo#FixFormat()<CR>
" increment and decrement due:date {{{3
nmap <silent> <buffer> <localleader>p <Plug>TodotxtIncrementDueDateNormal
vmap <silent> <buffer> <localleader>p <Plug>TodotxtIncrementDueDateVisual
nmap <silent> <buffer> <localleader>P <Plug>TodotxtDecrementDueDateNormal
vmap <silent> <buffer> <localleader>P <Plug>TodotxtDecrementDueDateVisual
endif
" Additional options {{{2
" Prefix creation date when opening a new line {{{3
if exists("g:Todo_txt_prefix_creation_date")
nnoremap <script> <silent> <buffer> o o<C-R>=strftime("%Y-%m-%d")<CR>
nnoremap <script> <silent> <buffer> O O<C-R>=strftime("%Y-%m-%d")<CR>
inoremap <script> <silent> <buffer> <CR> <CR><C-R>=strftime("%Y-%m-%d")<CR>
endif
" Functions for maps {{{1
function! s:ChangeDueDateWrapper(by_days, repeat_mapping)
call todo#CreateNewRecurrence(0)
call todo#ChangeDueDate(a:by_days, 'd', '')
silent! call repeat#set(a:repeat_mapping, v:count)
endfunction
" Folding {{{1
" Options {{{2
setlocal foldmethod=expr
setlocal foldexpr=TodoFoldLevel(v:lnum)
setlocal foldtext=TodoFoldText()
" Go to first completed task
let oldpos=getcurpos()
if(!exists("g:Todo_fold_char"))
let g:Todo_fold_char='@'
let base_pos=search('^x\s', 'ce')
" Get next completed task
let first_incomplete = search('^\s*[^<x\s>]')
if (first_incomplete < base_pos)
" Check if all tasks from
let g:Todo_fold_char='x'
endif
call setpos('.', oldpos)
endif
function! s:get_contextproject(line) abort "{{{2
return matchstr(getline(a:line), g:Todo_fold_char.'[^ ]\+')
endfunction "}}}3
" TodoFoldLevel(lnum) {{{2
function! TodoFoldLevel(lnum)
" The match function returns the index of the matching pattern or -1 if
" the pattern doesn't match. In this case, we always try to match a
" completed task from the beginning of the line so that the matching
" function will always return -1 if the pattern doesn't match or 0 if the
" pattern matches. Incrementing by one the value returned by the matching
" function we will return 1 for the completed tasks (they will be at the
" first folding level) while for the other lines 0 will be returned,
" indicating that they do not fold.
return match(getline(a:lnum),'^[xX]\s.\+$') + 1
let this_context = s:get_contextproject(a:lnum)
let next_context = s:get_contextproject(a:lnum - 1)
if g:Todo_fold_char == 'x'
" fold on cmpleted task
return match(getline(a:lnum),'\C^x\s') + 1
endif
let fold_level = 0
if this_context ==# next_context
let fold_level = '1'
else
let fold_level = '>1'
endif
return fold_level
endfunction
" TodoFoldText() {{{2
function! TodoFoldText()
let this_context = s:get_contextproject(v:foldstart)
if g:Todo_fold_char == 'x'
let this_context = 'Completed tasks'
endif
" The text displayed at the fold is formatted as '+- N Completed tasks'
" where N is the number of lines folded.
return '+' . v:folddashes . ' '
\ . (v:foldend - v:foldstart + 1)
\ . ' Completed tasks '
\ .' '. this_context.' '
endfunction
" Restore context {{{1
let &cpo = s:save_cpo
" vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab foldmethod=marker

View File

@@ -1,11 +0,0 @@
#!/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 dateregex.after import regex_date_after
from dateregex.before import regex_date_before

View File

@@ -1,95 +0,0 @@
#!/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

@@ -1,79 +0,0 @@
#!/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) % 12 + 1, 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

View File

@@ -1,31 +0,0 @@
#!/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,44 +3,46 @@
" Author: David Beniamine <David@Beniamine.net>,Leandro Freitas <freitass@gmail.com>
" License: Vim license
" Website: http://github.com/dbeniamine/todo.txt-vim
" vim: ts=4 sw=4 :help tw=78 cc=80
if exists("b:current_syntax")
finish
endif
syntax match TodoDone '^[xX]\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityA '^([aA])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityB '^([bB])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityC '^([cC])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityD '^([dD])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityE '^([eE])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityF '^([fF])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityG '^([gG])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityH '^([hH])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityI '^([iI])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityJ '^([jJ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityK '^([kK])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityL '^([lL])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityM '^([mM])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityN '^([nN])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityO '^([oO])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityP '^([pP])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityQ '^([qQ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityR '^([rR])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityS '^([sS])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityT '^([tT])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityU '^([uU])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityV '^([vV])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityW '^([wW])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityX '^([xX])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityY '^([yY])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoPriorityZ '^([zZ])\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,OverDueDate
syntax match TodoDone '^[x]\s.\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext
syntax match TodoPriorityA '^(A) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityB '^(B) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityC '^(C) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityD '^(D) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityE '^(E) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityF '^(F) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityG '^(G) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityH '^(H) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityI '^(I) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityJ '^(J) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityK '^(K) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityL '^(L) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityM '^(M) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityN '^(N) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityO '^(O) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityP '^(P) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityQ '^(Q) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityR '^(R) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityS '^(S) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityT '^(T) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityU '^(U) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityV '^(V) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityW '^(W) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityX '^(X) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityY '^(Y) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoPriorityZ '^(Z) .\+$' contains=TodoKey,TodoDate,TodoProject,TodoContext,TodoDueToday,TodoOverDueDate
syntax match TodoDate '\d\{2,4\}-\d\{2\}-\d\{2\}' contains=NONE
syntax match TodoKey '\S*\S:\S\S*' contains=TodoDate
syntax match TodoProject '\(^\|\W\)+[^[:blank:]]\+' contains=NONE
syntax match TodoContext '\(^\|\W\)@[^[:blank:]]\+' contains=NONE
let s:todayDate=strftime('%Y\-%m\-%d')
execute 'syntax match TodoDueToday /\v\c<due:' . s:todayDate . '>/ contains=NONE'
" Other priority colours might be defined by the user
highlight default link TodoKey Special
highlight default link TodoDone Comment
@@ -50,13 +52,137 @@ highlight default link TodoPriorityC type
highlight default link TodoDate PreProc
highlight default link TodoProject Special
highlight default link TodoContext Special
highlight default link TodoDueToday Todo
let b:curdir = expand('<sfile>:p:h')
let s:script_dir = b:curdir . "/python/"
if has('python3')
execute "py3file " . s:script_dir. "todo.py"
elseif has('python')
execute "pyfile " . s:script_dir. "todo.py"
endif
function! todo#GetDateRegexForPastDates(...)
" Build a RegExp to match all dates prior to a reference date.
"
" Optionally accepts a (year, month, day) for the date, otherwise assumes the
" reference date is the current date.
"
" In the end, the RegExp will look something like:
" =todo#GetDateRegexForPastDates(2017, 09, 15)
" \v(([01]\d{3}|200\d|201[0-6])\-\d{2}\-\d{2}|(2017\-(0[0-8])\-\d{2})|(2017\-09\-0\d)|(2017\-09\-1[0-4]))
"
" We split the RegExp into a few alternation groups:
" 1. All dates prior to 2000, dates before this are not supported
" 2. All previous decades for the reference date century
" 3. The current decade up to the year prior to the reference year
" 4. All months for the reference year up to the end of the previous month
" 5. Days of the month part 1.
" 6. Days of the month part 2.
"
" Will not work on reference dates past 2099, or before 2000.
"
" Invalid months and days are not checked, i.e. 2015-14-67 will match.
"
" Years must be 4 digits.
"
" Get the reference date
let l:day=strftime("%d")
let l:month=strftime("%m")
let l:year=strftime("%Y")
if a:0 >= 1
let l:year=a:1
endif
if a:0 >= 2
let l:month=a:2
endif
if a:0 >= 3
let l:day=a:3
endif
" Use very magic mode, and start an alternation
let l:overdueRex = '\v('
" PART 1: 0000-1999
" This sucker is static and won't change to year 3000. I'm not coding for the year 3000.
let l:overdueRex = l:overdueRex . '([01]\d{3}'
" PART 2. All previous decades for the reference date century
" i.e. for 2017: "200\d", for 2035: "20[0-2]\d"
" for 2000: skip
let l:decade = strpart(l:year, 2, 1) " i.e. the 1 from 2017
if l:decade > 0
let l:overdueRex = l:overdueRex . '|20'
if l:decade > 1
let l:overdueRex = l:overdueRex . '[0-' . (l:decade - 1) . ']'
else
let l:overdueRex = l:overdueRex . '0'
endif
let l:overdueRex = l:overdueRex . '\d'
endif
" PART 3: This decade, to previous year
" i.e. for 2017: "201[0-6]", for 2035: "203[0-4]", for 2000: skip
let l:y = strpart(l:year, 3, 1) " Last digit of the year, i.e. 7 for 2017
if l:y > 0
if l:y > 1
let l:overdueRex = l:overdueRex . '|20' . l:decade . '[0-' . (l:y - 1) . ']'
else
let l:overdueRex = l:overdueRex . '|20' . l:decade . '0'
endif
endif
let l:overdueRex = l:overdueRex . ')\-\d{2}\-\d{2}|'
" PART 4: All months to the end of the previous month
" i.e. for a date of 2017-09-07, "2017-(0[1-8])-\d{2}"
" for 2017-10-01: "2017-(0[0-9])-\d{2}"
" for 2017-11-30: "2017-(0\d|1[0-0])-\d{2}"
" for 2017-12-30: "2017-(0\d|1[0-1])-\d{2}"
" for 2017-01-20: skip
" This only applies if the reference date is not in January
if l:month > 1
let l:overdueRex = l:overdueRex . '(' . l:year . '\-(0'
if l:month > 10
let l:overdueRex = l:overdueRex . '\d|1'
endif
let l:y = strpart(printf('%02d', l:month), 1, 1) " Second digit of the month
if l:month == 10
" When the month is 10, y = 0, and y - 1 = -1 = bad, deal with it.
let l:y = 10
endif
let l:overdueRex = l:overdueRex . '[0-' . (l:y - 1) . '])\-\d{2})|'
endif
" PART 5. Days of the month part 1.
" i.e. for 2017-09-07: skip
" for 2017-12-29: "2017-12-[0-1]\d"
let l:y = strpart(printf('%02d', l:day), 0, 1) " First digit of the day
if l:y > 0
if l:y > 1
let l:overdueRex = l:overdueRex . '(' . l:year . '\-' . printf('%02d', l:month) . '\-[0-' . (l:y - 1) . ']\d)|'
else
let l:overdueRex = l:overdueRex . '(' . l:year . '\-' . printf('%02d', l:month) . '\-0\d)|'
endif
endif
" PART 6. Days of the month part 2.
" i.e. for 2017-09-07: "2017-09-0[0-6]"
" for 2017-12-29: "2017-12-2[0-8]"
" for 2017-09-20: skip
let l:d = strpart(printf('%02d', l:day), 1, 1) " Last digit of the day
if l:d > 0
let l:y = strpart(printf('%02d', l:day), 0, 1) " First digit of the day
let l:overdueRex = l:overdueRex . '(' . l:year . '\-' . printf('%02d', l:month) . '\-' . l:y
if l:d > 1
let l:overdueRex = l:overdueRex . '[0-' . (l:d - 1) . ']'
else
let l:overdueRex = l:overdueRex . '0'
endif
let l:overdueRex = l:overdueRex . ')'
endif
let l:overdueRex = substitute(l:overdueRex, '|$', '', 'e')
let l:overdueRex = l:overdueRex . ')'
return l:overdueRex
endfunction
execute 'syntax match TodoOverDueDate /\v\c<due:' . todo#GetDateRegexForPastDates() . '>/'
highlight default link TodoOverDueDate Error
let b:current_syntax = "todo"
" vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab foldmethod=marker

17
tests/clean-vim.sh Normal file
View File

@@ -0,0 +1,17 @@
#/bin/bash
# Start a clean vim for testing development.
REPO_TOP=$(git rev-parse --show-toplevel)
cd "${REPO_TOP}"
vim -Nu <(cat <<EOF
filetype off
set rtp+=~/.vim/bundle/vader.vim
set rtp+=./
filetype plugin indent on
syntax enable
autocmd filetype todo setlocal omnifunc=todo#Complete
EOF
) $*

23
tests/include/setup.vader Normal file
View File

@@ -0,0 +1,23 @@
Execute (Clean up test environment):
Save maplocalleader
let maplocalleader = '\'
function! ReplaceCurrentDates(expected)
if a:expected != ''
execute "silent! %substitute/" . a:expected . "/**EXPECTED**/"
endif
execute "silent! %substitute/" . strftime("%Y-%m-%d") . "/**TODAY**/"
for b:unit in ['D', 'W', 'M', 'Y']
let [s:year, s:month, s:day] = todo#ParseDate(strftime("%Y-%m-%d"))
let [s:year, s:month, s:day] = todo#DateAdd(s:year, s:month, s:day, 2, b:unit)
let s:duedate = printf('%04d', s:year) . '-' . printf('%02d', s:month) . '-' . printf('%02d', s:day)
execute "silent! %substitute/" . s:duedate . "/**TODAY+2" . b:unit . "**/"
endfor
endfunction
let g:Todo_fold_char='x'
Before:
After:
Given:

View File

@@ -0,0 +1,4 @@
Given:
Execute (Restoring test environment):
Restore

49
tests/runtests.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
REPO_TOP=$(git rev-parse --show-toplevel)
cd "${REPO_TOP}"
echo "Basic environment"
echo "-----------------"
vim -Nu <(cat <<EOF
filetype off
set rtp+=~/.vim/bundle/vader.vim
set rtp+=./
filetype plugin indent on
syntax enable
autocmd filetype todo setlocal omnifunc=todo#Complete
EOF
) +Vader! tests/*.vader && echo Success || exit 1
# Run through variations of user preferences that might mess with us.
echo
echo "Ignore case enabled"
echo "-------------------"
vim -Nu <(cat <<EOF
filetype off
set rtp+=~/.vim/bundle/vader.vim
set rtp+=./
filetype plugin indent on
syntax enable
autocmd filetype todo setlocal omnifunc=todo#Complete
set ignorecase
EOF
) +Vader! tests/*.vader && echo Success || exit 1
echo
echo "no hyphen in iskeyword"
echo "----------------------"
vim -Nu <(cat <<EOF
filetype off
set rtp+=~/.vim/bundle/vader.vim
set rtp+=./
filetype plugin indent on
syntax enable
autocmd filetype todo setlocal omnifunc=todo#Complete
set iskeyword+=-
EOF
) +Vader! tests/*.vader && echo Success || exit 1
echo
echo "All tests are passing."
echo

118
tests/todo.txt Normal file
View File

@@ -0,0 +1,118 @@
x Test todo.txt file with a number of test cases from the vader unit tests for quick manual checks.
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L01
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L02
x (A) Done due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L03
Active due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L04
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L05
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L06
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L01
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L02
(A) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L03
(B) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L04
(C) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L05
(D) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L06
(E) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L07
(F) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L08
(G) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L09
(H) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L10
(I) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L11
(J) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L12
(K) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L13
(L) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L14
(M) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L15
(N) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L16
(O) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L17
(P) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L18
(Q) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L19
(R) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L20
(S) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L21
(T) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L22
(U) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L23
(V) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L24
(W) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L25
(X) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L26
(Y) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L27
(Z) Priorit due:2000-01-01 due:2050-01-01 2017-09-10 +Project @Context key:value L28
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L29
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L30
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L01
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L02
X Done tasks must start with a lowercase x then space L03
xDone tasks must start with a lowercase x then space L04
XDone tasks must start with a lowercase x then space L05
(a) Priority must start with an uppercase letter in rounds followed by space L06
(A)Priority must start with an uppercase letter in rounds followed by space L07
A Priority must start with an uppercase letter in rounds followed by space L08
a Priority must start with an uppercase letter in rounds followed by space L09
Priority (A) must start with an uppercase letter in rounds followed by space L10
due:2050-01-01 keys are valid on the start of the line L11
due:2010-01-01 overdue dates are valid on the start of the line L12
2010-01-01 dates are valid on the start of the line L13
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L14
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L15
Invalid dates 17-10-05 20100101 01-01-2010 2010/01/01 10/01/01 2010-01-01-2010 L16
@Contexts are valid on the start of the line L17
+Projects are valid on the start of the line L18
The key: syntax must be followed by a value, same for due: L19
due: syntax must be a whole word notdue:2010-01-01 pro@jects and con+texts also L20
x 345678901234567890123456789012345678901234567890123456789012345678901234567890 L21
x . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 L22
x 2017-09-18 Complete task
x 2017-09-18 2017-09-01 Completed task with a created date
x 2017-09-18 (A) Completed priority task
x 2017-09-18 2017-09-01 (A) Completed priority task with a created date
X 2017-09-18 Not to be confused for a complete task
Active task
2017-09-01 Active task with a created date
(A) Active priority task
(A) 2017-09-01 Active priority task with a created date
X 2017-09-18 Not to be confused for a complete task
XNot to be confused for a complete task
x 2017-09-18 Rules are not clear on leading whitespace, see comments in test
Tricky incomplete task x 2017-09-18
active dUE:2051-01-01 cAsE EXP:24 GIV:01
overdue due:2001-01-01 EXP:02 GIV:02
notdue overdue:2011-11-11 invalid key EXP:33 GIV:03
overdue duE:2009-01-01 cAsE EXP:18 GIV:04
xoverdue due:2001-02-01 This is not done (must be lower x) EXP:03 GIV:05
overdue due:2012-01-01 \|| no tasks the between bars ||/ EXP:21 GIV:06
x done due:2011-11-11 topmost done task EXP:44 GIV:07
notdue due: 2011-11-11 space invalidates due: EXP:34 GIV:08
overdue due:2005-01-01 +Project @Context EXP:10 GIV:09
overdue due:2002-01-01 @Context EXP:04 GIV:10
overdue due:2004-02-01 EXP:09 GIV:11
notdue due: due:2011-MM-DD EXP:35 GIV:12
overdue due:2000-01-01 cursor here for top, most overdue EXP:01 GIV:13
notdue due:2011-11-1 EXP:36 GIV:14
active due:2059-01-01 bottommost active task EXP:32 GIV:15
overdue due:2006-01-01 EXP:12 GIV:16
overdue due:2007-02-01 +Project EXP:15 GIV:17
active due:2056-01-01 EXP:29 GIV:18
notdue due:2011-1-11 EXP:37 GIV:19
x done due:2011-11-11 EXP:45 GIV:20
overdue dUe:2008-02-01 cAsE EXP:17 GIV:21
X overdue due:2002-02-01 This is not done (must be lower x) EXP:05 GIV:22
+Project overdue due:2003-02-01 project at start of line EXP:07 GIV:23
notdue due:2011 EXP:38 GIV:24
active DUe:2052-01-01 cAsE EXP:25 GIV:25
overdue due:2007-01-01 EXP:14 GIV:26
overdue Due:2008-01-01 cAsE EXP:16 GIV:27
notdue @Project EXP:39 GIV:28
active due:2055-01-01 EXP:28 GIV:29
active due:2057-01-01 EXP:30 GIV:30
overdue DuE:2009-02-01 cAsE EXP:19 GIV:31
notdue @Context EXP:40 GIV:32
x done due:2011-11-11 bottommost done task cursor here bottom EXP:46 GIV:33
active DUE:2053-01-01 cAsE EXP:26 GIV:34
active key:value due:2054-01-01 leading key:value EXP:27 GIV:35
active due:2058-01-01 EXP:31 GIV:36
notdue key:value EXP:41 GIV:37
overdue due:2017-01-01 Last overdue task when sorted EXP:22 GIV:38
overdue due:2010-12-31 /|| no tasks the between bars ||\ EXP:20 GIV:39
active due:2050-01-01 cursor here with "notoverdue" setting EXP:23 GIV:40
notdue due:invalid invalid due date EXP:42 GIV:41
overdue 2011-11-11 due:2005-02-01 leading date EXP:11 GIV:42
due:2004-01-01 overdue due: at start of line EXP:08 GIV:43
notdue notdue:2011-11-11 invalid key EXP:43 GIV:44
overdue due:2006-02-01 due:2011-11-11 two dates, choose first EXP:13 GIV:45
@Context overdue due:2003-01-01 context at start of line EXP:06 GIV:46

1409
tests/todo.vader Normal file

File diff suppressed because it is too large Load Diff