├── .gitignore ├── LICENSE ├── autoload ├── class.vim ├── class │ ├── buffer │ │ ├── based.vim │ │ └── shield.vim │ ├── date.vim │ ├── fantasy │ │ ├── game.vim │ │ ├── grid.vim │ │ └── maze │ │ │ ├── backer.vim │ │ │ ├── base.vim │ │ │ ├── kruskal.vim │ │ │ └── prim.vim │ ├── graph.vim │ ├── graph │ │ ├── Sample.vim │ │ ├── distance.vim │ │ ├── edge.vim │ │ ├── edgeit.vim │ │ ├── mspant.vim │ │ ├── node.vim │ │ └── travel.vim │ ├── heap │ │ └── binary.vim │ ├── less │ │ ├── cursor.vim │ │ ├── dict.vim │ │ ├── list.vim │ │ ├── math.vim │ │ ├── rtp.vim │ │ ├── rtp_test.vim │ │ └── window.vim │ ├── math │ │ ├── line.vim │ │ ├── matrix.vim │ │ ├── point.vim │ │ ├── polyline.vim │ │ ├── position.vim │ │ ├── randit.vim │ │ └── random.vim │ ├── more │ │ ├── dict.vim │ │ ├── heap.vim │ │ ├── list.vim │ │ ├── matrix.vim │ │ ├── queue.vim │ │ └── stack.vim │ ├── requeue.vim │ ├── set │ │ └── disjoint.vim │ ├── textfile.vim │ ├── textfile │ │ ├── csv.vim │ │ └── endmark.vim │ ├── tree │ │ ├── binary.vim │ │ ├── branch.vim │ │ ├── file.vim │ │ └── fs.vim │ └── viml │ │ ├── builder.vim │ │ ├── cmdline.vim │ │ ├── loger.vim │ │ ├── messager.vim │ │ ├── option │ │ ├── base.vim │ │ ├── multiple.vim │ │ ├── pairs.vim │ │ └── single.vim │ │ ├── source.vim │ │ └── tabapp.vim ├── cn │ ├── buffer.vim │ ├── dict.vim │ ├── list.vim │ ├── number.vim │ ├── readme.md │ ├── string.vim │ └── util.vim ├── jp │ ├── Assertion.vim │ ├── Async │ │ └── Promise.vim │ ├── Bitwise.vim │ ├── ConcurrentProcess.vim │ ├── Data │ │ ├── Base64.vim │ │ ├── BigNum.vim │ │ ├── Closure.vim │ │ ├── Collection.vim │ │ ├── Counter.vim │ │ ├── Dict.vim │ │ ├── Either.vim │ │ ├── LazyList.vim │ │ ├── List.vim │ │ ├── List │ │ │ └── Closure.vim │ │ ├── Optional.vim │ │ ├── OrderedSet.vim │ │ ├── Set.vim │ │ ├── String.vim │ │ ├── String │ │ │ └── Interpolation.vim │ │ └── Tree.vim │ ├── Database │ │ └── SQLite.vim │ ├── DateTime.vim │ ├── Experimental │ │ └── Functor.vim │ ├── Hash │ │ └── MD5.vim │ ├── Interpreter │ │ ├── Brainf__k.lua │ │ └── Brainf__k.vim │ ├── Locale │ │ └── Message.vim │ ├── Mapping.vim │ ├── Math.vim │ ├── OptionParser.vim │ ├── Prelude.vim │ ├── Process.vim │ ├── Random.vim │ ├── Random │ │ ├── Mt19937ar.vim │ │ └── Xor128.vim │ ├── Stream.vim │ ├── System │ │ ├── Cache.vim │ │ ├── Cache │ │ │ ├── Base.vim │ │ │ ├── Deprecated.vim │ │ │ ├── Dummy.vim │ │ │ ├── File.vim │ │ │ ├── Memory.vim │ │ │ └── SingleFile.vim │ │ ├── File.vim │ │ ├── Filepath.vim │ │ ├── Process.vim │ │ └── Process │ │ │ ├── Mock.vim │ │ │ ├── System.vim │ │ │ └── Vimproc.vim │ ├── Text │ │ ├── CSV.vim │ │ ├── INI.vim │ │ ├── LTSV.vim │ │ ├── Lexer.vim │ │ ├── Parser.vim │ │ ├── TOML.vim │ │ └── Table.vim │ ├── Vim │ │ ├── Buffer.vim │ │ ├── BufferManager.vim │ │ ├── Compat.vim │ │ ├── Guard.vim │ │ ├── Message.vim │ │ ├── Python.vim │ │ ├── ScriptLocal.vim │ │ ├── Search.vim │ │ ├── Type.vim │ │ ├── ViewTracer.vim │ │ ├── WindowLayout.vim │ │ └── WindowLayout │ │ │ ├── BorderLayout.vim │ │ │ ├── FlowLayout.vim │ │ │ └── GridLayout.vim │ └── Web │ │ ├── HTML.vim │ │ ├── HTTP.vim │ │ ├── HTTP │ │ ├── Cookie.vim │ │ └── CookieJar.vim │ │ ├── JSON.vim │ │ ├── URI.vim │ │ ├── URI │ │ ├── HTTP.vim │ │ └── HTTPS.vim │ │ └── XML.vim ├── object.vim ├── package.vim ├── sample │ ├── base.vim │ ├── inter1.vim │ ├── inter2.vim │ ├── inter3.vim │ ├── sub.vim │ ├── subsub.vim │ ├── upc2.vim │ └── usemod.vim ├── tempclass.vim └── vimloo │ └── plugin.vim ├── content.md ├── doc.md ├── class-design.md ├── class-dict.md ├── vimllib-jp.md └── vimlmod.md ├── doc └── vimloo.txt ├── plugin └── vimloo.vim ├── readme-en.md └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | tags 4 | *.o 5 | *.out 6 | *.log 7 | core.* 8 | Session.vim 9 | Sessionx.vim 10 | *.tgz 11 | *.tar.gz 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 lymslive 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 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /autoload/class/buffer/based.vim: -------------------------------------------------------------------------------- 1 | " Class: class#buffer#based 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-08-13 5 | " Modify: 2017-08-14 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#buffer#based' 15 | let s:class._version_ = 1 16 | 17 | " the logical owner object 18 | let s:class.owner = class#new() 19 | let s:class.bufnr = 0 20 | 21 | function! class#buffer#based#class() abort "{{{ 22 | return s:class 23 | endfunction "}}} 24 | 25 | " NEW: 26 | function! class#buffer#based#new(...) abort "{{{ 27 | let l:obj = class#new(s:class, a:000) 28 | return l:obj 29 | endfunction "}}} 30 | " CTOR: 31 | function! class#buffer#based#ctor(this, ...) abort "{{{ 32 | let a:this.bufnr = bufnr('%') 33 | endfunction "}}} 34 | 35 | " OLD: 36 | function! class#buffer#based#old() abort "{{{ 37 | let l:class = class#old(s:class) 38 | return l:class 39 | endfunction "}}} 40 | 41 | " ISOBJECT: 42 | function! class#buffer#based#isobject(that) abort "{{{ 43 | return class#isobject(s:class, a:that) 44 | endfunction "}}} 45 | 46 | " SetOwner: 47 | function! s:class.SetOwner(obj) dict abort "{{{ 48 | let self.owner = a:obj 49 | endfunction "}}} 50 | 51 | " RegBufvar: 52 | function! s:class.RegBufvar(bufvar) dict abort "{{{ 53 | if has_key(b:, a:bufvar) && b:[a:bufvar] isnot self 54 | : WLOG 'overide already existed bufvar: ' . a:bufvar 55 | endif 56 | let b:[a:bufvar] = self 57 | endfunction "}}} 58 | " RegTabvar: 59 | function! s:class.RegTabvar(tabvar) dict abort "{{{ 60 | if has_key(t:, a:tabvar) && t:[a:tabvar] isnot self 61 | : WLOG 'overide already existed bufvar: ' . t:tabvar 62 | endif 63 | let t:[a:tabvar] = self 64 | endfunction "}}} 65 | 66 | " list: return the buffer content as list of lines string 67 | " NOTE: getbufline() only valid for loaded buffer 68 | function! s:class.list() dict abort "{{{ 69 | if bufloaded(self.bufnr) 70 | return getbufline(self.bufnr, 1, '$') 71 | else 72 | let l:bufnr = bufnr('%') 73 | : update 74 | : execute 'buffer ' . self.bufnr 75 | let l:lsContent = getbufline(self.bufnr, 1, '$') 76 | : execute 'buffer ' . l:bufnr 77 | return l:lsContent 78 | endif 79 | endfunction "}}} 80 | 81 | " Focus: 82 | function! s:class.Focus(...) dict abort "{{{ 83 | if bufnr('%') == self.bufnr 84 | return self 85 | endif 86 | 87 | " load buffer in current window 88 | if a:0 == 0 || empty(a:1) 89 | : execute 'buffer ' self.bufnr 90 | return self 91 | endif 92 | 93 | " current tabpage, other window 94 | let l:iWindow = bufwinnr(self.bufnr) 95 | if l:iWindow != -1 96 | : execute l:iWindow . 'wincmd w' 97 | return self 98 | endif 99 | 100 | " try other tabpage 101 | if a:1 =~? 't' 102 | let l:FWindow = class#less#window#export() 103 | let l:target = l:FWindow.FindBufwinnr(self.bufnr) 104 | if !empty(l:target) && type(l:target) == v:t_list 105 | let l:tab = l:target[0] 106 | let l:win = l:target[1] 107 | : execute l:tab . 'tabnext' 108 | : execute l:win . 'wincmd w' 109 | return self 110 | endif 111 | endif 112 | 113 | " back to load in origin window 114 | : execute 'buffer .' self.bufnr 115 | return self 116 | endfunction "}}} 117 | 118 | " LOAD: 119 | let s:load = 1 120 | function! class#buffer#based#load(...) abort "{{{ 121 | if a:0 > 0 && !empty(a:1) 122 | unlet! s:load 123 | endif 124 | endfunction "}}} 125 | 126 | " TEST: 127 | function! class#buffer#based#test(...) abort "{{{ 128 | let l:obj = class#buffer#based#new() 129 | call class#echo(l:obj) 130 | endfunction "}}} 131 | -------------------------------------------------------------------------------- /autoload/class/buffer/shield.vim: -------------------------------------------------------------------------------- 1 | " Class: class#buffer#shield 2 | " Author: lymslive 3 | " Description: a special buffer shield, protcted from manually editing 4 | " suggest to create b:variable of this class 5 | " Create: 2017-07-14 6 | " Modify: 2017-08-04 7 | 8 | "LOAD: 9 | if exists('s:load') && !exists('g:DEBUG') 10 | finish 11 | endif 12 | 13 | " CLASS: 14 | let s:class = class#old() 15 | let s:class._name_ = 'class#buffer#shield' 16 | let s:class._version_ = 1 17 | 18 | " the logical owner object 19 | let s:class.owner = {} 20 | let s:class.bufnr = 0 21 | 22 | function! class#buffer#shield#class() abort "{{{ 23 | return s:class 24 | endfunction "}}} 25 | 26 | " NEW: 27 | function! class#buffer#shield#new(...) abort "{{{ 28 | let l:obj = class#new(s:class, a:000) 29 | return l:obj 30 | endfunction "}}} 31 | " CTOR: 32 | function! class#buffer#shield#ctor(this, ...) abort "{{{ 33 | let a:this.bufnr = bufnr('%') 34 | endfunction "}}} 35 | 36 | " OLD: 37 | function! class#buffer#shield#old() abort "{{{ 38 | let l:class = class#old(s:class) 39 | return l:class 40 | endfunction "}}} 41 | 42 | " ISOBJECT: 43 | function! class#buffer#shield#isobject(that) abort "{{{ 44 | return class#isobject(s:class, a:that) 45 | endfunction "}}} 46 | 47 | " Freeze: 48 | function! s:class.Freeze() dict abort "{{{ 49 | : setlocal buftype=nofile 50 | : setlocal nobuflisted 51 | : setlocal bufhidden=delete 52 | : setlocal nomodifiable 53 | : setlocal statusline=%t%=SHIELD 54 | : setlocal nonumber 55 | : setlocal nowrap 56 | endfunction "}}} 57 | 58 | " SetOwner: 59 | function! s:class.SetOwner(obj) dict abort "{{{ 60 | let self.owner = a:obj 61 | endfunction "}}} 62 | 63 | " Update: update current buffer with lsText 64 | function! s:class.Update(lsText) dict abort "{{{ 65 | " before update 66 | let l:bSame = v:true 67 | let l:bufnr = bufnr('%') 68 | if l:bufnr != self.bufnr 69 | let l:bSame = v:false 70 | let l:winnr = bufwinnr(self.bufnr) 71 | if l:winnr == -1 72 | : WLOG 'the buffer ' . self.bufnr . ' is not in window any more' 73 | return 74 | endif 75 | let l:winnr_old = winnr() 76 | execute l:winnr . 'wincmd w' 77 | endif 78 | 79 | " update 80 | if empty(a:lsText) 81 | : 1,$ delete 82 | return 83 | endif 84 | 85 | : setlocal modifiable 86 | let l:posCursor = getcurpos() 87 | 88 | let l:iOldEnd = line('$') 89 | call setline(1, a:lsText) 90 | let l:iNewEnd = len(a:lsText) 91 | 92 | if l:iOldEnd > l:iNewEnd 93 | let l:cmd = printf("%d,$ delete", l:iNewEnd + 1) 94 | execute l:cmd 95 | endif 96 | 97 | call setpos('.', l:posCursor) 98 | : setlocal nomodifiable 99 | 100 | " after update 101 | if !bSame 102 | execute l:winnr_old . 'wincmd w' 103 | endif 104 | endfunction "}}} 105 | 106 | " LOAD: 107 | let s:load = 1 108 | :DLOG '-1 class#buffer#shield is loading ...' 109 | function! class#buffer#shield#load(...) abort "{{{ 110 | if a:0 > 0 && !empty(a:1) && exists('s:load') 111 | unlet s:load 112 | return 0 113 | endif 114 | return s:load 115 | endfunction "}}} 116 | 117 | " TEST: 118 | function! class#buffer#shield#test(...) abort "{{{ 119 | return 0 120 | endfunction "}}} 121 | -------------------------------------------------------------------------------- /autoload/class/date.vim: -------------------------------------------------------------------------------- 1 | " Class: class#date 2 | " Author: lymslive 3 | " Description: a class deal with date 4 | " Create: 2017-02-17 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " BASIC: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#date' 15 | let s:class._version_ = 1 16 | 17 | let s:class.year = 0 18 | let s:class.month = 0 19 | let s:class.day = 0 20 | 21 | function! class#date#class() abort "{{{ 22 | return s:class 23 | endfunction "}}} 24 | 25 | " NEW: 26 | function! class#date#new(...) abort "{{{ 27 | let l:obj = class#new(s:class, a:000) 28 | return l:obj 29 | endfunction "}}} 30 | 31 | " CTOR: 32 | function! class#date#ctor(this, ...) abort "{{{ 33 | if a:0 >= 3 34 | let a:this.year = a:1 35 | let a:this.month = a:2 36 | let a:this.day = a:3 37 | return 0 38 | endif 39 | 40 | if a:0 == 0 41 | let l:sDatePath = strftime("%Y/%m/%d") 42 | elseif a:0 > 0 43 | let l:sDatePath = a:1 44 | endif 45 | 46 | if empty(l:sDatePath) 47 | return -1 48 | endif 49 | 50 | if match(l:sDatePath, '^\d\{8\}') != -1 51 | let a:this.year = strpart(l:sDatePath, 0, 4) 52 | let a:this.month = strpart(l:sDatePath, 4, 2) 53 | let a:this.day = strpart(l:sDatePath, 6, 2) 54 | return 0 55 | endif 56 | 57 | let l:lsSplit = split(l:sDatePath, '[^0-9]\+') 58 | if len(l:lsSplit) >= 3 59 | let a:this.year = l:lsSplit[0] 60 | let a:this.month = l:lsSplit[1] 61 | let a:this.day = l:lsSplit[2] 62 | return 0 63 | else 64 | return -1 65 | endif 66 | endfunction "}}} 67 | 68 | " ISOBJECT: 69 | function! class#date#isobject(that) abort "{{{ 70 | return class#isobject(s:class, a:that) 71 | endfunction "}}} 72 | 73 | " CONVERSION: date as a string, join by sep 74 | function! s:class.string(sep) dict abort "{{{ 75 | return join([self.year, self.month, self.day], a:sep) 76 | endfunction "}}} 77 | 78 | " CONVERSION: date as a int, make up by 8 digit 79 | function! s:class.number() dict abort "{{{ 80 | return 0 + join([self.year, self.month, self.day], '') 81 | endfunction "}}} 82 | 83 | " ShiftDay: change day filed and return self objcet 84 | function! s:class.ShiftDay(shift) dict abort "{{{ 85 | let self.day += a:shift 86 | 87 | if self.day > 31 88 | let self.day = 1 89 | endif 90 | if self.day <= 0 91 | let self.day = 31 92 | endif 93 | 94 | if self.day < 10 95 | let self.day = '0' . self.day 96 | endif 97 | 98 | return self 99 | endfunction "}}} 100 | 101 | " ShiftMonth: 102 | function! s:class.ShiftMonth(shift) dict abort "{{{ 103 | let self.month += a:shift 104 | 105 | if self.month > 12 106 | let self.month = 1 107 | endif 108 | if self.month <= 0 109 | let self.month = 12 110 | endif 111 | 112 | if self.month < 10 113 | let self.month = '0' . self.month 114 | endif 115 | 116 | return self 117 | endfunction "}}} 118 | 119 | " LOAD: 120 | let s:load = 1 121 | :DLOG 'class#date is loading ...' 122 | function! class#date#load(...) abort "{{{ 123 | if a:0 > 0 && !empty(a:1) && exists('s:load') 124 | unlet s:load 125 | return 0 126 | endif 127 | return s:load 128 | endfunction "}}} 129 | 130 | " TEST: 131 | function! class#date#test(...) abort "{{{ 132 | let l:jDate = class#date#new() 133 | echo l:jDate.string('/') 134 | echo class#date#new().string('-') 135 | echo class#date#new().number() 136 | echo class#date#new('2010/10/10').number() 137 | echo class#date#new(20101010).string('.') 138 | echo class#date#new('20101010').string('=') 139 | return 0 140 | endfunction "}}} 141 | -------------------------------------------------------------------------------- /autoload/class/fantasy/game.vim: -------------------------------------------------------------------------------- 1 | " Class: class#fantasy#game 2 | " Author: lymslive 3 | " Description: Game in VimL 4 | " Create: 2017-07-12 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#fantasy#game' 15 | let s:class._version_ = 1 16 | 17 | function! class#fantasy#game#class() abort "{{{ 18 | return s:class 19 | endfunction "}}} 20 | 21 | " NEW: 22 | function! class#fantasy#game#new(...) abort "{{{ 23 | let l:obj = class#new(s:class, a:000) 24 | return l:obj 25 | endfunction "}}} 26 | " CTOR: 27 | function! class#fantasy#game#ctor(this, ...) abort "{{{ 28 | " let l:Suctor = class#Suctor(s:class) 29 | " call l:Suctor(a:this) 30 | endfunction "}}} 31 | 32 | " OLD: 33 | function! class#fantasy#game#old() abort "{{{ 34 | let l:class = class#old(s:class) 35 | return l:class 36 | endfunction "}}} 37 | 38 | " ISOBJECT: 39 | function! class#fantasy#game#isobject(that) abort "{{{ 40 | return class#isobject(s:class, a:that) 41 | endfunction "}}} 42 | 43 | " LOAD: 44 | let s:load = 1 45 | :DLOG '-1 class#fantasy#game is loading ...' 46 | function! class#fantasy#game#load(...) abort "{{{ 47 | if a:0 > 0 && !empty(a:1) && exists('s:load') 48 | unlet s:load 49 | return 0 50 | endif 51 | return s:load 52 | endfunction "}}} 53 | 54 | " TEST: 55 | function! class#fantasy#game#test(...) abort "{{{ 56 | return 0 57 | endfunction "}}} 58 | -------------------------------------------------------------------------------- /autoload/class/graph/Sample.vim: -------------------------------------------------------------------------------- 1 | " File: Sample 2 | " Author: lymslive 3 | " Description: some graph for test & debug use 4 | " Create: 2017-07-28 5 | " Modify: 2017-08-01 6 | 7 | " https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm 8 | let s:matVertex = [ 9 | \ [ 0, 7, 9, 0, 0, 14], 10 | \ [ 7, 0, 10, 15, 0, 0], 11 | \ [ 9, 10, 0, 11, 0, 2], 12 | \ [ 0, 15, 11, 0, 6, 0], 13 | \ [ 0, 0, 0, 6, 0, 9], 14 | \ [14, 0, 2, 0, 9, 0] 15 | \ ] 16 | " size: 6*6 = 36 17 | 18 | let s:matEdge = [ 19 | \ [1, 2, 7], 20 | \ [1, 3, 9], 21 | \ [1, 6, 14], 22 | \ [2, 3, 10], 23 | \ [2, 4, 15], 24 | \ [3, 4, 11], 25 | \ [3, 6, 2], 26 | \ [4, 5, 6], 27 | \ [5, 6, 9], 28 | \ ] 29 | " size: 9*3 = 27 / 54 30 | 31 | " InputFromVertex: 32 | function! s:InputFromVertex() abort "{{{ 33 | let l:graph = class#graph#new() 34 | call l:graph.Init(s:matVertex) 35 | call l:graph.disp() 36 | 37 | let l:mspant = class#graph#mspant#new(l:graph) 38 | call l:mspant.Kruskal() 39 | call l:mspant.disp() 40 | 41 | call class#delete(l:graph) 42 | endfunction "}}} 43 | 44 | " InputFromEdge: 45 | function! s:InputFromEdge() abort "{{{ 46 | let l:graph = class#graph#new() 47 | call l:graph.Init(s:matEdge, {'edge': 9, 'direct': 0}) 48 | call l:graph.disp() 49 | let l:jDist = class#graph#distance#new(l:graph) 50 | let l:dRet = l:jDist.SolveWeighted(1, 5) 51 | echo l:dRet 52 | call class#delete(l:graph) 53 | endfunction "}}} 54 | 55 | " TEST: 56 | function! class#graph#Sample#test(...) abort "{{{ 57 | " call s:InputFromVertex() 58 | call s:InputFromEdge() 59 | return 0 60 | endfunction "}}} 61 | -------------------------------------------------------------------------------- /autoload/class/graph/edge.vim: -------------------------------------------------------------------------------- 1 | " Class: class#graph#edge 2 | " Author: lymslive 3 | " Description: edge object of a graph 4 | " Create: 2017-07-12 5 | " Modify: 2017-08-01 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | " used as inner struct of graph, not based on class but bare dict 14 | let s:class = {} 15 | let s:class.from = {} 16 | let s:class.to = {} 17 | let s:class.weight = 1 18 | 19 | function! class#graph#edge#class() abort "{{{ 20 | return s:class 21 | endfunction "}}} 22 | 23 | " NEW: #new(from, to, [weight, data]) 24 | function! class#graph#edge#new(from, to, ...) abort "{{{ 25 | let l:obj = copy(s:class) 26 | let l:obj.from = a:from 27 | let l:obj.to = a:to 28 | 29 | if a:0 >= 1 30 | let l:obj.weight = a:1 31 | else 32 | let l:obj.weight = 1 33 | endif 34 | return l:obj 35 | endfunction "}}} 36 | 37 | " Compare: 38 | function! class#graph#edge#Compare(first, second) abort "{{{ 39 | return a:first.weight - a:second.weight 40 | endfunction "}}} 41 | 42 | " LOAD: 43 | let s:load = 1 44 | :DLOG '-1 class#graph#edge is loading ...' 45 | function! class#graph#edge#load(...) abort "{{{ 46 | if a:0 > 0 && !empty(a:1) && exists('s:load') 47 | unlet s:load 48 | return 0 49 | endif 50 | return s:load 51 | endfunction "}}} 52 | 53 | " TEST: 54 | function! class#graph#edge#test(...) abort "{{{ 55 | return 0 56 | endfunction "}}} 57 | -------------------------------------------------------------------------------- /autoload/class/graph/edgeit.vim: -------------------------------------------------------------------------------- 1 | " Class: class#graph#edgeit 2 | " Author: lymslive 3 | " Description: iterator of graph edge 4 | " Create: 2017-07-12 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#graph#edgeit' 15 | let s:class._version_ = 1 16 | 17 | " belong to which graph 18 | let s:class.graph = {} 19 | 20 | " current index of vertex and edge 21 | let s:class.iv = 0 22 | let s:class.ie = 0 23 | 24 | function! class#graph#edgeit#class() abort "{{{ 25 | return s:class 26 | endfunction "}}} 27 | 28 | " NEW: 29 | function! class#graph#edgeit#new(...) abort "{{{ 30 | let l:obj = class#new(s:class, a:000) 31 | return l:obj 32 | endfunction "}}} 33 | " CTOR: 34 | function! class#graph#edgeit#ctor(this, graph) abort "{{{ 35 | if !class#graph#isobject(a:graph) 36 | :ELOG 'edgeit expect a owner graph object' 37 | return v:none 38 | endif 39 | 40 | let a:this.graph = a:graph 41 | let a:this.iv = 0 42 | let a:this.ie = 0 43 | endfunction "}}} 44 | 45 | " ISOBJECT: 46 | function! class#graph#edgeit#isobject(that) abort "{{{ 47 | return class#isobject(s:class, a:that) 48 | endfunction "}}} 49 | 50 | " End: check if the iterator ends, return v:true or v:false 51 | function! s:class.End() dict abort "{{{ 52 | if self.iv >= len(self.graph.vertex) 53 | return v:true 54 | elseif self.ie >= len(self.graph.vertex[iv].edge) 55 | return v:true 56 | else 57 | return v:false 58 | endif 59 | endfunction "}}} 60 | 61 | " Next: return the current edge, and step the cursor to next 62 | function! s:class.Next() dict abort "{{{ 63 | if self.End() 64 | return {} 65 | endif 66 | 67 | let l:jEdge = self.graph.vertex[self.iv].edge[self.ie] 68 | 69 | let self.ie += 1 70 | if self.ie >= len(self.graph.vertex[iv].edge) 71 | let self.iv += 1 72 | let self.ie = 0 73 | endif 74 | 75 | return l:jEdge 76 | endfunction "}}} 77 | 78 | " LOAD: 79 | let s:load = 1 80 | :DLOG '-1 class#graph#edgeit is loading ...' 81 | function! class#graph#edgeit#load(...) abort "{{{ 82 | if a:0 > 0 && !empty(a:1) && exists('s:load') 83 | unlet s:load 84 | return 0 85 | endif 86 | return s:load 87 | endfunction "}}} 88 | 89 | " TEST: 90 | function! class#graph#edgeit#test(...) abort "{{{ 91 | return 0 92 | endfunction "}}} 93 | -------------------------------------------------------------------------------- /autoload/class/graph/mspant.vim: -------------------------------------------------------------------------------- 1 | " Class: class#graph#mspant 2 | " Author: lymslive 3 | " Description: min span tree 4 | " Create: 2017-07-31 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#graph#mspant' 15 | let s:class._version_ = 1 16 | 17 | " refer to the origin graph 18 | let s:class.graph = {} 19 | " the collection of edge in the span tree 20 | let s:class.tree = [] 21 | 22 | function! class#graph#mspant#class() abort "{{{ 23 | return s:class 24 | endfunction "}}} 25 | 26 | " NEW: 27 | function! class#graph#mspant#new(...) abort "{{{ 28 | if a:0 < 1 || !class#graph#isobject(a:1) 29 | : ELOG '[#graph#mspant] expect a graph object' 30 | return v:none 31 | endif 32 | let l:obj = class#new(s:class, a:000) 33 | return l:obj 34 | endfunction "}}} 35 | " CTOR: 36 | function! class#graph#mspant#ctor(this, graph) abort "{{{ 37 | " let l:Suctor = class#Suctor(s:class) 38 | " call l:Suctor(a:this) 39 | let a:this.graph = a:graph 40 | let a:this.tree = [] 41 | endfunction "}}} 42 | 43 | " ISOBJECT: 44 | function! class#graph#mspant#isobject(that) abort "{{{ 45 | return class#isobject(s:class, a:that) 46 | endfunction "}}} 47 | 48 | " GetTree: 49 | function! s:class.GetTree() dict abort "{{{ 50 | return self.tree 51 | endfunction "}}} 52 | 53 | " Kruskal: 54 | function! s:class.Kruskal() dict abort "{{{ 55 | let l:set = class#set#disjoint#new() 56 | for l:vertex in self.graph.vertex 57 | call l:set.MakeSet(l:vertex.id) 58 | endfor 59 | 60 | if !empty(self.tree) 61 | let self.tree = [] 62 | endif 63 | 64 | let l:lsEdge = self.graph.EdgeList(1) 65 | for l:edge in l:lsEdge 66 | if l:set.Find(l:edge.from.id) != l:set.Find(l:edge.to.id) 67 | call add(self.tree, l:edge) 68 | call l:set.Union(l:edge.from.id, l:edge.to.id) 69 | endif 70 | endfor 71 | 72 | call l:set.Free() 73 | return self.tree 74 | endfunction "}}} 75 | 76 | " disp: 77 | function! s:class.disp() dict abort "{{{ 78 | echo 'Min Span Tree Edge: *' . len(self.tree) 79 | let l:iSum = 0 80 | for l:edge in self.tree 81 | echo printf(' [%s-->%s] = %d', l:edge.from.id, l:edge.to.id, l:edge.weight) 82 | let l:iSum += l:edge.weight 83 | endfor 84 | echo ' Total Weight: ' . l:iSum 85 | endfunction "}}} 86 | 87 | " LOAD: 88 | let s:load = 1 89 | :DLOG '-1 class#graph#mspant is loading ...' 90 | function! class#graph#mspant#load(...) abort "{{{ 91 | if a:0 > 0 && !empty(a:1) && exists('s:load') 92 | unlet s:load 93 | return 0 94 | endif 95 | return s:load 96 | endfunction "}}} 97 | 98 | " TEST: 99 | function! class#graph#mspant#test(...) abort "{{{ 100 | return 0 101 | endfunction "}}} 102 | -------------------------------------------------------------------------------- /autoload/class/graph/node.vim: -------------------------------------------------------------------------------- 1 | " Class: class#graph#node 2 | " Author: lymslive 3 | " Description: the vertex node of a graph 4 | " Create: 2017-07-12 5 | " Modify: 2017-07-28 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | " used as inner struct of graph, not based on class but bare dict 14 | let s:class = {} 15 | " identifier of a vertex node 16 | let s:class.id = 0 17 | " edges to other vertex, a list of other vertext node 18 | let s:class.edge = [] 19 | 20 | function! class#graph#node#class() abort "{{{ 21 | return s:class 22 | endfunction "}}} 23 | 24 | " NEW: 25 | function! class#graph#node#new(...) abort "{{{ 26 | let l:obj = copy(s:class) 27 | if a:0 >= 1 28 | let l:obj.id = a:1 29 | endif 30 | let l:obj.edge = [] 31 | return l:obj 32 | endfunction "}}} 33 | 34 | " LOAD: 35 | let s:load = 1 36 | :DLOG '-1 class#graph#node is loading ...' 37 | function! class#graph#node#load(...) abort "{{{ 38 | if a:0 > 0 && !empty(a:1) && exists('s:load') 39 | unlet s:load 40 | return 0 41 | endif 42 | return s:load 43 | endfunction "}}} 44 | 45 | " TEST: 46 | function! class#graph#node#test(...) abort "{{{ 47 | return 0 48 | endfunction "}}} 49 | -------------------------------------------------------------------------------- /autoload/class/graph/travel.vim: -------------------------------------------------------------------------------- 1 | " Class: class#graph#travel 2 | " Author: lymslive 3 | " Description: travel problem in full complete graph 4 | " Refer: https://en.wikipedia.org/wiki/Travelling_salesman_problem 5 | " Create: 2017-08-02 6 | " Modify: 2017-08-04 7 | 8 | "LOAD: 9 | if exists('s:load') && !exists('g:DEBUG') 10 | finish 11 | endif 12 | 13 | " CLASS: 14 | let s:class = class#old() 15 | let s:class._name_ = 'class#graph#travel' 16 | let s:class._version_ = 1 17 | 18 | let s:class.graph = {} 19 | 20 | function! class#graph#travel#class() abort "{{{ 21 | return s:class 22 | endfunction "}}} 23 | 24 | " NEW: 25 | function! class#graph#travel#new(...) abort "{{{ 26 | if a:0 < 1 || !class#graph#isobject(a:1) 27 | : ELOG '[#graph#travel] expect a graph object' 28 | return v:none 29 | endif 30 | let l:obj = class#new(s:class, a:000) 31 | return l:obj 32 | endfunction "}}} 33 | " CTOR: 34 | function! class#graph#travel#ctor(this, graph) abort "{{{ 35 | let a:this.graph = a:graph 36 | endfunction "}}} 37 | 38 | " ISOBJECT: 39 | function! class#graph#travel#isobject(that) abort "{{{ 40 | return class#isobject(s:class, a:that) 41 | endfunction "}}} 42 | 43 | " LowBound: 44 | " the low bound is min span tree 45 | function! s:class.LowBound() dict abort "{{{ 46 | let l:span = class#graph#mspant#new(self.graph) 47 | let l:lsEdge = l:span.Kruskal() 48 | let l:iSum = 0 49 | for l:edge in l:lsEdge 50 | let l:iSum += l:edge.weight 51 | endfor 52 | return l:iSum 53 | endfunction "}}} 54 | 55 | " Greedy: a valid path by greedy algorithm 56 | " a:1, also return path, otherwise only return distance 57 | function! s:class.Greedy(...) dict abort "{{{ 58 | let l:iSum = 0 59 | let l:idPath = [] 60 | 61 | let l:iVertexCnt = len(self.graph.vertex) 62 | let l:jVertex = self.graph.vertex[0] 63 | let l:jVertex.visit_ = v:true 64 | let l:iVisitCnt = 1 65 | call add(l:idPath, l:jVertex.id) 66 | 67 | while l:iVisitCnt < l:iVertexCnt 68 | if empty(l:jVertex.edge) 69 | break 70 | endif 71 | 72 | let l:jNext = {} 73 | let l:iMin = -1 74 | for l:edge in l:jVertex.edge 75 | if get(l:edge.to, 'visit_', v:false) 76 | continue 77 | endif 78 | 79 | if (l:iMin < 0 || l:edge.weight < l:iMin) && l:edge.weight > 0 80 | let l:jNext = l:edge.to 81 | let l:iMin = l:edge.weight 82 | endif 83 | endfor 84 | 85 | if !empty(l:jNext) 86 | let l:iSum += l:iMin 87 | let l:jNext.visit_ = v:true 88 | let l:iVisitCnt += 1 89 | call add(l:idPath, l:jVertex.id) 90 | let l:jVertex = l:jNext 91 | else 92 | break 93 | endif 94 | endwhile 95 | 96 | for l:jVertex in self.graph.vertex 97 | unlet! l:jVertex.visit_ 98 | endfor 99 | 100 | if l:iVisitCnt != l:iVertexCnt 101 | : ELOG '[class#graph#travel.Greedy] ' . 'graph may not full complete' 102 | return -1 103 | endif 104 | 105 | if a:0 > 0 && !empty(a:1) 106 | return {'dist': l:iSum, 'path': l:idPath} 107 | else 108 | return l:iSum 109 | endif 110 | endfunction "}}} 111 | 112 | " LOAD: 113 | let s:load = 1 114 | :DLOG '-1 class#graph#travel is loading ...' 115 | function! class#graph#travel#load(...) abort "{{{ 116 | if a:0 > 0 && !empty(a:1) && exists('s:load') 117 | unlet s:load 118 | return 0 119 | endif 120 | return s:load 121 | endfunction "}}} 122 | 123 | " TEST: 124 | function! class#graph#travel#test(...) abort "{{{ 125 | return 0 126 | endfunction "}}} 127 | -------------------------------------------------------------------------------- /autoload/class/less/cursor.vim: -------------------------------------------------------------------------------- 1 | " Class: module#less#cursor 2 | " Author: lymslive 3 | " Description: funtions deal with current cursor 4 | " Create: 2017-03-09 5 | " Modify: 2017-08-14 6 | 7 | let s:class = {} 8 | function! class#less#cursor#export() abort "{{{ 9 | return s:class 10 | endfunction "}}} 11 | 12 | 13 | " GetWord: Get the word under cursor, as 14 | " > a:000, add each to &isk temporary, get the word then restore &isk 15 | " > only a:1 == one space, get word as 16 | function! s:class.GetWord(...) dict abort "{{{ 17 | if a:0 == 0 18 | return expand('') 19 | elseif a:0 == 1 && a:1 ==# ' ' 20 | return expand('') 21 | endif 22 | 23 | let l:opSave = &l:iskeyword 24 | 25 | for l:c in a:000 26 | execute 'setlocal iskeyword+=' . l:c 27 | endfor 28 | 29 | let l:word = expand('') 30 | let &l:iskeyword = l:opSave 31 | return l:word 32 | endfunction "}}} 33 | 34 | " GetChar: get the single char under cursor 35 | function! s:class.GetChar() dict abort "{{{ 36 | let l:sLine = getline('.') 37 | let l:iColumn = col('.') 38 | return l:sLine[l:iColumn - 1] 39 | endfunction "}}} 40 | 41 | " SplitLine: split line into three parts by cursor 42 | " accpect upto 2 arguments, then shift left and right first 43 | function! s:class.SplitLine(...) dict abort "{{{ 44 | if a:0 == 0 45 | return self.SplitCursor_() 46 | elseif a:0 == 1 47 | if empty(a:1) 48 | return self.SplitCursor_() 49 | endif 50 | let l:cLeft = a:1 51 | let l:cRight = a:1 52 | elseif a:0 >= 2 53 | let l:cLeft = a:1 54 | let l:cRight = a:2 55 | endif 56 | return self.SplitBetween_(l:cLeft, l:cRight) 57 | endfunction "}}} 58 | 59 | " SplitCursor_: [string before, char at cursor, string after] 60 | " return list of 3 item 61 | function! s:class.SplitCursor_() dict abort "{{{ 62 | let l:line = getline('.') 63 | if empty(l:line) 64 | return ['', '', ''] 65 | endif 66 | 67 | let l:idx = col('.') - 1 68 | let l:end = len(l:line) - 1 69 | if l:idx <= 0 70 | return ['', l:line[0], strpart(l:line, 1)] 71 | elseif l:idx >= l:end 72 | return [strpart(l:line, 0, l:end), l:line[l:end], ''] 73 | else 74 | return [strpart(l:line, 0, l:idx), 75 | \ l:line[l:idx], 76 | \ strpart(l:line, l:idx+1)] 77 | endif 78 | endfunction "}}} 79 | 80 | " SplitBetween_: 81 | " shift cursor to match left and right 82 | " split line to 3 parts 83 | " when either is empty, hold on cursor 84 | function! s:class.SplitBetween_(left, right) dict abort "{{{ 85 | let l:line = getline('.') 86 | if empty(l:line) 87 | return ['', '', ''] 88 | endif 89 | 90 | if empty(a:left) && empty(a:right) 91 | return self.SplitCursor_() 92 | endif 93 | 94 | let l:idx = col('.') - 1 95 | let l:end = len(l:line) - 1 96 | 97 | let l:iLeft = l:idx 98 | if !empty(a:left) && l:line[l:idx] != a:left 99 | let l:iLeft = strridx(l:line, a:left, l:idx) 100 | endif 101 | 102 | let l:iRight = l:idx 103 | if !empty(a:right) && l:line[l:idx] != a:right 104 | let l:iRight = stridx(l:line, a:right, l:idx) 105 | endif 106 | 107 | return [strpart(l:line, 0, l:iLeft), 108 | \ strpart(l:line, l:iLeft, l:iRight - l:iLeft + 1), 109 | \ strpart(l:line, l:iRight+1)] 110 | endfunction "}}} 111 | 112 | -------------------------------------------------------------------------------- /autoload/class/less/list.vim: -------------------------------------------------------------------------------- 1 | " Class: module#less#list 2 | " Author: lymslive 3 | " Description: VimL module frame, list util 4 | " Create: 2017-02-25 5 | " Modify: 2017-08-21 6 | 7 | let s:class = {} 8 | function! class#less#list#export() abort "{{{ 9 | return s:class 10 | endfunction "}}} 11 | 12 | " IsListof: 13 | function! s:class.IsListof(list, type) dict abort "{{{ 14 | if type(a:list) != type([]) 15 | return v:false 16 | endif 17 | for l:item in a:list 18 | if type(l:item) != a:type 19 | return v:false 20 | endif 21 | endfor 22 | return v:true 23 | endfunction "}}} 24 | 25 | " BreakString: split a string in individual characters 26 | function! s:class.BreakString(string) dict abort "{{{ 27 | return split(a:string, '\zs') 28 | endfunction "}}} 29 | 30 | " BackIndex: return a hash from value to index 31 | " each item in list should be string or number that fit for dict key 32 | function! s:class.BackIndex(list) dict abort "{{{ 33 | let l:hash = {} 34 | for i in range((a:list)) 35 | let l:item = a:list[i] 36 | let l:hash[l:item] = i 37 | endfor 38 | return l:hash 39 | endfunction "}}} 40 | 41 | " Flat: 42 | " > a:lsArgv, a list 43 | " > a:1, deepth 44 | " < return, a flattend list 45 | function! s:class.Flat(lsArgv, ...) dict abort "{{{ 46 | let l:iDeepth = get(a:000, 0, 1) 47 | if l:iDeepth == 0 48 | return a:lsArgv 49 | endif 50 | 51 | let l:lsRet = [] 52 | let l:iDeepth -= 1 53 | for l:arg in a:lsArgv 54 | if type(l:arg) == type([]) 55 | let l:lsRet += self.Flat(l:arg, l:iDeepth) 56 | elseif type(l:arg) == type({}) 57 | for [l:key, l:val] in items(l:arg) 58 | let l:lsRet += [l:key, l:val] 59 | unlet l:key l:val 60 | endfor 61 | else 62 | let l:lsRet += [larg] 63 | endif 64 | endfor 65 | 66 | return l:lsRet 67 | endfunction "}}} 68 | 69 | " Swap: swap two items in list 70 | " not check index beyond range, let it go die in that case 71 | function! s:class.Swap(list, idx, jdx) dict abort "{{{ 72 | if a:idx == a:jdx 73 | return 74 | endif 75 | let l:tmp = a:list[a:idx] 76 | let a:list[a:idx] = a:list[a:jdx] 77 | let a:list[a:jdx] = l:tmp 78 | endfunction "}}} 79 | 80 | " Prompt: return a string than can be used in prompt, as: 81 | " 0 \t item[0] 82 | " 1 \t item[1] 83 | function! s:class.PromptString(list) dict abort "{{{ 84 | let l:lsOutput = [] 85 | let l:iPrefix = 0 86 | for l:item in a:list 87 | call add(l:lsOutput, printf("%d\t%s", l:iPrefix, l:item)) 88 | let l:iPrefix += 1 89 | endfor 90 | return join(l:lsOutput, "\n") 91 | endfunction "}}} 92 | 93 | " TEST: 94 | function! class#less#list#test(...) abort "{{{ 95 | call s:testPromptList() 96 | return 0 97 | endfunction "}}} 98 | 99 | " testPrompt: 100 | function! s:testPromptList() abort "{{{ 101 | let l:list = ['aaaaa', 'bbbbb', 'ccccc'] 102 | let l:display = s:class.PromptString(l:list) 103 | echo l:display 104 | let l:reply = input('Select: ', 0) 105 | let l:result = l:list[0+l:reply] 106 | echo 'you have select:' l:result 107 | endfunction "}}} 108 | -------------------------------------------------------------------------------- /autoload/class/less/math.vim: -------------------------------------------------------------------------------- 1 | " Class: module#less#math 2 | " Author: lymslive 3 | " Description: VimL module frame 4 | " Create: 2017-03-04 5 | " Modify: 2017-08-05 6 | 7 | let s:class = {} 8 | function! class#less#math#export() abort "{{{ 9 | return s:class 10 | endfunction "}}} 11 | 12 | " CutMax: 13 | function! s:class.CutMax(input, max) dict abort "{{{ 14 | return a:input < a:max ? a:input : a:max 15 | endfunction "}}} 16 | 17 | " CutMin: 18 | function! s:class.CutMin(input, min) dict abort "{{{ 19 | return a:input > min ? a:input : a:min 20 | endfunction "}}} 21 | 22 | " CutEnd: 23 | function! s:class.CutEnd(input, min, max) dict abort "{{{ 24 | if a:input <= a:min 25 | return a:min 26 | elseif a:input >= a:max 27 | return a:max 28 | else 29 | return a:input 30 | endif 31 | endfunction "}}} 32 | 33 | -------------------------------------------------------------------------------- /autoload/class/less/rtp_test.vim: -------------------------------------------------------------------------------- 1 | " File: rtp_test 2 | " Author: lymslive 3 | " Description: unit test for rtp.vim 4 | " Create: 2018-06-01 5 | " Modify: 2018-06-01 6 | 7 | let s:rtp = class#less#rtp#export() 8 | 9 | " Main: 10 | function! class#less#rtp_test#Main() abort "{{{ 11 | " code 12 | endfunction "}}} 13 | 14 | " FindAoptScript: 15 | function! class#less#rtp_test#FindAoptScript() abort "{{{ 16 | let l:name = 'note' 17 | let l:script = s:rtp.FindAoptScript(l:name) 18 | echomsg l:script 19 | endfunction "}}} 20 | -------------------------------------------------------------------------------- /autoload/class/less/window.vim: -------------------------------------------------------------------------------- 1 | " Class: module#less#window 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-27 5 | " Modify: 2017-08-13 6 | 7 | let s:class = {} 8 | function! class#less#window#export() abort "{{{ 9 | return s:class 10 | endfunction "}}} 11 | 12 | " FindWindow: find a window by &filetype 13 | " > a:1, bOtherTab, also find in other tab 14 | " < return winnr 15 | " < return [tabnr, winnr] if bOtherTab 16 | " < return empty if not found 17 | function! s:class.FindWindow(sFileType, ...) dict abort "{{{ 18 | let l:count = winnr('$') 19 | for l:win in range(1, l:count) 20 | if getwinvar(l:win, '&filetype') ==# a:sFileType 21 | return l:win 22 | endif 23 | endfor 24 | 25 | let l:bOtherTab = get(a:000, 0, v:false) 26 | if !l:bOtherTab 27 | return 0 28 | endif 29 | 30 | for l:tab in range(1, tabpagenr('$')) 31 | if l:tab == tabpagenr() 32 | continue 33 | endif 34 | for l:win in range(1, tabpagewinnr(l:tab, '$')) 35 | if gettabwinvar(l:tab, l:win, '&filetype') ==# a:sFileType 36 | return [l:tab, l:win] 37 | endif 38 | endfor 39 | endfor 40 | 41 | return [0, 0] 42 | endfunction "}}} 43 | 44 | " GotoWindow: find and goto a window by &filetype 45 | function! s:class.GotoWindow(sFileType, ...) dict abort "{{{ 46 | let l:bOtherTab = get(a:000, 0, v:false) 47 | let l:target = self.FindWindow(a:sFileType, l:bOtherTab) 48 | if type(l:target) == type(0) 49 | let l:win = l:target 50 | if l:win != 0 && l:win != winnr() 51 | execute l:win . 'wincmd w' 52 | endif 53 | return l:win 54 | elseif type(l:target) == type([]) 55 | let l:tab = get(l:target, 0, 0) 56 | let l:win = get(l:target, 1, 0) 57 | if l:tab != 0 && l:tab != tabpagenr() 58 | execute l:tab . 'tabnext' 59 | if l:win != 0 && l:win != winnr() 60 | execute l:win . 'wincmd w' 61 | endif 62 | endif 63 | return [l:tab, l:win] 64 | endif 65 | endfunction "}}} 66 | 67 | " FindTabpage: find a tab that have t:varname=value 68 | function! s:class.FindTabpage(varname, value) dict abort "{{{ 69 | let l:iTabCount = tabpagenr('$') 70 | for i in range(1, l:iTabCount) 71 | if gettabvar(i, a:varname, '') ==# a:value 72 | return i 73 | endif 74 | endfor 75 | return 0 76 | endfunction "}}} 77 | 78 | " FindBufwinnr: find a window by bufnr name or bufnr 79 | " > a:1, bOtherTab, also find in other tab 80 | " < return winnr 81 | " < return [tabnr, winnr] if bOtherTab 82 | " < return empty if not found 83 | " when this function finish, will back to origin tab&win 84 | function! s:class.FindBufwinnr(buffer, ...) dict abort "{{{ 85 | let l:iWindow = bufwinnr(a:buffer) 86 | if l:iWindow != -1 87 | return l:iWindow 88 | endif 89 | 90 | let l:bOtherTab = get(a:000, 0, v:false) 91 | if !l:bOtherTab 92 | return 0 93 | endif 94 | 95 | let l:iTabOld = tabpagenr() 96 | let l:Ret = [] 97 | for l:tab in range(1, tabpagenr('$')) 98 | if l:tab == l:iTabOld 99 | continue 100 | endif 101 | 102 | : execute l:tab . 'tabnext' 103 | 104 | let l:win = bufwinnr(a:buffer) 105 | if l:iWindow != -1 106 | let l:Ret = [l:tab, l:win] 107 | break 108 | endif 109 | endfor 110 | 111 | : execute l:iTabOld . 'tabnext' 112 | return l:Ret 113 | endfunction "}}} 114 | -------------------------------------------------------------------------------- /autoload/class/math/line.vim: -------------------------------------------------------------------------------- 1 | " Class: class#math#line 2 | " Author: lymslive 3 | " Description: a line object with two point ends 4 | " Create: 2017-06-30 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#math#line' 15 | let s:class._version_ = 1 16 | 17 | let s:class.from = {} 18 | let s:class.to = {} 19 | 20 | function! class#math#line#class() abort "{{{ 21 | return s:class 22 | endfunction "}}} 23 | 24 | " NEW: 25 | function! class#math#line#new(...) abort "{{{ 26 | if a:0 < 2 27 | :ELOG 'please new line(pt1, pt2)' 28 | return v:none 29 | endif 30 | 31 | if !class#math#point#isobject(a:1) 32 | :ELOG 'on #new line(pt1, pt2), argument pt1 is not a point' 33 | return v:none 34 | endif 35 | 36 | if !class#math#point#isobject(a:2) 37 | :ELOG 'on #new line(pt1, pt2), argument pt2 is not a point' 38 | return v:none 39 | endif 40 | 41 | let l:obj = class#new(s:class, a:000) 42 | return l:obj 43 | endfunction "}}} 44 | " CTOR: 45 | function! class#math#line#ctor(this, from, to) abort "{{{ 46 | " let l:Suctor = class#Suctor(s:class) 47 | " call l:Suctor(a:this) 48 | let a:this.from = a:from 49 | let a:this.to = a:to 50 | endfunction "}}} 51 | 52 | " ISOBJECT: 53 | function! class#math#line#isobject(that) abort "{{{ 54 | return class#isobject(s:class, a:that) 55 | endfunction "}}} 56 | 57 | " Distance: 58 | function! s:class.Distance() dict abort "{{{ 59 | if self.from.x == self.to.x 60 | return abs(self.from.y - self.to.y) 61 | elseif self.from.y == self.to.y 62 | return abs(self.from.x - self.to.x) 63 | else 64 | return sqrt(pow(self.from.x - self.to.x, 2) + pow(self.from.y - self.to.y, 2)) 65 | endif 66 | endfunction "}}} 67 | 68 | " LOAD: 69 | let s:load = 1 70 | :DLOG '-1 class#math#line is loading ...' 71 | function! class#math#line#load(...) abort "{{{ 72 | if a:0 > 0 && !empty(a:1) && exists('s:load') 73 | unlet s:load 74 | return 0 75 | endif 76 | return s:load 77 | endfunction "}}} 78 | 79 | " TEST: 80 | function! class#math#line#test(...) abort "{{{ 81 | return 0 82 | endfunction "}}} 83 | -------------------------------------------------------------------------------- /autoload/class/math/polyline.vim: -------------------------------------------------------------------------------- 1 | " Class: class#math#polyline 2 | " Author: lymslive 3 | " Description: a set of point in order, connected successively 4 | " Create: 2017-06-30 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#math#polyline' 15 | let s:class._version_ = 1 16 | 17 | let s:points = [] 18 | " closed polyline means connect the last point to the first 19 | let s:closed = v:false 20 | 21 | function! class#math#polyline#class() abort "{{{ 22 | return s:class 23 | endfunction "}}} 24 | 25 | " NEW: #new(pt1, pt2, pt3, ...) 26 | function! class#math#polyline#new(...) abort "{{{ 27 | let l:obj = class#new(s:class, a:000) 28 | return l:obj 29 | endfunction "}}} 30 | " CTOR: 31 | function! class#math#polyline#ctor(this, ...) abort "{{{ 32 | " let l:Suctor = class#Suctor(s:class) 33 | " call l:Suctor(a:this) 34 | let a:this.points = [] 35 | 36 | if a:0 <= 0 37 | return 38 | endif 39 | 40 | for l:idx in range(a:0) 41 | call a:this.AddPoint(a:1) 42 | endfor 43 | endfunction "}}} 44 | 45 | " ISOBJECT: 46 | function! class#math#polyline#isobject(that) abort "{{{ 47 | return class#isobject(s:class, a:that) 48 | endfunction "}}} 49 | 50 | " AddPoint: 51 | function! s:class.AddPoint(pt) dict abort "{{{ 52 | if !class#math#point#isobject(a:pt) 53 | :ELOG 'polyline.AddPoint() expect a point object' 54 | return self 55 | endif 56 | 57 | call add(self.points, a:pt) 58 | endfunction "}}} 59 | 60 | " SetClose: 61 | function! s:class.SetClose(bClose) dict abort "{{{ 62 | if empty(a:bClose) 63 | let self.closed = v:false 64 | else 65 | let self.closed = v:true 66 | endif 67 | return self 68 | endfunction "}}} 69 | 70 | " IsClose: 71 | function! s:class.IsClose() dict abort "{{{ 72 | return self.closed 73 | endfunction "}}} 74 | 75 | " LOAD: 76 | let s:load = 1 77 | :DLOG '-1 class#math#polyline is loading ...' 78 | function! class#math#polyline#load(...) abort "{{{ 79 | if a:0 > 0 && !empty(a:1) && exists('s:load') 80 | unlet s:load 81 | return 0 82 | endif 83 | return s:load 84 | endfunction "}}} 85 | 86 | " TEST: 87 | function! class#math#polyline#test(...) abort "{{{ 88 | return 0 89 | endfunction "}}} 90 | -------------------------------------------------------------------------------- /autoload/class/math/position.vim: -------------------------------------------------------------------------------- 1 | " Class: class#math#position 2 | " Author: lymslive 3 | " Description: like point(x, y) but used as (row, col), more like point(y, x) 4 | " Create: 2017-07-06 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#math#position' 15 | let s:class._version_ = 1 16 | 17 | let s:class.row = 0 18 | let s:class.col = 0 19 | 20 | function! class#math#position#class() abort "{{{ 21 | return s:class 22 | endfunction "}}} 23 | 24 | " NEW: #new(row, col) 25 | function! class#math#position#new(...) abort "{{{ 26 | if a:0 < 2 || type(a:1) != type(0) || type(a:2) != type(0) 27 | :ELOG 'please new position(row, col)' 28 | return v:none 29 | endif 30 | 31 | let l:obj = class#new(s:class, a:000) 32 | return l:obj 33 | endfunction "}}} 34 | " CTOR: 35 | function! class#math#position#ctor(this, row, col) abort "{{{ 36 | let a:this.row = a:row 37 | let a:this.col = a:col 38 | endfunction "}}} 39 | 40 | " ISOBJECT: 41 | function! class#math#position#isobject(that) abort "{{{ 42 | return class#isobject(s:class, a:that) 43 | endfunction "}}} 44 | 45 | " LOAD: 46 | let s:load = 1 47 | :DLOG '-1 class#math#position is loading ...' 48 | function! class#math#position#load(...) abort "{{{ 49 | if a:0 > 0 && !empty(a:1) && exists('s:load') 50 | unlet s:load 51 | return 0 52 | endif 53 | return s:load 54 | endfunction "}}} 55 | 56 | " TEST: 57 | function! class#math#position#test(...) abort "{{{ 58 | return 0 59 | endfunction "}}} 60 | -------------------------------------------------------------------------------- /autoload/class/math/randit.vim: -------------------------------------------------------------------------------- 1 | " Class: class#math#randit 2 | " Author: lymslive 3 | " Description: iterate randomly in range[1, maxint] 4 | " each time call Next(), generate a rand number with no repeat and 5 | " after maxint times, output 0 marked as the end 6 | " Create: 2017-07-06 7 | " Modify: 2017-08-21 8 | 9 | "LOAD: 10 | if exists('s:load') && !exists('g:DEBUG') 11 | finish 12 | endif 13 | 14 | " CLASS: 15 | let s:class = class#old() 16 | let s:class._name_ = 'class#math#randit' 17 | let s:class._version_ = 1 18 | 19 | let s:class.maxint = 10 20 | let s:class.yield = 0 21 | 22 | function! class#math#randit#class() abort "{{{ 23 | return s:class 24 | endfunction "}}} 25 | 26 | " NEW: 27 | function! class#math#randit#new(...) abort "{{{ 28 | let l:obj = class#new(s:class, a:000) 29 | return l:obj 30 | endfunction "}}} 31 | " CTOR: 32 | function! class#math#randit#ctor(this, ...) abort "{{{ 33 | if a:0 < 1 || type(a:1) != type(0) 34 | :ELOG 'expcet randit(maxint)' 35 | return v:none 36 | endif 37 | call a:this.Reset(a:1) 38 | endfunction "}}} 39 | 40 | " ISOBJECT: 41 | function! class#math#randit#isobject(that) abort "{{{ 42 | return class#isobject(s:class, a:that) 43 | endfunction "}}} 44 | 45 | " Reset: 46 | function! s:class.Reset(maxint) dict abort "{{{ 47 | if type(a:maxint) != type(0) 48 | :ELOG 'randit expcet a int number' 49 | else 50 | let self.maxint = a:maxint 51 | endif 52 | 53 | let self._range = range(1, self.maxint) 54 | let self._random = class#math#random#new() 55 | let self.yield = 0 56 | return self 57 | endfunction "}}} 58 | 59 | " Next: 60 | function! s:class.Next() dict abort "{{{ 61 | if self.Empty() 62 | return 0 63 | endif 64 | 65 | let l:length = len(self._range) 66 | let l:idx = self._random.Rand(l:length - self.yield) 67 | let l:val = self._range[l:idx] 68 | let self.yield += 1 69 | 70 | " keep self._range array, just swap value 71 | let l:FList = class#less#list#export() 72 | call l:FList.Swap(self._range, l:idx, l:length - self.yield) 73 | 74 | return l:val 75 | endfunction "}}} 76 | 77 | " Empty: 78 | function! s:class.Empty() dict abort "{{{ 79 | return len(self._range) - self.yield <= 0 80 | endfunction "}}} 81 | 82 | " list: return the whole randed list 83 | function! s:class.list() dict abort "{{{ 84 | while !self.Empty() 85 | call self.Next() 86 | endwhile 87 | return self._range 88 | endfunction "}}} 89 | 90 | " LOAD: 91 | let s:load = 1 92 | :DLOG '-1 class#math#randit is loading ...' 93 | function! class#math#randit#load(...) abort "{{{ 94 | if a:0 > 0 && !empty(a:1) && exists('s:load') 95 | unlet s:load 96 | return 0 97 | endif 98 | return s:load 99 | endfunction "}}} 100 | 101 | " TEST: 102 | function! class#math#randit#test(...) abort "{{{ 103 | let l:it = class#math#randit#new(10) 104 | for _ in range(10) 105 | echo l:it.Next() 106 | endfor 107 | echo l:it.list() 108 | let l:it = class#math#randit#new(10) 109 | echo l:it.list() 110 | 111 | echo '---' 112 | let l:it = class#math#randit#new(16) 113 | let l:rand = l:it.Next() 114 | while !empty(l:rand) 115 | echo l:rand 116 | let l:rand = l:it.Next() 117 | endwhile 118 | echo l:it.list() 119 | let l:it = class#math#randit#new(16) 120 | echo l:it.list() 121 | 122 | return 0 123 | endfunction "}}} 124 | -------------------------------------------------------------------------------- /autoload/class/math/random.vim: -------------------------------------------------------------------------------- 1 | " Class: class#math#random 2 | " Author: lymslive 3 | " Description: random number generator, by simple LCG 4 | " Create: 2017-06-29 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " LCG: x(n+1) = (a * x(n) + c) % m 13 | let s:A = 16807 14 | let s:C = 1 15 | " The max int in vimL 2^31 - 1 16 | let s:M = 2147483647 17 | let s:X = localtime() 18 | 19 | " CLASS: 20 | let s:class = class#old() 21 | let s:class._name_ = 'class#math#random' 22 | let s:class._version_ = 1 23 | 24 | let s:class.seed = s:X 25 | 26 | function! class#math#random#class() abort "{{{ 27 | return s:class 28 | endfunction "}}} 29 | 30 | " NEW: 31 | function! class#math#random#new(...) abort "{{{ 32 | let l:obj = class#new(s:class, a:000) 33 | return l:obj 34 | endfunction "}}} 35 | " CTOR: 36 | function! class#math#random#ctor(this, ...) abort "{{{ 37 | let l:Suctor = class#Suctor(s:class) 38 | call l:Suctor(a:this) 39 | if a:0 > 0 40 | call a:this.First(a:1) 41 | else 42 | call a:this.First() 43 | endif 44 | endfunction "}}} 45 | 46 | " First: reset the rand seed 47 | function! s:class.First(...) dict abort "{{{ 48 | if a:0 < 1 || empty(a:1) 49 | let self.seed = localtime() 50 | else 51 | let self.seed = a:1 52 | endif 53 | return self.Next() 54 | endfunction "}}} 55 | 56 | " Next: 57 | function! s:class.Next() dict abort "{{{ 58 | let self.seed = (self.seed * s:A + s:C) % s:M 59 | if self.seed < 0 60 | let self.seed = -self.seed 61 | endif 62 | return self.seed 63 | endfunction "}}} 64 | 65 | " Rand: 66 | function! s:class.Rand(iMax) dict abort "{{{ 67 | let l:iRand = self.Next() 68 | return l:iRand % a:iMax 69 | endfunction "}}} 70 | 71 | " ISOBJECT: 72 | function! class#math#random#isobject(that) abort "{{{ 73 | return class#isobject(s:class, a:that) 74 | endfunction "}}} 75 | 76 | " TODO: optimize the default seed, other by simple localtime() 77 | 78 | " LOAD: 79 | let s:load = 1 80 | :DLOG '-1 class#math#random is loading ...' 81 | function! class#math#random#load(...) abort "{{{ 82 | if a:0 > 0 && !empty(a:1) && exists('s:load') 83 | unlet s:load 84 | return 0 85 | endif 86 | return s:load 87 | endfunction "}}} 88 | 89 | " TEST: 90 | function! class#math#random#test(...) abort "{{{ 91 | let l:rander = class#math#random#new() 92 | " call l:rander.First(localtime()) 93 | for l:idx in range(20) 94 | echo l:rander.Rand(100) 95 | endfor 96 | return 0 97 | endfunction "}}} 98 | -------------------------------------------------------------------------------- /autoload/class/more/dict.vim: -------------------------------------------------------------------------------- 1 | " Class: class#more#dict 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-08-02 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#more#dict' 15 | let s:class._version_ = 1 16 | 17 | function! class#more#dict#class() abort "{{{ 18 | return s:class 19 | endfunction "}}} 20 | 21 | " NEW: 22 | function! class#more#dict#new(...) abort "{{{ 23 | let l:obj = class#new(s:class, a:000) 24 | return l:obj 25 | endfunction "}}} 26 | " CTOR: 27 | function! class#more#dict#ctor(this, ...) abort "{{{ 28 | if a:0 == 0 29 | let a:this.dict_ = {} 30 | elseif type(a:1) == v:t_list 31 | let a:this.dict_ = a:1 32 | else 33 | : ELOG '[class#more#dict#ctor] expect a dict variable' 34 | endif 35 | endfunction "}}} 36 | 37 | " MERGE: 38 | function! class#more#dict#merge(that) abort "{{{ 39 | call a:that._merge_(s:class) 40 | endfunction "}}} 41 | 42 | " ISOBJECT: 43 | function! class#more#dict#isobject(that) abort "{{{ 44 | return class#isobject(s:class, a:that) 45 | endfunction "}}} 46 | 47 | " dict: 48 | function! s:class.dict() dict abort "{{{ 49 | if has_key(self, 'dict_') 50 | return self.dict_ 51 | else 52 | : ELOG '[class#more#dict] ' . 'not implement dict()' 53 | return {} 54 | endif 55 | endfunction "}}} 56 | 57 | " size: 58 | function! s:class.size() dict abort "{{{ 59 | return len(keys(self.dict())) 60 | endfunction "}}} 61 | " empty: 62 | function! s:class.empty() dict abort "{{{ 63 | return empty(self.dict()) 64 | endfunction "}}} 65 | 66 | " string: 67 | function! s:class.string() dict abort "{{{ 68 | let l:lsOutput = [] 69 | let l:sHeader = printf('{dict: %d keys}', self.size()) 70 | call add(l:lsOutput, l:sHeader) 71 | for [l:key, l:val] in items(self.dict()) 72 | let l:val_type = type(l:val) 73 | if l:val_type == v:t_string 74 | let l:val_str = l:val 75 | elseif l:val_type == v:t_list 76 | let l:val_str = '[...]' 77 | elseif l:val_type == v:t_dict 78 | let l:val_str = '{...}' 79 | else 80 | let l:val_str = string(l:val) 81 | endif 82 | let l:val_str = '' 83 | let l:sItem = printf(' %s => %s', l:key, l:val_str) 84 | call add(l:lsOutput, l:sItem) 85 | unlet l:key l:val 86 | endfor 87 | return join(l:lsOutput, "\n") 88 | endfunction "}}} 89 | " disp: 90 | function! s:class.disp() dict abort "{{{ 91 | echo self.string() 92 | endfunction "}}} 93 | 94 | " LOAD: 95 | let s:load = 1 96 | :DLOG '-1 class#more#dict is loading ...' 97 | function! class#more#dict#load(...) abort "{{{ 98 | if a:0 > 0 && !empty(a:1) && exists('s:load') 99 | unlet s:load 100 | return 0 101 | endif 102 | return s:load 103 | endfunction "}}} 104 | 105 | " TEST: 106 | function! class#more#dict#test(...) abort "{{{ 107 | return 0 108 | endfunction "}}} 109 | -------------------------------------------------------------------------------- /autoload/class/more/list.vim: -------------------------------------------------------------------------------- 1 | " Class: class#more#list 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-08-02 5 | " Modify: 2017-08-07 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#more#list' 15 | let s:class._version_ = 1 16 | 17 | function! class#more#list#class() abort "{{{ 18 | return s:class 19 | endfunction "}}} 20 | 21 | " NEW: 22 | function! class#more#list#new(...) abort "{{{ 23 | let l:obj = class#new(s:class, a:000) 24 | return l:obj 25 | endfunction "}}} 26 | " CTOR: 27 | function! class#more#list#ctor(this, ...) abort "{{{ 28 | if a:0 == 0 29 | let a:this.list_ = [] 30 | elseif type(a:1) == v:t_list 31 | let a:this.list_ = a:1 32 | else 33 | : ELOG '[class#more#list#ctor] expect a list variable' 34 | endif 35 | endfunction "}}} 36 | 37 | " OLD: 38 | function! class#more#list#old() abort "{{{ 39 | let l:class = class#old(s:class) 40 | return l:class 41 | endfunction "}}} 42 | 43 | " list: 44 | function! s:class.list() dict abort "{{{ 45 | if has_key(self, 'list_') 46 | return self.list_ 47 | else 48 | : ELOG '[class#more#list] ' . 'not implement list()' 49 | return [] 50 | endif 51 | endfunction "}}} 52 | 53 | " size: 54 | function! s:class.size() dict abort "{{{ 55 | return len(self.list()) 56 | endfunction "}}} 57 | " empty: 58 | function! s:class.empty() dict abort "{{{ 59 | return empty(self.list()) 60 | endfunction "}}} 61 | 62 | " string: 63 | function! s:class.string() dict abort "{{{ 64 | return string(self.list()) 65 | endfunction "}}} 66 | " disp: 67 | function! s:class.disp() dict abort "{{{ 68 | echo self.string() 69 | endfunction "}}} 70 | 71 | " LOAD: 72 | let s:load = 1 73 | :DLOG '-1 class#more#list is loading ...' 74 | function! class#more#list#load(...) abort "{{{ 75 | if a:0 > 0 && !empty(a:1) && exists('s:load') 76 | unlet s:load 77 | return 0 78 | endif 79 | return s:load 80 | endfunction "}}} 81 | 82 | " TEST: 83 | function! class#more#list#test(...) abort "{{{ 84 | return 0 85 | endfunction "}}} 86 | -------------------------------------------------------------------------------- /autoload/class/more/queue.vim: -------------------------------------------------------------------------------- 1 | " Class: class#more#queue 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-03-14 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#more#list#old() 14 | let s:class._name_ = 'class#more#queue' 15 | let s:class._version_ = 1 16 | 17 | function! class#more#queue#class() abort "{{{ 18 | return s:class 19 | endfunction "}}} 20 | 21 | " NEW: 22 | function! class#more#queue#new(...) abort "{{{ 23 | let l:obj = class#new(s:class, a:000) 24 | return l:obj 25 | endfunction "}}} 26 | " CTOR: 27 | function! class#more#queue#ctor(this, ...) abort "{{{ 28 | if a:0 == 0 29 | let a:this.queue_ = [] 30 | elseif type(a:1) == v:t_list 31 | let a:this.queue_ = a:1 32 | else 33 | : ELOG '[class#more#queue#ctor] expect a list variable' 34 | endif 35 | let l:Suctor = class#Suctor(s:class) 36 | call l:Suctor(a:this, a:this.heap_) 37 | endfunction "}}} 38 | 39 | " queue: user class must implement, operate which list? 40 | function! s:class.queue() dict abort "{{{ 41 | if has_key(self, 'queue_') 42 | return self.queue_ 43 | else 44 | return self.list() 45 | endif 46 | endfunction "}}} 47 | 48 | " push: 49 | function! s:class.push(item) dict abort "{{{ 50 | let l:queue = self.queue() 51 | call add(l:queue, a:item) 52 | endfunction "}}} 53 | 54 | " shift: 55 | function! s:class.shift() dict abort "{{{ 56 | let l:queue = self.queue() 57 | if empty(l:queue) 58 | return '' 59 | endif 60 | return remove(l:queue, 0) 61 | endfunction "}}} 62 | 63 | " front: 64 | function! s:class.front() dict abort "{{{ 65 | let l:queue = self.queue() 66 | if empty(l:queue) 67 | return '' 68 | endif 69 | return l:queue[0] 70 | endfunction "}}} 71 | 72 | " LOAD: 73 | let s:load = 1 74 | :DLOG '-1 class#more#queue is loading ...' 75 | function! class#more#queue#load(...) abort "{{{ 76 | if a:0 > 0 && !empty(a:1) && exists('s:load') 77 | unlet s:load 78 | return 0 79 | endif 80 | return s:load 81 | endfunction "}}} 82 | 83 | " TEST: 84 | function! class#more#queue#test(...) abort "{{{ 85 | return 0 86 | endfunction "}}} 87 | -------------------------------------------------------------------------------- /autoload/class/more/stack.vim: -------------------------------------------------------------------------------- 1 | " Class: class#more#stack 2 | " Author: lymslive 3 | " Description: used a stack 4 | " Create: 2017-03-14 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#more#list#old() 14 | let s:class._name_ = 'class#more#stack' 15 | let s:class._version_ = 1 16 | 17 | function! class#more#stack#class() abort "{{{ 18 | return s:class 19 | endfunction "}}} 20 | 21 | " NEW: 22 | function! class#more#stack#new(...) abort "{{{ 23 | let l:obj = class#new(s:class, a:000) 24 | return l:obj 25 | endfunction "}}} 26 | " CTOR: 27 | function! class#more#stack#ctor(this, ...) abort "{{{ 28 | if a:0 == 0 29 | let a:this.stack_ = [] 30 | elseif type(a:1) == v:t_list 31 | let a:this.stack_ = a:1 32 | else 33 | : ELOG '[class#more#stack#ctor] expect a list variable' 34 | endif 35 | let l:Suctor = class#Suctor(s:class) 36 | call l:Suctor(a:this, a:this.stack_) 37 | endfunction "}}} 38 | 39 | " stack: user class must implement, operate which list? 40 | function! s:class.stack() dict abort "{{{ 41 | if has_key(self, 'stack_') 42 | return self.stack_ 43 | else 44 | return self.list() 45 | endif 46 | endfunction "}}} 47 | 48 | " push: 49 | function! s:class.push(item) dict abort "{{{ 50 | let l:stack = self.stack() 51 | call add(l:stack, a:item) 52 | endfunction "}}} 53 | 54 | " pop: 55 | function! s:class.pop() dict abort "{{{ 56 | let l:stack = self.stack() 57 | if empty(l:stack) 58 | return '' 59 | endif 60 | return remove(l:stack, -1) 61 | endfunction "}}} 62 | 63 | " top: 64 | function! s:class.top() dict abort "{{{ 65 | let l:stack = self.stack() 66 | if empty(l:stack) 67 | return '' 68 | endif 69 | return l:stack[-1] 70 | endfunction "}}} 71 | 72 | " LOAD: 73 | let s:load = 1 74 | :DLOG '-1 class#more#stack is loading ...' 75 | function! class#more#stack#load(...) abort "{{{ 76 | if a:0 > 0 && !empty(a:1) && exists('s:load') 77 | unlet s:load 78 | return 0 79 | endif 80 | return s:load 81 | endfunction "}}} 82 | 83 | " TEST: 84 | function! class#more#stack#test(...) abort "{{{ 85 | return 0 86 | endfunction "}}} 87 | -------------------------------------------------------------------------------- /autoload/class/set/disjoint.vim: -------------------------------------------------------------------------------- 1 | " Class: class#set#disjoint 2 | " Author: lymslive 3 | " Description: Disjoint-set data structure 4 | " Refer: https://en.wikipedia.org/wiki/Disjoint-set_data_structure 5 | " Create: 2017-07-31 6 | " Modify: 2017-08-04 7 | 8 | "LOAD: 9 | if exists('s:load') && !exists('g:DEBUG') 10 | finish 11 | endif 12 | 13 | " CLASS: 14 | let s:class = class#old() 15 | let s:class._name_ = 'class#set#disjoint' 16 | let s:class._version_ = 1 17 | 18 | " use an id to represent a node, id should be int or string 19 | " that use as a key of dictionary 20 | let s:class.hashid = {} 21 | 22 | " the node structure 23 | let s:struct = {} 24 | let s:struct.id = 0 25 | let s:struct.rank = 0 26 | let s:struct.parent = {} 27 | 28 | function! class#set#disjoint#class() abort "{{{ 29 | return s:class 30 | endfunction "}}} 31 | 32 | " NEW: 33 | function! class#set#disjoint#new(...) abort "{{{ 34 | let l:obj = class#new(s:class, a:000) 35 | return l:obj 36 | endfunction "}}} 37 | " CTOR: 38 | function! class#set#disjoint#ctor(this, ...) abort "{{{ 39 | " let l:Suctor = class#Suctor(s:class) 40 | " call l:Suctor(a:this) 41 | 42 | " let a:this.hashid = {} 43 | endfunction "}}} 44 | 45 | " ISOBJECT: 46 | function! class#set#disjoint#isobject(that) abort "{{{ 47 | return class#isobject(s:class, a:that) 48 | endfunction "}}} 49 | 50 | " MakeSet: 51 | function! s:class.MakeSet(id) dict abort "{{{ 52 | if !has_key(self.hashid, a:id) 53 | let l:item = copy(s:struct) 54 | let l:item.id = a:id 55 | let l:item.rank = 0 56 | let l:item.parent = l:item 57 | let self.hashid[a:id] = l:item 58 | else 59 | : ELOG '[#disjoint.MakeSet] already in set, id: ' . a:id 60 | endif 61 | return self 62 | endfunction "}}} 63 | 64 | " Find: 65 | function! s:class.Find(id) dict abort "{{{ 66 | if !has_key(self.hashid, a:id) 67 | : ELOG '[#disjoint.Find] not in set, id: ' . a:id 68 | return 0 69 | endif 70 | let l:item = self.hashid[a:id] 71 | let l:root = self.FindItem_(l:item) 72 | return l:root.id 73 | endfunction "}}} 74 | 75 | " FindItem_: 76 | " find by item object, recursive algorithm 77 | function! s:class.FindItem_(item) dict abort "{{{ 78 | let l:item = a:item 79 | if l:item.parent isnot l:item 80 | let l:item.parent = self.FindItem_(l:item.parent) 81 | endif 82 | return l:item.parent 83 | endfunction "}}} 84 | 85 | " Union: 86 | function! s:class.Union(idX, idY) dict abort "{{{ 87 | let l:ridX = self.Find(a:idX) 88 | let l:ridY = self.Find(a:idY) 89 | 90 | if l:ridX ==# l:ridY 91 | return self 92 | endif 93 | let l:rootX = self.hashid[l:ridX] 94 | let l:rootY = self.hashid[l:ridY] 95 | 96 | if l:rootX.rank < l:rootY.rank 97 | let l:rootX.parent = l:rootY 98 | elseif l:rootX.rank > l:rootY.rank 99 | let l:rootY.parent = l:rootX 100 | else 101 | let l:rootY.parent = l:rootX 102 | let l:rootX.rank += 1 103 | endif 104 | 105 | return self 106 | endfunction "}}} 107 | 108 | " Free: break cycle reference 109 | function! s:class.Free() dict abort "{{{ 110 | for [l:key, l:item] in items(self.hashid) 111 | unlet! l:item.parent 112 | unlet l:key l:item 113 | endfor 114 | endfunction "}}} 115 | 116 | " LOAD: 117 | let s:load = 1 118 | :DLOG '-1 class#set#disjoint is loading ...' 119 | function! class#set#disjoint#load(...) abort "{{{ 120 | if a:0 > 0 && !empty(a:1) && exists('s:load') 121 | unlet s:load 122 | return 0 123 | endif 124 | return s:load 125 | endfunction "}}} 126 | 127 | " TEST: 128 | function! class#set#disjoint#test(...) abort "{{{ 129 | return 0 130 | endfunction "}}} 131 | -------------------------------------------------------------------------------- /autoload/class/textfile.vim: -------------------------------------------------------------------------------- 1 | " Class: class#textfile 2 | " Author: lymslive 3 | " Description: deal with a text file 4 | " Create: 2017-03-22 5 | " Modify: 2017-08-04 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#textfile' 15 | let s:class._version_ = 1 16 | 17 | " absolute path of file 18 | let s:class.path = '' 19 | " let self.content_ = [] 20 | 21 | function! class#textfile#class() abort "{{{ 22 | return s:class 23 | endfunction "}}} 24 | 25 | " NEW: new(path) 26 | function! class#textfile#new(...) abort "{{{ 27 | let l:obj = class#new(s:class, a:000) 28 | return l:obj 29 | endfunction "}}} 30 | " CTOR: 31 | function! class#textfile#ctor(this, ...) abort "{{{ 32 | if a:0 < 1 || empty(a:1) 33 | :ELOG 'class#textfile expect a path' 34 | return -1 35 | else 36 | let a:this.path = expand(a:1) 37 | endif 38 | endfunction "}}} 39 | 40 | " OLD: 41 | function! class#textfile#old() abort "{{{ 42 | let l:class = class#old(s:class) 43 | return l:class 44 | endfunction "}}} 45 | 46 | " ISOBJECT: 47 | function! class#textfile#isobject(that) abort "{{{ 48 | return class#isobject(s:class, a:that) 49 | endfunction "}}} 50 | 51 | " string: represent file path 52 | function! s:class.string() dict abort "{{{ 53 | return self.path 54 | endfunction "}}} 55 | 56 | " number: represent count of lines 57 | function! s:class.number() dict abort "{{{ 58 | return len(self.list()) 59 | endfunction "}}} 60 | 61 | " list: represent the content lines 62 | function! s:class.list() dict abort "{{{ 63 | if has_key(self, 'content_') 64 | return self.content_ 65 | endif 66 | 67 | let l:pFileName = self.string() 68 | if !filereadable(l:pFileName) 69 | let self.content_ = [] 70 | else 71 | let self.content_ = readfile(l:pFileName) 72 | endif 73 | 74 | return self.content_ 75 | endfunction "}}} 76 | 77 | " CanRead: 78 | function! s:class.CanRead() dict abort "{{{ 79 | return filereadable(self.path) 80 | endfunction "}}} 81 | " CanWrite: 82 | function! s:class.CanWrite() dict abort "{{{ 83 | return filewritable(self.path) 84 | endfunction "}}} 85 | " Read: 86 | function! s:class.Read() dict abort "{{{ 87 | return readfile(self.pah) 88 | endfunction "}}} 89 | " Write: 90 | " Write() write self.content_ to file 91 | " Write('flag') write self.content_ to file with flag, such as 'a' 92 | " Write([list]) write list of content to file, overwritten. 93 | function! s:class.Write(...) dict abort "{{{ 94 | if !self.CanWrite() 95 | return -1 96 | endif 97 | 98 | let l:pDiretory = fnamemodify(self.path, ':p:h') 99 | if !isdirectory(l:pDiretory) 100 | call mkdir(l:pDiretory, 'p') 101 | endif 102 | 103 | if a:0 == 0 || empty(a:1) 104 | if has_key(self.content_) 105 | return writefile(self.content_, self.path) 106 | else 107 | return -1 108 | endif 109 | endif 110 | 111 | if type(a:1) == type('') 112 | let l:flag = a:1 113 | if has_key(self.content_) 114 | return writefile(self.content_, self.path, l:flag) 115 | else 116 | return -1 117 | endif 118 | elseif type(a:1) == type([]) 119 | let l:lsContent = a:1 120 | return writefile(l:lsContent, self.path) 121 | else 122 | :ELOG 'class#textfile.write() expect a flag string or list content' 123 | return -1 124 | endif 125 | endfunction "}}} 126 | 127 | " Clear: 128 | function! s:class.Clear() dict abort "{{{ 129 | let self.content_ = [] 130 | endfunction "}}} 131 | 132 | " Append: 133 | function! s:class.Append(sLine) dict abort "{{{ 134 | call add(self.list(), sLine) 135 | endfunction "}}} 136 | 137 | " LOAD: 138 | let s:load = 1 139 | :DLOG '-1 class#textfile is loading ...' 140 | function! class#textfile#load(...) abort "{{{ 141 | if a:0 > 0 && !empty(a:1) && exists('s:load') 142 | unlet s:load 143 | return 0 144 | endif 145 | return s:load 146 | endfunction "}}} 147 | 148 | " TEST: 149 | function! class#textfile#test(...) abort "{{{ 150 | return 0 151 | endfunction "}}} 152 | -------------------------------------------------------------------------------- /autoload/class/tree/binary.vim: -------------------------------------------------------------------------------- 1 | " Class: class#tree#binary 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-08-02 5 | " Modify: 2017-08-03 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#tree#binary' 15 | let s:class._version_ = 1 16 | 17 | let s:class.parent = {} 18 | let s:class.left = {} 19 | let s:class.right = {} 20 | let s:class.key_ = 0 21 | 22 | function! class#tree#binary#class() abort "{{{ 23 | return s:class 24 | endfunction "}}} 25 | 26 | " NEW: 27 | function! class#tree#binary#new(...) abort "{{{ 28 | let l:obj = copy(s:class) 29 | call l:obj._new_(a:000, 1) 30 | return l:obj 31 | endfunction "}}} 32 | " CTOR: 33 | function! class#tree#binary#ctor(this, ...) abort "{{{ 34 | let l:Suctor = s:class._suctor_() 35 | call l:Suctor(a:this) 36 | endfunction "}}} 37 | 38 | " ISOBJECT: 39 | function! class#tree#binary#isobject(that) abort "{{{ 40 | return s:class._isobject_(a:that) 41 | endfunction "}}} 42 | 43 | " LOAD: 44 | let s:load = 1 45 | :DLOG '-1 class#tree#binary is loading ...' 46 | function! class#tree#binary#load(...) abort "{{{ 47 | if a:0 > 0 && !empty(a:1) && exists('s:load') 48 | unlet s:load 49 | return 0 50 | endif 51 | return s:load 52 | endfunction "}}} 53 | 54 | " TEST: 55 | function! class#tree#binary#test(...) abort "{{{ 56 | return 0 57 | endfunction "}}} 58 | -------------------------------------------------------------------------------- /autoload/class/tree/branch.vim: -------------------------------------------------------------------------------- 1 | " Class: class#tree#branch 2 | " Author: lymslive 3 | " Description: a tree with many children 4 | " Create: 2017-08-02 5 | " Modify: 2017-08-13 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#tree#branch' 15 | let s:class._version_ = 1 16 | 17 | let s:class.parent = {} 18 | let s:class.children = {} 19 | let s:class.key_ = 0 20 | 21 | function! class#tree#branch#class() abort "{{{ 22 | return s:class 23 | endfunction "}}} 24 | 25 | " NEW: 26 | function! class#tree#branch#new(...) abort "{{{ 27 | let l:obj = copy(s:class) 28 | call l:obj._new_(a:000, 1) 29 | return l:obj 30 | endfunction "}}} 31 | " CTOR: 32 | function! class#tree#branch#ctor(this, ...) abort "{{{ 33 | let l:Suctor = s:class._suctor_() 34 | call l:Suctor(a:this) 35 | endfunction "}}} 36 | 37 | " ISOBJECT: 38 | function! class#tree#branch#isobject(that) abort "{{{ 39 | return s:class._isobject_(a:that) 40 | endfunction "}}} 41 | 42 | " IsRoot: 43 | function! s:class.IsRoot() dict abort "{{{ 44 | return !has_key(self, 'parent') || empty(self.parent) 45 | endfunction "}}} 46 | 47 | " IsLeaf: 48 | function! s:class.IsLeaf() dict abort "{{{ 49 | return !has_key(self, 'children') || empty(self.children) 50 | endfunction "}}} 51 | 52 | " PathUpward: 53 | function! s:class.PathUpward() dict abort "{{{ 54 | let l:node = self 55 | let l:lsPath = [l:node] 56 | while has_key(l:node, 'parent') && !empty(l:node.parent) 57 | call add(l:lsPath, l:node.parent) 58 | let l:node = l:node.parent 59 | endwhile 60 | endfunction "}}} 61 | 62 | " LOAD: 63 | let s:load = 1 64 | :DLOG '-1 class#tree#branch is loading ...' 65 | function! class#tree#branch#load(...) abort "{{{ 66 | if a:0 > 0 && !empty(a:1) && exists('s:load') 67 | unlet s:load 68 | return 0 69 | endif 70 | return s:load 71 | endfunction "}}} 72 | 73 | " TEST: 74 | function! class#tree#branch#test(...) abort "{{{ 75 | return 0 76 | endfunction "}}} 77 | -------------------------------------------------------------------------------- /autoload/class/tree/file.vim: -------------------------------------------------------------------------------- 1 | " Class: class#tree#file 2 | " Author: lymslive 3 | " Description: file system tree 4 | " Create: 2017-08-02 5 | " Modify: 2017-08-13 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#tree#branch#old() 14 | let s:class._name_ = 'class#tree#file' 15 | let s:class._version_ = 1 16 | 17 | let s:class.name = '' 18 | let s:class.size = 0 19 | let s:class.type = '' 20 | let s:class.time = 0 21 | let s:class.perm = '' 22 | 23 | function! class#tree#file#class() abort "{{{ 24 | return s:class 25 | endfunction "}}} 26 | 27 | " NEW: 28 | function! class#tree#file#new(...) abort "{{{ 29 | let l:obj = copy(s:class) 30 | call l:obj._new_(a:000, 1) 31 | return l:obj 32 | endfunction "}}} 33 | " CTOR: 34 | function! class#tree#file#ctor(this, ...) abort "{{{ 35 | let l:Suctor = s:class._suctor_() 36 | call l:Suctor(a:this) 37 | endfunction "}}} 38 | 39 | " ISOBJECT: 40 | function! class#tree#file#isobject(that) abort "{{{ 41 | return s:class._isobject_(a:that) 42 | endfunction "}}} 43 | 44 | " FullName: 45 | function! s:class.FullName() dict abort "{{{ 46 | let l:lsPath = self.PathUpward() 47 | let l:lsPath = reverse(l:lsPath) 48 | let l:lsPath = map(l:lsPath, 'v:val.name') 49 | let l:rtp = class#less#rtp#export() 50 | return l:rtp.slash . join(l:lsPath, l:rtp.slash) 51 | endfunction "}}} 52 | 53 | " ReadNode: 54 | " read file information from full path, into this object 55 | function! s:class.ReadNode(path) dict abort "{{{ 56 | let self.name = fnamemodify(a:path, ':p:t') 57 | let self.type = getftype(a:path) 58 | let self.size = getfsize(a:path) 59 | let self.perm = getfperm(a:path) 60 | let self.time = getftime(a:path) 61 | 62 | if self.type =~? 'dir' 63 | 64 | endif 65 | endfunction "}}} 66 | 67 | " AddChild: 68 | function! s:class.AddChild(child) dict abort "{{{ 69 | if !class#tree#file#isobject(a:child) 70 | : ELOG 'expect an object of class#tree#file' 71 | return self 72 | endif 73 | 74 | if empty(a:child.name) 75 | : ELOG 'child has no name?' 76 | return self 77 | endif 78 | 79 | let self.children[a:child.name] = a:child 80 | return self 81 | endfunction "}}} 82 | 83 | " LOAD: 84 | let s:load = 1 85 | :DLOG '-1 class#tree#file is loading ...' 86 | function! class#tree#file#load(...) abort "{{{ 87 | if a:0 > 0 && !empty(a:1) && exists('s:load') 88 | unlet s:load 89 | return 0 90 | endif 91 | return s:load 92 | endfunction "}}} 93 | 94 | " TEST: 95 | function! class#tree#file#test(...) abort "{{{ 96 | return 0 97 | endfunction "}}} 98 | -------------------------------------------------------------------------------- /autoload/class/tree/fs.vim: -------------------------------------------------------------------------------- 1 | " Class: class#tree#fs 2 | " Author: lymslive 3 | " Description: file system 4 | " Create: 2017-08-13 5 | " Modify: 2017-08-13 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#tree#fs' 15 | let s:class._version_ = 1 16 | 17 | let s:class.root = class#new() 18 | 19 | function! class#tree#fs#class() abort "{{{ 20 | return s:class 21 | endfunction "}}} 22 | 23 | " NEW: 24 | function! class#tree#fs#new(...) abort "{{{ 25 | let l:obj = class#new(s:class, a:000) 26 | return l:obj 27 | endfunction "}}} 28 | " CTOR: 29 | function! class#tree#fs#ctor(this, ...) abort "{{{ 30 | let l:Suctor = class#Suctor(s:class) 31 | call call(l:Suctor, extend([a:this], a:000)) 32 | endfunction "}}} 33 | 34 | " ISOBJECT: 35 | function! class#tree#fs#isobject(that) abort "{{{ 36 | return class#isobject(s:class, a:that) 37 | endfunction "}}} 38 | 39 | " INSTANCE: 40 | " let s:instance = {} 41 | function! class#tree#fs#instance() abort "{{{ 42 | if !exists('s:instance') 43 | let s:instance = class#new(s:class) 44 | endif 45 | return s:instance 46 | endfunction "}}} 47 | 48 | " get: return a file object from full path string 49 | function! s:class.get(path) dict abort "{{{ 50 | let l:rtp = class#less#rtp#export() 51 | if !l:rtp.IsAbsolute(a:path) 52 | return {} 53 | endif 54 | 55 | let l:lsPath = split(a:path, l:rtp.slash) 56 | let l:jFile = self.root 57 | for l:sName in l:lsPath 58 | let l:jFile = get(l:jFile.children, l:sName, {}) 59 | if empty(l:jFile) 60 | break 61 | endif 62 | endfor 63 | 64 | return l:jFile 65 | endfunction "}}} 66 | 67 | function! s:class.add(path) dict abort "{{{ 68 | let l:rtp = class#less#rtp#export() 69 | if !l:rtp.IsAbsolute(a:path) 70 | return self 71 | endif 72 | 73 | let l:lsPath = split(a:path, l:rtp.slash) 74 | let l:parent = self.root 75 | for l:idx in len(l:lsPath) 76 | let l:sName = l:lsPath[l:idx] 77 | if !has_key(l:parent.children, l:sName) 78 | let l:child = class#tree#file#new() 79 | let l:subPath = l:rtp.MakePath(l:lsPath[0 : l:idx]) 80 | let l:subPath = l:rtp.slash . l:subPath 81 | call l:child.ReadNode(l:subPath) 82 | call l:parent.AddChild(l:child) 83 | endif 84 | let l:parent = l:parent.children[l:sName] 85 | endfor 86 | 87 | return l:parent 88 | endfunction "}}} 89 | 90 | " LOAD: 91 | let s:load = 1 92 | function! class#tree#fs#load(...) abort "{{{ 93 | if a:0 > 0 && !empty(a:1) 94 | unlet! s:load 95 | endif 96 | endfunction "}}} 97 | 98 | " TEST: 99 | function! class#tree#fs#test(...) abort "{{{ 100 | let l:obj = class#tree#fs#new() 101 | call class#echo(l:obj) 102 | endfunction "}}} 103 | -------------------------------------------------------------------------------- /autoload/class/viml/messager.vim: -------------------------------------------------------------------------------- 1 | " Class: class#viml#messager 2 | " Author: lymslive 3 | " Description: capture the vim command message output 4 | " Create: 2017-02-28 5 | " Modify: 2017-08-05 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#old() 14 | let s:class._name_ = 'class#viml#messager' 15 | let s:class._version_ = 1 16 | let s:class.command = '' 17 | 18 | function! class#viml#messager#class() abort "{{{ 19 | return s:class 20 | endfunction "}}} 21 | 22 | " NEW: 23 | function! class#viml#messager#new(...) abort "{{{ 24 | let l:obj = class#new(s:class, a:000) 25 | return l:obj 26 | endfunction "}}} 27 | 28 | " CTOR: 29 | function! class#viml#messager#ctor(this, ...) abort "{{{ 30 | if a:0 > 0 31 | let a:this.command = a:1 32 | endif 33 | endfunction "}}} 34 | 35 | " ISOBJECT: 36 | function! class#viml#messager#isobject(that) abort "{{{ 37 | return class#isobject(s:class, a:that) 38 | endfunction "}}} 39 | 40 | " Capture: 41 | function! s:class.Capture(...) dict abort "{{{ 42 | if a:0 > 0 && !empty(a:1) 43 | let self.command = a:1 44 | endif 45 | 46 | let l:sOut = '' 47 | try 48 | redir => l:sOut 49 | silent execute self.command 50 | finally 51 | redir END 52 | endtry 53 | 54 | return l:sOut 55 | endfunction "}}} 56 | 57 | " CaptureList: 58 | function! s:class.CaptureList(...) dict abort "{{{ 59 | if a:0 > 0 && !empty(a:1) 60 | let l:sOut = self.Capture(a:1) 61 | else 62 | let l:sOut = self.Capture() 63 | endif 64 | 65 | if !empty(l:sOut) 66 | return split(l:sOut, "\n") 67 | else 68 | return [] 69 | endif 70 | endfunction "}}} 71 | 72 | " LOAD: 73 | let s:load = 1 74 | :DLOG 'class#viml#messager is loading ...' 75 | function! class#viml#messager#load(...) abort "{{{ 76 | if a:0 > 0 && !empty(a:1) && exists('s:load') 77 | unlet s:load 78 | return 0 79 | endif 80 | return s:load 81 | endfunction "}}} 82 | 83 | " TEST: 84 | function! class#viml#messager#test(...) abort "{{{ 85 | if a:0 == 0 86 | :ELOG 'class#viml#messager#test need command argument' 87 | return 88 | endif 89 | let l:command = join(a:000) 90 | let l:obj = class#viml#messager#new(l:command) 91 | :LOG 'capture ' . l:command 92 | echo l:obj.Capture() 93 | 94 | let l:lsOutPut = l:obj.CaptureList() 95 | :LOG 'capture as list: ' . len(l:lsOutPut) 96 | echo l:lsOutPut 97 | 98 | return 0 99 | endfunction "}}} 100 | -------------------------------------------------------------------------------- /autoload/class/viml/option/base.vim: -------------------------------------------------------------------------------- 1 | " Class: class#viml#option#base 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-12 5 | " Modify: 2017-08-05 6 | 7 | " BASIC: 8 | let s:class = class#old() 9 | let s:class._name_ = 'class#viml#option#base' 10 | let s:class._version_ = 1 11 | 12 | let s:class.Char = '' 13 | let s:class.Name = '' 14 | let s:class.Desc = '' 15 | 16 | function! class#viml#option#base#class() abort "{{{ 17 | return s:class 18 | endfunction "}}} 19 | 20 | " NEW: 21 | function! class#viml#option#base#new(...) abort "{{{ 22 | let l:obj = class#new(s:class, a:000) 23 | return l:obj 24 | endfunction "}}} 25 | 26 | " CTOR: 27 | function! class#viml#option#base#ctor(this, ...) abort "{{{ 28 | if a:0 < 3 29 | echoerr '[class#viml#option#base] expcet 3 arguments: (Char, Name, Desc)' 30 | return 31 | endif 32 | 33 | let a:this.Char = a:1 34 | let a:this.Name = a:2 35 | let a:this.Desc = a:3 36 | endfunction "}}} 37 | 38 | " OLD: 39 | function! class#viml#option#base#old() abort "{{{ 40 | let l:class = class#old(s:class) 41 | return l:class 42 | endfunction "}}} 43 | 44 | " STRING: -c, --Name Desc 45 | " a:1, padding Name to this length, to make Desc align right 46 | function! s:class.string(...) dict abort "{{{ 47 | let l:sRet = self.DescName() 48 | 49 | if a:0 > 0 && a:1 > 0 50 | let l:iPadding = a:1 - len(self.Name) 51 | if l:iPadding > 0 52 | let l:sRet .= repeat(' ', l:iPadding) 53 | endif 54 | endif 55 | 56 | let l:sRet .= self.Desc 57 | 58 | return l:sRet 59 | endfunction "}}} 60 | 61 | " DescName: 62 | function! s:class.DescName() dict abort "{{{ 63 | if self.Name ==# '-' 64 | let l:sRet = '-' 65 | elseif self.Name ==# '--' 66 | let l:sRet = '--' 67 | else 68 | let l:sRet = '-' . self.Char . ', --' . self.Name 69 | endif 70 | return l:sRet 71 | endfunction "}}} 72 | 73 | function! s:class.number() dict abort "{{{ 74 | return self._version_ 75 | endfunction "}}} 76 | 77 | " LOAD: 78 | function! class#viml#option#base#load() abort "{{{ 79 | return 1 80 | endfunction "}}} 81 | 82 | " TEST: 83 | function! class#viml#option#base#test() abort "{{{ 84 | return 1 85 | endfunction "}}} 86 | -------------------------------------------------------------------------------- /autoload/class/viml/option/multiple.vim: -------------------------------------------------------------------------------- 1 | " Class: class#viml#option#multiple 2 | " Author: lymslive 3 | " Description: option with multiple argument 4 | " Create: 2017-02-25 5 | " Modify: 2017-08-05 6 | 7 | "LOAD: 8 | if exists('s:load') && !exists('g:DEBUG') 9 | finish 10 | endif 11 | 12 | " CLASS: 13 | let s:class = class#viml#option#pairs#old() 14 | let s:class._name_ = 'class#viml#option#multiple' 15 | let s:class._version_ = 1 16 | 17 | " redefien argument and default type 18 | unlet! s:class.Argument 19 | unlet! s:class.Default 20 | let s:class.Argument = [] 21 | let s:class.Default = [] 22 | 23 | function! class#viml#option#multiple#class() abort "{{{ 24 | return s:class 25 | endfunction "}}} 26 | 27 | " NEW: 28 | function! class#viml#option#multiple#new(...) abort "{{{ 29 | let l:obj = class#new(s:class, a:000) 30 | return l:obj 31 | endfunction "}}} 32 | 33 | " CTOR: 4 arguments 34 | function! class#viml#option#multiple#ctor(this, ...) abort "{{{ 35 | let l:Suctor = class#Suctor(s:class) 36 | call l:Suctor(a:this, a:1, a:2, a:3) 37 | 38 | let a:this.Argument = [] 39 | let a:this.Default = [] 40 | if a:0 > 3 41 | let a:this.HasDefault = v:true 42 | if type(a:4) == type([]) 43 | call extend(a:this.Default, a:4) 44 | else 45 | call add(a:this.Default, a:4) 46 | endif 47 | endif 48 | endfunction "}}} 49 | 50 | " SetValue: 51 | function! s:class.SetValue(arg) dict abort "{{{ 52 | let self.Set = v:true 53 | call add(self.Argument, a:arg) 54 | endfunction "}}} 55 | 56 | " ISOBJECT: 57 | function! class#viml#option#multiple#isobject(that) abort "{{{ 58 | return class#isobject(s:class, a:that) 59 | endfunction "}}} 60 | 61 | " LOAD: 62 | let s:load = 1 63 | :DLOG 'class#viml#option#multiple is loading ...' 64 | function! class#viml#option#multiple#load(...) abort "{{{ 65 | if a:0 > 0 && !empty(a:1) && exists('s:load') 66 | unlet s:load 67 | return 0 68 | endif 69 | return s:load 70 | endfunction "}}} 71 | 72 | " TEST: 73 | function! class#viml#option#multiple#test(...) abort "{{{ 74 | return 0 75 | endfunction "}}} 76 | -------------------------------------------------------------------------------- /autoload/class/viml/option/pairs.vim: -------------------------------------------------------------------------------- 1 | " Class: class#viml#option#pairs 2 | " Author: lymslive 3 | " Description: option with argument 4 | " Create: 2017-02-13 5 | " Modify: 2017-08-05 6 | 7 | " BASIC: 8 | let s:class = class#viml#option#single#old() 9 | let s:class._name_ = 'class#viml#option#pairs' 10 | let s:class._version_ = 1 11 | 12 | " the argument for this option 13 | let s:class.Argument = '' 14 | " user must provide argument for this option? 15 | let s:class.HasDefault = v:false 16 | " default value, if not provided, it's argument is must required 17 | let s:class.Default = '' 18 | 19 | function! class#viml#option#pairs#class() abort "{{{ 20 | return s:class 21 | endfunction "}}} 22 | 23 | " NEW: 24 | function! class#viml#option#pairs#new(...) abort "{{{ 25 | let l:obj = class#new(s:class, a:000) 26 | return l:obj 27 | endfunction "}}} 28 | 29 | " CTOR: 4 arguments 30 | function! class#viml#option#pairs#ctor(this, ...) abort "{{{ 31 | if a:0 < 3 32 | echoerr '[class#viml#option#pairs] expcet at least 3 arguments: (Char, Name, Desc)' 33 | return 34 | endif 35 | let l:Suctor = class#Suctor(s:class) 36 | call l:Suctor(a:this, a:1, a:2, a:3) 37 | if a:0 > 3 38 | let a:this.HasDefault = v:true 39 | let a:this.Default = a:4 40 | endif 41 | endfunction "}}} 42 | 43 | " OLD: 44 | function! class#viml#option#pairs#old() abort "{{{ 45 | let l:class = class#old(s:class) 46 | return l:class 47 | endfunction "}}} 48 | 49 | " ISOBJECT: 50 | function! class#viml#option#pairs#isobject(that) abort "{{{ 51 | return class#isobject(s:class, a:that) 52 | endfunction "}}} 53 | 54 | " Must: 55 | function! s:class.Must() dict abort "{{{ 56 | return !self.HasDefault 57 | endfunction "}}} 58 | 59 | " Value: 60 | " the value of argument for this option 61 | function! s:class.Value() dict abort "{{{ 62 | if self.Has() 63 | return self.Argument 64 | else 65 | return self.Default 66 | endif 67 | endfunction "}}} 68 | 69 | " SetValue: 70 | function! s:class.SetValue(arg) dict abort "{{{ 71 | let self.Set = v:true 72 | let self.Argument = a:arg 73 | endfunction "}}} 74 | 75 | " STRING: -c, --Name [+|-]Desc 76 | " a:1, padding Name to this length, to make Desc align right 77 | " the [+|-] before Desc show if this option has default 78 | " [+] requires user must provided a argument 79 | function! s:class.string(...) dict abort "{{{ 80 | let l:sRet = self.DescName() 81 | 82 | if a:0 > 0 && a:1 > 0 83 | let l:iPadding = a:1 - len(self.Name) 84 | if l:iPadding > 0 85 | let l:sRet .= repeat(' ', l:iPadding) 86 | endif 87 | endif 88 | 89 | if self.Must() 90 | let l:sRet .= ' [+]' . self.Desc 91 | else 92 | let l:sRet .= ' [-]' . self.Desc . '('. string(self.Default) . ')' 93 | endif 94 | 95 | return l:sRet 96 | endfunction "}}} 97 | 98 | " LOAD: 99 | function! class#viml#option#pairs#load() abort "{{{ 100 | return 1 101 | endfunction "}}} 102 | 103 | " TEST: 104 | function! class#viml#option#pairs#test() abort "{{{ 105 | return 1 106 | endfunction "}}} 107 | -------------------------------------------------------------------------------- /autoload/class/viml/option/single.vim: -------------------------------------------------------------------------------- 1 | " Class: class#viml#option#single 2 | " Author: lymslive 3 | " Description: option without argument 4 | " Create: 2017-02-12 5 | " Modify: 2017-08-05 6 | 7 | " BASIC: 8 | let s:class = class#viml#option#base#old() 9 | let s:class._name_ = 'class#viml#option#single' 10 | let s:class._version_ = 1 11 | 12 | " dose this option is set? // v:false 13 | let s:class.Set = v:false 14 | 15 | function! class#viml#option#single#class() abort "{{{ 16 | return s:class 17 | endfunction "}}} 18 | 19 | " NEW: 20 | function! class#viml#option#single#new(...) abort "{{{ 21 | let l:obj = class#new(s:class, a:000) 22 | return l:obj 23 | endfunction "}}} 24 | 25 | " CTOR: 3 arguments 26 | function! class#viml#option#single#ctor(this, ...) abort "{{{ 27 | if a:0 < 3 28 | echoerr '[class#viml#option#single] expcet 3 arguments: (Char, Name, Desc)' 29 | return 30 | endif 31 | let l:Suctor = class#Suctor(s:class) 32 | call l:Suctor(a:this, a:1, a:2, a:3) 33 | endfunction "}}} 34 | 35 | " OLD: 36 | function! class#viml#option#single#old() abort "{{{ 37 | let l:class = class#old(s:class) 38 | return l:class 39 | endfunction "}}} 40 | 41 | " ISOBJECT: 42 | function! class#viml#option#single#isobject(that) abort "{{{ 43 | return class#isobject(s:class, a:that) 44 | endfunction "}}} 45 | 46 | " Has: 47 | function! s:class.Has() dict abort "{{{ 48 | return self.Set 49 | endfunction "}}} 50 | 51 | " Value: this type option is just boolean, set or unset 52 | function! s:class.Value() dict abort "{{{ 53 | if self.Has() 54 | return 1 55 | else 56 | return 0 57 | endif 58 | endfunction "}}} 59 | 60 | " SetValue: 61 | function! s:class.SetValue() dict abort "{{{ 62 | let self.Set = v:true 63 | endfunction "}}} 64 | 65 | " UnSet: 66 | function! s:class.UnSet() dict abort "{{{ 67 | let self.Set = v:false 68 | endfunction "}}} 69 | 70 | " STRING: -c, --Name [0]Desc 71 | " a:1, padding Name to this length, to make Desc align right 72 | " the [0] before Desc show this option need no more argument 73 | function! s:class.string(...) dict abort "{{{ 74 | let l:sRet = self.DescName() 75 | 76 | if self.Name ==# '-' 77 | let l:sRet .= '(single dash) ' . self.Desc 78 | return l:sRet 79 | elseif self.Name ==# '--' 80 | let l:sRet .= '(double dash) ' . self.Desc 81 | return l:sRet 82 | endif 83 | 84 | if a:0 > 0 && a:1 > 0 85 | let l:iPadding = a:1 - len(self.Name) 86 | if l:iPadding > 0 87 | let l:sRet .= repeat(' ', l:iPadding) 88 | endif 89 | endif 90 | 91 | let l:sRet .= ' [0]' . self.Desc 92 | 93 | return l:sRet 94 | endfunction "}}} 95 | 96 | " LOAD: 97 | function! class#viml#option#single#load() abort "{{{ 98 | return 1 99 | endfunction "}}} 100 | 101 | " TEST: 102 | function! class#viml#option#single#test() abort "{{{ 103 | return 1 104 | endfunction "}}} 105 | -------------------------------------------------------------------------------- /autoload/cn/buffer.vim: -------------------------------------------------------------------------------- 1 | " File: buffer 2 | " Author: lymslive 3 | " Description: handle special buffer 4 | " Create: 2018-09-23 5 | " Modify: 2018-09-23 6 | 7 | let s:execute = package#imports('cn#util', 'execute') 8 | 9 | let s:AUX_OPTION = {'buftype': 'nofile', 'bufhidden':'hide'} 10 | lockvar s:AUX_OPTION 11 | 12 | " Func: s:auxbuffer 13 | " create an auxiliary buffer, with name and local option dict 14 | " return the bufnr. 15 | " if the auxiliary buffer with that name already exist, just return. 16 | " a:1 -- option dict 17 | " a:2 -- callback func without argument, to init the buffer 18 | function! s:auxbuffer(name, ...) abort "{{{ 19 | if bufnr(a:name) > 0 20 | return bufnr(a:name) 21 | endif 22 | if a:0 > 0 && type(a:1) == type({}) && !empty(a:1) 23 | let l:option = extend(copy(s:AUX_OPTION), a:1) 24 | else 25 | let l:option = s:AUX_OPTION 26 | endif 27 | 28 | call s:execute('hide edit %s', a:name) 29 | let l:bufnr = bufnr('%') 30 | call s:_setlocal(l:option) 31 | if a:0 >= 2 && type(a:2) == v:t_func 32 | call call(a:2, []) 33 | endif 34 | buffer # 35 | 36 | return l:bufnr 37 | endfunction "}}} 38 | 39 | " Func: s:_setlocal 40 | function! s:_setlocal(option) abort "{{{ 41 | for [l:opt, l:val] in items(a:option) 42 | call s:execute('setlocal %s=%s', l:opt, l:val) 43 | unlet l:opt l:val 44 | endfor 45 | endfunction "}}} 46 | -------------------------------------------------------------------------------- /autoload/cn/number.vim: -------------------------------------------------------------------------------- 1 | " File: number 2 | " Author: lymslive 3 | " Description: util for number 4 | " Create: 2018-09-30 5 | " Modify: 2018-09-30 6 | 7 | " Func: s:list 8 | function! s:list(number) abort "{{{ 9 | return range(a:number) 10 | endfunction "}}} 11 | 12 | " Func: s:cut_roof 13 | function! s:cut_roof(input, max) abort "{{{ 14 | return a:input < a:max ? a:input : a:max 15 | endfunction "}}} 16 | 17 | " Func: s:cut_floor 18 | function! s:cut_floor(input, min) abort "{{{ 19 | return a:input > min ? a:input : a:min 20 | endfunction "}}} 21 | 22 | " Func: s:cut_between 23 | function! s:cut_between(input, min, max) abort "{{{ 24 | if a:input <= a:min 25 | return a:min 26 | elseif a:input >= a:max 27 | return a:max 28 | else 29 | return a:input 30 | endif 31 | endfunction "}}} 32 | -------------------------------------------------------------------------------- /autoload/cn/readme.md: -------------------------------------------------------------------------------- 1 | # 个人及参考国人 viml 工具库 2 | 3 | 计划将自己常用的工具库放在 `cn#` 命名空间下。 4 | -------------------------------------------------------------------------------- /autoload/cn/util.vim: -------------------------------------------------------------------------------- 1 | " File: util 2 | " Author: lymslive 3 | " Description: some util functions 4 | " Create: 2017-03-06 5 | " Modify: 2018-09-22 6 | 7 | " GetAutoName: 8 | " my UltiSnips need this function 9 | function! cn#util#GetAutoName(pFileName) abort "{{{ 10 | let l:rtp = class#less#rtp#export() 11 | return l:rtp.GetAutoName(a:pFileName) 12 | endfunction "}}} 13 | 14 | " Func: s:execute 15 | " short for :execute printf(cmd, ...) 16 | function! s:execute(...) abort "{{{ 17 | if a:0 == 0 18 | return s:error('execute need at least a argument') 19 | elseif a:0 == 1 20 | let l:cmd = a:1 21 | else 22 | let l:cmd = call('printf', a:000) 23 | endif 24 | :WLOG l:cmd 25 | execute l:cmd 26 | return 0 27 | endfunction "}}} 28 | 29 | " Func: s:error 30 | " log a error msg and return a value 31 | function! s:error(msg, ...) abort "{{{ 32 | :ELOG a:msg 33 | return get(a:000, 0, 0) 34 | endfunction "}}} 35 | -------------------------------------------------------------------------------- /autoload/jp/Data/Base64.vim: -------------------------------------------------------------------------------- 1 | " Utilities for Base64. 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | function! s:encode(data) abort 7 | let b64 = s:_b64encode(s:_str2bytes(a:data), s:standard_table, '=') 8 | return join(b64, '') 9 | endfunction 10 | 11 | function! s:encodebin(data) abort 12 | let b64 = s:_b64encode(s:_binstr2bytes(a:data), s:standard_table, '=') 13 | return join(b64, '') 14 | endfunction 15 | 16 | function! s:decode(data) abort 17 | let bytes = s:_b64decode(split(a:data, '\zs'), s:standard_table, '=') 18 | return s:_bytes2str(bytes) 19 | endfunction 20 | 21 | let s:standard_table = [ 22 | \ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 23 | \ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 24 | \ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 25 | \ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'] 26 | 27 | function! s:_b64encode(bytes, table, pad) abort 28 | let b64 = [] 29 | for i in range(0, len(a:bytes) - 1, 3) 30 | let n = a:bytes[i] * 0x10000 31 | \ + get(a:bytes, i + 1, 0) * 0x100 32 | \ + get(a:bytes, i + 2, 0) 33 | call add(b64, a:table[n / 0x40000]) 34 | call add(b64, a:table[n / 0x1000 % 0x40]) 35 | call add(b64, a:table[n / 0x40 % 0x40]) 36 | call add(b64, a:table[n % 0x40]) 37 | endfor 38 | if len(a:bytes) % 3 == 1 39 | let b64[-1] = a:pad 40 | let b64[-2] = a:pad 41 | endif 42 | if len(a:bytes) % 3 == 2 43 | let b64[-1] = a:pad 44 | endif 45 | return b64 46 | endfunction 47 | 48 | function! s:_b64decode(b64, table, pad) abort 49 | let a2i = {} 50 | for i in range(len(a:table)) 51 | let a2i[a:table[i]] = i 52 | endfor 53 | let bytes = [] 54 | for i in range(0, len(a:b64) - 1, 4) 55 | let n = a2i[a:b64[i]] * 0x40000 56 | \ + a2i[a:b64[i + 1]] * 0x1000 57 | \ + (a:b64[i + 2] == a:pad ? 0 : a2i[a:b64[i + 2]]) * 0x40 58 | \ + (a:b64[i + 3] == a:pad ? 0 : a2i[a:b64[i + 3]]) 59 | call add(bytes, n / 0x10000) 60 | call add(bytes, n / 0x100 % 0x100) 61 | call add(bytes, n % 0x100) 62 | endfor 63 | if a:b64[-1] == a:pad 64 | unlet a:b64[-1] 65 | endif 66 | if a:b64[-2] == a:pad 67 | unlet a:b64[-1] 68 | endif 69 | return bytes 70 | endfunction 71 | 72 | function! s:_binstr2bytes(str) abort 73 | return map(range(len(a:str)/2), 'eval("0x".a:str[v:val*2 : v:val*2+1])') 74 | endfunction 75 | 76 | function! s:_str2bytes(str) abort 77 | return map(range(len(a:str)), 'char2nr(a:str[v:val])') 78 | endfunction 79 | 80 | function! s:_bytes2str(bytes) abort 81 | return eval('"' . join(map(copy(a:bytes), 'printf(''\x%02x'', v:val)'), '') . '"') 82 | endfunction 83 | 84 | let &cpo = s:save_cpo 85 | unlet s:save_cpo 86 | 87 | " vim:set et ts=2 sts=2 sw=2 tw=0: 88 | -------------------------------------------------------------------------------- /autoload/jp/Data/Collection.vim: -------------------------------------------------------------------------------- 1 | " Utilities both for list and dict. 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | function! s:get_f(collection, key, otherwise) abort 7 | " TODO make it work also for list 8 | if has_key(a:collection, a:key) 9 | return a:collection[a:key] 10 | else 11 | return function(a:otherwise)() 12 | endif 13 | endfunction 14 | 15 | let &cpo = s:save_cpo 16 | unlet s:save_cpo 17 | 18 | " vim:set et ts=2 sts=2 sw=2 tw=0: 19 | -------------------------------------------------------------------------------- /autoload/jp/Data/Dict.vim: -------------------------------------------------------------------------------- 1 | " Utilities for dictionary. 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | let s:t = package#import('jp#Vim#Type').types 7 | 8 | 9 | function! s:_ensure_key(key) abort 10 | let t = type(a:key) 11 | if t != s:t.string && t != s:t.number 12 | throw 'vital: Data.Dict: Invalid key: ' . string(a:key) 13 | endif 14 | endfunction 15 | 16 | function! s:from_list(list) abort 17 | let dict = {} 18 | let i = 0 19 | let len = len(a:list) 20 | while i < len 21 | if type(a:list[i]) == s:t.list 22 | let key_value = a:list[i] 23 | if len(key_value) != 2 24 | throw 'vital: Data.Dict: Invalid key-value pair index at ' . i 25 | endif 26 | call s:_ensure_key(key_value[0]) 27 | let dict[key_value[0]] = key_value[1] 28 | let i += 1 29 | else 30 | if len <= i + 1 31 | throw 'vital: Data.Dict: Invalid key-value pair index at ' . i 32 | endif 33 | call s:_ensure_key(a:list[i]) 34 | let dict[a:list[i]] = a:list[i + 1] 35 | let i += 2 36 | endif 37 | endwhile 38 | return dict 39 | endfunction 40 | 41 | " Makes a dict from keys and values 42 | function! s:make(keys, values, ...) abort 43 | let dict = {} 44 | let fill = a:0 ? a:1 : 0 45 | for i in range(len(a:keys)) 46 | let key = type(a:keys[i]) == s:t.string ? a:keys[i] : string(a:keys[i]) 47 | if key ==# '' 48 | throw "vital: Data.Dict: Can't use an empty string for key." 49 | endif 50 | let dict[key] = get(a:values, i, fill) 51 | endfor 52 | return dict 53 | endfunction 54 | 55 | " Swaps keys and values 56 | function! s:swap(dict) abort 57 | return s:make(values(a:dict), keys(a:dict)) 58 | endfunction 59 | 60 | " Makes a index dict from a list 61 | function! s:make_index(list, ...) abort 62 | let value = a:0 ? a:1 : 1 63 | return s:make(a:list, [], value) 64 | endfunction 65 | 66 | function! s:pick(dict, keys) abort 67 | let new_dict = {} 68 | for key in a:keys 69 | if has_key(a:dict, key) 70 | let new_dict[key] = a:dict[key] 71 | endif 72 | endfor 73 | return new_dict 74 | endfunction 75 | 76 | function! s:omit(dict, keys) abort 77 | let new_dict = copy(a:dict) 78 | for key in a:keys 79 | if has_key(a:dict, key) 80 | call remove(new_dict, key) 81 | endif 82 | endfor 83 | return new_dict 84 | endfunction 85 | 86 | function! s:clear(dict) abort 87 | for key in keys(a:dict) 88 | call remove(a:dict, key) 89 | endfor 90 | return a:dict 91 | endfunction 92 | 93 | function! s:_max_by(dict, expr) abort 94 | let dict = s:swap(map(copy(a:dict), a:expr)) 95 | let key = dict[max(keys(dict))] 96 | return [key, a:dict[key]] 97 | endfunction 98 | 99 | function! s:max_by(dict, expr) abort 100 | if empty(a:dict) 101 | throw 'vital: Data.Dict: Empty dictionary' 102 | endif 103 | return s:_max_by(a:dict, a:expr) 104 | endfunction 105 | 106 | function! s:min_by(dict, expr) abort 107 | if empty(a:dict) 108 | throw 'vital: Data.Dict: Empty dictionary' 109 | endif 110 | return s:_max_by(a:dict, '-(' . a:expr . ')') 111 | endfunction 112 | 113 | function! s:_foldl(f, init, xs) abort 114 | let memo = a:init 115 | for [k, v] in a:xs 116 | let expr = substitute(a:f, 'v:key', string(k), 'g') 117 | let expr = substitute(expr, 'v:val', string(v), 'g') 118 | let expr = substitute(expr, 'v:memo', string(memo), 'g') 119 | unlet memo 120 | let memo = eval(expr) 121 | endfor 122 | return memo 123 | endfunction 124 | 125 | function! s:foldl(f, init, dict) abort 126 | return s:_foldl(a:f, a:init, items(a:dict)) 127 | endfunction 128 | 129 | function! s:foldr(f, init, dict) abort 130 | return s:_foldl(a:f, a:init, reverse(items(a:dict))) 131 | endfunction 132 | 133 | let &cpo = s:save_cpo 134 | unlet s:save_cpo 135 | 136 | " vim:set et ts=2 sts=2 sw=2 tw=0: 137 | -------------------------------------------------------------------------------- /autoload/jp/Data/Optional.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:ARRAY_TYPE = type([]) 5 | 6 | function! s:none() abort 7 | return [] 8 | endfunction 9 | 10 | function! s:some(v) abort 11 | return [a:v] 12 | endfunction 13 | 14 | function! s:new(v, ...) abort 15 | if exists('v:null') 16 | return a:v == v:null || (a:0 > 0 && a:v == a:1) 17 | \ ? s:none() 18 | \ : s:some(a:v) 19 | elseif a:0 > 0 20 | return a:v == a:1 21 | \ ? s:none() 22 | \ : s:some(a:v) 23 | else 24 | throw 'vital: Data.Optional: both v:null and {null} are missing' 25 | endif 26 | endfunction 27 | 28 | function! s:is_optional(v) abort 29 | return type(a:v) == s:ARRAY_TYPE && len(a:v) <= 1 30 | endfunction 31 | 32 | function! s:empty(o) abort 33 | return empty(a:o) 34 | endfunction 35 | 36 | function! s:exists(o) abort 37 | return !empty(a:o) 38 | endfunction 39 | 40 | function! s:set(o, v) abort 41 | if empty(a:o) 42 | call add(a:o, a:v) 43 | else 44 | let a:o[0] = a:v 45 | endif 46 | endfunction 47 | 48 | function! s:unset(o) abort 49 | if !empty(a:o) 50 | unlet! a:o[0] 51 | endif 52 | endfunction 53 | 54 | function! s:get(o) abort 55 | if empty(a:o) 56 | throw 'vital: Data.Optional: An empty Data.Optional value' 57 | endif 58 | return a:o[0] 59 | endfunction 60 | 61 | function! s:get_unsafe(o) abort 62 | return a:o[0] 63 | endfunction 64 | 65 | function! s:get_or(o, alt) abort 66 | return get(a:o, 0, a:alt) 67 | endfunction 68 | 69 | function! s:has(o, type) abort 70 | if empty(a:o) 71 | return 0 72 | else 73 | return type(a:o[0]) == a:type 74 | endif 75 | endfunction 76 | 77 | function! s:_valid_args(args) abort 78 | for Arg in a:args 79 | if !s:is_optional(Arg) 80 | throw 'vital: Data.Optional: Non-optional argument' 81 | endif 82 | unlet Arg 83 | endfor 84 | 85 | for Arg in a:args 86 | if empty(Arg) 87 | return 0 88 | endif 89 | unlet Arg 90 | endfor 91 | 92 | return 1 93 | endfunction 94 | 95 | function! s:apply(f, ...) abort 96 | if !s:_valid_args(a:000) 97 | return s:none() 98 | endif 99 | 100 | return s:some(call(a:f, map(copy(a:000), 'v:val[0]'))) 101 | endfunction 102 | 103 | function! s:map(x, f) abort 104 | return s:apply(a:f, a:x) 105 | endfunction 106 | 107 | function! s:bind(f, ...) abort 108 | if !s:_valid_args(a:000) 109 | return s:none() 110 | endif 111 | 112 | return call(a:f, map(copy(a:000), 'v:val[0]')) 113 | endfunction 114 | 115 | function! s:flatten(o, ...) abort 116 | if (a:0 > 0 && a:1 == 0) 117 | \ || !s:is_optional(a:o) 118 | \ || empty(a:o) 119 | \ || !s:is_optional(a:o[0]) 120 | return a:o 121 | endif 122 | 123 | if a:0 > 0 124 | return s:flatten(a:o[0], a:1 - 1) 125 | else 126 | return s:flatten(a:o[0]) 127 | endif 128 | endfunction 129 | 130 | function! s:_echo(msg, hl) abort 131 | if empty(a:hl) 132 | echo a:msg 133 | else 134 | execute 'echohl' a:hl[0] 135 | echo a:msg 136 | echohl None 137 | endif 138 | endfunction 139 | 140 | function! s:echo(o, ...) abort 141 | if !s:is_optional(a:o) 142 | throw 'vital: Data.Optional: Not an optional value' 143 | endif 144 | 145 | if empty(a:o) 146 | call s:_echo('None', a:000) 147 | else 148 | call s:_echo('Some(' . string(a:o[0]) . ')', a:000) 149 | endif 150 | endfunction 151 | 152 | let &cpo = s:save_cpo 153 | unlet s:save_cpo 154 | -------------------------------------------------------------------------------- /autoload/jp/Data/OrderedSet.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | 5 | function! s:new(...) abort 6 | let obj = deepcopy(s:ordered_set) 7 | if a:0 8 | \ && type(a:1) == type({}) 9 | \ && has_key(a:1, 'Fn_identifier') 10 | let obj.Fn_identifier = a:1.Fn_identifier 11 | endif 12 | return obj 13 | endfunction 14 | 15 | 16 | let s:ordered_set = { 17 | \ '_list': [], 18 | \ '_dict': {}, 19 | \ '_origin_pos': 0, 20 | \ 'Fn_identifier': 'string', 21 | \} 22 | 23 | function! s:ordered_set.prepend(list) abort 24 | for V in reverse(a:list) 25 | call self.unshift(V) 26 | endfor 27 | endfunction 28 | 29 | function! s:ordered_set.append(list) abort 30 | for V in a:list 31 | call self.push(V) 32 | endfor 33 | endfunction 34 | 35 | function! s:ordered_set.push(elem) abort 36 | let id = call(self.Fn_identifier, [a:elem]) 37 | if !has_key(self._dict, id) 38 | let self._dict[id] = len(self._list) - self._origin_pos 39 | call add(self._list, a:elem) 40 | return 1 41 | endif 42 | return 0 43 | endfunction 44 | 45 | function! s:ordered_set.unshift(elem) abort 46 | let id = call(self.Fn_identifier, [a:elem]) 47 | if !has_key(self._dict, id) 48 | let self._origin_pos += 1 49 | let self._dict[id] = -self._origin_pos 50 | call insert(self._list, a:elem) 51 | return 1 52 | endif 53 | return 0 54 | endfunction 55 | 56 | function! s:ordered_set.empty() abort 57 | return empty(self._list) 58 | endfunction 59 | 60 | function! s:ordered_set.size() abort 61 | return len(self._list) 62 | endfunction 63 | 64 | function! s:ordered_set.to_list() abort 65 | return copy(self._list) 66 | endfunction 67 | 68 | function! s:ordered_set.has(elem) abort 69 | let id = call(self.Fn_identifier, [a:elem]) 70 | return has_key(self._dict, id) 71 | endfunction 72 | 73 | function! s:ordered_set.has_id(id) abort 74 | return has_key(self._dict, a:id) 75 | endfunction 76 | 77 | function! s:ordered_set.clear() abort 78 | let self._list = [] 79 | let self._dict = {} 80 | let self._origin_pos = 0 81 | endfunction 82 | 83 | function! s:ordered_set.remove(elem) abort 84 | let id = call(self.Fn_identifier, [a:elem]) 85 | if has_key(self._dict, id) 86 | let idx = self._origin_pos + self._dict[id] 87 | unlet self._dict[id] 88 | unlet self._list[idx] 89 | if idx < self._origin_pos 90 | for i in range(0, idx - 1) 91 | let id = call(self.Fn_identifier, [self._list[i]]) 92 | let self._dict[id] += 1 93 | endfor 94 | let self._origin_pos -= 1 95 | else 96 | for i in range(idx, len(self._list) - 1) 97 | let id = call(self.Fn_identifier, [self._list[i]]) 98 | let self._dict[id] -= 1 99 | endfor 100 | endif 101 | return 1 102 | endif 103 | return 0 104 | endfunction 105 | 106 | 107 | let &cpo = s:save_cpo 108 | unlet s:save_cpo 109 | 110 | " vim:set et ts=2 sts=2 sw=2 tw=0: 111 | -------------------------------------------------------------------------------- /autoload/jp/Data/String/Interpolation.vim: -------------------------------------------------------------------------------- 1 | " String interpolation in Vim script 2 | let s:save_cpo = &cpo 3 | set cpo&vim 4 | 5 | function! s:interpolate(string, ...) abort 6 | let context = get(a:, 1, {}) 7 | let str = a:string 8 | let ps = s:_parse_first_idx_range(str) 9 | while !empty(ps) 10 | let [s, e] = ps 11 | let expr = str[(s + len(s:_parser_config._ps)):(e - len(s:_parser_config._pend))] 12 | let V = s:_context_eval(expr, context) 13 | let str = (s > 0 ? str[0:(s-1)] : '') . V . str[(e+1):] 14 | let ps = s:_parse_first_idx_range(str, s + len(V)) 15 | unlet V 16 | endwhile 17 | return str 18 | endfunction 19 | 20 | "" Contextual eval() 21 | " NOTE: Old vim doesn't support extending l: 22 | " call extend(l:, a:context) 23 | function! s:_context_eval(expr, context) abort 24 | for s:key in filter(keys(a:context), "v:val =~# '^\\h\\w*$'") 25 | if type(a:context[s:key]) is# type(function('tr')) && s:key !~# '^\u' 26 | continue 27 | endif 28 | let {s:key} = a:context[s:key] 29 | endfor 30 | sandbox return eval(a:expr) 31 | endfunction 32 | 33 | " Pair Parser: 34 | let s:_parser_config = {} 35 | let s:_parser_config._ppr = '$' " pattern prefix 36 | let s:_parser_config._psb = '{' " pattern start bracket 37 | let s:_parser_config._ps = s:_parser_config._ppr . s:_parser_config._psb " pattern start 38 | let s:_parser_config._peb = '}' " pattern end bracket 39 | let s:_parser_config._psu = '' " pattern suffix 40 | let s:_parser_config._pend = s:_parser_config._peb . s:_parser_config._psu " pattern end 41 | 42 | " return [start_index, end_index] or [] if not found 43 | function! s:_parse_first_idx_range(str, ...) abort 44 | let i = get(a:, 1, 0) 45 | let level = 0 46 | let str_state = '' 47 | let str_DOUBLE = '"' 48 | let str_SINGLE = "'" 49 | while i < len(a:str) 50 | if a:str[(i):(i + len(s:_parser_config._ps)-1)] is# s:_parser_config._ps 51 | let j = i + len(s:_parser_config._ps) 52 | while j < len(a:str) 53 | if a:str[j] is# str_DOUBLE && str_state is# str_DOUBLE 54 | let str_state = '' 55 | elseif a:str[j] is# str_DOUBLE && str_state isnot# str_SINGLE 56 | let str_state = str_DOUBLE 57 | elseif a:str[j] is# str_SINGLE && str_state is# str_SINGLE 58 | let str_state = '' 59 | elseif a:str[j] is# str_SINGLE && str_state isnot# str_DOUBLE 60 | let str_state = str_SINGLE 61 | elseif str_state isnot# '' 62 | " pass 63 | elseif a:str[(j):(j + len(s:_parser_config._psb)-1)] is# s:_parser_config._psb 64 | let level += 1 65 | elseif a:str[(j):(j + len(s:_parser_config._pend)-1)] is# s:_parser_config._pend 66 | let level -= 1 67 | if level < 0 68 | return [i, j] 69 | endif 70 | elseif a:str[(j):(j + len(s:_parser_config._psb)-1)] is# s:_parser_config._psb 71 | let level -= 1 72 | endif 73 | let j += 1 74 | endwhile 75 | endif 76 | let i += 1 77 | endwhile 78 | return [] " not found 79 | endfunction 80 | 81 | let &cpo = s:save_cpo 82 | unlet s:save_cpo 83 | 84 | " vim:set et ts=2 sts=2 sw=2 tw=0: 85 | -------------------------------------------------------------------------------- /autoload/jp/Data/Tree.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! s:_renderer(idx, tree) abort 5 | let lines = [] 6 | let value = string(a:tree) 7 | let children = [] 8 | if type({}) is type(a:tree) 9 | let value = string(get(a:tree, 'token', '')) 10 | let children = get(a:tree, 'children', []) 11 | endif 12 | let lines += [ join(repeat(['|'], a:idx), ' ') . (a:idx is 0 ? '' : ' ') . '*' . ' ' . value ] 13 | for cidx in range(0, len(children) - 1) 14 | if cidx isnot len(a:tree.children) - 1 15 | let lines += [ join(repeat(['|'], (a:idx + 1)), ' ') . ' ' . '/' ] 16 | let lines += s:_renderer(a:idx+1, children[cidx]) 17 | let lines += [ join(repeat(['|'], a:idx + 1), ' ') ] 18 | else 19 | let lines += s:_renderer(a:idx, children[cidx]) 20 | endif 21 | endfor 22 | return lines 23 | endfunction 24 | 25 | function! s:new(token, ...) abort 26 | if type(a:token) == type({}) && has_key(a:token,'token') && has_key(a:token,'children') 27 | let obj = a:token 28 | else 29 | let obj = { 'token': a:token , 'children': a:0 > 0 30 | \ ? ( a:0 == 1 ? (type(a:1) == type([]) ? a:1 : [(a:1)]) 31 | \ : a:000 32 | \ ) 33 | \ : [] } 34 | endif 35 | 36 | function! obj.addchild(...) dict abort 37 | let self.children += map(copy(a:000), 'copy(v:val)') 38 | return self 39 | endfunction 40 | 41 | function! obj.todict() dict abort 42 | return { type(self.token) == type('') 43 | \ ? self.token : string(self.token) 44 | \ : map(copy(self.children),'type(v:val) == type({}) ? v:val.todict() : string(v:val)') } 45 | endfunction 46 | 47 | function! obj.preorder_traversal() dict abort 48 | let tkns = [] 49 | let tkns += [(self.token)] 50 | for child in self.children 51 | let tkns += s:new(child).preorder_traversal() 52 | unlet child 53 | endfor 54 | return tkns 55 | endfunction 56 | 57 | function! obj.inorder_traversal() dict abort 58 | let tkns = [] 59 | if ! empty(self.children) 60 | let tkns += s:new(get(self.children, 0, '')).inorder_traversal() 61 | endif 62 | let tkns += [(self.token)] 63 | if ! empty(self.children) 64 | let tkns += s:new(get(self.children, 1, '')).inorder_traversal() 65 | endif 66 | return tkns 67 | endfunction 68 | 69 | function! obj.postorder_traversal() dict abort 70 | let tkns = [] 71 | for child in self.children 72 | let tkns += s:new(child).preorder_traversal() 73 | unlet child 74 | endfor 75 | let tkns += [(self.token)] 76 | return tkns 77 | endfunction 78 | 79 | function! obj.renderer() dict abort 80 | return reverse(s:_renderer(0, self)) 81 | endfunction 82 | 83 | return copy(obj) 84 | endfunction 85 | 86 | let &cpo = s:save_cpo 87 | unlet s:save_cpo 88 | -------------------------------------------------------------------------------- /autoload/jp/Database/SQLite.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:P = package#import('jp#Process') 5 | 6 | let s:_debug_mode = 0 7 | 8 | function! s:is_available() abort 9 | return executable('sqlite3') 10 | endfunction 11 | 12 | function! s:_quote_escape(x) abort 13 | return printf('"%s"', escape(a:x, '"')) 14 | endfunction 15 | 16 | " This function name is long on purpose to discourage people to use that 17 | " frequently. 18 | function! s:build_line_from_query_with_placeholders(q, xs) abort 19 | let num_placeholders = len(split(a:q, '?', 1)) - 1 20 | call s:debug('build_line_from_query_with_placeholders', a:q, a:xs, 21 | \ {'num_placeholders': num_placeholders}) 22 | if len(a:xs) != num_placeholders 23 | throw "vital: Database.SQLite: build_line_from_query_with_placeholders() number of placeholders doesn't match." 24 | endif 25 | let line = substitute(a:q, '?', '%s', 'g') 26 | if num_placeholders > 0 27 | let line = call('printf', [line] + map(copy(a:xs), 's:_quote_escape(v:val)')) 28 | endif 29 | return line 30 | endfunction 31 | 32 | " s:query('a.db', 'SELECT * from b') == 33 | " s:query('a.db', 'SELECT * from b', []) 34 | function! s:query_rawdata(db, q, ...) abort 35 | if a:0 > 1 36 | throw 'vital: Database.SQLite: query() too many arguments' 37 | endif 38 | let xs = get(a:000, 0, []) 39 | " hmm... 40 | " if !filewritable(a:db) 41 | " throw printf("vital: Database.SQLite: given db (%s) isn't writable.", a:db) 42 | " endif 43 | let built = s:build_line_from_query_with_placeholders(a:q, xs) 44 | let cmd = printf( 45 | \ 'sqlite3 -batch -line %s', 46 | \ s:_quote_escape(a:db)) 47 | call s:debug('query', a:q, xs, 48 | \ {'built': built, 'cmd': cmd}) 49 | return s:P.system(cmd, built) 50 | endfunction 51 | 52 | " ' 53 | " x = 123a 54 | " 55 | " x = 999' 56 | " to [{'x':'123a'},{'x','999}] 57 | function! s:_to_vim(result) abort 58 | let chunks = split(a:result, "\r\\?\n\r\\?\n") 59 | call s:debug('parse_result', a:result, chunks) 60 | let l = [] 61 | for chunk in chunks 62 | let d = {} 63 | for line in split(chunk, "\r\\?\n") 64 | let tmp = matchlist(line, '^\s*\(\w\+\) = \(.*\)$') 65 | call s:debug(tmp) 66 | if len(tmp) > 3 67 | let d[tmp[1]] = tmp[2] 68 | endif 69 | endfor 70 | call add(l, d) 71 | endfor 72 | return l 73 | endfunction 74 | 75 | " s:query('a.db', 'SELECT * from b') == 76 | " s:query('a.db', 'SELECT * from b', []) 77 | function! s:query(db, q, ...) abort 78 | if a:0 > 1 79 | throw 'vital: Database.SQLite: query() too many arguments' 80 | endif 81 | let xs = get(a:000, 0, []) 82 | return s:_to_vim(s:query_rawdata(a:db, a:q, xs)) 83 | endfunction 84 | 85 | function! s:debug_mode_to(to) abort 86 | let s:_debug_mode = a:to 87 | endfunction 88 | 89 | function! s:debug(...) abort 90 | if s:_debug_mode 91 | echomsg string(a:000) 92 | endif 93 | endfunction 94 | 95 | let &cpo = s:save_cpo 96 | unlet s:save_cpo 97 | 98 | " vim:set et ts=2 sts=2 sw=2 tw=0: 99 | -------------------------------------------------------------------------------- /autoload/jp/Experimental/Functor.vim: -------------------------------------------------------------------------------- 1 | " "Callable thing" in vital. 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | 7 | " [Callable Object] is one of the following values: 8 | " - function name (String) 9 | " - Funcref value 10 | " - callable object 11 | " 12 | " [Functor] is a Dictionary which has the key "do" of Funcref value. 13 | " Please note that `Functor.wrap([Callable Object]).do` is always Funcref value. 14 | " So you can always call .do() method without checking return value of `Functor.wrap()`. 15 | " e.g.: `Functor.wrap("").do()` 16 | 17 | 18 | " The same arguments as call() 19 | " but first argument is [Callable Object]. 20 | function! s:call(callable, args, ...) abort 21 | let functor = s:wrap(a:callable) 22 | return call(functor.do, a:args, (a:0 ? a:1 : functor)) 23 | endfunction 24 | 25 | " Convert [Callable Object] to [Functor]. 26 | " NOTE: `s:wrap(callable).do` must be Funcref value. 27 | let s:TYPE_STRING = type('') 28 | let s:TYPE_FUNCREF = type(function('tr')) 29 | let s:TYPE_DICT = type({}) 30 | function! s:wrap(callable) abort 31 | if type(a:callable) ==# s:TYPE_FUNCREF 32 | return {'do': a:callable} 33 | elseif type(a:callable) ==# s:TYPE_STRING 34 | return {'do': function(a:callable)} 35 | elseif type(a:callable) ==# s:TYPE_DICT 36 | \ && has_key(a:callable, 'do') 37 | if type(a:callable.do) ==# s:TYPE_FUNCREF 38 | return a:callable 39 | elseif type(a:callable.do) ==# s:TYPE_STRING 40 | return extend(a:callable, { 41 | \ 'do': function(a:callable.do), 42 | \}, 'force') 43 | endif 44 | endif 45 | throw 'vital: Experimental.Functor: wrap(): ' 46 | \ . 'a:callable is not callable!' 47 | endfunction 48 | 49 | " Bind a:this to a:callable's `self`. 50 | function! s:bind(callable, this) abort 51 | let this = copy(a:this) 52 | let this.do = s:wrap(a:callable).do 53 | return this 54 | endfunction 55 | 56 | " Curry a:callable's 1st argument with a:v. 57 | function! s:curry(callable, v) abort 58 | return { 59 | \ 'do': s:localfunc('__curry_stub', s:__sid()), 60 | \ '__functor': s:wrap(a:callable), 61 | \ '__value': a:v, 62 | \} 63 | endfunction 64 | function! s:__curry_stub(...) dict abort 65 | return s:call(self.__functor, [self.__value] + a:000) 66 | endfunction 67 | function! s:__sid() abort 68 | return matchstr(expand(''), '\zs\d\+\ze___sid$') 69 | endfunction 70 | 71 | " Convert script-local function to globally callable function. 72 | function! s:localfunc(funcname, sid) abort 73 | return function(printf('%d_%s', a:sid, a:funcname)) 74 | endfunction 75 | 76 | 77 | let &cpo = s:save_cpo 78 | unlet s:save_cpo 79 | 80 | " vim:set et ts=2 sts=2 sw=2 tw=0: 81 | -------------------------------------------------------------------------------- /autoload/jp/Interpreter/Brainf__k.lua: -------------------------------------------------------------------------------- 1 | local public = {lua = {}, vim = {}} 2 | local P = _G[vim.eval('s:LuaP')].lua 3 | 4 | function public.lua.lua_parse(tokens) 5 | if tokens == '' then 6 | return {}, '' 7 | end 8 | 9 | local t = string.sub(tokens, 1, 1) 10 | local tokens = string.sub(tokens, 2) 11 | 12 | if t == '[' then 13 | local ast1, rest1 = public.lua.lua_parse(tokens) 14 | local ast2, rest2 = public.lua.lua_parse(rest1) 15 | return P.cons(ast1, ast2), rest2 16 | elseif t == ']' then 17 | return {}, tokens 18 | else -- TODO 19 | local asts, rest = public.lua.lua_parse(tokens) 20 | return P.cons(t, asts), rest 21 | end 22 | end 23 | 24 | local _ = {} 25 | 26 | function _.get(table, key, default) 27 | local x = table[key] 28 | if x then 29 | return x 30 | else 31 | return default 32 | end 33 | end 34 | 35 | function _.print_without_newline(str) 36 | -- TODO currently if_lua's io.write doesn't work as print since it's special 37 | vim.command(string.format('echon "%s"', str)) 38 | end 39 | 40 | function public.lua.lua_execute(asts, pointer, tape) 41 | if #asts == 0 then 42 | return pointer, tape 43 | end 44 | local ast = asts[1] 45 | local asts = P.rest(asts) 46 | 47 | if type(ast) == "table" then 48 | if _.get(tape, pointer, 0) == 0 then 49 | return public.lua.lua_execute(asts, pointer, tape) 50 | else 51 | local pointer, tape = public.lua.lua_execute(ast, pointer, tape) 52 | return public.lua.lua_execute(P.cons(ast, asts), pointer, tape) 53 | end 54 | else 55 | if ast == '+' then 56 | tape[pointer] = _.get(tape, pointer, 0) + 1 57 | return public.lua.lua_execute(asts, pointer, tape) 58 | elseif ast == '-' then 59 | tape[pointer] = _.get(tape, pointer, 0) - 1 60 | return public.lua.lua_execute(asts, pointer, tape) 61 | elseif ast == '>' then 62 | return public.lua.lua_execute(asts, pointer + 1, tape) 63 | elseif ast == '<' then 64 | return public.lua.lua_execute(asts, pointer - 1, tape) 65 | elseif ast == '.' then 66 | _.print_without_newline(string.char(_.get(tape, pointer, 0))) 67 | return public.lua.lua_execute(asts, pointer, tape) 68 | else 69 | return public.lua.lua_execute(asts, pointer, tape) 70 | end 71 | end 72 | end 73 | 74 | function public.vim.lua_parse(tokens) 75 | local asts, rest = public.lua.lua_parse(tokens) 76 | return P.from_lua({asts, rest}) 77 | end 78 | 79 | function public.vim.lua_execute(asts, pointer, tape) 80 | local tape = P.to_lua(tape) 81 | local asts = P.to_lua(asts) 82 | local pointer, tape = public.lua.lua_execute(asts, pointer, tape) 83 | return P.from_lua({pointer, tape}) 84 | end 85 | 86 | _G[vital_context] = public 87 | -------------------------------------------------------------------------------- /autoload/jp/Interpreter/Brainf__k.vim: -------------------------------------------------------------------------------- 1 | " Author: Tatsuhiro Ujihisa 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | let s:sfile = expand(':p') 7 | 8 | function! s:_vital_loaded(V) abort 9 | let s:V = a:V 10 | let s:Prelude = s:V.import('Prelude') 11 | 12 | if has('lua') 13 | let s:P = s:V.import('Deprecated.Lua.Prelude') 14 | let s:LuaP = s:P.lua_namespace() 15 | 16 | execute printf('lua vital_context = "%s"', escape(s:sfile, '\')) 17 | call luaeval('dofile(_A)', substitute(s:sfile, '.vim$', '.lua', '')) 18 | endif 19 | endfunction 20 | 21 | function! s:_vital_depends() abort 22 | return ['Prelude'] 23 | \ + (has('lua') ? ['Deprecated.Lua.Prelude'] : []) 24 | endfunction 25 | 26 | function! s:run(bfcode) abort 27 | call s:run_vim_parse_execute(a:bfcode) 28 | endfunction 29 | 30 | function! s:run_vim_parse_execute(bfcode) abort 31 | let [asts, rest] = s:_vim_parse(a:bfcode) 32 | if rest !=# '' 33 | throw 'vital: Interpreter.Brainf__k: run_vim_parse_execute(): parser failed to consume' 34 | endif 35 | call s:_vim_execute(asts, 0, {}) 36 | endfunction 37 | 38 | function! s:run_lua_parse_execute(bfcode) abort 39 | let [asts, rest] = s:_lua_parse(a:bfcode) 40 | if rest !=# '' 41 | throw 'vital: Interpreter.Brainf__k: run_vim_parse_execute(): parser failed to consume' 42 | endif 43 | call s:_lua_execute(asts, 0, {}) 44 | endfunction 45 | 46 | function! s:_vim_parse(tokens) abort 47 | if a:tokens ==# '' 48 | return [[], ''] 49 | endif 50 | 51 | let [t, tokens] = [a:tokens[0], a:tokens[1:]] 52 | 53 | if t ==# '[' 54 | let [ast1, rest1] = s:_vim_parse(tokens) 55 | let [ast2, rest2] = s:_vim_parse(rest1) 56 | return [[ast1] + ast2, rest2] 57 | elseif t ==# ']' 58 | return [[], tokens] 59 | elseif t =~# '[+-><,\.]' 60 | let [asts, rest] = s:_vim_parse(tokens) 61 | return [[t] + asts, rest] 62 | else 63 | return s:_vim_parse(tokens) 64 | endif 65 | endfunction 66 | 67 | function! s:_lua_parse(bfcode) abort 68 | return luaeval('_G[_A[0]].vim.lua_parse(_A[1])', [s:sfile, a:bfcode]) 69 | endfunction 70 | 71 | " args: 72 | " asts: a list of parsed ASTs 73 | " pointer: where to refer in tape (give 0 when you start) 74 | " tape: storage for BF (give {} when you start) 75 | " return: [pointer, tape] 76 | " the final state of pointer and tape to continue if you have more ASTs that 77 | " you didn't pass to the call. 78 | function! s:_vim_execute(asts, pointer, tape) abort 79 | let [asts, pointer, tape] = [a:asts, a:pointer, a:tape] 80 | while len(asts) > 0 81 | unlet! ast 82 | let [ast, asts] = [asts[0], asts[1:]] 83 | 84 | if s:Prelude.is_list(ast) 85 | if get(tape, pointer, 0) == 0 86 | " go next 87 | else 88 | let [pointer, tape] = s:_vim_execute(ast, pointer, tape) 89 | let asts = [ast] + asts 90 | endif 91 | else 92 | if ast ==# '+' 93 | let tape[pointer] = get(tape, pointer, 0) + 1 94 | elseif ast ==# '-' 95 | let tape[pointer] = get(tape, pointer, 0) - 1 96 | elseif ast ==# '>' 97 | let pointer += 1 98 | elseif ast ==# '<' 99 | let pointer -= 1 100 | elseif ast ==# '.' 101 | echon nr2char(get(tape, pointer, 0)) 102 | endif 103 | endif 104 | endwhile 105 | return [pointer, tape] 106 | endfunction 107 | 108 | function! s:_lua_execute(asts, pointer, tape) abort 109 | return luaeval('_G[_A[0]].vim.lua_execute(_A[1], _A[2], _A[3])', [s:sfile, a:asts, a:pointer, a:tape]) 110 | endfunction 111 | 112 | " let s:hello_world = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>." 113 | 114 | let &cpo = s:save_cpo 115 | unlet s:save_cpo 116 | -------------------------------------------------------------------------------- /autoload/jp/Locale/Message.vim: -------------------------------------------------------------------------------- 1 | " very simple message localization library. 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | function! s:new(path) abort 7 | let obj = copy(s:Message) 8 | let obj.path = a:path =~# '%s' ? a:path : 'message/' . a:path . '/%s.txt' 9 | return obj 10 | endfunction 11 | 12 | function! s:get_lang() abort 13 | return v:lang ==# 'C' ? 'en' : v:lang[: 1] 14 | endfunction 15 | 16 | let s:Message = {} 17 | function! s:Message.get(text) abort 18 | if !has_key(self, 'lang') 19 | call self.load(s:get_lang()) 20 | endif 21 | if has_key(self.data, a:text) 22 | return self.data[a:text] 23 | endif 24 | let text = self.missing(a:text) 25 | return type(text) == type('') ? text : a:text 26 | endfunction 27 | function! s:Message.load(lang) abort 28 | let pattern = printf(self.path, a:lang) 29 | let files = split(globpath(&runtimepath, pattern), "\n") 30 | let data = {} 31 | for file in files 32 | if filereadable(file) 33 | let lines = filter(readfile(file), 'v:val !~# "^\\s*#"') 34 | sandbox let res = eval(iconv(join(lines, ''), 'utf-8', &encoding)) 35 | if type(res) == type(data) 36 | call extend(data, res) 37 | endif 38 | unlet res 39 | endif 40 | endfor 41 | let self.lang = a:lang 42 | let self.data = data 43 | endfunction 44 | let s:Message._ = s:Message.get 45 | function! s:Message.missing(text) abort 46 | endfunction 47 | 48 | let &cpo = s:save_cpo 49 | unlet s:save_cpo 50 | 51 | " vim:set et ts=2 sts=2 sw=2 tw=0: 52 | -------------------------------------------------------------------------------- /autoload/jp/Math.vim: -------------------------------------------------------------------------------- 1 | " math utilities. 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | " TODO Simpler way? 7 | function! s:modulo(m, n) abort 8 | let d = a:m * a:n < 0 ? 1 : 0 9 | return a:m + (-(a:m + (0 < a:n ? d : -d)) / a:n + d) * a:n 10 | endfunction 11 | 12 | function! s:fib(n) abort 13 | let [a, b, i] = [0, 1, 0] 14 | while i < a:n 15 | let [a, b, i] = [b, a + b, i + 1] 16 | endwhile 17 | return a 18 | endfunction 19 | 20 | function! s:_lcm(m, n) abort 21 | if a:m == 0 || a:n == 0 22 | return 0 23 | endif 24 | return (a:m / s:_gcd(a:m, a:n)) * a:n 25 | endfunction 26 | 27 | function! s:_gcd(m, n) abort 28 | if a:m == 0 && a:n == 0 29 | return 0 30 | elseif a:m == 0 31 | return a:n 32 | elseif a:n == 0 33 | return a:m 34 | endif 35 | let tmp = 0 36 | let m = a:m 37 | let n = a:n 38 | while m % n != 0 39 | let tmp = n 40 | let n = m % n 41 | let m = tmp 42 | endwhile 43 | return n 44 | endfunction 45 | 46 | function! s:lcm(list) abort 47 | let list = map(a:list, 'abs(v:val)') 48 | if len(list) == 0 49 | throw 'vital: Math: Empty list' 50 | endif 51 | while len(list) > 1 52 | let list = [s:_lcm(list[0], list[1])] + list[2:] 53 | endwhile 54 | return list[0] 55 | endfunction 56 | 57 | function! s:gcd(list) abort 58 | let list = map(a:list, 'abs(v:val)') 59 | if len(list) == 0 60 | throw 'vital: Math: Empty list' 61 | endif 62 | while len(list) > 1 63 | let list = [s:_gcd(list[0], list[1])] + list[2:] 64 | endwhile 65 | return list[0] 66 | endfunction 67 | 68 | function! s:sum(list) abort 69 | let sum = 0 70 | for x in a:list 71 | if type(x) != type(0) && type(x) != type(0.0) 72 | throw 'vital: Math: Included not a number' 73 | endif 74 | let sum += x 75 | endfor 76 | return sum 77 | endfunction 78 | 79 | function! s:round(float, ...) abort 80 | let digits = get(a:, 1, 0) 81 | let n = pow(10.0, digits) 82 | return round(a:float*n)/n 83 | endfunction 84 | 85 | function! s:_get_num_digits(base) abort 86 | if a:base < 2 || a:base > 36 87 | throw 'vital: Math: base number must be from 2 to 36' 88 | endif 89 | return (map(range(0x30, 0x39) + range(0x41, 0x5A), 'nr2char(v:val)'))[0 : a:base-1] 90 | endfunction 91 | 92 | function! s:str2nr(str, ...) abort 93 | let base = get(a:000, 0, 10) 94 | let digits = s:_get_num_digits(base) 95 | let str = toupper(a:str) 96 | if a:str =~# '^-' 97 | let str = str[1:] 98 | let sign = -1 99 | else 100 | let sign = 1 101 | endif 102 | let total = 0 103 | let power_of_base = 1 104 | for c in reverse(split(str, '\zs')) 105 | let digit = index(digits, c) 106 | if digit == -1 107 | throw 'vital: Math: given string includes out of range character' 108 | endif 109 | let total += digit * power_of_base 110 | let power_of_base = power_of_base * base 111 | endfor 112 | 113 | return sign * total 114 | endfunction 115 | 116 | function! s:nr2str(n, ...) abort 117 | let base = get(a:000, 0, 10) 118 | let digits = s:_get_num_digits(base) 119 | let rest = a:n 120 | if rest == 0 121 | return '0' 122 | endif 123 | let sign = (rest >= 0) ? 1 : -1 124 | let rest = rest * sign 125 | let str = '' 126 | while rest > 0 127 | let str = digits[rest % base] . str 128 | let rest = rest / base 129 | endwhile 130 | if sign < 0 131 | let str = '-' . str 132 | endif 133 | return str 134 | endfunction 135 | 136 | 137 | let &cpo = s:save_cpo 138 | unlet s:save_cpo 139 | 140 | " vim:set et ts=2 sts=2 sw=2 tw=0: 141 | -------------------------------------------------------------------------------- /autoload/jp/Random.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Bitwise = package#import('jp#Bitwise') 5 | 6 | let s:loaded_generator_modules = {} 7 | 8 | let s:Random = {} 9 | 10 | function! s:Random.next(...) abort 11 | if a:0 12 | return map(range(a:1), 'self._generator.next()') 13 | endif 14 | return self._generator.next() 15 | endfunction 16 | 17 | function! s:Random.seed(seed) abort 18 | let seed = type(a:seed) == type([]) ? a:seed : [a:seed] 19 | return self._generator.seed(seed) 20 | endfunction 21 | 22 | function! s:Random.generate_canonical() abort 23 | let b = 32 24 | let min = self._generator.min() + 0.0 25 | let r = (self._generator.max() + 0.0) - min + 1.0 26 | let log2r = float2nr(log(r) / log(2.0)) 27 | let k = max([1, (b + log2r - 1) / log2r]) 28 | let sum = 0.0 29 | let tmp = 1.0 30 | while k != 0 31 | let sum += (self._generator.next() - min) * tmp 32 | let tmp = tmp * r 33 | let k -= 1 34 | endwhile 35 | return sum / tmp 36 | endfunction 37 | 38 | function! s:Random.range(from, ...) abort 39 | let [from, to] = a:0 ? [a:from, a:1] : [0, a:from] 40 | let range = to - from 41 | let base = self.generate_canonical() * range 42 | return (type(range) == type(0.0) ? base : float2nr(base)) + from 43 | endfunction 44 | 45 | function! s:Random.bool() abort 46 | return self.range(2) 47 | endfunction 48 | 49 | function! s:Random.sample(list, ...) abort 50 | if a:0 == 0 51 | return a:list[self.range(len(a:list))] 52 | endif 53 | let list = copy(a:list) 54 | let result = [] 55 | for _ in range(a:1) 56 | let result += [remove(list, self.range(len(list)))] 57 | endfor 58 | return result 59 | endfunction 60 | 61 | function! s:Random.shuffle(list) abort 62 | let pos = len(a:list) 63 | while 1 < pos 64 | let n = self.range(pos) 65 | let pos -= 1 66 | if n != pos 67 | let temp = a:list[n] 68 | let a:list[n] = a:list[pos] 69 | let a:list[pos] = temp 70 | endif 71 | endwhile 72 | return a:list 73 | endfunction 74 | 75 | 76 | function! s:make_seed() abort 77 | let seed = localtime() 78 | if has('reltime') 79 | let time = split(reltimestr(reltime()), '\.') 80 | for n in time 81 | let seed = s:Bitwise.xor(seed, str2nr(n)) 82 | endfor 83 | endif 84 | if exists('*getpid') 85 | let seed = s:Bitwise.xor(seed, getpid()) 86 | endif 87 | let seed = s:_seed_from_string(seed, expand('~')) 88 | return seed 89 | endfunction 90 | 91 | function! s:_seed_from_string(seed, str) abort 92 | let seed = a:seed 93 | for n in range(len(a:str)) 94 | let seed = s:Bitwise.xor(seed, s:Bitwise.lshift(a:str[n], n % 4)) 95 | endfor 96 | return seed 97 | endfunction 98 | 99 | function! s:new(...) abort 100 | let generator = a:0 ? a:1 : '' 101 | let seed = 2 <= a:0 ? a:2 : s:make_seed() 102 | let random = deepcopy(s:Random) 103 | let random._generator = s:_get_generator(generator) 104 | call random.seed(seed) 105 | return random 106 | endfunction 107 | 108 | function! s:_get_generator(arg) abort 109 | " todo: fix to select generator randomly in Random/ subdir 110 | let arg = 111 | \ empty(a:arg) 112 | \ ? 'Xor128' 113 | \ : a:arg 114 | if type(arg) == type('') 115 | if !has_key(s:loaded_generator_modules, arg) 116 | let module_name = 'jp#Random#' . arg 117 | let module = package#import(module_name) 118 | let s:loaded_generator_modules[arg] = module 119 | endif 120 | let gen = s:loaded_generator_modules[arg].new_generator() 121 | return gen 122 | endif 123 | if type(arg) == type({}) 124 | return arg 125 | endif 126 | throw printf('vital: Random: Invalid generator: %s', string(a:arg)) 127 | endfunction 128 | 129 | function! s:_common() abort 130 | if !exists('s:common_random') 131 | let s:common_random = s:new('', s:make_seed()) 132 | endif 133 | return s:common_random 134 | endfunction 135 | let s:func_type = type(function('type')) 136 | for s:func in keys(filter(copy(s:Random), 'type(v:val) == s:func_type')) 137 | execute join([ 138 | \ 'function! s:' . s:func . '(...) abort', 139 | \ ' let r = s:_common()', 140 | \ ' return call(r.' . s:func . ', a:000, r)', 141 | \ 'endfunction', 142 | \ ], "\n") 143 | endfor 144 | 145 | let &cpo = s:save_cpo 146 | unlet s:save_cpo 147 | -------------------------------------------------------------------------------- /autoload/jp/Random/Xor128.vim: -------------------------------------------------------------------------------- 1 | " random number generator using xorshift128 2 | " http://www.jstatsoft.org/v08/i14/paper 3 | 4 | let s:save_cpo = &cpo 5 | set cpo&vim 6 | 7 | 8 | let s:B = package#import('jp#Bitwise') 9 | 10 | 11 | let s:Generator = {} 12 | 13 | function! s:Generator.next() abort 14 | let t = s:B.xor(self._x, s:B.lshift(self._x, 11)) 15 | let w = self._w 16 | let self._x = self._y 17 | let self._y = self._z 18 | let self._z = self._w 19 | let self._w = s:B.xor(s:B.xor(w, s:B.rshift32(w, 19)), s:B.xor(t, s:B.rshift32(t, 8))) 20 | return s:B.sign_extension(self._w) 21 | endfunction 22 | 23 | " 0x80000000 in 32bit and 0xFFFFFFFF80000000 in 64bit 24 | function! s:Generator.min() abort 25 | return -2147483648 26 | endfunction 27 | 28 | " 0x7FFFFFFF in 32bit/64bit 29 | function! s:Generator.max() abort 30 | return 2147483647 31 | endfunction 32 | 33 | function! s:_fmix32(x) abort 34 | let x = s:B.and(0xFFFFFFFF, a:x) 35 | let x = s:B.and(0xFFFFFFFF, 0x85EBCA6B * s:B.xor(x, s:B.rshift(x, 16))) 36 | let x = s:B.and(0xFFFFFFFF, 0xC2B2AE35 * s:B.xor(x, s:B.rshift(x, 13))) 37 | return s:B.xor(x, s:B.rshift(x, 16)) 38 | endfunction 39 | 40 | function! s:Generator.seed(seeds) abort 41 | let x = 123456789 42 | for seed in a:seeds 43 | let x = s:_fmix32(x + seed) 44 | endfor 45 | 46 | let s = [0, 0, 0, 0] 47 | for i in range(4) 48 | let x += 0x9E3779B9 49 | let s[i] = s:_fmix32(x) 50 | endfor 51 | let [self._x, self._y, self._z, self._w] = s 52 | endfunction 53 | 54 | function! s:new_generator() abort 55 | let gen = deepcopy(s:Generator) 56 | call gen.seed([]) 57 | return gen 58 | endfunction 59 | 60 | 61 | function! s:_common_generator() abort 62 | if !exists('s:common_generator') 63 | let s:common_generator = s:new_generator() 64 | endif 65 | return s:common_generator 66 | endfunction 67 | 68 | function! s:srand(...) abort 69 | if a:0 == 0 70 | let x = has('reltime') ? reltime()[1] : localtime() 71 | elseif a:0 == 1 72 | let x = a:1 73 | else 74 | throw 'vital: Random.Xor128: srand(): too many arguments' 75 | endif 76 | call s:_common_generator().seed([x]) 77 | endfunction 78 | 79 | function! s:rand() abort 80 | return s:_common_generator().next() 81 | endfunction 82 | 83 | 84 | let &cpo = s:save_cpo 85 | unlet s:save_cpo 86 | 87 | " vim:set et ts=2 sts=2 sw=2 tw=0: 88 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:registry = {} 5 | let s:thisdir = expand(':p:h') 6 | 7 | " load: 8 | function! jp#System#Cache#load() abort "{{{ 9 | let s:P = package#import('jp#Prelude') 10 | call s:register('dummy', 'Cache.Dummy') 11 | call s:register('memory', 'Cache.Memory') 12 | call s:register('file', 'Cache.File') 13 | call s:register('singlefile', 'Cache.SingleFile') 14 | endfunction "}}} 15 | 16 | function! s:_vital_depends() abort 17 | return [ 18 | \ 'Prelude', 19 | \ 'System.Cache.Dummy', 20 | \ 'System.Cache.Memory', 21 | \ 'System.Cache.File', 22 | \ 'System.Cache.SingleFile', 23 | \] 24 | endfunction 25 | 26 | function! s:new(name, ...) abort 27 | if !has_key(s:registry, a:name) 28 | throw printf( 29 | \ 'vital: System.Cache: A cache system "%s" is not registered.', 30 | \ a:name, 31 | \) 32 | endif 33 | let class = s:registry[a:name] 34 | return call(class.new, a:000, class) 35 | endfunction 36 | 37 | function! s:register(name, class) abort 38 | let class = s:P.is_string(a:class) ? package#rimport(s:thisdir, a:class) : a:class 39 | let s:registry[a:name] = class 40 | endfunction 41 | function! s:unregister(name) abort 42 | unlet! s:registry[a:name] 43 | endfunction 44 | 45 | let &cpo = s:save_cpo 46 | unlet s:save_cpo 47 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 48 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache/Base.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Prelude = package#import('jp#Prelude') 5 | 6 | let s:cache = { 7 | \ '__name__': 'base', 8 | \} 9 | function! s:new(...) abort 10 | return deepcopy(s:cache) 11 | endfunction 12 | function! s:cache.cache_key(obj) abort 13 | let cache_key = s:Prelude.is_string(a:obj) ? a:obj : string(a:obj) 14 | return cache_key 15 | endfunction 16 | function! s:cache.has(name) abort 17 | throw 'vital: System.Cache.Base: has({name}) is not implemented' 18 | endfunction 19 | function! s:cache.get(name, ...) abort 20 | throw 'vital: System.Cache.Base: get({name}[, {default}]) is not implemented' 21 | endfunction 22 | function! s:cache.set(name, value) abort 23 | throw 'vital: System.Cache.Base: set({name}, {value}[, {default}]) is not implemented' 24 | endfunction 25 | function! s:cache.keys() abort 26 | throw 'vital: System.Cache.Base: keys() is not implemented' 27 | endfunction 28 | function! s:cache.remove(name) abort 29 | throw 'vital: System.Cache.Base: remove({name}) is not implemented' 30 | endfunction 31 | function! s:cache.clear() abort 32 | throw 'vital: System.Cache.Base: clear() is not implemented' 33 | endfunction 34 | function! s:cache.on_changed() abort 35 | " A user defined hook function 36 | endfunction 37 | 38 | let &cpo = s:save_cpo 39 | unlet s:save_cpo 40 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 41 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache/Deprecated.vim: -------------------------------------------------------------------------------- 1 | " Note: 2 | " This module is deprecated. Use a new `Syste.Cache` instead. 3 | 4 | let s:save_cpo = &cpo 5 | set cpo&vim 6 | 7 | let s:S = package#import('jp#Data#String', 'hash') 8 | 9 | function! s:getfilename(cache_dir, filename) abort 10 | return s:_encode_name(a:cache_dir, a:filename) 11 | endfunction 12 | 13 | function! s:filereadable(cache_dir, filename) abort 14 | let cache_name = s:_encode_name(a:cache_dir, a:filename) 15 | return filereadable(cache_name) 16 | endfunction 17 | 18 | function! s:readfile(cache_dir, filename) abort 19 | let cache_name = s:_encode_name(a:cache_dir, a:filename) 20 | return filereadable(cache_name) ? readfile(cache_name) : [] 21 | endfunction 22 | 23 | function! s:writefile(cache_dir, filename, list) abort 24 | let cache_name = s:_encode_name(a:cache_dir, a:filename) 25 | 26 | call writefile(a:list, cache_name) 27 | endfunction 28 | 29 | function! s:delete(cache_dir, filename) abort 30 | echoerr 'System.Cache.delete() is obsolete. Use its deletefile() instead.' 31 | return call('s:deletefile', a:cache_dir, a:filename) 32 | endfunction 33 | 34 | function! s:deletefile(cache_dir, filename) abort 35 | let cache_name = s:_encode_name(a:cache_dir, a:filename) 36 | return delete(cache_name) 37 | endfunction 38 | 39 | function! s:_encode_name(cache_dir, filename) abort 40 | " Check cache directory. 41 | if !isdirectory(a:cache_dir) 42 | call mkdir(a:cache_dir, 'p') 43 | endif 44 | let cache_dir = a:cache_dir 45 | if cache_dir !~# '/$' 46 | let cache_dir .= '/' 47 | endif 48 | 49 | return cache_dir . s:_create_hash(cache_dir, a:filename) 50 | endfunction 51 | 52 | function! s:check_old_cache(cache_dir, filename) abort 53 | " Check old cache file. 54 | let cache_name = s:_encode_name(a:cache_dir, a:filename) 55 | let ret = getftime(cache_name) == -1 56 | \ || getftime(cache_name) <= getftime(a:filename) 57 | if ret && filereadable(cache_name) 58 | " Delete old cache. 59 | call delete(cache_name) 60 | endif 61 | 62 | return ret 63 | endfunction 64 | 65 | function! s:_create_hash(dir, str) abort 66 | if len(a:dir) + len(a:str) < 150 67 | let hash = substitute(substitute( 68 | \ a:str, ':', '=-', 'g'), '[/\\]', '=+', 'g') 69 | else 70 | let hash = s:S.hash(a:str) 71 | endif 72 | 73 | return hash 74 | endfunction 75 | 76 | let &cpo = s:save_cpo 77 | unlet s:save_cpo 78 | 79 | " vim:set et ts=2 sts=2 sw=2 tw=0: 80 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache/Dummy.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Base = package#import('jp#System#Cache#Base') 5 | 6 | let s:cache = { 7 | \ '__name__': 'dummy', 8 | \} 9 | function! s:new(...) abort 10 | return extend( 11 | \ call(s:Base.new, a:000, s:Base), 12 | \ deepcopy(s:cache) 13 | \) 14 | endfunction 15 | 16 | function! s:cache.has(name) abort 17 | return 0 18 | endfunction 19 | function! s:cache.get(name, ...) abort 20 | return get(a:000, 0, '') 21 | endfunction 22 | function! s:cache.set(name, value) abort 23 | " do nothing 24 | endfunction 25 | function! s:cache.keys() abort 26 | return [] 27 | endfunction 28 | function! s:cache.remove(name) abort 29 | " do nothing 30 | endfunction 31 | function! s:cache.clear() abort 32 | " do nothing 33 | endfunction 34 | 35 | let &cpo = s:save_cpo 36 | unlet s:save_cpo 37 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 38 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache/File.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Prelude = package#import('jp#Prelude') 5 | let s:String = package#import('jp#Data#String') 6 | let s:File = package#import('jp#System#File') 7 | let s:Path = package#import('jp#System#Filepath') 8 | let s:Base = package#import('jp#System#Cache#Base') 9 | 10 | function! s:hash(cache_dir, str) abort 11 | " I'm not really sure if 150 is a best threshold for a path length. 12 | " But the value is for backward compatible behavior 13 | if len(a:cache_dir) + len(a:str) < 150 14 | let hash = substitute(substitute( 15 | \ a:str, ':', '=-', 'g'), '[/\\]', '=+', 'g') 16 | else 17 | let hash = s:String.hash(a:str) 18 | endif 19 | return hash 20 | endfunction 21 | 22 | function! s:load(filename, ...) abort 23 | let default = get(a:000, 0, {}) 24 | let raw = filereadable(a:filename) ? readfile(a:filename) : [] 25 | if empty(raw) 26 | return default 27 | endif 28 | sandbox let obj = eval(join(raw, "\n")) 29 | return obj 30 | endfunction 31 | 32 | function! s:dump(filename, obj) abort 33 | call writefile([string(a:obj)], a:filename) 34 | endfunction 35 | 36 | let s:cache = { 37 | \ '__name__': 'file', 38 | \} 39 | function! s:new(...) abort 40 | let options = get(a:000, 0, {}) 41 | if !has_key(options, 'cache_dir') 42 | throw 'vital: System.Cache.File: No "cache_dir" option is specified.' 43 | endif 44 | " create a cache directory if it does not exist 45 | if !isdirectory(options.cache_dir) 46 | call mkdir(options.cache_dir, 'p') 47 | endif 48 | return extend( 49 | \ call(s:Base.new, a:000, s:Base), 50 | \ extend(options, deepcopy(s:cache)) 51 | \) 52 | endfunction 53 | 54 | function! s:cache.cache_key(obj) abort 55 | let cache_key = s:Prelude.is_string(a:obj) ? a:obj : string(a:obj) 56 | let cache_key = s:hash(self.cache_dir, cache_key) 57 | return cache_key 58 | endfunction 59 | function! s:cache.get_cache_filename(name) abort 60 | let cache_key = self.cache_key(a:name) 61 | let filename = s:Path.join(self.cache_dir, cache_key) 62 | return filename 63 | endfunction 64 | function! s:cache.has(name) abort 65 | let filename = self.get_cache_filename(a:name) 66 | return filereadable(filename) 67 | endfunction 68 | function! s:cache.get(name, ...) abort 69 | let default = get(a:000, 0, '') 70 | let filename = self.get_cache_filename(a:name) 71 | return s:load(filename, default) 72 | endfunction 73 | function! s:cache.set(name, value) abort 74 | let filename = self.get_cache_filename(a:name) 75 | call s:dump(filename, a:value) 76 | call self.on_changed() 77 | endfunction 78 | function! s:cache.remove(name) abort 79 | let filename = self.get_cache_filename(a:name) 80 | if filereadable(filename) 81 | call delete(filename) 82 | call self.on_changed() 83 | endif 84 | endfunction 85 | function! s:cache.clear() abort 86 | call s:File.rmdir(self.cache_dir, 'r') 87 | call self.on_changed() 88 | endfunction 89 | function! s:cache.keys() abort 90 | let keys = split(glob(s:Path.join(self.cache_dir, '*'), 0), '\n') 91 | return map(keys, 'fnamemodify(v:val, ":t")') 92 | endfunction 93 | 94 | let &cpo = s:save_cpo 95 | unlet s:save_cpo 96 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 97 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache/Memory.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Base = package#import('jp#System#Cache#Base') 5 | 6 | let s:cache = { 7 | \ '_cached': {}, 8 | \ '__name__': 'memory', 9 | \} 10 | function! s:new(...) abort 11 | return extend( 12 | \ call(s:Base.new, a:000, s:Base), 13 | \ deepcopy(s:cache) 14 | \) 15 | endfunction 16 | 17 | function! s:cache.has(name) abort 18 | let cache_key = self.cache_key(a:name) 19 | return has_key(self._cached, cache_key) 20 | endfunction 21 | function! s:cache.get(name, ...) abort 22 | let default = get(a:000, 0, '') 23 | let cache_key = self.cache_key(a:name) 24 | if has_key(self._cached, cache_key) 25 | return self._cached[cache_key] 26 | else 27 | return default 28 | endif 29 | endfunction 30 | function! s:cache.set(name, value) abort 31 | let cache_key = self.cache_key(a:name) 32 | let self._cached[cache_key] = a:value 33 | call self.on_changed() 34 | endfunction 35 | function! s:cache.remove(name) abort 36 | let cache_key = self.cache_key(a:name) 37 | if has_key(self._cached, cache_key) 38 | unlet self._cached[cache_key] 39 | call self.on_changed() 40 | endif 41 | endfunction 42 | function! s:cache.keys() abort 43 | return keys(self._cached) 44 | endfunction 45 | function! s:cache.clear() abort 46 | let self._cached = {} 47 | call self.on_changed() 48 | endfunction 49 | 50 | let &cpo = s:save_cpo 51 | unlet s:save_cpo 52 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 53 | -------------------------------------------------------------------------------- /autoload/jp/System/Cache/SingleFile.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Base = package#import('jp#System#Cache#Base') 5 | let s:File = package#import('jp#System#Cache#File') 6 | let s:Memory = package#import('jp#System#Cache#Memory') 7 | 8 | let s:cache = { 9 | \ '__name__': 'singlefile', 10 | \} 11 | function! s:new(...) abort 12 | let options = extend({ 13 | \ 'cache_file': '', 14 | \ 'autodump': 1, 15 | \}, get(a:000, 0, {}) 16 | \) 17 | if empty(options.cache_file) 18 | throw 'vital: System.Cache.SingleFile: "cache_file" option is empty.' 19 | endif 20 | " create a cache directory if it does not exist 21 | let cache_dir = fnamemodify(options.cache_file, ':p:h') 22 | if !isdirectory(cache_dir) 23 | call mkdir(cache_dir, 'p') 24 | endif 25 | let cache = extend( 26 | \ call(s:Base.new, a:000, s:Base), 27 | \ extend(options, deepcopy(s:cache)) 28 | \) 29 | " Add internal cache system 30 | let cache._memory = s:Memory.new() 31 | let cache._memory.__parent__ = cache 32 | function! cache._memory.on_changed() abort 33 | if self.__parent__.autodump 34 | call self.__parent__.dump() 35 | endif 36 | endfunction 37 | " Load cache 38 | call cache.load() 39 | return cache 40 | endfunction 41 | 42 | function! s:cache.load() abort 43 | if filereadable(self.cache_file) 44 | let obj = s:File.load(self.cache_file, {}) 45 | if type(obj) == type({}) 46 | let self._memory._cached = obj 47 | call self.on_changed() 48 | endif 49 | endif 50 | endfunction 51 | function! s:cache.dump() abort 52 | call s:File.dump(self.cache_file, self._memory._cached) 53 | endfunction 54 | 55 | function! s:cache.has(name) abort 56 | return self._memory.has(a:name) 57 | endfunction 58 | function! s:cache.get(name, ...) abort 59 | let default = get(a:000, 0, '') 60 | return self._memory.get(a:name, default) 61 | endfunction 62 | function! s:cache.set(name, value) abort 63 | call self._memory.set(a:name, a:value) 64 | call self.on_changed() 65 | endfunction 66 | function! s:cache.remove(name) abort 67 | if self._memory.has(a:name) 68 | call self._memory.remove(a:name) 69 | call self.on_changed() 70 | endif 71 | endfunction 72 | function! s:cache.keys() abort 73 | return self._memory.keys() 74 | endfunction 75 | function! s:cache.clear() abort 76 | call self._memory.clear() 77 | call self.on_changed() 78 | endfunction 79 | 80 | let &cpo = s:save_cpo 81 | unlet! s:save_cpo 82 | " vim:set et ts=2 sts=2 sw=2 tw=0 fdm=marker: 83 | -------------------------------------------------------------------------------- /autoload/jp/System/Process.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpoptions = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:registry = {} 5 | let s:priority = [] 6 | 7 | " load: 8 | function! jp#System#Process#load() abort "{{{ 9 | let s:Prelude = package#import('jp#Prelude') 10 | let s:String = package#import('jp#Data#String') 11 | call s:register('jp#System#Process#Vimproc') 12 | call s:register('jp#System#Process#System') 13 | endfunction "}}} 14 | 15 | function! s:_throw(msg) abort 16 | throw printf('vital: System.Process: %s', a:msg) 17 | endfunction 18 | 19 | function! s:register(name) abort 20 | let client = package#import(a:name) 21 | if client.is_available() 22 | let s:registry[a:name] = client 23 | call add(s:priority, a:name) 24 | endif 25 | endfunction 26 | 27 | function! s:_execute(args, options) abort 28 | for name_or_client in a:options.clients 29 | let client = s:Prelude.is_string(name_or_client) 30 | \ ? s:registry[name_or_client] 31 | \ : name_or_client 32 | if !client.is_supported(a:options) 33 | continue 34 | endif 35 | return client.execute(a:args, a:options) 36 | endfor 37 | call s:_throw(printf( 38 | \ 'None of client support options : %s', 39 | \ string(a:options), 40 | \)) 41 | endfunction 42 | 43 | " execute({args}[, {options}]) 44 | function! s:execute(args, ...) abort 45 | let options = extend({ 46 | \ 'clients': s:priority, 47 | \ 'input': 0, 48 | \ 'timeout': 0, 49 | \ 'background': 0, 50 | \ 'encode_input': 1, 51 | \ 'encode_output': 1, 52 | \ 'split_output': 1, 53 | \ 'debug': &verbose, 54 | \}, get(a:000, 0, {})) 55 | if s:Prelude.is_string(options.input) && !empty(options.encode_input) 56 | let encoding = s:Prelude.is_string(options.encode_input) 57 | \ ? options.encode_input 58 | \ : &encoding 59 | let options.input = s:String.iconv(options.input, encoding, 'char') 60 | endif 61 | let result = s:_execute(a:args, options) 62 | if s:Prelude.is_string(result.output) && !empty(options.encode_output) 63 | let encoding = s:Prelude.is_string(options.encode_output) 64 | \ ? options.encode_output 65 | \ : &encoding 66 | let result.output = s:String.iconv(result.output, 'char', encoding) 67 | endif 68 | if options.split_output 69 | let result.content = s:String.split_posix_text(result.output) 70 | endif 71 | let result.success = result.status == 0 72 | let result.args = a:args 73 | let result.options = options 74 | return result 75 | endfunction 76 | 77 | let &cpoptions = s:save_cpoptions 78 | unlet s:save_cpoptions 79 | -------------------------------------------------------------------------------- /autoload/jp/System/Process/Mock.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpoptions = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! s:is_available() abort 5 | return 1 6 | endfunction 7 | 8 | function! s:is_supported(options) abort 9 | return 1 10 | endfunction 11 | 12 | function! s:execute(args, options) abort 13 | if a:options.debug > 0 14 | echomsg printf( 15 | \ 'vital: System.Process.Mock: %s', 16 | \ join(a:args) 17 | \) 18 | endif 19 | return { 20 | \ 'status': 0, 21 | \ 'output': 'Output of System.Process.Mock', 22 | \} 23 | endfunction 24 | 25 | let &cpoptions = s:save_cpoptions 26 | unlet s:save_cpoptions 27 | -------------------------------------------------------------------------------- /autoload/jp/System/Process/System.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpoptions = &cpoptions 2 | set cpoptions&vim 3 | 4 | " load: 5 | function! jp#System#Process#System#load() abort "{{{ 6 | let s:Prelude = package#import('jp#Prelude') 7 | let s:String = package#import('jp#Data#String') 8 | let s:Guard = package#import('jp#Vim#Guard') 9 | endfunction "}}} 10 | 11 | function! s:is_available() abort 12 | return 1 13 | endfunction 14 | 15 | function! s:is_supported(options) abort 16 | if get(a:options, 'timeout') 17 | return 0 18 | elseif get(a:options, 'background') && s:Prelude.is_windows() 19 | return 0 20 | endif 21 | return 1 22 | endfunction 23 | 24 | function! s:shellescape(string) abort 25 | if s:Prelude.is_windows() 26 | " NOTE: 27 | " In windows, a string which does not contain space SHOULD NOT be escaped 28 | return a:string =~# '\s' ? shellescape(a:string) : a:string 29 | else 30 | return shellescape(a:string) 31 | endif 32 | endfunction 33 | 34 | function! s:execute(args, options) abort 35 | " NOTE: 36 | " execute() is a command for executing program WITHOUT using shell. 37 | " so mimic that behaviour with shell 38 | let guard = s:Guard.store(filter([ 39 | \ '&shell', 40 | \ '&shellcmdflag', 41 | \ '&shellquote', 42 | \ '&shellredir', 43 | \ '&shelltemp', 44 | \ (exists('+shelltype') ? '&shelltype' : ''), 45 | \ (exists('+shellxescape') ? '&shellxescape' : ''), 46 | \ (exists('+shellxquote') ? '&shellxquote' : ''), 47 | \ (exists('+shellslash') ? '&shellslash' : ''), 48 | \], '!empty(v:val)') 49 | \) 50 | try 51 | " Reset shell related options 52 | if s:Prelude.is_windows() 53 | set shell& 54 | if exists('+shellslash') 55 | set shellslash& 56 | endif 57 | else 58 | set shell=sh 59 | endif 60 | set shellcmdflag& shellquote& shellredir& shelltemp& 61 | if exists('+shelltype') 62 | set shelltype& 63 | endif 64 | if exists('+shellxescape') 65 | set shellxescape& 66 | endif 67 | if exists('+shellxquote') 68 | set shellxquote& 69 | endif 70 | let cmdline = join(map( 71 | \ copy(a:args), 72 | \ 's:shellescape(v:val)', 73 | \)) 74 | if a:options.background && !s:Prelude.is_windows() 75 | let cmdline = cmdline . ' &' 76 | endif 77 | if a:options.debug > 0 78 | echomsg printf( 79 | \ 'vital: System.Process.System: %s', 80 | \ cmdline 81 | \) 82 | endif 83 | if v:version < 704 || (v:version == 704 && !has('patch122')) 84 | " {cmdline} of system() before Vim 7.4.122 is not converted so convert 85 | " it manually from &encoding to 'char' 86 | let cmdline = s:String.iconv(cmdline, &encoding, 'char') 87 | endif 88 | let args = [cmdline] + (s:Prelude.is_string(a:options.input) ? [a:options.input] : []) 89 | let output = call('system', args) 90 | if s:Prelude.is_windows() 91 | " A builtin system() add a trailing space in Windows. 92 | " It is probably an issue of pipe in Windows so remove it. 93 | let output = substitute(output, '\s\n$', '\n', '') 94 | endif 95 | " NOTE: 96 | " Vim 7.4 always return exit_status:0 for background process so mimic 97 | let status = a:options.background ? 0 : v:shell_error 98 | " NOTE: 99 | " status, output are COMMON information 100 | " cmdline is an EXTRA information 101 | return { 102 | \ 'status': status, 103 | \ 'output': output, 104 | \ 'cmdline': cmdline, 105 | \} 106 | finally 107 | call guard.restore() 108 | endtry 109 | endfunction 110 | 111 | let &cpoptions = s:save_cpoptions 112 | unlet s:save_cpoptions 113 | -------------------------------------------------------------------------------- /autoload/jp/System/Process/Vimproc.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpoptions = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:Prelude = package#import('jp#Prelude') 5 | 6 | function! s:is_available() abort 7 | if exists('s:vimproc_available') 8 | return s:vimproc_available 9 | endif 10 | try 11 | call vimproc#version() 12 | let s:vimproc_available = 1 13 | catch 14 | let s:vimproc_available = 0 15 | endtry 16 | return s:vimproc_available 17 | endfunction 18 | 19 | function! s:is_supported(options) abort 20 | if get(a:options, 'background') && ( 21 | \ s:Prelude.is_string(get(a:options, 'input')) || 22 | \ get(a:options, 'timeout') 23 | \) 24 | return 0 25 | endif 26 | return 1 27 | endfunction 28 | 29 | function! s:execute(args, options) abort 30 | let cmdline = join(map( 31 | \ copy(a:args), 32 | \ 'vimproc#shellescape(v:val)', 33 | \)) 34 | if a:options.debug > 0 35 | echomsg printf( 36 | \ 'vital: System.Process.Vimproc: %s', 37 | \ cmdline 38 | \) 39 | endif 40 | if a:options.background 41 | let output = vimproc#system_bg(cmdline) 42 | " NOTE: 43 | " background process via Builtin always return exit_code:0 so mimic 44 | let status = 0 45 | else 46 | let output = vimproc#system( 47 | \ cmdline, 48 | \ s:Prelude.is_string(a:options.input) ? a:options.input : '', 49 | \ a:options.timeout, 50 | \) 51 | let status = vimproc#get_last_status() 52 | endif 53 | " NOTE: 54 | " status, output are COMMON information 55 | " errormsg, cmdline are EXTRA information 56 | return { 57 | \ 'status': status, 58 | \ 'output': output, 59 | \ 'errormsg': vimproc#get_last_errmsg(), 60 | \ 'cmdline': cmdline, 61 | \} 62 | endfunction 63 | 64 | let &cpoptions = s:save_cpoptions 65 | unlet s:save_cpoptions 66 | -------------------------------------------------------------------------------- /autoload/jp/Text/CSV.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! s:parse(csvlines) abort 5 | return map(split(a:csvlines, '\r\?\n', 1), 's:parse_record(v:val)') 6 | endfunction 7 | 8 | function! s:parse_file(file) abort 9 | return s:parse(join(readfile(a:file), "\n")) 10 | endfunction 11 | 12 | function! s:parse_record(csvline) abort 13 | let csvline = a:csvline 14 | let record = [] 15 | let rx_rest = '\(,\|$\)\(.*\)' 16 | let rx_quotecol = '^"\(\|\%(.\{-}"\@ 0 19 | return {'type': 'parameter', 'key': m[1], 'value': m[2]} 20 | endif 21 | " is section line? 22 | let m = matchlist(line, s:section_pattern) 23 | if len(m) > 0 24 | return {'type': 'section', 'name': m[1]} 25 | endif 26 | " unknown format 27 | return {'type': 'unknown', 'value': line} 28 | endfunction 29 | 30 | function! s:parse(ini, ...) abort 31 | let fail_silently = get(a:000, 0, 1) 32 | let sections = {} 33 | let sections[s:default_section] = {} 34 | let current_section = s:default_section 35 | 36 | for line in split(a:ini, '\v%(\r?\n)+') 37 | let record = s:parse_record(line) 38 | if record.type ==# 'section' 39 | let current_section = record.name 40 | let sections[current_section] = get(sections, current_section, {}) 41 | elseif record.type ==# 'parameter' 42 | let sections[current_section][record.key] = record.value 43 | elseif record.type ==# 'unknown' && !fail_silently 44 | throw 'vital: Text.INI: Parsing a record failed: ' . record.value 45 | endif 46 | endfor 47 | return sections 48 | endfunction 49 | 50 | function! s:parse_file(file, ...) abort 51 | let fail_silently = get(a:000, 0, 1) 52 | return s:parse(join(readfile(a:file), "\n"), fail_silently) 53 | endfunction 54 | 55 | 56 | let &cpo = s:save_cpo 57 | unlet s:save_cpo 58 | "vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker 59 | -------------------------------------------------------------------------------- /autoload/jp/Text/LTSV.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! s:parse(ltsv) abort 5 | return map(split(a:ltsv, '\r\?\n'), 's:parse_record(v:val)') 6 | endfunction 7 | 8 | function! s:parse_file(file) abort 9 | return s:parse(join(readfile(a:file), "\n")) 10 | endfunction 11 | 12 | function! s:parse_record(line) abort 13 | let record = {} 14 | for field in split(a:line, "\t") 15 | let splitted = matchlist(field, '^\([0-9A-Za-z_.-]\+\):\(.*\)$') 16 | if empty(splitted) 17 | throw 'vital: Text.LTSV: Parsing a record failed: ' . field 18 | endif 19 | let record[splitted[1]] = splitted[2] 20 | endfor 21 | return record 22 | endfunction 23 | 24 | function! s:dump(data) abort 25 | if type(a:data) == type([]) 26 | return join(map(copy(a:data), 's:_dump_record(v:val)'), "\n") 27 | elseif type(a:data) == type({}) 28 | return s:_dump_record(a:data) 29 | endif 30 | return a:data 31 | endfunction 32 | 33 | function! s:dump_file(data, file, ...) abort 34 | let ltsv = split(s:dump(a:data), "\n") 35 | if a:0 && a:1 && filereadable(a:file) 36 | let ltsv = readfile(a:file) + ltsv 37 | endif 38 | call writefile(ltsv, a:file) 39 | endfunction 40 | 41 | function! s:_dump_record(obj) abort 42 | return join(values(map(copy(a:obj), 'v:key . ":" . s:_to_s(v:val)')), "\t") 43 | endfunction 44 | 45 | function! s:_to_s(data) abort 46 | let t = type(a:data) 47 | return t == type('') || t == type(0) ? a:data : string(a:data) 48 | endfunction 49 | 50 | let &cpo = s:save_cpo 51 | unlet s:save_cpo 52 | -------------------------------------------------------------------------------- /autoload/jp/Text/Lexer.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:Prelude = package#import('jp#Prelude') 5 | 6 | function! s:_list2dict(list) abort 7 | if s:Prelude.is_list(a:list) 8 | if len(a:list) < 2 | call s:_exception('too few arguments.') | endif 9 | if 2 < len(a:list) | call s:_exception('too many arguments.') | endif 10 | if ! s:Prelude.is_string(a:list[0]) | call s:_exception('element of list is not string.') | endif 11 | if ! s:Prelude.is_string(a:list[1]) | call s:_exception('element of list is not string.') | endif 12 | let tkn = { 'label' : a:list[0], 'regex' : a:list[1] } 13 | return tkn 14 | else 15 | call s:_exception('first argument is not list.') 16 | endif 17 | endfunction 18 | 19 | function! s:_exception(msg) abort 20 | throw printf('vital: Text.Lexer: %s', a:msg) 21 | endfunction 22 | 23 | let s:obj = { 'tokens' : [] } 24 | 25 | function! s:obj.exec(string) dict abort 26 | let match_tokens = [] 27 | let idx = 0 28 | while idx < len(a:string) 29 | let best_tkn = {} 30 | for tkn in self.tokens 31 | let matched_text = matchstr(a:string[(idx):],'^' . tkn.regex) 32 | if ! empty(matched_text) 33 | let best_tkn = s:_token(tkn.label,matched_text,idx) 34 | break 35 | endif 36 | endfor 37 | if best_tkn == {} 38 | call s:_exception(printf('cannot match. col:%d',idx)) 39 | else 40 | let idx += len(best_tkn.matched_text) 41 | let match_tokens += [best_tkn] 42 | endif 43 | endwhile 44 | return match_tokens 45 | endfunction 46 | 47 | function! s:lexer(patterns) abort 48 | let obj = deepcopy(s:obj) 49 | for e in a:patterns 50 | let obj.tokens += [(s:_list2dict(e))] 51 | endfor 52 | return obj 53 | endfunction 54 | 55 | function! s:_token(label,matched_text,col) abort 56 | let obj = {} 57 | let obj['label'] = a:label 58 | let obj['matched_text'] = a:matched_text 59 | let obj['col'] = a:col 60 | return obj 61 | endfunction 62 | 63 | " Deprecated 64 | function! s:simple_parser(expr) abort 65 | echoerr 'vital: Text.Lexer: simple_parser(expr) is obsolete. Use Text.Parser.parser() instead.' 66 | let obj = { 'expr' : a:expr, 'idx' : 0, 'tokens' : [] } 67 | function! obj.end() dict abort 68 | return len(self.expr) <= self.idx 69 | endfunction 70 | function! obj.next() dict abort 71 | if self.end() 72 | call s:_exception('Already end of tokens.') 73 | else 74 | return self.expr[self.idx] 75 | endif 76 | endfunction 77 | function! obj.next_is(label) dict abort 78 | return self.next().label ==# a:label 79 | endfunction 80 | " @vimlint(EVL104, 1, l:next) 81 | function! obj.consume() dict abort 82 | if ! self.end() 83 | let next = self.next() 84 | let self.idx += 1 85 | else 86 | call s:_exception('Already end of tokens.') 87 | endif 88 | return next 89 | endfunction 90 | " @vimlint(EVL104, 0, l:next) 91 | return deepcopy(obj) 92 | endfunction 93 | 94 | let &cpo = s:save_cpo 95 | unlet s:save_cpo 96 | 97 | " vim:set et ts=2 sts=2 sw=2 tw=0: 98 | -------------------------------------------------------------------------------- /autoload/jp/Text/Parser.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | 5 | function! s:_exception(msg) abort 6 | throw printf('vital: Text.Parser: %s', a:msg) 7 | endfunction 8 | 9 | 10 | let s:obj = { '_idx' : 0, '_tokens' : [], '_ignore_labels' : [] } 11 | 12 | function! s:obj.config(dict) dict abort 13 | if has_key(a:dict,'ignore_labels') 14 | let self._ignore_labels = a:dict.ignore_labels 15 | endif 16 | return self 17 | endfunction 18 | 19 | function! s:obj.end() dict abort 20 | return len(self._tokens) <= self._idx 21 | endfunction 22 | 23 | function! s:obj.next() dict abort 24 | if self.end() 25 | call s:_exception('Already end of tokens.') 26 | else 27 | return self._tokens[self._idx] 28 | endif 29 | endfunction 30 | 31 | function! s:obj.next_is(labels) dict abort 32 | let labels = type([]) == type(a:labels) ? a:labels : [ a:labels ] 33 | if ! self.end() 34 | for lbl in labels 35 | if self.next().label ==# lbl 36 | return 1 37 | endif 38 | endfor 39 | endif 40 | return 0 41 | endfunction 42 | 43 | function! s:obj.ignore() dict abort 44 | while self.next_is(self._ignore_labels) 45 | call self.consume() 46 | endwhile 47 | return self 48 | endfunction 49 | 50 | " @vimlint(EVL104, 1, l:next) 51 | function! s:obj.consume() dict abort 52 | if ! self.end() 53 | let next = self.next() 54 | let self._idx += 1 55 | else 56 | call s:_exception('Already end of tokens.') 57 | endif 58 | return next 59 | endfunction 60 | " @vimlint(EVL104, 0, l:next) 61 | 62 | function! s:obj.tostring() dict abort 63 | if ! self.end() 64 | return '' 65 | else 66 | return join( map(deepcopy(self._tokens[(self._idx):]),'v:val.matched_text'), '') 67 | endif 68 | endfunction 69 | 70 | function! s:parser() abort 71 | let o = {} 72 | function! o.exec(lexered_tokens) abort 73 | let obj = deepcopy(s:obj) 74 | let obj._tokens = deepcopy(a:lexered_tokens) 75 | return obj 76 | endfunction 77 | return o 78 | endfunction 79 | 80 | 81 | let &cpo = s:save_cpo 82 | unlet s:save_cpo 83 | 84 | " vim:set et ts=2 sts=2 sw=2 tw=0: 85 | -------------------------------------------------------------------------------- /autoload/jp/Vim/Compat.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | " Vim.Compat: Vim compatibility wrapper functions for different 5 | " versions/patchlevels of Vim. 6 | " 7 | " This module is not for multiple OS compatibilities but for versions of Vim 8 | " itself. 9 | 10 | " e.g.) 11 | " echo s:has_version('7.3.629') 12 | " echo s:has_version('7.3') 13 | if has('patch-7.4.237') 14 | function! s:has_version(version) abort 15 | let versions = split(a:version, '\.') 16 | if len(versions) == 2 17 | let vim_version = versions[0] * 100 + versions[1] 18 | return v:version >= vim_version 19 | endif 20 | return has('patch-' . a:version) 21 | endfunction 22 | else 23 | function! s:has_version(version) abort 24 | let versions = split(a:version, '\.') 25 | if len(versions) == 2 26 | let versions += [0] 27 | elseif len(versions) != 3 28 | return 0 29 | endif 30 | let vim_version = versions[0] * 100 + versions[1] 31 | let patch_level = versions[2] 32 | return v:version > vim_version || 33 | \ (v:version == vim_version && 34 | \ (patch_level == 0 || has('patch' . patch_level))) 35 | endfunction 36 | endif 37 | 38 | " Patch 7.3.694 39 | if exists('*shiftwidth') 40 | function! s:shiftwidth() abort 41 | return shiftwidth() 42 | endfunction 43 | elseif s:has_version('7.3.629') 44 | " 7.3.629: When 'shiftwidth' is zero use the value of 'tabstop'. 45 | function! s:shiftwidth() abort 46 | return &shiftwidth == 0 ? &tabstop : &shiftwidth 47 | endfunction 48 | else 49 | function! s:shiftwidth() abort 50 | return &shiftwidth 51 | endfunction 52 | endif 53 | 54 | " Patch 7.4.503 55 | if has('patch-7.4.503') 56 | function! s:writefile(...) abort 57 | return call('writefile', a:000) 58 | endfunction 59 | else 60 | function! s:writefile(list, fname, ...) abort 61 | let flags = get(a:000, 0, '') 62 | if flags !~# 'a' 63 | return writefile(a:list, a:fname, flags) 64 | endif 65 | let f = tempname() 66 | let r = writefile(a:list, f, substitute(flags, 'a', '', 'g')) 67 | if r 68 | return r 69 | endif 70 | if has('win32') " This means any versions of windows https://github.com/vim-jp/vital.vim/wiki/Coding-Rule#how-to-check-if-the-runtime-os-is-windows 71 | silent! execute '!type ' . shellescape(f) '>>' . shellescape(a:fname) 72 | else 73 | silent! execute '!cat ' . shellescape(f) '>>' . shellescape(a:fname) 74 | endif 75 | if v:shell_error 76 | throw printf( 77 | \ 'vital: Vim.Compat: writefile() failed to append to "%s".', 78 | \ a:fname, 79 | \) 80 | endif 81 | return delete(f) 82 | endfunction 83 | endif 84 | 85 | " doautocmd User with 86 | if s:has_version('7.3.438') 87 | function! s:doautocmd(expr, ...) abort 88 | if get(a:000, 0, 0) 89 | execute 'doautocmd ' . a:expr 90 | else 91 | execute 'doautocmd ' . a:expr 92 | endif 93 | endfunction 94 | else 95 | function! s:doautocmd(expr, ...) abort 96 | execute 'doautocmd ' . a:expr 97 | endfunction 98 | endif 99 | 100 | if s:has_version('7.3.831') 101 | function! s:getbufvar(...) abort 102 | return call('getbufvar', a:000) 103 | endfunction 104 | else 105 | function! s:getbufvar(expr, varname, ...) abort 106 | let v = getbufvar(a:expr, a:varname) 107 | return empty(v) ? get(a:000, 0, '') : v 108 | endfunction 109 | endif 110 | 111 | if s:has_version('7.3.831') 112 | function! s:getwinvar(...) abort 113 | return call('getwinvar', a:000) 114 | endfunction 115 | else 116 | function! s:getwinvar(expr, varname, ...) abort 117 | let v = getwinvar(a:expr, a:varname) 118 | return empty(v) ? get(a:000, 0, '') : v 119 | endfunction 120 | endif 121 | 122 | let &cpo = s:save_cpo 123 | unlet s:save_cpo 124 | 125 | " vim:set et ts=2 sts=2 sw=2 tw=0: 126 | -------------------------------------------------------------------------------- /autoload/jp/Vim/Message.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | 5 | 6 | function! s:echo(hl, msg) abort 7 | execute 'echohl' a:hl 8 | try 9 | echo a:msg 10 | finally 11 | echohl None 12 | endtry 13 | endfunction 14 | 15 | function! s:echomsg(hl, msg) abort 16 | execute 'echohl' a:hl 17 | try 18 | for m in split(a:msg, "\n") 19 | echomsg m 20 | endfor 21 | finally 22 | echohl None 23 | endtry 24 | endfunction 25 | 26 | function! s:error(msg) abort 27 | call s:echomsg('ErrorMsg', a:msg) 28 | endfunction 29 | 30 | function! s:warn(msg) abort 31 | call s:echomsg('WarningMsg', a:msg) 32 | endfunction 33 | 34 | function! s:capture(command) abort 35 | try 36 | redir => out 37 | silent execute a:command 38 | finally 39 | redir END 40 | endtry 41 | return out 42 | endfunction 43 | 44 | " * Get max length of |hit-enter|. 45 | " If a string length of a message is greater than the max length, 46 | " Vim waits for user input according to |hit-enter|. 47 | " XXX: Those fixed values may be different between different OSes? 48 | " Currently tested on only Windows. 49 | function! s:get_hit_enter_max_length() abort 50 | let maxlen = &columns * &cmdheight - 1 51 | if &ruler 52 | " TODO 53 | endif 54 | if &showcmd 55 | let maxlen -= 11 56 | endif 57 | return maxlen 58 | endfunction 59 | 60 | 61 | 62 | let &cpo = s:save_cpo 63 | unlet s:save_cpo 64 | 65 | " vim:set et ts=2 sts=2 sw=2 tw=0: 66 | -------------------------------------------------------------------------------- /autoload/jp/Vim/Python.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:current_major_version = 0 5 | 6 | function! s:_throw(msg) abort 7 | throw printf('vital: Vim.Python: %s', a:msg) 8 | endfunction 9 | 10 | function! s:_get_valid_major_version(version) abort 11 | if index([0, 2, 3], a:version) == -1 12 | call s:_throw('"version" requires to be 0, 2, or 3') 13 | elseif a:version == 2 && !s:is_python2_enabled() 14 | call s:_throw('+python is required') 15 | elseif a:version == 3 && !s:is_python3_enabled() 16 | call s:_throw('+python3 is required') 17 | elseif !s:is_enabled() 18 | call s:_throw('+python and/or +python3 is required') 19 | endif 20 | return a:version == 0 21 | \ ? s:current_major_version == 0 22 | \ ? s:is_python2_enabled() 23 | \ ? 2 24 | \ : 3 25 | \ : s:current_major_version 26 | \ : a:version 27 | endfunction 28 | 29 | 30 | function! s:is_enabled() abort 31 | return s:is_python2_enabled() || s:is_python3_enabled() 32 | endfunction 33 | function! s:is_python2_enabled() abort 34 | if exists('s:is_python2_enabled') 35 | return s:is_python2_enabled 36 | endif 37 | try 38 | if !has('python') 39 | let s:is_python2_enabled = 0 40 | else 41 | python 0 42 | let s:is_python2_enabled = 1 43 | endif 44 | catch /^Vim(python)/ 45 | let s:is_python2_enabled = 0 46 | catch /^Vim\%((\a\+)\)\=:\%(E263\|E264\|E887\)/ 47 | let s:is_python2_enabled = 0 48 | endtry 49 | return s:is_python2_enabled 50 | endfunction 51 | function! s:is_python3_enabled() abort 52 | if exists('s:is_python3_enabled') 53 | return s:is_python3_enabled 54 | endif 55 | try 56 | if !has('python3') 57 | let s:is_python3_enabled = 0 58 | else 59 | python3 0 60 | let s:is_python3_enabled = 1 61 | endif 62 | catch /^Vim(python3)/ 63 | let s:is_python3_enabled = 0 64 | catch /^Vim\%((\a\+)\)\=:\%(E263\|E264\|E887\)/ 65 | let s:is_python3_enabled = 0 66 | endtry 67 | return s:is_python3_enabled 68 | endfunction 69 | 70 | function! s:get_major_version() abort 71 | if s:is_python2_enabled() && s:is_python3_enabled() 72 | return s:_get_valid_major_version(s:current_major_version) 73 | elseif s:is_enabled() 74 | return s:is_python2_enabled() ? 2 : 3 75 | endif 76 | return 0 77 | endfunction 78 | 79 | function! s:set_major_version(version) abort 80 | let s:current_major_version = s:_get_valid_major_version(a:version) 81 | endfunction 82 | 83 | function! s:exec_file(path, ...) abort 84 | let major_version = s:_get_valid_major_version(get(a:000, 0, 0)) 85 | if s:is_python2_enabled() && s:is_python3_enabled() 86 | let exec = major_version == 2 ? 'pyfile' : 'py3file' 87 | else 88 | let exec = s:is_python2_enabled() ? 'pyfile' : 'py3file' 89 | endif 90 | return printf('%s %s', exec, a:path) 91 | endfunction 92 | 93 | function! s:exec_code(code, ...) abort 94 | let major_version = s:_get_valid_major_version(get(a:000, 0, 0)) 95 | let code = type(a:code) == type('') ? a:code : join(a:code, "\n") 96 | if s:is_python2_enabled() && s:is_python3_enabled() 97 | let exec = major_version == 2 ? 'python' : 'python3' 98 | else 99 | let exec = s:is_python2_enabled() ? 'python' : 'python3' 100 | endif 101 | return printf('%s %s', exec, code) 102 | endfunction 103 | 104 | if v:version >= 704 || (v:version == 703 && has('patch601')) 105 | function! s:eval_expr(expr, ...) abort 106 | let major_version = s:_get_valid_major_version(get(a:000, 0, 0)) 107 | let expr = type(a:expr) == type('') ? a:expr : join(a:expr, "\n") 108 | if s:is_python2_enabled() && s:is_python3_enabled() 109 | return major_version == 2 ? pyeval(expr) : py3eval(expr) 110 | else 111 | return s:is_python2_enabled() ? pyeval(expr) : py3eval(expr) 112 | endif 113 | endfunction 114 | else 115 | function! s:eval_expr(expr, ...) abort 116 | call s:_throw('eval_expr() requires Vim 7.3.601 or later') 117 | endfunction 118 | endif 119 | 120 | 121 | let &cpo = s:save_cpo 122 | unlet! s:save_cpo 123 | " vim:set et ts=2 sts=2 sw=2 tw=0 fdm=marker: 124 | -------------------------------------------------------------------------------- /autoload/jp/Vim/Search.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:S = package#import('jp#Data#String') 5 | 6 | " [I wrapper 7 | " known issue: it messes undo tree slightly 8 | function! s:finddef(str) abort 9 | let before = getpos('.') 10 | call append(0, a:str) " ugh 11 | try 12 | " call setpos('.', getpos('1')) 13 | 1 14 | redir => result 15 | silent! normal! [I 16 | redir END 17 | 18 | " tokenizing phase 19 | let lines = s:S.lines(result) 20 | let tokens = [] 21 | for line in lines 22 | if line =~# '^\s*\d' 23 | let matches = matchlist(line, '\s*\d\+:\s\+\(\d\+\)\(.*\)') 24 | let lnum = matches[1] 25 | let body = matches[2] 26 | let tokens += [['item', lnum, body]] 27 | else 28 | let tokens += [['file', line]] 29 | endif 30 | endfor 31 | 32 | " parsing phase 33 | let parsed = {} 34 | let current_file = '*undefined*' 35 | for [label ; xs] in tokens 36 | if label ==# 'file' || current_file ==# '*undefined*' 37 | let current_file = xs[0] 38 | let parsed[current_file] = {} 39 | else 40 | let parsed[current_file][xs[0]] = xs[1] 41 | endif 42 | endfor 43 | return parsed 44 | finally 45 | silent! undo 46 | call setpos('.', before) 47 | endtry 48 | endfunction 49 | 50 | let &cpo = s:save_cpo 51 | unlet s:save_cpo 52 | -------------------------------------------------------------------------------- /autoload/jp/Vim/Type.vim: -------------------------------------------------------------------------------- 1 | let s:types = { 2 | \ 'number': 0, 3 | \ 'string': 1, 4 | \ 'func': 2, 5 | \ 'list': 3, 6 | \ 'dict': 4, 7 | \ 'float': 5, 8 | \ 'bool': 6, 9 | \ 'none': 7, 10 | \ 'job': 8, 11 | \ 'channel': 9, 12 | \ } 13 | lockvar 1 s:types 14 | 15 | let s:type_names = { 16 | \ '0': 'number', 17 | \ '1': 'string', 18 | \ '2': 'func', 19 | \ '3': 'list', 20 | \ '4': 'dict', 21 | \ '5': 'float', 22 | \ '6': 'bool', 23 | \ '7': 'none', 24 | \ '8': 'job', 25 | \ '9': 'channel', 26 | \ } 27 | lockvar 1 s:type_names 28 | 29 | " package: 30 | function! jp#Vim#Type#package() abort "{{{ 31 | return s: 32 | endfunction "}}} 33 | let s:EXPORT = {} 34 | let s:EXPORT[''] = '' 35 | let s:EXPORT.types = s:types 36 | let s:EXPORT.type_names = s:type_names 37 | 38 | 39 | function! s:is_numeric(value) abort 40 | let t = type(a:value) 41 | return t == s:types.number || t == s:types.float 42 | endfunction 43 | 44 | function! s:is_special(value) abort 45 | let t = type(a:value) 46 | return t == s:types.bool || t == s:types.none 47 | endfunction 48 | 49 | function! s:is_predicate(value) abort 50 | let t = type(a:value) 51 | return t == s:types.number || t == s:types.string || 52 | \ t == s:types.bool || t == s:types.none 53 | endfunction 54 | 55 | function! s:is_comparable(value1, value2) abort 56 | if !exists('s:is_comparable_cache') 57 | let s:is_comparable_cache = s:_make_is_comparable_cache() 58 | endif 59 | return s:is_comparable_cache[type(a:value1)][type(a:value2)] 60 | endfunction 61 | 62 | function! s:_make_is_comparable_cache() abort 63 | let vals = [ 64 | \ 0, '', function('type'), [], {}, 0.0, 65 | \ get(v:, 'false'), 66 | \ get(v:, 'null'), 67 | \ exists('*test_null_job') ? test_null_job() : 0, 68 | \ exists('*test_null_channel') ? test_null_channel() : 0, 69 | \ ] 70 | 71 | let result = [] 72 | for l:V1 in vals 73 | let result_V1 = [] 74 | let result += [result_V1] 75 | for l:V2 in vals 76 | try 77 | let _ = V1 == V2 78 | let result_V1 += [1] 79 | catch 80 | let result_V1 += [0] 81 | endtry 82 | unlet V2 83 | endfor 84 | unlet V1 85 | endfor 86 | return result 87 | endfunction 88 | -------------------------------------------------------------------------------- /autoload/jp/Vim/ViewTracer.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! s:trace_window(...) abort 5 | let tabnr = get(a:000, 0, tabpagenr()) 6 | let winnr = get(a:000, 1, winnr()) 7 | return {'window': gettabwinvar(tabnr, winnr, '')} 8 | endfunction 9 | 10 | function! s:trace_tabpage(...) abort 11 | let tabnr = get(a:000, 0, tabpagenr()) 12 | return {'tabpage': s:_gettabdict(tabnr)} 13 | endfunction 14 | 15 | function! s:find(handle) abort 16 | if has_key(a:handle, 'window') 17 | return s:_find_window(a:handle.window) 18 | elseif has_key(a:handle, 'tabpage') 19 | return s:_find_tabpage(a:handle.tabpage) 20 | endif 21 | return [0, 0] 22 | endfunction 23 | 24 | function! s:_find_window(scope_var) abort 25 | for tabnr in range(1, tabpagenr('$')) 26 | for winnr in range(1, tabpagewinnr(tabnr, '$')) 27 | if gettabwinvar(tabnr, winnr, '') is a:scope_var 28 | return [tabnr, winnr] 29 | endif 30 | endfor 31 | endfor 32 | return [0, 0] 33 | endfunction 34 | 35 | function! s:_find_tabpage(scope_var) abort 36 | for tabnr in range(1, tabpagenr('$')) 37 | if s:_gettabdict(tabnr) is a:scope_var 38 | return [tabnr, 0] 39 | endif 40 | endfor 41 | return [0, 0] 42 | endfunction 43 | 44 | function! s:exists(handle) abort 45 | return s:find(a:handle) != [0, 0] 46 | endfunction 47 | 48 | function! s:tabnr(handle) abort 49 | return s:find(a:handle)[0] 50 | endfunction 51 | 52 | function! s:winnr(handle) abort 53 | return s:find(a:handle)[1] 54 | endfunction 55 | 56 | function! s:jump(handle) abort 57 | let [tabnr, winnr] = s:find(a:handle) 58 | if tabnr == 0 59 | return 60 | endif 61 | call s:_move(tabnr, winnr) 62 | endfunction 63 | 64 | function! s:_move(tabnr, winnr) abort 65 | if a:tabnr != 0 && a:tabnr != tabpagenr() 66 | execute a:tabnr 'tabnext' 67 | endif 68 | if a:winnr != 0 && a:winnr != winnr() 69 | execute a:winnr 'wincmd w' 70 | endif 71 | endfunction 72 | 73 | if has('patch-7.4.834') 74 | function! s:_gettabdict(tabnr) abort 75 | return gettabvar(a:tabnr, '') 76 | endfunction 77 | elseif has('patch-7.4.434') 78 | " After Vim 7.4.434, gettabvar() can return the scope variable. 79 | " But, gettabvar() sometimes returns '' with new tabpage. 80 | " This can avoid by calling gettabvar() twice. 81 | " This Bug is fixed in 7.4.834. 82 | function! s:_gettabdict(tabnr) abort 83 | let dict = gettabvar(a:tabnr, '') 84 | return dict is# '' ? gettabvar(a:tabnr, '') : dict 85 | endfunction 86 | else 87 | " Before Vim 7.4.434, gettabvar() doesn't return 88 | " the scope variable. 89 | function! s:_gettabdict(tabnr) abort 90 | let cur_tabnr = tabpagenr() 91 | if a:tabnr != cur_tabnr 92 | let save_lazyredraw = &lazyredraw 93 | try 94 | set lazyredraw 95 | noautocmd execute 'tabnext' a:tabnr 96 | let scope_var = t: 97 | noautocmd execute 'tabnext' cur_tabnr 98 | finally 99 | let &lazyredraw = save_lazyredraw 100 | endtry 101 | else 102 | let scope_var = t: 103 | endif 104 | return scope_var 105 | endfunction 106 | endif 107 | 108 | let &cpo = s:save_cpo 109 | unlet s:save_cpo 110 | -------------------------------------------------------------------------------- /autoload/jp/Vim/WindowLayout/FlowLayout.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | " 5 | " Flow Layout 6 | " 7 | let s:flow_layout = {} 8 | 9 | function! s:new() abort 10 | return deepcopy(s:flow_layout) 11 | endfunction 12 | 13 | function! s:_flow_layout_apply(wl, data) dict abort 14 | " already exists a window 15 | let items = copy(a:data.items) 16 | let skip = 1 17 | 18 | for item in items 19 | if !skip 20 | botright vsplit 21 | endif 22 | 23 | if has_key(item, 'bufref') 24 | call a:wl.bufopen(item.bufref) 25 | endif 26 | if has_key(item, 'walias') 27 | call a:wl.walias('.', item.walias) 28 | endif 29 | 30 | let skip = 0 31 | endfor 32 | endfunction 33 | let s:flow_layout.apply = function('s:_flow_layout_apply') 34 | 35 | " @vimlint(EVL103, 1, a:wl) 36 | " @vimlint(EVL103, 1, a:data) 37 | function! s:_flow_layout_adjust_size(wl, data) dict abort 38 | " do nothing 39 | endfunction 40 | " @vimlint(EVL103, 0, a:wl) 41 | " @vimlint(EVL103, 0, a:data) 42 | let s:flow_layout.adjust_size = function('s:_flow_layout_adjust_size') 43 | 44 | let &cpo = s:save_cpo 45 | unlet s:save_cpo 46 | " vim: tabstop=2 shiftwidth=2 expandtab 47 | -------------------------------------------------------------------------------- /autoload/jp/Vim/WindowLayout/GridLayout.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | " 5 | " Grid Layout 6 | " 7 | let s:grid_layout = {} 8 | 9 | function! s:new() abort 10 | return deepcopy(s:grid_layout) 11 | endfunction 12 | 13 | function! s:_grid_layout_apply(wl, data) dict abort 14 | let nrows = float2nr(ceil(len(a:data.cells) / (1.0 * a:data.column))) 15 | " already exists a row window 16 | for _ in range(2, nrows) 17 | aboveleft split 18 | endfor 19 | 20 | " col starts with 1, since already exists a column window 21 | let [col, row] = [1, 0] 22 | while row <= nrows && (col + a:data.column * row) < len(a:data.cells) 23 | call s:_apply_common_options(a:wl, get(a:data.cells, col + a:data.column * row - 1, {})) 24 | 25 | belowright vsplit 26 | let col += 1 27 | 28 | if col >= a:data.column 29 | call s:_apply_common_options(a:wl, get(a:data.cells, col + a:data.column * row - 1, {})) 30 | 31 | execute 'wincmd j' 32 | let col = 1 33 | let row += 1 34 | endif 35 | endwhile 36 | endfunction 37 | let s:grid_layout.apply = function('s:_grid_layout_apply') 38 | 39 | function! s:_apply_common_options(wl, layoutdata) abort 40 | " open buffer 41 | if has_key(a:layoutdata, 'bufref') 42 | call a:wl.bufopen(a:layoutdata.bufref) 43 | endif 44 | " make walias 45 | if has_key(a:layoutdata, 'walias') 46 | call a:wl.walias('.', a:layoutdata.walias) 47 | endif 48 | endfunction 49 | 50 | " @vimlint(EVL103, 1, a:wl) 51 | " @vimlint(EVL103, 1, a:data) 52 | function! s:_grid_layout_adjust_size(wl, data) dict abort 53 | " do nothing 54 | endfunction 55 | " @vimlint(EVL103, 0, a:wl) 56 | " @vimlint(EVL103, 0, a:data) 57 | let s:grid_layout.adjust_size = function('s:_grid_layout_adjust_size') 58 | 59 | let &cpo = s:save_cpo 60 | unlet s:save_cpo 61 | " vim: tabstop=2 shiftwidth=2 expandtab 62 | -------------------------------------------------------------------------------- /autoload/jp/Web/HTML.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:string = package#import('jp#Data#String') 5 | let s:xml = package#import('jp#Web#XML') 6 | let s:http = package#import('jp#Web#HTTP') 7 | 8 | function! s:decodeEntityReference(str) abort 9 | let str = a:str 10 | let str = substitute(str, '>', '>', 'g') 11 | let str = substitute(str, '<', '<', 'g') 12 | let str = substitute(str, '"', '"', 'g') 13 | let str = substitute(str, ''', "'", 'g') 14 | let str = substitute(str, ' ', ' ', 'g') 15 | let str = substitute(str, '¥', '\¥', 'g') 16 | let str = substitute(str, '&#\(\d\+\);', '\=s:string.nr2enc_char(submatch(1))', 'g') 17 | let str = substitute(str, '&', '\&', 'g') 18 | let str = substitute(str, '»', '>', 'g') 19 | let str = substitute(str, '«', '<', 'g') 20 | return str 21 | endfunction 22 | 23 | function! s:encodeEntityReference(str) abort 24 | let str = a:str 25 | let str = substitute(str, '&', '\&', 'g') 26 | let str = substitute(str, '>', '\>', 'g') 27 | let str = substitute(str, '<', '\<', 'g') 28 | let str = substitute(str, "\n", '\ ', 'g') 29 | let str = substitute(str, '"', '\"', 'g') 30 | let str = substitute(str, "'", '\'', 'g') 31 | let str = substitute(str, ' ', '\ ', 'g') 32 | return str 33 | endfunction 34 | 35 | function! s:parse(content) abort 36 | let content = substitute(a:content, '<\(area\|base\|basefont\|br\|nobr\|col\|frame\|hr\|img\|input\|isindex\|link\|meta\|param\|embed\|keygen\|command\)\([^>]*[^/]\|\)>', '<\1\2/>', 'g') 37 | return s:xml.parse(content) 38 | endfunction 39 | 40 | function! s:parseFile(fname) abort 41 | return s:parse(join(readfile(a:fname), "\n")) 42 | endfunction 43 | 44 | function! s:parseURL(url) abort 45 | return s:parse(s:http.get(a:url).content) 46 | endfunction 47 | 48 | let &cpo = s:save_cpo 49 | unlet s:save_cpo 50 | 51 | " vim:set et ts=2 sts=2 sw=2 tw=0: 52 | -------------------------------------------------------------------------------- /autoload/jp/Web/HTTP/CookieJar.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " RFC: http://tools.ietf.org/html/rfc6265 5 | " Japanese Translation: http://www.hcn.zaq.ne.jp/___/WEB/RFC6265-ja.html 6 | 7 | 8 | let s:URI = package#import('jp#Web#URI') 9 | let s:DateTime = package#import('jp#DateTime') 10 | let s:Cookie = package#import('jp#Web#HTTP#Cookie') 11 | 12 | function! s:new(...) abort 13 | let jar = deepcopy(s:Jar) 14 | if a:0 15 | call jar.import(a:1) 16 | endif 17 | return jar 18 | endfunction 19 | 20 | function! s:build_http_header(cookies) abort 21 | return join(map(copy(a:cookies), 's:_make_cookie_header_entry(v:val)'), '; ') 22 | endfunction 23 | 24 | 25 | let s:Jar = { 26 | \ '_cookies': {}, 27 | \ } 28 | 29 | function! s:Jar.add(cookie) abort 30 | let id = s:_cookie_id(a:cookie) 31 | let self._cookies[id] = a:cookie 32 | endfunction 33 | 34 | function! s:Jar.add_all(cookies) abort 35 | for cookie in a:cookies 36 | call self.add(cookie) 37 | endfor 38 | endfunction 39 | 40 | function! s:Jar.add_from_headers(headers, request_uri) abort 41 | let headers = filter(copy(a:headers), 's:_is_set_cookie_header(v:val)') 42 | let strings = map(headers, 'matchstr(v:val, "\\c^set-cookie:\\s*\\zs.*")') 43 | let cookies = map(strings, 's:Cookie.new(v:val, a:request_uri)') 44 | call self.add_all(cookies) 45 | endfunction 46 | 47 | function! s:Jar.get(...) abort 48 | return get(call(self.get_all, a:000, self), 0, {}) 49 | endfunction 50 | 51 | function! s:Jar.get_all(...) abort 52 | let condition = a:0 ? a:1 : {} 53 | let cookies = values(self._cookies) 54 | 55 | if has_key(condition, 'url') 56 | let uri = s:URI.new(condition.url) 57 | if uri is 0 58 | return [] 59 | endif 60 | call filter(cookies, 'v:val.is_match(uri)') 61 | endif 62 | 63 | if has_key(condition, 'name') 64 | let name = condition.name 65 | call filter(cookies, 'v:val.name() ==# name') 66 | endif 67 | 68 | if has_key(condition, 'name_pattern') 69 | let pattern = condition.name_pattern 70 | call filter(cookies, 'v:val.name() =~# pattern') 71 | endif 72 | 73 | if has_key(condition, 'expired') 74 | let expired = !!condition.expired 75 | call filter(cookies, 'v:val.is_expired() == expired') 76 | endif 77 | 78 | if has_key(condition, 'valid') 79 | let valid = !!condition.valid 80 | call filter(cookies, 'v:val.is_valid() == valid') 81 | endif 82 | 83 | return cookies 84 | endfunction 85 | 86 | function! s:Jar.build_http_header(url, ...) abort 87 | let condition = { 88 | \ 'url': a:url, 89 | \ 'expired': 0, 90 | \ 'valid': 1, 91 | \ } 92 | let cookies = self.get_all(condition) 93 | let dry_run = a:0 && a:1 94 | if !dry_run 95 | let now = s:DateTime.now() 96 | for cookie in cookies 97 | call cookie.touch(now) 98 | endfor 99 | endif 100 | return s:build_http_header(cookies) 101 | endfunction 102 | 103 | function! s:Jar.sweep_expired(...) abort 104 | let now = a:0 ? a:1 : s:DateTime.now() 105 | call filter(self._cookies, '!v:val.is_expired(now)') 106 | endfunction 107 | 108 | function! s:Jar.clear() abort 109 | let self._cookies = {} 110 | endfunction 111 | 112 | function! s:Jar.export(...) abort 113 | let all = a:0 && a:1 114 | let cookies = self.get_all() 115 | if !all 116 | call filter(cookies, 'v:val.is_persistent()') 117 | endif 118 | return { 119 | \ 'cookies': map(cookies, 's:Cookie.export(v:val)'), 120 | \ } 121 | endfunction 122 | 123 | function! s:Jar.import(data) abort 124 | let cookies = map(copy(a:data.cookies), 's:Cookie.import(v:val)') 125 | call self.add_all(cookies) 126 | endfunction 127 | 128 | 129 | function! s:_make_cookie_header_entry(cookie) abort 130 | let name = s:URI.encode(a:cookie.name()) 131 | let value = s:URI.encode(a:cookie.value()) 132 | return printf('%s=%s', name, value) 133 | endfunction 134 | 135 | function! s:_is_set_cookie_header(header) abort 136 | return a:header =~? '^set-cookie: ' 137 | endfunction 138 | 139 | function! s:_cookie_id(cookie) abort 140 | return join([a:cookie.domain(), a:cookie.path(), a:cookie.name()], "\n") 141 | endfunction 142 | 143 | 144 | let &cpoptions = s:save_cpo 145 | unlet s:save_cpo 146 | -------------------------------------------------------------------------------- /autoload/jp/Web/URI/HTTP.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | " The following four URIs are equivalent: 5 | " * http://example.com 6 | " * http://example.com/ 7 | " * http://example.com:/ 8 | " * http://example.com:80/ 9 | " 10 | " https://tools.ietf.org/html/rfc3986#section-6.2.3 11 | function! s:canonicalize(uriobj) abort 12 | if a:uriobj.path() ==# '' 13 | call a:uriobj.path('/') 14 | endif 15 | if a:uriobj.port() ==# a:uriobj.default_port() 16 | call a:uriobj.port('') 17 | endif 18 | endfunction 19 | 20 | function! s:default_port(uriobj) abort 21 | return '80' 22 | endfunction 23 | 24 | " vim:set et ts=2 sts=2 sw=2 tw=0:fen: 25 | -------------------------------------------------------------------------------- /autoload/jp/Web/URI/HTTPS.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:HTTP = package#import('jp#Web#URI#HTTP') 5 | 6 | function! s:canonicalize(uriobj) abort 7 | return s:HTTP.canonicalize(a:uriobj) 8 | endfunction 9 | 10 | function! s:default_port(uriobj) abort 11 | return '443' 12 | endfunction 13 | 14 | " vim:set et ts=2 sts=2 sw=2 tw=0:fen: 15 | -------------------------------------------------------------------------------- /autoload/sample/base.vim: -------------------------------------------------------------------------------- 1 | " Class: sample#base 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-20 5 | " Modify: 2017-02-20 6 | 7 | " CLASS: 8 | let s:class = class#old() 9 | let s:class._name_ = 'sample#base' 10 | let s:class._version_ = 1 11 | 12 | let s:class.baseProperty = 'baseProperty' 13 | 14 | function! sample#base#class() abort "{{{ 15 | return s:class 16 | endfunction "}}} 17 | 18 | " NEW: 19 | function! sample#base#new(...) abort "{{{ 20 | let l:obj = copy(s:class) 21 | call l:obj._new_(a:000) 22 | return l:obj 23 | endfunction "}}} 24 | 25 | " CTOR: 26 | function! sample#base#ctor(this, argv) abort "{{{ 27 | if len(a:argv) > 0 28 | let a:this.baseProperty = a:argv[0] 29 | endif 30 | endfunction "}}} 31 | 32 | " BaseMethod: 33 | function! s:class.BaseMethod() dict abort "{{{ 34 | echo 'calling BaseMethod()' 35 | return self.baseProperty 36 | endfunction "}}} 37 | 38 | " ISOBJECT: 39 | function! sample#base#isobject(that) abort "{{{ 40 | return s:class._isobject_(a:that) 41 | endfunction "}}} 42 | function! sample#base#isa(that) abort "{{{ 43 | return s:class._isa_(a:that) 44 | endfunction "}}} 45 | 46 | echo 'sample#base is loading' 47 | 48 | " TEST: 49 | function! sample#base#test(...) abort "{{{ 50 | return 0 51 | endfunction "}}} 52 | -------------------------------------------------------------------------------- /autoload/sample/inter1.vim: -------------------------------------------------------------------------------- 1 | " Class: sample#inter1 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-20 5 | " Modify: 2017-02-20 6 | 7 | " CLASS: 8 | let s:class = class#old() 9 | let s:class._name_ = 'sample#inter1' 10 | let s:class._version_ = 1 11 | 12 | function! sample#inter1#class() abort "{{{ 13 | return s:class 14 | endfunction "}}} 15 | 16 | " InterFuncA1: 17 | function! s:class.InterFuncA1() dict abort "{{{ 18 | echo 'calling InterFuncA1 of sample#inter1' 19 | endfunction "}}} 20 | " InterFuncB1: 21 | function! s:class.InterFuncB1() dict abort "{{{ 22 | echo 'calling InterFuncB1 of sample#inter1' 23 | endfunction "}}} 24 | 25 | " MERGE: 26 | function! sample#inter1#merge(that) abort "{{{ 27 | call a:that._merge_(s:class) 28 | endfunction "}}} 29 | 30 | " ISOBJECT: 31 | function! sample#inter1#isobject(that) abort "{{{ 32 | return s:class._isobject_(a:that) 33 | endfunction "}}} 34 | function! sample#inter1#isa(that) abort "{{{ 35 | return s:class._isa_(a:that) 36 | endfunction "}}} 37 | 38 | echo 'sample#inter1 is loading' 39 | 40 | " TEST: 41 | function! sample#inter1#test(...) abort "{{{ 42 | return 0 43 | endfunction "}}} 44 | -------------------------------------------------------------------------------- /autoload/sample/inter2.vim: -------------------------------------------------------------------------------- 1 | " Class: sample#inter2 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-20 5 | " Modify: 2017-02-20 6 | 7 | " CLASS: 8 | let s:class = class#old() 9 | let s:class._name_ = 'sample#inter2' 10 | let s:class._version_ = 1 11 | 12 | function! sample#inter2#class() abort "{{{ 13 | return s:class 14 | endfunction "}}} 15 | 16 | " InterFuncA2: 17 | function! s:class.InterFuncA2() dict abort "{{{ 18 | echo 'calling InterFuncA2 of sample#inter2' 19 | endfunction "}}} 20 | " InterFuncB2: 21 | function! s:class.InterFuncB2() dict abort "{{{ 22 | echo 'calling InterFuncB2 of sample#inter2' 23 | endfunction "}}} 24 | 25 | " MERGE: 26 | function! sample#inter2#merge(that) abort "{{{ 27 | call a:that._merge_(s:class) 28 | endfunction "}}} 29 | 30 | " ISOBJECT: 31 | function! sample#inter2#isobject(that) abort "{{{ 32 | return s:class._isobject_(a:that) 33 | endfunction "}}} 34 | function! sample#inter2#isa(that) abort "{{{ 35 | return s:class._isa_(a:that) 36 | endfunction "}}} 37 | 38 | echo 'sample#inter2 is loading' 39 | 40 | " TEST: 41 | function! sample#inter2#test(...) abort "{{{ 42 | return 0 43 | endfunction "}}} 44 | -------------------------------------------------------------------------------- /autoload/sample/inter3.vim: -------------------------------------------------------------------------------- 1 | " Class: sample#inter2 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-20 5 | " Modify: 2017-02-20 6 | 7 | " CLASS: 8 | let s:class = class#old() 9 | let s:class._name_ = 'sample#inter3' 10 | let s:class._version_ = 1 11 | 12 | function! sample#inter3#class() abort "{{{ 13 | return s:class 14 | endfunction "}}} 15 | 16 | " InterFuncA3: 17 | function! s:class.InterFuncA3() dict abort "{{{ 18 | echo 'calling InterFuncA3 of sample#inter3' 19 | endfunction "}}} 20 | " InterFuncB3: 21 | function! s:class.InterFuncB3() dict abort "{{{ 22 | echo 'calling InterFuncB3 of sample#inter3' 23 | endfunction "}}} 24 | 25 | " MERGE: 26 | function! sample#inter3#merge(that) abort "{{{ 27 | call a:that._merge_(s:class) 28 | endfunction "}}} 29 | 30 | " ISOBJECT: 31 | function! sample#inter3#isobject(that) abort "{{{ 32 | return s:class._isobject_(a:that) 33 | endfunction "}}} 34 | function! sample#inter3#isa(that) abort "{{{ 35 | return s:class._isa_(a:that) 36 | endfunction "}}} 37 | 38 | echo 'sample#inter3 is loading' 39 | 40 | " TEST: 41 | function! sample#inter3#test(...) abort "{{{ 42 | return 0 43 | endfunction "}}} 44 | -------------------------------------------------------------------------------- /autoload/sample/sub.vim: -------------------------------------------------------------------------------- 1 | " Class: sample#sub 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-20 5 | " Modify: 2017-02-20 6 | 7 | " CLASS: 8 | let s:class = class#old('sample#base', 'sample#inter1', 'sample#inter2') 9 | let s:class._name_ = 'sample#sub' 10 | let s:class._version_ = 1 11 | 12 | let s:class.subProperty = 'subProperty' 13 | 14 | function! sample#sub#class() abort "{{{ 15 | return s:class 16 | endfunction "}}} 17 | 18 | " NEW: 19 | function! sample#sub#new(...) abort "{{{ 20 | let l:obj = copy(s:class) 21 | call l:obj._new_(a:000) 22 | return l:obj 23 | endfunction "}}} 24 | 25 | " CTOR: 26 | function! sample#sub#ctor(this, argv) abort "{{{ 27 | if len(a:argv) > 0 28 | let a:this.subProperty = a:argv[0] 29 | endif 30 | if len(a:argv) > 1 31 | let l:Suctor = s:class._suctor_() 32 | call l:Suctor(a:this, [a:argv[1]]) 33 | endif 34 | endfunction "}}} 35 | 36 | " COPY: 37 | function! sample#sub#copy(that, ...) abort "{{{ 38 | let l:obj = copy(s:class) 39 | call l:obj._copy_(a:that) 40 | if a:0 > 0 41 | let l:obj.subProperty = a:1 42 | endif 43 | return l:obj 44 | endfunction "}}} 45 | 46 | " OLD: 47 | function! sample#sub#old() abort "{{{ 48 | let l:class = copy(s:class) 49 | call l:class._old_() 50 | return l:class 51 | endfunction "}}} 52 | 53 | " SubMethod: 54 | function! s:class.SubMethod() dict abort "{{{ 55 | echo 'calling SubMethod()' 56 | endfunction "}}} 57 | 58 | " ISOBJECT: 59 | function! sample#sub#isobject(that) abort "{{{ 60 | return s:class._isobject_(a:that) 61 | endfunction "}}} 62 | function! sample#sub#isa(that) abort "{{{ 63 | return s:class._isa_(a:that) 64 | endfunction "}}} 65 | 66 | " TEST: 67 | function! sample#sub#test(...) abort "{{{ 68 | if a:0 > 1 69 | let l:jsub = sample#sub#new(a:1, a:2) 70 | else 71 | let l:jsub = sample#sub#new() 72 | endif 73 | echo l:jsub.subProperty l:jsub.baseProperty 74 | 75 | call l:jsub.SubMethod() 76 | call l:jsub.BaseMethod() 77 | call l:jsub.InterFuncA1() 78 | call l:jsub.InterFuncB1() 79 | call l:jsub.InterFuncA2() 80 | call l:jsub.InterFuncB2() 81 | 82 | echo 'jsub sub#isobject? ' . sample#sub#isobject(l:jsub) 83 | echo 'jsub base#isobject? ' . sample#base#isobject(l:jsub) 84 | 85 | echo 'jsub sub#isa? ' . sample#sub#isa(l:jsub) 86 | echo 'jsub base#isa? ' . sample#base#isa(l:jsub) 87 | echo 'jsub inter1#isa? ' . sample#inter1#isa(l:jsub) 88 | echo 'jsub inter2#isa? ' . sample#inter2#isa(l:jsub) 89 | 90 | let l:jbase = sample#base#new('base') 91 | let l:jcsub = sample#sub#copy(l:jbase, 'sub') 92 | echo l:jcsub._name_ l:jcsub._super_ 93 | echo l:jcsub.baseProperty l:jcsub.subProperty 94 | return 0 95 | endfunction "}}} 96 | -------------------------------------------------------------------------------- /autoload/sample/subsub.vim: -------------------------------------------------------------------------------- 1 | " Class: sample#subsub 2 | " Author: lymslive 3 | " Description: VimL class frame 4 | " Create: 2017-02-20 5 | " Modify: 2017-02-20 6 | 7 | " CLASS: 8 | let s:class = sample#sub#old() 9 | call sample#inter3#merge(s:class) 10 | let s:class._name_ = 'sample#subsub' 11 | let s:class._version_ = 1 12 | 13 | function! sample#subsub#class() abort "{{{ 14 | return s:class 15 | endfunction "}}} 16 | 17 | " NEW: 18 | function! sample#subsub#new(...) abort "{{{ 19 | let l:obj = copy(s:class) 20 | call l:obj._new_(a:000) 21 | return l:obj 22 | endfunction "}}} 23 | 24 | " CTOR: 25 | function! sample#subsub#ctor(this, argv) abort "{{{ 26 | let l:Suctor = s:class._suctor_() 27 | call l:Suctor(a:this, a:argv) 28 | endfunction "}}} 29 | 30 | " ISOBJECT: 31 | function! sample#subsub#isobject(that) abort "{{{ 32 | return s:class._isobject_(a:that) 33 | endfunction "}}} 34 | function! sample#subsub#isa(that) abort "{{{ 35 | return s:class._isa_(a:that) 36 | endfunction "}}} 37 | 38 | echo 'sample#subsub is loading ...' 39 | 40 | " TEST: 41 | function! sample#subsub#test(...) abort "{{{ 42 | if a:0 > 1 43 | let l:jsub = sample#subsub#new(a:1, a:2) 44 | else 45 | let l:jsub = sample#subsub#new() 46 | endif 47 | echo l:jsub.subProperty l:jsub.baseProperty 48 | 49 | call l:jsub.SubMethod() 50 | call l:jsub.BaseMethod() 51 | call l:jsub.InterFuncA1() 52 | call l:jsub.InterFuncB1() 53 | call l:jsub.InterFuncA2() 54 | call l:jsub.InterFuncB2() 55 | call l:jsub.InterFuncA3() 56 | call l:jsub.InterFuncB3() 57 | 58 | echo 'jsub sub#isobject? ' . sample#sub#isobject(l:jsub) 59 | echo 'jsub base#isobject? ' . sample#base#isobject(l:jsub) 60 | 61 | echo 'jsub sub#isa? ' . sample#sub#isa(l:jsub) 62 | echo 'jsub base#isa? ' . sample#base#isa(l:jsub) 63 | echo 'jsub inter1#isa? ' . sample#inter1#isa(l:jsub) 64 | echo 'jsub inter2#isa? ' . sample#inter2#isa(l:jsub) 65 | echo 'jsub inter3#isa? ' . sample#inter3#isa(l:jsub) 66 | endfunction "}}} 67 | -------------------------------------------------------------------------------- /autoload/sample/upc2.vim: -------------------------------------------------------------------------------- 1 | " update tempclass v1 to v2 2 | " batch substitute some api code 3 | 4 | g/let l:obj = copy(s:class)/delete 5 | g/let l:class = copy(s:class)/delete 6 | %s/call l:obj._new_(a:000.*)/let l:obj = class#new(s:class, a:000)/ 7 | %s/let l:Suctor = s:class._suctor_()/let l:Suctor = class#Suctor(s:class)/ 8 | %s/call l:class._old_()/let l:class = class#old(s:class)/ 9 | %s/return s:class._isobject_(a:that)/return class#isobject(s:class, a:that)/ 10 | %s/return s:class._isa_(a:that)/return class#isa(s:class, a:that)/ 11 | -------------------------------------------------------------------------------- /autoload/sample/usemod.vim: -------------------------------------------------------------------------------- 1 | let s:List = module#import('unite.Data.List') 2 | let s:array = [1, 2, 3] 3 | echo s:array 4 | 5 | :DLOG 'call pop ...' 6 | echo s:List.pop(s:array) 7 | echo s:array 8 | 9 | :DLOG 'call push ...' 10 | echo s:List.push(s:array, 4) 11 | echo s:array 12 | -------------------------------------------------------------------------------- /autoload/tempclass.vim: -------------------------------------------------------------------------------- 1 | " HEADER: -h 2 | " Class: tempclass 3 | " Author: lymslive 4 | " Description: VimL class frame 5 | " Create: 2017-02-10 6 | " Modify: 2018-05-21 7 | 8 | " LOAD: -l 9 | if exists('s:load') && !exists('g:DEBUG') 10 | finish 11 | endif 12 | 13 | " CLASS: 14 | let s:class = class#old() 15 | let s:class._name_ = 'tempclass' 16 | let s:class._version_ = 1 17 | 18 | function! tempclass#class() abort "{{{ 19 | return s:class 20 | endfunction "}}} 21 | 22 | " NEW: -n 23 | function! tempclass#new(...) abort "{{{ 24 | let l:obj = class#new(s:class, a:000) 25 | return l:obj 26 | endfunction "}}} 27 | " CTOR: -c 28 | function! tempclass#ctor(this, ...) abort "{{{ 29 | let l:Suctor = class#Suctor(s:class) 30 | call call(l:Suctor, extend([a:this], a:000)) 31 | endfunction "}}} 32 | 33 | " DECTOR: -D 34 | function! tempclass#dector(this) abort "{{{ 35 | endfunction "}}} 36 | 37 | " OLD: -O 38 | function! tempclass#old() abort "{{{ 39 | let l:class = class#old(s:class) 40 | return l:class 41 | endfunction "}}} 42 | 43 | " MASTER: -M 44 | function! tempclass#master(that, ...) abort "{{{ 45 | if a:0 > 0 && !empty(a:1) 46 | call class#AsMaster(a:that, s:class, a:1) 47 | else 48 | call class#AddMaster(a:that, s:class) 49 | endif 50 | endfunction "}}} 51 | 52 | " FATHER: -F 53 | function! tempclass#father(that, ...) abort "{{{ 54 | if a:0 > 0 && !empty(a:1) 55 | call class#AsFather(a:that, s:class, a:1) 56 | else 57 | call class#AddFather(a:that, s:class) 58 | endif 59 | endfunction "}}} 60 | 61 | " ISOBJECT: -s 62 | function! tempclass#isobject(that) abort "{{{ 63 | return class#isobject(s:class, a:that) 64 | endfunction "}}} 65 | 66 | " ISA: -S 67 | function! tempclass#isa(that) abort "{{{ 68 | return class#isa(s:class, a:that) 69 | endfunction "}}} 70 | 71 | " INSTANCE: -I 72 | " let s:instance = {} 73 | function! tempclass#instance() abort "{{{ 74 | if !exists('s:instance') 75 | let s:instance = class#new(s:class) 76 | endif 77 | return s:instance 78 | endfunction "}}} 79 | 80 | " CONVERSION: -X 81 | function! s:class.string() dict abort "{{{ 82 | return self._class_._name_ 83 | endfunction "}}} 84 | function! s:class.number() dict abort "{{{ 85 | return self._class_._version_ 86 | endfunction "}}} 87 | 88 | " VIEW: -V 89 | function! s:class.disp() dict abort "{{{ 90 | echo self.string() . ':' . self.number() 91 | endfunction "}}} 92 | 93 | " USE: -U 94 | function! tempclass#use(...) abort "{{{ 95 | return class#use(s:class, a:000) 96 | endfunction "}}} 97 | 98 | " LOAD: -l 99 | let s:load = 1 100 | function! tempclass#load(...) abort "{{{ 101 | if a:0 > 0 && !empty(a:1) 102 | unlet! s:load 103 | endif 104 | endfunction "}}} 105 | 106 | " TEST: -t 107 | function! tempclass#test(...) abort "{{{ 108 | let l:obj = tempclass#new() 109 | call class#echo(l:obj) 110 | endfunction "}}} 111 | -------------------------------------------------------------------------------- /autoload/vimloo/plugin.vim: -------------------------------------------------------------------------------- 1 | " File: vimloo.vim 2 | " Author: lymslive 3 | " Description: global command defined for vimloo 4 | " Create: 2017-02-11 5 | " Modify: 2018-05-02 6 | 7 | " for back compatible reason, pre-define some dummy command 8 | if !exists(':DLOG') 9 | command! -nargs=* DLOG " pass 10 | command! -nargs=* ELOG " pass 11 | command! -nargs=* WLOG " pass 12 | endif 13 | 14 | " load: 15 | function! vimloo#plugin#load() abort "{{{ 16 | return 1 17 | endfunction "}}} 18 | 19 | -------------------------------------------------------------------------------- /content.md: -------------------------------------------------------------------------------- 1 | # vimloo 主要文件内容 2 | 3 | * [autoload/package.vim](autoload/package.vim) 4 | package 包管理机制 5 | * [autoload/object.vim](autoload/object.vim) 6 | object 通用对象定义 7 | * [autoload/class.vim](autoload/class.vim) 8 | class 基类定义 9 | * [autoload/tempclass.vim](autoload/tempclass.vim) 10 | 标准模板子类定义范例 11 | * [plugin/vimloo.vim](plugin/vimloo.vim) 12 | 全局命令定义 13 | * [autoload/jp/](autoload/jp/) 14 | 导入日本社区的 vital 库 15 | * [autoload/ly/](autoload/ly/) 16 | 个人写的通用模块 17 | 18 | * [autoload/class/](autoload/class/) 19 | 一些工具类定义都放在 class 子目录下 20 | * [autoload/class/less](autoload/class/less) 21 | 伪装成类的过程化模块,一些实用函数 22 | * [autoload/class/cmdlime.vim](autoload/class/cmdlime.vim) 23 | 解析命令行选项工具,助于实现复杂功能的自定义命令 24 | * [autoload/class/option/](autoload/class/option/) 25 | 命令行选项的类定义 26 | * [autoload/class/loger.vim](autoload/class/loger.vim) 27 | 日志类定义,LogOn LogOff LogLevel LOG 等命令,增加简单方便的 echo 调试脚本的灵活性与实用性。 28 | 29 | -------------------------------------------------------------------------------- /doc.md/class-dict.md: -------------------------------------------------------------------------------- 1 | # VimL 基础对象模型教程 2 | 3 | VimL 语言其实并没有内置的对象概念。其变量类型主要有两种简单标量(数字与字符串) 4 | 与两种集合类型(列表与字典)。但在字典的键中不仅可存普通变量,还能存函数(实际 5 | 是函数引用 Funcref),因而字典就可以当作对象来使用了。 6 | 7 | ## 字典当作对象使用 (dict as object) 8 | 9 | 字典的常规定义与使用如: 10 | ``` 11 | let dic = {'x': 3, 'y': 4} 12 | echo dic['x'] 13 | echo dic['y'] 14 | ``` 15 | 16 | 但是,也可写成这样: 17 | ``` 18 | let obj = {} 19 | let obj.x = 3 20 | let obj.y = 4 21 | echo obj.x + obj.y 22 | ``` 23 | 24 | 这就有点像对象的点号引用语法了。当然了,要用点号引用字典的键,那个键不能用奇怪 25 | 字符串,须用正常的能用于变量标志符的字符串。 26 | 27 | ## 用字典的键保存函数 28 | 29 | 用如下语法定义一个函数并保存在字典中: 30 | ``` 31 | function! obj.distance() dict 32 | return sqrt(self.x*self.x + self.y*self.y) 33 | endfunction 34 | ``` 35 | 36 | 与常规函数相比,其函数名不是简单的变量名,而是 `obj.distance`,表示它是存于字 37 | 典 `dict` 中的键名 `distance` 中。可以分别用如下命令查看一下这像什么情况: 38 | ``` 39 | echo obj.distance 40 | echo obj['distance'] 41 | echo obj 42 | ``` 43 | 44 | 函数定义头行末尾的关键字 `dict` 表示该函数通过字典变量调用,此时函数体中的 45 | `self` 就代表该字典本身。调用方法如下: 46 | ``` 47 | echo obj.distance() 48 | echo obj.distance() * 2 49 | ``` 50 | 51 | 请注意,带括号的 `obj.distance()` 表示函数调用,它返回函数计算值 `5.0`。而不带 52 | 括号的 `obj.distance` 等效于 `obj['distance']`,获取这个键名中所存的东西,它是 53 | 个函数引用。 54 | 55 | ## 类与实例:实例是类字典的拷贝 56 | 57 | 可以继续为上面的字典变量 `obj` 添加更多的属性(键存值)与方法(键存函数)。然 58 | 而它始终还只是一个“对象”,如何抽象出更“类”的东西呢。可以这样写: 59 | ``` 60 | let class = {} 61 | let class.x = 0 62 | let class.y = 0 63 | function! class.distance() dict 64 | return sqrt(self.x*self.x + self.y*self.y) 65 | endfunction 66 | 67 | let obj1 = copy(class) 68 | let obj1.x = 3 69 | let obj1.y = 4 70 | echo obj1.distance() 71 | 72 | let obj2 = copy(class) 73 | let obj2.x = 30 74 | let obj2.y = 40 75 | echo obj2.distance() 76 | 77 | echo obj1.distance == obj2.distance 78 | echo obj1.distance() == obj2.distance() 79 | ``` 80 | 81 | 上面第一段代码,定义了一个“类” 也即一个名为 `class` 的字典。为该类定义了两个属 82 | 性名为 `x` `y` 及一个方法 `distance`。然后以这个类为模板,创建了两个“实例”对象 83 | 。最后两行演示相等性,这两个对象的 `distance` 方法是相同的,但它们各自调用 84 | `distance()` 方法产生的结果是不相等的。 85 | 86 | 从 VimL 角度看,`class` `obj1` `obj2` 都只是三个不同的字典变量。键名 `x` `y` 87 | 存的是值,相互独立,键名 `distance` 保存的函数引用,却是引用同一个函数。 88 | 89 | ## 类与对象的动态性 90 | 91 | 既然类与对象都是字典,那么可以继续为其添加属性(键值)而互不影响。如: 92 | ``` 93 | let class.z = 0 94 | let obj1.a = obj1.distance() 95 | let obj2.b = obj2.distance() 96 | 97 | function! class.product() dict 98 | return (self.x*self.x + self.y*self.y) 99 | endfunction 100 | 101 | let obj3 = copy(class) 102 | echo obj3.product() 103 | let obj3.x = 3 104 | let obj3.y = 4 105 | let obj3.z = obj3.product() 106 | echo obj3.z 107 | ``` 108 | 109 | 为类 `class` 新加一个属性 `z`,但已创建的实例 `obj1` `obj2` 不会有这个属性。 110 | `obj1` 新加一个 `a` 属性来保存 `disctance()` 的计算值,`obj2` 也不会有 `a` 属 111 | 性。`obj2` 新加的 `b` 属性亦然。 112 | 113 | 特别地,如果为类 `class` 新定义一个 `product` 方法,则原来的 `obj1` `obj2` 不 114 | 可调用该方法。但若此后再创建一个 `obj3`,它就可用 `product` 方法了,因为它从此 115 | 刻的 `class` 字典中拷贝过来了。 116 | 117 | ## 继承:子类也是父类的拷贝 118 | 119 | 如下代码,可以在原来的类基础上创建新类: 120 | ``` 121 | let subclass = copy(class) 122 | 123 | " 添加新的属性,或覆盖原来的键值定义 124 | 125 | let subobj = copy(subclass) 126 | ``` 127 | 128 | 由于 VimL 是弱类型语言,那也就容易实现多态了。比如把许多不同类的实例对象,保存 129 | 在一个列表内,对它们调用同一个方法,那显然会根据它们各自保存的函数引用调用相应 130 | 的实现方法了。 131 | -------------------------------------------------------------------------------- /doc.md/vimllib-jp.md: -------------------------------------------------------------------------------- 1 | # VimL 脚本通用工具库收集 2 | 3 | ## `jp#` 日本 vim 社区的 vital.vim 4 | 5 | 源于这里:https://github.com/vim-jp/vital.vim 6 | 7 | 我将 vital 的模块稍作整理,重置于 `jp#` 命名空间之下。这是日本 `japanese` 的缩 8 | 写;如果懂汉语拼音的话,也可读作极品 `jiping` 。 9 | 10 | ### 所作调整只有: 11 | 12 | * 将依赖引用其他模块的语句,改用 `package#import()` 函数按 `#` 化的标准路径引 13 | 入。基本只涉及发动部分模块的前面几行,不影响具体功能的实现。 14 | * 将其明确标记为 `Deprecated` 的剔除,不再跟踪维护。 15 | * 测试目录 `test/` 为了能重跑,也将导入模块的语句调整。按 vital 原来使用的测试 16 | 框架,需要用到 [thinca/vim-themis](https://github.com/thinca/vim-themis) 。 17 | 18 | ### 使用方法 19 | 20 | 只要下载仓库的目录加入 vim 的 `&rtp` 路径,可在任意 VimL 脚本中按标准路径导入 21 | `jp#` 库,如: 22 | 23 | ```vim 24 | let L = package#import('jp#Data#List') 25 | call L.pop() 26 | ``` 27 | 28 | 也可以在插件中先建立本地包管理对象,用略短的相对路径导入,如: 29 | ```vim 30 | let V = package#new('near compatible to vital', 'jp') 31 | let V = package#new('jp') 32 | let L = V.import('Data.List') 33 | call L.pop() 34 | ``` 35 | 36 | 上面两句 `package#new()` 调用几乎等效,因为对象的名字不重要,重要的是路径。 37 | 38 | `vital` 原来的惯用做法,是提供另一个命令,将所需的部分模块(及其引用的模块)安 39 | 装(也就是复制)到各做插件中,同时也在每个安装的模块文件头部,自动生成一些必要 40 | 的导出代码。虽然据说这能使各插件保持独立,解耦,但个人认为这造成了很大的冗余。 41 | 如果你安装他们的插件套餐,vim 运行时就得重复加载那些内容功能相同只是位置路径不 42 | 一样的脚本。 43 | 44 | 这里的 `package.vim` 提供一种全局共享的思路,让每个工具模块组织下标准的 `#` 命 45 | 名空间之下,而日本社区的 vital 正归于 `jp#` 命名空间下。但是也依然提供使用对象 46 | 的方法来管理特定插件目录下的模块,不论是自己新写的,还是从其他地方拷过来的。 47 | 48 | -------------------------------------------------------------------------------- /plugin/vimloo.vim: -------------------------------------------------------------------------------- 1 | " File: vimloo.vim 2 | " Author: lymslive 3 | " Description: global command defined for vimloo 4 | " Create: 2017-02-11 5 | " Modify: 2017-08-01 6 | 7 | call vimloo#plugin#load() 8 | -------------------------------------------------------------------------------- /readme-en.md: -------------------------------------------------------------------------------- 1 | # A Solution of Object Orient Programming in Viml Script 2 | `vimloo` `git/readme` 3 | 4 | ## Introduction 5 | 6 | * `class` is a dict variable defined in a script which under the autoload 7 | subdirecotry, class name is the relative path to autoload. 8 | * `object` instance is a sub-copy of class, may with modified data keys. 9 | * `derived` class is also a sub-copy of base class, may add data or/and method 10 | keys. 11 | 12 | ## Functionality 13 | 14 | * base class design, providing many fundamental methods and functions. 15 | * template files to make it easy to create custome class and module. 16 | * some other smart commands used in script to help writting viml code in a more 17 | pretty way. 18 | 19 | ## Install 20 | 21 | Just clone down this rep to a runtime path of vim(`&rtp`), or use some plugin 22 | manage tool to Install. For example: 23 | 24 | ```sh 25 | $ mkdir -p ~/.vim/pack/lymslive/opt 26 | $ cd ~/.vim/pack/lymslive/opt 27 | $ git clone https://github.com/lymslive/vimloo 28 | ``` 29 | 30 | * requirement: vim7.4 or above, recommanded vim8.0 31 | * for common user, only the code in `autoload/` is needed 32 | * for VimL Plugin writer, the command in `plugin` may also be helpful 33 | 34 | Any vimer can feel free to install this plugin, because by default, there is 35 | no effect on your own vim evironment or habit, expcept some disk space, and an 36 | item longer of vim's `runtimepath`. The script code in `autoload/` is sourced 37 | only when needed, and so little effect on the speed of vim startup. 38 | 39 | ## Command 40 | 41 | For viml script writer, add one of the following config to `.vimrc`: 42 | ```vim 43 | let g:vimloo_plugin_enable = 1 44 | let g:vimloo_ftplugin_enable = 1 45 | ``` 46 | or 47 | ```vim 48 | call vimloo#plugin#load() 49 | ``` 50 | 51 | Then some useful command is definded for writting vim script. 52 | 53 | * `:ClassNew {name}` when currnet director is under some `autoload` 54 | sub-director, or given `name` as full path, this command will create a new 55 | file with `name.vim`, and auto generate a class definition by that name. 56 | * `:ClassAdd` when editing an exisited vim file, this will append a class 57 | definition by the current file name. 58 | * `:ClassPart {option}` the default behavior of `ClassNew` or `ClassAdd` only 59 | generate minimun required component, this command will add more later. Refer 60 | to the template class file [autoload/tempclass.vim](autoload/tempclass.vim). 61 | * `:ClassTest [argumemt list]` if the class file contain a `#test()` function, 62 | this will call that function, and extra command argument is also passed. 63 | * `:ClassRename` if the class file is moved to another place, the funtion names 64 | `path#to#class#func()` will be wrong, this commnad is used to repair such 65 | problem. 66 | 67 | ## Function 68 | 69 | Some of most import functions to define and use class are: 70 | 71 | * `class#new()` create an object instance, anywhere when needed. 72 | * `class#old()` create a derived class, mainly used in class file. 73 | * `class#isobject()` determined whether a virable is an instance of a class. 74 | * `class#use()` import a class package to where used frequently, avoid 75 | `long#path#to#class#name()`. 76 | 77 | Function argument is not included above, detail refer to online help doc. It's 78 | common to define their own `path#to#class#new()` functions in each individul 79 | class file. The later usually has one less argument than the base `class#new()` 80 | functios, since the sepcific `s:class` is passed to `class#new()`, for example. 81 | 82 | ## Plugin Practice 83 | 84 | There are some vim plugins based on `vimloo`, and so `vimloo` must be 85 | installed with any of them: 86 | 87 | * [vnote](https://github.com/lymslive/vnote) 88 | * [StartVim](https://github.com/lymslive/StartVim) 89 | * [tygame](https://github.com/lymslive/tygame) 90 | 91 | ## Documentation 92 | 93 | Online help `doc/vimloo.txt` is available. 94 | 95 | A _chinese version_ readme is also availabe 96 | ([中文补充文档](readme-zh.md)). 97 | 98 | ## Change Log 99 | 100 | * 2017-8: class.vim version change to 2. The base class mechanism has improved 101 | much compare to version 1. The object dictionary struct is not necessary the 102 | same as class dictionary. A class is mainly direct on how to create an 103 | object. 104 | --------------------------------------------------------------------------------