Skip to content

Commit cd7b3c3

Browse files
committed
Merge branch 'dev'
2 parents c650c39 + 7e67d26 commit cd7b3c3

File tree

3 files changed

+194
-5
lines changed

3 files changed

+194
-5
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ The sequence matching the expression '^\s\*[ ].\*' marks a line as a TODO list i
3838
[X] Done
3939
```
4040

41+
##### Items Hierarchy
42+
43+
If one item has lesser indentation than the next one then the first one is meant
44+
to be **parent** and the second to be **child**.
45+
46+
###### Example
47+
48+
```
49+
[ ] Parent
50+
[ ] Child1
51+
[ ] Child2
52+
```
53+
54+
###### Rules:
55+
* Changig state of the parent item changes the state of all children items accorndantly
56+
* If all children items are marked done, parent will also be marked as done
57+
* If parent is marked as done and one of the children changes state to not done
58+
parent will also be marked as not done
59+
4160
##### Commands
4261

4362
* `:VimTodoListsCreateNewItemAbove` - creates a new item in a line above cursor
@@ -126,6 +145,11 @@ Changelog
126145
* Improves work with indentations of list items
127146
* Fixed the error when trying to navigate the buffer that doesn't contain items
128147

148+
149+
#### 0.4.0
150+
151+
* Added items hierarchy support
152+
129153
Credits
130154
-------
131155

doc/vim-todo-lists.txt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*vim-todo-lists.txt* Version 0.3.0
1+
*vim-todo-lists.txt* Version 0.4.0
22
*vim-todo-lists*
33

44
Plugin for TODO lists management.
@@ -59,6 +59,25 @@ Example
5959
[ ] Not done
6060
[X] Done
6161

62+
Items Hierarchy
63+
---------------
64+
65+
If one item has lesser indentation than the next one then the first one is meant
66+
to be 'parent' and the second to be 'child'.
67+
68+
Example
69+
-------
70+
71+
[ ] Parent
72+
[ ] Child1
73+
[ ] Child2
74+
75+
Rules:
76+
* Changig state of the parent item changes the state of all children items accorndantly
77+
* If all children items are marked done, parent will also be marked as done
78+
* If parent is marked as done and one of the children changes state to not done
79+
parent will also be marked as not done
80+
6281
Commands
6382
--------
6483
*:VimTodoListsCreateNewItemAbove* *:VimTodoListsCreateNewItemBelow*
@@ -159,6 +178,10 @@ SOFTWARE.
159178
* Improves work with indentations of list items
160179
* Fixed the error when trying to navigate the buffer that doesn't contain items
161180

181+
0.4.0
182+
183+
* Added items hierarchy support
184+
162185
==============================================================================
163186
8. Credits *VimTodoListsCredits*
164187

plugin/vim-todo-lists.vim

Lines changed: 146 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,147 @@ function! VimTodoListsInit()
4444
endfunction
4545

4646

47+
" Sets the item done
48+
function! VimTodoListsSetItemDone(lineno)
49+
let l:line = getline(a:lineno)
50+
call setline(a:lineno, substitute(l:line, '^\(\s*\)\[ \]', '\1[X]', ''))
51+
endfunction
52+
53+
54+
" Sets the item not done
55+
function! VimTodoListsSetItemNotDone(lineno)
56+
let l:line = getline(a:lineno)
57+
call setline(a:lineno, substitute(l:line, '^\(\s*\)\[X\]', '\1[ ]', ''))
58+
endfunction
59+
60+
61+
" Checks that line is a todo list item
62+
function! VimTodoListsLineIsItem(line)
63+
if match(a:line, '^\s*\[[ X]\].*') != -1
64+
return 1
65+
else
66+
67+
return 0
68+
endfunction
69+
70+
71+
" Checks that item is not done
72+
function! VimTodoListsItemIsNotDone(line)
73+
if match(a:line, '^\s*\[ \].*') != -1
74+
return 1
75+
else
76+
return 0
77+
endif
78+
79+
return 0
80+
endfunction
81+
82+
83+
" Checks that item is done
84+
function! VimTodoListsItemIsDone(line)
85+
if match(a:line, '^\s*\[X\].*') != -1
86+
return 1
87+
else
88+
return 0
89+
endif
90+
91+
return 0
92+
endfunction
93+
94+
95+
" Counts the number of leading spaces
96+
function! VimTodoListsCountLeadingSpaces(line)
97+
return (strlen(a:line) - strlen(substitute(a:line, '^\s*', '', '')))
98+
endfunction
99+
100+
101+
" Returns the line number of the parent
102+
function! VimTodoListsFindParent(lineno)
103+
let l:indent = VimTodoListsCountLeadingSpaces(getline(a:lineno))
104+
let l:parent_lineno = -1
105+
106+
for current_line in range (a:lineno, 1, -1)
107+
if (VimTodoListsLineIsItem(getline(current_line)) &&
108+
\ VimTodoListsCountLeadingSpaces(getline(current_line)) < l:indent)
109+
let l:parent_lineno = current_line
110+
break
111+
endif
112+
endfor
113+
114+
return l:parent_lineno
115+
endfunction
116+
117+
118+
" Returns the line number of the last child
119+
function! VimTodoListsFindLastChild(lineno)
120+
let l:indent = VimTodoListsCountLeadingSpaces(getline(a:lineno))
121+
let l:last_child_lineno = a:lineno
122+
123+
" If item is the last line in the buffer it has no children
124+
if a:lineno == line('$')
125+
return l:last_child_lineno
126+
endif
127+
128+
for current_line in range (a:lineno + 1, line('$'))
129+
if (VimTodoListsLineIsItem(getline(current_line)) &&
130+
\ VimTodoListsCountLeadingSpaces(getline(current_line)) > l:indent)
131+
let l:last_child_lineno = current_line
132+
else
133+
break
134+
endif
135+
endfor
136+
137+
return l:last_child_lineno
138+
endfunction
139+
140+
141+
" Marks the parent done if all children are done
142+
function! VimTodoListsUpdateParent(lineno)
143+
let l:parent_lineno = VimTodoListsFindParent(a:lineno)
144+
145+
" No parent item
146+
if l:parent_lineno == -1
147+
return
148+
endif
149+
150+
let l:last_child_lineno = VimTodoListsFindLastChild(l:parent_lineno)
151+
152+
" There is no children
153+
if l:last_child_lineno == l:parent_lineno
154+
return
155+
endif
156+
157+
for current_line in range(l:parent_lineno + 1, l:last_child_lineno)
158+
if VimTodoListsItemIsNotDone(getline(current_line)) == 1
159+
" Not all children are done
160+
call VimTodoListsSetItemNotDone(l:parent_lineno)
161+
call VimTodoListsUpdateParent(l:parent_lineno)
162+
return
163+
endif
164+
endfor
165+
166+
call VimTodoListsSetItemDone(l:parent_lineno)
167+
call VimTodoListsUpdateParent(l:parent_lineno)
168+
endfunction
169+
170+
171+
" Applies the function for each child
172+
function! VimTodoListsForEachChild(lineno, function)
173+
let l:last_child_lineno = VimTodoListsFindLastChild(a:lineno)
174+
175+
" No children items
176+
if l:last_child_lineno == a:lineno
177+
call call(a:function, [a:lineno])
178+
return
179+
endif
180+
181+
for current_line in range(a:lineno, l:last_child_lineno)
182+
call call(a:function, [current_line])
183+
endfor
184+
185+
endfunction
186+
187+
47188
" Sets mapping for normal navigation and editing mode
48189
function! VimTodoListsSetNormalMode()
49190
nunmap <buffer> o
@@ -114,12 +255,13 @@ endfunction
114255
function! VimTodoListsToggleItem()
115256
let l:line = getline('.')
116257

117-
if match(l:line, '^\s*\[ \].*') != -1
118-
call setline('.', substitute(l:line, '^\(\s*\)\[ \]', '\1[X]', ''))
119-
elseif match(l:line, '^\s*\[X\] .*') != -1
120-
call setline('.', substitute(l:line, '^\(\s*\)\[X\]', '\1[ ]', ''))
258+
if VimTodoListsItemIsNotDone(l:line) == 1
259+
call VimTodoListsForEachChild(line('.'), 'VimTodoListsSetItemDone')
260+
elseif VimTodoListsItemIsDone(l:line) == 1
261+
call VimTodoListsForEachChild(line('.'), 'VimTodoListsSetItemNotDone')
121262
endif
122263

264+
call VimTodoListsUpdateParent(line('.'))
123265
endfunction
124266

125267

0 commit comments

Comments
 (0)