mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-02 23:40:06 +08:00
Add lua projectmanager (#4401)
This commit is contained in:
parent
7b4ae22d45
commit
b518b77e49
@ -3,7 +3,14 @@
|
|||||||
"alternate": "test/api/{}.vader",
|
"alternate": "test/api/{}.vader",
|
||||||
"doc": "docs/api/{}.md"
|
"doc": "docs/api/{}.md"
|
||||||
},
|
},
|
||||||
"autoload/SpaceVim/plugins/a.vim": { "alternate": "test/plugin/a.vader" },
|
"autoload/SpaceVim/plugins/a.vim": {
|
||||||
|
"alternate": "test/plugin/a.vader",
|
||||||
|
"lua" : "lua/spacevim/plugin/a.lua"
|
||||||
|
},
|
||||||
|
"lua/spacevim/plugin/a.lua": {
|
||||||
|
"alternate": "test/lua/plugin/a.vader",
|
||||||
|
"vim" : "autoload/SpaceVim/plugins/a.vim"
|
||||||
|
},
|
||||||
"test/plugin/a.vader": { "alternate": "autoload/SpaceVim/plugins/a.vim" },
|
"test/plugin/a.vader": { "alternate": "autoload/SpaceVim/plugins/a.vim" },
|
||||||
"autoload/SpaceVim/layers/lang/*.vim": { "doc": "docs/layers/lang/{}.md" },
|
"autoload/SpaceVim/layers/lang/*.vim": { "doc": "docs/layers/lang/{}.md" },
|
||||||
"test/api/*.vader": { "alternate": "autoload/SpaceVim/api/{}.vim" },
|
"test/api/*.vader": { "alternate": "autoload/SpaceVim/api/{}.vim" },
|
||||||
|
@ -233,25 +233,16 @@ let s:file['updateFiles'] = function('s:updatefiles')
|
|||||||
" 2. if it is a dir, end with /
|
" 2. if it is a dir, end with /
|
||||||
" 3. if a:path end with /, then return path also end with /
|
" 3. if a:path end with /, then return path also end with /
|
||||||
function! s:unify_path(path, ...) abort
|
function! s:unify_path(path, ...) abort
|
||||||
call SpaceVim#logger#info('a:path is :' . a:path)
|
if empty(a:path)
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
let mod = a:0 > 0 ? a:1 : ':p'
|
let mod = a:0 > 0 ? a:1 : ':p'
|
||||||
let path = fnamemodify(a:path, mod . ':gs?[\\/]?/?')
|
let path = fnamemodify(a:path, mod . ':gs?[\\/]?/?')
|
||||||
call SpaceVim#logger#info('a:path is :' . a:path)
|
|
||||||
call SpaceVim#logger#info('path is :' . path)
|
|
||||||
if isdirectory(path) && path[-1:] !=# '/'
|
if isdirectory(path) && path[-1:] !=# '/'
|
||||||
call SpaceVim#logger#info('case one')
|
|
||||||
call SpaceVim#logger#info('a:path is :' . a:path)
|
|
||||||
call SpaceVim#logger#info('path is :' . path)
|
|
||||||
return path . '/'
|
return path . '/'
|
||||||
elseif a:path[-1:] ==# '/' && path[-1:] !=# '/'
|
elseif a:path[-1:] ==# '/' && path[-1:] !=# '/'
|
||||||
call SpaceVim#logger#info('case two')
|
|
||||||
call SpaceVim#logger#info('a:path is :' . a:path)
|
|
||||||
call SpaceVim#logger#info('path is :' . path)
|
|
||||||
return path . '/'
|
return path . '/'
|
||||||
else
|
else
|
||||||
call SpaceVim#logger#info('case three')
|
|
||||||
call SpaceVim#logger#info('a:path is :' . a:path)
|
|
||||||
call SpaceVim#logger#info('path is :' . path)
|
|
||||||
return path
|
return path
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -6,323 +6,366 @@
|
|||||||
" License: GPLv3
|
" License: GPLv3
|
||||||
"=============================================================================
|
"=============================================================================
|
||||||
|
|
||||||
" project item:
|
|
||||||
" {
|
|
||||||
" "path" : "path/to/root",
|
|
||||||
" "name" : "name of the project, by default it is name of root directory",
|
|
||||||
" "type" : "git maven or svn",
|
|
||||||
" }
|
|
||||||
"
|
|
||||||
|
|
||||||
let s:BUFFER = SpaceVim#api#import('vim#buffer')
|
|
||||||
let s:FILE = SpaceVim#api#import('file')
|
|
||||||
" the name projectmanager is too long
|
|
||||||
" use rooter instead
|
|
||||||
let s:LOGGER =SpaceVim#logger#derive('rooter')
|
|
||||||
let s:TIME = SpaceVim#api#import('time')
|
|
||||||
let s:JSON = SpaceVim#api#import('data#json')
|
|
||||||
let s:LIST = SpaceVim#api#import('data#list')
|
|
||||||
let s:VIM = SpaceVim#api#import('vim')
|
|
||||||
|
|
||||||
function! s:update_rooter_patterns() abort
|
|
||||||
let s:project_rooter_patterns = filter(copy(g:spacevim_project_rooter_patterns), 'v:val !~# "^!"')
|
|
||||||
let s:project_rooter_ignores = map(filter(copy(g:spacevim_project_rooter_patterns), 'v:val =~# "^!"'), 'v:val[1:]')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:is_ignored_dir(dir) abort
|
|
||||||
return len(filter(copy(s:project_rooter_ignores), 'a:dir =~# v:val')) > 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
||||||
call add(g:spacevim_project_rooter_patterns, '.SpaceVim.d/')
|
if $SPACEVIM_LUA
|
||||||
let s:spacevim_project_rooter_patterns = copy(g:spacevim_project_rooter_patterns)
|
function! SpaceVim#plugins#projectmanager#complete_project(ArgLead, CmdLine, CursorPos) abort
|
||||||
call s:update_rooter_patterns()
|
return luaeval('require("spacevim.plugin.projectmanager").complete('
|
||||||
|
\ .'require("spacevim").eval("a:ArgLead"),'
|
||||||
let s:project_paths = {}
|
\ .'require("spacevim").eval("a:CmdLine"),'
|
||||||
let s:project_cache_path = s:FILE.unify_path(g:spacevim_data_dir, ':p') . 'SpaceVim/projects.json'
|
\ .'require("spacevim").eval("a:CursorPos"))')
|
||||||
|
endfunction
|
||||||
function! s:cache() abort
|
function! SpaceVim#plugins#projectmanager#OpenProject(p) abort
|
||||||
call writefile([s:JSON.json_encode(s:project_paths)], s:FILE.unify_path(s:project_cache_path, ':p'))
|
lua require("spacevim.plugin.projectmanager").OpenProject(
|
||||||
endfunction
|
\ require("spacevim").eval("a:p")
|
||||||
|
|
||||||
function! s:load_cache() abort
|
|
||||||
if filereadable(s:project_cache_path)
|
|
||||||
call s:LOGGER.info('Load projects cache from: ' . s:project_cache_path)
|
|
||||||
let cache_context = join(readfile(s:project_cache_path, ''), '')
|
|
||||||
if !empty(cache_context)
|
|
||||||
let cache_object = s:JSON.json_decode(cache_context)
|
|
||||||
if s:VIM.is_dict(cache_object)
|
|
||||||
let s:project_paths = filter(cache_object, '!empty(v:key)')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call s:LOGGER.info('projects cache file does not exists!')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
if g:spacevim_enable_projects_cache
|
|
||||||
call s:load_cache()
|
|
||||||
endif
|
|
||||||
|
|
||||||
let g:unite_source_menu_menus =
|
|
||||||
\ get(g:,'unite_source_menu_menus',{})
|
|
||||||
let g:unite_source_menu_menus.Projects = {'description':
|
|
||||||
\ 'Custom mapped keyboard shortcuts [SPC] p p'}
|
|
||||||
let g:unite_source_menu_menus.Projects.command_candidates =
|
|
||||||
\ get(g:unite_source_menu_menus.Projects,'command_candidates', [])
|
|
||||||
|
|
||||||
function! s:cache_project(prj) abort
|
|
||||||
let s:project_paths[a:prj.path] = a:prj
|
|
||||||
let g:unite_source_menu_menus.Projects.command_candidates = []
|
|
||||||
for key in s:sort_by_opened_time()
|
|
||||||
let desc = '[' . s:project_paths[key].name . '] ' . s:project_paths[key].path . ' <' . strftime('%Y-%m-%d %T', s:project_paths[key].opened_time) . '>'
|
|
||||||
let cmd = "call SpaceVim#plugins#projectmanager#open('" . s:project_paths[key].path . "')"
|
|
||||||
call add(g:unite_source_menu_menus.Projects.command_candidates, [desc,cmd])
|
|
||||||
endfor
|
|
||||||
if g:spacevim_enable_projects_cache
|
|
||||||
call s:cache()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" sort projects based on opened_time, and remove extra projects based on
|
|
||||||
" projects_cache_num
|
|
||||||
function! s:sort_by_opened_time() abort
|
|
||||||
let paths = keys(s:project_paths)
|
|
||||||
let paths = sort(paths, function('s:compare_time'))
|
|
||||||
if g:spacevim_projects_cache_num > 0 && s:LIST.has_index(paths, g:spacevim_projects_cache_num)
|
|
||||||
for path in paths[g:spacevim_projects_cache_num :]
|
|
||||||
call remove(s:project_paths, path)
|
|
||||||
endfor
|
|
||||||
let paths = paths[:g:spacevim_projects_cache_num - 1]
|
|
||||||
endif
|
|
||||||
return paths
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:compare_time(d1, d2) abort
|
|
||||||
let proj1 = get(s:project_paths, a:d1, {})
|
|
||||||
let proj1time = get(proj1, 'opened_time', 0)
|
|
||||||
let proj2 = get(s:project_paths, a:d2, {})
|
|
||||||
let proj2time = get(proj2, 'opened_time', 0)
|
|
||||||
return proj2time - proj1time
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
||||||
" this function will use fuzzy find layer, now only denite and unite are
|
|
||||||
" supported.
|
|
||||||
|
|
||||||
function! SpaceVim#plugins#projectmanager#list() abort
|
|
||||||
if SpaceVim#layers#isLoaded('unite')
|
|
||||||
Unite menu:Projects
|
|
||||||
elseif SpaceVim#layers#isLoaded('denite')
|
|
||||||
Denite menu:Projects
|
|
||||||
elseif SpaceVim#layers#isLoaded('fzf')
|
|
||||||
FzfMenu Projects
|
|
||||||
elseif SpaceVim#layers#isLoaded('leaderf')
|
|
||||||
call SpaceVim#layers#leaderf#run_menu('Projects')
|
|
||||||
else
|
|
||||||
call SpaceVim#logger#warn('fuzzy find layer is needed to find project!')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! SpaceVim#plugins#projectmanager#open(project) abort
|
|
||||||
let path = s:project_paths[a:project]['path']
|
|
||||||
tabnew
|
|
||||||
exe 'lcd ' . path
|
|
||||||
if g:spacevim_filemanager ==# 'vimfiler'
|
|
||||||
Startify | VimFiler
|
|
||||||
elseif g:spacevim_filemanager ==# 'nerdtree'
|
|
||||||
Startify | NERDTree
|
|
||||||
elseif g:spacevim_filemanager ==# 'defx'
|
|
||||||
Startify | Defx
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! SpaceVim#plugins#projectmanager#current_name() abort
|
|
||||||
return get(b:, '_spacevim_project_name', '')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" This function is called when projectmanager change the directory.
|
|
||||||
"
|
|
||||||
" What should be cached?
|
|
||||||
" only the directory and project name.
|
|
||||||
function! SpaceVim#plugins#projectmanager#RootchandgeCallback() abort
|
|
||||||
let project = {
|
|
||||||
\ 'path' : getcwd(),
|
|
||||||
\ 'name' : fnamemodify(getcwd(), ':t'),
|
|
||||||
\ 'opened_time' : localtime()
|
|
||||||
\ }
|
|
||||||
if empty(project.path)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call s:cache_project(project)
|
|
||||||
let g:_spacevim_project_name = project.name
|
|
||||||
let b:_spacevim_project_name = g:_spacevim_project_name
|
|
||||||
for Callback in s:project_callback
|
|
||||||
call call(Callback, [])
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:project_callback = []
|
|
||||||
function! SpaceVim#plugins#projectmanager#reg_callback(func) abort
|
|
||||||
if type(a:func) == 2
|
|
||||||
call add(s:project_callback, a:func)
|
|
||||||
else
|
|
||||||
call SpaceVim#logger#warn('can not register the project callback: ' . string(a:func))
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! SpaceVim#plugins#projectmanager#current_root() abort
|
|
||||||
" @todo skip some plugin buffer
|
|
||||||
if bufname('%') =~# '\[denite\]'
|
|
||||||
\ || bufname('%') ==# 'denite-filter'
|
|
||||||
\ || bufname('%') ==# '\[defx\]'
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if join(g:spacevim_project_rooter_patterns, ':') !=# join(s:spacevim_project_rooter_patterns, ':')
|
|
||||||
call s:LOGGER.info('project_rooter_patterns option has been change, clear b:rootDir')
|
|
||||||
call setbufvar('%', 'rootDir', '')
|
|
||||||
let s:spacevim_project_rooter_patterns = copy(g:spacevim_project_rooter_patterns)
|
|
||||||
call s:update_rooter_patterns()
|
|
||||||
endif
|
|
||||||
let rootdir = getbufvar('%', 'rootDir', '')
|
|
||||||
if empty(rootdir)
|
|
||||||
let rootdir = s:find_root_directory()
|
|
||||||
if empty(rootdir)
|
|
||||||
let rootdir = s:FILE.unify_path(getcwd())
|
|
||||||
endif
|
|
||||||
call setbufvar('%', 'rootDir', rootdir)
|
|
||||||
endif
|
|
||||||
call s:change_dir(rootdir)
|
|
||||||
call SpaceVim#plugins#projectmanager#RootchandgeCallback()
|
|
||||||
return rootdir
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:change_dir(dir) abort
|
|
||||||
let bufname = bufname('%')
|
|
||||||
if empty(bufname)
|
|
||||||
let bufname = 'No Name'
|
|
||||||
endif
|
|
||||||
call s:LOGGER.info('buffer name: ' . bufname)
|
|
||||||
if a:dir ==# s:FILE.unify_path(getcwd())
|
|
||||||
call s:LOGGER.info('same as current directory, no need to change.')
|
|
||||||
else
|
|
||||||
call s:LOGGER.info('change to root: ' . a:dir)
|
|
||||||
exe 'cd ' . fnameescape(fnamemodify(a:dir, ':p'))
|
|
||||||
try
|
|
||||||
let b:git_dir = fugitive#extract_git_dir(expand('%:p'))
|
|
||||||
catch
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! SpaceVim#plugins#projectmanager#kill_project() abort
|
|
||||||
let name = get(b:, '_spacevim_project_name', '')
|
|
||||||
if name !=# ''
|
|
||||||
call s:BUFFER.filter_do(
|
|
||||||
\ {
|
|
||||||
\ 'expr' : [
|
|
||||||
\ 'buflisted(v:val)',
|
|
||||||
\ 'getbufvar(v:val, "_spacevim_project_name") == "' . name . '"',
|
|
||||||
\ ],
|
|
||||||
\ 'do' : 'bd %d'
|
|
||||||
\ }
|
|
||||||
\ )
|
\ )
|
||||||
endif
|
endfunction
|
||||||
|
function! SpaceVim#plugins#projectmanager#list() abort
|
||||||
endfunction
|
lua require("spacevim.plugin.projectmanager").list()
|
||||||
|
endfunction
|
||||||
if g:spacevim_project_rooter_automatically
|
function! SpaceVim#plugins#projectmanager#open(project) abort
|
||||||
augroup spacevim_project_rooter
|
lua require("spacevim.plugin.projectmanager").open(
|
||||||
autocmd!
|
\ require("spacevim").eval("a:project")
|
||||||
autocmd VimEnter,BufEnter * call SpaceVim#plugins#projectmanager#current_root()
|
\ )
|
||||||
autocmd BufWritePost * :call setbufvar('%', 'rootDir', '') | call SpaceVim#plugins#projectmanager#current_root()
|
endfunction
|
||||||
augroup END
|
function! SpaceVim#plugins#projectmanager#current_name() abort
|
||||||
endif
|
return luaeval('require("spacevim.plugin.projectmanager").current_name()')
|
||||||
function! s:find_root_directory() abort
|
endfunction
|
||||||
" @question confused about expand and fnamemodify
|
function! SpaceVim#plugins#projectmanager#RootchandgeCallback() abort
|
||||||
" ref: https://github.com/vim/vim/issues/6793
|
lua require("spacevim.plugin.projectmanager").RootchandgeCallback()
|
||||||
|
endfunction
|
||||||
|
function! SpaceVim#plugins#projectmanager#reg_callback(func) abort
|
||||||
|
lua require("spacevim.plugin.projectmanager").reg_callback(
|
||||||
|
\ require("spacevim").eval("string(a:func)")
|
||||||
|
\ )
|
||||||
|
endfunction
|
||||||
|
function! SpaceVim#plugins#projectmanager#current_root() abort
|
||||||
|
return luaeval('require("spacevim.plugin.projectmanager").current_root()')
|
||||||
|
endfunction
|
||||||
|
function! SpaceVim#plugins#projectmanager#kill_project() abort
|
||||||
|
lua require("spacevim.plugin.projectmanager").kill_project()
|
||||||
|
endfunction
|
||||||
|
else
|
||||||
|
|
||||||
|
|
||||||
" get the current path of buffer or working dir
|
" project item:
|
||||||
|
" {
|
||||||
|
" "path" : "path/to/root",
|
||||||
|
" "name" : "name of the project, by default it is name of root directory",
|
||||||
|
" "type" : "git maven or svn",
|
||||||
|
" }
|
||||||
|
"
|
||||||
|
|
||||||
let fd = expand('%:p')
|
let s:BUFFER = SpaceVim#api#import('vim#buffer')
|
||||||
if empty(fd)
|
let s:FILE = SpaceVim#api#import('file')
|
||||||
let fd = getcwd()
|
" the name projectmanager is too long
|
||||||
endif
|
" use rooter instead
|
||||||
|
let s:LOGGER =SpaceVim#logger#derive('rooter')
|
||||||
|
let s:TIME = SpaceVim#api#import('time')
|
||||||
|
let s:JSON = SpaceVim#api#import('data#json')
|
||||||
|
let s:LIST = SpaceVim#api#import('data#list')
|
||||||
|
let s:VIM = SpaceVim#api#import('vim')
|
||||||
|
|
||||||
let dirs = []
|
function! s:update_rooter_patterns() abort
|
||||||
call s:LOGGER.info('Start to find root for: ' . s:FILE.unify_path(fd))
|
let s:project_rooter_patterns = filter(copy(g:spacevim_project_rooter_patterns), 'v:val !~# "^!"')
|
||||||
for pattern in s:project_rooter_patterns
|
let s:project_rooter_ignores = map(filter(copy(g:spacevim_project_rooter_patterns), 'v:val =~# "^!"'), 'v:val[1:]')
|
||||||
if stridx(pattern, '/') != -1
|
endfunction
|
||||||
if g:spacevim_project_rooter_outermost
|
|
||||||
let find_path = s:FILE.finddir(pattern, fd, -1)
|
function! s:is_ignored_dir(dir) abort
|
||||||
else
|
return len(filter(copy(s:project_rooter_ignores), 'a:dir =~# v:val')) > 0
|
||||||
let find_path = s:FILE.finddir(pattern, fd)
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
call add(g:spacevim_project_rooter_patterns, '.SpaceVim.d/')
|
||||||
|
let s:spacevim_project_rooter_patterns = copy(g:spacevim_project_rooter_patterns)
|
||||||
|
call s:update_rooter_patterns()
|
||||||
|
|
||||||
|
let s:project_paths = {}
|
||||||
|
let s:project_cache_path = s:FILE.unify_path(g:spacevim_data_dir, ':p') . 'SpaceVim/projects.json'
|
||||||
|
|
||||||
|
function! s:cache() abort
|
||||||
|
call writefile([s:JSON.json_encode(s:project_paths)], s:FILE.unify_path(s:project_cache_path, ':p'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:load_cache() abort
|
||||||
|
if filereadable(s:project_cache_path)
|
||||||
|
call s:LOGGER.info('Load projects cache from: ' . s:project_cache_path)
|
||||||
|
let cache_context = join(readfile(s:project_cache_path, ''), '')
|
||||||
|
if !empty(cache_context)
|
||||||
|
let cache_object = s:JSON.json_decode(cache_context)
|
||||||
|
if s:VIM.is_dict(cache_object)
|
||||||
|
let s:project_paths = filter(cache_object, '!empty(v:key)')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
if g:spacevim_project_rooter_outermost
|
call s:LOGGER.info('projects cache file does not exists!')
|
||||||
let find_path = s:FILE.findfile(pattern, fd, -1)
|
|
||||||
else
|
|
||||||
let find_path = s:FILE.findfile(pattern, fd)
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
let path_type = getftype(find_path)
|
endfunction
|
||||||
if ( path_type ==# 'dir' || path_type ==# 'file' )
|
|
||||||
\ && !s:is_ignored_dir(find_path)
|
|
||||||
let find_path = s:FILE.unify_path(find_path, ':p')
|
|
||||||
if path_type ==# 'dir'
|
|
||||||
let dir = s:FILE.unify_path(find_path, ':h:h')
|
|
||||||
else
|
|
||||||
let dir = s:FILE.unify_path(find_path, ':h')
|
|
||||||
endif
|
|
||||||
if dir !=# s:FILE.unify_path(expand('$HOME'))
|
|
||||||
call s:LOGGER.info(' (' . pattern . '):' . dir)
|
|
||||||
call add(dirs, dir)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return s:sort_dirs(deepcopy(dirs))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
if g:spacevim_enable_projects_cache
|
||||||
function! s:sort_dirs(dirs) abort
|
call s:load_cache()
|
||||||
let dir = get(sort(a:dirs, function('s:compare')), 0, '')
|
|
||||||
let bufdir = getbufvar('%', 'rootDir', '')
|
|
||||||
if bufdir ==# dir
|
|
||||||
return ''
|
|
||||||
else
|
|
||||||
return dir
|
|
||||||
endif
|
endif
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:compare(d1, d2) abort
|
let g:unite_source_menu_menus =
|
||||||
if !g:spacevim_project_rooter_outermost
|
\ get(g:,'unite_source_menu_menus',{})
|
||||||
return len(split(a:d2, '/')) - len(split(a:d1, '/'))
|
let g:unite_source_menu_menus.Projects = {'description':
|
||||||
else
|
\ 'Custom mapped keyboard shortcuts [SPC] p p'}
|
||||||
return len(split(a:d1, '/')) - len(split(a:d2, '/'))
|
let g:unite_source_menu_menus.Projects.command_candidates =
|
||||||
endif
|
\ get(g:unite_source_menu_menus.Projects,'command_candidates', [])
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:FILE = SpaceVim#api#import('file')
|
function! s:cache_project(prj) abort
|
||||||
|
let s:project_paths[a:prj.path] = a:prj
|
||||||
function! SpaceVim#plugins#projectmanager#complete_project(ArgLead, CmdLine, CursorPos) abort
|
let g:unite_source_menu_menus.Projects.command_candidates = []
|
||||||
call SpaceVim#commands#debug#completion_debug(a:ArgLead, a:CmdLine, a:CursorPos)
|
for key in s:sort_by_opened_time()
|
||||||
let dir = get(g:,'spacevim_src_root', '~')
|
let desc = '[' . s:project_paths[key].name . '] ' . s:project_paths[key].path . ' <' . strftime('%Y-%m-%d %T', s:project_paths[key].opened_time) . '>'
|
||||||
"return globpath(dir, '*')
|
let cmd = "call SpaceVim#plugins#projectmanager#open('" . s:project_paths[key].path . "')"
|
||||||
let result = split(globpath(dir, '*'), "\n")
|
call add(g:unite_source_menu_menus.Projects.command_candidates, [desc,cmd])
|
||||||
let ps = []
|
endfor
|
||||||
for p in result
|
if g:spacevim_enable_projects_cache
|
||||||
if isdirectory(p) && isdirectory(p . s:FILE.separator . '.git')
|
call s:cache()
|
||||||
call add(ps, fnamemodify(p, ':t'))
|
|
||||||
endif
|
endif
|
||||||
endfor
|
endfunction
|
||||||
return join(ps, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! SpaceVim#plugins#projectmanager#OpenProject(p) abort
|
" sort projects based on opened_time, and remove extra projects based on
|
||||||
let dir = get(g:, 'spacevim_src_root', '~') . a:p
|
" projects_cache_num
|
||||||
exe 'CtrlP '. dir
|
function! s:sort_by_opened_time() abort
|
||||||
endfunction
|
let paths = keys(s:project_paths)
|
||||||
|
let paths = sort(paths, function('s:compare_time'))
|
||||||
|
if g:spacevim_projects_cache_num > 0 && s:LIST.has_index(paths, g:spacevim_projects_cache_num)
|
||||||
|
for path in paths[g:spacevim_projects_cache_num :]
|
||||||
|
call remove(s:project_paths, path)
|
||||||
|
endfor
|
||||||
|
let paths = paths[:g:spacevim_projects_cache_num - 1]
|
||||||
|
endif
|
||||||
|
return paths
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:compare_time(d1, d2) abort
|
||||||
|
let proj1 = get(s:project_paths, a:d1, {})
|
||||||
|
let proj1time = get(proj1, 'opened_time', 0)
|
||||||
|
let proj2 = get(s:project_paths, a:d2, {})
|
||||||
|
let proj2time = get(proj2, 'opened_time', 0)
|
||||||
|
return proj2time - proj1time
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function! s:change_dir(dir) abort
|
||||||
|
let bufname = bufname('%')
|
||||||
|
if empty(bufname)
|
||||||
|
let bufname = 'No Name'
|
||||||
|
endif
|
||||||
|
call s:LOGGER.info('buffer name: ' . bufname)
|
||||||
|
if a:dir ==# s:FILE.unify_path(getcwd())
|
||||||
|
call s:LOGGER.info('same as current directory, no need to change.')
|
||||||
|
else
|
||||||
|
call s:LOGGER.info('change to root: ' . a:dir)
|
||||||
|
exe 'cd ' . fnameescape(fnamemodify(a:dir, ':p'))
|
||||||
|
try
|
||||||
|
let b:git_dir = fugitive#extract_git_dir(expand('%:p'))
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
if g:spacevim_project_rooter_automatically
|
||||||
|
augroup spacevim_project_rooter
|
||||||
|
autocmd!
|
||||||
|
autocmd VimEnter,BufEnter * call SpaceVim#plugins#projectmanager#current_root()
|
||||||
|
autocmd BufWritePost * :call setbufvar('%', 'rootDir', '') | call SpaceVim#plugins#projectmanager#current_root()
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
function! s:find_root_directory() abort
|
||||||
|
" @question confused about expand and fnamemodify
|
||||||
|
" ref: https://github.com/vim/vim/issues/6793
|
||||||
|
|
||||||
|
|
||||||
|
" get the current path of buffer or working dir
|
||||||
|
|
||||||
|
let fd = expand('%:p')
|
||||||
|
if empty(fd)
|
||||||
|
let fd = getcwd()
|
||||||
|
endif
|
||||||
|
|
||||||
|
let dirs = []
|
||||||
|
call s:LOGGER.info('Start to find root for: ' . s:FILE.unify_path(fd))
|
||||||
|
for pattern in s:project_rooter_patterns
|
||||||
|
if stridx(pattern, '/') != -1
|
||||||
|
if g:spacevim_project_rooter_outermost
|
||||||
|
let find_path = s:FILE.finddir(pattern, fd, -1)
|
||||||
|
else
|
||||||
|
let find_path = s:FILE.finddir(pattern, fd)
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
if g:spacevim_project_rooter_outermost
|
||||||
|
let find_path = s:FILE.findfile(pattern, fd, -1)
|
||||||
|
else
|
||||||
|
let find_path = s:FILE.findfile(pattern, fd)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let path_type = getftype(find_path)
|
||||||
|
if ( path_type ==# 'dir' || path_type ==# 'file' )
|
||||||
|
\ && !s:is_ignored_dir(find_path)
|
||||||
|
let find_path = s:FILE.unify_path(find_path, ':p')
|
||||||
|
if path_type ==# 'dir'
|
||||||
|
let dir = s:FILE.unify_path(find_path, ':h:h')
|
||||||
|
else
|
||||||
|
let dir = s:FILE.unify_path(find_path, ':h')
|
||||||
|
endif
|
||||||
|
if dir !=# s:FILE.unify_path(expand('$HOME'))
|
||||||
|
call s:LOGGER.info(' (' . pattern . '):' . dir)
|
||||||
|
call add(dirs, dir)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return s:sort_dirs(deepcopy(dirs))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function! s:sort_dirs(dirs) abort
|
||||||
|
let dir = get(sort(a:dirs, function('s:compare')), 0, '')
|
||||||
|
let bufdir = getbufvar('%', 'rootDir', '')
|
||||||
|
if bufdir ==# dir
|
||||||
|
return ''
|
||||||
|
else
|
||||||
|
return dir
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:compare(d1, d2) abort
|
||||||
|
if !g:spacevim_project_rooter_outermost
|
||||||
|
return len(split(a:d2, '/')) - len(split(a:d1, '/'))
|
||||||
|
else
|
||||||
|
return len(split(a:d1, '/')) - len(split(a:d2, '/'))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:FILE = SpaceVim#api#import('file')
|
||||||
|
|
||||||
|
function! SpaceVim#plugins#projectmanager#complete_project(ArgLead, CmdLine, CursorPos) abort
|
||||||
|
call SpaceVim#commands#debug#completion_debug(a:ArgLead, a:CmdLine, a:CursorPos)
|
||||||
|
let dir = get(g:,'spacevim_src_root', '~')
|
||||||
|
"return globpath(dir, '*')
|
||||||
|
let result = split(globpath(dir, '*'), "\n")
|
||||||
|
let ps = []
|
||||||
|
for p in result
|
||||||
|
if isdirectory(p) && isdirectory(p . s:FILE.separator . '.git')
|
||||||
|
call add(ps, fnamemodify(p, ':t'))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return join(ps, "\n")
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SpaceVim#plugins#projectmanager#OpenProject(p) abort
|
||||||
|
let dir = get(g:, 'spacevim_src_root', '~') . a:p
|
||||||
|
exe 'CtrlP '. dir
|
||||||
|
endfunction
|
||||||
|
" this function will use fuzzy find layer, now only denite and unite are
|
||||||
|
" supported.
|
||||||
|
|
||||||
|
function! SpaceVim#plugins#projectmanager#list() abort
|
||||||
|
if SpaceVim#layers#isLoaded('unite')
|
||||||
|
Unite menu:Projects
|
||||||
|
elseif SpaceVim#layers#isLoaded('denite')
|
||||||
|
Denite menu:Projects
|
||||||
|
elseif SpaceVim#layers#isLoaded('fzf')
|
||||||
|
FzfMenu Projects
|
||||||
|
elseif SpaceVim#layers#isLoaded('leaderf')
|
||||||
|
call SpaceVim#layers#leaderf#run_menu('Projects')
|
||||||
|
else
|
||||||
|
call SpaceVim#logger#warn('fuzzy find layer is needed to find project!')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SpaceVim#plugins#projectmanager#open(project) abort
|
||||||
|
let path = s:project_paths[a:project]['path']
|
||||||
|
tabnew
|
||||||
|
exe 'lcd ' . path
|
||||||
|
if g:spacevim_filemanager ==# 'vimfiler'
|
||||||
|
Startify | VimFiler
|
||||||
|
elseif g:spacevim_filemanager ==# 'nerdtree'
|
||||||
|
Startify | NERDTree
|
||||||
|
elseif g:spacevim_filemanager ==# 'defx'
|
||||||
|
Startify | Defx
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SpaceVim#plugins#projectmanager#current_name() abort
|
||||||
|
return get(b:, '_spacevim_project_name', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" This function is called when projectmanager change the directory.
|
||||||
|
"
|
||||||
|
" What should be cached?
|
||||||
|
" only the directory and project name.
|
||||||
|
function! SpaceVim#plugins#projectmanager#RootchandgeCallback() abort
|
||||||
|
let project = {
|
||||||
|
\ 'path' : getcwd(),
|
||||||
|
\ 'name' : fnamemodify(getcwd(), ':t'),
|
||||||
|
\ 'opened_time' : localtime()
|
||||||
|
\ }
|
||||||
|
if empty(project.path)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call s:cache_project(project)
|
||||||
|
let g:_spacevim_project_name = project.name
|
||||||
|
let b:_spacevim_project_name = g:_spacevim_project_name
|
||||||
|
for Callback in s:project_callback
|
||||||
|
call call(Callback, [])
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:project_callback = []
|
||||||
|
function! SpaceVim#plugins#projectmanager#reg_callback(func) abort
|
||||||
|
if type(a:func) == 2
|
||||||
|
call add(s:project_callback, a:func)
|
||||||
|
else
|
||||||
|
call SpaceVim#logger#warn('can not register the project callback: ' . string(a:func))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SpaceVim#plugins#projectmanager#current_root() abort
|
||||||
|
" @todo skip some plugin buffer
|
||||||
|
if bufname('%') =~# '\[denite\]'
|
||||||
|
\ || bufname('%') ==# 'denite-filter'
|
||||||
|
\ || bufname('%') ==# '\[defx\]'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if join(g:spacevim_project_rooter_patterns, ':') !=# join(s:spacevim_project_rooter_patterns, ':')
|
||||||
|
call s:LOGGER.info('project_rooter_patterns option has been change, clear b:rootDir')
|
||||||
|
call setbufvar('%', 'rootDir', '')
|
||||||
|
let s:spacevim_project_rooter_patterns = copy(g:spacevim_project_rooter_patterns)
|
||||||
|
call s:update_rooter_patterns()
|
||||||
|
endif
|
||||||
|
let rootdir = getbufvar('%', 'rootDir', '')
|
||||||
|
if empty(rootdir)
|
||||||
|
let rootdir = s:find_root_directory()
|
||||||
|
if empty(rootdir)
|
||||||
|
let rootdir = s:FILE.unify_path(getcwd())
|
||||||
|
endif
|
||||||
|
call setbufvar('%', 'rootDir', rootdir)
|
||||||
|
endif
|
||||||
|
call s:change_dir(rootdir)
|
||||||
|
call SpaceVim#plugins#projectmanager#RootchandgeCallback()
|
||||||
|
return rootdir
|
||||||
|
endfunction
|
||||||
|
function! SpaceVim#plugins#projectmanager#kill_project() abort
|
||||||
|
let name = get(b:, '_spacevim_project_name', '')
|
||||||
|
if name !=# ''
|
||||||
|
call s:BUFFER.filter_do(
|
||||||
|
\ {
|
||||||
|
\ 'expr' : [
|
||||||
|
\ 'buflisted(v:val)',
|
||||||
|
\ 'getbufvar(v:val, "_spacevim_project_name") == "' . name . '"',
|
||||||
|
\ ],
|
||||||
|
\ 'do' : 'bd %d'
|
||||||
|
\ }
|
||||||
|
\ )
|
||||||
|
endif
|
||||||
|
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
" vim:set et nowrap sw=2 cc=80:
|
" vim:set et nowrap sw=2 cc=80:
|
||||||
|
@ -1,18 +1,6 @@
|
|||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
|
||||||
local options = require('spacevim.opt')
|
|
||||||
local layers = require('spacevim.layer')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function M.bootstrap()
|
|
||||||
|
|
||||||
options.init()
|
|
||||||
layers.init()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.eval(l)
|
function M.eval(l)
|
||||||
if vim.api ~= nil then
|
if vim.api ~= nil then
|
||||||
return vim.api.nvim_eval(l)
|
return vim.api.nvim_eval(l)
|
||||||
|
@ -1,9 +1,32 @@
|
|||||||
local layer = {}
|
--=============================================================================
|
||||||
|
-- layer.lua --- spacevim layer module
|
||||||
|
-- Copyright (c) 2016-2019 Wang Shidong & Contributors
|
||||||
|
-- Author: Wang Shidong < wsdjeg@outlook.com >
|
||||||
|
-- URL: https://spacevim.org
|
||||||
|
-- License: GPLv3
|
||||||
|
--=============================================================================
|
||||||
|
|
||||||
|
|
||||||
function layer.init()
|
local M = {}
|
||||||
|
local sp = require('spacevim')
|
||||||
|
|
||||||
|
-- local mt = {
|
||||||
|
-- __newindex = function(layer, layer_name, layer_obj)
|
||||||
|
-- rawset(layer, layer_name, layer_obj)
|
||||||
|
-- end,
|
||||||
|
-- __index = function(layer, layer_name)
|
||||||
|
-- if vim.g ~= nil then
|
||||||
|
-- return vim.g['spacevim_' .. key] or nil
|
||||||
|
-- else
|
||||||
|
-- return sp.eval('get(g:, "spacevim_' .. key .. '", v:null)')
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- }
|
||||||
|
-- setmetatable(M, mt)
|
||||||
|
|
||||||
|
function M.isLoaded(layer)
|
||||||
|
return sp.call('SpaceVim#layers#isLoaded', layer) == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return layer
|
return M
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
local options = {}
|
local M = {}
|
||||||
|
local sp = require('spacevim')
|
||||||
|
|
||||||
options._opts = {}
|
local mt = {
|
||||||
|
-- this is call when we use opt.xxxx = xxx
|
||||||
|
__newindex = function(table, key, value)
|
||||||
|
if vim.g ~= nil then
|
||||||
|
vim.g['spacevim_' .. key] = value
|
||||||
|
else
|
||||||
|
end
|
||||||
|
|
||||||
|
end,
|
||||||
|
-- this is call when we use opt.xxxx
|
||||||
|
__index = function(table, key)
|
||||||
|
if vim.g ~= nil then
|
||||||
|
return vim.g['spacevim_' .. key] or nil
|
||||||
|
else
|
||||||
|
return sp.eval('get(g:, "spacevim_' .. key .. '", v:null)')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
setmetatable(M, mt)
|
||||||
|
|
||||||
function options.init()
|
return M
|
||||||
options._opts.version = '1.2.0'
|
|
||||||
-- Change the default indentation of SpaceVim, default is 2.
|
|
||||||
options._opts.default_indent = 2
|
|
||||||
options._opts.expand_tab = true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
@ -44,13 +44,16 @@ function M.set_config_name(path, name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function M.alt(request_parse, ...)
|
function M.alt(request_parse, ...)
|
||||||
local arg={...}
|
local argvs=...
|
||||||
local type = 'alternate'
|
local alt_type = 'alternate'
|
||||||
|
if argvs ~= nil then
|
||||||
|
alt_type = argvs[1] or alt_type
|
||||||
|
end
|
||||||
local alt = nil
|
local alt = nil
|
||||||
if fn.exists('b:alternate_file_config') ~= 1 then
|
if fn.exists('b:alternate_file_config') ~= 1 then
|
||||||
local conf_file_path = M.getConfigPath()
|
local conf_file_path = M.getConfigPath()
|
||||||
local file = sp_file.unify_path(fn.bufname('%'), ':.')
|
local file = sp_file.unify_path(fn.bufname('%'), ':.')
|
||||||
alt = M.get_alt(file, conf_file_path, request_parse, type)
|
alt = M.get_alt(file, conf_file_path, request_parse, alt_type)
|
||||||
end
|
end
|
||||||
logger.debug('alt is:' .. alt)
|
logger.debug('alt is:' .. alt)
|
||||||
if alt ~= nil and alt ~= '' then
|
if alt ~= nil and alt ~= '' then
|
||||||
@ -87,7 +90,7 @@ local function _keys(val)
|
|||||||
end
|
end
|
||||||
local function _comp(a, b)
|
local function _comp(a, b)
|
||||||
if (string.match(a, '*') == '*'
|
if (string.match(a, '*') == '*'
|
||||||
and string.match(b, '*') == '*')
|
and string.match(b, '*') == '*')
|
||||||
then
|
then
|
||||||
return #a < #b
|
return #a < #b
|
||||||
elseif string.match(a, '*') == '*' then
|
elseif string.match(a, '*') == '*' then
|
||||||
@ -119,8 +122,8 @@ local function parse(alt_config_json)
|
|||||||
logger.debug(file)
|
logger.debug(file)
|
||||||
project_config[alt_config_json.root][file] = {}
|
project_config[alt_config_json.root][file] = {}
|
||||||
if alt_config_json.config[file] ~= nil then
|
if alt_config_json.config[file] ~= nil then
|
||||||
for type, type_v in pairs(alt_config_json.config[file]) do
|
for alt_type, type_v in pairs(alt_config_json.config[file]) do
|
||||||
project_config[alt_config_json.root][file][type] = type_v
|
project_config[alt_config_json.root][file][alt_type] = type_v
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for a_type, _ in pairs(alt_config_json.config[key]) do
|
for a_type, _ in pairs(alt_config_json.config[key]) do
|
||||||
|
351
lua/spacevim/plugin/projectmanager.lua
Normal file
351
lua/spacevim/plugin/projectmanager.lua
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
--=============================================================================
|
||||||
|
-- projectmanager.lua --- The lua version of projectmanager..vim
|
||||||
|
-- Copyright (c) 2016-2019 Wang Shidong & Contributors
|
||||||
|
-- Author: Wang Shidong < wsdjeg@outlook.com >
|
||||||
|
-- URL: https://spacevim.org
|
||||||
|
-- License: GPLv3
|
||||||
|
--=============================================================================
|
||||||
|
|
||||||
|
local logger = require('spacevim.logger').derive('roter')
|
||||||
|
local sp = require('spacevim')
|
||||||
|
local sp_file = require('spacevim.api.file')
|
||||||
|
local sp_json = require('spacevim.api.data.json')
|
||||||
|
local sp_opt = require('spacevim.opt')
|
||||||
|
local fn = sp.fn
|
||||||
|
local layer = require('spacevim.layer')
|
||||||
|
local project_paths = {}
|
||||||
|
local project_cache_path = sp_file.unify_path(sp_opt.data_dir, ':p') .. 'SpaceVim/projects.json'
|
||||||
|
local spacevim_project_rooter_patterns = {}
|
||||||
|
local project_rooter_patterns = {}
|
||||||
|
local project_rooter_ignores = {}
|
||||||
|
local project_callback = {}
|
||||||
|
|
||||||
|
local function update_rooter_patterns()
|
||||||
|
project_rooter_patterns = {}
|
||||||
|
project_rooter_ignores = {}
|
||||||
|
for _,v in pairs(sp_opt.project_rooter_patterns) do
|
||||||
|
if string.match(v, '^!') == nil then
|
||||||
|
table.insert(project_rooter_patterns, v)
|
||||||
|
else
|
||||||
|
table.insert(project_rooter_ignores, string.sub(v, 2, -1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function is_ignored_dir(dir)
|
||||||
|
for _,v in pairs(project_rooter_ignores) do
|
||||||
|
if string.match(dir, v) ~= nil then
|
||||||
|
logger.debug('this is an ignored dir:' .. dir)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local function cache()
|
||||||
|
local path = sp_file.unify_path(project_cache_path, ':p')
|
||||||
|
local file = io.open(path, 'w')
|
||||||
|
if file then
|
||||||
|
if file:write(sp_json.json_encode(project_paths)) == nil then
|
||||||
|
logger.debug('failed to write to file:' .. path)
|
||||||
|
end
|
||||||
|
io.close(file)
|
||||||
|
else
|
||||||
|
logger.debug('failed to open file:' .. path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function readfile(path)
|
||||||
|
local file = io.open(path, "r")
|
||||||
|
if file then
|
||||||
|
local content = file:read("*a")
|
||||||
|
io.close(file)
|
||||||
|
return content
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function filereadable(fpath)
|
||||||
|
local f = io.open(fpath, 'r')
|
||||||
|
if f ~= nil then io.close(f) return true else return false end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load_cache()
|
||||||
|
if filereadable(project_cache_path) then
|
||||||
|
logger.info('Load projects cache from: ' .. project_cache_path)
|
||||||
|
local cache_context = readfile(project_cache_path)
|
||||||
|
if cache_context == nil then
|
||||||
|
local cache_object = sp_json.json_decode(cache_context)
|
||||||
|
if type(cache_object) == 'table' then
|
||||||
|
project_paths = fn.filter(cache_object, '!empty(v:key)')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
logger.info('projects cache file does not exists!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sort_by_opened_time()
|
||||||
|
local paths = {}
|
||||||
|
for k,v in pairs(project_paths) do table.insert(paths, k) end
|
||||||
|
table.sort(paths, compare_time)
|
||||||
|
if sp_opt.projects_cache_num > 0 and #paths >= sp_opt.projects_cache_num then
|
||||||
|
for i = sp_opt.projects_cache_num, #paths, 1 do
|
||||||
|
project_paths[paths[sp_opt.projects_cache_num]] = nil
|
||||||
|
table.remove(paths, sp_opt.projects_cache_num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return paths
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compare_time(d1, d2)
|
||||||
|
local proj1 = project_paths[d1] or {}
|
||||||
|
local proj1time = proj1['opened_time'] or 0
|
||||||
|
local proj2 = project_paths[d2] or {}
|
||||||
|
local proj2time = proj2['opened_time'] or 0
|
||||||
|
return proj2time - proj1time
|
||||||
|
end
|
||||||
|
local function change_dir(dir)
|
||||||
|
if dir == sp_file.unify_path(fn.getcwd()) then
|
||||||
|
logger.debug('same as current directory, no need to change.')
|
||||||
|
else
|
||||||
|
if dir ~= nil then
|
||||||
|
logger.info('change to root: ' .. dir)
|
||||||
|
sp.cmd('cd ' .. sp.fn.fnameescape(sp.fn.fnamemodify(dir, ':p')))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sort_dirs(dirs)
|
||||||
|
table.sort(dirs, compare)
|
||||||
|
local dir = dirs[1]
|
||||||
|
local bufdir = fn.getbufvar('%', 'rootDir', '')
|
||||||
|
if bufdir == dir then
|
||||||
|
return ''
|
||||||
|
else
|
||||||
|
return dir
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compare(d1, d2)
|
||||||
|
local _, al = string.gsub(d1, "/", "")
|
||||||
|
local _, bl = string.gsub(d2, "/", "")
|
||||||
|
if sp_opt.project_rooter_outermost == 0 then
|
||||||
|
return bl - al
|
||||||
|
else
|
||||||
|
return al - bl
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_root_directory()
|
||||||
|
local fd = fn.bufname('%')
|
||||||
|
if fn == '' then
|
||||||
|
logger.debug('bufname is empty')
|
||||||
|
fd = fn.getcwd()
|
||||||
|
end
|
||||||
|
logger.debug('start to find root for: ' .. fd)
|
||||||
|
local dirs = {}
|
||||||
|
for _,pattern in pairs(project_rooter_patterns) do
|
||||||
|
logger.debug('searching rooter_patterns:' .. pattern)
|
||||||
|
local find_path = ''
|
||||||
|
if string.sub(pattern, -1) == '/' then
|
||||||
|
if sp_opt.project_rooter_outermost == 1 then
|
||||||
|
find_path = sp_file.finddir(pattern, fd, -1)
|
||||||
|
else
|
||||||
|
find_path = sp_file.finddir(pattern, fd)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if sp_opt.project_rooter_outermost == 1 then
|
||||||
|
find_path = sp_file.findfile(pattern, fd, -1)
|
||||||
|
else
|
||||||
|
find_path = sp_file.findfile(pattern, fd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
logger.debug('find_path is:' .. find_path)
|
||||||
|
local path_type = fn.getftype(find_path)
|
||||||
|
logger.debug('path_type is:' .. path_type)
|
||||||
|
if ( path_type == 'dir' or path_type == 'file' )
|
||||||
|
and not(is_ignored_dir(find_path)) then
|
||||||
|
find_path = sp_file.unify_path(find_path, ':p')
|
||||||
|
if path_type == 'dir' then
|
||||||
|
find_path = sp_file.unify_path(find_path, ':h:h')
|
||||||
|
else
|
||||||
|
find_path = sp_file.unify_path(find_path, ':h')
|
||||||
|
end
|
||||||
|
logger.debug('find_path is:' .. find_path)
|
||||||
|
if find_path ~= sp_file.unify_path(fn.expand('$HOME')) then
|
||||||
|
logger.info(' (' .. pattern .. '):' .. find_path)
|
||||||
|
table.insert(dirs, find_path)
|
||||||
|
else
|
||||||
|
logger.info('ignore $HOME directory:' .. find_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return sort_dirs(dirs)
|
||||||
|
end
|
||||||
|
local function cache_project(prj)
|
||||||
|
project_paths[prj.path] = prj
|
||||||
|
sp.cmd('let g:unite_source_menu_menus.Projects.command_candidates = []')
|
||||||
|
for _, key in pairs(sort_by_opened_time()) do
|
||||||
|
local desc = '[' .. project_paths[key].name .. '] ' .. project_paths[key].path .. ' <' .. fn.strftime('%Y-%m-%d %T', project_paths[key].opened_time) .. '>'
|
||||||
|
local cmd = "call SpaceVim#plugins#projectmanager#open('" .. project_paths[key].path .. "')"
|
||||||
|
sp.cmd('call add(g:unite_source_menu_menus.Projects.command_candidates, ["'
|
||||||
|
.. desc
|
||||||
|
.. '", "'
|
||||||
|
.. cmd
|
||||||
|
.. '"])')
|
||||||
|
end
|
||||||
|
if sp_opt.enable_projects_cache then
|
||||||
|
cache()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- call add(g:spacevim_project_rooter_patterns, '.SpaceVim.d/')
|
||||||
|
|
||||||
|
-- let s:spacevim_project_rooter_patterns = copy(g:spacevim_project_rooter_patterns)
|
||||||
|
update_rooter_patterns()
|
||||||
|
|
||||||
|
if sp_opt.enable_projects_cache == 1 then
|
||||||
|
load_cache()
|
||||||
|
end
|
||||||
|
|
||||||
|
sp.cmd([[
|
||||||
|
let g:unite_source_menu_menus = get(g:,'unite_source_menu_menus',{})
|
||||||
|
let g:unite_source_menu_menus.Projects = {'description': 'Custom mapped keyboard shortcuts [SPC] p p'}
|
||||||
|
let g:unite_source_menu_menus.Projects.command_candidates = get(g:unite_source_menu_menus.Projects,'command_candidates', [])
|
||||||
|
]])
|
||||||
|
|
||||||
|
if sp_opt.project_rooter_automatically == 1 then
|
||||||
|
sp.cmd("augroup spacevim_project_rooter")
|
||||||
|
sp.cmd("autocmd!")
|
||||||
|
sp.cmd("autocmd VimEnter,BufEnter * call SpaceVim#plugins#projectmanager#current_root()")
|
||||||
|
sp.cmd("autocmd BufWritePost * :call setbufvar('%', 'rootDir', '') | call SpaceVim#plugins#projectmanager#current_root()")
|
||||||
|
sp.cmd("augroup END")
|
||||||
|
end
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
function M.list()
|
||||||
|
if layer.isLoaded('unite') then
|
||||||
|
sp.cmd('Unite menu:Projects')
|
||||||
|
elseif layer.isLoaded('denite') then
|
||||||
|
sp.cmd('Denite menu:Projects')
|
||||||
|
elseif layer.isLoaded('fzf') then
|
||||||
|
sp.cmd('FzfMenu Projects')
|
||||||
|
elseif layer.isLoaded('leaderf') then
|
||||||
|
sp.cmd("call SpaceVim#layers#leaderf#run_menu('Projects')")
|
||||||
|
else
|
||||||
|
logger.warn('fuzzy find layer is needed to find project!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.open(project)
|
||||||
|
local path = project_paths[project]['path']
|
||||||
|
sp.cmd('tabnew')
|
||||||
|
sp.cmd('lcd ' .. path)
|
||||||
|
if sp_opt.filemanager == 'vimfiler' then
|
||||||
|
sp.cmd('Startify | VimFiler')
|
||||||
|
elseif sp_opt.filemanager == 'nerdtree' then
|
||||||
|
sp.cmd('Startify | NERDTree')
|
||||||
|
elseif sp_opt.filemanager == 'defx' then
|
||||||
|
sp.cmd('Startify | Defx')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.current_name()
|
||||||
|
return sp.eval('b:_spacevim_project_name')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function M.RootchandgeCallback()
|
||||||
|
local path = sp_file.unify_path(fn.getcwd(), ':p')
|
||||||
|
local name = fn.fnamemodify(path, ':t')
|
||||||
|
local project = {
|
||||||
|
['path'] = path,
|
||||||
|
['name'] = name,
|
||||||
|
['opened_time'] = os.time()
|
||||||
|
}
|
||||||
|
if project.path == '' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
cache_project(project)
|
||||||
|
-- let g:_spacevim_project_name = project.name
|
||||||
|
-- let b:_spacevim_project_name = g:_spacevim_project_name
|
||||||
|
fn.setbufvar('%', '_spacevim_project_name', project.name)
|
||||||
|
for _, Callback in pairs(project_callback) do
|
||||||
|
logger.debug('run callback:' .. Callback)
|
||||||
|
fn.call(Callback, {})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.reg_callback(func)
|
||||||
|
if type(func) == 'string' then
|
||||||
|
if string.match(func, '^function%(') ~= nil then
|
||||||
|
table.insert(project_callback, string.sub(func, 11, -3))
|
||||||
|
else
|
||||||
|
table.insert(project_callback, func)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
logger.warn('type of func is:' .. type(func))
|
||||||
|
logger.warn('can not register the project callback: ' .. fn.string(func))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.kill_project()
|
||||||
|
local name = sp.eval('b:_spacevim_project_name')
|
||||||
|
if name ~= '' then
|
||||||
|
sp_buffer.filter_do(
|
||||||
|
{
|
||||||
|
['expr'] = {
|
||||||
|
'buflisted(v:val)',
|
||||||
|
'getbufvar(v:val, "_spacevim_project_name") == "' .. name .. '"',
|
||||||
|
},
|
||||||
|
['do'] = 'bd %d'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.complete_project(arglead, cmdline, cursorpos)
|
||||||
|
local dir = '~'
|
||||||
|
local result = fn.split(fn.globpath(dir, '*'), "\n")
|
||||||
|
local ps = {}
|
||||||
|
for p in result do
|
||||||
|
if fn.isdirectory(p) == 1 and fn.isdirectory(p .. sp_file.separator .. '.git') == 1 then
|
||||||
|
table.insert(ps, fn.fnamemodify(p, ':t'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return fn.join(ps, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function M.OpenProject(p)
|
||||||
|
sp.cmd('CtrlP '.. dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function M.current_root()
|
||||||
|
local bufname = fn.bufname('%')
|
||||||
|
if bufname == '[denite]'
|
||||||
|
or bufname == 'denite-filter'
|
||||||
|
or bufname == '[defx]' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if table.concat(sp_opt.project_rooter_patterns, ':') ~= table.concat(spacevim_project_rooter_patterns, ':') then
|
||||||
|
logger.info('project_rooter_patterns option has been change, clear b:rootDir')
|
||||||
|
fn.setbufvar('%', 'rootDir', '')
|
||||||
|
spacevim_project_rooter_patterns = sp_opt.project_rooter_patterns
|
||||||
|
update_rooter_patterns()
|
||||||
|
end
|
||||||
|
local rootdir = fn.getbufvar('%', 'rootDir', '')
|
||||||
|
-- @bug fn.getbufvar('%', 'rootDir', '') return nil
|
||||||
|
if rootdir == nil or rootdir == '' then
|
||||||
|
rootdir = find_root_directory()
|
||||||
|
if rootdir == nil or rootdir == '' then
|
||||||
|
rootdir = sp_file.unify_path(fn.getcwd())
|
||||||
|
end
|
||||||
|
fn.setbufvar('%', 'rootDir', rootdir)
|
||||||
|
end
|
||||||
|
change_dir(rootdir)
|
||||||
|
M.RootchandgeCallback()
|
||||||
|
return rootdir
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
Loading…
Reference in New Issue
Block a user