diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 73e8c85e..201f73cd 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -3,18 +3,18 @@ Search existing issues and check the FAQ. Make sure that you have the latest version of LeaderF. --> -- vim or neovim? +- vim or neovim? - [ ] vim - [ ] neovim -- `vim --version` or `nvim --version`: - +- Output of `vim --version` or `nvim --version`: - Output of `:echo has("python")`: - Output of `:echo has("python3")`: - Output of `:echo &pythondll`(only vim, not neovim): - Output of `:echo &pythonthreedll`(only vim, not neovim): - Output of `:py print(sys.version)`: - Output of `:py3 print(sys.version)`: -- Operating system: +- Output of `:echo g:Lf_Debug_Cmd`: +- Operating system: - [ ] Linux - [ ] Mac OS X - [ ] Windows diff --git a/autoload/leaderf.vim b/autoload/leaderf.vim index df7e1395..37946750 100644 --- a/autoload/leaderf.vim +++ b/autoload/leaderf.vim @@ -7,10 +7,209 @@ " License: Apache License, Version 2.0 " ============================================================================ +if exists('g:leaderf#loaded') + finish +else + let g:leaderf#loaded = 1 +endif + +if !exists("g:Lf_PythonVersion") + if has("python3") + let g:Lf_PythonVersion = 3 + let g:Lf_py = "py3 " + elseif has("python") + let g:Lf_PythonVersion = 2 + let g:Lf_py = "py " + else + echohl Error + echo "Error: LeaderF requires vim compiled with +python or +python3" + echohl None + finish + endif +else + if g:Lf_PythonVersion == 2 + if has("python") + let g:Lf_py = "py " + else + echohl Error + echo 'LeaderF Error: has("python") == 0' + echohl None + finish + endif + else + if has("python3") + let g:Lf_py = "py3 " + else + echohl Error + echo 'LeaderF Error: has("python3") == 0' + echohl None + finish + endif + endif +endif + exec g:Lf_py "import vim, sys, os.path" exec g:Lf_py "cwd = vim.eval('expand(\":p:h\")')" exec g:Lf_py "sys.path.insert(0, os.path.join(cwd, 'leaderf', 'python'))" +function! s:InitVar(var, value) + if !exists(a:var) + exec 'let '.a:var.'='.string(a:value) + endif +endfunction + +function! s:InitDict(var, dict) + if !exists(a:var) + exec 'let '.a:var.'='.string(a:dict) + else + let tmp = a:dict + for [key, value] in items(eval(a:var)) + let tmp[key] = value + endfor + exec 'let '.a:var.'='.string(tmp) + endif +endfunction + +call s:InitVar('g:Lf_WindowHeight', '0.5') +call s:InitVar('g:Lf_TabpagePosition', 2) +call s:InitVar('g:Lf_ShowRelativePath', 1) +call s:InitVar('g:Lf_DefaultMode', 'NameOnly') +call s:InitVar('g:Lf_CursorBlink', 1) +call s:InitVar('g:Lf_NeedCacheTime', '1.5') +call s:InitVar('g:Lf_NumberOfCache', 5) +call s:InitVar('g:Lf_UseMemoryCache', 1) +call s:InitVar('g:Lf_IndexTimeLimit', 120) +call s:InitVar('g:Lf_FollowLinks', 0) +call s:InitVar('g:Lf_DelimiterChar', ';') +call s:InitVar('g:Lf_MruFileExclude', []) +call s:InitVar('g:Lf_MruMaxFiles', 100) +call s:InitVar('g:Lf_HighlightIndividual', 1) +call s:InitVar('g:Lf_NumberOfHighlight', 100) +call s:InitVar('g:Lf_WildIgnore', { + \ 'dir': [], + \ 'file': [] + \}) +call s:InitVar('g:Lf_MruWildIgnore', { + \ 'dir': [], + \ 'file': [] + \}) +if &encoding ==? "utf-8" + call s:InitVar('g:Lf_StlSeparator', { + \ 'left': '►', + \ 'right': '◄', + \ 'font': '' + \}) +else + call s:InitVar('g:Lf_StlSeparator', { + \ 'left': '', + \ 'right': '', + \ 'font': '' + \}) +endif +call s:InitVar('g:Lf_StlPalette', {}) +call s:InitVar('g:Lf_Ctags', 'ctags') +call s:InitVar('g:Lf_PreviewCode', 0) +call s:InitVar('g:Lf_UseVersionControlTool', 1) +call s:InitVar('g:Lf_RememberLastSearch', 0) +call s:InitVar('g:Lf_UseCache', 1) +call s:InitVar('g:Lf_RootMarkers', ['.git', '.hg', '.svn']) +call s:InitVar('g:Lf_WorkingDirectoryMode', 'c') +call s:InitVar('g:Lf_ShowHidden', 0) +call s:InitDict('g:Lf_PreviewResult', { + \ 'File': 0, + \ 'Buffer': 0, + \ 'Mru': 0, + \ 'Tag': 0, + \ 'BufTag': 1, + \ 'Function': 1, + \ 'Line': 0, + \ 'Colorscheme': 0 + \}) +call s:InitDict('g:Lf_NormalMap', {}) +call s:InitVar('g:Lf_Extensions', {}) + +let s:Lf_CommandMap = { + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': ['', ''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': ['', ''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': ['', ''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '': [''], + \ '<2-LeftMouse>': ['<2-LeftMouse>'], + \ '': [''], + \ '': [''] + \} + +function! s:InitCommandMap(var, dict) + if !exists(a:var) + exec 'let '.a:var.'='.string(a:dict) + else + let tmp = a:dict + for [key, value] in items(eval(a:var)) + call filter(tmp, 'v:key !=? key') + for i in value + if index(['', ''], toupper(i)) >= 0 + call filter(tmp, "v:key != ''") + endif + call filter(tmp, '!empty(filter(tmp[v:key], "v:val !=? i"))') + endfor + let tmp[toupper(key)] = map(value, 'toupper(v:val)') + endfor + exec 'let '.a:var.'='.string(tmp) + endif +endfunction + +call s:InitCommandMap('g:Lf_CommandMap', s:Lf_CommandMap) + function! leaderf#versionCheck() if g:Lf_PythonVersion == 2 && pyeval("sys.version_info < (2, 7)") echohl Error diff --git a/autoload/leaderf/BufTag.vim b/autoload/leaderf/BufTag.vim index bb1c5dc9..05eff683 100644 --- a/autoload/leaderf/BufTag.vim +++ b/autoload/leaderf/BufTag.vim @@ -11,8 +11,6 @@ if leaderf#versionCheck() == 0 " this check is necessary finish endif -let g:Lf_bufTagExpl_loaded = 1 - exec g:Lf_py "from leaderf.bufTagExpl import *" function! leaderf#BufTag#Maps() diff --git a/autoload/leaderf/File.vim b/autoload/leaderf/File.vim index 8eb5c710..68bad828 100644 --- a/autoload/leaderf/File.vim +++ b/autoload/leaderf/File.vim @@ -11,8 +11,6 @@ if leaderf#versionCheck() == 0 " this check is necessary finish endif -let g:Lf_fileExpl_loaded = 1 - exec g:Lf_py "from leaderf.fileExpl import *" function! leaderf#File#Maps() diff --git a/autoload/leaderf/Function.vim b/autoload/leaderf/Function.vim index 8fe57477..2b75c844 100644 --- a/autoload/leaderf/Function.vim +++ b/autoload/leaderf/Function.vim @@ -11,8 +11,6 @@ if leaderf#versionCheck() == 0 " this check is necessary finish endif -let g:Lf_functionExpl_loaded = 1 - exec g:Lf_py "from leaderf.functionExpl import *" function! leaderf#Function#Maps() diff --git a/autoload/leaderf/python/leaderf/bufExpl.py b/autoload/leaderf/python/leaderf/bufExpl.py index 75db7d7b..f2135e80 100644 --- a/autoload/leaderf/python/leaderf/bufExpl.py +++ b/autoload/leaderf/python/leaderf/bufExpl.py @@ -21,6 +21,14 @@ def __init__(self): self._max_bufname_len = 0 def getContent(self, *args, **kwargs): + mru_bufnrs = [] + for num in reversed(lfEval("g:Lf_MruBufnrs")): + if num not in mru_bufnrs: + mru_bufnrs.append(int(num)) + for num in reversed(mru_bufnrs): + mru.setBufferTimestamp(num) + lfCmd("let g:Lf_MruBufnrs = []") + if "--all" not in kwargs.get("arguments", {}): if "--tabpage" not in kwargs.get("arguments", {}): buffers = {b.number: b for b in vim.buffers diff --git a/autoload/leaderf/python/leaderf/mru.py b/autoload/leaderf/python/leaderf/mru.py index e1ccf14a..b4822fec 100644 --- a/autoload/leaderf/python/leaderf/mru.py +++ b/autoload/leaderf/python/leaderf/mru.py @@ -36,7 +36,6 @@ def getCacheFileName(self): def normalize(self, name): if '~' in name: name = os.path.expanduser(name) - name = os.path.abspath(name) if sys.platform[:3] == 'win': if name[:4] == '\\\\?\\' and os.path.isabs(name): if os.path.isabs(name[4:]) and name[5:6] == ':': @@ -48,29 +47,37 @@ def normalize(self, name): name = name[:11].lower() + name[11:] return name - def saveToCache(self, buf_name): - buf_name = self.normalize(buf_name) - if True in (fnmatch.fnmatch(buf_name, i) - for i in lfEval("g:Lf_MruFileExclude")): + def saveToCache(self, buf_name_list): + buf_names = [] + for name in buf_name_list: + name = self.normalize(name) + if True in (fnmatch.fnmatch(name, i) + for i in lfEval("g:Lf_MruFileExclude")): + continue + buf_names.append(name) + + if not buf_names: return - nocase = False - compare = buf_name - if sys.platform[:3] == 'win' or sys.platform in ('cygwin', 'msys'): - nocase = True - compare = buf_name.lower() + with lfOpen(self._cache_file, 'r+', errors='ignore') as f: lines = f.readlines() - for i, line in enumerate(lines): - text = line.rstrip() - if (compare == text) or (nocase and compare == text.lower()): - if i == 0: - return - del lines[i] - break - - lines.insert(0, buf_name + '\n') - if len(lines) > int(lfEval("g:Lf_MruMaxFiles")): - del lines[-1] + for name in buf_names: + nocase = False + compare = name + if sys.platform[:3] == 'win' or sys.platform in ('cygwin', 'msys'): + nocase = True + compare = name.lower() + + for i, line in enumerate(lines): + text = line.rstrip() + if (compare == text) or (nocase and compare == text.lower()): + del lines[i] + break + + lines = [name + '\n' for name in buf_names] + lines + max_files = int(lfEval("g:Lf_MruMaxFiles")) + if len(lines) > max_files: + del lines[max_files:] f.seek(0) f.truncate(0) f.writelines(lines) diff --git a/autoload/leaderf/python/leaderf/mruExpl.py b/autoload/leaderf/python/leaderf/mruExpl.py index 5ba84ba6..c966ad9c 100644 --- a/autoload/leaderf/python/leaderf/mruExpl.py +++ b/autoload/leaderf/python/leaderf/mruExpl.py @@ -20,6 +20,9 @@ def __init__(self): self._max_bufname_len = 0 def getContent(self, *args, **kwargs): + mru.saveToCache(lfEval("readfile(g:Lf_MruCacheFileName)")) + lfCmd("call writefile([], g:Lf_MruCacheFileName)") + with lfOpen(mru.getCacheFileName(), 'r+', errors='ignore') as f: lines = f.readlines() lines = [name for name in lines if os.path.exists(lfDecode(name.rstrip()))] @@ -81,6 +84,7 @@ def getPrefixLength(self): def getMaxBufnameLen(self): return self._max_bufname_len + #***************************************************** # MruExplManager #***************************************************** @@ -187,14 +191,13 @@ def deleteMru(self): line = vim.current.line dirname = self._getDigest(line, 2) basename = self._getDigest(line, 1) - self._explorer.delFromCache(escSpecial(dirname + basename)) + self._explorer.delFromCache(dirname + basename) if len(self._content) > 0: self._content.remove(line) del vim.current.line lfCmd("setlocal nomodifiable") - #***************************************************** # mruExplManager is a singleton #***************************************************** diff --git a/autoload/lfMru.vim b/autoload/lfMru.vim index 1a64ad3a..1d142b29 100644 --- a/autoload/lfMru.vim +++ b/autoload/lfMru.vim @@ -7,19 +7,35 @@ " License: Apache License, Version 2.0 " ============================================================================ -exec g:Lf_py "import vim, sys, os.path" -exec g:Lf_py "cwd = vim.eval('expand(\":p:h\")')" -exec g:Lf_py "sys.path.insert(0, os.path.join(cwd, 'leaderf', 'python'))" -exec g:Lf_py "from leaderf.mru import *" +let g:Lf_CacheDirectory = substitute(g:Lf_CacheDirectory, '[\/]$', '', '') + +if !isdirectory(g:Lf_CacheDirectory) + call mkdir(g:Lf_CacheDirectory, "p") +endif + +if !isdirectory(g:Lf_CacheDirectory . '/.LfCache') + call mkdir(g:Lf_CacheDirectory . '/.LfCache', "p") +endif + +let g:Lf_MruCacheFileName = g:Lf_CacheDirectory . '/.LfCache/tempMru' + +if !filereadable(g:Lf_MruCacheFileName) + call writefile([], g:Lf_MruCacheFileName) +endif function! lfMru#record(name) if a:name == '' || !filereadable(a:name) return endif - - exec g:Lf_py 'mru.saveToCache(r"""'.a:name.'""")' + let file_list = readfile(g:Lf_MruCacheFileName) + if empty(file_list) + call writefile([a:name], g:Lf_MruCacheFileName) + elseif a:name != file_list[0] + call filter(file_list, 'v:val != a:name') + call writefile([a:name] + file_list, g:Lf_MruCacheFileName) + endif endfunction function! lfMru#recordBuffer(bufNum) - exec g:Lf_py 'mru.setBufferTimestamp('.a:bufNum.')' + call add(g:Lf_MruBufnrs, a:bufNum) endfunction diff --git a/plugin/leaderf.vim b/plugin/leaderf.vim index 97f30216..67a81464 100644 --- a/plugin/leaderf.vim +++ b/plugin/leaderf.vim @@ -18,58 +18,17 @@ else let g:leaderf_loaded = 1 endif -if !exists("g:Lf_PythonVersion") - if has("python3") - let g:Lf_PythonVersion = 3 - let g:Lf_py = "py3 " - elseif has("python") - let g:Lf_PythonVersion = 2 - let g:Lf_py = "py " - else - echohl Error - echo "Error: LeaderF requires vim compiled with +python or +python3" - echohl None - finish - endif -else - if g:Lf_PythonVersion == 2 - if has("python") - let g:Lf_py = "py " - else - echohl Error - echo 'LeaderF Error: has("python") == 0' - echohl None - finish - endif - else - if has("python3") - let g:Lf_py = "py3 " - else - echohl Error - echo 'LeaderF Error: has("python3") == 0' - echohl None - finish - endif - endif -endif - function! s:InitVar(var, value) if !exists(a:var) exec 'let '.a:var.'='.string(a:value) endif endfunction -function! s:InitDict(var, dict) - if !exists(a:var) - exec 'let '.a:var.'='.string(a:dict) - else - let tmp = a:dict - for [key, value] in items(eval(a:var)) - let tmp[key] = value - endfor - exec 'let '.a:var.'='.string(tmp) - endif -endfunction +call s:InitVar('g:Lf_ShortcutF', 'f') +call s:InitVar('g:Lf_ShortcutB', 'b') +call s:InitVar('g:Lf_WindowPosition', 'bottom') +call s:InitVar('g:Lf_CacheDirectory', $HOME) +call s:InitVar('g:Lf_MruBufnrs', []) function! g:LfNoErrMsgMatch(expr, pat) try @@ -94,151 +53,6 @@ function! g:LfRegisterSelf(cmd, description) let g:Lf_SelfContent[a:cmd] = a:description endfunction -call s:InitVar('g:Lf_ShortcutF', 'f') -call s:InitVar('g:Lf_ShortcutB', 'b') -call s:InitVar('g:Lf_WindowPosition', 'bottom') -call s:InitVar('g:Lf_WindowHeight', '0.5') -call s:InitVar('g:Lf_TabpagePosition', 2) -call s:InitVar('g:Lf_ShowRelativePath', 1) -call s:InitVar('g:Lf_DefaultMode', 'NameOnly') -call s:InitVar('g:Lf_CursorBlink', 1) -call s:InitVar('g:Lf_CacheDirectory', $HOME) -call s:InitVar('g:Lf_NeedCacheTime', '1.5') -call s:InitVar('g:Lf_NumberOfCache', 5) -call s:InitVar('g:Lf_UseMemoryCache', 1) -call s:InitVar('g:Lf_IndexTimeLimit', 120) -call s:InitVar('g:Lf_FollowLinks', 0) -call s:InitVar('g:Lf_DelimiterChar', ';') -call s:InitVar('g:Lf_MruFileExclude', []) -call s:InitVar('g:Lf_MruMaxFiles', 100) -call s:InitVar('g:Lf_HighlightIndividual', 1) -call s:InitVar('g:Lf_NumberOfHighlight', 100) -call s:InitVar('g:Lf_WildIgnore', { - \ 'dir': [], - \ 'file': [] - \}) -call s:InitVar('g:Lf_MruWildIgnore', { - \ 'dir': [], - \ 'file': [] - \}) -if &encoding ==? "utf-8" - call s:InitVar('g:Lf_StlSeparator', { - \ 'left': '►', - \ 'right': '◄', - \ 'font': '' - \}) -else - call s:InitVar('g:Lf_StlSeparator', { - \ 'left': '', - \ 'right': '', - \ 'font': '' - \}) -endif -call s:InitVar('g:Lf_StlPalette', {}) -call s:InitVar('g:Lf_Ctags', 'ctags') -call s:InitVar('g:Lf_PreviewCode', 0) -call s:InitVar('g:Lf_UseVersionControlTool', 1) -call s:InitVar('g:Lf_RememberLastSearch', 0) -call s:InitVar('g:Lf_UseCache', 1) -call s:InitVar('g:Lf_RootMarkers', ['.git', '.hg', '.svn']) -call s:InitVar('g:Lf_WorkingDirectoryMode', 'c') -call s:InitVar('g:Lf_ShowHidden', 0) -call s:InitDict('g:Lf_PreviewResult', { - \ 'File': 0, - \ 'Buffer': 0, - \ 'Mru': 0, - \ 'Tag': 0, - \ 'BufTag': 1, - \ 'Function': 1, - \ 'Line': 0, - \ 'Colorscheme': 0 - \}) -call s:InitDict('g:Lf_NormalMap', {}) -call s:InitVar('g:Lf_Extensions', {}) - -let s:Lf_CommandMap = { - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': ['', ''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': ['', ''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': ['', ''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '': [''], - \ '<2-LeftMouse>': ['<2-LeftMouse>'], - \ '': [''], - \ '': [''] - \} - -function! s:InitCommandMap(var, dict) - if !exists(a:var) - exec 'let '.a:var.'='.string(a:dict) - else - let tmp = a:dict - for [key, value] in items(eval(a:var)) - call filter(tmp, 'v:key !=? key') - for i in value - if index(['', ''], toupper(i)) >= 0 - call filter(tmp, "v:key != ''") - endif - call filter(tmp, '!empty(filter(tmp[v:key], "v:val !=? i"))') - endfor - let tmp[toupper(key)] = map(value, 'toupper(v:val)') - endfor - exec 'let '.a:var.'='.string(tmp) - endif -endfunction - -call s:InitCommandMap('g:Lf_CommandMap', s:Lf_CommandMap) - - augroup LeaderF_Mru autocmd BufAdd,BufEnter,BufWritePost * call lfMru#record(expand(':p')) | \ call lfMru#recordBuffer(expand(''))