Update 2024-02-14 16:20 Linux/x86_64-ld5587

This commit is contained in:
c0dev0id 2024-02-14 16:20:07 +01:00
parent 35ed2c3d92
commit 8d78a17efb
19 changed files with 2058 additions and 0 deletions

View File

@ -0,0 +1,23 @@
==============================================
This is a copy of the MIT license.
==============================================
Copyright (C) 2013 Zc He <farseer90718@gmail.com>
Copyright (C) 2013 David J Patrick <davamundo@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,223 @@
vim-taskwarrior
===============
_a vim interface for [taskwarrior](https://taskwarrior.org)_
Taskwarrior is a command-line todo list manager. It helps you manage task lists
with projects, tags, dates, dependencies, annotations, recurrences and apply
complex (or simple) queries with attribute modifiers, boolean, regex filters
and produce any number of reports, built-in or customizable reports, attributes
and color themes. Task keeps data in JSON text files and it's always improving.
Find out more at https://taskwarrior.org and read man task and man taskrc.
vim-taskwarrior is a vim plugin that extends taskwarrior with an interactive
interface. It features a rich set of mappings and commands, is easy to customize,
and makes adding, modifying, sorting, reporting and marking done, fast, easy and fun!
Homepage: https://github.com/farseer90718/vim-taskwarrior, patches welcome!
----
### Prerequisites:
This plugin requires Taskwarrior 2.2.0 or higher, although >2.3.x is required
for taskd sync functions, and recommended in general, and well worth the price;
free :)
see: https://taskwarrior.org/download/
Vim version 7.x is required.
Suggested plugins
* [vim-airline](https://github.com/bling/vim-airline) for [better statusline information](https://github.com/farseer90718/vim-taskwarrior#screenshot).
* [unite.vim](https://github.com/Shougo/unite.vim) for easier bookmark/history operations.
If you experience line-wrapping issues, add the following line to your .vimrc
```
let g:task_rc_override = 'rc.defaultwidth=0'
```
If you experience task truncation (vim-taskwarrior not showing enough tasks), add:
```
let g:task_rc_override = 'rc.defaultheight=0'
```
----
### Screenshot:
![screenshot](https://raw.github.com/farseer90718/vim-taskwarrior/master/screenshot.png)
![vim-taskwarrior animated gif](http://taskextras.org/attachments/download/655/20131110_002753.gif)
### Installing:
Either [download zip file](https://github.com/farseer90718/vim-taskwarrior/archive/master.zip)
and extract in ~/.vim or use your favorite plugin manager.
- [Pathogen](https://github.com/tpope/vim-pathogen)
- `git clone https://github.com/farseer90718/vim-taskwarrior ~/.vim/bundle/vim-taskwarrior`
- [Vundle](https://github.com/gmarik/vundle)
1. Add `Bundle 'farseer90718/vim-taskwarrior'` to .vimrc
2. Run `:BundleInstall`
- [NeoBundle](https://github.com/Shougo/neobundle.vim)
1. Add `NeoBundle 'farseer90718/vim-taskwarrior'` to .vimrc
2. Run `:NeoBundleInstall`
- [vim-plug](https://github.com/junegunn/vim-plug)
1. Add `Plug 'blindFS/vim-taskwarrior'` to .vimrc
2. Run `:PlugInstall`
----
### Default map:
```vim
nnoremap <buffer> A ... " add annotation
nnoremap <buffer> x ... " delete annotation.
nnoremap <buffer> o ... " open the annotation as a file.
nnoremap <buffer> a ... " create new task.
nnoremap <buffer> d ... " set the task in current line done.
nnoremap <buffer> D ... " delete task
nnoremap <buffer> <Del> ... " delete field/annotation/task
nnoremap <buffer> <Space> ... " select/remove current task to selected list
nnoremap <buffer> m ... " modify current field.
nnoremap <buffer> M ... " modify current task.
nnoremap <buffer> f ... " change filter
nnoremap <buffer> r ... " change report type
nnoremap <buffer> c ... " execute a command for selected tasks/current task
nnoremap <buffer> R ... " refresh the report/clear selected list
nnoremap <buffer> q ... " quit buffer.
nnoremap <buffer> X ... " clear all completed task.
nnoremap <buffer> p ... " duplicate selected tasks
nnoremap <buffer> u ... " undo last change.
nnoremap <buffer> + ... " start task
nnoremap <buffer> - ... " stop task
nnoremap <buffer> S ... " sync with taskd server.
nnoremap <buffer> s ... " sort by this column primarily.(if already of the highest priority then switch the polarity)
nnoremap <buffer> < ... " sort by this column increasingly.(if already increasingly then increase its priority)
nnoremap <buffer> > ... " sort by this column decreasingly.(if already decreasingly then decrease its priority)
nnoremap <buffer> H ... " cycle column format left
nnoremap <buffer> L ... " cycle column format right
nnoremap <buffer> J ... " next historical entry
nnoremap <buffer> K ... " previous historical entry
nnoremap <buffer> B ... " create a bookmark for current combination
nnoremap <buffer> <F1> ... " view the documents
nnoremap <buffer> <CR> ... " show task info.
nnoremap <buffer> <TAB> ... " jump to the next column
nnoremap <buffer> <S-TAB> ... " jump to the previous column
nnoremap <buffer> <right> ... " jump to the next non-empty column
nnoremap <buffer> <left> ... " jump to the previous non-empty column
vnoremap <buffer> d ... " set done to all visual selected tasks
vnoremap <buffer> D ... " delete all visual selected tasks
vnoremap <buffer> <CR> ... " show information about visual selected tasks
vnoremap <buffer> <Space> ... " add visual selected tasks to selected list
```
----
### Commands:
```vim
:TW [args] " task [filter report arguments]
:TWUndo " undo the previous modification
:TWEditTaskrc " edit ~/.taskrc
:TWEditVitrc " edit ~/.vitrc
:TWDeleteCompleted " clear all completed tasks
:TWAdd " add new tasks interactively
:TWAnnotate " add an annotation
:TWComplete " mark task done
:TWDelete " deleta a task
:TWDeleteAnnotation " delete an annotation
:TWModifyInteractive " make changes to a task interactively (use with caution!)
:TWReportInfo " run the info report
:TWReportSort [args] " overide the sort method, reset to default if no arguments passed
:TWSync " synchronise with taskd server
:TWToggleReadonly " toggle readonly option
:TWToggleHLField " toggle highlight field option
:TWHistory " list history records using unite.vim
:TWHistoryClear " clear history
:TWBookmark " list bookmarks using unite.vim
:TWBookmarkClear " clear bookmarks
```
----
### Options:
```vim
" default task report type
let g:task_report_name = 'next'
" custom reports have to be listed explicitly to make them available
let g:task_report_command = []
" whether the field under the cursor is highlighted
let g:task_highlight_field = 1
" can not make change to task data when set to 1
let g:task_readonly = 0
" vim built-in term for task undo in gvim
let g:task_gui_term = 1
" allows user to override task configurations. Seperated by space. Defaults to ''
let g:task_rc_override = 'rc.defaultwidth=999'
" default fields to ask when adding a new task
let g:task_default_prompt = ['due', 'description']
" whether the info window is splited vertically
let g:task_info_vsplit = 0
" info window size
let g:task_info_size = 15
" info window position
let g:task_info_position = 'belowright'
" directory to store log files defaults to taskwarrior data.location
let g:task_log_directory = '~/.task'
" max number of historical entries
let g:task_log_max = '20'
" forward arrow shown on statusline
let g:task_left_arrow = ' <<'
" backward arrow ...
let g:task_left_arrow = '>> '
```
----
### Syntax highlightling:
Default scheme:
```vim
highlight default link taskwarrior_tablehead Tabline
highlight default link taskwarrior_field IncSearch
highlight default link taskwarrior_selected Visual
highlight default link taskwarrior_id VarId
highlight default link taskwarrior_project String
highlight default link taskwarrior_Status Include
highlight default link taskwarrior_priority Class
highlight default link taskwarrior_due Todo
highlight default link taskwarrior_end Keyword
highlight default link taskwarrior_description Normal
highlight default link taskwarrior_entry Special
highlight default link taskwarrior_depends Todo
highlight default link taskwarrior_tags Keyword
highlight default link taskwarrior_uuid VarId
highlight default link taskwarrior_urgency Todo
```
Feel free to change any of above by something like:
```vim
hi taskwarrior_xxx guibg = xxx guifg = xxx ctermbg = xxx ctermfg = xxx
```
in your vimrc.
### Acknowledgement:
* [vim-airline](https://github.com/bling/vim-airline) by bling
* [unite.vim](https://github.com/Shougo/unite.vim) by Shougo
* [webapi-vim](https://github.com/mattn/webapi-vim) by mattn
### License:
[MIT](https://raw.github.com/farseer90718/vim-taskwarrior/master/LICENSE.txt)
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/farseer90718/vim-taskwarrior/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

View File

@ -0,0 +1,41 @@
function! airline#extensions#taskwarrior#apply(...)
if &ft == 'taskreport'
call a:1.add_section('airline_a', ' Taskwarrior ')
call a:1.add_section('airline_b', ' %{b:command} %{&readonly ? g:airline_symbols.readonly : ""}')
call a:1.add_section('airline_b', ' @%{b:context} ')
call a:1.add_section('airline_b', g:task_left_arrow.' %{b:hist > 1 ? g:task_right_arrow : ""}')
call a:1.add_section('airline_c', ' %{b:filter} ')
call a:1.add_section('airline_c', ' %{b:sstring} ')
call a:1.split()
call a:1.add_section('airline_x', ' %{b:now} ')
call a:1.add_section('airline_x', ' %{b:task_report_columns[taskwarrior#data#current_index()]} ')
call a:1.add_section('airline_y', ' %{b:sort} ')
if b:active != '0'
call airline#parts#define_text('active', ' '.b:active.' ')
call airline#parts#define_accent('active', 'orange')
call a:1.add_section('airline_z', airline#section#create(['active']))
endif
call a:1.add_section('airline_z', ' %{b:summary[0]} ')
call airline#parts#define_text('completed', ' '.b:summary[1].' ')
call airline#parts#define_accent('completed', 'green')
call a:1.add_section('airline_z', airline#section#create(['completed']))
call a:1.add_section('airline_z', ' %{b:summary[2]} ')
return 1
elseif &ft == 'taskinfo'
call a:1.add_section('airline_a', ' Taskinfo ')
call a:1.add_section('airline_b', ' %{b:command." ".g:airline_symbols.readonly }')
call a:1.add_section('airline_c', ' %{b:filter} ')
call a:1.split()
return 1
endif
endfunction
function s:context()
let con = split(system('task context show'), '\n')
let con = con =~ 'No context' ? 'none' : con
return con
endfunction
function! airline#extensions#taskwarrior#init(ext)
call a:ext.add_statusline_func('airline#extensions#taskwarrior#apply')
endfunction

View File

@ -0,0 +1,44 @@
function! taskinfo#init(command, filter, info)
if exists('g:task_info')
call taskinfo#quit()
endif
if a:command != 'info'
\ && exists('g:task_info_arg')
\ && g:task_info_arg == [a:command, a:filter]
unlet g:task_info_arg
return
endif
execute g:task_info_position.' '.g:task_info_size.
\ (g:task_info_vsplit ? 'v' : '').'split'
edit taskinfo
let g:task_info = bufnr('%')
let g:task_info_arg = [a:command, a:filter]
setlocal noswapfile
setlocal modifiable
call append(0, a:info)
silent global/^[\t ]*$/delete
silent global/^[ -]\+$/delete
setlocal readonly
setlocal nomodifiable
setlocal buftype=nofile
setlocal nowrap
setlocal filetype=taskinfo
1
let b:command = a:command
let b:filter = a:filter
nnoremap <silent> <buffer> q :call taskinfo#quit()<CR>
nnoremap <silent> <buffer> <enter> :call taskinfo#quit()<CR>
if a:command != 'info'
wincmd W
endif
endfunction
function! taskinfo#quit()
silent! execute g:task_info.'bd!'
unlet g:task_info
endfunction

View File

@ -0,0 +1,221 @@
function! taskwarrior#list(...) abort
setlocal noreadonly
setlocal modifiable
let pos = getpos('.')
%delete
call taskwarrior#buffer_var_init()
let b:command = get(a:, 1, b:command)
let b:filter = get(a:, 2, b:filter)
let b:type = get(a:, 3, b:type)
let b:rc = get(a:, 4, b:rc). ' rc.defaultheight=0'
let b:rc .= ' '.join(filter(split(b:filter, ' '), "v:val =~ '^rc\..*'"))
let b:filter = join(filter(split(b:filter, ' '), "v:val !~ '^rc\..*'"))
let rcs = split(b:rc, ' ')
let b:rc = join(filter(copy(rcs), "match(rcs, matchstr(v:val, '^[^=:]*'), v:key+1) == -1"), ' ')
if b:type == 'special'
setlocal buftype=nofile
call append(0, split(system('task '.b:rc.' '.b:filter.' '.b:command), '\n'))
silent global/^[\t ]*$/delete
execute 'setlocal filetype=task_'.b:command
nnoremap <buffer> q :call taskwarrior#Bclose(bufnr('%'))<CR>
call setpos('.', pos)
return
endif
let b:hist = get(b:, 'hist', 1)
call taskwarrior#log#history('write')
let rcc = matchstr(b:rc, 'rc\.report\.'.b:command.'\.columns.\zs\S*')
let rcl = matchstr(b:rc, 'rc\.report\.'.b:command.'\.labels.\zs\S*')
" let b:task_report_columns = rcc == '' ? split(system("task _get -- rc.report.".b:command.".columns")[0:-2], ',') : split(rcc, ',')
" let b:task_report_labels = rcl == '' ? split(system("task _get -- rc.report.".b:command.".labels")[0:-2], ',') : split(rcl, ',')
let b:task_report_columns = rcc == '' ? split(matchstr(system("task show |grep report.".b:command.".columns")[0:-2], '\S*$'), ',') : split(rcc, ',')
let b:task_report_labels = rcl == '' ? split(matchstr(system("task show |grep report.".b:command.".labels")[0:-2], '\S*$'), ',') : split(rcl, ',')
let line1 = join(b:task_report_labels, ' ')
let context = split(substitute(
\ system('task '.b:rc.' '.b:filter.' '.b:command),
\ '\[[0-9;]\+m',
\ '', 'g'),
\ '\n')
let split_lineno = match(context, '^[ -]\+$')
if split_lineno == -1
call append(0, line1)
else
let end = len(context)-match(reverse(copy(context)), '^$')
call append(0, context[split_lineno-1:end-1])
silent global/^[\t ]*$/delete
silent global/^[ -]\+$/delete
endif
call filter(b:task_report_columns, "index(split(getline(1), ' '), b:task_report_labels[v:key]) != -1")
call filter(b:task_report_labels, "index(split(getline(1), ' '), v:val) != -1")
let b:task_columns = []
let ci = 0
1
while ci != -1
let b:task_columns += [ci]
let ci = search('\s\S', 'W', 1)
let ci = ci > 0 ? virtcol('.') : -1
endwhile
let b:task_columns += [999]
let b:summary = taskwarrior#data#global_stats()
let b:sort = taskwarrior#sort#order_list()[0]
let a_tasks = split(system('task active limit:1 rc.verbose:nothing
\ rc.report.active.sort=start-
\ rc.report.active.columns=start.active,start.age,id,description.desc
\ rc.report.active.labels=A,Age,ID,Description'), '\n')
let b:now = len(a_tasks) > 0 ? a_tasks[-1] : ''
let b:active = split(system('task start.any: count'), '\n')[0]
let b:selected = []
let b:sline = []
let b:sstring = ''
let con = split(system('task context show'), '\n')[0]
let b:context = con =~ 'No context' ? 'none' :
\ matchstr(con, 'Context .\zs\S*\ze. ')
setlocal filetype=taskreport
if exists('b:ct')
for l in range(line('$'))
if taskwarrior#data#get_uuid(l) == b:ct
let pos[1] = l
break
endif
endfor
endif
call setpos('.', pos)
endfunction
function! taskwarrior#buffer_var_init()
let b:command = get(b:, 'command', g:task_report_name)
let b:filter = get(b:, 'filter', '')
let b:type = get(b:, 'type', 'report')
let b:rc = get(b:, 'rc', g:task_rc_override)
endfunction
function! taskwarrior#init(...)
if exists(':TagbarClose')
TagbarClose
endif
let argstring = join(a:000, ' ')
let [command, filter, type] = taskwarrior#command_type(argstring)
let rc = g:task_rc_override
if type == 'interactive'
if !g:task_readonly
execute '!task '.argstring
call taskwarrior#refresh()
endif
return
endif
execute 'edit task\ '.command.'\ '.type
if exists('g:task_view')
let g:task_view += [bufnr('%')]
else
let g:task_view = [bufnr('%')]
endif
setlocal noswapfile
call taskwarrior#list(command, filter, type, rc)
endfunction
function! taskwarrior#refresh()
if exists('g:task_view')
for bufn in g:task_view
execute bufn.'buffer'
call taskwarrior#list()
endfor
else
call taskwarrior#init()
endif
endfunction
function! taskwarrior#Bclose(buffer)
if a:buffer =~ '^\d\+$'
let btarget = bufnr(str2nr(a:buffer))
else
let btarget = bufnr(a:buffer)
endif
if bufname(btarget) == ''
bdelete
return
endif
" Numbers of windows that view target buffer which we will delete.
let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) == btarget')
let wcurrent = winnr()
for w in wnums
execute w.'wincmd w'
let prevbuf = bufnr('#')
if prevbuf > 0 && buflisted(prevbuf) && prevbuf != w
buffer #
else
bprevious
endif
if btarget == bufnr('%')
" Numbers of listed buffers which are not the target to be deleted.
let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget')
" Listed, not target, and not displayed.
let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0')
" Take the first buffer, if any (could be more intelligent).
let bjump = (bhidden + blisted + [-1])[0]
if bjump > 0
execute 'buffer '.bjump
else
enew
endif
endif
endfor
execute 'silent! bdelete '.btarget
execute wcurrent.'wincmd w'
endfunction
function! taskwarrior#hi_field()
silent! syntax clear taskwarrior_field
let index = taskwarrior#data#current_index()
execute 'syntax match taskwarrior_field /\%>1l\%'.line('.').'l\%'.(b:task_columns[index]+1).'v.*\%<'.(b:task_columns[index+1]+1).'v/'
endfunction
function! taskwarrior#quit()
call taskwarrior#Bclose(bufnr('%'))
call remove(g:task_view, index(g:task_view, bufnr('%')))
endfunction
function! taskwarrior#quit_all()
for bufn in g:task_view
call taskwarrior#Bclose(bufn)
endfor
let g:task_view = []
endfunction
function! taskwarrior#system_call(filter, command, args, mode)
if a:mode == 'silent'
call system('task '.a:filter.' '.a:command.' '.a:args)
elseif a:mode == 'echo'
echo "\n----------------\n"
echo system('task '.a:filter.' '.a:command.' '.a:args)
else
execute '!task '.a:filter.' '.a:command.' '.a:args
endif
call taskwarrior#refresh()
endfunction
function! taskwarrior#command_type(string)
for sub in split(a:string, ' ')
if index(g:task_report_command, sub) != -1
return [ sub, substitute(' '.a:string, ' '.sub, '', ''), 'report' ]
elseif index(g:task_interactive_command, sub) != -1
return [ sub, substitute(' '.a:string, ' '.sub, '', ''), 'interactive' ]
elseif index(g:task_all_commands, sub) != -1
return [ sub, substitute(' '.a:string, ' '.sub, '', ''), 'special' ]
endif
endfor
return [ g:task_report_name, a:string, 'report' ]
endfunction

View File

@ -0,0 +1,370 @@
function! taskwarrior#action#new()
call taskwarrior#system_call('', 'add', taskwarrior#data#get_args('add'), 'echo')
endfunction
function! taskwarrior#action#set_done()
call taskwarrior#system_call(taskwarrior#data#get_uuid(), ' done', '', 'silent')
endfunction
function! taskwarrior#action#urgency() abort
let cc = taskwarrior#data#current_column()
let udas = split(system('task _udas'), '\n')
let cmap = { 'start' : 'active',
\ 'entry' : 'age',
\ 'depends' : 'blocked',
\ 'parent' : 'blocking',
\ 'wait' : 'waiting',
\ 'description' : 'annotations'
\ }
let isuda = 0
if has_key(cmap, cc)
let cc = cmap[cc]
elseif index(['due', 'priority', 'project', 'tags', 'scheduled']
\ , cc) == -1
if index(udas, cc) == -1
call taskwarrior#sort#by_arg('urgency-')
return
else
let isuda = 1
endif
endif
let rcfile = $HOME.'/.taskrc'
if filereadable(rcfile)
let cv = taskwarrior#data#get_value_by_column(line('.'), cc)
let option = isuda ? 'urgency.uda.'.cc.'.coefficient' :
\ 'urgency.'.cc.'.coefficient'
if len(cv)
let ctag = expand('<cword>')
if cc == 'tags' && index(split(cv), ctag) != -1
let option = 'urgency.user.tag.'.ctag.'.coefficient'
elseif cc == 'project' && cv =~ '^[^ \t%\\*]\+$'
let pl = split(cv, '\.')
let idx = index(pl, expand('<cword>'))
let option = 'urgency.user.project.'.
\ join(pl[0:idx], '.').'.coefficient'
elseif isuda && cv =~ '^\w\+$'
let option = 'urgency.uda.'.cc.'.'.cv.'.coefficient'
endif
endif
let default_raw = split(system('task _get rc.'.option), '\n')
let default = len(default_raw) ? default_raw[0] : '0'
let new = input(option.' : ', default)
let lines = readfile(rcfile)
let index = match(lines, option)
if str2float(new) == str2float(default)
elseif str2float(new) == 0
call filter(lines, 'v:val !~ option')
elseif index == -1
call add(lines, option.'='.new)
else
let lines[index] = option.'='.new
endif
call writefile(lines, rcfile)
endif
call taskwarrior#sort#by_arg('urgency-')
execute 'normal! :\<Esc>'
endfunction
function! taskwarrior#action#modify(mode)
let uuid = taskwarrior#data#get_uuid()
if uuid == ''
return
endif
if a:mode == 'current'
let field = taskwarrior#data#current_column()
if index(['id', 'uuid', 'status', 'urgency'], field) != -1
return
elseif field == 'description'
call taskwarrior#system_call(uuid, 'modify', taskwarrior#data#get_args('modify', [field]), 'external')
else
call taskwarrior#system_call(uuid, 'modify', taskwarrior#data#get_args('modify', [field]), 'silent')
endif
else
call taskwarrior#system_call(uuid, 'modify', taskwarrior#data#get_args('modify'), 'external')
endif
endfunction
function! taskwarrior#action#delete()
let uuid = taskwarrior#data#get_uuid()
if uuid == ''
call taskwarrior#action#annotate('del')
else
let ccol = taskwarrior#data#current_column()
if index(['project', 'tags', 'due', 'priority', 'start', 'depends'], ccol) != -1
call taskwarrior#system_call(uuid, 'modify', ccol.':', 'silent')
else
execute '!task '.uuid.' delete'
endif
endif
call taskwarrior#refresh()
endfunction
function! taskwarrior#action#remove()
execute '!task '.taskwarrior#data#get_uuid().' delete'
call taskwarrior#list()
endfunction
function! taskwarrior#action#annotate(op)
let ln = line('.')
let offset = -1
while ln > 1 && taskwarrior#data#get_uuid(ln) == ''
let ln -= 1
let offset += 1
endwhile
let uuid = taskwarrior#data#get_uuid(ln)
if uuid == ''
return
endif
if a:op == 'add'
let annotation = input('new annotation:', '', 'file')
call taskwarrior#system_call(uuid, ' annotate ', annotation, 'silent')
elseif a:op == 'del'
let annotation = input('annotation pattern to delete:')
call taskwarrior#system_call(uuid, ' denotate ', annotation, 'silent')
elseif offset >= 0
let taskobj = taskwarrior#data#get_query(uuid)
if exists('taskobj.annotations[offset].description')
let file = substitute(taskobj.annotations[offset].description, '\s*\/\s*', '/', 'g')
let file = escape(file, ' ')
let ft = 'text'
if executable('file')
let ft = system('file '.file)[:-2]
endif
if ft =~ 'text$'
execute 'e '.file
elseif ft !~ '(No such file or directory)' || file =~ '[a-z]*:\/\/[^ >,;]*'
if executable('xdg-open')
call system('xdg-open '.file.'&')
elseif executable('open')
call system('open '.file.'&')
endif
endif
endif
endif
endfunction
function! taskwarrior#action#filter()
let column = taskwarrior#data#current_column()
if index(['project', 'tags', 'status', 'priority'], column) != -1 && line('.') > 1
let filter = substitute(substitute(taskwarrior#data#get_args('modify', [column]), 'tags:', '+', ''), '\v^\s*\+(\s|$)', '', '')
elseif column =~ '\v^(entry|end|due)$'
let filter = column.'.before:'.input(column.'.before:', taskwarrior#data#get_value_by_column('.', column))
elseif column == 'description'
let filter = 'description:'.input('description:', taskwarrior#data#get_value_by_column('.', column) )
else
let filter = input('new filter:', b:filter, 'customlist,taskwarrior#complete#filter')
endif
let filter = substitute(filter, 'status:\(\s\|$\)', 'status.any: ', 'g')
if filter != b:filter
let b:filter = filter
let b:hist = 1
call taskwarrior#list()
endif
endfunction
function! taskwarrior#action#command()
if len(b:selected) == 0
let filter = taskwarrior#data#get_uuid()
else
let filter = join(b:selected, ',')
endif
let command = input('task '.filter.':', '', 'customlist,taskwarrior#complete#command')
if index(g:task_all_commands, b:command) == -1
return
endif
call taskwarrior#system_call(filter, command, '', 'interactive')
endfunction
function! taskwarrior#action#report()
let command = input('new report:', g:task_report_name, 'customlist,taskwarrior#complete#report')
if index(g:task_report_command, command) != -1 && command != b:command
let b:command = command
let b:hist = 1
call taskwarrior#list()
endif
endfunction
function! taskwarrior#action#paste()
if len(b:selected) == 0
return
elseif len(b:selected) < 3
call taskwarrior#system_call(join(b:selected, ','), 'duplicate', '', 'echo')
else
call taskwarrior#system_call(join(b:selected, ','), 'duplicate', '', 'interactive')
endif
endfunction
function! taskwarrior#action#columns_format_change(direction)
let ccol = taskwarrior#data#current_column()
if !exists('g:task_columns_format[ccol]')
return
endif
let clist = g:task_columns_format[ccol]
if len(clist) == 1
return
endif
let ccol_ful = b:task_report_columns[taskwarrior#data#current_index()]
let ccol_sub = matchstr(ccol_ful, '\.\zs.*')
let rcl = matchstr(b:rc, 'rc\.report\.'.b:command.'\.columns.\zs\S*')
" let dfl = system('task _get -- rc.report.'.b:command.'.columns')[0:-2]
let dfl = matchstr(system('task show | grep report.'.b:command.'.columns')[0:-2], '\S*$')
let index = index(clist, ccol_sub)
let index = index == -1 ? 0 : index
if a:direction == 'left'
let index -= 1
else
let index += 1
if index == len(clist)
let index = 0
endif
endif
let newsub = index == 0 ? '' : '.'.clist[index]
let b:rc .= ' rc.report.'.b:command.'.columns:'.
\ substitute(
\ rcl == '' ? dfl : rcl,
\ '[=:,]\zs'.ccol_ful.'\ze\(,\|$\)',
\ ccol.newsub, ''
\ )
let b:hist = 1
call taskwarrior#list()
endfunction
function! taskwarrior#action#date(count)
let ccol = taskwarrior#data#current_column()
if index(['due', 'end', 'entry'], ccol) == -1
return
endif
setlocal modifiable
if exists('g:loaded_speeddating')
call speeddating#increment(a:count)
elseif a:count > 0
execute 'normal! '.a:count.''
else
execute 'normal! '.-a:count.''
endif
let b:ct = taskwarrior#data#get_uuid()
call taskwarrior#system_call(b:ct, 'modify', ccol.':'.taskwarrior#data#get_value_by_column('.', ccol, 'temp'), 'silent')
endfunction
function! taskwarrior#action#visual(action) range
let line1 = getpos("'<")[1]
let line2 = getpos("'>")[1]
let fil = []
let lin = []
for l in range(line1, line2)
let uuid = taskwarrior#data#get_uuid(l)
if uuid !~ '^\s*$'
let fil += [uuid]
let lin += [l]
endif
endfor
let filter = join(fil, ',')
if a:action == 'done'
call taskwarrior#system_call(filter, 'done', '', 'interactive')
elseif a:action == 'delete'
call taskwarrior#system_call(filter, 'delete', '', 'interactive')
elseif a:action == 'info'
call taskinfo#init('information', filter, split(system('task rc.color=no information '.filter), '\n'))
elseif a:action == 'select'
for var in fil
let index = index(b:selected, var)
if index == -1
let b:selected += [var]
let b:sline += [lin[index(fil, var)]]
else
call remove(b:selected, index)
call remove(b:sline, index)
endif
endfor
let b:sstring = join(b:selected, ' ')
setlocal syntax=taskreport
endif
endfunction
function! taskwarrior#action#move_cursor(direction, mode)
let ci = taskwarrior#data#current_index()
if ci == -1 || (ci == 0 && a:direction == 'left') || (ci == len(b:task_columns)-1 && a:direction == 'right')
return
endif
if a:direction == 'left'
call search('\%'.(b:task_columns[ci-1]+1).'v', 'be')
else
call search('\%'.(b:task_columns[ci+1]+1).'v', 'e')
endif
if a:mode == 'skip' && taskwarrior#data#get_value_by_index('.', taskwarrior#data#current_index()) =~ '^\s*$'
call taskwarrior#action#move_cursor(a:direction, 'skip')
endif
endfunction
function! taskwarrior#action#undo()
if has("gui_running")
if exists('g:task_gui_term') && g:task_gui_term == 1
!task rc.color=off undo
elseif executable('xterm')
silent !xterm -e 'task undo'
elseif executable('urxvt')
silent !urxvt -e task undo
elseif executable('gnome-terminal')
silent !gnome-terminal -e 'task undo'
endif
else
sil !clear
!task undo
endif
call taskwarrior#refresh()
endfunction
function! taskwarrior#action#clear_completed()
!task status:completed delete
call taskwarrior#refresh()
endfunction
function! taskwarrior#action#sync(action)
execute '!task '.a:action.' '
call taskwarrior#refresh()
endfunction
function! taskwarrior#action#select()
let uuid = taskwarrior#data#get_uuid()
if uuid == ''
return
endif
let index = index(b:selected, uuid)
if index == -1
let b:selected += [uuid]
let b:sline += [line('.')]
else
call remove(b:selected, index)
call remove(b:sline, index)
endif
let b:sstring = join(b:selected, ' ')
setlocal syntax=taskreport
endfunction
function! taskwarrior#action#show_info(...)
if a:0 > 0
let command = 'info'
let filter = a:1
else
let ccol = taskwarrior#data#current_column()
let dict = { 'project': 'projects',
\ 'tags': 'tags',
\ 'id': 'stats',
\ 'depends': 'blocking',
\ 'recur': 'recurring',
\ 'due': 'overdue',
\ 'wait': 'waiting',
\ 'urgency': 'ready',
\ 'entry': 'history.monthly',
\ 'end': 'history.monthly'}
let command = get(dict, ccol, 'summary')
let uuid = taskwarrior#data#get_uuid()
if uuid !~ '^\s*$'
let command = substitute(command, '\v(summary|stats)', 'information', '')
let filter = taskwarrior#data#get_uuid()
else
let filter = b:filter
endif
endif
call taskinfo#init(command, filter, split(system('task rc.color=no '.command.' '.filter), '\n'))
endfunction

View File

@ -0,0 +1,54 @@
function! taskwarrior#complete#TW(A, L, P)
let command = copy(g:task_all_commands)
let filter = copy(g:task_filter)
let config = copy(g:task_all_configurations)
let contexts = split(system('task _context'), '\n')
let context_cmd = ['define', 'show', 'list', 'delete']
let words = split(a:L, ' ')
if len(words) > 1 && words[1] == 'context'
if len(words) == 2 || index(context_cmd, words[2]) == -1
return filter(context_cmd + contexts + ['none'],
\ 'match(v:val, a:A) != -1')
elseif words[2] == 'delete'
return filter(contexts, 'match(v:val, a:A) != -1')
else
return []
endif
endif
for ph in words
if ph == 'config' || ph == 'show'
return filter(config, 'match(v:val, a:A) != -1')
elseif ph =~ '^rc\..*'
return map(filter(config, 'match(v:val, a:A[3:]) != -1'),
\ "'rc.'.v:val")
elseif index(command, ph) != -1
return filter(filter, 'match(v:val, a:A) != -1')
endif
endfor
return filter(command+filter, 'match(v:val, a:A) != -1')
endfunction
function! taskwarrior#complete#sort(A, L, P)
let cols = map(split(system('task _columns'), '\n'),
\ 'matchstr(v:val, "^\\w*")')
return filter(cols, 'match(v:val, a:A) != -1')
endfunction
function! taskwarrior#complete#filter(A, L, P)
let lead = matchstr(a:A, '\S*$')
let lead = lead == '' ? '.*' : lead
let dict = copy(g:task_filter)
for ph in split(a:L, ' ')
call remove(dict, index(dict, matchstr(ph, '.*:\ze')))
endfor
return map(filter(dict, 'match(v:val, lead) != -1'),
\ "matchstr(a:L, '.*\\ze\\s\\+\\S*').' '.v:val")
endfunction
function! taskwarrior#complete#command(A, L, P)
return filter(copy(g:task_all_commands), 'match(v:val, a:A) != -1')
endfunction
function! taskwarrior#complete#report(A, L, P)
return filter(copy(g:task_report_command), 'match(v:val, a:A) != -1')
endfunction

View File

@ -0,0 +1,132 @@
function! taskwarrior#data#get_uuid(...)
let line = a:0 == 0 ? '.' : a:1
let vol = taskwarrior#data#get_value_by_column(line, 'uuid')
let vol = vol =~ '[0-9a-f]\{8}\(-[0-9a-f]\{4}\)\{3}-[0-9a-f]\{12}' ?
\ vol : taskwarrior#data#get_value_by_column(line, 'id')
return vol =~ '^\s*-*\s*$' ? '' : vol
endfunction
function! taskwarrior#data#get_args(...)
if a:0 == 0
return
elseif a:0 == 1
return taskwarrior#data#get_args(a:1, g:task_default_prompt)
endif
let arg = ' '
for key in a:2
let default = a:1 == 'modify' ?
\ taskwarrior#data#get_value_by_column('.', key)
\ : ''
let temp = shellescape(input(key.":", default), 1)
if key == 'description'
let arg .= ' '.temp
elseif temp !~ '^[ \t]*$' || a:1 == 'modify'
let arg .= ' '.key.':'.temp
endif
endfor
echom arg
return arg
endfunction
function! taskwarrior#data#get_value_by_column(line, column, ...)
if a:line == 1 || (a:line == '.' && line('.') == 1)
return ''
endif
if a:column == 'id' || a:column == 'uuid' || exists('a:1')
let index = match(b:task_report_columns, '^'.a:column.'.*')
return taskwarrior#data#get_value_by_index(a:line, index(b:task_report_columns, a:column))
else
let dict = taskwarrior#data#get_query()
let val = get(dict, a:column, '')
if type(val) == type('')
return val
elseif type(val) == type([])
return join(val, ' ')
else
return string(val)
endif
endif
endfunction
function! taskwarrior#data#get_value_by_index(line, index)
if exists('b:task_columns[a:index]')
return substitute(getline(a:line)[b:task_columns[a:index]:b:task_columns[a:index+1]-1], '\(\s*$\|^\s*\)', '', 'g')
endif
return ''
endfunction
function! taskwarrior#data#current_index()
let i = 0
while i < len(b:task_columns) && virtcol('.') >= b:task_columns[i]
let i += 1
endwhile
return i-1
endfunction
function! taskwarrior#data#current_column()
return matchstr(b:task_report_columns[taskwarrior#data#current_index()], '^\w\+')
endfunction
function! taskwarrior#data#get_stats(method)
let dict = {}
if a:method != 'current'
let stat = split(system('task '.a:method.' stats'), '\n')
else
let uuid = taskwarrior#data#get_uuid()
let stat = split(system('task '.taskwarrior#data#get_uuid().' stats'), '\n')
if uuid == '' || len(stat) < 5
return {}
endif
endif
for line in stat[2:-1]
if line !~ '^\W*$'
let dict[split(line, '\s\s')[0]] = substitute(split(line, '\s\s')[-1], '^\s*', '', '')
endif
endfor
return dict
endfunction
function! taskwarrior#data#get_query(...)
let uuid = get(a:, 1, taskwarrior#data#get_uuid())
if uuid == ''
return {}
endif
let obj = webapi#json#decode(substitute(system(
\ 'task rc.verbose=off '.uuid.' export'),
\ '\nConfiguration.*', '', ''))
return type(obj) == 3 ? obj[0] : obj
endfunction
function! taskwarrior#data#global_stats()
let dict = taskwarrior#data#get_stats(b:filter)
return [
\ get(dict, 'Pending', 0),
\ get(dict, 'Completed', 0),
\ get(taskwarrior#data#get_stats(''), 'Pending', 0)
\ ]
endfunction
function! taskwarrior#data#category()
let dict = {}
let dict.Pending = []
let dict.Waiting = []
let dict.Recurring = []
let dict.Completed = []
for i in range(2, line('$'))
let uuid = taskwarrior#data#get_uuid(i)
if uuid == ''
continue
endif
let subdict = taskwarrior#data#get_stats(uuid)
if subdict.Pending == '1'
let dict.Pending += [i]
elseif subdict.Waiting == '1'
let dict.Waiting += [i]
elseif subdict.Recurring == '1'
let dict.Recurring += [i]
elseif subdict.Completed == '1'
let dict.Completed += [i]
endif
endfor
return dict
endfunction

View File

@ -0,0 +1,68 @@
if !isdirectory(expand(g:task_log_directory))
call mkdir(expand(g:task_log_directory), 'p')
endif
let s:history_file = expand(g:task_log_directory.'/.vim_tw.history')
let s:bookmark_file = expand(g:task_log_directory.'/.vim_tw.bookmark')
function! taskwarrior#log#history(action)
if findfile(s:history_file) == ''
call writefile([], s:history_file)
endif
if a:action == 'write' && filewritable(s:history_file) && b:hist == 1
let fl = readfile(s:history_file)
let numb = len(fl)
let last = numb ? substitute(fl[-1], '\v($|\n|\t|\s)', '', 'g') : ''
let current = join([b:command, b:filter, b:rc], ' ')
if last == substitute(current, '[\t ]', '', 'g')
return
endif
call add(fl, current)
if numb >= g:task_log_max
call remove(fl, 0)
endif
call writefile(fl, s:history_file)
elseif a:action == 'read' && filereadable(s:history_file)
call taskwarrior#init(join(split(readfile(s:history_file)[-1], ' '), ' '))
elseif a:action == 'clear'
call writefile([], s:history_file)
elseif a:action != 'write'
let hists = readfile(s:history_file)
if a:action == 'previous'
if b:hist >= len(hists)
return
endif
let b:hist += 1
elseif a:action == 'next'
if b:hist == 1
return
endif
let b:hist -= 1
endif
let hlist = split(substitute(hists[-b:hist], '\v($|\n)', ' ', ''), ' ')
if len(hlist) != 3
return
endif
let [b:command, b:filter, b:rc] = hlist
call taskwarrior#list()
endif
endfunction
function! taskwarrior#log#bookmark(action)
if findfile(s:bookmark_file) == ''
call writefile([], s:bookmark_file)
endif
if a:action == 'new' && filewritable(s:bookmark_file)
let now = b:command.' '.b:filter.' '.b:rc
let ext = readfile(s:bookmark_file)
if index(ext, now) == -1
execute 'redir >> '.s:bookmark_file
silent! echo now
redir END
echohl String
echomsg 'New bookmark added.'
echohl None
endif
elseif a:action == 'clear'
call writefile([], s:bookmark_file)
endif
endfunction

View File

@ -0,0 +1,88 @@
function! taskwarrior#sort#by_arg(...)
let args = substitute(join(a:000, ' '), '\s\+', ',', 'g')
let args = substitute(args, '\w\zs,', '-,', 'g')
let args = substitute(args, '\w\zs$', '-', '')
if args =~ '^\s*$'
let b:rc = substitute(b:rc, 'rc.report.'.b:command.'.sort[:=]\S*', '', 'g')
else
let b:rc .= args == '' ? '' : ' rc.report.'.b:command.'.sort:'.args
endif
let b:hist = 1
call taskwarrior#list()
endfunction
function! taskwarrior#sort#by_column(polarity, column)
let fromrc = matchstr(b:rc, 'rc\.report\.'.b:command.'\.sort.\zs\S*')
" let default = system('task _get -- rc.report.'.b:command.'.sort')[0:-2]
let default = matchstr(system('task show | grep report.'.b:command.'.sort')[0:-2], '\S*$')
let colshort = map(copy(b:task_report_columns), 'matchstr(v:val, "^\\w*")')
let ccol = index(colshort, a:column) == -1 ?
\ taskwarrior#data#current_column() :
\ a:column
let list = split(fromrc, ',')
let ind = index(split(fromrc, '[-+],\='), ccol)
let dlist = split(default, ',')
let dind = index(split(default, '[-+],\='), ccol)
if fromrc == ''
if dind != -1
if a:polarity == 'm'
if dind == 0
let dlist[0] = dlist[0][0:-2].(dlist[0][-1:-1] == '+' ? '-' : '+')
endif
call insert(dlist, remove(dlist, dind))
elseif dlist[dind] == ccol.a:polarity
return
else
let dlist[dind] = ccol.a:polarity
endif
let b:rc .= ' rc.report.'.b:command.'.sort:'.join(dlist, ',')
else
let polarity = a:polarity == 'm' ? '-' : a:polarity
let b:rc .= ' rc.report.'.b:command.'.sort:'.ccol.polarity.','.default
endif
elseif ind != -1
if a:polarity == 'm'
if ind == 0
let list[0] = list[0][0:-2].(list[0][-1:-1] == '+' ? '-' : '+')
else
call insert(list, remove(list, ind))
endif
elseif list[ind] == ccol.a:polarity
if a:polarity == '+'
call insert(list, remove(list, ind), ind > 1 ? ind-1 : 0)
else
if ind > len(list)-3
call add(list, remove(list, ind))
else
call insert(list, remove(list, ind), ind+1)
endif
endif
else
let list[ind] = ccol.a:polarity
endif
let g:listabc = list
let b:rc = substitute(b:rc, 'report\.'.b:command.'\.sort.'.fromrc, 'report.'.b:command.'.sort:'.join(list, ','), '')
else
let polarity = a:polarity == 'm' ? '-' : a:polarity
let b:rc = substitute(b:rc, 'report\.'.b:command.'\.sort.', 'report.'.b:command.'.sort:'.ccol.polarity.',', '')
endif
let b:hist = 1
call taskwarrior#list()
endfunction
function! taskwarrior#sort#order_list()
let fromrc = matchstr(b:rc, 'rc\.report\.'.b:command.'\.sort.\zs\S*')
if fromrc == ''
" let list = split(system('task _get -- rc.report.'.b:command.'.sort')[0:-2], ',')
let list = split(matchstr(system('task show | grep report.'.b:command.'.sort')[0:-2], '\S*$'), ',')
else
let list = split(fromrc, ',')
endif
while exists('list[0]') && match(b:task_report_columns, list[0][0:-2]) == -1 && system('task count '.list[0][0:-2].'.any:')[0] == '0'
call remove(list, 0)
endwhile
if len(list) == 0
let list = ['status-']
endif
return list
endfunction

View File

@ -0,0 +1,23 @@
let s:save_cpo = &cpo
set cpo&vim
function! unite#kinds#task#define()
return s:kind
endfunction
let s:kind = {
\ 'name' : 'task',
\ 'default_action' : 'show',
\ 'action_table': {},
\}
let s:kind.action_table.show = {
\ 'description' : 'Show report',
\ }
function! s:kind.action_table.show.func(candidate)
call taskwarrior#init(join(split(a:candidate.word, '[ \t]'), ' '))
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,68 @@
let s:save_cpo = &cpo
set cpo&vim
let s:template = {
\ 'name' : 'task/',
\ 'description' : 'vim-taskwarrior ',
\ 'filters' : ['matcher_regexp'],
\ 'action_table': {},
\ 'hooks' : {},
\ }
let s:bookmark = {
\ 'name' : 'bookmark',
\ 'logfile' : expand(g:task_log_directory.'/.vim_tw.bookmark')
\ }
let s:history = {
\ 'name' : 'history',
\ 'logfile' : expand(g:task_log_directory.'/.vim_tw.history')
\ }
function! s:make_source(dict)
let source = deepcopy(s:template)
let source.name .= a:dict.name
let source.description .= a:dict.name
let source.logfile = a:dict.logfile
function! source.hooks.on_syntax(args, context)
syntax match uniteSource__task_rc /rc.*/ contained containedin=ALL contains=uniteCandidateInputKeyword
syntax match uniteSource__task_report /\w\+\ze[ \t]\+/ contained containedin=ALL
highlight default link uniteSource__task_rc String
highlight default link uniteSource__task_report Keyword
endfunction
function! source.gather_candidates(args, context)
if findfile(self.logfile) == ''
call writefile([], self.logfile)
endif
return map(reverse(readfile(self.logfile)),
\ '{"word": v:val,
\ "kind": "task",
\ "source": "task/" . self.name,
\ }')
endfunction
let source.action_table.delete = {
\ 'description' : 'remove the item',
\ }
function! source.action_table.delete.func(candidate)
let current = substitute(a:candidate.word, '\s', '', 'g')
let lfile = g:task_log_directory.'/.vim_tw.bookmark'
let all = readfile(lfile)
let allns = map(copy(all), "substitute(v:val, '[ \t]', '', 'g')")
call remove(all, index(allns, current))
call writefile(all, lfile)
endfunction
return source
endfunction
function! unite#sources#task#define()
return map([s:bookmark, s:history], 's:make_source(v:val)')
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,135 @@
" json
" Last Change: 2012-03-08
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
" License: This file is placed in the public domain.
" Reference:
"
let s:save_cpo = &cpo
set cpo&vim
function! webapi#json#null()
return 0
endfunction
function! webapi#json#true()
return 1
endfunction
function! webapi#json#false()
return 0
endfunction
function! s:nr2byte(nr)
if a:nr < 0x80
return nr2char(a:nr)
elseif a:nr < 0x800
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
else
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
endif
endfunction
function! s:nr2enc_char(charcode)
if &encoding == 'utf-8'
return nr2char(a:charcode)
endif
let char = s:nr2byte(a:charcode)
if strlen(char) > 1
let char = strtrans(iconv(char, 'utf-8', &encoding))
endif
return char
endfunction
function! s:fixup(val, tmp)
if type(a:val) == 0
return a:val
elseif type(a:val) == 1
if a:val == a:tmp.'null'
return function('webapi#json#null')
elseif a:val == a:tmp.'true'
return function('webapi#json#true')
elseif a:val == a:tmp.'false'
return function('webapi#json#false')
endif
return a:val
elseif type(a:val) == 2
return a:val
elseif type(a:val) == 3
return map(a:val, 's:fixup(v:val, a:tmp)')
elseif type(a:val) == 4
return map(a:val, 's:fixup(v:val, a:tmp)')
else
return string(a:val)
endif
endfunction
function! webapi#json#decode(json)
let json = iconv(a:json, "utf-8", &encoding)
if get(g:, 'webapi#json#parse_strict', 1) == 1 && substitute(substitute(substitute(
\ json,
\ '\\\%(["\\/bfnrt]\|u[0-9a-fA-F]\{4}\)', '\@', 'g'),
\ '"[^\"\\\n\r]*\"\|true\|false\|null\|-\?\d\+'
\ . '\%(\.\d*\)\?\%([eE][+\-]\{-}\d\+\)\?', ']', 'g'),
\ '\%(^\|:\|,\)\%(\s*\[\)\+', '', 'g') !~ '^[\],:{} \t\n]*$'
throw json
endif
let json = substitute(json, '\n', '', 'g')
let json = substitute(json, '\\u34;', '\\"', 'g')
if v:version >= 703 && has('patch780')
let json = substitute(json, '\\u\(\x\x\x\x\)', '\=iconv(nr2char(str2nr(submatch(1), 16), 1), "utf-8", &encoding)', 'g')
else
let json = substitute(json, '\\u\(\x\x\x\x\)', '\=s:nr2enc_char("0x".submatch(1))', 'g')
endif
if get(g:, 'webapi#json#allow_nil', 0) != 0
let tmp = '__WEBAPI_JSON__'
while 1
if stridx(json, tmp) == -1
break
endif
let tmp .= '_'
endwhile
let [null,true,false] = [
\ tmp.'null',
\ tmp.'true',
\ tmp.'false']
sandbox let ret = eval(json)
call s:fixup(ret, tmp)
else
let [null,true,false] = [0,1,0]
sandbox let ret = eval(json)
endif
return ret
endfunction
function! webapi#json#encode(val)
if type(a:val) == 0
return a:val
elseif type(a:val) == 1
let json = '"' . escape(a:val, '\"') . '"'
let json = substitute(json, "\r", '\\r', 'g')
let json = substitute(json, "\n", '\\n', 'g')