├── LICENSE.txt ├── README.md ├── autoload ├── airline │ └── extensions │ │ └── taskwarrior.vim ├── taskinfo.vim ├── taskwarrior.vim ├── taskwarrior │ ├── action.vim │ ├── complete.vim │ ├── data.vim │ ├── log.vim │ └── sort.vim ├── unite │ ├── kinds │ │ └── task.vim │ └── sources │ │ └── task.vim └── webapi │ └── json.vim ├── doc └── vim-tw.txt ├── ftplugin └── taskreport.vim ├── plugin └── taskwarrior.vim ├── screenshot.png └── syntax ├── taskinfo.vim └── taskreport.vim /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ============================================== 2 | This is a copy of the MIT license. 3 | ============================================== 4 | Copyright (C) 2013 Zc He 5 | Copyright (C) 2013 David J Patrick 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 11 | of the Software, and to permit persons to whom the Software is furnished to do 12 | so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vim-taskwarrior 2 | =============== 3 | 4 | _a vim interface for [taskwarrior](https://taskwarrior.org)_ 5 | 6 | Taskwarrior is a command-line todo list manager. It helps you manage task lists 7 | with projects, tags, dates, dependencies, annotations, recurrences and apply 8 | complex (or simple) queries with attribute modifiers, boolean, regex filters 9 | and produce any number of reports, built-in or customizable reports, attributes 10 | and color themes. Task keeps data in JSON text files and it's always improving. 11 | Find out more at https://taskwarrior.org and read man task and man taskrc. 12 | 13 | vim-taskwarrior is a vim plugin that extends taskwarrior with an interactive 14 | interface. It features a rich set of mappings and commands, is easy to customize, 15 | and makes adding, modifying, sorting, reporting and marking done, fast, easy and fun! 16 | Homepage: https://github.com/farseer90718/vim-taskwarrior, patches welcome! 17 | 18 | ---- 19 | 20 | ### Prerequisites: 21 | 22 | This plugin requires Taskwarrior 2.2.0 or higher, although >2.3.x is required 23 | for taskd sync functions, and recommended in general, and well worth the price; 24 | free :) 25 | see: https://taskwarrior.org/download/ 26 | 27 | Vim version 7.x is required. 28 | 29 | Suggested plugins 30 | 31 | * [vim-airline](https://github.com/bling/vim-airline) for [better statusline information](https://github.com/farseer90718/vim-taskwarrior#screenshot). 32 | * [unite.vim](https://github.com/Shougo/unite.vim) for easier bookmark/history operations. 33 | 34 | If you experience line-wrapping issues, add the following line to your .vimrc 35 | 36 | ``` 37 | let g:task_rc_override = 'rc.defaultwidth=0' 38 | ``` 39 | 40 | If you experience task truncation (vim-taskwarrior not showing enough tasks), add: 41 | 42 | ``` 43 | let g:task_rc_override = 'rc.defaultheight=0' 44 | ``` 45 | 46 | 47 | ---- 48 | 49 | ### Screenshot: 50 | 51 | ![screenshot](https://raw.github.com/farseer90718/vim-taskwarrior/master/screenshot.png) 52 | ![vim-taskwarrior animated gif](http://taskextras.org/attachments/download/655/20131110_002753.gif) 53 | 54 | ### Installing: 55 | 56 | Either [download zip file](https://github.com/farseer90718/vim-taskwarrior/archive/master.zip) 57 | and extract in ~/.vim or use your favorite plugin manager. 58 | 59 | - [Pathogen](https://github.com/tpope/vim-pathogen) 60 | - `git clone https://github.com/farseer90718/vim-taskwarrior ~/.vim/bundle/vim-taskwarrior` 61 | - [Vundle](https://github.com/gmarik/vundle) 62 | 1. Add `Bundle 'farseer90718/vim-taskwarrior'` to .vimrc 63 | 2. Run `:BundleInstall` 64 | - [NeoBundle](https://github.com/Shougo/neobundle.vim) 65 | 1. Add `NeoBundle 'farseer90718/vim-taskwarrior'` to .vimrc 66 | 2. Run `:NeoBundleInstall` 67 | - [vim-plug](https://github.com/junegunn/vim-plug) 68 | 1. Add `Plug 'blindFS/vim-taskwarrior'` to .vimrc 69 | 2. Run `:PlugInstall` 70 | 71 | ---- 72 | 73 | ### Default map: 74 | 75 | ```vim 76 | nnoremap A ... " add annotation 77 | nnoremap x ... " delete annotation. 78 | nnoremap o ... " open the annotation as a file. 79 | nnoremap a ... " create new task. 80 | nnoremap d ... " set the task in current line done. 81 | nnoremap D ... " delete task 82 | nnoremap ... " delete field/annotation/task 83 | nnoremap ... " select/remove current task to selected list 84 | nnoremap m ... " modify current field. 85 | nnoremap M ... " modify current task. 86 | nnoremap f ... " change filter 87 | nnoremap r ... " change report type 88 | nnoremap c ... " execute a command for selected tasks/current task 89 | nnoremap R ... " refresh the report/clear selected list 90 | nnoremap q ... " quit buffer. 91 | nnoremap X ... " clear all completed task. 92 | nnoremap p ... " duplicate selected tasks 93 | nnoremap u ... " undo last change. 94 | nnoremap + ... " start task 95 | nnoremap - ... " stop task 96 | nnoremap S ... " sync with taskd server. 97 | nnoremap s ... " sort by this column primarily.(if already of the highest priority then switch the polarity) 98 | nnoremap < ... " sort by this column increasingly.(if already increasingly then increase its priority) 99 | nnoremap > ... " sort by this column decreasingly.(if already decreasingly then decrease its priority) 100 | nnoremap H ... " cycle column format left 101 | nnoremap L ... " cycle column format right 102 | nnoremap J ... " next historical entry 103 | nnoremap K ... " previous historical entry 104 | nnoremap B ... " create a bookmark for current combination 105 | nnoremap ... " view the documents 106 | nnoremap ... " show task info. 107 | nnoremap ... " jump to the next column 108 | nnoremap ... " jump to the previous column 109 | nnoremap ... " jump to the next non-empty column 110 | nnoremap ... " jump to the previous non-empty column 111 | vnoremap d ... " set done to all visual selected tasks 112 | vnoremap D ... " delete all visual selected tasks 113 | vnoremap ... " show information about visual selected tasks 114 | vnoremap ... " add visual selected tasks to selected list 115 | 116 | ``` 117 | ---- 118 | 119 | ### Commands: 120 | 121 | ```vim 122 | :TW [args] " task [filter report arguments] 123 | :TWUndo " undo the previous modification 124 | :TWEditTaskrc " edit ~/.taskrc 125 | :TWEditVitrc " edit ~/.vitrc 126 | :TWDeleteCompleted " clear all completed tasks 127 | :TWAdd " add new tasks interactively 128 | :TWAnnotate " add an annotation 129 | :TWComplete " mark task done 130 | :TWDelete " deleta a task 131 | :TWDeleteAnnotation " delete an annotation 132 | :TWModifyInteractive " make changes to a task interactively (use with caution!) 133 | :TWReportInfo " run the info report 134 | :TWReportSort [args] " overide the sort method, reset to default if no arguments passed 135 | :TWSync " synchronise with taskd server 136 | :TWToggleReadonly " toggle readonly option 137 | :TWToggleHLField " toggle highlight field option 138 | :TWHistory " list history records using unite.vim 139 | :TWHistoryClear " clear history 140 | :TWBookmark " list bookmarks using unite.vim 141 | :TWBookmarkClear " clear bookmarks 142 | 143 | ``` 144 | ---- 145 | 146 | ### Options: 147 | 148 | ```vim 149 | " default task report type 150 | let g:task_report_name = 'next' 151 | " custom reports have to be listed explicitly to make them available 152 | let g:task_report_command = [] 153 | " whether the field under the cursor is highlighted 154 | let g:task_highlight_field = 1 155 | " can not make change to task data when set to 1 156 | let g:task_readonly = 0 157 | " vim built-in term for task undo in gvim 158 | let g:task_gui_term = 1 159 | " allows user to override task configurations. Seperated by space. Defaults to '' 160 | let g:task_rc_override = 'rc.defaultwidth=999' 161 | " default fields to ask when adding a new task 162 | let g:task_default_prompt = ['due', 'description'] 163 | " whether the info window is splited vertically 164 | let g:task_info_vsplit = 0 165 | " info window size 166 | let g:task_info_size = 15 167 | " info window position 168 | let g:task_info_position = 'belowright' 169 | " directory to store log files defaults to taskwarrior data.location 170 | let g:task_log_directory = '~/.task' 171 | " max number of historical entries 172 | let g:task_log_max = '20' 173 | " forward arrow shown on statusline 174 | let g:task_left_arrow = ' <<' 175 | " backward arrow ... 176 | let g:task_left_arrow = '>> ' 177 | 178 | ``` 179 | ---- 180 | 181 | ### Syntax highlightling: 182 | 183 | Default scheme: 184 | 185 | ```vim 186 | highlight default link taskwarrior_tablehead Tabline 187 | highlight default link taskwarrior_field IncSearch 188 | highlight default link taskwarrior_selected Visual 189 | highlight default link taskwarrior_id VarId 190 | highlight default link taskwarrior_project String 191 | highlight default link taskwarrior_Status Include 192 | highlight default link taskwarrior_priority Class 193 | highlight default link taskwarrior_due Todo 194 | highlight default link taskwarrior_end Keyword 195 | highlight default link taskwarrior_description Normal 196 | highlight default link taskwarrior_entry Special 197 | highlight default link taskwarrior_depends Todo 198 | highlight default link taskwarrior_tags Keyword 199 | highlight default link taskwarrior_uuid VarId 200 | highlight default link taskwarrior_urgency Todo 201 | ``` 202 | 203 | Feel free to change any of above by something like: 204 | 205 | ```vim 206 | hi taskwarrior_xxx guibg = xxx guifg = xxx ctermbg = xxx ctermfg = xxx 207 | ``` 208 | 209 | in your vimrc. 210 | 211 | ### Acknowledgement: 212 | 213 | * [vim-airline](https://github.com/bling/vim-airline) by bling 214 | * [unite.vim](https://github.com/Shougo/unite.vim) by Shougo 215 | * [webapi-vim](https://github.com/mattn/webapi-vim) by mattn 216 | 217 | ### License: 218 | 219 | [MIT](https://raw.github.com/farseer90718/vim-taskwarrior/master/LICENSE.txt) 220 | 221 | 222 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/farseer90718/vim-taskwarrior/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 223 | 224 | -------------------------------------------------------------------------------- /autoload/airline/extensions/taskwarrior.vim: -------------------------------------------------------------------------------- 1 | function! airline#extensions#taskwarrior#apply(...) 2 | if &ft == 'taskreport' 3 | call a:1.add_section('airline_a', ' Taskwarrior ') 4 | call a:1.add_section('airline_b', ' %{b:command} %{&readonly ? g:airline_symbols.readonly : ""}') 5 | call a:1.add_section('airline_b', ' @%{b:context} ') 6 | call a:1.add_section('airline_b', g:task_left_arrow.' %{b:hist > 1 ? g:task_right_arrow : ""}') 7 | call a:1.add_section('airline_c', ' %{b:filter} ') 8 | call a:1.add_section('airline_c', ' %{b:sstring} ') 9 | call a:1.split() 10 | call a:1.add_section('airline_x', ' %{b:now} ') 11 | call a:1.add_section('airline_x', ' %{b:task_report_columns[taskwarrior#data#current_index()]} ') 12 | call a:1.add_section('airline_y', ' %{b:sort} ') 13 | if b:active != '0' 14 | call airline#parts#define_text('active', ' '.b:active.' ') 15 | call airline#parts#define_accent('active', 'orange') 16 | call a:1.add_section('airline_z', airline#section#create(['active'])) 17 | endif 18 | call a:1.add_section('airline_z', ' %{b:summary[0]} ') 19 | call airline#parts#define_text('completed', ' '.b:summary[1].' ') 20 | call airline#parts#define_accent('completed', 'green') 21 | call a:1.add_section('airline_z', airline#section#create(['completed'])) 22 | call a:1.add_section('airline_z', ' %{b:summary[2]} ') 23 | return 1 24 | elseif &ft == 'taskinfo' 25 | call a:1.add_section('airline_a', ' Taskinfo ') 26 | call a:1.add_section('airline_b', ' %{b:command." ".g:airline_symbols.readonly }') 27 | call a:1.add_section('airline_c', ' %{b:filter} ') 28 | call a:1.split() 29 | return 1 30 | endif 31 | endfunction 32 | 33 | function s:context() 34 | let con = split(system('task context show'), '\n') 35 | let con = con =~ 'No context' ? 'none' : con 36 | return con 37 | endfunction 38 | 39 | function! airline#extensions#taskwarrior#init(ext) 40 | call a:ext.add_statusline_func('airline#extensions#taskwarrior#apply') 41 | endfunction 42 | -------------------------------------------------------------------------------- /autoload/taskinfo.vim: -------------------------------------------------------------------------------- 1 | function! taskinfo#init(command, filter, info) 2 | if exists('g:task_info') 3 | call taskinfo#quit() 4 | endif 5 | 6 | if a:command != 'info' 7 | \ && exists('g:task_info_arg') 8 | \ && g:task_info_arg == [a:command, a:filter] 9 | unlet g:task_info_arg 10 | return 11 | endif 12 | 13 | execute g:task_info_position.' '.g:task_info_size. 14 | \ (g:task_info_vsplit ? 'v' : '').'split' 15 | edit taskinfo 16 | let g:task_info = bufnr('%') 17 | let g:task_info_arg = [a:command, a:filter] 18 | setlocal noswapfile 19 | setlocal modifiable 20 | call append(0, a:info) 21 | silent global/^[\t ]*$/delete 22 | silent global/^[ -]\+$/delete 23 | setlocal readonly 24 | setlocal nomodifiable 25 | setlocal buftype=nofile 26 | setlocal nowrap 27 | setlocal filetype=taskinfo 28 | 1 29 | 30 | let b:command = a:command 31 | let b:filter = a:filter 32 | 33 | nnoremap q :call taskinfo#quit() 34 | nnoremap :call taskinfo#quit() 35 | 36 | if a:command != 'info' 37 | wincmd W 38 | endif 39 | endfunction 40 | 41 | function! taskinfo#quit() 42 | silent! execute g:task_info.'bd!' 43 | unlet g:task_info 44 | endfunction 45 | -------------------------------------------------------------------------------- /autoload/taskwarrior.vim: -------------------------------------------------------------------------------- 1 | function! taskwarrior#list(...) abort 2 | setlocal noreadonly 3 | setlocal modifiable 4 | let pos = getpos('.') 5 | %delete 6 | call taskwarrior#buffer_var_init() 7 | let b:command = get(a:, 1, b:command) 8 | let b:filter = get(a:, 2, b:filter) 9 | let b:type = get(a:, 3, b:type) 10 | let b:rc = get(a:, 4, b:rc). ' rc.defaultheight=0' 11 | 12 | let b:rc .= ' '.join(filter(split(b:filter, ' '), "v:val =~ '^rc\..*'")) 13 | let b:filter = join(filter(split(b:filter, ' '), "v:val !~ '^rc\..*'")) 14 | let rcs = split(b:rc, ' ') 15 | let b:rc = join(filter(copy(rcs), "match(rcs, matchstr(v:val, '^[^=:]*'), v:key+1) == -1"), ' ') 16 | 17 | if b:type == 'special' 18 | setlocal buftype=nofile 19 | call append(0, split(system('task '.b:rc.' '.b:filter.' '.b:command), '\n')) 20 | silent global/^[\t ]*$/delete 21 | execute 'setlocal filetype=task_'.b:command 22 | nnoremap q :call taskwarrior#Bclose(bufnr('%')) 23 | call setpos('.', pos) 24 | return 25 | endif 26 | 27 | let b:hist = get(b:, 'hist', 1) 28 | call taskwarrior#log#history('write') 29 | 30 | let rcc = matchstr(b:rc, 'rc\.report\.'.b:command.'\.columns.\zs\S*') 31 | let rcl = matchstr(b:rc, 'rc\.report\.'.b:command.'\.labels.\zs\S*') 32 | " let b:task_report_columns = rcc == '' ? split(system("task _get -- rc.report.".b:command.".columns")[0:-2], ',') : split(rcc, ',') 33 | " let b:task_report_labels = rcl == '' ? split(system("task _get -- rc.report.".b:command.".labels")[0:-2], ',') : split(rcl, ',') 34 | let b:task_report_columns = rcc == '' ? split(matchstr(system("task show |grep report.".b:command.".columns")[0:-2], '\S*$'), ',') : split(rcc, ',') 35 | let b:task_report_labels = rcl == '' ? split(matchstr(system("task show |grep report.".b:command.".labels")[0:-2], '\S*$'), ',') : split(rcl, ',') 36 | let line1 = join(b:task_report_labels, ' ') 37 | 38 | let context = split(substitute( 39 | \ system('task '.b:rc.' '.b:filter.' '.b:command), 40 | \ '\[[0-9;]\+m', 41 | \ '', 'g'), 42 | \ '\n') 43 | let split_lineno = match(context, '^[ -]\+$') 44 | if split_lineno == -1 45 | call append(0, line1) 46 | else 47 | let end = len(context)-match(reverse(copy(context)), '^$') 48 | call append(0, context[split_lineno-1:end-1]) 49 | silent global/^[\t ]*$/delete 50 | silent global/^[ -]\+$/delete 51 | endif 52 | 53 | call filter(b:task_report_columns, "index(split(getline(1), ' '), b:task_report_labels[v:key]) != -1") 54 | call filter(b:task_report_labels, "index(split(getline(1), ' '), v:val) != -1") 55 | 56 | let b:task_columns = [] 57 | let ci = 0 58 | 1 59 | while ci != -1 60 | let b:task_columns += [ci] 61 | let ci = search('\s\S', 'W', 1) 62 | let ci = ci > 0 ? virtcol('.') : -1 63 | endwhile 64 | 65 | let b:task_columns += [999] 66 | let b:summary = taskwarrior#data#global_stats() 67 | let b:sort = taskwarrior#sort#order_list()[0] 68 | let a_tasks = split(system('task active limit:1 rc.verbose:nothing 69 | \ rc.report.active.sort=start- 70 | \ rc.report.active.columns=start.active,start.age,id,description.desc 71 | \ rc.report.active.labels=A,Age,ID,Description'), '\n') 72 | let b:now = len(a_tasks) > 0 ? a_tasks[-1] : '' 73 | let b:active = split(system('task start.any: count'), '\n')[0] 74 | let b:selected = [] 75 | let b:sline = [] 76 | let b:sstring = '' 77 | let con = split(system('task context show'), '\n')[0] 78 | let b:context = con =~ 'No context' ? 'none' : 79 | \ matchstr(con, 'Context .\zs\S*\ze. ') 80 | 81 | setlocal filetype=taskreport 82 | if exists('b:ct') 83 | for l in range(line('$')) 84 | if taskwarrior#data#get_uuid(l) == b:ct 85 | let pos[1] = l 86 | break 87 | endif 88 | endfor 89 | endif 90 | call setpos('.', pos) 91 | endfunction 92 | 93 | function! taskwarrior#buffer_var_init() 94 | let b:command = get(b:, 'command', g:task_report_name) 95 | let b:filter = get(b:, 'filter', '') 96 | let b:type = get(b:, 'type', 'report') 97 | let b:rc = get(b:, 'rc', g:task_rc_override) 98 | endfunction 99 | 100 | function! taskwarrior#init(...) 101 | if exists(':TagbarClose') 102 | TagbarClose 103 | endif 104 | let argstring = join(a:000, ' ') 105 | let [command, filter, type] = taskwarrior#command_type(argstring) 106 | let rc = g:task_rc_override 107 | 108 | if type == 'interactive' 109 | if !g:task_readonly 110 | execute '!task '.argstring 111 | call taskwarrior#refresh() 112 | endif 113 | return 114 | endif 115 | 116 | execute 'edit task\ '.command.'\ '.type 117 | 118 | if exists('g:task_view') 119 | let g:task_view += [bufnr('%')] 120 | else 121 | let g:task_view = [bufnr('%')] 122 | endif 123 | 124 | setlocal noswapfile 125 | call taskwarrior#list(command, filter, type, rc) 126 | 127 | endfunction 128 | 129 | function! taskwarrior#refresh() 130 | if exists('g:task_view') 131 | for bufn in g:task_view 132 | execute bufn.'buffer' 133 | call taskwarrior#list() 134 | endfor 135 | else 136 | call taskwarrior#init() 137 | endif 138 | endfunction 139 | 140 | function! taskwarrior#Bclose(buffer) 141 | if a:buffer =~ '^\d\+$' 142 | let btarget = bufnr(str2nr(a:buffer)) 143 | else 144 | let btarget = bufnr(a:buffer) 145 | endif 146 | if bufname(btarget) == '' 147 | bdelete 148 | return 149 | endif 150 | " Numbers of windows that view target buffer which we will delete. 151 | let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) == btarget') 152 | let wcurrent = winnr() 153 | for w in wnums 154 | execute w.'wincmd w' 155 | let prevbuf = bufnr('#') 156 | if prevbuf > 0 && buflisted(prevbuf) && prevbuf != w 157 | buffer # 158 | else 159 | bprevious 160 | endif 161 | if btarget == bufnr('%') 162 | " Numbers of listed buffers which are not the target to be deleted. 163 | let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget') 164 | " Listed, not target, and not displayed. 165 | let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0') 166 | " Take the first buffer, if any (could be more intelligent). 167 | let bjump = (bhidden + blisted + [-1])[0] 168 | if bjump > 0 169 | execute 'buffer '.bjump 170 | else 171 | enew 172 | endif 173 | endif 174 | endfor 175 | execute 'silent! bdelete '.btarget 176 | execute wcurrent.'wincmd w' 177 | endfunction 178 | 179 | 180 | function! taskwarrior#hi_field() 181 | silent! syntax clear taskwarrior_field 182 | let index = taskwarrior#data#current_index() 183 | execute 'syntax match taskwarrior_field /\%>1l\%'.line('.').'l\%'.(b:task_columns[index]+1).'v.*\%<'.(b:task_columns[index+1]+1).'v/' 184 | endfunction 185 | 186 | function! taskwarrior#quit() 187 | call taskwarrior#Bclose(bufnr('%')) 188 | call remove(g:task_view, index(g:task_view, bufnr('%'))) 189 | endfunction 190 | 191 | function! taskwarrior#quit_all() 192 | for bufn in g:task_view 193 | call taskwarrior#Bclose(bufn) 194 | endfor 195 | let g:task_view = [] 196 | endfunction 197 | 198 | function! taskwarrior#system_call(filter, command, args, mode) 199 | if a:mode == 'silent' 200 | call system('task '.a:filter.' '.a:command.' '.a:args) 201 | elseif a:mode == 'echo' 202 | echo "\n----------------\n" 203 | echo system('task '.a:filter.' '.a:command.' '.a:args) 204 | else 205 | execute '!task '.a:filter.' '.a:command.' '.a:args 206 | endif 207 | call taskwarrior#refresh() 208 | endfunction 209 | 210 | function! taskwarrior#command_type(string) 211 | for sub in split(a:string, ' ') 212 | if index(g:task_report_command, sub) != -1 213 | return [ sub, substitute(' '.a:string, ' '.sub, '', ''), 'report' ] 214 | elseif index(g:task_interactive_command, sub) != -1 215 | return [ sub, substitute(' '.a:string, ' '.sub, '', ''), 'interactive' ] 216 | elseif index(g:task_all_commands, sub) != -1 217 | return [ sub, substitute(' '.a:string, ' '.sub, '', ''), 'special' ] 218 | endif 219 | endfor 220 | return [ g:task_report_name, a:string, 'report' ] 221 | endfunction 222 | -------------------------------------------------------------------------------- /autoload/taskwarrior/action.vim: -------------------------------------------------------------------------------- 1 | function! taskwarrior#action#new() 2 | call taskwarrior#system_call('', 'add', taskwarrior#data#get_args('add'), 'echo') 3 | endfunction 4 | 5 | function! taskwarrior#action#set_done() 6 | call taskwarrior#system_call(taskwarrior#data#get_uuid(), ' done', '', 'silent') 7 | endfunction 8 | 9 | function! taskwarrior#action#urgency() abort 10 | let cc = taskwarrior#data#current_column() 11 | let udas = split(system('task _udas'), '\n') 12 | let cmap = { 'start' : 'active', 13 | \ 'entry' : 'age', 14 | \ 'depends' : 'blocked', 15 | \ 'parent' : 'blocking', 16 | \ 'wait' : 'waiting', 17 | \ 'description' : 'annotations' 18 | \ } 19 | let isuda = 0 20 | if has_key(cmap, cc) 21 | let cc = cmap[cc] 22 | elseif index(['due', 'priority', 'project', 'tags', 'scheduled'] 23 | \ , cc) == -1 24 | if index(udas, cc) == -1 25 | call taskwarrior#sort#by_arg('urgency-') 26 | return 27 | else 28 | let isuda = 1 29 | endif 30 | endif 31 | let rcfile = $HOME.'/.taskrc' 32 | if filereadable(rcfile) 33 | let cv = taskwarrior#data#get_value_by_column(line('.'), cc) 34 | let option = isuda ? 'urgency.uda.'.cc.'.coefficient' : 35 | \ 'urgency.'.cc.'.coefficient' 36 | if len(cv) 37 | let ctag = expand('') 38 | if cc == 'tags' && index(split(cv), ctag) != -1 39 | let option = 'urgency.user.tag.'.ctag.'.coefficient' 40 | elseif cc == 'project' && cv =~ '^[^ \t%\\*]\+$' 41 | let pl = split(cv, '\.') 42 | let idx = index(pl, expand('')) 43 | let option = 'urgency.user.project.'. 44 | \ join(pl[0:idx], '.').'.coefficient' 45 | elseif isuda && cv =~ '^\w\+$' 46 | let option = 'urgency.uda.'.cc.'.'.cv.'.coefficient' 47 | endif 48 | endif 49 | let default_raw = split(system('task _get rc.'.option), '\n') 50 | let default = len(default_raw) ? default_raw[0] : '0' 51 | let new = input(option.' : ', default) 52 | let lines = readfile(rcfile) 53 | let index = match(lines, option) 54 | if str2float(new) == str2float(default) 55 | elseif str2float(new) == 0 56 | call filter(lines, 'v:val !~ option') 57 | elseif index == -1 58 | call add(lines, option.'='.new) 59 | else 60 | let lines[index] = option.'='.new 61 | endif 62 | call writefile(lines, rcfile) 63 | endif 64 | call taskwarrior#sort#by_arg('urgency-') 65 | execute 'normal! :\' 66 | endfunction 67 | 68 | function! taskwarrior#action#modify(mode) 69 | let uuid = taskwarrior#data#get_uuid() 70 | if uuid == '' 71 | return 72 | endif 73 | if a:mode == 'current' 74 | let field = taskwarrior#data#current_column() 75 | if index(['id', 'uuid', 'status', 'urgency'], field) != -1 76 | return 77 | elseif field == 'description' 78 | call taskwarrior#system_call(uuid, 'modify', taskwarrior#data#get_args('modify', [field]), 'external') 79 | else 80 | call taskwarrior#system_call(uuid, 'modify', taskwarrior#data#get_args('modify', [field]), 'silent') 81 | endif 82 | else 83 | call taskwarrior#system_call(uuid, 'modify', taskwarrior#data#get_args('modify'), 'external') 84 | endif 85 | endfunction 86 | 87 | function! taskwarrior#action#delete() 88 | let uuid = taskwarrior#data#get_uuid() 89 | if uuid == '' 90 | call taskwarrior#action#annotate('del') 91 | else 92 | let ccol = taskwarrior#data#current_column() 93 | if index(['project', 'tags', 'due', 'priority', 'start', 'depends'], ccol) != -1 94 | call taskwarrior#system_call(uuid, 'modify', ccol.':', 'silent') 95 | else 96 | execute '!task '.uuid.' delete' 97 | endif 98 | endif 99 | call taskwarrior#refresh() 100 | endfunction 101 | 102 | function! taskwarrior#action#remove() 103 | execute '!task '.taskwarrior#data#get_uuid().' delete' 104 | call taskwarrior#list() 105 | endfunction 106 | 107 | function! taskwarrior#action#annotate(op) 108 | let ln = line('.') 109 | let offset = -1 110 | while ln > 1 && taskwarrior#data#get_uuid(ln) == '' 111 | let ln -= 1 112 | let offset += 1 113 | endwhile 114 | let uuid = taskwarrior#data#get_uuid(ln) 115 | if uuid == '' 116 | return 117 | endif 118 | if a:op == 'add' 119 | let annotation = input('new annotation:', '', 'file') 120 | call taskwarrior#system_call(uuid, ' annotate ', annotation, 'silent') 121 | elseif a:op == 'del' 122 | let annotation = input('annotation pattern to delete:') 123 | call taskwarrior#system_call(uuid, ' denotate ', annotation, 'silent') 124 | elseif offset >= 0 125 | let taskobj = taskwarrior#data#get_query(uuid) 126 | if exists('taskobj.annotations[offset].description') 127 | let file = substitute(taskobj.annotations[offset].description, '\s*\/\s*', '/', 'g') 128 | let file = escape(file, ' ') 129 | let ft = 'text' 130 | if executable('file') 131 | let ft = system('file '.file)[:-2] 132 | endif 133 | if ft =~ 'text$' 134 | execute 'e '.file 135 | elseif ft !~ '(No such file or directory)' || file =~ '[a-z]*:\/\/[^ >,;]*' 136 | if executable('xdg-open') 137 | call system('xdg-open '.file.'&') 138 | elseif executable('open') 139 | call system('open '.file.'&') 140 | endif 141 | endif 142 | endif 143 | endif 144 | endfunction 145 | 146 | function! taskwarrior#action#filter() 147 | let column = taskwarrior#data#current_column() 148 | if index(['project', 'tags', 'status', 'priority'], column) != -1 && line('.') > 1 149 | let filter = substitute(substitute(taskwarrior#data#get_args('modify', [column]), 'tags:', '+', ''), '\v^\s*\+(\s|$)', '', '') 150 | elseif column =~ '\v^(entry|end|due)$' 151 | let filter = column.'.before:'.input(column.'.before:', taskwarrior#data#get_value_by_column('.', column)) 152 | elseif column == 'description' 153 | let filter = 'description:'.input('description:', taskwarrior#data#get_value_by_column('.', column) ) 154 | else 155 | let filter = input('new filter:', b:filter, 'customlist,taskwarrior#complete#filter') 156 | endif 157 | let filter = substitute(filter, 'status:\(\s\|$\)', 'status.any: ', 'g') 158 | if filter != b:filter 159 | let b:filter = filter 160 | let b:hist = 1 161 | call taskwarrior#list() 162 | endif 163 | endfunction 164 | 165 | function! taskwarrior#action#command() 166 | if len(b:selected) == 0 167 | let filter = taskwarrior#data#get_uuid() 168 | else 169 | let filter = join(b:selected, ',') 170 | endif 171 | let command = input('task '.filter.':', '', 'customlist,taskwarrior#complete#command') 172 | if index(g:task_all_commands, b:command) == -1 173 | return 174 | endif 175 | call taskwarrior#system_call(filter, command, '', 'interactive') 176 | endfunction 177 | 178 | function! taskwarrior#action#report() 179 | let command = input('new report:', g:task_report_name, 'customlist,taskwarrior#complete#report') 180 | if index(g:task_report_command, command) != -1 && command != b:command 181 | let b:command = command 182 | let b:hist = 1 183 | call taskwarrior#list() 184 | endif 185 | endfunction 186 | 187 | function! taskwarrior#action#paste() 188 | if len(b:selected) == 0 189 | return 190 | elseif len(b:selected) < 3 191 | call taskwarrior#system_call(join(b:selected, ','), 'duplicate', '', 'echo') 192 | else 193 | call taskwarrior#system_call(join(b:selected, ','), 'duplicate', '', 'interactive') 194 | endif 195 | endfunction 196 | 197 | function! taskwarrior#action#columns_format_change(direction) 198 | let ccol = taskwarrior#data#current_column() 199 | if !exists('g:task_columns_format[ccol]') 200 | return 201 | endif 202 | let clist = g:task_columns_format[ccol] 203 | if len(clist) == 1 204 | return 205 | endif 206 | let ccol_ful = b:task_report_columns[taskwarrior#data#current_index()] 207 | let ccol_sub = matchstr(ccol_ful, '\.\zs.*') 208 | let rcl = matchstr(b:rc, 'rc\.report\.'.b:command.'\.columns.\zs\S*') 209 | " let dfl = system('task _get -- rc.report.'.b:command.'.columns')[0:-2] 210 | let dfl = matchstr(system('task show | grep report.'.b:command.'.columns')[0:-2], '\S*$') 211 | let index = index(clist, ccol_sub) 212 | let index = index == -1 ? 0 : index 213 | if a:direction == 'left' 214 | let index -= 1 215 | else 216 | let index += 1 217 | if index == len(clist) 218 | let index = 0 219 | endif 220 | endif 221 | let newsub = index == 0 ? '' : '.'.clist[index] 222 | let b:rc .= ' rc.report.'.b:command.'.columns:'. 223 | \ substitute( 224 | \ rcl == '' ? dfl : rcl, 225 | \ '[=:,]\zs'.ccol_ful.'\ze\(,\|$\)', 226 | \ ccol.newsub, '' 227 | \ ) 228 | let b:hist = 1 229 | call taskwarrior#list() 230 | endfunction 231 | 232 | function! taskwarrior#action#date(count) 233 | let ccol = taskwarrior#data#current_column() 234 | if index(['due', 'end', 'entry'], ccol) == -1 235 | return 236 | endif 237 | setlocal modifiable 238 | if exists('g:loaded_speeddating') 239 | call speeddating#increment(a:count) 240 | elseif a:count > 0 241 | execute 'normal! '.a:count.'' 242 | else 243 | execute 'normal! '.-a:count.'' 244 | endif 245 | let b:ct = taskwarrior#data#get_uuid() 246 | call taskwarrior#system_call(b:ct, 'modify', ccol.':'.taskwarrior#data#get_value_by_column('.', ccol, 'temp'), 'silent') 247 | endfunction 248 | 249 | function! taskwarrior#action#visual(action) range 250 | let line1 = getpos("'<")[1] 251 | let line2 = getpos("'>")[1] 252 | let fil = [] 253 | let lin = [] 254 | for l in range(line1, line2) 255 | let uuid = taskwarrior#data#get_uuid(l) 256 | if uuid !~ '^\s*$' 257 | let fil += [uuid] 258 | let lin += [l] 259 | endif 260 | endfor 261 | let filter = join(fil, ',') 262 | if a:action == 'done' 263 | call taskwarrior#system_call(filter, 'done', '', 'interactive') 264 | elseif a:action == 'delete' 265 | call taskwarrior#system_call(filter, 'delete', '', 'interactive') 266 | elseif a:action == 'info' 267 | call taskinfo#init('information', filter, split(system('task rc.color=no information '.filter), '\n')) 268 | elseif a:action == 'select' 269 | for var in fil 270 | let index = index(b:selected, var) 271 | if index == -1 272 | let b:selected += [var] 273 | let b:sline += [lin[index(fil, var)]] 274 | else 275 | call remove(b:selected, index) 276 | call remove(b:sline, index) 277 | endif 278 | endfor 279 | let b:sstring = join(b:selected, ' ') 280 | setlocal syntax=taskreport 281 | endif 282 | endfunction 283 | 284 | function! taskwarrior#action#move_cursor(direction, mode) 285 | let ci = taskwarrior#data#current_index() 286 | if ci == -1 || (ci == 0 && a:direction == 'left') || (ci == len(b:task_columns)-1 && a:direction == 'right') 287 | return 288 | endif 289 | if a:direction == 'left' 290 | call search('\%'.(b:task_columns[ci-1]+1).'v', 'be') 291 | else 292 | call search('\%'.(b:task_columns[ci+1]+1).'v', 'e') 293 | endif 294 | if a:mode == 'skip' && taskwarrior#data#get_value_by_index('.', taskwarrior#data#current_index()) =~ '^\s*$' 295 | call taskwarrior#action#move_cursor(a:direction, 'skip') 296 | endif 297 | endfunction 298 | 299 | function! taskwarrior#action#undo() 300 | if has("gui_running") 301 | if exists('g:task_gui_term') && g:task_gui_term == 1 302 | !task rc.color=off undo 303 | elseif executable('xterm') 304 | silent !xterm -e 'task undo' 305 | elseif executable('urxvt') 306 | silent !urxvt -e task undo 307 | elseif executable('gnome-terminal') 308 | silent !gnome-terminal -e 'task undo' 309 | endif 310 | else 311 | sil !clear 312 | !task undo 313 | endif 314 | call taskwarrior#refresh() 315 | endfunction 316 | 317 | function! taskwarrior#action#clear_completed() 318 | !task status:completed delete 319 | call taskwarrior#refresh() 320 | endfunction 321 | 322 | function! taskwarrior#action#sync(action) 323 | execute '!task '.a:action.' ' 324 | call taskwarrior#refresh() 325 | endfunction 326 | 327 | function! taskwarrior#action#select() 328 | let uuid = taskwarrior#data#get_uuid() 329 | if uuid == '' 330 | return 331 | endif 332 | let index = index(b:selected, uuid) 333 | if index == -1 334 | let b:selected += [uuid] 335 | let b:sline += [line('.')] 336 | else 337 | call remove(b:selected, index) 338 | call remove(b:sline, index) 339 | endif 340 | let b:sstring = join(b:selected, ' ') 341 | setlocal syntax=taskreport 342 | endfunction 343 | 344 | function! taskwarrior#action#show_info(...) 345 | if a:0 > 0 346 | let command = 'info' 347 | let filter = a:1 348 | else 349 | let ccol = taskwarrior#data#current_column() 350 | let dict = { 'project': 'projects', 351 | \ 'tags': 'tags', 352 | \ 'id': 'stats', 353 | \ 'depends': 'blocking', 354 | \ 'recur': 'recurring', 355 | \ 'due': 'overdue', 356 | \ 'wait': 'waiting', 357 | \ 'urgency': 'ready', 358 | \ 'entry': 'history.monthly', 359 | \ 'end': 'history.monthly'} 360 | let command = get(dict, ccol, 'summary') 361 | let uuid = taskwarrior#data#get_uuid() 362 | if uuid !~ '^\s*$' 363 | let command = substitute(command, '\v(summary|stats)', 'information', '') 364 | let filter = taskwarrior#data#get_uuid() 365 | else 366 | let filter = b:filter 367 | endif 368 | endif 369 | call taskinfo#init(command, filter, split(system('task rc.color=no '.command.' '.filter), '\n')) 370 | endfunction 371 | -------------------------------------------------------------------------------- /autoload/taskwarrior/complete.vim: -------------------------------------------------------------------------------- 1 | function! taskwarrior#complete#TW(A, L, P) 2 | let command = copy(g:task_all_commands) 3 | let filter = copy(g:task_filter) 4 | let config = copy(g:task_all_configurations) 5 | let contexts = split(system('task _context'), '\n') 6 | let context_cmd = ['define', 'show', 'list', 'delete'] 7 | let words = split(a:L, ' ') 8 | if len(words) > 1 && words[1] == 'context' 9 | if len(words) == 2 || index(context_cmd, words[2]) == -1 10 | return filter(context_cmd + contexts + ['none'], 11 | \ 'match(v:val, a:A) != -1') 12 | elseif words[2] == 'delete' 13 | return filter(contexts, 'match(v:val, a:A) != -1') 14 | else 15 | return [] 16 | endif 17 | endif 18 | for ph in words 19 | if ph == 'config' || ph == 'show' 20 | return filter(config, 'match(v:val, a:A) != -1') 21 | elseif ph =~ '^rc\..*' 22 | return map(filter(config, 'match(v:val, a:A[3:]) != -1'), 23 | \ "'rc.'.v:val") 24 | elseif index(command, ph) != -1 25 | return filter(filter, 'match(v:val, a:A) != -1') 26 | endif 27 | endfor 28 | return filter(command+filter, 'match(v:val, a:A) != -1') 29 | endfunction 30 | 31 | function! taskwarrior#complete#sort(A, L, P) 32 | let cols = map(split(system('task _columns'), '\n'), 33 | \ 'matchstr(v:val, "^\\w*")') 34 | return filter(cols, 'match(v:val, a:A) != -1') 35 | endfunction 36 | 37 | function! taskwarrior#complete#filter(A, L, P) 38 | let lead = matchstr(a:A, '\S*$') 39 | let lead = lead == '' ? '.*' : lead 40 | let dict = copy(g:task_filter) 41 | for ph in split(a:L, ' ') 42 | call remove(dict, index(dict, matchstr(ph, '.*:\ze'))) 43 | endfor 44 | return map(filter(dict, 'match(v:val, lead) != -1'), 45 | \ "matchstr(a:L, '.*\\ze\\s\\+\\S*').' '.v:val") 46 | endfunction 47 | 48 | function! taskwarrior#complete#command(A, L, P) 49 | return filter(copy(g:task_all_commands), 'match(v:val, a:A) != -1') 50 | endfunction 51 | 52 | function! taskwarrior#complete#report(A, L, P) 53 | return filter(copy(g:task_report_command), 'match(v:val, a:A) != -1') 54 | endfunction 55 | -------------------------------------------------------------------------------- /autoload/taskwarrior/data.vim: -------------------------------------------------------------------------------- 1 | function! taskwarrior#data#get_uuid(...) 2 | let line = a:0 == 0 ? '.' : a:1 3 | let vol = taskwarrior#data#get_value_by_column(line, 'uuid') 4 | let vol = vol =~ '[0-9a-f]\{8}\(-[0-9a-f]\{4}\)\{3}-[0-9a-f]\{12}' ? 5 | \ vol : taskwarrior#data#get_value_by_column(line, 'id') 6 | return vol =~ '^\s*-*\s*$' ? '' : vol 7 | endfunction 8 | 9 | function! taskwarrior#data#get_args(...) 10 | if a:0 == 0 11 | return 12 | elseif a:0 == 1 13 | return taskwarrior#data#get_args(a:1, g:task_default_prompt) 14 | endif 15 | let arg = ' ' 16 | for key in a:2 17 | let default = a:1 == 'modify' ? 18 | \ taskwarrior#data#get_value_by_column('.', key) 19 | \ : '' 20 | let temp = shellescape(input(key.":", default), 1) 21 | if key == 'description' 22 | let arg .= ' '.temp 23 | elseif temp !~ '^[ \t]*$' || a:1 == 'modify' 24 | let arg .= ' '.key.':'.temp 25 | endif 26 | endfor 27 | echom arg 28 | return arg 29 | endfunction 30 | 31 | function! taskwarrior#data#get_value_by_column(line, column, ...) 32 | if a:line == 1 || (a:line == '.' && line('.') == 1) 33 | return '' 34 | endif 35 | if a:column == 'id' || a:column == 'uuid' || exists('a:1') 36 | let index = match(b:task_report_columns, '^'.a:column.'.*') 37 | return taskwarrior#data#get_value_by_index(a:line, index(b:task_report_columns, a:column)) 38 | else 39 | let dict = taskwarrior#data#get_query() 40 | let val = get(dict, a:column, '') 41 | if type(val) == type('') 42 | return val 43 | elseif type(val) == type([]) 44 | return join(val, ' ') 45 | else 46 | return string(val) 47 | endif 48 | endif 49 | endfunction 50 | 51 | function! taskwarrior#data#get_value_by_index(line, index) 52 | if exists('b:task_columns[a:index]') 53 | return substitute(getline(a:line)[b:task_columns[a:index]:b:task_columns[a:index+1]-1], '\(\s*$\|^\s*\)', '', 'g') 54 | endif 55 | return '' 56 | endfunction 57 | 58 | function! taskwarrior#data#current_index() 59 | let i = 0 60 | while i < len(b:task_columns) && virtcol('.') >= b:task_columns[i] 61 | let i += 1 62 | endwhile 63 | return i-1 64 | endfunction 65 | 66 | function! taskwarrior#data#current_column() 67 | return matchstr(b:task_report_columns[taskwarrior#data#current_index()], '^\w\+') 68 | endfunction 69 | 70 | function! taskwarrior#data#get_stats(method) 71 | let dict = {} 72 | if a:method != 'current' 73 | let stat = split(system('task '.a:method.' stats'), '\n') 74 | else 75 | let uuid = taskwarrior#data#get_uuid() 76 | let stat = split(system('task '.taskwarrior#data#get_uuid().' stats'), '\n') 77 | if uuid == '' || len(stat) < 5 78 | return {} 79 | endif 80 | endif 81 | for line in stat[2:-1] 82 | if line !~ '^\W*$' 83 | let dict[split(line, '\s\s')[0]] = substitute(split(line, '\s\s')[-1], '^\s*', '', '') 84 | endif 85 | endfor 86 | return dict 87 | endfunction 88 | 89 | function! taskwarrior#data#get_query(...) 90 | let uuid = get(a:, 1, taskwarrior#data#get_uuid()) 91 | if uuid == '' 92 | return {} 93 | endif 94 | let obj = webapi#json#decode(substitute(system( 95 | \ 'task rc.verbose=off '.uuid.' export'), 96 | \ '\nConfiguration.*', '', '')) 97 | return type(obj) == 3 ? obj[0] : obj 98 | endfunction 99 | 100 | function! taskwarrior#data#global_stats() 101 | let dict = taskwarrior#data#get_stats(b:filter) 102 | return [ 103 | \ get(dict, 'Pending', 0), 104 | \ get(dict, 'Completed', 0), 105 | \ get(taskwarrior#data#get_stats(''), 'Pending', 0) 106 | \ ] 107 | endfunction 108 | 109 | function! taskwarrior#data#category() 110 | let dict = {} 111 | let dict.Pending = [] 112 | let dict.Waiting = [] 113 | let dict.Recurring = [] 114 | let dict.Completed = [] 115 | for i in range(2, line('$')) 116 | let uuid = taskwarrior#data#get_uuid(i) 117 | if uuid == '' 118 | continue 119 | endif 120 | let subdict = taskwarrior#data#get_stats(uuid) 121 | if subdict.Pending == '1' 122 | let dict.Pending += [i] 123 | elseif subdict.Waiting == '1' 124 | let dict.Waiting += [i] 125 | elseif subdict.Recurring == '1' 126 | let dict.Recurring += [i] 127 | elseif subdict.Completed == '1' 128 | let dict.Completed += [i] 129 | endif 130 | endfor 131 | return dict 132 | endfunction 133 | -------------------------------------------------------------------------------- /autoload/taskwarrior/log.vim: -------------------------------------------------------------------------------- 1 | if !isdirectory(expand(g:task_log_directory)) 2 | call mkdir(expand(g:task_log_directory), 'p') 3 | endif 4 | let s:history_file = expand(g:task_log_directory.'/.vim_tw.history') 5 | let s:bookmark_file = expand(g:task_log_directory.'/.vim_tw.bookmark') 6 | 7 | function! taskwarrior#log#history(action) 8 | if findfile(s:history_file) == '' 9 | call writefile([], s:history_file) 10 | endif 11 | if a:action == 'write' && filewritable(s:history_file) && b:hist == 1 12 | let fl = readfile(s:history_file) 13 | let numb = len(fl) 14 | let last = numb ? substitute(fl[-1], '\v($|\n|\t|\s)', '', 'g') : '' 15 | let current = join([b:command, b:filter, b:rc], ' ') 16 | if last == substitute(current, '[\t ]', '', 'g') 17 | return 18 | endif 19 | call add(fl, current) 20 | if numb >= g:task_log_max 21 | call remove(fl, 0) 22 | endif 23 | call writefile(fl, s:history_file) 24 | elseif a:action == 'read' && filereadable(s:history_file) 25 | call taskwarrior#init(join(split(readfile(s:history_file)[-1], ' '), ' ')) 26 | elseif a:action == 'clear' 27 | call writefile([], s:history_file) 28 | elseif a:action != 'write' 29 | let hists = readfile(s:history_file) 30 | if a:action == 'previous' 31 | if b:hist >= len(hists) 32 | return 33 | endif 34 | let b:hist += 1 35 | elseif a:action == 'next' 36 | if b:hist == 1 37 | return 38 | endif 39 | let b:hist -= 1 40 | endif 41 | let hlist = split(substitute(hists[-b:hist], '\v($|\n)', ' ', ''), ' ') 42 | if len(hlist) != 3 43 | return 44 | endif 45 | let [b:command, b:filter, b:rc] = hlist 46 | call taskwarrior#list() 47 | endif 48 | endfunction 49 | 50 | function! taskwarrior#log#bookmark(action) 51 | if findfile(s:bookmark_file) == '' 52 | call writefile([], s:bookmark_file) 53 | endif 54 | if a:action == 'new' && filewritable(s:bookmark_file) 55 | let now = b:command.' '.b:filter.' '.b:rc 56 | let ext = readfile(s:bookmark_file) 57 | if index(ext, now) == -1 58 | execute 'redir >> '.s:bookmark_file 59 | silent! echo now 60 | redir END 61 | echohl String 62 | echomsg 'New bookmark added.' 63 | echohl None 64 | endif 65 | elseif a:action == 'clear' 66 | call writefile([], s:bookmark_file) 67 | endif 68 | endfunction 69 | -------------------------------------------------------------------------------- /autoload/taskwarrior/sort.vim: -------------------------------------------------------------------------------- 1 | function! taskwarrior#sort#by_arg(...) 2 | let args = substitute(join(a:000, ' '), '\s\+', ',', 'g') 3 | let args = substitute(args, '\w\zs,', '-,', 'g') 4 | let args = substitute(args, '\w\zs$', '-', '') 5 | if args =~ '^\s*$' 6 | let b:rc = substitute(b:rc, 'rc.report.'.b:command.'.sort[:=]\S*', '', 'g') 7 | else 8 | let b:rc .= args == '' ? '' : ' rc.report.'.b:command.'.sort:'.args 9 | endif 10 | let b:hist = 1 11 | call taskwarrior#list() 12 | endfunction 13 | 14 | function! taskwarrior#sort#by_column(polarity, column) 15 | let fromrc = matchstr(b:rc, 'rc\.report\.'.b:command.'\.sort.\zs\S*') 16 | " let default = system('task _get -- rc.report.'.b:command.'.sort')[0:-2] 17 | let default = matchstr(system('task show | grep report.'.b:command.'.sort')[0:-2], '\S*$') 18 | let colshort = map(copy(b:task_report_columns), 'matchstr(v:val, "^\\w*")') 19 | let ccol = index(colshort, a:column) == -1 ? 20 | \ taskwarrior#data#current_column() : 21 | \ a:column 22 | let list = split(fromrc, ',') 23 | let ind = index(split(fromrc, '[-+],\='), ccol) 24 | let dlist = split(default, ',') 25 | let dind = index(split(default, '[-+],\='), ccol) 26 | if fromrc == '' 27 | if dind != -1 28 | if a:polarity == 'm' 29 | if dind == 0 30 | let dlist[0] = dlist[0][0:-2].(dlist[0][-1:-1] == '+' ? '-' : '+') 31 | endif 32 | call insert(dlist, remove(dlist, dind)) 33 | elseif dlist[dind] == ccol.a:polarity 34 | return 35 | else 36 | let dlist[dind] = ccol.a:polarity 37 | endif 38 | let b:rc .= ' rc.report.'.b:command.'.sort:'.join(dlist, ',') 39 | else 40 | let polarity = a:polarity == 'm' ? '-' : a:polarity 41 | let b:rc .= ' rc.report.'.b:command.'.sort:'.ccol.polarity.','.default 42 | endif 43 | elseif ind != -1 44 | if a:polarity == 'm' 45 | if ind == 0 46 | let list[0] = list[0][0:-2].(list[0][-1:-1] == '+' ? '-' : '+') 47 | else 48 | call insert(list, remove(list, ind)) 49 | endif 50 | elseif list[ind] == ccol.a:polarity 51 | if a:polarity == '+' 52 | call insert(list, remove(list, ind), ind > 1 ? ind-1 : 0) 53 | else 54 | if ind > len(list)-3 55 | call add(list, remove(list, ind)) 56 | else 57 | call insert(list, remove(list, ind), ind+1) 58 | endif 59 | endif 60 | else 61 | let list[ind] = ccol.a:polarity 62 | endif 63 | let g:listabc = list 64 | let b:rc = substitute(b:rc, 'report\.'.b:command.'\.sort.'.fromrc, 'report.'.b:command.'.sort:'.join(list, ','), '') 65 | else 66 | let polarity = a:polarity == 'm' ? '-' : a:polarity 67 | let b:rc = substitute(b:rc, 'report\.'.b:command.'\.sort.', 'report.'.b:command.'.sort:'.ccol.polarity.',', '') 68 | endif 69 | let b:hist = 1 70 | call taskwarrior#list() 71 | endfunction 72 | 73 | function! taskwarrior#sort#order_list() 74 | let fromrc = matchstr(b:rc, 'rc\.report\.'.b:command.'\.sort.\zs\S*') 75 | if fromrc == '' 76 | " let list = split(system('task _get -- rc.report.'.b:command.'.sort')[0:-2], ',') 77 | let list = split(matchstr(system('task show | grep report.'.b:command.'.sort')[0:-2], '\S*$'), ',') 78 | else 79 | let list = split(fromrc, ',') 80 | endif 81 | while exists('list[0]') && match(b:task_report_columns, list[0][0:-2]) == -1 && system('task count '.list[0][0:-2].'.any:')[0] == '0' 82 | call remove(list, 0) 83 | endwhile 84 | if len(list) == 0 85 | let list = ['status-'] 86 | endif 87 | return list 88 | endfunction 89 | -------------------------------------------------------------------------------- /autoload/unite/kinds/task.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! unite#kinds#task#define() 5 | return s:kind 6 | endfunction 7 | 8 | let s:kind = { 9 | \ 'name' : 'task', 10 | \ 'default_action' : 'show', 11 | \ 'action_table': {}, 12 | \} 13 | 14 | let s:kind.action_table.show = { 15 | \ 'description' : 'Show report', 16 | \ } 17 | 18 | function! s:kind.action_table.show.func(candidate) 19 | call taskwarrior#init(join(split(a:candidate.word, '[ \t]'), ' ')) 20 | endfunction 21 | 22 | let &cpo = s:save_cpo 23 | unlet s:save_cpo 24 | -------------------------------------------------------------------------------- /autoload/unite/sources/task.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:template = { 5 | \ 'name' : 'task/', 6 | \ 'description' : 'vim-taskwarrior ', 7 | \ 'filters' : ['matcher_regexp'], 8 | \ 'action_table': {}, 9 | \ 'hooks' : {}, 10 | \ } 11 | 12 | let s:bookmark = { 13 | \ 'name' : 'bookmark', 14 | \ 'logfile' : expand(g:task_log_directory.'/.vim_tw.bookmark') 15 | \ } 16 | 17 | let s:history = { 18 | \ 'name' : 'history', 19 | \ 'logfile' : expand(g:task_log_directory.'/.vim_tw.history') 20 | \ } 21 | 22 | function! s:make_source(dict) 23 | let source = deepcopy(s:template) 24 | let source.name .= a:dict.name 25 | let source.description .= a:dict.name 26 | let source.logfile = a:dict.logfile 27 | 28 | function! source.hooks.on_syntax(args, context) 29 | syntax match uniteSource__task_rc /rc.*/ contained containedin=ALL contains=uniteCandidateInputKeyword 30 | syntax match uniteSource__task_report /\w\+\ze[ \t]\+/ contained containedin=ALL 31 | highlight default link uniteSource__task_rc String 32 | highlight default link uniteSource__task_report Keyword 33 | endfunction 34 | 35 | function! source.gather_candidates(args, context) 36 | if findfile(self.logfile) == '' 37 | call writefile([], self.logfile) 38 | endif 39 | return map(reverse(readfile(self.logfile)), 40 | \ '{"word": v:val, 41 | \ "kind": "task", 42 | \ "source": "task/" . self.name, 43 | \ }') 44 | endfunction 45 | 46 | let source.action_table.delete = { 47 | \ 'description' : 'remove the item', 48 | \ } 49 | 50 | function! source.action_table.delete.func(candidate) 51 | let current = substitute(a:candidate.word, '\s', '', 'g') 52 | let lfile = g:task_log_directory.'/.vim_tw.bookmark' 53 | let all = readfile(lfile) 54 | let allns = map(copy(all), "substitute(v:val, '[ \t]', '', 'g')") 55 | call remove(all, index(allns, current)) 56 | call writefile(all, lfile) 57 | endfunction 58 | 59 | return source 60 | endfunction 61 | 62 | function! unite#sources#task#define() 63 | return map([s:bookmark, s:history], 's:make_source(v:val)') 64 | endfunction 65 | 66 | 67 | let &cpo = s:save_cpo 68 | unlet s:save_cpo 69 | -------------------------------------------------------------------------------- /autoload/webapi/json.vim: -------------------------------------------------------------------------------- 1 | " json 2 | " Last Change: 2012-03-08 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | function! webapi#json#null() 11 | return 0 12 | endfunction 13 | 14 | function! webapi#json#true() 15 | return 1 16 | endfunction 17 | 18 | function! webapi#json#false() 19 | return 0 20 | endfunction 21 | 22 | function! s:nr2byte(nr) 23 | if a:nr < 0x80 24 | return nr2char(a:nr) 25 | elseif a:nr < 0x800 26 | return nr2char(a:nr/64+192).nr2char(a:nr%64+128) 27 | else 28 | return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 29 | endif 30 | endfunction 31 | 32 | function! s:nr2enc_char(charcode) 33 | if &encoding == 'utf-8' 34 | return nr2char(a:charcode) 35 | endif 36 | let char = s:nr2byte(a:charcode) 37 | if strlen(char) > 1 38 | let char = strtrans(iconv(char, 'utf-8', &encoding)) 39 | endif 40 | return char 41 | endfunction 42 | 43 | function! s:fixup(val, tmp) 44 | if type(a:val) == 0 45 | return a:val 46 | elseif type(a:val) == 1 47 | if a:val == a:tmp.'null' 48 | return function('webapi#json#null') 49 | elseif a:val == a:tmp.'true' 50 | return function('webapi#json#true') 51 | elseif a:val == a:tmp.'false' 52 | return function('webapi#json#false') 53 | endif 54 | return a:val 55 | elseif type(a:val) == 2 56 | return a:val 57 | elseif type(a:val) == 3 58 | return map(a:val, 's:fixup(v:val, a:tmp)') 59 | elseif type(a:val) == 4 60 | return map(a:val, 's:fixup(v:val, a:tmp)') 61 | else 62 | return string(a:val) 63 | endif 64 | endfunction 65 | 66 | function! webapi#json#decode(json) 67 | let json = iconv(a:json, "utf-8", &encoding) 68 | if get(g:, 'webapi#json#parse_strict', 1) == 1 && substitute(substitute(substitute( 69 | \ json, 70 | \ '\\\%(["\\/bfnrt]\|u[0-9a-fA-F]\{4}\)', '\@', 'g'), 71 | \ '"[^\"\\\n\r]*\"\|true\|false\|null\|-\?\d\+' 72 | \ . '\%(\.\d*\)\?\%([eE][+\-]\{-}\d\+\)\?', ']', 'g'), 73 | \ '\%(^\|:\|,\)\%(\s*\[\)\+', '', 'g') !~ '^[\],:{} \t\n]*$' 74 | throw json 75 | endif 76 | let json = substitute(json, '\n', '', 'g') 77 | let json = substitute(json, '\\u34;', '\\"', 'g') 78 | if v:version >= 703 && has('patch780') 79 | let json = substitute(json, '\\u\(\x\x\x\x\)', '\=iconv(nr2char(str2nr(submatch(1), 16), 1), "utf-8", &encoding)', 'g') 80 | else 81 | let json = substitute(json, '\\u\(\x\x\x\x\)', '\=s:nr2enc_char("0x".submatch(1))', 'g') 82 | endif 83 | if get(g:, 'webapi#json#allow_nil', 0) != 0 84 | let tmp = '__WEBAPI_JSON__' 85 | while 1 86 | if stridx(json, tmp) == -1 87 | break 88 | endif 89 | let tmp .= '_' 90 | endwhile 91 | let [null,true,false] = [ 92 | \ tmp.'null', 93 | \ tmp.'true', 94 | \ tmp.'false'] 95 | sandbox let ret = eval(json) 96 | call s:fixup(ret, tmp) 97 | else 98 | let [null,true,false] = [0,1,0] 99 | sandbox let ret = eval(json) 100 | endif 101 | return ret 102 | endfunction 103 | 104 | function! webapi#json#encode(val) 105 | if type(a:val) == 0 106 | return a:val 107 | elseif type(a:val) == 1 108 | let json = '"' . escape(a:val, '\"') . '"' 109 | let json = substitute(json, "\r", '\\r', 'g') 110 | let json = substitute(json, "\n", '\\n', 'g') 111 | let json = substitute(json, "\t", '\\t', 'g') 112 | let json = substitute(json, '\([[:cntrl:]]\)', '\=printf("\x%02d", char2nr(submatch(1)))', 'g') 113 | return iconv(json, &encoding, "utf-8") 114 | elseif type(a:val) == 2 115 | let s = string(a:val) 116 | if s == "function('webapi#json#null')" 117 | return 'null' 118 | elseif s == "function('webapi#json#true')" 119 | return 'true' 120 | elseif s == "function('webapi#json#false')" 121 | return 'false' 122 | endif 123 | elseif type(a:val) == 3 124 | return '[' . join(map(copy(a:val), 'webapi#json#encode(v:val)'), ',') . ']' 125 | elseif type(a:val) == 4 126 | return '{' . join(map(keys(a:val), 'webapi#json#encode(v:val).":".webapi#json#encode(a:val[v:val])'), ',') . '}' 127 | else 128 | return string(a:val) 129 | endif 130 | endfunction 131 | 132 | let &cpo = s:save_cpo 133 | unlet s:save_cpo 134 | 135 | " vim:set et: 136 | -------------------------------------------------------------------------------- /doc/vim-tw.txt: -------------------------------------------------------------------------------- 1 | *vim-tw.txt* a vim interface for |Taskwarrior| version 1.1 ~ 2 | _ _ _ _ ~ 3 | __ _(_)_ __ ___ | |_ __ _ __| |____ __ ____ _ _ _ _ _(_)___ _ _ ~ 4 | \ V / | ' \ |___| | _/ _` (_-< / /\ V V / _` | '_| '_| / _ \ '_| ~ 5 | \_/|_|_|_|_| \__\__,_/__/_\_\ \_/\_/\__,_|_| |_| |_\___/_| ~ 6 | ~ 7 | ~ 8 | ============================================================================== 9 | QUICK-REFERENCE *tw-quickref* 10 | 11 | | a = add task | m = modify | S = taskd sync | = this help | 12 | | A = annotate | M = mod prompts | s = sort col | = task info | 13 | | d = task done | q = quit buffer | < = sort incr | c = abort | 14 | | D = task delete | r = new report | > = sort decr | = task/anno | 15 | | c = task cmd | u = undo last | = next col | = (de)select | 16 | | f = add filter | x = del annot | = prev col | p = dupe select | 17 | | H = cycle fmt l | + = start task | = r field | R = refresh | 18 | | L = cycle fmt r | - = stop task | = l field | X = clear done | 19 | | J = next entry | K = prev entry | B = new bookmark | o = open annotation | 20 | 21 | ============================================================================== 22 | CONTENTS *tw-contents* 23 | 24 | 01. Intro ........................................................ |Taskwarrior| 25 | 02. Prerequisites ........................................... |tw-prerequisites| 26 | 03. Mappings ..................................................... |tw-mappings| 27 | 04. Commands ..................................................... |tw-commands| 28 | 4.1 Global Commands ....................................... |tw-gl-commands| 29 | 4.2 Local Commands ........................................ |tw-lc-commands| 30 | 05. Customization ........................................... |tw-customization| 31 | 06. Troubleshooting ....................................... |tw-troubleshooting| 32 | 07. Contributions ........................................... |tw-contributions| 33 | 08. License ....................................................... |tw-license| 34 | 09. Changelog ................................................... |tw-changelog| 35 | 36 | ============================================================================== 37 | 1. INTRODUCTION *Taskwarrior* 38 | 39 | Taskwarrior is a command-line todo list manager. It helps you manage task lists 40 | with projects, tags, dates, dependencies, annotations, recurrences and apply 41 | complex (or simple) queries with attribute-modifiers, booleans, regex filters, 42 | custom attributes and color themes, and any number of built-in or customizable 43 | reports. Task keeps data in JSON text files and it's always improving. 44 | Find out more at https://taskwarrior.org and read man task and man taskrc. 45 | 46 | vim-taskwarrior is a vim plugin that extends taskwarrior with an interactive 47 | interface. It features a rich set of mappings and commands, is easy to customize 48 | and makes adding, modifying, sorting and marking tasks done, fast, easy and fun! 49 | Homepage: https://github.com/farseer90718/vim-taskwarrior, patches welcome! 50 | 51 | ============================================================================== 52 | 2. PREREQUISITES *tw-prerequisites* 53 | 54 | This plugin requires Taskwarrior 2.2.0 or higher, although > 2.3.x is required 55 | for taskd sync functions, and recommended in general, and well worth the price; 56 | free :) see: https://taskwarrior.org/download/ 57 | 58 | Vim version 7.x is required. 59 | 60 | the vim-airline plugin (https://github.com/bling/vim-airline) is not required 61 | but it greatly enhances the status-bar and takes the guess-work out of reports. 62 | 63 | If you experience line-wrapping issues, add the following line to your .vimrc 64 | let g:task_rc_override = 'defaultwidth=999' 65 | 66 | ============================================================================== 67 | 3. MAPPING *tw-mappings* 68 | 69 | (taskwarrior_quickref) :quick reference 70 | (taskwarrior_quit) :quit the buffer 71 | (taskwarrior_skip_left) :move the cursor to the left field, skipping blanks 72 | (taskwarrior_step_left) :move the cursor to the left field without skipping 73 | (taskwarrior_skip_right) :... right ... 74 | (taskwarrior_step_right) :... ... 75 | (taskwarrior_sort_increase) :increase the priority of current field in sorting 76 | (taskwarrior_sort_decrease) :decrease ... 77 | (taskwarrior_sort_inverse) :invert the sorting method of the main field 78 | (taskwarrior_show_info) :show information 79 | (taskwarrior_filter) :apply a new filter to the tasks 80 | (taskwarrior_next_format) :change the format of current field to the next one 81 | (taskwarrior_previous_format) :... previous ... 82 | (taskwarrior_next_history) :next history of report 83 | (taskwarrior_previous_history) :previous ... 84 | (taskwarrior_new_bookmark) :add a new bookmark for current setup 85 | (taskwarrior_visual_show_info) :show informations about selected tasks 86 | (taskwarrior_annotate) :add a new annotation 87 | (taskwarrior_denotate) :delete the annotation 88 | (taskwarrior_open_annotate) :open the annotation as a file or url 89 | (taskwarrior_remove) :remove the task 90 | (taskwarrior_delete) :remove the task/annotation 91 | (taskwarrior_new) :new task 92 | (taskwarrior_command) :apply a command to selected tasks 93 | (taskwarrior_done) :set the selected tasks done 94 | (taskwarrior_report) :change report type 95 | (taskwarrior_refresh) :refresh the buffer 96 | (taskwarrior_clear_completed) :clear all completed tasks 97 | (taskwarrior_undo) :undo 98 | (taskwarrior_sync) :synchronise with the remote server 99 | (taskwarrior_modify_field) :modify current field of the task 100 | (taskwarrior_modify_task) :modify the fields specified in |g:task_default_prompt| 101 | (taskwarrior_paste) :duplicate the selected tasks 102 | (taskwarrior_start_task) :start a task 103 | (taskwarrior_stop_task) :stop a task 104 | (taskwarrior_select) :select a task 105 | (taskwarrior_increase) :increase a number/date 106 | (taskwarrior_decrease) :decrease ... 107 | (taskwarrior_visual_done) :set visual selected tasks done 108 | (taskwarrior_visual_delete) :delete visual selected tasks 109 | (taskwarrior_visual_select) :select visual selected tasks 110 | 111 | Default ones 112 | ------------------------------------------------------------------------------ 113 | 114 | (taskwarrior_quickref) 115 | q (taskwarrior_quit) 116 | (taskwarrior_skip_left) 117 | (taskwarrior_step_left) 118 | (taskwarrior_skip_right) 119 | (taskwarrior_step_right) 120 | < (taskwarrior_sort_increase) 121 | > (taskwarrior_sort_decrease) 122 | s (taskwarrior_sort_inverse) 123 | (taskwarrior_show_info) 124 | f (taskwarrior_filter) 125 | H (taskwarrior_next_format) 126 | L (taskwarrior_previous_format) 127 | J (taskwarrior_next_history) 128 | K (taskwarrior_previous_history) 129 | B (taskwarrior_new_bookmark) 130 | (taskwarrior_visual_show_info) 131 | 132 | A (taskwarrior_annotate) 133 | x (taskwarrior_denotate) 134 | o (taskwarrior_open_annotate) 135 | D (taskwarrior_remove) 136 | (taskwarrior_delete) 137 | a (taskwarrior_new) 138 | c (taskwarrior_command) 139 | d (taskwarrior_done) 140 | r (taskwarrior_report) 141 | R (taskwarrior_refresh) 142 | X (taskwarrior_clear_completed) 143 | u (taskwarrior_undo) 144 | S (taskwarrior_sync) 145 | m (taskwarrior_modify_field) 146 | M (taskwarrior_modify_task) 147 | p (taskwarrior_paste) 148 | + (taskwarrior_start_task) 149 | - (taskwarrior_stop_task) 150 | (taskwarrior_select) 151 | (taskwarrior_increase) 152 | (taskwarrior_decrease) 153 | d (taskwarrior_visual_done) 154 | D (taskwarrior_visual_delete) 155 | (taskwarrior_visual_delete) 156 | (taskwarrior_visual_select) 157 | 158 | How to change 159 | ------------------------------------------------------------------------------ 160 | Add something like these to your configuration files 161 | 162 | augroup TaskwarriorMapping 163 | autocmd! 164 | autocmd FileType taskreport nmap {key} 165 | \ (taskwarrior_...) 166 | autocmd FileType taskreport nunmap {key} 167 | augroup END 168 | 169 | ============================================================================== 170 | 4. COMMAND *tw-commands* 171 | 172 | 4.1 Global Commands *tw-gl-commands* 173 | ------------------------------------------------------------------------------ 174 | 175 | Almost the same as the shell command 'task' *:TW* 176 | Undo last move *:TWUndo* 177 | Edit taskrc right away *:TWEditTaskrc* 178 | Edit vitrc *:TWEditVitrc* 179 | Delete completed tasks *:TWDeleteCompleted* 180 | list history records using |unite.vim| *:TWHistory* 181 | clear history *:TWHistoryClear* 182 | list bookmarks using |unite.vim| *:TWBookmark* 183 | clear bookmarks *:TWBookmarkClear* 184 | 4.2 Local Commands *tw-lc-commands* 185 | ------------------------------------------------------------------------------ 186 | 187 | Add an annotation *:TWAnnotate* 188 | Mark task done *:TWComplete* 189 | Delete a task *:TWDelete* 190 | Delete an annotation *:TWDeleteAnnotation* 191 | Make changes to a task interactively *:TWModifyInteractive* 192 | Run the info report *:TWReportInfo* 193 | Overide the sort method *:TWReportSort* 194 | Synchronise with taskd server *:TWSync* 195 | Toggle readonly option *:TWToggleReadonly* 196 | Toggle highlight field option *:TWToggleHLField* 197 | 198 | ============================================================================== 199 | 5. CUSTOMIZATION *tw-customization* 200 | 201 | *g:task_report_name* 202 | Default task report type. 203 | Default value is 'next'. 204 | *g:task_highlight_field* 205 | Whether the field under the cursor is highlighted. 206 | Default value is 1. 207 | *g:task_readonly* 208 | Can not make change to task data when set to 1. 209 | Default value is 0. 210 | *g:task_rc_override* 211 | Allows user to override task configurations. Seperated by space. 212 | Default value is ''. 213 | *g:task_default_prompt* 214 | Default fields to ask when adding a new task. 215 | Default value is: 216 | ['due', 'project', 'priority', 'description', 'tag', 'depends']. 217 | *g:task_info_vsplit* 218 | Whether the info window is splited vertically. 219 | Default value is 0. 220 | *g:task_info_size* 221 | Info window size. 222 | Default value is 15 for horizontal and 50 for vertical. 223 | *g:task_info_position* 224 | Info window position. 225 | Default value is 'belowright'. 226 | *g:task_log_directory* 227 | Directory to store log files defaults to taskwarrior data.location. 228 | Default value is taskwarrior data.location. 229 | *g:task_log_max* 230 | Max number of historical entries. 231 | Default value is 10. 232 | *g:task_left_arrow* 233 | Forward arrow shown on statusline. 234 | Default value is ' <<' 235 | *g:task_right_arrow* 236 | Backward arrow shown on statusline. 237 | Default value is '>> ' 238 | *g:task_gui_term* 239 | Uses gvim's dumb terminal for undo commands when set to 1. 240 | Default value is 1 241 | 242 | ============================================================================== 243 | 6. TROUBLESHOOTING *tw-troubleshooting* 244 | 245 | 246 | ============================================================================== 247 | 7. CONTRIBUTIONS *tw-contributions* 248 | 249 | Contributions and pull requests are welcome. 250 | 251 | ============================================================================== 252 | 8. LICENSE *tw-license* 253 | 254 | MIT License. 255 | Copyright © 2013 Zc He. 256 | Copyright © 2013 David J Patrick. 257 | 258 | ============================================================================== 259 | 9. CHANGELOG *tw-changelog* 260 | 261 | .. in progress! 262 | 263 | -------------------------------------------------------------------------------- /ftplugin/taskreport.vim: -------------------------------------------------------------------------------- 1 | setlocal buftype=nofile 2 | setlocal nomodifiable 3 | setlocal cursorline 4 | setlocal startofline 5 | setlocal nowrap 6 | 7 | nnoremap (taskwarrior_quickref) :h tw-quickref 8 | nnoremap (taskwarrior_quit) :call taskwarrior#quit() 9 | nnoremap (taskwarrior_quit_all) :call taskwarrior#quit_all() 10 | nnoremap (taskwarrior_skip_left) :call taskwarrior#action#move_cursor('left', 'skip') 11 | nnoremap (taskwarrior_step_left) :call taskwarrior#action#move_cursor('left', 'step') 12 | nnoremap (taskwarrior_skip_right) :call taskwarrior#action#move_cursor('right', 'skip') 13 | nnoremap (taskwarrior_step_right) :call taskwarrior#action#move_cursor('right', 'step') 14 | nnoremap (taskwarrior_sort_increase) :call taskwarrior#sort#by_column('+', '') 15 | nnoremap (taskwarrior_sort_decrease) :call taskwarrior#sort#by_column('-', '') 16 | nnoremap (taskwarrior_sort_inverse) :call taskwarrior#sort#by_column('m', '') 17 | nnoremap (taskwarrior_show_info) :call taskwarrior#action#show_info() 18 | nnoremap (taskwarrior_filter) :call taskwarrior#action#filter() 19 | nnoremap (taskwarrior_next_format) :call taskwarrior#action#columns_format_change('left') 20 | nnoremap (taskwarrior_previous_format) :call taskwarrior#action#columns_format_change('right') 21 | nnoremap (taskwarrior_next_history) :call taskwarrior#log#history('next') 22 | nnoremap (taskwarrior_previous_history) :call taskwarrior#log#history('previous') 23 | nnoremap (taskwarrior_new_bookmark) :call taskwarrior#log#bookmark('new') 24 | vnoremap (taskwarrior_visual_show_info) :call taskwarrior#action#visual('info') 25 | 26 | nnoremap (taskwarrior_annotate) :call taskwarrior#action#annotate('add') 27 | nnoremap (taskwarrior_denotate) :call taskwarrior#action#annotate('del') 28 | nnoremap (taskwarrior_open_annotate) :call taskwarrior#action#annotate('open') 29 | nnoremap (taskwarrior_remove) :call taskwarrior#action#remove() 30 | nnoremap (taskwarrior_delete) :call taskwarrior#action#delete() 31 | nnoremap (taskwarrior_new) :call taskwarrior#action#new() 32 | nnoremap (taskwarrior_command) :call taskwarrior#action#command() 33 | nnoremap (taskwarrior_done) :call taskwarrior#action#set_done() 34 | nnoremap (taskwarrior_report) :call taskwarrior#action#report() 35 | nnoremap (taskwarrior_refresh) :call taskwarrior#list() 36 | nnoremap (taskwarrior_clear_completed) :call taskwarrior#action#clear_completed() 37 | nnoremap (taskwarrior_undo) :call taskwarrior#action#undo() 38 | nnoremap (taskwarrior_urgency) :call taskwarrior#action#urgency() 39 | nnoremap (taskwarrior_sync) :call taskwarrior#action#sync('sync') 40 | nnoremap (taskwarrior_modify_field) :call taskwarrior#action#modify('current') 41 | nnoremap (taskwarrior_modify_task) :call taskwarrior#action#modify('') 42 | nnoremap (taskwarrior_paste) :call taskwarrior#action#paste() 43 | nnoremap (taskwarrior_start_task) :call taskwarrior#system_call(taskwarrior#data#get_uuid(), 'start', '', 'silent') 44 | nnoremap (taskwarrior_stop_task) :call taskwarrior#system_call(taskwarrior#data#get_uuid(), 'stop', '', 'silent') 45 | nnoremap (taskwarrior_select) :call taskwarrior#action#select() 46 | nnoremap (taskwarrior_increase) :call taskwarrior#action#date(v:count1) 47 | nnoremap (taskwarrior_decrease) :call taskwarrior#action#date(-v:count1) 48 | vnoremap (taskwarrior_visual_done) :call taskwarrior#action#visual('done') 49 | vnoremap (taskwarrior_visual_delete) :call taskwarrior#action#visual('delete') 50 | vnoremap (taskwarrior_visual_select) :call taskwarrior#action#visual('select') 51 | 52 | nmap (taskwarrior_quickref) 53 | nmap Q (taskwarrior_quit_all) 54 | nmap q (taskwarrior_quit) 55 | nmap (taskwarrior_skip_left) 56 | nmap (taskwarrior_step_left) 57 | nmap (taskwarrior_skip_right) 58 | nmap (taskwarrior_step_right) 59 | nmap < (taskwarrior_sort_increase) 60 | nmap > (taskwarrior_sort_decrease) 61 | nmap s (taskwarrior_sort_inverse) 62 | nmap (taskwarrior_show_info) 63 | nmap f (taskwarrior_filter) 64 | nmap H (taskwarrior_next_format) 65 | nmap L (taskwarrior_previous_format) 66 | nmap J (taskwarrior_next_history) 67 | nmap K (taskwarrior_previous_history) 68 | nmap B (taskwarrior_new_bookmark) 69 | vmap (taskwarrior_visual_show_info) 70 | 71 | if g:task_highlight_field 72 | autocmd CursorMoved :call taskwarrior#hi_field() 73 | else 74 | autocmd! CursorMoved 75 | endif 76 | 77 | if g:task_readonly 78 | setlocal readonly 79 | if hasmapto('(taskwarrior_undo)') 80 | nunmap A 81 | nunmap x 82 | nunmap o 83 | nunmap D 84 | nunmap 85 | nunmap a 86 | nunmap c 87 | nunmap d 88 | nunmap r 89 | nunmap R 90 | nunmap X 91 | nunmap u 92 | nunmap S 93 | nunmap m 94 | nunmap M 95 | nunmap p 96 | nunmap + 97 | nunmap - 98 | nunmap 99 | nunmap 100 | nunmap 101 | vunmap d 102 | vunmap D 103 | vunmap 104 | vunmap 105 | endif 106 | else 107 | nmap A (taskwarrior_annotate) 108 | nmap x (taskwarrior_denotate) 109 | nmap o (taskwarrior_open_annotate) 110 | nmap D (taskwarrior_remove) 111 | nmap (taskwarrior_delete) 112 | nmap a (taskwarrior_new) 113 | nmap c (taskwarrior_command) 114 | nmap d (taskwarrior_done) 115 | nmap r (taskwarrior_report) 116 | nmap R (taskwarrior_refresh) 117 | nmap X (taskwarrior_clear_completed) 118 | nmap u (taskwarrior_undo) 119 | nmap U (taskwarrior_urgency) 120 | nmap S (taskwarrior_sync) 121 | nmap m (taskwarrior_modify_field) 122 | nmap M (taskwarrior_modify_task) 123 | nmap p (taskwarrior_paste) 124 | nmap + (taskwarrior_start_task) 125 | nmap - (taskwarrior_stop_task) 126 | nmap (taskwarrior_select) 127 | nmap (taskwarrior_increase) 128 | nmap (taskwarrior_decrease) 129 | vmap d (taskwarrior_visual_done) 130 | vmap D (taskwarrior_visual_delete) 131 | vmap (taskwarrior_visual_delete) 132 | vmap (taskwarrior_visual_select) 133 | 134 | command! -buffer TWAdd :call taskwarrior#action#new() 135 | command! -buffer TWAnnotate :call taskwarrior#action#annotate('add') 136 | command! -buffer TWComplete :call taskwarrior#action#set_done() 137 | command! -buffer TWDelete :call taskwarrior#action#delete() 138 | command! -buffer TWDeleteAnnotation :call taskwarrior#action#annotate('del') 139 | command! -buffer TWModifyInteractive :call taskwarrior#modify('') 140 | command! -buffer TWSync :call taskwarrior#action#sync('sync') 141 | endif 142 | 143 | command! -buffer TWToggleReadonly :let g:task_readonly = (g:task_readonly ? 0 : 1) | call taskwarrior#refresh() 144 | command! -buffer TWToggleHLField :let g:task_highlight_field = (g:task_highlight_field ? 0 : 1) | call taskwarrior#refresh() 145 | command! -buffer -nargs=? -complete=customlist,taskwarrior#complete#sort TWReportSort :call taskwarrior#action#sort_by_arg() 146 | -------------------------------------------------------------------------------- /plugin/taskwarrior.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_taskwarrior') && g:loaded_taskwarrior 2 | finish 3 | endif 4 | 5 | if !executable('task') 6 | echoerr "This plugin depends on taskwarrior(https://taskwarrior.org)." 7 | finish 8 | endif 9 | 10 | let g:task_report_command = get(g:, 'task_report_command', []) 11 | let s:task_report_command = ['active', 'all', 'blocked', 'blocking', 'completed', 'list', 'long', 'ls', 'minimal', 'newest', 'next', 'oldest', 'overdue', 'ready', 'recurring', 'unblocked', 'waiting'] 12 | let g:task_report_command = extend(s:task_report_command, g:task_report_command) 13 | let g:task_interactive_command = ['annotate', 'denotate', 'execute', 'duplicate', 14 | \ 'append', 'prepend', 'stop', 'delete', 'done', 'undo', 15 | \ 'config', 'edit', 'start', 'sync', 'synchronize', 'add', 16 | \ 'modify', 'import', 'colors', 'color', 'logo', 'context'] 17 | let g:task_filter = ['description:', 'proj:', 'pri:', 'status:', 'tag:', 'due.before:', 'due.after:', 'entry.before', 'entry.after', 'end.before', 'end.after', '+'] 18 | let g:task_all_commands = split(system('task _command'), '\n') 19 | let g:task_all_configurations = split(system('task _config'), '\n') 20 | let g:task_report_name = index(g:task_report_command, get(g:, 'task_report_name')) != -1 ? get(g:, 'task_report_name') : 'next' 21 | let g:task_highlight_field = get(g:, 'task_highlight_field', 1) 22 | let g:task_readonly = get(g:, 'task_readonly', 0) 23 | let g:task_rc_override = get(g:, 'task_rc_override', '') 24 | let g:task_default_prompt = get(g:, 'task_default_prompt', ['due', 'project', 'priority', 'description', 'tag', 'depends']) 25 | let g:task_info_vsplit = get(g:, 'task_info_vsplit', 0) 26 | let g:task_info_size = get(g:, 'task_info_size', g:task_info_vsplit? 50 : 15) 27 | let g:task_info_position = get(g:, 'task_info_position', 'belowright') 28 | " let g:task_log_directory = get(g:, 'task_log_file', system('task _get -- rc.data.location')[0:-2]) 29 | let g:task_log_directory = get(g:, 'task_log_file', matchstr(system('task show | grep data.location')[0:-2], '\S*$')) 30 | let g:task_log_max = get(g:, 'task_log_max', 10) 31 | let g:task_left_arrow = get(g:, 'task_left_arrow', ' <<') 32 | let g:task_right_arrow = get(g:, 'task_right_arrow', '>> ') 33 | let g:task_readonly_symbol = get(g:, 'task_readonly_symbol', '  ') 34 | let g:task_gui_term = get(g:, 'task_gui_term', 1) 35 | let g:task_columns_format = { 36 | \ 'depends': ['list', 'count', 'indicator'], 37 | \ 'description': ['combined', 'desc', 'oneline', 'truncated', 'count'], 38 | \ 'due': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'], 39 | \ 'end': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'], 40 | \ 'entry': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'], 41 | \ 'id': ['number'], 42 | \ 'imask': ['number'], 43 | \ 'mask': ['default'], 44 | \ 'modified': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'], 45 | \ 'parent': ['long', 'short'], 46 | \ 'priority': ['short', 'long'], 47 | \ 'project': ['full', 'parent', 'indented'], 48 | \ 'recur': ['duration', 'indicator'], 49 | \ 'scheduled': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'], 50 | \ 'start': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown', 'active'], 51 | \ 'status': ['long', 'short'], 52 | \ 'tags': ['list', 'indicator', 'count'], 53 | \ 'until': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'], 54 | \ 'urgency': ['real', 'integer'], 55 | \ 'uuid': ['long', 'short'], 56 | \ 'wait': ['formatted', 'julian', 'epoch', 'iso', 'age', 'countdown'] } 57 | " 58 | "commented out pending taskd collision avoidance 59 | "command! TaskPush call tw#remote('push') 60 | "command! TaskPull call tw#remote('pull') 61 | "command! TaskMerge call tw#remote('merge') 62 | " 63 | "commands; 64 | " 65 | command! -nargs=? -complete=customlist,taskwarrior#complete#TW TW :call taskwarrior#init() 66 | command! -nargs=? TWReportInfo :call taskwarrior#action#show_info() 67 | "command! TWConfigColor 68 | command! TWDeleteCompleted :call taskwarrior#action#clear_completed() 69 | "command! TWDeleteNote 70 | "command! TWEdit 71 | "command! TWEditAnnotation 72 | "command! TWEditDescription 73 | command! TWEditTaskrc :execute "e ".$HOME."/.taskrc" 74 | command! TWEditVitrc :execute "e ".$HOME."/.vitrc" 75 | command! TWEditTaskopenrc :execute "e ".$HOME."/.taskopenrc" 76 | "command! TWExport 77 | "command! TWHelp 78 | command! TWHistory :Unite task/history 79 | command! TWHistoryClear :call taskwarrior#log#history('clear') 80 | command! TWBookmark :Unite task/bookmark 81 | command! TWBookmarkClear :call taskwarrior#log#bookmark('clear') 82 | "command! TWInsert 83 | "command! TWImport 84 | "command! TWNote 85 | "command! TWOpen 86 | "command! TWOpenInline 87 | "command! TWReport 88 | "command! TWReportAgenda 89 | "command! TWReportBreak 90 | "command! TWReportCalendar 91 | "command! TWReportDesc 92 | "command! TWReportEdit 93 | "command! TWReportGantt 94 | "command! TWReportProjects 95 | "command! TWReportTags 96 | "command! TWSyncFiles 97 | "command! TWSyncStatus 98 | "command! TWTheme 99 | "command! TWThemeEdit 100 | "command! TWThemeShow 101 | command! TWUndo :call taskwarrior#action#undo() 102 | "command! TWWiki 103 | "command! TWWikiDiary 104 | "command! TWWikiDiaryAdd 105 | "command! TWWikiGenIndex 106 | "command! TWWikiGenProject 107 | "command! TWWikiGenTag 108 | "command! TWWikiIndex 109 | 110 | let g:loaded_taskwarrior = 1 111 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blindFS/vim-taskwarrior/8ae6c5ee2ed54d759a58a8d9f67bc76430e3bd25/screenshot.png -------------------------------------------------------------------------------- /syntax/taskinfo.vim: -------------------------------------------------------------------------------- 1 | if exists("b:current_syntax") 2 | finish 3 | endif 4 | 5 | syntax match taskinfo_head /.*\%1l/ 6 | highlight default link taskinfo_head Tabline 7 | 8 | let b:current_syntax = 'taskinfo' 9 | -------------------------------------------------------------------------------- /syntax/taskreport.vim: -------------------------------------------------------------------------------- 1 | if exists("b:current_syntax") 2 | finish 3 | endif 4 | 5 | if exists('b:task_report_labels') 6 | syntax match taskwarrior_tablehead /.*\%1l/ 7 | endif 8 | 9 | for n in b:sline 10 | execute 'syntax match taskwarrior_selected /.*\%'.n.'l/ contains=ALL' 11 | endfor 12 | 13 | if search('[^\x00-\xff]') == 0 14 | let exp = 'syntax match taskwarrior_%s /\%%>1l\%%%dc.*\%%<%dc/' 15 | else 16 | let exp = 'syntax match taskwarrior_%s /\%%>1l\%%%dv.*\%%<%dv/' 17 | endif 18 | 19 | if exists('b:task_columns') && exists('b:task_report_columns') 20 | for i in range(0, len(b:task_report_columns)-1) 21 | if exists('b:task_columns['.(i+1).']') 22 | execute printf(exp, matchstr(b:task_report_columns[i], '^\w\+') , b:task_columns[i]+1, b:task_columns[i+1]+1) 23 | endif 24 | endfor 25 | endif 26 | 27 | highlight default link taskwarrior_tablehead Tabline 28 | highlight default link taskwarrior_field IncSearch 29 | highlight default link taskwarrior_selected Visual 30 | highlight default link taskwarrior_id VarId 31 | highlight default link taskwarrior_project String 32 | highlight default link taskwarrior_Status Include 33 | highlight default link taskwarrior_priority Class 34 | highlight default link taskwarrior_due Todo 35 | highlight default link taskwarrior_end Keyword 36 | highlight default link taskwarrior_description Normal 37 | highlight default link taskwarrior_entry Special 38 | highlight default link taskwarrior_depends Todo 39 | highlight default link taskwarrior_tags Keyword 40 | highlight default link taskwarrior_uuid VarId 41 | highlight default link taskwarrior_urgency Todo 42 | 43 | let b:current_syntax = 'taskreport' 44 | --------------------------------------------------------------------------------