Functions to remove all todo items that are done (#906)

Add function VimwikiRemoveDone that will delete lines with todo list items marked as done. Works on ranges as well as without range on the current list.

Co-authored-by: Tinmarino <tinmarino@gmail.com>
This commit is contained in:
Michael F. Schönitzer 2020-06-08 14:31:35 +02:00 committed by GitHub
parent 61093f4f2a
commit a9f21c6d4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 329 additions and 0 deletions

View File

@ -155,6 +155,24 @@ function! s:line_has_marker(lnum) abort
endfunction
" Remove a list item and it's children (recursive)
function! s:remove_including_children(item)
let num_removed_lines = 1
let child = s:get_first_child(a:item)
while child.type != 0
let num_removed_lines += s:remove_including_children(child)
let child = s:get_first_child(a:item)
endwhile
exec a:item.lnum.'delete _'
return num_removed_lines
endfunction
function! s:is_done(item)
return a:item.type != 0 && a:item.cb !=# '' && s:get_rate(a:item) == 100
endfunction
" ---------------------------------------------------------
" get properties of a list item
" ---------------------------------------------------------
@ -1085,6 +1103,105 @@ function! vimwiki#lst#remove_cb_in_list() abort
endfunction
" Iterate over given todo list and remove all task that are done
" If recursive is true, child items will be checked too
function! s:remove_done_in_list(item, recursive)
" Clause non-null item type
if a:item.type == 0
return
endif
" Recurse self on list item
let first_item = s:get_first_item_in_list(a:item, 0)
let total_lines_removed = 0
let cur_item = first_item
while 1
let next_item = s:get_next_list_item(cur_item, 0)
if s:is_done(cur_item)
let lines_removed = s:remove_including_children(cur_item)
elseif a:recursive
let lines_removed = s:remove_done_in_list(s:get_first_child(cur_item), a:recursive)
else
let lines_removed = 0
endif
let total_lines_removed += lines_removed
if next_item.type == 0
break
else
let next_item.lnum -= lines_removed
let cur_item = next_item
endif
endwhile
" Update state of parent item (percentage of done)
call s:update_state(s:get_parent(first_item))
return total_lines_removed
endfunction
" Iterate over the list that the cursor is positioned in
" and remove all lines of task that are done.
" If recursive is true, child items will be checked too
function! vimwiki#lst#remove_done_in_current_list(recursive)
let item = s:get_corresponding_item(line('.'))
call s:remove_done_in_list(item, a:recursive)
endfunction
" Remove selected lines if they contain a task that is done
function! vimwiki#lst#remove_done_in_range(first_line, last_line)
let first_item = s:get_corresponding_item(a:first_line)
let last_item = s:get_corresponding_item(a:last_line)
" Clause non-null first and last type item
if first_item.type == 0 || last_item.type == 0
return
endif
" For each line, delete done tasks
let parent_items_of_lines = []
let cur_ln = first_item.lnum
let end_ln = last_item.lnum
while cur_ln > 0 && cur_ln <= end_ln
let cur_item = s:get_item(cur_ln)
if s:is_done(cur_item)
let cur_parent_item = s:get_parent(cur_item)
if index(parent_items_of_lines, cur_parent_item) == -1
call insert(parent_items_of_lines, cur_parent_item)
endif
exe cur_ln.'delete _'
let cur_ln -= 1
let end_ln -= 1
endif
let cur_ln = s:get_next_line(cur_ln)
endwhile
" Update all parent state (percentage of done)
for parent_item in parent_items_of_lines
call s:update_state(parent_item)
endfor
endfunction
" wrapper function to distinguish between function used with a range or not
" vim 8.0.1089 and newer and corresponding neovim versions allow to use <range> to distinguish if
" the function has been called with a range. For older versions we use remove_done_in_range if
" first and last line are identical, which means there was either no range or the range was within
" one line.
function! vimwiki#lst#remove_done(recursive, range, first_line, last_line)
if a:range ==# '<range>'
let range = a:first_line != a:last_line
else
let range = a:range > 0
endif
if range
call vimwiki#lst#remove_done_in_range(a:first_line, a:last_line)
else
call vimwiki#lst#remove_done_in_current_list(a:recursive)
endif
endfunction
" ---------------------------------------------------------
" change the level of list items

View File

@ -799,6 +799,18 @@ Vimwiki file.
*:VimwikiRenameFile*
Rename the wiki page you are in.
*:VimwikiRemoveDone*
With range: Remove all lines that have a checked |vimwiki-todo-lists| checkbox
Otherwise:
Remove all lines in the current todo-list that have a checked box. This is
applied to the list in which the cursor is in, as well as all its sublists.
The status of parents is updated accordingly.
If you want to remove only items of the current nesting level, (re)define
a command that calls the same function with `0` as first argument: >
:command! -buffer -range VimwikiRemoveDone call
\ vimwiki#lst#remove_done(0, "<range>", <line1>, <line2>)
<
*:VimwikiNextTask*
Jump to the next unfinished task in the current wiki page.

View File

@ -297,6 +297,7 @@ command! -buffer VimwikiRemoveCBInList call vimwiki#lst#remove_cb_in_list()
command! -buffer VimwikiRenumberList call vimwiki#lst#adjust_numbered_list()
command! -buffer VimwikiRenumberAllLists call vimwiki#lst#adjust_whole_buffer()
command! -buffer VimwikiListToggle call vimwiki#lst#toggle_list_item()
command! -buffer -range VimwikiRemoveDone call vimwiki#lst#remove_done(1, "<range>", <line1>, <line2>)
" table commands
command! -buffer -nargs=* VimwikiTable call vimwiki#tbl#create(<f-args>)

199
test/list_clean.vader Normal file
View File

@ -0,0 +1,199 @@
Include: vader_includes/vader_setup.vader
Given vimwiki (simple list):
* [X] Done 1
* [ ] Todo 1
* [X] Done 2
* [ ] Todo 2
Execute (Set syntax to default):
call SetSyntax('default')
Do (clean done, without recursion):
:call vimwiki#lst#remove_done_in_current_list(0)\<Enter>
Expect (two removed):
* [ ] Todo 1
* [ ] Todo 2
Given vimwiki (simple list):
* [X] Done 1
* [ ] Todo 1
* [X] Done 2
* [ ] Todo 2
Do (clean done with recursion, function):
:call vimwiki#lst#remove_done_in_current_list(1)\<Enter>
Expect (two removed):
* [ ] Todo 1
* [ ] Todo 2
Given vimwiki (simple list):
* [X] Done 1
* [ ] Todo 1
* [X] Done 2
* [ ] Todo 2
Do (clean done with recursion, command):
:VimwikiRemoveDone\<Enter>
Expect (two removed):
* [ ] Todo 1
* [ ] Todo 2
Given vimwiki (with sub items):
* [X] Done 1
* [X] Subdone 1
* [ ] Todo 1
* [o] Done 2
* [X] Subdone1
* [ ] Subtodo
* [ ] Todo 2
Do (clean done, without recursion):
:call vimwiki#lst#remove_done_in_current_list(0)\<Enter>
Expect (first removed):
* [ ] Todo 1
* [o] Done 2
* [X] Subdone1
* [ ] Subtodo
* [ ] Todo 2
Given vimwiki (with sub items):
* [ ] Todo 1
* [o] Done 2
* [X] Subdone1
* [ ] Subtodo
* [ ] Todo 2
Do (clean done, with recursion):
:call vimwiki#lst#remove_done_in_current_list(1)\<Enter>
Expect (all removed):
* [ ] Todo 1
* [ ] Done 2
* [ ] Subtodo
* [ ] Todo 2
Given vimwiki (nested list with space and code):
* [X] Done 1
* [ ] Todo 1
* [ ] Todo Post space
* [X] Done Post space
* [ ] Todo code
{{{code
* [X] print "hello, world"
}}}
* [ ] Post code Todo
* [X] Done Sub-child
* [X] Sub-sub-child
* Without cb
* [X] Post code Done
* [X] Done Sub-child
* [X] Sub-sub-child
* Without cb
Do (clean done, without recursion):
:call vimwiki#lst#remove_done_in_current_list(0)\<Enter>
Expect (removed):
* [ ] Todo 1
* [ ] Todo Post space
* [ ] Todo code
{{{code
* [X] print "hello, world"
}}}
* [ ] Post code Todo
* [X] Done Sub-child
* [X] Sub-sub-child
* Without cb
Given vimwiki (nested list with space and code):
* [X] Done 1
* [ ] Todo 1
* [ ] Todo Post space
* [X] Done Post space
* [ ] Todo code
{{{code
* [X] print "hello, world"
}}}
* [ ] Post code Todo
* [X] Done Sub-child
* [X] Sub-sub-child
* Without cb
* [X] Post code Done
* [X] Done Sub-child
* [X] Sub-sub-child
* Without cb
Do (clean done, with recursion):
:call vimwiki#lst#remove_done_in_current_list(1)\<Enter>
Expect (removed):
* [ ] Todo 1
* [ ] Todo Post space
* [ ] Todo code
{{{code
* [X] print "hello, world"
}}}
* [ ] Post code Todo
Given vimwiki (two lists):
* [X] Done 1
* [ ] Todo 1
Line in between.
* [ ] Todo Post space
* [X] Done Post space
Do (clean done, with recursion):
:call vimwiki#lst#remove_done_in_current_list(1)\<Enter>
Expect (only first is removed):
* [ ] Todo 1
Line in between.
* [ ] Todo Post space
* [X] Done Post space
Given vimwiki (list):
* [X] Done 1
* [ ] Todo 1
Line in between.
* [X] Done 2
* [X] Done 3
* [ ] Todo 2
* [X] Done 4
Do (clean done, with range):
:1,6VimwikiRemoveDone\<Enter>
Expect (only first is removed):
* [ ] Todo 1
Line in between.
* [X] Done 3
* [ ] Todo 2
* [X] Done 4
Include: vader_includes/vader_teardown.vader