💾 Archived View for republic.circumlunar.space › users › johngodlee › posts › 2019-05-25-vim-task.gm… captured on 2023-09-28 at 16:21:21. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-12-04)

-=-=-=-=-=-=-

Task management macros in Vim

DATE: 2019-05-25

AUTHOR: John L. Godlee

I'm slowly trying to emulate parts of the Emacs Org-mode syntax[1]. Particularly, when I write TODO lists, having [ ] or [*] at the beginning of a line to indicate whether that task is 'pending' or 'done', respectively. I'm not ready to dive straight into a Vim Org-mode plugin, but I have started to write little functions to make editing the files slightly more efficient. One such keybinding is simply to toggle whether a task is marked as 'done' or 'pending':

1: https://orgmode.org/guide/

" Toggle task as done
autocmd Filetype text,markdown nnoremap <Leader>D :call ToggleTask()<CR>

function! ToggleTask()
    if (getline('.') =~ '^\[\*\]')>0      " If you find [*] at line start
    	.s/^\[\*\]/[ ]/g
    elseif (getline('.') =~ '^\[\ \]')>0  " OR If you find [ ] at line start
    	.s/^\[\ \]/[*]/g
    else								  " OR if neither
    	echom 'Not a task line'
    endif
endfunction

The keybinding applies to text and markdown files and is called by <Leader>d. This calls a function named ToggleTask(). The function searches the current cursor line to see if it contains [*] and if it does, replaces it with [ ], then if [*] isn't found it does the opposite, searching for [ ] and changing it to [*], finally if neither of the abov regexes are matched, a message echom is displayed stating that the cursor line is not a task.

Similarly, I have the line below which makes a line a task line simply by prepending it with [ ]:

autocmd Filetype text,markdown nnoremap <Leader>T :s/^/[ ] /g <CR>

These aren't perfect by any stretch, it would be nicer to roll the whole lot into a more intelligent single function that can toggle between 'not a task', 'task to do', 'finished task', that would also take into account common line prefixes like enumerated lists.

Update - 2019_06_06

I did what I said I would do and rolled it all into one function:

" Create and toggle done status of task lines
autocmd Filetype text,markdown nnoremap <Leader>z :call ToggleTask()<CR>

function! ToggleTask()
    if (getline('.') =~ '^\[x\]')>0       " IF you find [x] at line start
    	.s/^\[x\]/[ ]/g
    elseif (getline('.') =~ '^\[\ \]')>0  " OR if you find [ ] at line start
    	.s/^\[\ \]/[x]/g
    elseif (getline('.') =~ '^\d\+\.\ \[\ \]')>0  " OR if the line begins with 1. [ ]
    	.s/\[\ \]/[x]/g
    elseif (getline('.') =~ '^\d\+\.\ \[x\]')>0  " OR if the line begins with 1. [x]
    	.s/\[x\]/[ ]/g
    elseif (getline('.') =~ '^\d\+\.')>0  " OR if the line begins with a 1.
    	.s/\d\+\./& [ ]/
    elseif (getline('.') =~ '^\*\|-')>0	  " OR if the line begins with a * or -
    	.s/^\*\|-/[ ]/
    else								  " OR if none
    	.s/^/[ ] /g
    endif
endfunction