" ============================================================================= " Filename: autoload/calendar/argument.vim " Author: itchyny " License: MIT License " Last Change: 2020/10/17 01:28:50. " ============================================================================= let s:save_cpo = &cpo set cpo&vim " Deal with argument for the :Calendar command. let s:calendars = filter(map(split(globpath(&rtp, 'autoload/calendar/day/**.vim'), '\n'), \ "substitute(v:val, '.*/\\|.vim', '', 'g')"), \ 'v:val !~# "^\(default\\|gregorian\\|julian\)$"') let s:all_value_options = { \ '-year': [], \ '-month': [], \ '-day': [], \ '-locale': [ 'default', 'en', 'ja' ], \ '-calendar': ['default', 'gregorian', 'julian'] + sort(s:calendars), \ '-calendar_candidates': [], \ '-first_day': [ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ], \ '-time_zone': map(range(-12, 12), 'printf("%+03d00", v:val)'), \ '-date_endian': [ 'little', 'big', 'middle' ], \ '-date_separator': [ '/', '-', '.', '" "' ], \ '-event_start_time_minwidth': [], \ '-cache_directory': [], \ '-updatetime': [], \ '-view': [ 'year', 'month', 'week', 'days', 'day', 'clock', 'event', 'agenda' ], \ '-frame': [ 'default', 'unicode', 'space', 'unicode_bold', 'unicode_round', 'unicode_double' ], \ '-position': [ 'here', 'below', 'tab', 'left', 'right', 'topleft', 'topright' ], \ '-split': [ 'horizontal', 'vertical' ], \ '-width': [], \ '-height': [], \ '-message_prefix': [], \ '-task_width': [], \ } let s:all_novalue_options = [ \ '-google_calendar', \ '-google_task', \ '-date_month_name', \ '-date_full_month_name', \ '-cyclic_view', \ '-task', \ '-event_start_time', \ '-skip_event_delete_confirm', \ '-skip_task_delete_confirm', \ '-skip_task_clear_completed_confirm', \ '-yank_deleting', \ '-task_delete', \ '-clock_12hour', \ '-week_number', \ '-debug' ] let s:value_options = deepcopy(s:all_value_options) let s:novalue_options = deepcopy(s:all_novalue_options) if has_key(g:, 'calendar_hide_options') && type(g:calendar_hide_options) == type([]) && len(g:calendar_hide_options) for s:k in g:calendar_hide_options if has_key(s:value_options, s:k) unlet s:value_options[s:k] elseif has_key(s:value_options, '-' . s:k) unlet s:value_options['-' . s:k] endif let s:i = index(s:novalue_options, s:k) if s:i >= 0 call remove(s:novalue_options, s:i) endif let s:i = index(s:novalue_options, '-' . s:k) if s:i >= 0 call remove(s:novalue_options, s:i) endif endfor unlet s:k s:i endif let s:options = copy(s:novalue_options) + map(keys(deepcopy(s:value_options)), 'v:val . "="') let s:all_options = copy(s:novalue_options) for [s:key, s:val] in items(deepcopy(s:value_options)) call extend(s:all_options, map(s:val, 's:key . "=" . v:val')) endfor unlet s:key s:val " Completion function. function! calendar#argument#complete(arglead, cmdline, cursorpos) abort try for key in keys(s:value_options) if a:cmdline =~# key if a:cmdline =~# key . '=$' return &wildmode =~# 'full' \ ? map(copy(s:value_options[key]), 'key . "=" . v:val') \ : copy(s:value_options[key]) elseif a:cmdline =~# key . '=\S\+$' let lead = '^' . substitute(a:cmdline, '.*=', '', '') let list = filter(copy(s:value_options[key]), 'v:val =~# lead') if !len(list) let lead = substitute(a:cmdline, '.*=', '', '') let list = filter(copy(s:value_options[key]), 'v:val =~# lead') endif let arglead = substitute(a:arglead, '=.*', '=', '') return map(list, 'arglead . v:val') endif endif endfor let s:options = copy(s:novalue_options) \ + map(keys(deepcopy(s:value_options)), &wildmode =~# 'full' ? 'v:val' : 'v:val . "="') let options = copy(s:options) if a:arglead != '' let options = sort(filter(copy(s:options), 'stridx(v:val, a:arglead) != -1')) if len(options) == 0 let arglead = substitute(a:arglead, '^-\+', '', '') let options = sort(filter(copy(s:options), 'stridx(v:val, arglead) != -1')) if len(options) == 0 try let argl = substitute(a:arglead, '\(.\)', '.*\1', 'g') . '.*' let options = sort(filter(copy(s:options), 'v:val =~? argl')) if len(options) == 0 let options = sort(filter(copy(s:all_options), 'stridx(v:val, arglead) != -1')) endif catch let options = copy(s:options) endtry endif endif endif return sort(filter(options, 'stridx(a:cmdline, v:val) == -1')) catch return s:options endtry endfunction " Splitting the argument. " This function deals with quotes. function! calendar#argument#split(args) abort let args = [''] let quoteflag = 0 let quote = '' for i in range(len(a:args)) if a:args[i] ==# ' ' if quoteflag let args[-1] .= a:args[i] elseif args[-1] !=# '' call add(args, '') endif elseif (a:args[i] ==# '"' || a:args[i] ==# "'") if quoteflag && quote ==# a:args[i] call add(args, '') let quoteflag = 0 let quote = '' elseif quoteflag let args[-1] .= a:args[i] else let quoteflag = 1 let quote = a:args[i] endif else let args[-1] .= a:args[i] endif endfor return filter(args, 'len(v:val)') endfunction " Option parsing and constructing the buffer-creating command. function! calendar#argument#parse(args) abort let args = calendar#argument#split(a:args) let isnewbuffer = bufname('%') != '' || &l:filetype != '' || &modified let name = " `='" . calendar#argument#buffername('calendar') . "'`" let command = 'tabnew' let commandprefix = '' let addname = 1 let ymd = [] let variables = {} let [width, height] = [-1, -1] let [arg_year, flg_year] = [0, 0] let [arg_month, flg_month] = [0, 0] let [arg_day, flg_day] = [0, 0] let flg_ymd = 0 for arg in args let novalue = 0 if arg !~# '=' && arg !~# '^\d\+$' if index(s:novalue_options, substitute(arg, '!$', '', '')) >= 0 let bang = arg =~# '!$' let arg = substitute(arg, '!$', '', '') . '=' . (!bang) let novalue = 1 else let pat = substitute(substitute(arg, '^-', '=', ''), '!$', '', '') . '$' let opts = filter(copy(s:all_options), 'v:val =~# pat') let bang = arg =~# '!$' ? '!' : '' if len(opts) == 1 let arg = opts[0] . bang elseif len(opts) > 1 call calendar#echo#error(calendar#message#get('multiple_argument') . ': ' . join(opts, ', ')) endif endif endif if arg =~# '=' let optvar = split(arg, '=') if len(optvar) == 2 && (has_key(s:value_options, optvar[0]) || novalue) let option = substitute(optvar[0], '^-\+', '', '') if option ==# 'position' if optvar[1] ==# 'here' let command = 'try | edit' . name . ' | catch | tabnew' . name . ' | endtry' let addname = 0 elseif optvar[1] ==# 'here!' let command = 'edit!' elseif optvar[1] ==# 'below' if command ==# 'tabnew' let command = 'new' endif let commandprefix = 'below ' let isnewbuffer = 1 elseif index(['left', 'right', 'topleft', 'topright'], optvar[1]) >= 0 if command ==# 'tabnew' let command = 'vnew' endif let commandprefix = optvar[1] ==# 'left' ? 'leftabove ' \ : optvar[1] ==# 'right' ? 'rightbelow ' \ : optvar[1] ==# 'topleft' ? 'topleft ' \ : optvar[1] ==# 'topright' ? 'botright ' \ : '' let isnewbuffer = 1 elseif optvar[1] ==# 'tab' let command = 'tabnew' let isnewbuffer = 1 endif elseif option ==# 'split' if optvar[1] ==# 'horizontal' let command = 'new' let isnewbuffer = 1 elseif optvar[1] ==# 'vertical' let command = 'vnew' let isnewbuffer = 1 endif elseif option ==# 'width' let width = optvar[1] + 0 elseif option ==# 'height' let height = optvar[1] + 0 elseif option ==# 'year' let [arg_year, flg_year, flg_ymd] = [optvar[1], 1, 1] elseif option ==# 'month' let [arg_month, flg_month, flg_ymd] = [optvar[1], 1, 1] elseif option ==# 'day' let [arg_day, flg_day, flg_ymd] = [optvar[1], 1, 1] endif let variables[option] = optvar[1] endif elseif arg =~# '^\d\+$' call add(ymd, arg) endif endfor if command ==# 'new' && height > 0 let command = height . ' ' . command elseif command ==# 'vnew' && width > 0 let command = width . ' ' . command endif let cmd1 = 'keepalt '. commandprefix . command . (addname ? name : '') let cmd2 = 'keepalt edit' . name let command = 'if isnewbuffer | ' . cmd1 . ' | else | ' . cmd2 . '| endif' if flg_ymd let ymd = [arg_year, arg_month, arg_day, flg_year, flg_month, flg_day] endif return [isnewbuffer, command, variables, ymd] endfunction " :Calendar [year month day] " The order is properly dealt with based on the endian setting. function! calendar#argument#day(day, default) abort let [y, m, d] = a:default let l = len(a:day) let endian = calendar#setting#get('date_endian') if l == 1 let day0 = a:day[0] * 1 if 0 < day0 && day0 < 13 let [m, d] = [day0, 1] else let [y, m, d] = [day0, 1, 1] endif elseif l == 2 let [day0, day1] = [a:day[0] * 1, a:day[1] * 1] if 0 < day0 && day0 < 13 && 0 < day1 && day1 < 32 && (endian ==# 'big' || endian ==# 'middle') let [m, d] = [day0, day1] elseif 0 < day0 && day0 < 32 && 0 < day1 && day1 < 13 && (endian ==# 'little') let [m, d] = [day1, day0] elseif 0 < day1 && day1 < 13 && endian ==# 'big' let [y, m, d] = [day0, day1, 1] elseif 0 < day0 && day0 < 13 && (endian ==# 'middle' || endian ==# 'little') let [y, m, d] = [day1, day0, 1] endif elseif l == 3 if endian ==# 'big' let [y, m, d] = [a:day[0] * 1, a:day[1] * 1, a:day[2] * 1] elseif endian ==# 'middle' let [m, d, y] = [a:day[0] * 1, a:day[1] * 1, a:day[2] * 1] else let [d, m, y] = [a:day[0] * 1, a:day[1] * 1, a:day[2] * 1] endif elseif l == 6 if a:day[3] | let y = a:day[0] | endif if a:day[4] | let m = a:day[1] | endif if a:day[5] | let d = a:day[2] | endif endif return calendar#day#new(y, m, d) endfunction " Decision of the buffer name. function! calendar#argument#buffername(name) abort let buflist = [] for i in range(tabpagenr('$')) call extend(buflist, tabpagebuflist(i + 1)) endfor let matcher = 'bufname(v:val) =~# ("\\[" . a:name . "\\( \\d\\+\\)\\?\\]") && index(buflist, v:val) >= 0' let substituter = 'substitute(bufname(v:val), ".*\\(\\d\\+\\).*", "\\1", "") + 0' let bufs = map(filter(range(1, bufnr('$')), matcher), substituter) let i = 0 while index(bufs, i) >= 0 let i += 1 endwhile return '[' . a:name . (len(bufs) && i ? ' ' . i : '') . ']' endfunction let &cpo = s:save_cpo unlet s:save_cpo