├── .themisrc ├── LICENSE ├── README.md ├── autoload ├── opengoogletranslate.vim ├── opengoogletranslate.vimspec ├── opengoogletranslate │ └── command.vim ├── operator │ └── opengoogletranslate.vim ├── vital.vim └── vital │ ├── _opengoogletranslate.vim │ ├── _opengoogletranslate │ ├── ArgumentParser.vim │ ├── Data │ │ ├── Dict.vim │ │ └── List.vim │ ├── Prelude.vim │ ├── System │ │ └── Filepath.vim │ ├── Vim │ │ └── SelectedText.vim │ └── Web │ │ ├── URI.vim │ │ └── URI │ │ ├── HTTP.vim │ │ └── HTTPS.vim │ ├── opengoogletranslate.vim │ └── opengoogletranslate.vital ├── doc └── open-googletranslate.txt └── plugin ├── opengoogletranslate.vim └── operator └── opengoogletranslate.vim /.themisrc: -------------------------------------------------------------------------------- 1 | let g:root = fnamemodify(expand(''), ':h') 2 | let g:__vital_power_assert_config = { 3 | \ '__debug__': 1, 4 | \ '__pseudo_throw__': 0, 5 | \ '__max_length__': -1 6 | \ } 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 haya14busa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 16 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 17 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 20 | THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## vim-open-googletranslate 2 | 3 | vim-open-googletranslate provides utilities which helps you open Google Translate (https://translate.google.com/) from Vim. 4 | 5 | See [![:h open-googletranslate.txt](https://img.shields.io/badge/doc-%3Ah%20open--googletranslate.txt-red.svg)](doc/open-googletranslate.txt) 6 | 7 | ![vim-open-googletranslate demo](https://raw.githubusercontent.com/haya14busa/i/cd1e9f0386daf5d2a04e81f76ac86bb9f4d0af15/vim-open-googletranslate/anim.gif) 8 | 9 | 10 | If you find yourself opening too many tabs using vim-open-googletranslate, you 11 | might want to use electron-open-url](https://github.com/rhysd/electron-open-url) 12 | to reuse the same opened window. 13 | 14 | ```vim 15 | let g:opengoogletranslate#openbrowsercmd = 'electron-open --without-focus' 16 | ``` 17 | 18 | ![with electron-open-url](https://raw.githubusercontent.com/haya14busa/i/7fbb23a9570f8d0699e05d27e3375552d6505e6d/vim-open-googletranslate/with-electron-open-url.gif) 19 | 20 | If you were looking for more streamlined Google Translation integration with Vim, 21 | see https://github.com/haya14busa/vim-gtrans which uses Google Translation API internally. 22 | -------------------------------------------------------------------------------- /autoload/opengoogletranslate.vim: -------------------------------------------------------------------------------- 1 | let s:URI = vital#opengoogletranslate#import('Web.URI') 2 | 3 | let g:opengoogletranslate#default_lang = get(g:, 'opengoogletranslate#default_lang', '') 4 | let g:opengoogletranslate#openbrowsercmd = get(g:, 'opengoogletranslate#openbrowsercmd', '') 5 | 6 | " opengoogletranslate#open() opens Google Translate page. 7 | " 8 | " TODO: support removing comment prefix in given input? 9 | function! opengoogletranslate#open(...) abort 10 | let url = call('opengoogletranslate#url', a:000) 11 | let [cmd; args] = split(g:opengoogletranslate#openbrowsercmd, ' ', 1) 12 | if executable(cmd) ==# 1 13 | if !has('nvim') 14 | call job_start([cmd] + args + [url]) 15 | else 16 | silent! call system([cmd] + args + [url]) 17 | endif 18 | return 19 | endif 20 | try 21 | call openbrowser#open(url) 22 | catch /^Vim\%((\a\+)\)\=:E117/ 23 | call s:throw('open-broser.vim not found. Please install https://github.com/tyru/open-browser.vim') 24 | endtry 25 | endfunction 26 | 27 | " opengoogletranslate#url() returns URL of Google Translate. 28 | " target_lang and from_lang args can be empty string. 29 | function! opengoogletranslate#url(input, target_lang, from_lang) abort 30 | let to = a:target_lang 31 | if to ==# '' 32 | if g:opengoogletranslate#default_lang !=# '' 33 | let to = g:opengoogletranslate#default_lang 34 | else 35 | let to = s:infer_target_lang() 36 | endif 37 | endif 38 | return s:gtl_url(a:input, to, a:from_lang) 39 | endfunction 40 | 41 | " s:gtl_url() returns URL of Google Translate. from_lang arg can be empty and 42 | " will be converted to 'auto'. 43 | " 44 | " https://translate.google.com/#auto/{lang}/{input} 45 | " https://translate.google.com/#en/ja/input 46 | " e.g. https://translate.google.com/#auto/ja/input 47 | function! s:gtl_url(input, target_lang, from_lang) abort 48 | let from = a:from_lang ==# '' ? 'auto' : a:from_lang 49 | let i = s:URI.encode(a:input) 50 | return printf('https://translate.google.com/#%s/%s/%s', from, a:target_lang, i) 51 | endfunction 52 | 53 | function! s:infer_target_lang() abort 54 | return s:_infer_target_lang(v:lang) 55 | endfunction 56 | 57 | function! s:_infer_target_lang(lang) abort 58 | if a:lang ==# 'C' 59 | return 'en' 60 | elseif len(a:lang) < 2 61 | return 'en' 62 | else 63 | return a:lang[:1] 64 | endif 65 | endfunction 66 | 67 | function! s:throw(msg) abort 68 | throw printf('vim-open-googletranslate: %s', a:msg) 69 | endfunction 70 | -------------------------------------------------------------------------------- /autoload/opengoogletranslate.vimspec: -------------------------------------------------------------------------------- 1 | Describe opengoogletranslate 2 | Before all 3 | let file = g:root . '/autoload/opengoogletranslate.vim' 4 | let S = vital#vital#import('Vim.ScriptLocal').sfuncs(file) 5 | exe vital#vital#import('Vim.PowerAssert').define('PowerAssert') 6 | End 7 | 8 | Describe opengoogletranslate#url 9 | It ok 10 | let tests = [ 11 | \ { 12 | \ 'from': 'en', 13 | \ 'to': 'ja', 14 | \ 'input': 'input', 15 | \ 'want': 'https://translate.google.com/#en/ja/input', 16 | \ }, 17 | \ { 18 | \ 'from': '', 19 | \ 'to': 'ja', 20 | \ 'input': 'input', 21 | \ 'want': 'https://translate.google.com/#auto/ja/input', 22 | \ }, 23 | \ { 24 | \ 'from': '', 25 | \ 'to': '', 26 | \ 'input': 'input', 27 | \ 'want': printf('https://translate.google.com/#auto/%s/input', S.infer_target_lang()), 28 | \ }, 29 | \ { 30 | \ 'from': 'en', 31 | \ 'to': 'ja', 32 | \ 'input': "in put\n2nd", 33 | \ 'want': 'https://translate.google.com/#en/ja/in%20put%0A2nd', 34 | \ }, 35 | \ ] 36 | for tt in tests 37 | let [from, to, input] = [tt.from, tt.to, tt.input] 38 | PowerAssert opengoogletranslate#url(input, to, from) ==# tt.want 39 | endfor 40 | End 41 | End 42 | 43 | 44 | Describe s:gtl_url 45 | It ok 46 | let tests = [ 47 | \ { 48 | \ 'from': 'en', 49 | \ 'to': 'ja', 50 | \ 'input': 'input', 51 | \ 'want': 'https://translate.google.com/#en/ja/input', 52 | \ }, 53 | \ { 54 | \ 'from': '', 55 | \ 'to': 'ja', 56 | \ 'input': 'input', 57 | \ 'want': 'https://translate.google.com/#auto/ja/input', 58 | \ }, 59 | \ ] 60 | let l:S_gtl_url = S.gtl_url 61 | for tt in tests 62 | let [from, to, input] = [tt.from, tt.to, tt.input] 63 | PowerAssert S_gtl_url(input, to, from) ==# tt.want 64 | endfor 65 | End 66 | End 67 | 68 | Describe s:_infer_target_lang 69 | It ok 70 | let tests = [ 71 | \ {'in': 'C', 'want': 'en'}, 72 | \ {'in': 'x', 'want': 'en'}, 73 | \ {'in': 'en_US.utf8', 'want': 'en'}, 74 | \ {'in': 'ja_JP.UTF-8', 'want': 'ja'}, 75 | \ ] 76 | let l:S_infer_target_lang = S._infer_target_lang 77 | for tt in tests 78 | let [in, want] = [tt.in, tt.want] 79 | PowerAssert l:S_infer_target_lang(in) ==# want 80 | endfor 81 | End 82 | End 83 | End 84 | -------------------------------------------------------------------------------- /autoload/opengoogletranslate/command.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " FILE: autoload/command/opengoogletranslate.vim 3 | " AUTHOR: haya14busa 4 | " License: MIT license 5 | "============================================================================= 6 | scriptencoding utf-8 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | let s:ArgumentParser = vital#opengoogletranslate#import('ArgumentParser') 11 | 12 | function! s:get_parser() abort 13 | let s:parser = s:ArgumentParser.new({ 14 | \ 'name': 'OpenGoogleTranslate', 15 | \ 'description': 'open Google Translate in browser', 16 | \ }) 17 | call s:parser.add_argument( 18 | \ '--to', '-t', 'language translate to (e.g. en, ja, etc...)', { 19 | \ 'type': s:ArgumentParser.types.value, 20 | \ } 21 | \ ) 22 | call s:parser.add_argument( 23 | \ '--from', '-f', 'language translate from (e.g. en, ja, etc...)', { 24 | \ 'type': s:ArgumentParser.types.value, 25 | \ } 26 | \ ) 27 | return s:parser 28 | endfunction 29 | 30 | function! s:parse(...) abort 31 | let parser = s:get_parser() 32 | return call(parser.parse, a:000, parser) 33 | endfunction 34 | 35 | function! opengoogletranslate#command#command(...) abort 36 | let options = call('s:parse', a:000) 37 | if empty(options) 38 | return 39 | endif 40 | let to = get(options, 'to', '') 41 | let from = get(options, 'from', '') 42 | let input = join(options.__unknown__, ' ') 43 | if input ==# '' 44 | let [start, end] = [options.__range__[0], options.__range__[1]] 45 | let input = join(getline(start, end), "\n") 46 | endif 47 | call opengoogletranslate#open(input, to, from) 48 | endfunction 49 | 50 | function! opengoogletranslate#command#complete(...) abort 51 | let parser = s:get_parser() 52 | return call(parser.complete, a:000, parser) 53 | endfunction 54 | 55 | let &cpo = s:save_cpo 56 | unlet s:save_cpo 57 | " __END__ 58 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 59 | -------------------------------------------------------------------------------- /autoload/operator/opengoogletranslate.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " FILE: autoload/operator/opengoogletranslate.vim 3 | " AUTHOR: haya14busa 4 | " License: MIT license 5 | "============================================================================= 6 | scriptencoding utf-8 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | let s:SelectedText = vital#opengoogletranslate#import('Vim.SelectedText') 11 | 12 | let s:INT = { 'MAX': 2147483647 } 13 | 14 | " operator#opengoogletranslate#do() open Google Translate with selected text. 15 | " 16 | " @param {'char'|'line'|'block'} wise 17 | function! operator#opengoogletranslate#do(wise) abort 18 | let [begin, end] = [getpos("'["), getpos("']")] 19 | if a:wise ==# 'block' 20 | normal! gv 21 | let curswant = winsaveview().curswant 22 | if curswant ==# s:INT.MAX 23 | if begin[2] > end[2] 24 | let begin[2] = s:INT.MAX 25 | else 26 | let end[2] = s:INT.MAX 27 | endif 28 | endif 29 | execute 'normal!' "\" 30 | endif 31 | let input = s:SelectedText.text(a:wise, begin, end) 32 | call opengoogletranslate#open(input, '', '') 33 | endfunction 34 | 35 | let &cpo = s:save_cpo 36 | unlet s:save_cpo 37 | " __END__ 38 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 39 | -------------------------------------------------------------------------------- /autoload/vital.vim: -------------------------------------------------------------------------------- 1 | function! vital#of(name) abort 2 | let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital', 1) 3 | let file = split(files, "\n") 4 | if empty(file) 5 | throw 'vital: version file not found: ' . a:name 6 | endif 7 | let ver = readfile(file[0], 'b') 8 | if empty(ver) 9 | throw 'vital: invalid version file: ' . a:name 10 | endif 11 | return vital#_{substitute(ver[0], '\W', '', 'g')}#new() 12 | endfunction 13 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate.vim: -------------------------------------------------------------------------------- 1 | let s:_plugin_name = expand(':t:r') 2 | 3 | function! vital#{s:_plugin_name}#new() abort 4 | return vital#{s:_plugin_name[1:]}#new() 5 | endfunction 6 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/ArgumentParser.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#ArgumentParser#import() abort 6 | return map({'_vital_depends': '', 'complete_choices': '', 'splitargs': '', '_vital_created': '', 'complete_files': '', 'complete_dummy': '', 'new_argument': '', 'strip_quotes': '', 'new': '', '_vital_loaded': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#ArgumentParser#import() abort', printf("return map({'_vital_depends': '', 'complete_choices': '', 'splitargs': '', '_vital_created': '', 'complete_files': '', 'complete_dummy': '', 'new_argument': '', 'strip_quotes': '', 'new': '', '_vital_loaded': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | let s:save_cpo = &cpo 17 | set cpo&vim 18 | 19 | function! s:_vital_loaded(V) abort 20 | let s:Prelude = a:V.import('Prelude') 21 | let s:Dict = a:V.import('Data.Dict') 22 | let s:List = a:V.import('Data.List') 23 | let s:Path = a:V.import('System.Filepath') 24 | endfunction 25 | 26 | function! s:_vital_created(module) abort 27 | if !exists('s:const') 28 | let s:const = {} 29 | let s:const.types = {} 30 | let s:const.types.any = 'ANY' 31 | let s:const.types.value = 'VALUE' 32 | let s:const.types.switch = 'SWITCH' 33 | let s:const.types.choice = 'CHOICE' 34 | let s:const.types.multiple = 'MULTIPLE' 35 | lockvar s:const 36 | endif 37 | call extend(a:module, s:const) 38 | endfunction 39 | 40 | function! s:_vital_depends() abort 41 | return ['Prelude', 'Data.Dict', 'Data.List', 'System.Filepath'] 42 | endfunction 43 | 44 | function! s:_dummy() abort 45 | endfunction 46 | 47 | function! s:_throw(msg) abort 48 | throw printf('vital: ArgumentParser: %s', a:msg) 49 | endfunction 50 | 51 | function! s:_ensure_list(x) abort 52 | return s:Prelude.is_list(a:x) ? a:x : [a:x] 53 | endfunction 54 | 55 | " Public functions 56 | function! s:splitargs(str) abort 57 | let single_quote = '''\zs[^'']\+\ze''' 58 | let double_quote = '"\zs[^"]\+\ze"' 59 | let bare_strings = '\%(\\\s\|[^ \t''"]\)\+' 60 | let atoms = [single_quote, double_quote, bare_strings] 61 | let pattern = '\%(' . join(atoms, '\|') . '\)' 62 | return split(a:str, pattern . '*\zs\%(\s\+\|$\)\ze') 63 | endfunction 64 | 65 | function! s:strip_quotes(str) abort 66 | return a:str =~# '^\%(".*"\|''.*''\)$' ? a:str[1:-2] : a:str 67 | endfunction 68 | 69 | function! s:new(...) abort 70 | let settings = extend({ 71 | \ 'name': '', 72 | \ 'description': '', 73 | \ 'auto_help': 1, 74 | \ 'validate_required': 1, 75 | \ 'validate_types': 1, 76 | \ 'validate_conflicts': 1, 77 | \ 'validate_superordinates': 1, 78 | \ 'validate_dependencies': 1, 79 | \ 'validate_pattern': 1, 80 | \ 'enable_positional_assign': 0, 81 | \ 'complete_unknown': function('s:complete_dummy'), 82 | \ 'unknown_description': '', 83 | \ 'complete_threshold': 0, 84 | \}, get(a:000, 0, {})) 85 | " validate unknown options 86 | let available_settings = [ 87 | \ 'name', 88 | \ 'description', 89 | \ 'auto_help', 90 | \ 'validate_required', 91 | \ 'validate_types', 92 | \ 'validate_conflicts', 93 | \ 'validate_superordinates', 94 | \ 'validate_dependencies', 95 | \ 'validate_pattern', 96 | \ 'enable_positional_assign', 97 | \ 'complete_unknown', 98 | \ 'unknown_description', 99 | \ 'complete_threshold', 100 | \] 101 | for key in keys(settings) 102 | if key !~# '^__\w' && index(available_settings, key) == -1 103 | call s:_throw(printf( 104 | \ 'Unknown setting "%s" is specified', key, 105 | \)) 106 | endif 107 | endfor 108 | let parser = extend(deepcopy(s:parser), s:Dict.pick(settings, [ 109 | \ 'name', 110 | \ 'auto_help', 111 | \ 'complete_unknown', 112 | \ 'validate_required', 113 | \ 'validate_types', 114 | \ 'validate_conflicts', 115 | \ 'validate_superordinates', 116 | \ 'validate_dependencies', 117 | \ 'validate_pattern', 118 | \ 'enable_positional_assign', 119 | \ 'unknown_description', 120 | \ 'complete_threshold', 121 | \])) 122 | let parser.description = s:Prelude.is_list(settings.description) 123 | \ ? join(settings.description, "\n") 124 | \ : settings.description 125 | if parser.auto_help 126 | call parser.add_argument( 127 | \ '--help', '-h', 'show this help', 128 | \) 129 | endif 130 | return parser 131 | endfunction 132 | 133 | " @vimlint(EVL104, 1, l:options) 134 | " @vimlint(EVL104, 1, l:description) 135 | " @vimlint(EVL104, 1, l:alias) 136 | function! s:new_argument(name, ...) abort 137 | " determind name 138 | if a:name =~# '^--\?' 139 | let positional = 0 140 | let name = substitute(a:name, '^--\?', '', '') 141 | else 142 | let positional = 1 143 | let name = a:name 144 | endif 145 | " determind arguments 146 | if a:0 == 0 " add_argument({name}) 147 | let alias = '' 148 | let description = '' 149 | let options = {} 150 | elseif a:0 == 1 151 | " add_argument({name}, {description}) 152 | " add_argument({name}, {options}) 153 | if s:Prelude.is_string(a:1) || s:Prelude.is_list(a:1) 154 | let alias = '' 155 | let description = a:1 156 | let options = {} 157 | else 158 | let alias = '' 159 | let description = '' 160 | let options = a:1 161 | endif 162 | elseif a:0 == 2 163 | " add_argument({name}, {alias}, {description}) 164 | " add_argument({name}, {description}, {options}) 165 | if s:Prelude.is_string(a:2) || s:Prelude.is_list(a:2) 166 | let alias = a:1 167 | let description = a:2 168 | let options = {} 169 | elseif s:Prelude.is_dict(a:2) 170 | let alias = '' 171 | let description = a:1 172 | let options = a:2 173 | endif 174 | elseif a:0 == 3 175 | " add_argument({name}, {alias}, {description}, {options}) 176 | let alias = a:1 177 | let description = a:2 178 | let options = a:3 179 | else 180 | call s:_throw('Too many arguments are specified') 181 | endif 182 | " validate unknown options 183 | let available_options = [ 184 | \ 'alias', 185 | \ 'description', 186 | \ 'terminal', 187 | \ 'required', 188 | \ 'default', 189 | \ 'on_default', 190 | \ 'type', 191 | \ 'deniable', 192 | \ 'choices', 193 | \ 'pattern', 194 | \ 'complete', 195 | \ 'conflicts', 196 | \ 'dependencies', 197 | \ 'superordinates', 198 | \] 199 | for key in keys(options) 200 | if key !~# '^__\w' && index(available_options, key) == -1 201 | call s:_throw(printf( 202 | \ 'Unknown option "%s" is specified', key, 203 | \)) 204 | endif 205 | endfor 206 | " create an argument instance 207 | let argument = extend(deepcopy(s:argument), extend({ 208 | \ 'name': name, 209 | \ 'description': s:_ensure_list(description), 210 | \ 'positional': positional, 211 | \ 'alias': substitute(alias, '^-', '', ''), 212 | \ 'complete': function('s:_dummy'), 213 | \}, options)) 214 | " automatically assign argument type 215 | if argument.type == -1 216 | if !empty(argument.choices) 217 | let argument.type = s:const.types.choice 218 | elseif !empty(argument.pattern) 219 | let argument.type = s:const.types.value 220 | elseif argument.complete != function('s:_dummy') 221 | let argument.type = s:const.types.value 222 | elseif argument.positional 223 | let argument.type = s:const.types.value 224 | else 225 | let argument.type = s:const.types.switch 226 | endif 227 | endif 228 | " automatically assign complete function 229 | if argument.complete == function('s:_dummy') 230 | if argument.type == s:const.types.choice 231 | let argument.complete = function('s:complete_choices') 232 | else 233 | let argument.complete = function('s:complete_dummy') 234 | endif 235 | endif 236 | " validate options 237 | if positional 238 | if !empty(argument.alias) 239 | call s:_throw( 240 | \ '"alias" option cannot be specified to a positional argument' 241 | \) 242 | elseif !empty(argument.default) 243 | call s:_throw( 244 | \ '"default" option cannot be specified to a positional argument' 245 | \) 246 | elseif argument.type ==# s:const.types.any || argument.type ==# s:const.types.switch 247 | call s:_throw( 248 | \ '"type" option cannot be ANY or SWITCH for a positional argument' 249 | \) 250 | endif 251 | elseif !empty(argument.default) && argument.required 252 | call s:_throw( 253 | \ '"default" and "required" options cannot be specified together' 254 | \) 255 | elseif empty(argument.choices) && argument.type == s:const.types.choice 256 | call s:_throw( 257 | \ '"choices" option is required for CHOICE argument' 258 | \) 259 | elseif !empty(argument.pattern) && argument.type == s:const.types.switch 260 | call s:_throw( 261 | \ '"pattern" option cannot be specified for SWITCH argument' 262 | \) 263 | endif 264 | return argument 265 | endfunction 266 | 267 | function! s:complete_dummy(arglead, cmdline, cursorpos, ...) dict abort 268 | return [] 269 | endfunction 270 | 271 | function! s:complete_files(arglead, cmdline, cursorpos, ...) dict abort 272 | let root = expand(get(self, '__complete_files_root', '.')) 273 | let root = s:Path.realpath(s:Path.remove_last_separator(root) . s:Path.separator()) 274 | let candidates = split( 275 | \ glob(s:Path.join(root, a:arglead . '*'), 0), 276 | \ "\r\\?\n", 277 | \) 278 | " substitute 'root' 279 | call map(candidates, printf( 280 | \ 'substitute(v:val, ''^%s'', '''', '''')', 281 | \ escape(root, '\~.^$[]'), 282 | \)) 283 | " substitute /home/ to ~/ if ~/ is specified 284 | if a:arglead =~# '^\~' 285 | call map(candidates, 'fnameescape(v:val, '':~'')') 286 | endif 287 | call map(candidates, printf( 288 | \ 'isdirectory(v:val) ? v:val . ''%s'' : v:val', 289 | \ s:Path.path_separator(), 290 | \)) 291 | return candidates 292 | endfunction 293 | 294 | function! s:complete_choices(arglead, cmdline, cursorpos, ...) dict abort 295 | let options = get(a:000, 0, {}) 296 | if !has_key(self, 'get_choices') 297 | return [] 298 | endif 299 | let candidates = self.get_choices(options) 300 | return filter(copy(candidates), printf('v:val =~# ''^%s''', a:arglead)) 301 | endfunction 302 | 303 | " Instance 304 | let s:argument = { 305 | \ 'name': '', 306 | \ 'description': [], 307 | \ 'terminal': 0, 308 | \ 'positional': 0, 309 | \ 'required': 0, 310 | \ 'default': '', 311 | \ 'alias': '', 312 | \ 'type': -1, 313 | \ 'deniable': 0, 314 | \ 'choices': [], 315 | \ 'pattern': '', 316 | \ 'conflicts': [], 317 | \ 'dependencies': [], 318 | \ 'superordinates': [], 319 | \} 320 | function! s:argument.get_choices(options) abort 321 | if s:Prelude.is_funcref(self.choices) 322 | let candidates = self.choices(deepcopy(a:options)) 323 | elseif s:Prelude.is_list(self.choices) 324 | let candidates = self.choices 325 | else 326 | let candidates = [] 327 | endif 328 | return candidates 329 | endfunction 330 | 331 | let s:parser = { 332 | \ 'hooks': {}, 333 | \ 'arguments': {}, 334 | \ '_arguments': [], 335 | \ 'positional': [], 336 | \ 'required': [], 337 | \ 'alias': {}, 338 | \} 339 | function! s:parser.register_argument(argument) abort 340 | " Validate argument 341 | if has_key(self.arguments, a:argument.name) 342 | call s:_throw(printf( 343 | \ 'An argument "%s" is already registered', 344 | \ a:argument.name, 345 | \)) 346 | endif 347 | " register argument 348 | let self.arguments[a:argument.name] = a:argument 349 | call add(self._arguments, a:argument) 350 | " register positional 351 | if a:argument.positional 352 | call add(self.positional, a:argument.name) 353 | endif 354 | " register required 355 | if a:argument.required 356 | call add(self.required, a:argument.name) 357 | endif 358 | " register alias 359 | if !empty(a:argument.alias) 360 | let self.alias[a:argument.alias] = a:argument.name 361 | endif 362 | endfunction 363 | 364 | function! s:parser.unregister_argument(argument) abort 365 | " Validate argument 366 | if !has_key(self.arguments, a:argument.name) 367 | call s:_throw(printf( 368 | \ 'An argument "%s" has not been registered yet', 369 | \ a:argument.name, 370 | \)) 371 | endif 372 | " unregister argument 373 | unlet! self.arguments[a:argument.name] 374 | call remove(self._arguments, index(self._arguments, a:argument)) 375 | " unregister positional 376 | if a:argument.positional 377 | call remove(self.positional, index(self.positional, a:argument.name)) 378 | endif 379 | " unregister required 380 | if a:argument.required 381 | call remove(self.required, index(self.required, a:argument.name)) 382 | endif 383 | " unregister alias 384 | if !empty(a:argument.alias) 385 | unlet! self.alias[a:argument.alias] 386 | endif 387 | endfunction 388 | 389 | function! s:parser.add_argument(...) abort 390 | let argument = call('s:new_argument', a:000) 391 | call self.register_argument(argument) 392 | return argument 393 | endfunction 394 | 395 | function! s:parser.get_conflicted_arguments(name, options) abort 396 | let conflicts = self.arguments[a:name].conflicts 397 | if empty(conflicts) 398 | return [] 399 | endif 400 | return filter(keys(a:options), 'index(conflicts, v:val) >= 0') 401 | endfunction 402 | 403 | function! s:parser.get_superordinate_arguments(name, options) abort 404 | let superordinates = self.arguments[a:name].superordinates 405 | if empty(superordinates) 406 | return [] 407 | endif 408 | return filter(keys(a:options), 'index(superordinates, v:val) >= 0') 409 | endfunction 410 | 411 | function! s:parser.get_missing_dependencies(name, options) abort 412 | let dependencies = self.arguments[a:name].dependencies 413 | if empty(dependencies) 414 | return [] 415 | endif 416 | return filter(copy(dependencies), '!has_key(a:options, v:val)') 417 | endfunction 418 | 419 | function! s:parser.get_positional_arguments() abort 420 | return deepcopy(self.positional) 421 | endfunction 422 | 423 | function! s:parser.get_optional_arguments() abort 424 | return map(filter(values(self.arguments), '!v:val.positional'), 'v:val.name') 425 | endfunction 426 | 427 | function! s:parser.get_optional_argument_aliases() abort 428 | return keys(self.alias) 429 | endfunction 430 | 431 | function! s:parser.parse(bang, range, ...) abort 432 | let cmdline = get(a:000, 0, '') 433 | let args = s:Prelude.is_string(cmdline) ? s:splitargs(cmdline) : cmdline 434 | let options = self.parse_args(args, extend({ 435 | \ '__bang__': s:Prelude.is_string(a:bang) ? a:bang ==# '!' : a:bang, 436 | \ '__range__': a:range, 437 | \}, get(a:000, 1, {}))) 438 | call self._regulate_options(options) 439 | " to avoid exception in validation 440 | if self.auto_help && get(options, 'help', 0) 441 | redraw | echo self.help() 442 | return {} 443 | endif 444 | call self.hooks.pre_validate(options) 445 | try 446 | call self._validate_options(options) 447 | catch /vital: ArgumentParser:/ 448 | echohl WarningMsg 449 | redraw 450 | echo printf('%s validation error:', self.name) 451 | echohl None 452 | echo substitute(v:exception, '^vital: ArgumentParser: ', '', '') 453 | if self.auto_help 454 | echo printf("See a command usage by ':%s -h'", 455 | \ self.name, 456 | \) 457 | endif 458 | return {} 459 | endtry 460 | call self.hooks.post_validate(options) 461 | return options 462 | endfunction 463 | 464 | " @vimlint(EVL104, 1, l:name) 465 | " @vimlint(EVL101, 1, l:value) 466 | function! s:parser.parse_args(args, ...) abort 467 | let options = extend({ 468 | \ '__unknown__': [], 469 | \ '__args__': [], 470 | \}, get(a:000, 0, {})) 471 | let options.__args__ = extend(options.__args__, a:args) 472 | let length = len(options.__args__) 473 | let cursor = 0 474 | let arguments_pattern = printf('^\%%(%s\)$', join(keys(self.arguments), '\|')) 475 | let positional_length = len(self.positional) 476 | let positional_cursor = 0 477 | while cursor < length 478 | let cword = options.__args__[cursor] 479 | let nword = (cursor+1 < length) ? options.__args__[cursor+1] : '' 480 | if cword ==# '--' 481 | let cursor += 1 482 | let options.__terminated__ = 1 483 | break 484 | elseif cword =~# '^--\?' 485 | " optional argument 486 | let m = matchlist(cword, '^--\?\([^=]\+\|\)\%(=\(.*\)\|\)') 487 | let name = get(self.alias, m[1], m[1]) 488 | if name =~# arguments_pattern 489 | if !empty(m[2]) 490 | if self.arguments[name].type ==# s:const.types.multiple 491 | let options[name] = extend( 492 | \ get(options, name, []), 493 | \ [s:strip_quotes(m[2])], 494 | \) 495 | else 496 | let options[name] = s:strip_quotes(m[2]) 497 | endif 498 | elseif get(self, 'enable_positional_assign', 0) && !empty(nword) && nword !~# '^--\?' 499 | if self.arguments[name].type ==# s:const.types.multiple 500 | let options[name] = extend( 501 | \ get(options, name, []), 502 | \ [s:strip_quotes(nword)], 503 | \) 504 | else 505 | let options[name] = s:strip_quotes(nword) 506 | endif 507 | let cursor += 1 508 | else 509 | let options[name] = get(self.arguments[name], 'on_default', 1) 510 | endif 511 | elseif substitute(name, '^no-', '', '') =~# arguments_pattern 512 | let name = substitute(name, '^no-', '', '') 513 | if self.arguments[name].deniable 514 | let options[name] = 0 515 | else 516 | call add(options.__unknown__, cword) 517 | endif 518 | else 519 | call add(options.__unknown__, cword) 520 | endif 521 | else 522 | let name = '' 523 | while positional_cursor < positional_length 524 | let positional_cursor += 1 525 | let name = self.positional[positional_cursor - 1] 526 | if !empty(self.arguments[name].conflicts) && !empty(self.get_conflicted_arguments(name, options)) 527 | continue 528 | elseif !empty(self.arguments[name].superordinates) && empty(self.get_superordinate_arguments(name, options)) 529 | continue 530 | elseif !empty(self.arguments[name].dependencies) && !empty(self.get_missing_dependencies(name, options)) 531 | continue 532 | endif 533 | if self.arguments[name].type ==# s:const.types.multiple 534 | let options[name] = get(options, name, []) 535 | call add(options[name], s:strip_quotes(cword)) 536 | let positional_cursor -= 1 537 | else 538 | let options[name] = s:strip_quotes(cword) 539 | endif 540 | break 541 | endwhile 542 | if !has_key(options, name) 543 | let name = '' 544 | call add(options.__unknown__, cword) 545 | endif 546 | endif 547 | " terminal check 548 | if !empty(name) && get(self.arguments, name, { 'terminal': 0 }).terminal 549 | let cursor += 1 550 | let options.__terminated__ = 1 551 | break 552 | else 553 | let cursor += 1 554 | endif 555 | endwhile 556 | " assign remaining args as unknown 557 | let options.__unknown__ = extend( 558 | \ options.__unknown__, 559 | \ options.__args__[ cursor : ], 560 | \) 561 | return options 562 | endfunction " @vimlint(EVL104, 0, l:name) @vimlint(EVL101, 0, l:value) }}} 563 | 564 | function! s:parser._regulate_options(options) abort 565 | " assign default values 566 | let exists_pattern = printf('^\%%(%s\)$', join(keys(a:options), '\|')) 567 | for argument in values(self.arguments) 568 | if !empty(argument.default) && argument.name !~# exists_pattern 569 | let a:options[argument.name] = argument.default 570 | endif 571 | endfor 572 | endfunction 573 | 574 | function! s:parser._validate_options(options) abort 575 | if self.validate_required 576 | call self._validate_required(a:options) 577 | endif 578 | if self.validate_types 579 | call self._validate_types(a:options) 580 | endif 581 | if self.validate_conflicts 582 | call self._validate_conflicts(a:options) 583 | endif 584 | if self.validate_superordinates 585 | call self._validate_superordinates(a:options) 586 | endif 587 | if self.validate_dependencies 588 | call self._validate_dependencies(a:options) 589 | endif 590 | if self.validate_pattern 591 | call self._validate_pattern(a:options) 592 | endif 593 | endfunction 594 | 595 | function! s:parser._validate_required(options) abort 596 | let exist_required = keys(a:options) 597 | for name in self.required 598 | if index(exist_required, name) == -1 599 | call s:_throw(printf( 600 | \ 'Argument "%s" is required but not specified', 601 | \ name, 602 | \)) 603 | endif 604 | endfor 605 | endfunction 606 | 607 | function! s:parser._validate_types(options) abort 608 | for [name, value] in items(a:options) 609 | if name !~# '^__.*__$' 610 | let type = self.arguments[name].type 611 | if type == s:const.types.value && s:Prelude.is_number(value) 612 | call s:_throw(printf( 613 | \ 'Argument "%s" is VALUE argument but no value is specified', 614 | \ name, 615 | \)) 616 | elseif type == s:const.types.multiple && s:Prelude.is_number(value) 617 | call s:_throw(printf( 618 | \ 'Argument "%s" is MULTIPLE argument but no value is specified', 619 | \ name, 620 | \)) 621 | elseif type == s:const.types.switch && s:Prelude.is_string(value) 622 | call s:_throw(printf( 623 | \ 'Argument "%s" is SWITCH argument but "%s" is specified', 624 | \ name, value, 625 | \)) 626 | elseif type == s:const.types.choice 627 | let candidates = self.arguments[name].get_choices(a:options) 628 | let pattern = printf('^\%%(%s\)$', join(candidates, '\|')) 629 | if s:Prelude.is_number(value) 630 | call s:_throw(printf( 631 | \ 'Argument "%s" is CHOICE argument but no value is specified', 632 | \ name, 633 | \)) 634 | elseif value !~# pattern 635 | call s:_throw(printf( 636 | \ 'Argument "%s" is CHOICE argument but an invalid value "%s" is specified', 637 | \ name, value, 638 | \)) 639 | endif 640 | endif 641 | endif 642 | silent! unlet name 643 | silent! unlet value 644 | endfor 645 | endfunction 646 | 647 | function! s:parser._validate_conflicts(options) abort 648 | for [name, value] in items(a:options) 649 | if name !~# '^__.*__$' 650 | let conflicts = self.get_conflicted_arguments(name, a:options) 651 | if !empty(conflicts) 652 | call s:_throw(printf( 653 | \ 'Argument "%s" conflicts with an argument "%s"', 654 | \ name, conflicts[0], 655 | \)) 656 | endif 657 | endif 658 | silent! unlet name 659 | silent! unlet value 660 | endfor 661 | endfunction 662 | 663 | function! s:parser._validate_superordinates(options) abort 664 | for [name, value] in items(a:options) 665 | if name !~# '^__.*__$' 666 | let superordinates = self.get_superordinate_arguments(name, a:options) 667 | if !empty(self.arguments[name].superordinates) && empty(superordinates) 668 | call s:_throw(printf( 669 | \ 'No superordinate argument(s) of "%s" is specified', 670 | \ name, 671 | \)) 672 | endif 673 | endif 674 | silent! unlet name 675 | silent! unlet value 676 | endfor 677 | endfunction 678 | 679 | function! s:parser._validate_dependencies(options) abort 680 | for [name, value] in items(a:options) 681 | if name !~# '^__.*__$' 682 | let dependencies = self.get_missing_dependencies(name, a:options) 683 | if !empty(dependencies) 684 | call s:_throw(printf( 685 | \ 'Argument "%s" is required for an argument "%s" but missing', 686 | \ dependencies[0], name, 687 | \)) 688 | endif 689 | endif 690 | silent! unlet name 691 | silent! unlet value 692 | endfor 693 | endfunction 694 | 695 | function! s:parser._validate_pattern(options) abort 696 | for [name, value] in items(a:options) 697 | if name !~# '^__.*__$' 698 | let pattern = self.arguments[name].pattern 699 | if !empty(pattern) 700 | if s:Prelude.is_string(value) && value !~# pattern 701 | call s:_throw(printf( 702 | \ 'A value of argument "%s" does not follow a specified pattern "%s".', 703 | \ name, pattern, 704 | \)) 705 | elseif s:Prelude.is_list(value) 706 | for _value in value 707 | if _value !~# pattern 708 | call s:_throw(printf( 709 | \ 'One of value "%s" of argument "%s" does not follow a specified pattern "%s".', 710 | \ _value, name, pattern, 711 | \)) 712 | endif 713 | endfor 714 | endif 715 | endif 716 | endif 717 | silent! unlet name 718 | silent! unlet value 719 | endfor 720 | endfunction 721 | 722 | function! s:parser.complete(arglead, cmdline, cursorpos, ...) abort 723 | let cmdline = substitute(a:cmdline, '^[^ ]\+\s', '', '') 724 | let cmdline = substitute(cmdline, '[^ ]\+$', '', '') 725 | let options = extend( 726 | \ self.parse_args(s:splitargs(cmdline)), 727 | \ get(a:000, 0, {}), 728 | \) 729 | call self.hooks.pre_complete(options) 730 | if get(options, '__terminated__') 731 | if s:Prelude.is_funcref(get(self, 'complete_unknown')) 732 | let candidates = self.complete_unknown( 733 | \ a:arglead, 734 | \ cmdline, 735 | \ a:cursorpos, 736 | \ options, 737 | \) 738 | else 739 | let candidates = [] 740 | endif 741 | elseif empty(a:arglead) 742 | let candidates = [] 743 | let candidates += self._complete_positional_argument_value( 744 | \ a:arglead, 745 | \ cmdline, 746 | \ a:cursorpos, 747 | \ options, 748 | \) 749 | let candidates += self._complete_optional_argument( 750 | \ a:arglead, 751 | \ cmdline, 752 | \ a:cursorpos, 753 | \ options, 754 | \) 755 | elseif a:arglead =~# '^--\?[^=]\+=' 756 | let candidates = self._complete_optional_argument_value( 757 | \ a:arglead, 758 | \ cmdline, 759 | \ a:cursorpos, 760 | \ options, 761 | \) 762 | elseif a:arglead =~# '^--\?' 763 | let candidates = self._complete_optional_argument( 764 | \ a:arglead, 765 | \ cmdline, 766 | \ a:cursorpos, 767 | \ options, 768 | \) 769 | else 770 | let candidates = self._complete_positional_argument_value( 771 | \ a:arglead, 772 | \ cmdline, 773 | \ a:cursorpos, 774 | \ options, 775 | \) 776 | endif 777 | call self.hooks.post_complete(candidates, options) 778 | if !empty(self.complete_threshold) && len(candidates) >= self.complete_threshold 779 | return candidates[ : (self.complete_threshold - 1)] 780 | else 781 | return candidates 782 | endif 783 | endfunction 784 | 785 | function! s:parser._complete_optional_argument_value(arglead, cmdline, cursorpos, options) abort 786 | let m = matchlist(a:arglead, '^\(--\?\([^=]\+\)=\)\(.*\)') 787 | let prefix = m[1] 788 | let name = m[2] 789 | let value = m[3] 790 | if has_key(self.arguments, name) 791 | let candidates = self.arguments[name].complete( 792 | \ value, a:cmdline, a:cursorpos, a:options, 793 | \) 794 | call map(candidates, 'prefix . v:val') 795 | else 796 | let candidates = [] 797 | endif 798 | call self.hooks.post_complete_argument_value(candidates, a:options) 799 | return candidates 800 | endfunction 801 | 802 | function! s:parser._complete_optional_argument(arglead, cmdline, cursorpos, options) abort 803 | let candidates = [] 804 | for argument in values(self.arguments) 805 | if (has_key(a:options, argument.name) && argument.type !=# s:const.types.multiple) || argument.positional 806 | continue 807 | elseif !empty(argument.conflicts) && !empty(self.get_conflicted_arguments(argument.name, a:options)) 808 | continue 809 | elseif !empty(argument.superordinates) && empty(self.get_superordinate_arguments(argument.name, a:options)) 810 | continue 811 | elseif !empty(argument.dependencies) && !empty(self.get_missing_dependencies(argument.name, a:options)) 812 | continue 813 | endif 814 | if '--' . argument.name =~# '^' . a:arglead && len(argument.name) > 1 815 | call add(candidates, '--' . argument.name) 816 | elseif '-' . argument.name =~# '^' . a:arglead && len(argument.name) == 1 817 | call add(candidates, '-' . argument.name) 818 | endif 819 | if !empty(argument.alias) && '-' . argument.alias =~# '^' . a:arglead 820 | call add(candidates, '-' . argument.alias) 821 | endif 822 | endfor 823 | call self.hooks.post_complete_optional_argument(candidates, a:options) 824 | return candidates 825 | endfunction 826 | 827 | function! s:parser._complete_positional_argument_value(arglead, cmdline, cursorpos, options) abort 828 | let candidates = [] 829 | let available_argument = {} 830 | for name in self.positional 831 | let argument = self.arguments[name] 832 | if has_key(a:options, name) 833 | continue 834 | elseif !empty(argument.conflicts) && !empty(self.get_conflicted_arguments(name, a:options)) 835 | continue 836 | elseif !empty(argument.superordinates) && empty(self.get_superordinate_arguments(name, a:options)) 837 | continue 838 | elseif !empty(argument.dependencies) && !empty(self.get_missing_dependencies(name, a:options)) 839 | continue 840 | endif 841 | let available_argument = argument 842 | break 843 | endfor 844 | if !empty(available_argument) 845 | let candidates = available_argument.complete( 846 | \ a:arglead, a:cmdline, a:cursorpos, a:options, 847 | \) 848 | endif 849 | call self.hooks.post_complete_positional_argument(candidates, a:options) 850 | return candidates 851 | endfunction 852 | 853 | function! s:parser.help() abort 854 | let definitions = { 'positional': [], 'optional': [] } 855 | let descriptions = { 'positional': [], 'optional': [] } 856 | let commandlines = [] 857 | for argument in self._arguments 858 | if argument.positional 859 | let [definition, description] = self._help_positional_argument(argument) 860 | call add(definitions.positional, definition) 861 | call add(descriptions.positional, description) 862 | if argument.required 863 | call add(commandlines, definition) 864 | else 865 | call add(commandlines, printf('[%s]', definition)) 866 | endif 867 | else 868 | let [definition, description] = self._help_optional_argument(argument) 869 | let partial_definition = substitute(definition, '^\%(\s\+\|-.,\s\)', '', '') 870 | call add(definitions.optional, definition) 871 | call add(descriptions.optional, description) 872 | if argument.required 873 | call add(commandlines, printf('%s', partial_definition)) 874 | else 875 | call add(commandlines, printf('[%s]', partial_definition)) 876 | endif 877 | endif 878 | endfor 879 | " find a length of the longest definition 880 | let max_length = len(s:List.max_by(definitions.positional + definitions.optional, 'len(v:val)')) 881 | let buflines = [] 882 | call add(buflines, printf( 883 | \ ':%s', join(filter([ 884 | \ self.name, 885 | \ join(commandlines), 886 | \ empty(self.unknown_description) 887 | \ ? '' 888 | \ : printf('-- %s', self.unknown_description), 889 | \], '!empty(v:val)')))) 890 | call add(buflines, '') 891 | call add(buflines, self.description) 892 | if !empty(self.positional) 893 | call add(buflines, '') 894 | call add(buflines, 'Positional arguments:') 895 | for [definition, description] in s:List.zip(definitions.positional, descriptions.positional) 896 | let _definitions = split(definition, "\n") 897 | let _descriptions = split(description, "\n") 898 | let n = max([len(_definitions), len(_descriptions)]) 899 | let i = 0 900 | while i < n 901 | let _definition = get(_definitions, i, '') 902 | let _description = get(_descriptions, i, '') 903 | call add(buflines, printf( 904 | \ printf(' %%-%ds %%s', max_length), 905 | \ _definition, 906 | \ _description, 907 | \)) 908 | let i += 1 909 | endwhile 910 | endfor 911 | endif 912 | call add(buflines, '') 913 | call add(buflines, 'Optional arguments:') 914 | for [definition, description] in s:List.zip(definitions.optional, descriptions.optional) 915 | let _definitions = split(definition, "\n") 916 | let _descriptions = split(description, "\n") 917 | let n = max([len(_definitions), len(_descriptions)]) 918 | let i = 0 919 | while i < n 920 | let _definition = get(_definitions, i, '') 921 | let _description = get(_descriptions, i, '') 922 | call add(buflines, printf( 923 | \ printf(' %%-%ds %%s', max_length), 924 | \ _definition, 925 | \ _description, 926 | \)) 927 | let i += 1 928 | endwhile 929 | endfor 930 | return join(buflines, "\n") 931 | endfunction 932 | 933 | function! s:parser._help_optional_argument(arg) abort 934 | if empty(a:arg.alias) 935 | let alias = ' ' 936 | else 937 | let alias = printf('-%s, ', a:arg.alias) 938 | endif 939 | if a:arg.deniable 940 | let deniable = '[no-]' 941 | else 942 | let deniable = '' 943 | endif 944 | if a:arg.type == s:const.types.any 945 | let definition = printf( 946 | \ '%s--%s%s[=%s]', 947 | \ alias, 948 | \ deniable, 949 | \ a:arg.name, 950 | \ toupper(a:arg.name) 951 | \) 952 | elseif a:arg.type == s:const.types.value 953 | let definition = printf( 954 | \ '%s--%s%s=%s', 955 | \ alias, 956 | \ deniable, 957 | \ a:arg.name, 958 | \ toupper(a:arg.name) 959 | \) 960 | elseif a:arg.type == s:const.types.choice 961 | let definition = printf( 962 | \ '%s--%s%s={%s}', 963 | \ alias, 964 | \ deniable, 965 | \ a:arg.name, 966 | \ toupper(a:arg.name) 967 | \) 968 | else 969 | let definition = printf( 970 | \ '%s--%s%s', 971 | \ alias, 972 | \ deniable, 973 | \ a:arg.name, 974 | \) 975 | endif 976 | let description = join(a:arg.description, "\n") 977 | if a:arg.required 978 | let description = printf('%s (*)', description) 979 | endif 980 | return [definition, description] 981 | endfunction 982 | 983 | function! s:parser._help_positional_argument(arg) abort 984 | let definition = printf('%s', a:arg.name) 985 | let description = join(a:arg.description, "\n") 986 | if a:arg.required 987 | let description = printf('%s (*)', description) 988 | endif 989 | return [definition, description] 990 | endfunction 991 | 992 | " Available user hooks 993 | function! s:parser.hooks.pre_validate(options) abort 994 | endfunction 995 | 996 | function! s:parser.hooks.post_validate(options) abort 997 | endfunction 998 | 999 | function! s:parser.hooks.pre_complete(options) abort 1000 | endfunction 1001 | 1002 | function! s:parser.hooks.post_complete(candidates, options) abort 1003 | endfunction 1004 | 1005 | function! s:parser.hooks.post_complete_argument_value(candidates, options) abort 1006 | endfunction 1007 | 1008 | function! s:parser.hooks.post_complete_optional_argument(candidates, options) abort 1009 | endfunction 1010 | 1011 | function! s:parser.hooks.post_complete_positional_argument(candidates, options) abort 1012 | endfunction 1013 | 1014 | function! s:parser.hooks.validate() abort 1015 | let known_hooks = [ 1016 | \ 'pre_validate', 1017 | \ 'post_validate', 1018 | \ 'pre_complete', 1019 | \ 'post_complete', 1020 | \ 'post_complete_argument_value', 1021 | \ 'post_complete_optional_argument', 1022 | \ 'post_complete_positional_argument', 1023 | \] 1024 | for key in keys(self) 1025 | if key !=# 'validate' && index(known_hooks, key) == -1 1026 | call s:_throw(printf( 1027 | \ 'Unknown hook "%s" is found.', 1028 | \ key, 1029 | \)) 1030 | endif 1031 | endfor 1032 | endfunction 1033 | 1034 | let &cpo = s:save_cpo 1035 | unlet s:save_cpo 1036 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 1037 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Data/Dict.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Data#Dict#import() abort 6 | return map({'pick': '', 'clear': '', 'max_by': '', 'foldl': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Data#Dict#import() abort', printf("return map({'pick': '', 'clear': '', 'max_by': '', 'foldl': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | " Utilities for dictionary. 17 | 18 | let s:save_cpo = &cpo 19 | set cpo&vim 20 | 21 | " Makes a dict from keys and values 22 | function! s:make(keys, values, ...) abort 23 | let dict = {} 24 | let fill = a:0 ? a:1 : 0 25 | for i in range(len(a:keys)) 26 | let key = type(a:keys[i]) == type('') ? a:keys[i] : string(a:keys[i]) 27 | if key ==# '' 28 | throw "vital: Data.Dict: Can't use an empty string for key." 29 | endif 30 | let dict[key] = get(a:values, i, fill) 31 | endfor 32 | return dict 33 | endfunction 34 | 35 | " Swaps keys and values 36 | function! s:swap(dict) abort 37 | return s:make(values(a:dict), keys(a:dict)) 38 | endfunction 39 | 40 | " Makes a index dict from a list 41 | function! s:make_index(list, ...) abort 42 | let value = a:0 ? a:1 : 1 43 | return s:make(a:list, [], value) 44 | endfunction 45 | 46 | function! s:pick(dict, keys) abort 47 | let new_dict = {} 48 | for key in a:keys 49 | if has_key(a:dict, key) 50 | let new_dict[key] = a:dict[key] 51 | endif 52 | endfor 53 | return new_dict 54 | endfunction 55 | 56 | function! s:omit(dict, keys) abort 57 | let new_dict = copy(a:dict) 58 | for key in a:keys 59 | if has_key(a:dict, key) 60 | call remove(new_dict, key) 61 | endif 62 | endfor 63 | return new_dict 64 | endfunction 65 | 66 | function! s:clear(dict) abort 67 | for key in keys(a:dict) 68 | call remove(a:dict, key) 69 | endfor 70 | return a:dict 71 | endfunction 72 | 73 | function! s:_max_by(dict, expr) abort 74 | let dict = s:swap(map(copy(a:dict), a:expr)) 75 | let key = dict[max(keys(dict))] 76 | return [key, a:dict[key]] 77 | endfunction 78 | 79 | function! s:max_by(dict, expr) abort 80 | if empty(a:dict) 81 | throw 'vital: Data.Dict: Empty dictionary' 82 | endif 83 | return s:_max_by(a:dict, a:expr) 84 | endfunction 85 | 86 | function! s:min_by(dict, expr) abort 87 | if empty(a:dict) 88 | throw 'vital: Data.Dict: Empty dictionary' 89 | endif 90 | return s:_max_by(a:dict, '-(' . a:expr . ')') 91 | endfunction 92 | 93 | function! s:_foldl(f, init, xs) abort 94 | let memo = a:init 95 | for [k, v] in a:xs 96 | let expr = substitute(a:f, 'v:key', string(k), 'g') 97 | let expr = substitute(expr, 'v:val', string(v), 'g') 98 | let expr = substitute(expr, 'v:memo', string(memo), 'g') 99 | unlet memo 100 | let memo = eval(expr) 101 | endfor 102 | return memo 103 | endfunction 104 | 105 | function! s:foldl(f, init, dict) abort 106 | return s:_foldl(a:f, a:init, items(a:dict)) 107 | endfunction 108 | 109 | function! s:foldr(f, init, dict) abort 110 | return s:_foldl(a:f, a:init, reverse(items(a:dict))) 111 | endfunction 112 | 113 | let &cpo = s:save_cpo 114 | unlet s:save_cpo 115 | 116 | " vim:set et ts=2 sts=2 sw=2 tw=0: 117 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Data/List.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Data#List#import() abort 6 | return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'map_accum': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'shift': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Data#List#import() abort', printf("return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'map_accum': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'shift': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | " Utilities for list. 17 | 18 | let s:save_cpo = &cpo 19 | set cpo&vim 20 | 21 | function! s:pop(list) abort 22 | return remove(a:list, -1) 23 | endfunction 24 | 25 | function! s:push(list, val) abort 26 | call add(a:list, a:val) 27 | return a:list 28 | endfunction 29 | 30 | function! s:shift(list) abort 31 | return remove(a:list, 0) 32 | endfunction 33 | 34 | function! s:unshift(list, val) abort 35 | return insert(a:list, a:val) 36 | endfunction 37 | 38 | function! s:cons(x, xs) abort 39 | return [a:x] + a:xs 40 | endfunction 41 | 42 | function! s:conj(xs, x) abort 43 | return a:xs + [a:x] 44 | endfunction 45 | 46 | " Removes duplicates from a list. 47 | function! s:uniq(list) abort 48 | return s:uniq_by(a:list, 'v:val') 49 | endfunction 50 | 51 | " Removes duplicates from a list. 52 | function! s:uniq_by(list, f) abort 53 | let list = map(copy(a:list), printf('[v:val, %s]', a:f)) 54 | let i = 0 55 | let seen = {} 56 | while i < len(list) 57 | let key = string(list[i][1]) 58 | if has_key(seen, key) 59 | call remove(list, i) 60 | else 61 | let seen[key] = 1 62 | let i += 1 63 | endif 64 | endwhile 65 | return map(list, 'v:val[0]') 66 | endfunction 67 | 68 | function! s:clear(list) abort 69 | if !empty(a:list) 70 | unlet! a:list[0 : len(a:list) - 1] 71 | endif 72 | return a:list 73 | endfunction 74 | 75 | " Concatenates a list of lists. 76 | " XXX: Should we verify the input? 77 | function! s:concat(list) abort 78 | let memo = [] 79 | for Value in a:list 80 | let memo += Value 81 | endfor 82 | return memo 83 | endfunction 84 | 85 | " Take each elements from lists to a new list. 86 | function! s:flatten(list, ...) abort 87 | let limit = a:0 > 0 ? a:1 : -1 88 | let memo = [] 89 | if limit == 0 90 | return a:list 91 | endif 92 | let limit -= 1 93 | for Value in a:list 94 | let memo += 95 | \ type(Value) == type([]) ? 96 | \ s:flatten(Value, limit) : 97 | \ [Value] 98 | unlet! Value 99 | endfor 100 | return memo 101 | endfunction 102 | 103 | " Sorts a list with expression to compare each two values. 104 | " a:a and a:b can be used in {expr}. 105 | function! s:sort(list, expr) abort 106 | if type(a:expr) == type(function('function')) 107 | return sort(a:list, a:expr) 108 | endif 109 | let s:expr = a:expr 110 | return sort(a:list, 's:_compare') 111 | endfunction 112 | 113 | function! s:_compare(a, b) abort 114 | return eval(s:expr) 115 | endfunction 116 | 117 | " Sorts a list using a set of keys generated by mapping the values in the list 118 | " through the given expr. 119 | " v:val is used in {expr} 120 | function! s:sort_by(list, expr) abort 121 | let pairs = map(a:list, printf('[v:val, %s]', a:expr)) 122 | return map(s:sort(pairs, 123 | \ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]') 124 | endfunction 125 | 126 | " Returns a maximum value in {list} through given {expr}. 127 | " Returns 0 if {list} is empty. 128 | " v:val is used in {expr} 129 | function! s:max_by(list, expr) abort 130 | if empty(a:list) 131 | return 0 132 | endif 133 | let list = map(copy(a:list), a:expr) 134 | return a:list[index(list, max(list))] 135 | endfunction 136 | 137 | " Returns a minimum value in {list} through given {expr}. 138 | " Returns 0 if {list} is empty. 139 | " v:val is used in {expr} 140 | " FIXME: -0x80000000 == 0x80000000 141 | function! s:min_by(list, expr) abort 142 | return s:max_by(a:list, '-(' . a:expr . ')') 143 | endfunction 144 | 145 | " Returns List of character sequence between [a:from, a:to] 146 | " e.g.: s:char_range('a', 'c') returns ['a', 'b', 'c'] 147 | function! s:char_range(from, to) abort 148 | return map( 149 | \ range(char2nr(a:from), char2nr(a:to)), 150 | \ 'nr2char(v:val)' 151 | \) 152 | endfunction 153 | 154 | " Returns true if a:list has a:value. 155 | " Returns false otherwise. 156 | function! s:has(list, value) abort 157 | return index(a:list, a:value) isnot -1 158 | endfunction 159 | 160 | " Returns true if a:list[a:index] exists. 161 | " Returns false otherwise. 162 | " NOTE: Returns false when a:index is negative number. 163 | function! s:has_index(list, index) abort 164 | " Return true when negative index? 165 | " let index = a:index >= 0 ? a:index : len(a:list) + a:index 166 | return 0 <= a:index && a:index < len(a:list) 167 | endfunction 168 | 169 | " similar to Haskell's Data.List.span 170 | function! s:span(f, xs) abort 171 | let border = len(a:xs) 172 | for i in range(len(a:xs)) 173 | if !eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g')) 174 | let border = i 175 | break 176 | endif 177 | endfor 178 | return border == 0 ? [[], copy(a:xs)] : [a:xs[: border - 1], a:xs[border :]] 179 | endfunction 180 | 181 | " similar to Haskell's Data.List.break 182 | function! s:break(f, xs) abort 183 | return s:span(printf('!(%s)', a:f), a:xs) 184 | endfunction 185 | 186 | " similar to Haskell's Data.List.takeWhile 187 | function! s:take_while(f, xs) abort 188 | return s:span(a:f, a:xs)[0] 189 | endfunction 190 | 191 | " similar to Haskell's Data.List.partition 192 | function! s:partition(f, xs) abort 193 | return [filter(copy(a:xs), a:f), filter(copy(a:xs), '!(' . a:f . ')')] 194 | endfunction 195 | 196 | " similar to Haskell's Prelude.all 197 | function! s:all(f, xs) abort 198 | return !s:any(printf('!(%s)', a:f), a:xs) 199 | endfunction 200 | 201 | " similar to Haskell's Prelude.any 202 | function! s:any(f, xs) abort 203 | return !empty(filter(map(copy(a:xs), a:f), 'v:val')) 204 | endfunction 205 | 206 | " similar to Haskell's Prelude.and 207 | function! s:and(xs) abort 208 | return s:all('v:val', a:xs) 209 | endfunction 210 | 211 | " similar to Haskell's Prelude.or 212 | function! s:or(xs) abort 213 | return s:any('v:val', a:xs) 214 | endfunction 215 | 216 | function! s:map_accum(expr, xs, init) abort 217 | let memo = [] 218 | let init = a:init 219 | for x in a:xs 220 | let expr = substitute(a:expr, 'v:memo', init, 'g') 221 | let expr = substitute(expr, 'v:val', x, 'g') 222 | let [tmp, init] = eval(expr) 223 | call add(memo, tmp) 224 | endfor 225 | return memo 226 | endfunction 227 | 228 | " similar to Haskell's Prelude.foldl 229 | function! s:foldl(f, init, xs) abort 230 | let memo = a:init 231 | for x in a:xs 232 | let expr = substitute(a:f, 'v:val', string(x), 'g') 233 | let expr = substitute(expr, 'v:memo', string(memo), 'g') 234 | unlet memo 235 | let memo = eval(expr) 236 | endfor 237 | return memo 238 | endfunction 239 | 240 | " similar to Haskell's Prelude.foldl1 241 | function! s:foldl1(f, xs) abort 242 | if len(a:xs) == 0 243 | throw 'vital: Data.List: foldl1' 244 | endif 245 | return s:foldl(a:f, a:xs[0], a:xs[1:]) 246 | endfunction 247 | 248 | " similar to Haskell's Prelude.foldr 249 | function! s:foldr(f, init, xs) abort 250 | return s:foldl(a:f, a:init, reverse(copy(a:xs))) 251 | endfunction 252 | 253 | " similar to Haskell's Prelude.fold11 254 | function! s:foldr1(f, xs) abort 255 | if len(a:xs) == 0 256 | throw 'vital: Data.List: foldr1' 257 | endif 258 | return s:foldr(a:f, a:xs[-1], a:xs[0:-2]) 259 | endfunction 260 | 261 | " similar to python's zip() 262 | function! s:zip(...) abort 263 | return map(range(min(map(copy(a:000), 'len(v:val)'))), "map(copy(a:000), 'v:val['.v:val.']')") 264 | endfunction 265 | 266 | " similar to zip(), but goes until the longer one. 267 | function! s:zip_fill(xs, ys, filler) abort 268 | if empty(a:xs) && empty(a:ys) 269 | return [] 270 | elseif empty(a:ys) 271 | return s:cons([a:xs[0], a:filler], s:zip_fill(a:xs[1 :], [], a:filler)) 272 | elseif empty(a:xs) 273 | return s:cons([a:filler, a:ys[0]], s:zip_fill([], a:ys[1 :], a:filler)) 274 | else 275 | return s:cons([a:xs[0], a:ys[0]], s:zip_fill(a:xs[1 :], a:ys[1: ], a:filler)) 276 | endif 277 | endfunction 278 | 279 | " Inspired by Ruby's with_index method. 280 | function! s:with_index(list, ...) abort 281 | let base = a:0 > 0 ? a:1 : 0 282 | return map(copy(a:list), '[v:val, v:key + base]') 283 | endfunction 284 | 285 | " similar to Ruby's detect or Haskell's find. 286 | function! s:find(list, default, f) abort 287 | for x in a:list 288 | if eval(substitute(a:f, 'v:val', string(x), 'g')) 289 | return x 290 | endif 291 | endfor 292 | return a:default 293 | endfunction 294 | 295 | " Returns the index of the first element which satisfies the given expr. 296 | function! s:find_index(xs, f, ...) abort 297 | let len = len(a:xs) 298 | let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0 299 | let default = a:0 > 1 ? a:2 : -1 300 | if start >=# len || start < 0 301 | return default 302 | endif 303 | for i in range(start, len - 1) 304 | if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g')) 305 | return i 306 | endif 307 | endfor 308 | return default 309 | endfunction 310 | 311 | " Returns the index of the last element which satisfies the given expr. 312 | function! s:find_last_index(xs, f, ...) abort 313 | let len = len(a:xs) 314 | let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : len - 1 315 | let default = a:0 > 1 ? a:2 : -1 316 | if start >=# len || start < 0 317 | return default 318 | endif 319 | for i in range(start, 0, -1) 320 | if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g')) 321 | return i 322 | endif 323 | endfor 324 | return default 325 | endfunction 326 | 327 | " Similar to find_index but returns the list of indices satisfying the given expr. 328 | function! s:find_indices(xs, f, ...) abort 329 | let len = len(a:xs) 330 | let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0 331 | let result = [] 332 | if start >=# len || start < 0 333 | return result 334 | endif 335 | for i in range(start, len - 1) 336 | if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g')) 337 | call add(result, i) 338 | endif 339 | endfor 340 | return result 341 | endfunction 342 | 343 | " Return non-zero if a:list1 and a:list2 have any common item(s). 344 | " Return zero otherwise. 345 | function! s:has_common_items(list1, list2) abort 346 | return !empty(filter(copy(a:list1), 'index(a:list2, v:val) isnot -1')) 347 | endfunction 348 | 349 | function! s:intersect(list1, list2) abort 350 | let items = [] 351 | " for funcref 352 | for X in a:list1 353 | if index(a:list2, X) != -1 && index(items, X) == -1 354 | let items += [X] 355 | endif 356 | endfor 357 | return items 358 | endfunction 359 | 360 | " similar to Ruby's group_by. 361 | function! s:group_by(xs, f) abort 362 | let result = {} 363 | let list = map(copy(a:xs), printf('[v:val, %s]', a:f)) 364 | for x in list 365 | let Val = x[0] 366 | let key = type(x[1]) !=# type('') ? string(x[1]) : x[1] 367 | if has_key(result, key) 368 | call add(result[key], Val) 369 | else 370 | let result[key] = [Val] 371 | endif 372 | unlet Val 373 | endfor 374 | return result 375 | endfunction 376 | 377 | function! s:_default_compare(a, b) abort 378 | return a:a <# a:b ? -1 : a:a ># a:b ? 1 : 0 379 | endfunction 380 | 381 | function! s:binary_search(list, value, ...) abort 382 | let Predicate = a:0 >= 1 ? a:1 : 's:_default_compare' 383 | let dic = a:0 >= 2 ? a:2 : {} 384 | let start = 0 385 | let end = len(a:list) - 1 386 | 387 | while 1 388 | if start > end 389 | return -1 390 | endif 391 | 392 | let middle = (start + end) / 2 393 | 394 | let compared = call(Predicate, [a:value, a:list[middle]], dic) 395 | 396 | if compared < 0 397 | let end = middle - 1 398 | elseif compared > 0 399 | let start = middle + 1 400 | else 401 | return middle 402 | endif 403 | endwhile 404 | endfunction 405 | 406 | function! s:product(lists) abort 407 | let result = [[]] 408 | for pool in a:lists 409 | let tmp = [] 410 | for x in result 411 | let tmp += map(copy(pool), 'x + [v:val]') 412 | endfor 413 | let result = tmp 414 | endfor 415 | return result 416 | endfunction 417 | 418 | function! s:permutations(list, ...) abort 419 | if a:0 > 1 420 | throw 'vital: Data.List: too many arguments' 421 | endif 422 | let r = a:0 == 1 ? a:1 : len(a:list) 423 | if r > len(a:list) 424 | return [] 425 | elseif r < 0 426 | throw 'vital: Data.List: {r} must be non-negative integer' 427 | endif 428 | let n = len(a:list) 429 | let result = [] 430 | for indices in s:product(map(range(r), 'range(n)')) 431 | if len(s:uniq(indices)) == r 432 | call add(result, map(indices, 'a:list[v:val]')) 433 | endif 434 | endfor 435 | return result 436 | endfunction 437 | 438 | function! s:combinations(list, r) abort 439 | if a:r > len(a:list) 440 | return [] 441 | elseif a:r < 0 442 | throw 'vital: Data:List: {r} must be non-negative integer' 443 | endif 444 | let n = len(a:list) 445 | let result = [] 446 | for indices in s:permutations(range(n), a:r) 447 | if s:sort(copy(indices), 'a:a - a:b') == indices 448 | call add(result, map(indices, 'a:list[v:val]')) 449 | endif 450 | endfor 451 | return result 452 | endfunction 453 | 454 | let &cpo = s:save_cpo 455 | unlet s:save_cpo 456 | 457 | " vim:set et ts=2 sts=2 sw=2 tw=0: 458 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Prelude.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Prelude#import() abort 6 | return map({'escape_pattern': '', 'is_funcref': '', 'path2directory': '', 'wcswidth': '', 'is_string': '', 'input_helper': '', 'is_number': '', 'is_cygwin': '', 'path2project_directory': '', 'strwidthpart_reverse': '', 'input_safe': '', 'is_list': '', 'truncate_skipping': '', 'glob': '', 'truncate': '', 'is_dict': '', 'set_default': '', 'is_numeric': '', 'getchar_safe': '', 'substitute_path_separator': '', 'is_mac': '', 'strwidthpart': '', 'getchar': '', 'is_unix': '', 'is_windows': '', 'globpath': '', 'escape_file_searching': '', 'is_float': '', 'smart_execute_command': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Prelude#import() abort', printf("return map({'escape_pattern': '', 'is_funcref': '', 'path2directory': '', 'wcswidth': '', 'is_string': '', 'input_helper': '', 'is_number': '', 'is_cygwin': '', 'path2project_directory': '', 'strwidthpart_reverse': '', 'input_safe': '', 'is_list': '', 'truncate_skipping': '', 'glob': '', 'truncate': '', 'is_dict': '', 'set_default': '', 'is_numeric': '', 'getchar_safe': '', 'substitute_path_separator': '', 'is_mac': '', 'strwidthpart': '', 'getchar': '', 'is_unix': '', 'is_windows': '', 'globpath': '', 'escape_file_searching': '', 'is_float': '', 'smart_execute_command': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | let s:save_cpo = &cpo 17 | set cpo&vim 18 | 19 | if v:version > 703 || 20 | \ (v:version == 703 && has('patch465')) 21 | function! s:glob(expr) abort 22 | return glob(a:expr, 1, 1) 23 | endfunction 24 | else 25 | function! s:glob(expr) abort 26 | return split(glob(a:expr, 1), '\n') 27 | endfunction 28 | endif 29 | 30 | if v:version > 704 || 31 | \ (v:version == 704 && has('patch279')) 32 | function! s:globpath(path, expr) abort 33 | return globpath(a:path, a:expr, 1, 1) 34 | endfunction 35 | else 36 | function! s:globpath(path, expr) abort 37 | return split(globpath(a:path, a:expr, 1), '\n') 38 | endfunction 39 | endif 40 | 41 | " Wrapper functions for type(). 42 | let [ 43 | \ s:__TYPE_NUMBER, 44 | \ s:__TYPE_STRING, 45 | \ s:__TYPE_FUNCREF, 46 | \ s:__TYPE_LIST, 47 | \ s:__TYPE_DICT, 48 | \ s:__TYPE_FLOAT] = [ 49 | \ type(3), 50 | \ type(''), 51 | \ type(function('tr')), 52 | \ type([]), 53 | \ type({}), 54 | \ has('float') ? type(str2float('0')) : -1] 55 | " __TYPE_FLOAT = -1 when -float 56 | " This doesn't match to anything. 57 | 58 | " Number or Float 59 | function! s:is_numeric(Value) abort 60 | let _ = type(a:Value) 61 | return _ ==# s:__TYPE_NUMBER 62 | \ || _ ==# s:__TYPE_FLOAT 63 | endfunction 64 | 65 | " Number 66 | function! s:is_number(Value) abort 67 | return type(a:Value) ==# s:__TYPE_NUMBER 68 | endfunction 69 | 70 | " Float 71 | function! s:is_float(Value) abort 72 | return type(a:Value) ==# s:__TYPE_FLOAT 73 | endfunction 74 | " String 75 | function! s:is_string(Value) abort 76 | return type(a:Value) ==# s:__TYPE_STRING 77 | endfunction 78 | " Funcref 79 | function! s:is_funcref(Value) abort 80 | return type(a:Value) ==# s:__TYPE_FUNCREF 81 | endfunction 82 | " List 83 | function! s:is_list(Value) abort 84 | return type(a:Value) ==# s:__TYPE_LIST 85 | endfunction 86 | " Dictionary 87 | function! s:is_dict(Value) abort 88 | return type(a:Value) ==# s:__TYPE_DICT 89 | endfunction 90 | 91 | function! s:truncate_skipping(str, max, footer_width, separator) abort 92 | call s:_warn_deprecated('truncate_skipping', 'Data.String.truncate_skipping') 93 | 94 | let width = s:wcswidth(a:str) 95 | if width <= a:max 96 | let ret = a:str 97 | else 98 | let header_width = a:max - s:wcswidth(a:separator) - a:footer_width 99 | let ret = s:strwidthpart(a:str, header_width) . a:separator 100 | \ . s:strwidthpart_reverse(a:str, a:footer_width) 101 | endif 102 | 103 | return s:truncate(ret, a:max) 104 | endfunction 105 | 106 | function! s:truncate(str, width) abort 107 | " Original function is from mattn. 108 | " http://github.com/mattn/googlereader-vim/tree/master 109 | 110 | call s:_warn_deprecated('truncate', 'Data.String.truncate') 111 | 112 | if a:str =~# '^[\x00-\x7f]*$' 113 | return len(a:str) < a:width ? 114 | \ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width) 115 | endif 116 | 117 | let ret = a:str 118 | let width = s:wcswidth(a:str) 119 | if width > a:width 120 | let ret = s:strwidthpart(ret, a:width) 121 | let width = s:wcswidth(ret) 122 | endif 123 | 124 | if width < a:width 125 | let ret .= repeat(' ', a:width - width) 126 | endif 127 | 128 | return ret 129 | endfunction 130 | 131 | function! s:strwidthpart(str, width) abort 132 | call s:_warn_deprecated('strwidthpart', 'Data.String.strwidthpart') 133 | 134 | if a:width <= 0 135 | return '' 136 | endif 137 | let ret = a:str 138 | let width = s:wcswidth(a:str) 139 | while width > a:width 140 | let char = matchstr(ret, '.$') 141 | let ret = ret[: -1 - len(char)] 142 | let width -= s:wcswidth(char) 143 | endwhile 144 | 145 | return ret 146 | endfunction 147 | function! s:strwidthpart_reverse(str, width) abort 148 | call s:_warn_deprecated('strwidthpart_reverse', 'Data.String.strwidthpart_reverse') 149 | 150 | if a:width <= 0 151 | return '' 152 | endif 153 | let ret = a:str 154 | let width = s:wcswidth(a:str) 155 | while width > a:width 156 | let char = matchstr(ret, '^.') 157 | let ret = ret[len(char) :] 158 | let width -= s:wcswidth(char) 159 | endwhile 160 | 161 | return ret 162 | endfunction 163 | 164 | if v:version >= 703 165 | " Use builtin function. 166 | function! s:wcswidth(str) abort 167 | call s:_warn_deprecated('wcswidth', 'Data.String.wcswidth') 168 | return strwidth(a:str) 169 | endfunction 170 | else 171 | function! s:wcswidth(str) abort 172 | call s:_warn_deprecated('wcswidth', 'Data.String.wcswidth') 173 | 174 | if a:str =~# '^[\x00-\x7f]*$' 175 | return strlen(a:str) 176 | end 177 | 178 | let mx_first = '^\(.\)' 179 | let str = a:str 180 | let width = 0 181 | while 1 182 | let ucs = char2nr(substitute(str, mx_first, '\1', '')) 183 | if ucs == 0 184 | break 185 | endif 186 | let width += s:_wcwidth(ucs) 187 | let str = substitute(str, mx_first, '', '') 188 | endwhile 189 | return width 190 | endfunction 191 | 192 | " UTF-8 only. 193 | function! s:_wcwidth(ucs) abort 194 | let ucs = a:ucs 195 | if (ucs >= 0x1100 196 | \ && (ucs <= 0x115f 197 | \ || ucs == 0x2329 198 | \ || ucs == 0x232a 199 | \ || (ucs >= 0x2e80 && ucs <= 0xa4cf 200 | \ && ucs != 0x303f) 201 | \ || (ucs >= 0xac00 && ucs <= 0xd7a3) 202 | \ || (ucs >= 0xf900 && ucs <= 0xfaff) 203 | \ || (ucs >= 0xfe30 && ucs <= 0xfe6f) 204 | \ || (ucs >= 0xff00 && ucs <= 0xff60) 205 | \ || (ucs >= 0xffe0 && ucs <= 0xffe6) 206 | \ || (ucs >= 0x20000 && ucs <= 0x2fffd) 207 | \ || (ucs >= 0x30000 && ucs <= 0x3fffd) 208 | \ )) 209 | return 2 210 | endif 211 | return 1 212 | endfunction 213 | endif 214 | 215 | let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95') 216 | let s:is_cygwin = has('win32unix') 217 | let s:is_mac = !s:is_windows && !s:is_cygwin 218 | \ && (has('mac') || has('macunix') || has('gui_macvim') || 219 | \ (!isdirectory('/proc') && executable('sw_vers'))) 220 | let s:is_unix = has('unix') 221 | 222 | function! s:is_windows() abort 223 | return s:is_windows 224 | endfunction 225 | 226 | function! s:is_cygwin() abort 227 | return s:is_cygwin 228 | endfunction 229 | 230 | function! s:is_mac() abort 231 | return s:is_mac 232 | endfunction 233 | 234 | function! s:is_unix() abort 235 | return s:is_unix 236 | endfunction 237 | 238 | function! s:_warn_deprecated(name, alternative) abort 239 | try 240 | echohl Error 241 | echomsg 'Prelude.' . a:name . ' is deprecated! Please use ' . a:alternative . ' instead.' 242 | finally 243 | echohl None 244 | endtry 245 | endfunction 246 | 247 | function! s:smart_execute_command(action, word) abort 248 | execute a:action . ' ' . (a:word ==# '' ? '' : '`=a:word`') 249 | endfunction 250 | 251 | function! s:escape_file_searching(buffer_name) abort 252 | return escape(a:buffer_name, '*[]?{}, ') 253 | endfunction 254 | 255 | function! s:escape_pattern(str) abort 256 | call s:_warn_deprecated( 257 | \ 'escape_pattern', 258 | \ 'Data.String.escape_pattern', 259 | \) 260 | return escape(a:str, '~"\.^$[]*') 261 | endfunction 262 | 263 | function! s:getchar(...) abort 264 | let c = call('getchar', a:000) 265 | return type(c) == type(0) ? nr2char(c) : c 266 | endfunction 267 | 268 | function! s:getchar_safe(...) abort 269 | let c = s:input_helper('getchar', a:000) 270 | return type(c) == type('') ? c : nr2char(c) 271 | endfunction 272 | 273 | function! s:input_safe(...) abort 274 | return s:input_helper('input', a:000) 275 | endfunction 276 | 277 | function! s:input_helper(funcname, args) abort 278 | let success = 0 279 | if inputsave() !=# success 280 | throw 'vital: Prelude: inputsave() failed' 281 | endif 282 | try 283 | return call(a:funcname, a:args) 284 | finally 285 | if inputrestore() !=# success 286 | throw 'vital: Prelude: inputrestore() failed' 287 | endif 288 | endtry 289 | endfunction 290 | 291 | function! s:set_default(var, val) abort 292 | if !exists(a:var) || type({a:var}) != type(a:val) 293 | let {a:var} = a:val 294 | endif 295 | endfunction 296 | 297 | function! s:substitute_path_separator(path) abort 298 | return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path 299 | endfunction 300 | 301 | function! s:path2directory(path) abort 302 | return s:substitute_path_separator(isdirectory(a:path) ? a:path : fnamemodify(a:path, ':p:h')) 303 | endfunction 304 | 305 | function! s:_path2project_directory_git(path) abort 306 | let parent = a:path 307 | 308 | while 1 309 | let path = parent . '/.git' 310 | if isdirectory(path) || filereadable(path) 311 | return parent 312 | endif 313 | let next = fnamemodify(parent, ':h') 314 | if next == parent 315 | return '' 316 | endif 317 | let parent = next 318 | endwhile 319 | endfunction 320 | 321 | function! s:_path2project_directory_svn(path) abort 322 | let search_directory = a:path 323 | let directory = '' 324 | 325 | let find_directory = s:escape_file_searching(search_directory) 326 | let d = finddir('.svn', find_directory . ';') 327 | if d ==# '' 328 | return '' 329 | endif 330 | 331 | let directory = fnamemodify(d, ':p:h:h') 332 | 333 | " Search parent directories. 334 | let parent_directory = s:path2directory( 335 | \ fnamemodify(directory, ':h')) 336 | 337 | if parent_directory !=# '' 338 | let d = finddir('.svn', parent_directory . ';') 339 | if d !=# '' 340 | let directory = s:_path2project_directory_svn(parent_directory) 341 | endif 342 | endif 343 | return directory 344 | endfunction 345 | 346 | function! s:_path2project_directory_others(vcs, path) abort 347 | let vcs = a:vcs 348 | let search_directory = a:path 349 | 350 | let find_directory = s:escape_file_searching(search_directory) 351 | let d = finddir(vcs, find_directory . ';') 352 | if d ==# '' 353 | return '' 354 | endif 355 | return fnamemodify(d, ':p:h:h') 356 | endfunction 357 | 358 | function! s:path2project_directory(path, ...) abort 359 | let is_allow_empty = get(a:000, 0, 0) 360 | let search_directory = s:path2directory(a:path) 361 | let directory = '' 362 | 363 | " Search VCS directory. 364 | for vcs in ['.git', '.bzr', '.hg', '.svn'] 365 | if vcs ==# '.git' 366 | let directory = s:_path2project_directory_git(search_directory) 367 | elseif vcs ==# '.svn' 368 | let directory = s:_path2project_directory_svn(search_directory) 369 | else 370 | let directory = s:_path2project_directory_others(vcs, search_directory) 371 | endif 372 | if directory !=# '' 373 | break 374 | endif 375 | endfor 376 | 377 | " Search project file. 378 | if directory ==# '' 379 | for d in ['build.xml', 'prj.el', '.project', 'pom.xml', 'package.json', 380 | \ 'Makefile', 'configure', 'Rakefile', 'NAnt.build', 381 | \ 'P4CONFIG', 'tags', 'gtags'] 382 | let d = findfile(d, s:escape_file_searching(search_directory) . ';') 383 | if d !=# '' 384 | let directory = fnamemodify(d, ':p:h') 385 | break 386 | endif 387 | endfor 388 | endif 389 | 390 | if directory ==# '' 391 | " Search /src/ directory. 392 | let base = s:substitute_path_separator(search_directory) 393 | if base =~# '/src/' 394 | let directory = base[: strridx(base, '/src/') + 3] 395 | endif 396 | endif 397 | 398 | if directory ==# '' && !is_allow_empty 399 | " Use original path. 400 | let directory = search_directory 401 | endif 402 | 403 | return s:substitute_path_separator(directory) 404 | endfunction 405 | 406 | let &cpo = s:save_cpo 407 | unlet s:save_cpo 408 | 409 | " vim:set et ts=2 sts=2 sw=2 tw=0: 410 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/System/Filepath.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#System#Filepath#import() abort 6 | return map({'path_separator': '', 'is_case_tolerant': '', 'dirname': '', 'abspath': '', 'relpath': '', 'realpath': '', 'unify_separator': '', 'is_root_directory': '', 'split': '', 'path_extensions': '', 'unixpath': '', 'which': '', 'winpath': '', 'join': '', 'separator': '', 'is_relative': '', 'basename': '', 'remove_last_separator': '', 'is_absolute': '', 'contains': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#System#Filepath#import() abort', printf("return map({'path_separator': '', 'is_case_tolerant': '', 'dirname': '', 'abspath': '', 'relpath': '', 'realpath': '', 'unify_separator': '', 'is_root_directory': '', 'split': '', 'path_extensions': '', 'unixpath': '', 'which': '', 'winpath': '', 'join': '', 'separator': '', 'is_relative': '', 'basename': '', 'remove_last_separator': '', 'is_absolute': '', 'contains': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | " You should check the following related builtin functions. 17 | " fnamemodify() 18 | " resolve() 19 | " simplify() 20 | 21 | let s:save_cpo = &cpo 22 | set cpo&vim 23 | 24 | let s:path_sep_pattern = (exists('+shellslash') ? '[\\/]' : '/') . '\+' 25 | let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95') 26 | let s:is_cygwin = has('win32unix') 27 | let s:is_mac = !s:is_windows && !s:is_cygwin 28 | \ && (has('mac') || has('macunix') || has('gui_macvim') || 29 | \ (!isdirectory('/proc') && executable('sw_vers'))) 30 | let s:is_case_tolerant = filereadable(expand(':r') . '.VIM') 31 | 32 | " Get the directory separator. 33 | function! s:separator() abort 34 | return fnamemodify('.', ':p')[-1 :] 35 | endfunction 36 | 37 | " Get the path separator. 38 | let s:path_separator = s:is_windows ? ';' : ':' 39 | function! s:path_separator() abort 40 | return s:path_separator 41 | endfunction 42 | 43 | " Get the path extensions 44 | function! s:path_extensions() abort 45 | if !exists('s:path_extensions') 46 | if s:is_windows 47 | if exists('$PATHEXT') 48 | let pathext = $PATHEXT 49 | else 50 | " get default PATHEXT 51 | let pathext = matchstr(system('set pathext'), '\C^pathext=\zs.*\ze\n', 'i') 52 | endif 53 | let s:path_extensions = map(split(pathext, s:path_separator), 'tolower(v:val)') 54 | elseif s:is_cygwin 55 | " cygwin is not use $PATHEXT 56 | let s:path_extensions = ['', '.exe'] 57 | else 58 | let s:path_extensions = [''] 59 | endif 60 | endif 61 | return s:path_extensions 62 | endfunction 63 | 64 | " Convert all directory separators to "/". 65 | function! s:unify_separator(path) abort 66 | return substitute(a:path, s:path_sep_pattern, '/', 'g') 67 | endfunction 68 | 69 | " Get the full path of command. 70 | if exists('*exepath') 71 | function! s:which(str) abort 72 | return exepath(a:str) 73 | endfunction 74 | else 75 | function! s:which(command, ...) abort 76 | let pathlist = a:command =~# s:path_sep_pattern ? [''] : 77 | \ !a:0 ? split($PATH, s:path_separator) : 78 | \ type(a:1) == type([]) ? copy(a:1) : 79 | \ split(a:1, s:path_separator) 80 | 81 | let pathext = s:path_extensions() 82 | if index(pathext, '.' . tolower(fnamemodify(a:command, ':e'))) != -1 83 | let pathext = [''] 84 | endif 85 | 86 | let dirsep = s:separator() 87 | for dir in pathlist 88 | let head = dir ==# '' ? '' : dir . dirsep 89 | for ext in pathext 90 | let full = fnamemodify(head . a:command . ext, ':p') 91 | if filereadable(full) 92 | if s:is_case_tolerant() 93 | let full = glob(substitute( 94 | \ toupper(full), '\u:\@!', '[\0\L\0]', 'g'), 1) 95 | endif 96 | if full !=# '' 97 | return full 98 | endif 99 | endif 100 | endfor 101 | endfor 102 | 103 | return '' 104 | endfunction 105 | endif 106 | 107 | " Split the path with directory separator. 108 | " Note that this includes the drive letter of MS Windows. 109 | function! s:split(path) abort 110 | return split(a:path, s:path_sep_pattern) 111 | endfunction 112 | 113 | " Join the paths. 114 | " join('foo', 'bar') => 'foo/bar' 115 | " join('foo/', 'bar') => 'foo/bar' 116 | " join('/foo/', ['bar', 'buz/']) => '/foo/bar/buz/' 117 | function! s:join(...) abort 118 | let sep = s:separator() 119 | let path = '' 120 | for part in a:000 121 | let path .= sep . 122 | \ (type(part) is type([]) ? call('s:join', part) : 123 | \ part) 124 | unlet part 125 | endfor 126 | return substitute(path[1 :], s:path_sep_pattern, sep, 'g') 127 | endfunction 128 | 129 | " Check if the path is absolute path. 130 | if s:is_windows 131 | function! s:is_absolute(path) abort 132 | return a:path =~# '^[a-zA-Z]:[/\\]' 133 | endfunction 134 | else 135 | function! s:is_absolute(path) abort 136 | return a:path[0] ==# '/' 137 | endfunction 138 | endif 139 | 140 | function! s:is_relative(path) abort 141 | return !s:is_absolute(a:path) 142 | endfunction 143 | 144 | " Return the parent directory of the path. 145 | " NOTE: fnamemodify(path, ':h') does not return the parent directory 146 | " when path[-1] is the separator. 147 | function! s:dirname(path) abort 148 | let path = a:path 149 | let orig = a:path 150 | 151 | let path = s:remove_last_separator(path) 152 | if path ==# '' 153 | return orig " root directory 154 | endif 155 | 156 | let path = fnamemodify(path, ':h') 157 | return path 158 | endfunction 159 | 160 | " Return the basename of the path. 161 | " NOTE: fnamemodify(path, ':h') does not return basename 162 | " when path[-1] is the separator. 163 | function! s:basename(path) abort 164 | let path = a:path 165 | let orig = a:path 166 | 167 | let path = s:remove_last_separator(path) 168 | if path ==# '' 169 | return orig " root directory 170 | endif 171 | 172 | let path = fnamemodify(path, ':t') 173 | return path 174 | endfunction 175 | 176 | " Remove the separator at the end of a:path. 177 | function! s:remove_last_separator(path) abort 178 | let sep = s:separator() 179 | let pat = escape(sep, '\') . '\+$' 180 | return substitute(a:path, pat, '', '') 181 | endfunction 182 | 183 | 184 | " Return true if filesystem ignores alphabetic case of a filename. 185 | " Return false otherwise. 186 | function! s:is_case_tolerant() abort 187 | return s:is_case_tolerant 188 | endfunction 189 | 190 | 191 | function! s:abspath(path) abort 192 | if s:is_absolute(a:path) 193 | return a:path 194 | endif 195 | " Note: 196 | " the behavior of ':p' for non existing file path is not defined 197 | return filereadable(a:path) 198 | \ ? fnamemodify(a:path, ':p') 199 | \ : s:join(fnamemodify(getcwd(), ':p'), a:path) 200 | endfunction 201 | 202 | function! s:relpath(path) abort 203 | if s:is_relative(a:path) 204 | return a:path 205 | endif 206 | return fnamemodify(a:path, ':~:.') 207 | endfunction 208 | 209 | function! s:unixpath(path) abort 210 | return fnamemodify(a:path, ':gs?\\?/?') 211 | endfunction 212 | 213 | function! s:winpath(path) abort 214 | return fnamemodify(a:path, ':gs?/?\\?') 215 | endfunction 216 | 217 | if s:is_windows 218 | function! s:realpath(path) abort 219 | if exists('&shellslash') && &shellslash 220 | return s:unixpath(a:path) 221 | else 222 | return s:winpath(a:path) 223 | endif 224 | endfunction 225 | else 226 | function! s:realpath(path) abort 227 | return s:unixpath(a:path) 228 | endfunction 229 | endif 230 | 231 | if s:is_windows 232 | function! s:is_root_directory(path) abort 233 | return a:path =~# '^[a-zA-Z]:[/\\]$' 234 | endfunction 235 | else 236 | function! s:is_root_directory(path) abort 237 | return a:path ==# '/' 238 | endfunction 239 | endif 240 | 241 | function! s:contains(path, base) abort 242 | if a:path ==# '' || a:base ==# '' 243 | return 0 244 | endif 245 | let pathlist = s:split(a:path) 246 | let baselist = s:split(a:base) 247 | let pathlistlen = len(pathlist) 248 | let baselistlen = len(baselist) 249 | if pathlistlen < baselistlen 250 | return 0 251 | endif 252 | if baselistlen == 0 253 | return 1 254 | endif 255 | if s:is_case_tolerant 256 | call map(pathlist, 'tolower(v:val)') 257 | call map(baselist, 'tolower(v:val)') 258 | endif 259 | return pathlist[: baselistlen - 1] ==# baselist 260 | endfunction 261 | 262 | let &cpo = s:save_cpo 263 | unlet s:save_cpo 264 | 265 | " vim:set et ts=2 sts=2 sw=2 tw=0: 266 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Vim/SelectedText.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Vim#SelectedText#import() abort 6 | return map({'text': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Vim#SelectedText#import() abort', printf("return map({'text': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | "============================================================================= 17 | " FILE: autoload/vital/__vital__/Vim/SelectedText.vim 18 | " AUTHOR: haya14busa 19 | " License: MIT license 20 | "============================================================================= 21 | 22 | " text() returns selected text from begin to end. 23 | " 24 | " @param {'char'|'line'|'block'} wise 25 | " @return selected text 26 | function! s:text(wise, begin, end) abort 27 | let begin = a:begin 28 | let end = a:end 29 | if len(begin) > 3 30 | let begin = begin[1:2] 31 | endif 32 | if len(end) > 3 33 | let end = end[1:2] 34 | endif 35 | if s:_is_exclusive() && begin[1] !=# end[1] 36 | " Decrement column number for :set selection=exclusive 37 | let end[1] -= 1 38 | endif 39 | if a:wise !=# 'line' && begin ==# end 40 | let lines = [s:_get_pos_char(begin)] 41 | elseif a:wise ==# 'block' 42 | let [min_c, max_c] = s:_sort_num([begin[1], end[1]]) 43 | let lines = map(range(begin[0], end[0]), ' 44 | \ getline(v:val)[min_c - 1 : max_c - 1] 45 | \ ') 46 | elseif a:wise ==# 'line' 47 | let lines = getline(begin[0], end[0]) 48 | else 49 | if begin[0] ==# end[0] 50 | let lines = [getline(begin[0])[begin[1]-1 : end[1]-1]] 51 | else 52 | let lines = [getline(begin[0])[begin[1]-1 :]] 53 | \ + (end[0] - begin[0] < 2 ? [] : getline(begin[0]+1, end[0]-1)) 54 | \ + [getline(end[0])[: end[1]-1]] 55 | endif 56 | endif 57 | return join(lines, "\n") . (a:wise ==# 'line' ? "\n" : '') 58 | endfunction 59 | 60 | " @return Boolean 61 | function! s:_is_exclusive() abort 62 | return &selection is# 'exclusive' 63 | endfunction 64 | 65 | "" Return character at given position with multibyte handling. 66 | " 67 | " @arg [Number, Number] as coordinate 68 | " @return String 69 | function! s:_get_pos_char(pos) abort 70 | let [line, col] = a:pos 71 | return matchstr(getline(line), '.', col - 1) 72 | endfunction 73 | 74 | " 7.4.341 75 | " http://ftp.vim.org/vim/patches/7.4/7.4.341 76 | if v:version > 704 || v:version == 704 && has('patch341') 77 | function! s:_sort_num(xs) abort 78 | return sort(a:xs, 'n') 79 | endfunction 80 | else 81 | function! s:_sort_num_func(x, y) abort 82 | return a:x - a:y 83 | endfunction 84 | function! s:_sort_num(xs) abort 85 | return sort(a:xs, 's:_sort_num_func') 86 | endfunction 87 | endif 88 | 89 | " __END__ 90 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 91 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Web/URI.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Web#URI#import() abort 6 | return map({'decode': '', '_vital_depends': '', 'new_default_pattern_set': '', 'is_uri': '', 'new': '', 'clone_pattern_set': '', 'new_from_uri_like_string': '', 'new_from_seq_string': '', 'like_uri': '', 'encode': '', '_vital_loaded': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Web#URI#import() abort', printf("return map({'decode': '', '_vital_depends': '', 'new_default_pattern_set': '', 'is_uri': '', 'new': '', 'clone_pattern_set': '', 'new_from_uri_like_string': '', 'new_from_seq_string': '', 'like_uri': '', 'encode': '', '_vital_loaded': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | let s:save_cpo = &cpo 17 | set cpo&vim 18 | 19 | function! s:_vital_loaded(V) abort 20 | let s:V = a:V 21 | endfunction 22 | 23 | function! s:_vital_depends() abort 24 | return ['Web.URI.HTTP', 'Web.URI.HTTPS'] 25 | endfunction 26 | 27 | " NOTE: See s:DefaultPatternSet about the reason 28 | " why s:DefaultPatternSet is not deepcopy()ed here. 29 | function! s:new(uri, ...) abort 30 | let NothrowValue = get(a:000, 0, s:NONE) 31 | let pattern_set = get(a:000, 1, s:DefaultPatternSet) 32 | return s:_uri_new_sandbox( 33 | \ a:uri, 0, pattern_set, 0, NothrowValue) 34 | endfunction 35 | 36 | " NOTE: See s:DefaultPatternSet about the reason 37 | " why s:DefaultPatternSet is not deepcopy()ed here. 38 | function! s:new_from_uri_like_string(str, ...) abort 39 | let NothrowValue = get(a:000, 0, s:NONE) 40 | let pattern_set = get(a:000, 1, s:DefaultPatternSet) 41 | " Prepend http if no scheme. 42 | if a:str !~# '^' . pattern_set.get('scheme') . '://' 43 | let str = 'http://' . a:str 44 | else 45 | let str = a:str 46 | endif 47 | 48 | return s:_uri_new_sandbox( 49 | \ str, 0, pattern_set, 0, NothrowValue) 50 | endfunction 51 | 52 | " NOTE: See s:DefaultPatternSet about the reason 53 | " why s:DefaultPatternSet is not deepcopy()ed here. 54 | function! s:new_from_seq_string(uri, ...) abort 55 | let NothrowValue = get(a:000, 0, s:NONE) 56 | let pattern_set = get(a:000, 1, s:DefaultPatternSet) 57 | return s:_uri_new_sandbox( 58 | \ a:uri, 1, pattern_set, 1, NothrowValue) 59 | endfunction 60 | 61 | function! s:is_uri(str) abort 62 | let ERROR = [] 63 | return s:new(a:str, ERROR) isnot ERROR 64 | endfunction 65 | 66 | function! s:like_uri(str) abort 67 | let ERROR = [] 68 | return s:new_from_uri_like_string(a:str, ERROR) isnot ERROR 69 | endfunction 70 | 71 | function! s:encode(str, ...) abort 72 | let encoding = a:0 ? a:1 : 'utf-8' 73 | if encoding ==# '' 74 | let str = a:str 75 | else 76 | let str = iconv(a:str, &encoding, encoding) 77 | endif 78 | 79 | let result = '' 80 | for i in range(len(str)) 81 | if str[i] =~# '^[a-zA-Z0-9_.~-]$' 82 | let result .= str[i] 83 | else 84 | let result .= printf('%%%02X', char2nr(str[i])) 85 | endif 86 | endfor 87 | return result 88 | endfunction 89 | 90 | function! s:decode(str, ...) abort 91 | let result = substitute(a:str, '%\(\x\x\)', 92 | \ '\=printf("%c", str2nr(submatch(1), 16))', 'g') 93 | 94 | let encoding = a:0 ? a:1 : 'utf-8' 95 | if encoding ==# '' 96 | return result 97 | endif 98 | return iconv(result, encoding, &encoding) 99 | endfunction 100 | 101 | 102 | let s:NONE = [] 103 | 104 | function! s:_uri_new_sandbox(uri, ignore_rest, pattern_set, retall, NothrowValue) abort 105 | try 106 | let results = call('s:_uri_new', [a:uri, a:ignore_rest, a:pattern_set]) 107 | return a:retall ? results : results[0] 108 | catch 109 | if a:NothrowValue isnot s:NONE && s:_is_own_exception(v:exception) 110 | return a:NothrowValue 111 | else 112 | let ex = substitute(v:exception, '^Vim([^()]\+):', '', '') 113 | throw 'vital: Web.URI: ' . ex . ' @ ' . v:throwpoint 114 | \ . ' (original URI: ' . a:uri . ')' 115 | endif 116 | endtry 117 | endfunction 118 | 119 | function! s:_is_own_exception(str) abort 120 | return a:str =~# '^uri parse error\%(([^)]\+)\)\?:' 121 | endfunction 122 | 123 | 124 | " ================ Parsing Functions ================ 125 | 126 | " @return instance of s:URI . 127 | " 128 | " TODO: Support punycode 129 | " 130 | " Quoted the outline of RFC3986 here. 131 | " RFC3986: http://tools.ietf.org/html/rfc3986 132 | " 133 | " URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] 134 | " authority = [ userinfo "@" ] host [ ":" port ] 135 | function! s:_parse_uri(str, ignore_rest, pattern_set) abort 136 | let rest = a:str 137 | 138 | " Ignore leading/trailing whitespaces. 139 | let rest = substitute(rest, '^\s\+', '', '') 140 | let rest = substitute(rest, '\s\+$', '', '') 141 | 142 | " scheme 143 | let [scheme, rest] = s:_eat_scheme(rest, a:pattern_set) 144 | 145 | " hier-part 146 | let [hier_part, rest] = s:_eat_hier_part(rest, a:pattern_set) 147 | 148 | " query 149 | if rest[0] ==# '?' 150 | let [query, rest] = s:_eat_query(rest[1:], a:pattern_set) 151 | else 152 | let query = '' 153 | endif 154 | 155 | " fragment 156 | if rest[0] ==# '#' 157 | let [fragment, rest] = s:_eat_fragment(rest[1:], a:pattern_set) 158 | else 159 | let fragment = '' 160 | endif 161 | 162 | if !a:ignore_rest && rest !=# '' 163 | throw 'uri parse error: unnecessary string at the end.' 164 | endif 165 | 166 | let obj = deepcopy(s:URI) 167 | let obj.__scheme = scheme 168 | let obj.__userinfo = hier_part.userinfo 169 | let obj.__host = hier_part.host 170 | let obj.__port = hier_part.port 171 | let obj.__path = hier_part.path 172 | " NOTE: obj.__query must not have "?" as prefix. 173 | let obj.__query = substitute(query, '^?', '', '') 174 | " NOTE: obj.__fragment must not have "#" as prefix. 175 | let obj.__fragment = substitute(fragment, '^#', '', '') 176 | let obj.__pattern_set = a:pattern_set 177 | let obj.__handler = s:_get_handler_module(scheme, obj) 178 | return [obj, rest] 179 | endfunction 180 | 181 | function! s:_get_handler_module(scheme, uriobj) abort 182 | if a:scheme ==# '' 183 | return {} 184 | endif 185 | let name = 'Web.URI.' . toupper(a:scheme) 186 | if !s:V.exists(name) 187 | return {} 188 | endif 189 | return s:V.import(name) 190 | endfunction 191 | 192 | function! s:_eat_em(str, pat, ...) abort 193 | let pat = a:pat.'\C' 194 | let m = matchlist(a:str, pat) 195 | if empty(m) 196 | let prefix = printf('uri parse error%s: ', (a:0 ? '('.a:1.')' : '')) 197 | let msg = printf("can't parse '%s' with '%s'.", a:str, pat) 198 | throw prefix . msg 199 | endif 200 | let rest = strpart(a:str, strlen(m[0])) 201 | return [m[0], rest] 202 | endfunction 203 | 204 | " hier-part = "//" authority path-abempty 205 | " / path-absolute 206 | " / path-noscheme 207 | " / path-rootless 208 | " / path-empty 209 | function! s:_eat_hier_part(rest, pattern_set) abort 210 | let rest = a:rest 211 | if rest =~# '^://' 212 | " authority 213 | let rest = rest[3:] 214 | let [authority, rest] = s:_eat_authority(rest, a:pattern_set) 215 | let userinfo = authority.userinfo 216 | let host = authority.host 217 | let port = authority.port 218 | " path 219 | let [path, rest] = s:_eat_path_abempty(rest, a:pattern_set) 220 | elseif rest =~# ':' 221 | let rest = rest[1:] 222 | let userinfo = '' 223 | let host = '' 224 | let port = '' 225 | " path 226 | if rest =~# '^/[^/]' " begins with '/' but not '//' 227 | let [path, rest] = s:_eat_path_absolute(rest, a:pattern_set) 228 | elseif rest =~# '^[^:]' " begins with a non-colon segment 229 | let [path, rest] = s:_eat_path_noscheme(rest, a:pattern_set) 230 | elseif rest =~# a:pattern_set.segment_nz() " begins with a segment 231 | let [path, rest] = s:_eat_path_rootless(rest, a:pattern_set) 232 | elseif rest ==# '' || rest =~# '^[?#]' " zero characters 233 | let path = '' 234 | else 235 | throw printf("uri parse error(hier-part): can't parse '%s'.", rest) 236 | endif 237 | else 238 | throw printf("uri parse error(hier-part): can't parse '%s'.", rest) 239 | endif 240 | return [{ 241 | \ 'userinfo': userinfo, 242 | \ 'host': host, 243 | \ 'port': port, 244 | \ 'path': path, 245 | \}, rest] 246 | endfunction 247 | 248 | function! s:_eat_authority(str, pattern_set) abort 249 | let rest = a:str 250 | " authority(userinfo) 251 | try 252 | let oldrest = rest 253 | let [userinfo, rest] = s:_eat_userinfo(rest, a:pattern_set) 254 | let rest = s:_eat_em(rest, '^@')[1] 255 | catch 256 | let rest = oldrest 257 | let userinfo = '' 258 | endtry 259 | " authority(host) 260 | let [host, rest] = s:_eat_host(rest, a:pattern_set) 261 | " authority(port) 262 | if rest[0] ==# ':' 263 | let [port, rest] = s:_eat_port(rest[1:], a:pattern_set) 264 | else 265 | let port = '' 266 | endif 267 | return [{ 268 | \ 'userinfo': userinfo, 269 | \ 'host': host, 270 | \ 'port': port, 271 | \}, rest] 272 | endfunction 273 | 274 | " NOTE: More s:_eat_*() functions are defined by s:_create_eat_functions(). 275 | " =============== Parsing Functions =============== 276 | 277 | 278 | " ===================== s:URI ===================== 279 | 280 | function! s:_uri_new(str, ignore_rest, pattern_set) abort 281 | let [obj, rest] = s:_parse_uri(a:str, a:ignore_rest, a:pattern_set) 282 | if a:ignore_rest 283 | let original_url = a:str[: len(a:str)-len(rest)-1] 284 | return [obj, original_url, rest] 285 | else 286 | return [obj, a:str, ''] 287 | endif 288 | endfunction 289 | 290 | function! s:_uri_scheme(...) dict abort 291 | if a:0 292 | if self.is_scheme(a:1) 293 | let self.__scheme = a:1 294 | return self 295 | else 296 | throw 'vital: Web.URI: scheme(): ' 297 | \ . 'invalid argument (' . string(a:1) . ')' 298 | endif 299 | endif 300 | return self.__scheme 301 | endfunction 302 | 303 | function! s:_uri_userinfo(...) dict abort 304 | if a:0 305 | if self.is_userinfo(a:1) 306 | let self.__userinfo = a:1 307 | return self 308 | else 309 | throw 'vital: Web.URI: userinfo(): ' 310 | \ . 'invalid argument (' . string(a:1) . ')' 311 | endif 312 | endif 313 | return self.__userinfo 314 | endfunction 315 | 316 | function! s:_uri_host(...) dict abort 317 | if a:0 318 | if self.is_host(a:1) 319 | let self.__host = a:1 320 | return self 321 | else 322 | throw 'vital: Web.URI: host(): ' 323 | \ . 'invalid argument (' . string(a:1) . ')' 324 | endif 325 | endif 326 | return self.__host 327 | endfunction 328 | 329 | function! s:_uri_port(...) dict abort 330 | if a:0 331 | if type(a:1) ==# type(0) 332 | let self.__port = '' . a:1 333 | return self 334 | elseif type(a:1) ==# type('') && self.is_port(a:1) 335 | let self.__port = a:1 336 | return self 337 | else 338 | throw 'vital: Web.URI: port(): ' 339 | \ . 'invalid argument (' . string(a:1) . ')' 340 | endif 341 | endif 342 | return self.__port 343 | endfunction 344 | 345 | function! s:_uri_path(...) dict abort 346 | if a:0 347 | if self.is_path(a:1) 348 | let self.__path = a:1 349 | return self 350 | else 351 | throw 'vital: Web.URI: path(): ' 352 | \ . 'invalid argument (' . string(a:1) . ')' 353 | endif 354 | endif 355 | return self.__path 356 | endfunction 357 | 358 | function! s:_uri_authority(...) dict abort 359 | if a:0 360 | " TODO 361 | throw 'vital: Web.URI: uri.authority(value) does not support yet.' 362 | endif 363 | return 364 | \ (self.__userinfo !=# '' ? self.__userinfo . '@' : '') 365 | \ . self.__host 366 | \ . (self.__port !=# '' ? ':' . self.__port : '') 367 | endfunction 368 | 369 | function! s:_uri_opaque(...) dict abort 370 | if a:0 371 | " TODO 372 | throw 'vital: Web.URI: uri.opaque(value) does not support yet.' 373 | endif 374 | return printf('//%s%s', 375 | \ self.authority(), 376 | \ self.__path) 377 | endfunction 378 | 379 | function! s:_uri_query(...) dict abort 380 | if a:0 381 | " NOTE: self.__query must not have "?" as prefix. 382 | let query = substitute(a:1, '^?', '', '') 383 | if self.is_query(query) 384 | let self.__query = query 385 | return self 386 | else 387 | throw 'vital: Web.URI: query(): ' 388 | \ . 'invalid argument (' . string(a:1) . ')' 389 | endif 390 | endif 391 | return self.__query 392 | endfunction 393 | 394 | function! s:_uri_fragment(...) dict abort 395 | if a:0 396 | " NOTE: self.__fragment must not have "#" as prefix. 397 | let fragment = substitute(a:1, '^#', '', '') 398 | if self.is_fragment(fragment) 399 | let self.__fragment = fragment 400 | return self 401 | else 402 | throw 'vital: Web.URI: fragment(): ' 403 | \ . 'invalid argument (' . string(a:1) . ')' 404 | endif 405 | endif 406 | return self.__fragment 407 | endfunction 408 | 409 | function! s:_uri_canonicalize() dict abort 410 | call s:_call_handler_method(self, 'canonicalize', []) 411 | return self 412 | endfunction 413 | 414 | function! s:_uri_default_port() dict abort 415 | return s:_call_handler_method(self, 'default_port', []) 416 | endfunction 417 | 418 | function! s:_call_handler_method(this, name, args) abort 419 | if empty(a:this.__handler) 420 | throw 'vital: Web.URI: ' . a:name . '(): ' 421 | \ . "Handler was not found for scheme '" . a:this.__scheme . "'." 422 | endif 423 | return call(a:this.__handler[a:name], [a:this] + a:args) 424 | endfunction 425 | 426 | function! s:_uri_clone() dict abort 427 | return deepcopy(self) 428 | endfunction 429 | 430 | function! s:_uri_relative(relstr) dict abort 431 | call self.canonicalize() 432 | let relobj = s:_parse_relative_ref(a:relstr, self.__pattern_set) 433 | call s:_resolve_relative(self, relobj) 434 | return self 435 | endfunction 436 | 437 | " @seealso s:_parse_uri() 438 | " 439 | " URI-reference = URI / relative-ref 440 | " relative-ref = relative-part [ "?" query ] [ "#" fragment ] 441 | function! s:_parse_relative_ref(relstr, pattern_set) abort 442 | " relative-part 443 | let [relpart, rest] = s:_parse_relative_part(a:relstr, a:pattern_set) 444 | " query 445 | if rest[0] ==# '?' 446 | let [query, rest] = s:_eat_query(rest[1:], a:pattern_set) 447 | else 448 | let query = '' 449 | endif 450 | " fragment 451 | if rest[0] ==# '#' 452 | let [fragment, rest] = s:_eat_fragment(rest[1:], a:pattern_set) 453 | else 454 | let fragment = '' 455 | endif 456 | " no trailing string allowed. 457 | if rest !=# '' 458 | throw 'uri parse error(relative-ref): unnecessary string at the end.' 459 | endif 460 | 461 | let obj = deepcopy(s:URI) 462 | let obj.__pattern_set = s:clone_pattern_set(a:pattern_set) 463 | let obj.__scheme = '' 464 | let obj.__userinfo = relpart.userinfo 465 | let obj.__host = relpart.host 466 | let obj.__port = relpart.port 467 | let obj.__path = relpart.path 468 | " NOTE: obj.__query must not have "?" as prefix. 469 | let obj.__query = substitute(query, '^?', '', '') 470 | " NOTE: obj.__fragment must not have "#" as prefix. 471 | let obj.__fragment = substitute(fragment, '^#', '', '') 472 | return obj 473 | endfunction 474 | 475 | " @seealso s:_eat_hier_part() 476 | " 477 | " relative-part = "//" authority path-abempty 478 | " / path-absolute 479 | " / path-noscheme 480 | " / path-empty 481 | function! s:_parse_relative_part(rel_uri, pattern_set) abort 482 | let rest = a:rel_uri 483 | if rest =~# '^//' 484 | " authority 485 | let rest = rest[2:] 486 | let [authority, rest] = s:_eat_authority(rest, a:pattern_set) 487 | let userinfo = authority.userinfo 488 | let host = authority.host 489 | let port = authority.port 490 | " path 491 | let [path, rest] = s:_eat_path_abempty(rest, a:pattern_set) 492 | else 493 | let userinfo = '' 494 | let host = '' 495 | let port = '' 496 | " path 497 | if rest =~# '^/[^/]' " begins with '/' but not '//' 498 | let [path, rest] = s:_eat_path_absolute(rest, a:pattern_set) 499 | elseif rest =~# '^[^:]' " begins with a non-colon segment 500 | let [path, rest] = s:_eat_path_noscheme(rest, a:pattern_set) 501 | elseif rest ==# '' || rest =~# '^[?#]' " zero characters 502 | let path = '' 503 | else 504 | throw printf("uri parse error(relative-part): can't parse '%s'.", rest) 505 | endif 506 | endif 507 | return [{ 508 | \ 'userinfo': userinfo, 509 | \ 'host': host, 510 | \ 'port': port, 511 | \ 'path': path, 512 | \}, rest] 513 | endfunction 514 | 515 | " https://tools.ietf.org/html/rfc3986#section-5.2.2 516 | function! s:_resolve_relative(obj, relobj) abort 517 | if a:relobj.__scheme !=# '' 518 | let a:obj.__scheme = a:relobj.__scheme 519 | let a:obj.__userinfo = a:relobj.__userinfo 520 | let a:obj.__host = a:relobj.__host 521 | let a:obj.__port = a:relobj.__port 522 | let a:obj.__path = s:_remove_dot_segments(a:relobj.__path) 523 | let a:obj.__query = a:relobj.__query 524 | else 525 | if a:relobj.authority() !=# '' 526 | let a:obj.__userinfo = a:relobj.__userinfo 527 | let a:obj.__host = a:relobj.__host 528 | let a:obj.__port = a:relobj.__port 529 | let a:obj.__path = a:relobj.__path 530 | let a:obj.__query = a:relobj.__query 531 | else 532 | if a:relobj.__path ==# '' 533 | if a:relobj.__query !=# '' 534 | let a:obj.__query = a:relobj.__query 535 | endif 536 | else 537 | if a:relobj.__path[0] ==# '/' 538 | let a:obj.__path = s:_remove_dot_segments(a:relobj.__path) 539 | else 540 | let a:obj.__path = s:_merge_paths(a:obj, a:relobj) 541 | let a:obj.__path = s:_remove_dot_segments(a:obj.__path) 542 | endif 543 | let a:obj.__query = a:relobj.__query 544 | endif 545 | endif 546 | endif 547 | let a:obj.__fragment = a:relobj.__fragment 548 | endfunction 549 | 550 | " Merge base URI and relative URI. 551 | " 552 | " 5.2.3. Merge Paths 553 | " https://tools.ietf.org/html/rfc3986#section-5.2.3 554 | function! s:_merge_paths(baseobj, relobj) abort 555 | if a:baseobj.authority() !=# '' && a:baseobj.__path ==# '' 556 | return a:relobj.__path 557 | else 558 | return substitute(a:baseobj.__path, '/\zs[^/]\+$', '', '') 559 | \ . a:relobj.__path 560 | endif 561 | endfunction 562 | 563 | " Remove '.' or '..' in a:path. 564 | " Trailing '.' or '..' leaves '/' at the end. 565 | " e.g.: 566 | " base: http://example.com/a/b/c 567 | " rel: d/. 568 | " result: http://example.com/a/b/d/ 569 | " 570 | " 5.2.4. Remove Dot Segments 571 | " https://tools.ietf.org/html/rfc3986#section-5.2.4 572 | function! s:_remove_dot_segments(path) abort 573 | " Get rid of continuous '/'. 574 | " May exist empty string because of starting/trailing '/'. 575 | let paths = split(a:path, '/\+', 1) 576 | let i = 0 577 | while i < len(paths) 578 | if paths[i] ==# '.' 579 | call remove(paths, i) 580 | if i >=# len(paths) 581 | call add(paths, '') 582 | endif 583 | elseif paths[i] ==# '..' 584 | call remove(paths, i) 585 | " except starting '/..' or '..' 586 | if !empty(paths) && i > 0 && paths[i-1] !=# '' 587 | call remove(paths, i-1) 588 | let i -= 1 589 | endif 590 | if i >=# len(paths) 591 | call add(paths, '') 592 | endif 593 | else 594 | let i += 1 595 | endif 596 | endwhile 597 | return join(paths, '/') 598 | endfunction 599 | 600 | function! s:_uri_to_iri(...) dict abort 601 | " Same as uri.to_string(), but do unescape for self.__path. 602 | return printf( 603 | \ '%s://%s%s%s%s', 604 | \ self.__scheme, 605 | \ self.authority(), 606 | \ call('s:decode', [self.__path] + (a:0 ? [a:1] : [])), 607 | \ (self.__query !=# '' ? '?' . self.__query : ''), 608 | \ (self.__fragment !=# '' ? '#' . self.__fragment : ''), 609 | \) 610 | endfunction 611 | 612 | function! s:_uri_to_string() dict abort 613 | return printf( 614 | \ '%s://%s%s%s%s', 615 | \ self.__scheme, 616 | \ self.authority(), 617 | \ self.__path, 618 | \ (self.__query !=# '' ? '?' . self.__query : ''), 619 | \ (self.__fragment !=# '' ? '#' . self.__fragment : ''), 620 | \) 621 | endfunction 622 | 623 | 624 | let s:FUNCTION_DESCS = [ 625 | \ 'scheme', 'userinfo', 'host', 626 | \ 'port', 'path', 'path_abempty', 627 | \ 'path_absolute', 'path_noscheme', 628 | \ 'path_rootless', 629 | \ 'query', 'fragment' 630 | \] 631 | 632 | " Create s:_eat_*() functions. 633 | function! s:_create_eat_functions() abort 634 | for where in s:FUNCTION_DESCS 635 | execute join([ 636 | \ 'function! s:_eat_'.where.'(str, pattern_set) abort', 637 | \ 'return s:_eat_em(a:str, "^" . a:pattern_set.get('.string(where).'), '.string(where).')', 638 | \ 'endfunction', 639 | \], "\n") 640 | endfor 641 | endfunction 642 | call s:_create_eat_functions() 643 | 644 | " Create s:_uri_is_*() functions. 645 | function! s:_has_error(func, args) abort 646 | try 647 | call call(a:func, a:args) 648 | return 0 649 | catch 650 | return 1 651 | endtry 652 | endfunction 653 | function! s:_create_check_functions() abort 654 | for where in s:FUNCTION_DESCS 655 | execute join([ 656 | \ 'function! s:_uri_is_'.where.'(str) dict abort', 657 | \ 'return !s:_has_error("s:_eat_'.where.'", [a:str, self.__pattern_set])', 658 | \ 'endfunction', 659 | \], "\n") 660 | endfor 661 | endfunction 662 | call s:_create_check_functions() 663 | 664 | 665 | function! s:_local_func(name) abort 666 | let sid = matchstr(expand(''), '\zs\d\+\ze__local_func$') 667 | return function('' . sid . '_' . a:name) 668 | endfunction 669 | 670 | let s:URI = { 671 | \ '__scheme': '', 672 | \ '__userinfo': '', 673 | \ '__host': '', 674 | \ '__port': '', 675 | \ '__path': '', 676 | \ '__query': '', 677 | \ '__fragment': '', 678 | \ 679 | \ '__pattern_set': {}, 680 | \ 681 | \ 'scheme': s:_local_func('_uri_scheme'), 682 | \ 'userinfo': s:_local_func('_uri_userinfo'), 683 | \ 'host': s:_local_func('_uri_host'), 684 | \ 'port': s:_local_func('_uri_port'), 685 | \ 'path': s:_local_func('_uri_path'), 686 | \ 'authority': s:_local_func('_uri_authority'), 687 | \ 'opaque': s:_local_func('_uri_opaque'), 688 | \ 'query': s:_local_func('_uri_query'), 689 | \ 'fragment': s:_local_func('_uri_fragment'), 690 | \ 691 | \ 'clone': s:_local_func('_uri_clone'), 692 | \ 'relative': s:_local_func('_uri_relative'), 693 | \ 'canonicalize': s:_local_func('_uri_canonicalize'), 694 | \ 'default_port': s:_local_func('_uri_default_port'), 695 | \ 696 | \ 'to_iri': s:_local_func('_uri_to_iri'), 697 | \ 'to_string': s:_local_func('_uri_to_string'), 698 | \ 699 | \ 'is_scheme': s:_local_func('_uri_is_scheme'), 700 | \ 'is_userinfo': s:_local_func('_uri_is_userinfo'), 701 | \ 'is_host': s:_local_func('_uri_is_host'), 702 | \ 'is_port': s:_local_func('_uri_is_port'), 703 | \ 'is_path': s:_local_func('_uri_is_path'), 704 | \ 'is_query': s:_local_func('_uri_is_query'), 705 | \ 'is_fragment': s:_local_func('_uri_is_fragment'), 706 | \} 707 | 708 | " ===================== s:URI ===================== 709 | 710 | 711 | " ================= s:DefaultPatternSet ================== 712 | " s:DefaultPatternSet: Default patterns for URI syntax 713 | " 714 | " @seealso http://tools.ietf.org/html/rfc3986 715 | 716 | " s:new*() methods do not create new copy of s:DefaultPatternSet 717 | " Thus it shares this instance also cache. 718 | " But it is no problem because of the following reasons. 719 | " 1. Each component's return value doesn't change 720 | " unless it is overriden by a user. but... 721 | " 2. s:DefaultPatternSet can't be accessed by a user. 722 | let s:DefaultPatternSet = {'_cache': {}} 723 | 724 | function! s:new_default_pattern_set() abort 725 | return s:clone_pattern_set(s:DefaultPatternSet) 726 | endfunction 727 | 728 | function! s:clone_pattern_set(pattern_set) abort 729 | let pattern_set = deepcopy(a:pattern_set) 730 | let pattern_set._cache = {} 731 | return pattern_set 732 | endfunction 733 | 734 | " Memoize 735 | function! s:DefaultPatternSet.get(component, ...) abort 736 | if has_key(self._cache, a:component) 737 | return self._cache[a:component] 738 | endif 739 | let ret = call(self[a:component], a:000, self) 740 | let self._cache[a:component] = ret 741 | return ret 742 | endfunction 743 | 744 | " unreserved = ALPHA / DIGIT / "." / "_" / "~" / "-" 745 | function! s:DefaultPatternSet.unreserved() abort 746 | return '[[:alpha:]0-9._~-]' 747 | endfunction 748 | " pct-encoded = "%" HEXDIG HEXDIG 749 | function! s:DefaultPatternSet.pct_encoded() abort 750 | return '%\x\x' 751 | endfunction 752 | " sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 753 | " / "*" / "+" / "," / ";" / "=" 754 | function! s:DefaultPatternSet.sub_delims() abort 755 | return '[!$&''()*+,;=]' 756 | endfunction 757 | " dec-octet = DIGIT ; 0-9 758 | " / %x31-39 DIGIT ; 10-99 759 | " / "1" 2DIGIT ; 100-199 760 | " / "2" %x30-34 DIGIT ; 200-249 761 | " / "25" %x30-35 ; 250-255 762 | function! s:DefaultPatternSet.dec_octet() abort 763 | return '\%(1[0-9][0-9]\|2[0-4][0-9]\|25[0-5]\|[1-9][0-9]\|[0-9]\)' 764 | endfunction 765 | " IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet 766 | function! s:DefaultPatternSet.ipv4address() abort 767 | return self.dec_octet() . '\.' . self.dec_octet() 768 | \ . '\.' . self.dec_octet() . '\.' . self.dec_octet() 769 | endfunction 770 | " IPv6address = 6( h16 ":" ) ls32 771 | " / "::" 5( h16 ":" ) ls32 772 | " / [ h16 ] "::" 4( h16 ":" ) ls32 773 | " / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 774 | " / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 775 | " / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 776 | " / [ *4( h16 ":" ) h16 ] "::" ls32 777 | " / [ *5( h16 ":" ) h16 ] "::" h16 778 | " / [ *6( h16 ":" ) h16 ] "::" 779 | " 780 | " NOTE: Using repeat() in some parts because 781 | " can't use /\{ at most 10 in whole regexp. 782 | " https://github.com/vim/vim/blob/cde885473099296c4837de261833f48b24caf87c/src/regexp.c#L1884 783 | function! s:DefaultPatternSet.ipv6address() abort 784 | return '\%(' . join([ 785 | \ (repeat('\%(' . self.h16() . ':\)', 6) . self.ls32()), 786 | \ ('::' . repeat('\%(' . self.h16() . ':\)', 5) . self.ls32()), 787 | \ ('\%(' . self.h16() . '\)\?::' 788 | \ . repeat('\%(' . self.h16() . ':\)', 4) . self.ls32()), 789 | \ ('\%(\%(' . self.h16() . ':\)\?' . self.h16() . '\)\?::' 790 | \ . repeat('\%(' . self.h16() . ':\)', 3) . self.ls32()), 791 | \ ('\%(\%(' . self.h16() . ':\)\{,2}' . self.h16() . '\)\?::' 792 | \ . repeat('\%(' . self.h16() . ':\)', 2) . self.ls32()), 793 | \ ('\%(\%(' . self.h16() . ':\)\{,3}' . self.h16() . '\)\?::' 794 | \ . self.h16() . ':' . self.ls32()), 795 | \ ('\%(\%(' . self.h16() . ':\)\{,4}' . self.h16() . '\)\?::' . self.ls32()), 796 | \ ('\%(\%(' . self.h16() . ':\)\{,5}' . self.h16() . '\)\?::' . self.h16()), 797 | \ ('\%(\%(' . self.h16() . ':\)\{,6}' . self.h16() . '\)\?::') 798 | \], '\|') . '\)' 799 | endfunction 800 | " h16 = 1*4HEXDIG 801 | " ; 16 bits of address represented in hexadecimal 802 | function! s:DefaultPatternSet.h16() abort 803 | return '\x\{1,4}' 804 | endfunction 805 | " ls32 = ( h16 ":" h16 ) / IPv4address 806 | " ; least-significant 32 bits of address 807 | function! s:DefaultPatternSet.ls32() abort 808 | return '\%(' . self.h16() . ':' . self.h16() 809 | \ . '\|' . self.ipv4address() . '\)' 810 | endfunction 811 | " IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) 812 | function! s:DefaultPatternSet.ipv_future() abort 813 | return 'v\x\+\.' 814 | \ . '\%(' . join([self.unreserved(), 815 | \ self.sub_delims(), ':'], '\|') . '\)\+' 816 | endfunction 817 | " IP-Literal = "[" ( IPv6address / IPvFuture ) "]" 818 | function! s:DefaultPatternSet.ip_literal() abort 819 | return '\[\%(' . self.ipv6address() . '\|' . self.ipv_future() . '\)\]' 820 | endfunction 821 | " reg-name = *( unreserved / pct-encoded / sub-delims ) 822 | function! s:DefaultPatternSet.reg_name() abort 823 | return '\%(' . join([self.unreserved(), self.pct_encoded(), 824 | \ self.sub_delims()], '\|') . '\)*' 825 | endfunction 826 | " pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 827 | function! s:DefaultPatternSet.pchar() abort 828 | return '\%(' . join([self.unreserved(), self.pct_encoded(), 829 | \ self.sub_delims(), ':', '@'], '\|') . '\)' 830 | endfunction 831 | " segment = *pchar 832 | function! s:DefaultPatternSet.segment() abort 833 | return self.pchar() . '*' 834 | endfunction 835 | " segment-nz = 1*pchar 836 | function! s:DefaultPatternSet.segment_nz() abort 837 | return self.pchar() . '\+' 838 | endfunction 839 | " segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) 840 | " ; non-zero-length segment without any colon ":" 841 | function! s:DefaultPatternSet.segment_nz_nc() abort 842 | return '\%(' . join([self.unreserved(), self.pct_encoded(), 843 | \ self.sub_delims(), '@'], '\|') . '\)\+' 844 | endfunction 845 | " path-abempty = *( "/" segment ) 846 | function! s:DefaultPatternSet.path_abempty() abort 847 | return '\%(/' . self.segment() . '\)*' 848 | endfunction 849 | " path-absolute = "/" [ segment-nz *( "/" segment ) ] 850 | function! s:DefaultPatternSet.path_absolute() abort 851 | return '/\%(' . self.segment_nz() . '\%(/' . self.segment() . '\)*\)\?' 852 | endfunction 853 | " path-noscheme = segment-nz-nc *( "/" segment ) 854 | function! s:DefaultPatternSet.path_noscheme() abort 855 | return self.segment_nz_nc() . '\%(/' . self.segment() . '\)*' 856 | endfunction 857 | " path-rootless = segment-nz *( "/" segment ) 858 | function! s:DefaultPatternSet.path_rootless() abort 859 | return self.segment_nz() . '\%(/' . self.segment() . '\)*' 860 | endfunction 861 | 862 | " scheme = ALPHA *( ALPHA / DIGIT / "+" / "." / "-" ) 863 | function! s:DefaultPatternSet.scheme() abort 864 | return '[[:alpha:]][[:alpha:]0-9+.-]*' 865 | endfunction 866 | " userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) 867 | function! s:DefaultPatternSet.userinfo() abort 868 | return '\%(' . join([self.unreserved(), self.pct_encoded(), 869 | \ self.sub_delims(), ':'], '\|') . '\)*' 870 | endfunction 871 | " host = IP-literal / IPv4address / reg-name 872 | function! s:DefaultPatternSet.host() abort 873 | return '\%(' . join([self.ip_literal(), self.ipv4address(), 874 | \ self.reg_name()], '\|') . '\)' 875 | endfunction 876 | " port = *DIGIT 877 | function! s:DefaultPatternSet.port() abort 878 | return '[0-9]*' 879 | endfunction 880 | " path = path-abempty ; begins with "/" or is empty 881 | " / path-absolute ; begins with "/" but not "//" 882 | " / path-noscheme ; begins with a non-colon segment 883 | " / path-rootless ; begins with a segment 884 | " / path-empty ; zero characters 885 | function! s:DefaultPatternSet.path() abort 886 | return '\%(' . join([self.path_abempty(), self.path_absolute(), 887 | \ self.path_noscheme(), self.path_rootless(), 888 | \ ''], '\|') . '\)' 889 | endfunction 890 | " query = *( pchar / "/" / "?" ) 891 | function! s:DefaultPatternSet.query() abort 892 | return '\%(' . join([self.pchar(), '/', '?'], '\|') . '\)*' 893 | endfunction 894 | " fragment = *( pchar / "/" / "?" ) 895 | function! s:DefaultPatternSet.fragment() abort 896 | return '\%(' . join([self.pchar(), '/', '?'], '\|') . '\)*' 897 | endfunction 898 | 899 | " ================= s:DefaultPatternSet ================== 900 | 901 | " vim:set et ts=2 sts=2 sw=2 tw=0:fen: 902 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Web/URI/HTTP.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Web#URI#HTTP#import() abort 6 | return map({'canonicalize': '', 'default_port': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Web#URI#HTTP#import() abort', printf("return map({'canonicalize': '', 'default_port': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | let s:save_cpo = &cpo 17 | set cpo&vim 18 | 19 | " The following four URIs are equivalent: 20 | " * http://example.com 21 | " * http://example.com/ 22 | " * http://example.com:/ 23 | " * http://example.com:80/ 24 | " 25 | " https://tools.ietf.org/html/rfc3986#section-6.2.3 26 | function! s:canonicalize(uriobj) abort 27 | if a:uriobj.path() ==# '' 28 | call a:uriobj.path('/') 29 | endif 30 | if a:uriobj.port() ==# a:uriobj.default_port() 31 | call a:uriobj.port('') 32 | endif 33 | endfunction 34 | 35 | function! s:default_port(uriobj) abort 36 | return '80' 37 | endfunction 38 | 39 | " vim:set et ts=2 sts=2 sw=2 tw=0:fen: 40 | -------------------------------------------------------------------------------- /autoload/vital/_opengoogletranslate/Web/URI/HTTPS.vim: -------------------------------------------------------------------------------- 1 | " ___vital___ 2 | " NOTE: lines between '" ___vital___' is generated by :Vitalize. 3 | " Do not mofidify the code nor insert new lines before '" ___vital___' 4 | if v:version > 703 || v:version == 703 && has('patch1170') 5 | function! vital#_opengoogletranslate#Web#URI#HTTPS#import() abort 6 | return map({'canonicalize': '', '_vital_depends': '', 'default_port': '', '_vital_loaded': ''}, 'function("s:" . v:key)') 7 | endfunction 8 | else 9 | function! s:_SID() abort 10 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 11 | endfunction 12 | execute join(['function! vital#_opengoogletranslate#Web#URI#HTTPS#import() abort', printf("return map({'canonicalize': '', '_vital_depends': '', 'default_port': '', '_vital_loaded': ''}, \"function('%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") 13 | delfunction s:_SID 14 | endif 15 | " ___vital___ 16 | let s:save_cpo = &cpo 17 | set cpo&vim 18 | 19 | let s:HTTP = {} 20 | function! s:_vital_loaded(V) abort 21 | let s:HTTP = a:V.import('Web.URI.HTTP') 22 | endfunction 23 | 24 | function! s:_vital_depends() abort 25 | return ['Web.URI.HTTP'] 26 | endfunction 27 | 28 | 29 | function! s:canonicalize(uriobj) abort 30 | return s:HTTP.canonicalize(a:uriobj) 31 | endfunction 32 | 33 | function! s:default_port(uriobj) abort 34 | return '443' 35 | endfunction 36 | 37 | " vim:set et ts=2 sts=2 sw=2 tw=0:fen: 38 | -------------------------------------------------------------------------------- /autoload/vital/opengoogletranslate.vim: -------------------------------------------------------------------------------- 1 | let s:plugin_name = expand(':t:r') 2 | let s:vital_base_dir = expand(':h') 3 | let s:project_root = expand(':h:h:h') 4 | let s:is_vital_vim = s:plugin_name is# 'vital' 5 | 6 | let s:loaded = {} 7 | let s:cache_sid = {} 8 | 9 | " function() wrapper 10 | if v:version > 703 || v:version == 703 && has('patch1170') 11 | function! s:_function(fstr) abort 12 | return function(a:fstr) 13 | endfunction 14 | else 15 | function! s:_SID() abort 16 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 17 | endfunction 18 | let s:_s = '' . s:_SID() . '_' 19 | function! s:_function(fstr) abort 20 | return function(substitute(a:fstr, 's:', s:_s, 'g')) 21 | endfunction 22 | endif 23 | 24 | function! vital#{s:plugin_name}#new() abort 25 | return s:new(s:plugin_name) 26 | endfunction 27 | 28 | function! vital#{s:plugin_name}#import(...) abort 29 | if !exists('s:V') 30 | let s:V = s:new(s:plugin_name) 31 | endif 32 | return call(s:V.import, a:000, s:V) 33 | endfunction 34 | 35 | let s:Vital = {} 36 | 37 | function! s:new(plugin_name) abort 38 | let base = deepcopy(s:Vital) 39 | let base._plugin_name = a:plugin_name 40 | return base 41 | endfunction 42 | 43 | function! s:vital_files() abort 44 | if !exists('s:vital_files') 45 | let s:vital_files = map( 46 | \ s:is_vital_vim ? s:_global_vital_files() : s:_self_vital_files(), 47 | \ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")') 48 | endif 49 | return copy(s:vital_files) 50 | endfunction 51 | let s:Vital.vital_files = s:_function('s:vital_files') 52 | 53 | function! s:import(name, ...) abort dict 54 | let target = {} 55 | let functions = [] 56 | for a in a:000 57 | if type(a) == type({}) 58 | let target = a 59 | elseif type(a) == type([]) 60 | let functions = a 61 | endif 62 | unlet a 63 | endfor 64 | let module = self._import(a:name) 65 | if empty(functions) 66 | call extend(target, module, 'keep') 67 | else 68 | for f in functions 69 | if has_key(module, f) && !has_key(target, f) 70 | let target[f] = module[f] 71 | endif 72 | endfor 73 | endif 74 | return target 75 | endfunction 76 | let s:Vital.import = s:_function('s:import') 77 | 78 | function! s:load(...) abort dict 79 | for arg in a:000 80 | let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg] 81 | let target = split(join(as, ''), '\W\+') 82 | let dict = self 83 | let dict_type = type({}) 84 | while !empty(target) 85 | let ns = remove(target, 0) 86 | if !has_key(dict, ns) 87 | let dict[ns] = {} 88 | endif 89 | if type(dict[ns]) == dict_type 90 | let dict = dict[ns] 91 | else 92 | unlet dict 93 | break 94 | endif 95 | endwhile 96 | if exists('dict') 97 | call extend(dict, self._import(name)) 98 | endif 99 | unlet arg 100 | endfor 101 | return self 102 | endfunction 103 | let s:Vital.load = s:_function('s:load') 104 | 105 | function! s:unload() abort dict 106 | let s:loaded = {} 107 | let s:cache_sid = {} 108 | unlet! s:vital_files 109 | endfunction 110 | let s:Vital.unload = s:_function('s:unload') 111 | 112 | function! s:exists(name) abort dict 113 | if a:name !~# '\v^\u\w*%(\.\u\w*)*$' 114 | throw 'vital: Invalid module name: ' . a:name 115 | endif 116 | return s:_module_path(a:name) isnot# '' 117 | endfunction 118 | let s:Vital.exists = s:_function('s:exists') 119 | 120 | function! s:search(pattern) abort dict 121 | let paths = s:_extract_files(a:pattern, self.vital_files()) 122 | let modules = sort(map(paths, 's:_file2module(v:val)')) 123 | return s:_uniq(modules) 124 | endfunction 125 | let s:Vital.search = s:_function('s:search') 126 | 127 | function! s:plugin_name() abort dict 128 | return self._plugin_name 129 | endfunction 130 | let s:Vital.plugin_name = s:_function('s:plugin_name') 131 | 132 | function! s:_self_vital_files() abort 133 | let builtin = printf('%s/__%s__/', s:vital_base_dir, s:plugin_name) 134 | let installed = printf('%s/_%s/', s:vital_base_dir, s:plugin_name) 135 | let base = builtin . ',' . installed 136 | return split(globpath(base, '**/*.vim', 1), "\n") 137 | endfunction 138 | 139 | function! s:_global_vital_files() abort 140 | let pattern = 'autoload/vital/__*__/**/*.vim' 141 | return split(globpath(&runtimepath, pattern, 1), "\n") 142 | endfunction 143 | 144 | function! s:_extract_files(pattern, files) abort 145 | let tr = {'.': '/', '*': '[^/]*', '**': '.*'} 146 | let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g') 147 | let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target) 148 | return filter(a:files, 'v:val =~# regexp') 149 | endfunction 150 | 151 | function! s:_file2module(file) abort 152 | let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?') 153 | let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$') 154 | return join(split(tail, '[\\/]\+'), '.') 155 | endfunction 156 | 157 | " @param {string} name e.g. Data.List 158 | function! s:_import(name) abort dict 159 | if has_key(s:loaded, a:name) 160 | return copy(s:loaded[a:name]) 161 | endif 162 | let module = self._get_module(a:name) 163 | if has_key(module, '_vital_created') 164 | call module._vital_created(module) 165 | endif 166 | let export_module = filter(copy(module), 'v:key =~# "^\\a"') 167 | " Cache module before calling module.vital_loaded() to avoid cyclic 168 | " dependences but remove the cache if module._vital_loaded() fails. 169 | " let s:loaded[a:name] = export_module 170 | let s:loaded[a:name] = export_module 171 | if has_key(module, '_vital_loaded') 172 | try 173 | call module._vital_loaded(vital#{s:plugin_name}#new()) 174 | catch 175 | unlet s:loaded[a:name] 176 | throw 'vital: fail to call ._vital_loaded(): ' . v:exception 177 | endtry 178 | endif 179 | return copy(s:loaded[a:name]) 180 | endfunction 181 | let s:Vital._import = s:_function('s:_import') 182 | 183 | " s:_get_module() returns module object wihch has all script local functions. 184 | function! s:_get_module(name) abort dict 185 | let funcname = s:_import_func_name(self.plugin_name(), a:name) 186 | if s:_exists_autoload_func_with_source(funcname) 187 | return call(funcname, []) 188 | else 189 | return s:_get_builtin_module(a:name) 190 | endif 191 | endfunction 192 | 193 | function! s:_get_builtin_module(name) abort 194 | return s:sid2sfuncs(s:_module_sid(a:name)) 195 | endfunction 196 | 197 | if s:is_vital_vim 198 | " For vital.vim, we can use s:_get_builtin_module directly 199 | let s:Vital._get_module = s:_function('s:_get_builtin_module') 200 | else 201 | let s:Vital._get_module = s:_function('s:_get_module') 202 | endif 203 | 204 | function! s:_import_func_name(plugin_name, module_name) abort 205 | return printf('vital#_%s#%s#import', a:plugin_name, s:_dot_to_sharp(a:module_name)) 206 | endfunction 207 | 208 | function! s:_module_sid(name) abort 209 | let path = s:_module_path(a:name) 210 | if !filereadable(path) 211 | throw 'vital: module not found: ' . a:name 212 | endif 213 | let vital_dir = s:is_vital_vim ? '__\w\+__' : printf('_\{1,2}%s\%%(__\)\?', s:plugin_name) 214 | let base = join([vital_dir, ''], '[/\\]\+') 215 | let p = base . substitute('' . a:name, '\.', '[/\\\\]\\+', 'g') 216 | let sid = s:_sid(path, p) 217 | if !sid 218 | call s:_source(path) 219 | let sid = s:_sid(path, p) 220 | if !sid 221 | throw printf('vital: cannot get from path: %s', path) 222 | endif 223 | endif 224 | return sid 225 | endfunction 226 | 227 | function! s:_module_path(name) abort 228 | return get(s:_extract_files(a:name, s:vital_files()), 0, '') 229 | endfunction 230 | 231 | function! s:_module_sid_base_dir() abort 232 | return s:is_vital_vim ? &rtp : s:project_root 233 | endfunction 234 | 235 | function! s:_dot_to_sharp(name) abort 236 | return substitute(a:name, '\.', '#', 'g') 237 | endfunction 238 | 239 | " It will sources autoload file if a given func is not already defined. 240 | function! s:_exists_autoload_func_with_source(funcname) abort 241 | if exists('*' . a:funcname) 242 | " Return true if a given func is already defined 243 | return 1 244 | endif 245 | " source a file which may include a given func definition and try again. 246 | let path = 'autoload/' . substitute(substitute(a:funcname, '#[^#]*$', '.vim', ''), '#', '/', 'g') 247 | call s:_runtime(path) 248 | return exists('*' . a:funcname) 249 | endfunction 250 | 251 | function! s:_runtime(path) abort 252 | execute 'runtime' fnameescape(a:path) 253 | endfunction 254 | 255 | function! s:_source(path) abort 256 | execute 'source' fnameescape(a:path) 257 | endfunction 258 | 259 | " @vimlint(EVL102, 1, l:_) 260 | " @vimlint(EVL102, 1, l:__) 261 | function! s:_sid(path, filter_pattern) abort 262 | let unified_path = s:_unify_path(a:path) 263 | if has_key(s:cache_sid, unified_path) 264 | return s:cache_sid[unified_path] 265 | endif 266 | for line in filter(split(s:_redir(':scriptnames'), "\n"), 'v:val =~# a:filter_pattern') 267 | let [_, sid, path; __] = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$') 268 | if s:_unify_path(path) is# unified_path 269 | let s:cache_sid[unified_path] = sid 270 | return s:cache_sid[unified_path] 271 | endif 272 | endfor 273 | return 0 274 | endfunction 275 | 276 | function! s:_redir(cmd) abort 277 | let [save_verbose, save_verbosefile] = [&verbose, &verbosefile] 278 | set verbose=0 verbosefile= 279 | redir => res 280 | silent! execute a:cmd 281 | redir END 282 | let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] 283 | return res 284 | endfunction 285 | 286 | if filereadable(expand(':r') . '.VIM') " is case-insensitive or not 287 | let s:_unify_path_cache = {} 288 | " resolve() is slow, so we cache results. 289 | " Note: On windows, vim can't expand path names from 8.3 formats. 290 | " So if getting full path via and $HOME was set as 8.3 format, 291 | " vital load duplicated scripts. Below's :~ avoid this issue. 292 | function! s:_unify_path(path) abort 293 | if has_key(s:_unify_path_cache, a:path) 294 | return s:_unify_path_cache[a:path] 295 | endif 296 | let value = tolower(fnamemodify(resolve(fnamemodify( 297 | \ a:path, ':p')), ':~:gs?[\\/]?/?')) 298 | let s:_unify_path_cache[a:path] = value 299 | return value 300 | endfunction 301 | else 302 | function! s:_unify_path(path) abort 303 | return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?')) 304 | endfunction 305 | endif 306 | 307 | " copied and modified from Vim.ScriptLocal 308 | let s:SNR = join(map(range(len("\")), '"[\\x" . printf("%0x", char2nr("\"[v:val])) . "]"'), '') 309 | function! s:sid2sfuncs(sid) abort 310 | let fs = split(s:_redir(printf(':function /^%s%s_', s:SNR, a:sid)), "\n") 311 | let r = {} 312 | let pattern = printf('\m^function\s%d_\zs\w\{-}\ze(', a:sid) 313 | for fname in map(fs, 'matchstr(v:val, pattern)') 314 | let r[fname] = function(s:_sfuncname(a:sid, fname)) 315 | endfor 316 | return r 317 | endfunction 318 | 319 | "" Return funcname of script local functions with SID 320 | function! s:_sfuncname(sid, funcname) abort 321 | return printf('%s_%s', a:sid, a:funcname) 322 | endfunction 323 | 324 | if exists('*uniq') 325 | function! s:_uniq(list) abort 326 | return uniq(a:list) 327 | endfunction 328 | else 329 | function! s:_uniq(list) abort 330 | let i = len(a:list) - 1 331 | while 0 < i 332 | if a:list[i] ==# a:list[i - 1] 333 | call remove(a:list, i) 334 | endif 335 | let i -= 1 336 | endwhile 337 | return a:list 338 | endfunction 339 | endif 340 | -------------------------------------------------------------------------------- /autoload/vital/opengoogletranslate.vital: -------------------------------------------------------------------------------- 1 | opengoogletranslate 2 | 6e682fce672da9da08aee5db517d227be5ef663f 3 | 4 | Web.URI 5 | ArgumentParser 6 | Vim.SelectedText 7 | -------------------------------------------------------------------------------- /doc/open-googletranslate.txt: -------------------------------------------------------------------------------- 1 | *open-googletranslate.txt* Open Google Translate 2 | 3 | Author : haya14busa 4 | Version : 0.9.0 5 | License : MIT license {{{ 6 | 7 | Copyright (c) 2016 haya14busa 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | }}} 28 | 29 | ============================================================================== 30 | CONTENTS *open-googletranslate-contents* 31 | 32 | INTRODUCTION |open-googletranslate-introduction| 33 | INTERFACE |open-googletranslate-interface| 34 | COMMANDS |open-googletranslate-commands| 35 | KEY MAPPINGS |open-googletranslate-key-mappings| 36 | OPTIONS |open-googletranslate-options| 37 | CHANGELOG |open-googletranslate-changelog| 38 | 39 | ============================================================================== 40 | INTRODUCTION *open-googletranslate-introduction* 41 | 42 | *vim-open-googletranslate* (*open-googletranslate.vim* ) provides utilities to 43 | open Google Translate (https://translate.google.com/). 44 | 45 | Requirements: 46 | - |openbrowser| 0.1.1 or later 47 | https://github.com/tyru/open-browser.vim 48 | - [optional] |operator-user| 0.1.0 or later 49 | https://github.com/kana/vim-operator-user 50 | 51 | Latest version: 52 | https://github.com/haya14busa/vim-open-googletranslate 53 | 54 | ============================================================================== 55 | INTERFACE *open-googletranslate-interface* 56 | ------------------------------------------------------------------------------ 57 | COMMANDS *open-googletranslate-commands* 58 | 59 | *:OpenGoogleTranslate* 60 | :[range]OpenGoogleTranslate [--help] [--to=TO] [--from=FROM] [input text] 61 | Open GoogleTranslate with input text. You can specify input test 62 | either by optional arguments or visual selection. Otherwise, a whole 63 | buffer text will be uses as input text. 64 | 65 | You can specify target language by --to and from language by --from. 66 | 67 | ------------------------------------------------------------------------------ 68 | KEY MAPPINGS *open-googletranslate-key-mappings* 69 | 70 | (operator-open-googletranslate){motion} *(operator-open-googletranslate)* 71 | Open GoogleTranslate with text that {motion} moves over. 72 | 73 | ============================================================================== 74 | OPTIONS *open-googletranslate-options* 75 | 76 | g:opengoogletranslate#default_lang |g:opengoogletranslate#default_lang| 77 | Default target language. The format should be two lowercase letters 78 | (e.g. en, ja, etc...). Default is empty and inferred by |v:lang|. 79 | 80 | g:opengoogletranslate#openbrowsercmd *g:opengoogletranslate#openbrowsercmd* 81 | Browser command to open URL. Default is empty and it open your default 82 | browser. 83 | 84 | Example: 85 | You can use https://github.com/rhysd/electron-open-url to open 86 | Google Translate in same window instead of opening a lot of tabs. 87 | 88 | 89 | ============================================================================== 90 | CHANGELOG *open-googletranslate-changelog* 91 | 92 | 0.9.0 2016-11-12 93 | - Init. 94 | 95 | ============================================================================== 96 | vim:tw=78:ts=8:ft=help:norl:noet:fen:fdl=0:fdm=marker: 97 | -------------------------------------------------------------------------------- /plugin/opengoogletranslate.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " FILE: plugin/opengoogletranslate.vim 3 | " AUTHOR: haya14busa 4 | " License: MIT license 5 | "============================================================================= 6 | scriptencoding utf-8 7 | if expand('%:p') ==# expand(':p') 8 | unlet! g:loaded_opengoogletranslate 9 | endif 10 | if exists('g:loaded_opengoogletranslate') 11 | finish 12 | endif 13 | let g:loaded_opengoogletranslate = 1 14 | let s:save_cpo = &cpo 15 | set cpo&vim 16 | 17 | command! -nargs=* -range=% -bang 18 | \ -complete=customlist,opengoogletranslate#command#complete 19 | \ OpenGoogleTranslate 20 | \ call opengoogletranslate#command#command(, [, ], ) 21 | 22 | let &cpo = s:save_cpo 23 | unlet s:save_cpo 24 | " __END__ 25 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 26 | -------------------------------------------------------------------------------- /plugin/operator/opengoogletranslate.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " FILE: plugin/operator/opengoogletranslate.vim 3 | " AUTHOR: haya14busa 4 | " License: MIT license 5 | "============================================================================= 6 | scriptencoding utf-8 7 | if expand('%:p') ==# expand(':p') 8 | unlet! g:loaded_operator_opengoogletranslate 9 | endif 10 | if exists('g:loaded_operator_opengoogletranslate') 11 | finish 12 | endif 13 | let g:loaded_operator_opengoogletranslate = 1 14 | let s:save_cpo = &cpo 15 | set cpo&vim 16 | 17 | try 18 | call operator#user#define('open-googletranslate', 'operator#opengoogletranslate#do') 19 | catch /^Vim\%((\a\+)\)\=:E117/ 20 | " vim-operator-user not found. 21 | endtry 22 | 23 | let &cpo = s:save_cpo 24 | unlet s:save_cpo 25 | " __END__ 26 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 27 | --------------------------------------------------------------------------------