Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Version 0.2.1

added tree settings save/load methods
added ignore file/dir/find results change methods
some minor bugs fixed
  • Loading branch information...
commit adfb37bdf1ecd25895abed7f7dfdd990dce615b1 1 parent 8f4f720
Dmitry Geurkov authored January 11, 2013 vim-scripts committed January 13, 2013
252  autoload/easytree.py
... ...
@@ -0,0 +1,252 @@
  1
+# easytree.vim - simple tree file manager for vim
  2
+# Maintainer: Dmitry "troydm" Geurkov <d.geurkov@gmail.com>
  3
+# Version: 0.2.1
  4
+# Description: easytree.vim is a siple tree file manager
  5
+# Last Change: 10 January, 2013
  6
+# License: Vim License (see :help license)
  7
+# Website: https://github.com/troydm/easytree.vim
  8
+
  9
+import vim,random,os,grp,pwd,time,stat,sys,shutil,fnmatch,threading
  10
+
  11
+easytree_dirsize_calculator = None
  12
+easytree_dirsize_calculator_cur_size = 0
  13
+
  14
+def EasyTreeFnmatchList(f,patterns):
  15
+    for p in patterns:
  16
+        if fnmatch.fnmatch(f,p):
  17
+            return True
  18
+    return False
  19
+
  20
+def EasyTreeFind(pattern,dir,showhidden):
  21
+    if not ('*' in pattern or '?' in pattern or '[' in pattern):
  22
+        pattern = '*'+pattern+'*'
  23
+    ignore_find_result = vim.eval('b:ignore_find_result')
  24
+    filelist = EasyTreeList(dir,showhidden, lambda f: fnmatch.fnmatch(f,pattern))
  25
+    filelist = filter(lambda f: not EasyTreeFnmatchList(f,ignore_find_result), filelist)
  26
+    return filelist
  27
+
  28
+def EasyTreeList(dir,showhidden,findfilter):
  29
+    dir = os.path.expanduser(dir)
  30
+    ignore_dirs = vim.eval('b:ignore_dirs')
  31
+    ignore_files = vim.eval('b:ignore_files')
  32
+    filelist = []
  33
+    showhidden = int(showhidden) == 1
  34
+    for root, dirs, files in os.walk(dir):
  35
+        root = root.replace(dir,'')
  36
+        if root.startswith(os.sep):
  37
+            root = root[1:]
  38
+        if not showhidden:
  39
+            if root.startswith('.') or os.sep+'.' in root:
  40
+                continue
  41
+            dirs = filter(lambda d: not d.startswith("."),dirs)
  42
+            files = filter(lambda f: not f.startswith("."),files)
  43
+        if len(root) > 0:
  44
+            if EasyTreeFnmatchList(root,ignore_dirs):
  45
+                continue
  46
+            dirs = map(lambda d: root+os.sep+d,dirs)
  47
+            files = map(lambda f: root+os.sep+f,files)
  48
+        dirs = filter(findfilter, dirs)
  49
+        files = filter(findfilter, files)
  50
+        dirs = filter(lambda d: not EasyTreeFnmatchList(d,ignore_dirs), dirs)
  51
+        files = filter(lambda f: not EasyTreeFnmatchList(f,ignore_files), files)
  52
+        dirs = sorted(dirs)
  53
+        files = sorted(files)
  54
+        filelist.extend(dirs)
  55
+        filelist.extend(files)
  56
+    return filelist
  57
+
  58
+def EasyTreeListDir(dir,showhidden):
  59
+    dir = os.path.expanduser(dir)
  60
+    ignore_dirs = vim.eval('b:ignore_dirs')
  61
+    ignore_files = vim.eval('b:ignore_files')
  62
+    for root, dirs, files in os.walk(dir):
  63
+        if int(showhidden) == 0:
  64
+            dirs = filter(lambda d: not d.startswith("."),dirs)
  65
+            files = filter(lambda f: not f.startswith("."),files)
  66
+        dirs = filter(lambda d: not EasyTreeFnmatchList(d,ignore_dirs), dirs)
  67
+        files = filter(lambda f: not EasyTreeFnmatchList(f,ignore_files), files)
  68
+        dirs = sorted(dirs)
  69
+        files = sorted(files)
  70
+        return [root, dirs, files]
  71
+
  72
+def EasyTreeCreateFile():
  73
+    path = vim.eval('path')
  74
+    if path.endswith(os.sep):
  75
+        if not os.path.exists(path):
  76
+            os.makedirs(path)
  77
+        else:
  78
+            vim.command("redraw | echom 'directory "+path+" already exists'")
  79
+    else:
  80
+        dpath = os.path.dirname(path)
  81
+        if not os.path.exists(dpath):
  82
+            os.makedirs(dpath)
  83
+        if os.path.isdir(dpath):
  84
+            if not os.path.exists(path):
  85
+                open(path,'w').close()
  86
+            else:
  87
+                vim.command("redraw | echom 'file "+path+" already exists'")
  88
+
  89
+def EasyTreeRenameFile():
  90
+    dpath = vim.eval('dpath')
  91
+    fname = vim.eval('fname')
  92
+    fnameto = vim.eval('fnameto')
  93
+    if os.path.exists(dpath+fname):
  94
+        if not os.path.exists(dpath+fnameto):
  95
+            os.rename(dpath+fname,dpath+fnameto)
  96
+        else:
  97
+            vim.command("redraw | echom 'file "+(dpath+fnameto)+" already exists'")
  98
+    else:
  99
+        vim.command("redraw | echom 'file "+(dpath+fname)+" doesn't exists'")
  100
+
  101
+def EasyTreeCopyFiles():
  102
+    dpath = vim.eval('fpath')+os.sep
  103
+    files = vim.eval('files')
  104
+    i = 0
  105
+    if len(files) == 1:
  106
+        vim.command("redraw | echom 'copying 1 file, please wait...'")
  107
+    else:
  108
+        vim.command("redraw | echom 'copying "+str(len(files))+" files, please wait...'")
  109
+    for f in files:
  110
+        base = os.path.basename(f)
  111
+        dst = dpath+base
  112
+        if os.path.exists(f):
  113
+            copy = False
  114
+            overwrite = False
  115
+            if not os.path.exists(dst):
  116
+                copy = True
  117
+            else:
  118
+                vim.command("echom '"+dst+" already exists'")
  119
+                if int(vim.eval("<SID>AskConfirmationNoRedraw('would you like to overwrite it?')")) == 1:
  120
+                    copy = True
  121
+                    overwrite = True
  122
+                    vim.command("echom 'overwriting file "+dst+"'")
  123
+                elif int(vim.eval("<SID>AskConfirmationNoRedraw('would you like to paste it as another file?')")) == 1:
  124
+                    while True:
  125
+                        newbase = vim.eval("<SID>AskInputNoRedraw('"+dpath+"','"+base+"')")
  126
+                        if newbase == None or len(newbase) == 0:
  127
+                            break
  128
+                        elif not os.path.exists(dpath+newbase):
  129
+                            copy = True
  130
+                            dst = dpath+newbase
  131
+                            vim.command("echom 'saving file as "+dst+"'")
  132
+                            break
  133
+            if copy and f != dst:
  134
+                try:
  135
+                    if os.path.isdir(f):
  136
+                        if overwrite:
  137
+                            shutil.rmtree(dst)
  138
+                        shutil.copytree(f,dst)
  139
+                    else:
  140
+                        shutil.copyfile(f,dst)
  141
+                    i += 1
  142
+                except OSError, e:
  143
+                    print str(repr(e))
  144
+        else:
  145
+            vim.command("echom '"+f+" doesn't exists'")
  146
+    if i == 1:
  147
+        vim.command("echom '1 file copied'")
  148
+    else:
  149
+        vim.command("echom '"+str(i)+" files copied'")
  150
+
  151
+def EasyTreeRemoveFiles():
  152
+    files = vim.eval('files')
  153
+    i = 0
  154
+    messages = []
  155
+    if len(files) == 1:
  156
+        messages.append("deleting 1 file, please wait...")
  157
+    else:
  158
+        messages.append("deleting "+str(len(files))+" files, please wait...")
  159
+    for f in files:
  160
+        if os.path.exists(f):
  161
+            try:
  162
+                if os.path.isdir(f):
  163
+                    shutil.rmtree(f)
  164
+                else:
  165
+                    os.remove(f)
  166
+                i += 1
  167
+            except OSError, e:
  168
+                messages.append(str(repr(e)))
  169
+        else:
  170
+            messages.append(f+" doesn't exists")
  171
+    if i == 1:
  172
+        messages.append("1 file deleted")
  173
+    else:
  174
+        messages.append(str(i)+" files deleted")
  175
+    return messages
  176
+
  177
+def EasyTreeGetSize(size):
  178
+    if size >= 1073741824:
  179
+        size = str(size/1073741824.0)
  180
+        if size.find('.') != -1:
  181
+            size = size[:size.index('.')+2]
  182
+        return size + ' Gb'
  183
+    elif size >= 1048576:
  184
+        size = str(size/1048576.0) 
  185
+        if size.find('.') != -1:
  186
+            size = size[:size.index('.')+2]
  187
+        return size + ' Mb'
  188
+    elif size >= 1024:
  189
+        size = str(size/1024.0) 
  190
+        if size.find('.') != -1:
  191
+            size = size[:size.index('.')+2]
  192
+        return size + ' Kb'
  193
+    else:
  194
+        return str(size) + ' bytes'
  195
+    
  196
+def EasyTreeGetMode(m):
  197
+    mode = ''
  198
+    modes = 'drwxrwxrwx'
  199
+    fs = [stat.S_IFDIR, stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR, stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP, stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
  200
+    i = 0
  201
+    for f in fs:
  202
+        if f & m:
  203
+            mode += modes[i]
  204
+        else:
  205
+            mode += '-'
  206
+        i += 1
  207
+    return mode
  208
+
  209
+def EasyTreeGetDirSize(dir):
  210
+    global easytree_dirsize_calculator, easytree_dirsize_calculator_curr_size
  211
+    total = os.path.getsize(dir)
  212
+    easytree_dirsize_calculator_curr_size = total
  213
+    for dirpath, dirnames, filenames in os.walk(dir):
  214
+        if easytree_dirsize_calculator == None:
  215
+            return
  216
+        for d in dirnames:
  217
+            dp = os.path.join(dirpath, d)
  218
+            try:
  219
+                total += os.path.getsize(dp)
  220
+            except:
  221
+                pass
  222
+        for f in filenames:
  223
+            fp = os.path.join(dirpath, f)
  224
+            try:
  225
+                total += os.path.getsize(fp)
  226
+            except:
  227
+                pass
  228
+        easytree_dirsize_calculator_curr_size = total
  229
+    easytree_dirsize_calculator_curr_size = total
  230
+    return total
  231
+
  232
+def EasyTreeGetInfo():
  233
+    global easytree_dirsize_calculator
  234
+    path = vim.eval('fpath')
  235
+    if os.path.exists(path):
  236
+        st = os.stat(path)
  237
+        name = os.path.basename(path)
  238
+        user = pwd.getpwuid(st.st_uid).pw_name
  239
+        group = grp.getgrgid(st.st_gid).gr_name
  240
+        if stat.S_ISDIR(st.st_mode):
  241
+            size = 0
  242
+            if easytree_dirsize_calculator != None:
  243
+                t = easytree_dirsize_calculator
  244
+                easytree_dirsize_calculator = None
  245
+                t.join()
  246
+            easytree_dirsize_calculator = threading.Thread(target=EasyTreeGetDirSize, args=(path,))
  247
+            easytree_dirsize_calculator.setDaemon(True)
  248
+            easytree_dirsize_calculator.start()
  249
+        else:
  250
+            size = st.st_size
  251
+        return [name,user,group,EasyTreeGetSize(size), EasyTreeGetMode(st.st_mode), time.ctime(st.st_mtime)]
  252
+
1,055  autoload/easytree.vim
... ...
@@ -0,0 +1,1055 @@
  1
+" easytree.vim - simple tree file manager for vim
  2
+" Maintainer: Dmitry "troydm" Geurkov <d.geurkov@gmail.com>
  3
+" Version: 0.2.1
  4
+" Description: easytree.vim is a siple tree file manager
  5
+" Last Change: 10 January, 2013
  6
+" License: Vim License (see :help license)
  7
+" Website: https://github.com/troydm/easytree.vim
  8
+"
  9
+" See easytree.vim for help.  This can be accessed by doing:
  10
+" :help easytree
  11
+
  12
+let s:save_cpo = &cpo
  13
+set cpo&vim
  14
+
  15
+" check if already loaded {{{
  16
+if !exists('g:easytree_loaded')
  17
+    let g:easytree_loaded = 1
  18
+elseif g:easytree_loaded
  19
+    let &cpo = s:save_cpo
  20
+    unlet s:save_cpo
  21
+    finish
  22
+else
  23
+    let g:easytree_loaded = 1
  24
+endif
  25
+" }}}
  26
+
  27
+" load python module {{{
  28
+python << EOF
  29
+import vim, os, random, sys
  30
+easytree_path = vim.eval("expand('<sfile>:h')")
  31
+if not easytree_path in sys.path:
  32
+    sys.path.append(easytree_path)
  33
+del easytree_path 
  34
+import easytree
  35
+EOF
  36
+" }}}
  37
+
  38
+" functions {{{
  39
+" input helpers {{{
  40
+function! s:AskInput(message,val)
  41
+    let r = input(a:message,a:val)
  42
+    redraw
  43
+    echo ''
  44
+    return r
  45
+endfunction
  46
+
  47
+function! s:AskInputNoRedraw(message,val)
  48
+    let r = input(a:message,a:val)
  49
+    echo ' '
  50
+    return r
  51
+endfunction
  52
+
  53
+function! s:AskInputComplete(message,val,complete)
  54
+    let r = input(a:message,a:val,a:complete)
  55
+    redraw
  56
+    echo ''
  57
+    return r
  58
+endfunction
  59
+
  60
+function! s:AskConfirmation(message)
  61
+    let r = tolower(input(a:message.' (y/n) '))
  62
+    redraw
  63
+    echo ''
  64
+    return r == 'y' || r == 'ye' || r == 'yes'
  65
+endfunction
  66
+
  67
+function! s:AskConfirmationNoRedraw(message)
  68
+    let r = tolower(input(a:message.' (y/n) '))
  69
+    echo ' '
  70
+    return r == 'y' || r == 'ye' || r == 'yes'
  71
+endfunction
  72
+" }}}
  73
+
  74
+" utility functions {{{
  75
+function! s:IsDir(line)
  76
+    return !empty(matchlist(a:line,'^\s*[▸▾+\-] \(.*\)$'))
  77
+endfunction
  78
+
  79
+function! s:IsExpanded(line)
  80
+    return !empty(matchlist(a:line,'^\s*[▾\-] \(.*\)$'))
  81
+endfunction
  82
+
  83
+function! s:GetFName(line)
  84
+    return matchlist(a:line,'^[▸▾+\- ]\+\(.*\)$')[1]
  85
+endfunction
  86
+
  87
+function! s:GetParentLvlLinen(linen)
  88
+    if a:linen == 1
  89
+        return 1
  90
+    endif
  91
+    let lvl = s:GetLvl(getline(a:linen))
  92
+    if lvl == 1
  93
+        return 1
  94
+    else
  95
+        let linen = a:linen - 1
  96
+        while linen > 2 && s:GetLvl(getline(linen)) >= lvl
  97
+            let linen -= 1
  98
+        endwhile
  99
+        return linen
  100
+    endif
  101
+endfunction
  102
+
  103
+function! s:GetDirLine(linen)
  104
+    let linen = a:linen
  105
+    let line = getline(linen)
  106
+    if s:IsDir(line)
  107
+        return linen
  108
+    else
  109
+        let linelvl = s:GetLvl(line)-1
  110
+        let linen -= 1
  111
+        while linen > 2
  112
+            let line = getline(linen)
  113
+            if s:IsDir(line) && s:GetLvl(line) == linelvl
  114
+                return linen
  115
+            endif
  116
+            let linen -= 1
  117
+        endwhile
  118
+    endif
  119
+    return 1
  120
+endfunction
  121
+
  122
+function! s:GetLvl(line)
  123
+    let lvl = 0
  124
+    let lvls = '[▸▾+\- ] '
  125
+    while match(a:line, '^'.lvls) == 0
  126
+        let lvl += 1        
  127
+        let lvls = '  '.lvls
  128
+    endwhile
  129
+    return lvl
  130
+endfunction
  131
+
  132
+function! s:GetFullPathDir(linen)
  133
+    let fpath = s:GetFullPath(a:linen)
  134
+    if pyeval("os.path.isdir(vim.eval('fpath'))")
  135
+        return fpath
  136
+    else
  137
+        let fpath = pyeval("os.path.dirname(vim.eval('fpath'))")
  138
+        return fpath
  139
+    endif
  140
+endfunction
  141
+
  142
+function! s:GetFullPath(linen)
  143
+    if a:linen == 2
  144
+        let dirp = getline(1)
  145
+        if dirp != '/'
  146
+            let dirp = pyeval("os.path.abspath(vim.eval('dirp')+'/..')")
  147
+        endif
  148
+        return dirp
  149
+    elseif a:linen == 1
  150
+        return getline(1)
  151
+    endif
  152
+    let dirp = getline(1)
  153
+    let dirm = ''
  154
+    let line = getline(a:linen)
  155
+    let fname = ''
  156
+    let lvl = s:GetLvl(line)
  157
+    let lvln = a:linen
  158
+    while lvl > 0
  159
+        let fname = '/'.s:GetFName(getline(lvln)).fname
  160
+        let lvl -= 1
  161
+        if lvl > 0
  162
+            while s:GetLvl(getline(lvln)) != lvl
  163
+                let lvln -= 1
  164
+            endwhile
  165
+        endif
  166
+    endwhile
  167
+    if dirp == '/'
  168
+        return fname
  169
+    else
  170
+        return dirp.fname
  171
+    endif
  172
+endfunction
  173
+function! s:DirName(path)
  174
+    let path = a:path
  175
+    return pyeval("os.path.dirname(vim.eval('path'))")
  176
+endfunction
  177
+
  178
+function! s:FileName(path)
  179
+    let path = a:path
  180
+    return pyeval("os.path.basename(vim.eval('path'))")
  181
+endfunction
  182
+
  183
+function! s:GetPasteBuffer()
  184
+    let files = split(getreg(v:register),"\n")
  185
+    return filter(files,'filereadable(v:val) || isdirectory(v:val)')
  186
+endfunction
  187
+
  188
+function! s:FindBufnrByFilename(filename)
  189
+    for bnr in filter(range(1,bufnr('$')),"buflisted(v:val) && empty(getbufvar(v:val,'&buftype'))")
  190
+        if expand('#'.bnr.':p') == a:filename
  191
+            return bnr
  192
+        endif
  193
+    endfor
  194
+    return -1
  195
+endfunction
  196
+
  197
+function! s:DeleteBuf(filename)
  198
+    let bnr = s:FindBufnrByFilename(a:filename)
  199
+    if bnr != -1
  200
+        let message = expand('#'.bnr.':p').' is opened in '.bnr.' buffer'
  201
+        if getbufvar(bnr,'&modified')
  202
+            let message .= ' and is modified!'
  203
+        else
  204
+            let message .= '!'
  205
+        endif
  206
+        let message .= ' are you sure you want to delete this buffer?'
  207
+        if s:AskConfirmation(message)
  208
+            exe bnr.'bwipeout!'
  209
+            return 1
  210
+        endif
  211
+    else
  212
+        return 1
  213
+    endif
  214
+    return 0
  215
+endfunction
  216
+" }}}
  217
+
  218
+" action functions {{{
  219
+function! s:EditIgnoreFiles()
  220
+    let il = ''
  221
+    for f in b:ignore_files
  222
+        let il .= f.','
  223
+    endfor
  224
+    if len(il) > 0
  225
+        let il = il[:-2]
  226
+    endif
  227
+    let mil = ''
  228
+    for f in split(s:AskInput("ignore files: ",il),',')
  229
+        let mil .= "'".f."',"
  230
+    endfor
  231
+    if len(mil) > 0
  232
+        let mil = mil[:-2]
  233
+    endif
  234
+    exe 'let b:ignore_files = ['.mil.']'
  235
+    call s:RefreshAll()
  236
+endfunction
  237
+
  238
+function! s:EditIgnoreDirs()
  239
+    let il = ''
  240
+    for d in b:ignore_dirs
  241
+        let il .= d.','
  242
+    endfor
  243
+    if len(il) > 0
  244
+        let il = il[:-2]
  245
+    endif
  246
+    let mil = ''
  247
+    for d in split(s:AskInput("ignore dirs: ",il),',')
  248
+        let mil .= "'".d."',"
  249
+    endfor
  250
+    if len(mil) > 0
  251
+        let mil = mil[:-2]
  252
+    endif
  253
+    exe 'let b:ignore_dirs = ['.mil.']'
  254
+    call s:RefreshAll()
  255
+endfunction
  256
+
  257
+function! s:EditIgnoreFindResult()
  258
+    let il = ''
  259
+    for f in b:ignore_find_result
  260
+        let il .= f.','
  261
+    endfor
  262
+    if len(il) > 0
  263
+        let il = il[:-2]
  264
+    endif
  265
+    let mil = ''
  266
+    for f in split(s:AskInput("ignore find result: ",il),',')
  267
+        let mil .= "'".f."',"
  268
+    endfor
  269
+    if len(mil) > 0
  270
+        let mil = mil[:-2]
  271
+    endif
  272
+    exe 'let b:ignore_find_result = ['.mil.']'
  273
+endfunction
  274
+
  275
+function! s:ChangeDir(linen)
  276
+    let fpath = s:GetFullPathDir(a:linen)
  277
+    call s:InitializeNewTree(fpath)
  278
+    normal! 3G0
  279
+endfunction
  280
+
  281
+function! s:ChangeDirTo(...)
  282
+    if len(a:000) > 0
  283
+        let path = a:1
  284
+    else
  285
+        let path = s:AskInputComplete('go to ',getline(1),'dir')
  286
+    endif
  287
+    if !empty(path) 
  288
+        if pyeval("os.path.isdir(os.path.expanduser(vim.eval('path')))")
  289
+            call s:InitializeNewTree(path)
  290
+        else
  291
+            redraw
  292
+            echo 'invalid path '.path
  293
+        endif
  294
+    endif
  295
+endfunction
  296
+
  297
+function! s:ChangeCwdDir(linen)
  298
+    let fpath = s:GetFullPathDir(a:linen)
  299
+    exe 'cd '.fpath
  300
+    echo 'cwd: '.fpath
  301
+endfunction
  302
+
  303
+function! s:GoUpTree()
  304
+    normal! 2G0
  305
+    call s:EnterPressed()
  306
+endfunction
  307
+
  308
+function! s:ToggleHidden()
  309
+    if b:showhidden
  310
+        let b:showhidden = 0
  311
+    else
  312
+        let b:showhidden = 1
  313
+    endif
  314
+    call s:RefreshAll()
  315
+    if b:showhidden
  316
+        echo 'showing hidden files'
  317
+    else
  318
+        echo 'not showning hidden files'
  319
+    endif
  320
+endfunction
  321
+
  322
+function! s:CopyFile(linen)
  323
+    let fpath = s:GetFullPath(a:linen)
  324
+    call setreg(v:register,fpath)
  325
+    echo '1 file copied'
  326
+endfunction
  327
+
  328
+function! s:CopyFilesRange() range
  329
+    let buf = ''
  330
+    let i = 0
  331
+    for l in range(a:firstline,a:lastline)
  332
+        let fpath = s:GetFullPath(l)
  333
+        let buf .= fpath."\n"
  334
+        let i += 1
  335
+    endfor
  336
+    call setreg(v:register,buf)
  337
+    if i == 1
  338
+        echo '1 file copied'
  339
+    else
  340
+        echo i.' files copied'
  341
+    endif
  342
+endfunction
  343
+
  344
+function! s:EchoPasteBuffer()
  345
+    let files = s:GetPasteBuffer()
  346
+    if len(files) > 0 
  347
+        echo 'paste buffer:'
  348
+        for f in s:GetPasteBuffer()
  349
+            echo f
  350
+        endfor
  351
+    else
  352
+        echo 'no files in paste buffer'
  353
+    endif
  354
+endfunction
  355
+
  356
+function! s:PasteFiles(linen)
  357
+    let fpath = s:GetFullPathDir(a:linen)
  358
+    let files = s:GetPasteBuffer()
  359
+    if len(files) > 0
  360
+        let filesm = '1 file'
  361
+        if len(files) > 1
  362
+            let filesm = len(files).' files'
  363
+        endif
  364
+        for f in files
  365
+            echo f
  366
+        endfor
  367
+        if s:AskConfirmation('are you sure you want to paste '.filesm.'?')
  368
+            python easytree.EasyTreeCopyFiles()
  369
+            call s:Refresh(a:linen)
  370
+        endif
  371
+    endif
  372
+endfunction
  373
+
  374
+function! s:RemoveFile(linen)
  375
+    let messages = []
  376
+    if a:linen > 2
  377
+        let fpath = s:GetFullPath(a:linen)
  378
+        let files = [fpath]
  379
+        if s:DeleteBuf(fpath) && s:AskConfirmation('are you sure you want to delete this file?')
  380
+            let messages = pyeval('easytree.EasyTreeRemoveFiles()')
  381
+            call s:Refresh(s:GetParentLvlLinen(a:linen))
  382
+        endif
  383
+    endif
  384
+    for m in messages
  385
+        echom m
  386
+    endfor
  387
+endfunction
  388
+
  389
+function! s:RemoveFiles() range
  390
+    let files = []
  391
+    for l in range(a:firstline,a:lastline)
  392
+        if l > 2
  393
+            let fpath = s:GetFullPath(l)
  394
+            call add(files,fpath)
  395
+        endif
  396
+    endfor
  397
+    let messages = []
  398
+    if len(files) > 0
  399
+        for f in files
  400
+            if !s:DeleteBuf(f)
  401
+                return
  402
+            endif
  403
+            echo f
  404
+        endfor
  405
+        if s:AskConfirmation('are you really sure you want to delete this files?')
  406
+            let messages = pyeval('easytree.EasyTreeRemoveFiles()')
  407
+            call s:RefreshAll()
  408
+        endif
  409
+    endif
  410
+    for m in messages
  411
+        echom m
  412
+    endfor
  413
+endfunction
  414
+
  415
+function! s:CreateFile(linen)
  416
+    let fpath = s:GetFullPathDir(a:linen).'/'
  417
+    let path = s:AskInput('create '.fpath,'')
  418
+    if !empty(path)
  419
+        let path = fpath.path
  420
+        python easytree.EasyTreeCreateFile()
  421
+        call s:Refresh(a:linen)
  422
+    endif
  423
+endfunction
  424
+
  425
+function! s:RenameFile(linen)
  426
+    let fpath = s:GetFullPath(a:linen)
  427
+    let dpath = s:DirName(fpath).'/'
  428
+    let fname = s:FileName(fpath)
  429
+    let fnameto = s:AskInput('rename '.dpath,fname)
  430
+    if !empty(fnameto)
  431
+        if !s:DeleteBuf(fpath)
  432
+            return
  433
+        endif
  434
+        python easytree.EasyTreeRenameFile()
  435
+        call s:Refresh(s:GetParentLvlLinen(a:linen))
  436
+    endif
  437
+endfunction
  438
+
  439
+function! s:RefreshAll()
  440
+    if line('.') > 2
  441
+        let prevfpath = s:GetFullPath(line('.'))
  442
+    endif
  443
+    let toexpand = {}
  444
+    let newtree = line('$') == 1
  445
+    if !newtree
  446
+        for d in keys(b:expanded)
  447
+            if b:expanded[d]
  448
+                let toexpand[d] = 1
  449
+            endif
  450
+        endfor
  451
+        let expanded = b:expanded
  452
+    endif
  453
+    let line = getline(1)
  454
+    let pos = getpos('.')
  455
+    call s:InitializeTree(line)
  456
+    if newtree
  457
+        let toexpand = filter(b:expanded,'v:val == 1')
  458
+    else
  459
+        let b:expanded = expanded
  460
+    endif
  461
+    let linen = 3
  462
+    setlocal modifiable
  463
+    while line('$') >= linen
  464
+        let line = getline(linen)
  465
+        if s:GetLvl(line) == 1 && s:IsDir(line)
  466
+            let fpath = s:GetFullPath(linen)
  467
+            if has_key(toexpand, fpath)
  468
+                call s:ExpandDir(fpath,linen)
  469
+            endif
  470
+        endif
  471
+        let linen += 1
  472
+    endwhile
  473
+    setlocal nomodifiable
  474
+    if pos[1] > 2
  475
+        if prevfpath != s:GetFullPath(pos[1])
  476
+            let i = 1
  477
+            let maxln = line('$')
  478
+            while (pos[1]-i) > 2 || (pos[1]+i) <= maxln
  479
+                if (pos[1]-i) > 2
  480
+                    if prevfpath == s:GetFullPath(pos[1]-i)
  481
+                        let pos[1] -= i
  482
+                        break
  483
+                    endif
  484
+                endif
  485
+                if (pos[1]+i) <= maxln
  486
+                    if prevfpath == s:GetFullPath(pos[1]+i)
  487
+                        let pos[1] += i
  488
+                        break
  489
+                    endif
  490
+                endif
  491
+                let i += 1
  492
+            endwhile
  493
+        endif
  494
+    endif
  495
+    call setpos('.',pos)
  496
+    redraw
  497
+endfunction
  498
+
  499
+function! s:Refresh(linen)
  500
+    let linen = s:GetDirLine(a:linen)
  501
+    if linen == 1
  502
+        call s:RefreshAll()
  503
+    else
  504
+        let line = getline(linen)
  505
+        if s:IsExpanded(line)
  506
+            let fpath = s:GetFullPath(linen)
  507
+            let pos = getpos('.')
  508
+            setlocal modifiable
  509
+            call s:UnexpandDir(fpath,linen)
  510
+            call s:ExpandDir(fpath,linen)
  511
+            setlocal nomodifiable
  512
+            call setpos('.',pos)
  513
+        endif
  514
+    endif
  515
+endfunction
  516
+
  517
+function! s:Find(linen, find)
  518
+    let linen = a:linen
  519
+    if linen == 2
  520
+        let linen = 1
  521
+    endif
  522
+    let fpath = s:GetFullPathDir(linen)
  523
+    let find = s:AskInputComplete('search in '.fpath.' for ',a:find,'file')
  524
+    if !empty(find)
  525
+        let b:find = find
  526
+        echo 'searching for '.find
  527
+        exe "let b:findresult = pyeval(\"easytree.EasyTreeFind(vim.eval('find'),vim.eval('fpath'),".b:showhidden.")\")"
  528
+        redraw
  529
+        if fpath != getline(1)
  530
+            let fpath = fpath[len(getline(1)):]
  531
+            if len(fpath) > 0 && fpath[0] == '/' 
  532
+                let fpath = fpath[1:]
  533
+            endif
  534
+            if len(fpath) > 0
  535
+                let b:findresult = map(b:findresult,"fpath.'/'.v:val")
  536
+            endif
  537
+        endif
  538
+        if !empty(b:findresult)
  539
+            echo ''
  540
+            let b:findindex = -1
  541
+            call s:FindNext()
  542
+        else
  543
+            echo 'no files found'
  544
+        endif
  545
+    endif
  546
+endfunction
  547
+
  548
+function! s:FindNext()
  549
+    if empty(b:findresult)
  550
+        echo 'no files found'
  551
+        return
  552
+    endif
  553
+    let b:findindex += 1
  554
+    if b:findindex >= len(b:findresult)
  555
+        let b:findindex = 0
  556
+    endif
  557
+    call s:FindFile()
  558
+endfunction
  559
+
  560
+function! s:FindBackward()
  561
+    if empty(b:findresult)
  562
+        echo 'no files found'
  563
+        return
  564
+    endif
  565
+    let b:findindex -= 1
  566
+    if b:findindex < 0
  567
+        let b:findindex = len(b:findresult)-1
  568
+    endif
  569
+    call s:FindFile()
  570
+endfunction
  571
+
  572
+function! s:FindFile()
  573
+    if line('$') > 2
  574
+        let find = b:findresult[b:findindex]
  575
+        let findf = getline(1).'/'.find
  576
+        let findp = split(find,'/')
  577
+        let lvl = 1
  578
+        let i = 3
  579
+        while line('$') >= i
  580
+            if s:GetLvl(getline(i)) == lvl
  581
+                let fpath = s:GetFullPath(i)
  582
+                if lvl == len(findp)
  583
+                    if fpath == findf 
  584
+                        let pos = getpos('.')
  585
+                        let pos[1] = i
  586
+                        let pos[2] = 1
  587
+                        call setpos('.',pos)
  588
+                        return
  589
+                    endif
  590
+                else
  591
+                    let findlvlf = getline(1).'/'.join(findp[:(lvl-1)],'/')
  592
+                    if fpath == findlvlf
  593
+                        call s:Expand(i)
  594
+                        let lvl += 1
  595
+                    endif
  596
+                endif
  597
+            endif
  598
+            let i += 1
  599
+        endwhile
  600
+    endif
  601
+endfunction
  602
+
  603
+function! s:EnterPressed()
  604
+    if line('.') > 2
  605
+        let fpath = s:GetFullPath(line('.'))
  606
+        let isdir = s:IsDir(getline('.'))
  607
+        if isdir
  608
+            setlocal modifiable
  609
+            if s:IsExpanded(getline('.'))
  610
+                call s:UnexpandDir(fpath,line('.'))            
  611
+                let b:expanded[fpath] = 0
  612
+            else
  613
+                call s:ExpandDir(fpath,line('.'))            
  614
+                let b:expanded[fpath] = 1
  615
+            endif
  616
+            setlocal nomodifiable
  617
+            redraw
  618
+            echo ''
  619
+        else
  620
+            " Open file
  621
+            call s:OpenFile(fpath,'edit')
  622
+        endif
  623
+    elseif line('.') == 2
  624
+        let fpath = s:GetFullPath(line('.'))
  625
+        let pos = getpos('.')
  626
+        call s:InitializeNewTree(fpath)
  627
+        call setpos('.',pos)
  628
+    endif
  629
+endfunction
  630
+
  631
+function! s:Expand(linen)
  632
+    if a:linen > 2
  633
+        let fpath = s:GetFullPath(a:linen)
  634
+        let isdir = s:IsDir(getline(a:linen))
  635
+        if isdir
  636
+            setlocal modifiable
  637
+            if !s:IsExpanded(getline(a:linen))
  638
+                call s:ExpandDir(fpath,a:linen)            
  639
+                let b:expanded[fpath] = 1
  640
+            endif
  641
+            setlocal nomodifiable
  642
+        endif
  643
+    endif
  644
+endfunction
  645
+
  646
+function! s:ExpandAll(linen)
  647
+    if a:linen > 2
  648
+        let lines = line('$')
  649
+        call s:Expand(a:linen)
  650
+        let lines = line('$') - lines
  651
+        if lines > 0
  652
+            let linesexpanded = -lines
  653
+            for i in range(1,lines)
  654
+                let linesexpanded += lines
  655
+                if s:IsDir(getline(a:linen+i+linesexpanded))
  656
+                    let lines = line('$')
  657
+                    call s:ExpandAll(a:linen+i+linesexpanded)
  658
+                    let lines = line('$') - lines
  659
+                else
  660
+                    let lines = 0
  661
+                endif
  662
+            endfor
  663
+        endif
  664
+    endif
  665
+endfunction
  666
+
  667
+function! s:Unexpand(linen)
  668
+    if a:linen > 2
  669
+        let fpath = s:GetFullPath(a:linen)
  670
+        let isdir = s:IsDir(getline(a:linen))
  671
+        if isdir
  672
+            setlocal modifiable
  673
+            if s:IsExpanded(getline(a:linen))
  674
+                call s:UnexpandDir(fpath,a:linen)            
  675
+                let b:expanded[fpath] = 0
  676
+            endif
  677
+            setlocal nomodifiable
  678
+        endif
  679
+    endif
  680
+endfunction
  681
+
  682
+function! s:UnexpandAll(linen)
  683
+    if a:linen > 2
  684
+        let fpath = s:GetFullPath(a:linen).'/'
  685
+        call s:Unexpand(a:linen)
  686
+        let b:expanded = filter(b:expanded,"!(v:key =~ '".fpath."')")
  687
+    endif
  688
+endfunction
  689
+
  690
+function! s:Open(linen)
  691
+    let fpath = s:GetFullPath(a:linen)
  692
+    call s:OpenFile(fpath,'edit')
  693
+endfunction
  694
+
  695
+function! s:SplitOpen(linen)
  696
+    let fpath = s:GetFullPath(a:linen)
  697
+    call s:OpenFile(fpath,'sp')
  698
+endfunction
  699
+
  700
+function! s:VerticlySplitOpen(linen)
  701
+    let fpath = s:GetFullPath(a:linen)
  702
+    call s:OpenFile(fpath,'vs')
  703
+endfunction
  704
+
  705
+function! s:OpenFile(fpath,mode)
  706
+    call s:OpenEasyTreeFile(b:location,a:fpath,a:mode)
  707
+endfunction
  708
+
  709
+function! s:UnexpandDir(fpath,linen)
  710
+    let linen = a:linen
  711
+    if g:easytree_use_plus_and_minus
  712
+        call setline(linen,substitute(getline(linen),'-','+',''))
  713
+    else
  714
+        call setline(linen,substitute(getline(linen),'▾','▸',''))
  715
+    endif
  716
+    let lvl = s:GetLvl(getline(linen))
  717
+    let linen += 1
  718
+    let linee = linen
  719
+    while s:GetLvl(getline(linee)) > lvl
  720
+        let linee += 1 
  721
+    endwhile
  722
+    let linee -= 1
  723
+    if linee != linen
  724
+        let linee = (linen-1).':'.linee
  725
+    else
  726
+        let linee -= 1
  727
+    endif
  728
+    exe 'python vim.current.buffer['.linee.'] = None'
  729
+    call s:WidthAutoFit()
  730
+endfunction
  731
+
  732
+function! s:ExpandDir(fpath,linen)
  733
+    redraw
  734
+    echo 'expanding '.a:fpath
  735
+    let linen = a:linen
  736
+    if g:easytree_use_plus_and_minus
  737
+        call setline(linen,substitute(getline(linen),'+','-',''))
  738
+    else
  739
+        call setline(linen,substitute(getline(linen),'▸','▾',''))
  740
+    endif
  741
+    let lvl = s:GetLvl(getline(linen))
  742
+    let lvls = repeat('  ',lvl) 
  743
+    let treelist = pyeval("easytree.EasyTreeListDir(vim.eval('a:fpath'),".b:showhidden.")")
  744
+    let cascade = g:easytree_cascade_open_single_dir && len(treelist[1]) == 1 && len(treelist[2]) == 0
  745
+    for d in treelist[1]
  746
+        if g:easytree_use_plus_and_minus
  747
+            call append(linen,lvls.'+ '.d)
  748
+        else
  749
+            call append(linen,lvls.'▸ '.d)
  750
+        endif
  751
+        let linen += 1
  752
+        let fpath = s:GetFullPath(linen)
  753
+        if (has_key(b:expanded,fpath) && b:expanded[fpath]) || cascade
  754
+            let linen = s:ExpandDir(fpath,linen)
  755
+        endif
  756
+    endfor
  757
+    for f in treelist[2]
  758
+        call append(linen,lvls.'  '.f)
  759
+        let linen += 1
  760
+    endfor
  761
+    call s:WidthAutoFit()
  762
+    return linen
  763
+endfunction
  764
+" }}}
  765
+
  766
+" easytree window functions {{{
  767
+function! s:InitializeTree(dir)
  768
+    setlocal modifiable
  769
+    let b:find = ''
  770
+    let b:findresult = []
  771
+    let treelist = pyeval("easytree.EasyTreeListDir(vim.eval('a:dir'),".b:showhidden.")")
  772
+    silent! normal! ggdGG
  773
+    call setline(1, treelist[0])
  774
+    call append(1, '  .. (up a dir)')
  775
+    for d in treelist[1]
  776
+        if g:easytree_use_plus_and_minus
  777
+            call append(line('$'),'+ '.d)
  778
+        else
  779
+            call append(line('$'),'▸ '.d)
  780
+        endif
  781
+    endfor
  782
+    for f in treelist[2]
  783
+        call append(line('$'),'  '.f)
  784
+    endfor
  785
+    setlocal nomodifiable
  786
+    call s:WidthAutoFit()
  787
+endfunction
  788
+
  789
+function! s:InitializeNewTree(dir)
  790
+    let dir = a:dir
  791
+    if dir != '/' && dir[len(dir)-1] == '/'
  792
+        let dir = dir[:-2]
  793
+    endif
  794
+    setlocal modifiable
  795
+    normal! ggdG
  796
+    call setline(1,dir)
  797
+    setlocal nomodifiable
  798
+    let b:showhidden = g:easytree_show_hidden_files 
  799
+    let b:ignore_files = g:easytree_ignore_files
  800
+    let b:ignore_dirs = g:easytree_ignore_dirs
  801
+    let b:ignore_find_result = g:easytree_ignore_find_result
  802
+    if !(g:easytree_auto_load_settings && s:LoadSetting(dir))
  803
+        let b:expanded = {}
  804
+    endif
  805
+    call s:RefreshAll()
  806
+endfunction
  807
+
  808
+function! s:WidthAutoFit()
  809
+    if g:easytree_width_auto_fit
  810
+        let m = max(map(range(1,line('$')),"len(getline(v:val))"))+1
  811
+        if m > winwidth(0)
  812
+            exe 'vertical resize '.m
  813
+        endif
  814
+    endif
  815
+endfunction
  816
+
  817
+function! s:OpenEasyTreeFile(location,fpath,mode)
  818
+    let fpath = fnameescape(a:fpath)
  819
+    let wincreated = 0
  820
+    if winnr('$') == 1
  821
+        if a:location == 'left'
  822
+            wincmd v
  823
+            exe 'vertical resize '.(&columns/6)
  824
+        elseif a:location == 'right'
  825
+            wincmd v
  826
+            wincmd l
  827
+            exe 'vertical resize '.(&columns/6)
  828
+        elseif a:location == 'top'
  829
+            wincmd s
  830
+            exe 'resize '.(&lines/3)
  831
+        elseif a:location == 'bottom'
  832
+            wincmd s
  833
+            wincmd j
  834
+            exe 'resize '.(&lines/3)
  835
+        endif
  836
+        let wincreated = 1
  837
+    endif
  838
+    if a:location == 'left'
  839
+        wincmd l
  840
+    elseif a:location == 'right'
  841
+        wincmd h
  842
+    elseif a:location == 'top'
  843
+        wincmd j
  844
+    elseif a:location == 'bottom'
  845
+        wincmd k
  846
+    endif
  847
+    if !empty(&buftype) && a:mode == 'edit' && a:location != 'here' && !wincreated
  848
+        " find windows with file buffer
  849
+        let wnrs = filter(range(1,winnr('$')),"empty(getbufvar(winbufnr(v:val),'&buftype'))") 
  850
+        if len(wnrs) > 0
  851
+            let wnr = winnr()
  852
+            wincmd k
  853
+            if !(winnr() != wnr && index(wnrs,winnr()) != -1)
  854
+                exe wnr.'wincmd w'                
  855
+                wincmd j
  856
+                if !(winnr() != wnr && index(wnrs,winnr()) != -1)
  857
+                    exe wnrs[0].'wincmd w'
  858
+                endif
  859
+            endif
  860
+        else
  861
+            wincmd s
  862
+        endif
  863
+    endif
  864
+    stopinsert
  865
+    if a:mode == 'edit'
  866
+        exe a:mode.' '.fpath
  867
+    elseif a:mode == 'sp'
  868
+        if a:location == 'here' || a:location == 'left' || a:location == 'right' || a:location == 'top'
  869
+            wincmd s
  870
+            exe 'edit '.fpath
  871
+        elseif a:location == 'bottom'
  872
+            wincmd s
  873
+            wincmd j
  874
+            exe 'edit '.fpath
  875
+        endif
  876
+    elseif a:mode == 'vs'
  877
+        if a:location == 'here' || a:location == 'left' || a:location == 'top' || a:location == 'bottom'
  878
+            wincmd v
  879
+            exe 'edit '.fpath
  880
+        elseif a:location == 'right'
  881
+            wincmd v
  882
+            wincmd l
  883
+            exe 'edit '.fpath
  884
+        endif
  885
+    endif
  886
+endfunction
  887
+
  888
+function! s:GetNewEasyTreeWindowId()
  889
+    let id = 1
  890
+    for t in filter(range(1,bufnr('$')),"getbufvar(v:val,'&filetype') == 'easytree'")
  891
+        if getbufvar(t,'treeid') >= id
  892
+            let id = getbufvar(t,'treeid')+1
  893
+        endif
  894
+    endfor
  895
+    return id
  896
+endfunction
  897
+
  898
+function! s:GetInfo(linen)
  899
+    let fpath = s:GetFullPath(a:linen)
  900
+    let info = pyeval('easytree.EasyTreeGetInfo()')
  901
+    echo 'name: '.info[0].'  owner: '.info[1].':'.info[2].'  size: '.info[3].'  mode: '.info[4].'  last modified: '.info[5]
  902
+    if pyeval('easytree.easytree_dirsize_calculator != None')
  903
+        while 1
  904
+            sleep 1
  905
+            let info[3] = pyeval("easytree.EasyTreeGetSize(easytree.easytree_dirsize_calculator_curr_size)+(('.'*random.randint(1,3)).ljust(3))")
  906
+            redraw
  907
+            echo 'name: '.info[0].'  owner: '.info[1].':'.info[2].'  size: '.info[3].'  mode: '.info[4].'  last modified: '.info[5]
  908
+            if !pyeval('easytree.easytree_dirsize_calculator.isAlive()')
  909
+                let info[3] = pyeval("easytree.EasyTreeGetSize(easytree.easytree_dirsize_calculator_curr_size)")
  910
+                python easytree.easytree_dirsize_calculator = None
  911
+                break
  912
+            endif
  913
+        endwhile
  914
+    endif
  915
+    redraw
  916
+    echo 'name: '.info[0].'  owner: '.info[1].':'.info[2].'  size: '.info[3].'  mode: '.info[4].'  last modified: '.info[5]
  917
+endfunction
  918
+
  919
+function! s:OpenEasyTreeWindow(location)
  920
+    let treeid = s:GetNewEasyTreeWindowId()
  921
+    let treename = fnameescape('easytree - '.treeid)
  922
+    let location = a:location
  923
+    if a:location == 'left'
  924
+        exe 'topleft '.(&columns/6).'vs '.treename
  925
+    elseif a:location == 'right'
  926
+        exe 'botright '.(&columns/6).'vs '.treename
  927
+    elseif a:location == 'top'
  928
+        exe 'topleft '.(&lines/3).'sp '.treename
  929
+    elseif a:location == 'bottom'
  930
+        exe 'botright '.(&lines/3).'sp '.treename