" ___vital___ " NOTE: lines between '" ___vital___' is generated by :Vitalize. " Do not modify the code nor insert new lines before '" ___vital___' function! s:_SID() abort return matchstr(expand(''), '\zs\d\+\ze__SID$') endfunction execute join(['function! vital#_openbrowser#Data#Optional#import() abort', printf("return map({'flat_map': '', 'has': '', 'flatten': '', 'some': '', 'apply': '', 'last': '', 'get_unsafe': '', 'new': '', 'is_optional': '', 'echo': '', 'exists': '', 'map': '', 'empty': '', 'get': '', 'first': '', 'unset': '', 'bind': '', 'none': '', 'get_or': '', 'set': '', 'optional': ''}, \"vital#_openbrowser#function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") delfunction s:_SID " ___vital___ let s:save_cpo = &cpo set cpo&vim " NOTE: These are verbose to avoid key's unintentional confliction ;( let s:SOME_KEY = 'vital_data_optional_some' | lockvar s:SOME_KEY let s:NONE_KEY = 'vital_data_optional_none' | lockvar s:NONE_KEY function! s:_require_optional(...) abort for x in a:000 if !s:is_optional(x) throw printf('vital: Data.Optional: Not an optional value `%s`', string(x)) endif unlet x endfor endfunction function! s:_require_optionals(xs) abort call call(function('s:_require_optional'), a:xs) endfunction function! s:none() abort let none = {} let none[s:NONE_KEY] = {} return none endfunction function! s:some(v) abort let some = {} let some[s:SOME_KEY] = a:v return some endfunction function! s:new(v, ...) abort return a:v == v:null || (a:0 > 0 && a:v == a:1) \ ? s:none() \ : s:some(a:v) endfunction function! s:is_optional(v) abort return s:empty(a:v) || s:exists(a:v) endfunction function! s:empty(o) abort return (type(a:o) is type({})) && has_key(a:o, s:NONE_KEY) endfunction function! s:exists(o) abort return (type(a:o) is type({})) && has_key(a:o, s:SOME_KEY) endfunction function! s:set(o, v) abort if s:empty(a:o) unlet a:o[s:NONE_KEY] endif let a:o[s:SOME_KEY] = a:v endfunction function! s:unset(o) abort if s:exists(a:o) unlet a:o[s:SOME_KEY] endif let a:o[s:NONE_KEY] = {} endfunction function! s:get(o) abort if s:empty(a:o) throw 'vital: Data.Optional: An empty Data.Optional value' endif return a:o[s:SOME_KEY] endfunction function! s:get_unsafe(o) abort return a:o[s:SOME_KEY] endfunction function! s:get_or(o, alt) abort return get(a:o, s:SOME_KEY, a:alt()) endfunction function! s:has(o, type) abort return !s:empty(a:o) && (type(a:o[s:SOME_KEY]) is a:type) endfunction function! s:apply(f, ...) abort call s:_require_optionals(a:000) let args = [] for x in a:000 if s:empty(x) return s:none() endif call add(args, s:get(x)) unlet x endfor return s:some(call(a:f, args)) endfunction function! s:map(x, f) abort if s:empty(a:x) return s:none() endif let naked_result = call(a:f, [s:get(a:x)]) return s:some(naked_result) endfunction function! s:bind(f, ...) abort call s:_require_optionals(a:000) let args = [] for x in a:000 if s:empty(x) return s:none() endif call add(args, s:get(x)) endfor return call(a:f, args) endfunction let s:FLATTEN_DEFAULT_LIMIT = 1 | lockvar s:FLATTEN_DEFAULT_LIMIT function! s:flatten(x, ...) abort let limit = get(a:000, 0, s:FLATTEN_DEFAULT_LIMIT) if limit is 0 return s:_flatten_fully(a:x) endif return s:_flatten_with_limit(a:x, limit) endfunction " Returns true for some({non optional}). " Otherwise, returns false. " (Returns false for none().) function! s:_has_a_nest(x) abort return s:exists(a:x) && !s:is_optional(s:get(a:x)) endfunction function! s:_flatten_with_limit(x, limit) abort if s:empty(a:x) || s:_has_a_nest(a:x) || (a:limit <= 0) return a:x endif return s:_flatten_with_limit(s:get(a:x), a:limit - 1) endfunction function! s:_flatten_fully(x) abort if s:empty(a:x) || s:_has_a_nest(a:x) return a:x endif return s:_flatten_fully(s:get(a:x)) endfunction function! s:flat_map(f, x) abort return s:bind(a:f, a:x) endfunction function! s:optional(x, f, g) abort return s:get_or(s:map(a:x, a:f), a:g) endfunction function! s:first(xs) abort for x in a:xs if s:exists(x) return x endif endfor return s:none() endfunction function! s:last(xs) abort return s:first(reverse(copy(a:xs))) endfunction function! s:_echo(x) abort if s:empty(a:x) echo 'None' return endif echo 'Some (' . s:get(a:x) . ')' endfunction function! s:echo(o, ...) abort call s:_require_optional(a:o) execute 'echohl' get(a:000, 0, 'None') call s:map(a:o, function('s:_echo')) echohl None endfunction let &cpo = s:save_cpo unlet s:save_cpo