@@ -44,6 +44,147 @@ function! VimTodoListsInit()
4444endfunction
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
48189function ! VimTodoListsSetNormalMode ()
49190 nunmap <buffer> o
@@ -114,12 +255,13 @@ endfunction
114255function ! 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 (' .' ))
123265endfunction
124266
125267
0 commit comments