diff --git a/.SpaceVim.d/init.vim b/.SpaceVim.d/init.vim
index d50a4842d..4e25bc349 100644
--- a/.SpaceVim.d/init.vim
+++ b/.SpaceVim.d/init.vim
@@ -28,7 +28,7 @@ function! s:language_specified_mappings() abort
         \ 'execute current file', 1)
 endfunction
 call SpaceVim#mapping#space#regesit_lang_mappings('vader', function('s:language_specified_mappings'))
-call SpaceVim#plugins#a#set_config_name('.projections.json')
+call SpaceVim#plugins#a#set_config_name(getcwd(), '.projections.json')
 command! -nargs=1 IssueEdit call SpaceVim#dev#issuemanager#edit(<f-args>)
 command! -nargs=1 PullCreate call SpaceVim#dev#pull#create(<f-args>)
 command! -nargs=1 PullMerge call SpaceVim#dev#pull#merge(<f-args>)
diff --git a/.projections.json b/.projections.json
index 53eff1598..b0541e694 100644
--- a/.projections.json
+++ b/.projections.json
@@ -1,5 +1,8 @@
 {
-  "autoload/SpaceVim/api/*.vim": { "alternate": "test/api/{}.vader" },
+  "autoload/SpaceVim/api/*.vim": {
+      "alternate": "test/api/{}.vader",
+      "doc" : "docs/api/{}.md"
+  },
   "autoload/SpaceVim/plugins/a.vim": { "alternate": "test/plugin/a.vader" },
   "test/plugin/a.vader": { "alternate": "autoload/SpaceVim/plugins/a.vim" },
   "autoload/SpaceVim/layers/lang/*.vim": { "doc": "docs/layers/lang/{}.md" },
diff --git a/autoload/SpaceVim/commands.vim b/autoload/SpaceVim/commands.vim
index b8df0bf0a..f4e22fb36 100644
--- a/autoload/SpaceVim/commands.vim
+++ b/autoload/SpaceVim/commands.vim
@@ -58,6 +58,21 @@ function! SpaceVim#commands#load() abort
   command! -nargs=* SPInstall call SpaceVim#commands#install_plugin(<f-args>)
   command! -nargs=* SPClean call SpaceVim#commands#clean_plugin()
   command! -nargs=0 Report call SpaceVim#issue#new()
+  " Convenient command to see the difference between the current buffer and the
+  " file it was loaded from, thus the changes you made.  Only define it when not
+  " defined already.
+  command! DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
+        \ | wincmd p | diffthis
+  command! -nargs=* -complete=custom,SpaceVim#plugins#complete_plugs Plugin :call SpaceVim#plugins#Plugin(<f-args>)
+  "command for open project
+  command! -nargs=+ -complete=custom,SpaceVim#plugins#projectmanager#complete_project OpenProject :call SpaceVim#plugins#projectmanager#OpenProject(<f-args>)
+
+  command! -nargs=* -complete=custom,SpaceVim#plugins#pmd#complete PMD :call SpaceVim#plugins#pmd#run(<f-args>)
+
+
+  ""
+  " Switch to alternate file based on {type}.
+  command! -nargs=? -complete=custom,SpaceVim#plugins#a#complete -bang A :call SpaceVim#plugins#a#alt(<bang>0,<f-args>)
 endfunction
 
 " @vimlint(EVL103, 1, a:ArgLead)
diff --git a/autoload/SpaceVim/logger.vim b/autoload/SpaceVim/logger.vim
index c4f5783bc..7066d71e9 100644
--- a/autoload/SpaceVim/logger.vim
+++ b/autoload/SpaceVim/logger.vim
@@ -143,6 +143,6 @@ function! s:derive.error(msg) abort
 endfunction
 
 function! SpaceVim#logger#derive(name) abort
-  let s:derive.derive_name = a:name
+  let s:derive.derive_name = printf('%' . strdisplaywidth(s:LOGGER.get_name()) . 'S', a:name)
   return deepcopy(s:derive)
 endfunction
diff --git a/autoload/SpaceVim/plugins/a.vim b/autoload/SpaceVim/plugins/a.vim
index 5baefd246..3d0b20dc7 100644
--- a/autoload/SpaceVim/plugins/a.vim
+++ b/autoload/SpaceVim/plugins/a.vim
@@ -16,8 +16,17 @@ scriptencoding utf-8
 let s:CMP = SpaceVim#api#import('vim#compatible')
 let s:JSON = SpaceVim#api#import('data#json')
 let s:FILE = SpaceVim#api#import('file')
-let s:conf = '.project_alt.json'
-let s:cache_path = g:spacevim_data_dir.'/SpaceVim/a.json'
+let s:LOGGER =SpaceVim#logger#derive('a.vim')
+
+
+" local value
+"
+" s:alternate_conf define which file should be loaded as alternate
+" file configuration for current project, This is a directory
+let s:alternate_conf = {
+      \ '_' : '.project_alt.json'
+      \ }
+let s:cache_path = s:FILE.unify_path(g:spacevim_data_dir, ':p') . 'SpaceVim/a.json'
 
 
 " this is for saving the project configuration information. Use the path of
@@ -32,61 +41,81 @@ function! s:cache() abort
 endfunction
 
 function! s:load_cache() abort
-  let s:project_config = s:JSON.json_decode(join(readfile(s:cache_path, ''), ''))
+  call s:LOGGER.info('Try to load alt cache from: ' . s:cache_path)
+  let cache_context = join(readfile(s:cache_path, ''), '')
+  if !empty(cache_context)
+    let s:project_config = s:JSON.json_decode(cache_context)
+  endif
 endfunction
 
 
 
 " when this function is called, the project_config file name is changed, and
 " the project_config info is cleared.
-function! SpaceVim#plugins#a#set_config_name(name) abort
-  let s:conf = a:name
-  let s:project_config = {}
+function! SpaceVim#plugins#a#set_config_name(path, name) abort
+  let s:alternate_conf[a:path] = a:name
 endfunction
 
 function! s:get_project_config(conf_file) abort
-  let project_config_conf = get(b:, 'project_alt_json', {})
-  if !empty(project_config_conf)
-    return project_config_conf
-  endif
-  return s:JSON.json_decode(join(readfile(a:conf_file), "\n"))
+  let conf = s:JSON.json_decode(join(readfile(a:conf_file), "\n"))
+  let root = s:FILE.unify_path(a:conf_file, ':p:h')
+  return {
+        \ 'root' : root,
+        \ 'config' : conf
+        \ }
 endfunction
 
 function! SpaceVim#plugins#a#alt(request_paser,...) abort
   let type = get(a:000, 0, 'alternate')
-  let conf_file_path = s:FILE.unify_path(s:conf, ':p')
+  let conf_file_path = s:FILE.unify_path(get(s:alternate_conf, getcwd(), '_'), ':p')
   let file = s:FILE.unify_path(bufname('%'), ':.')
   let alt = SpaceVim#plugins#a#get_alt(file, conf_file_path, a:request_paser, type)
   if !empty(alt)
     exe 'e ' . alt
+  else
+    echo 'failed to find alternate file!'
   endif
 endfunction
 
-function! s:paser(conf, root) abort
-  for key in keys(a:conf)
+
+" the paser function should only accept one argv
+" the alt_config_json
+"
+" @todo Rewrite alternate file paser
+" paser function is written in vim script, and it is too slow,
+" we are going to rewrite this function in other language.
+" asynchronous paser should be supported.
+function! s:paser(alt_config_json) abort
+  call s:LOGGER.info('Start to paser alternate files for: ' . a:alt_config_json.root)
+  let s:project_config[a:alt_config_json.root] = {}
+  for key in keys(a:alt_config_json.config)
     let searchpath = key
-    if match(key, '/\*')
-      let searchpath = substitute(key, '*', '**/*', 'g')
+    if match(searchpath, '/\*')
+      let searchpath = substitute(searchpath, '*', '**/*', 'g')
     endif
     for file in s:CMP.globpath('.', searchpath)
       let file = s:FILE.unify_path(file, ':.')
-      let s:project_config[a:root][file] = {}
-      if has_key(a:conf, file)
-        for type in keys(a:conf[file])
-          if len(begin_end) == 2
-            let s:project_config[a:root][file][type] = a:conf[key][type]
-          endif
+      let s:project_config[a:alt_config_json.root][file] = {}
+      if has_key(a:alt_config_json.config, file)
+        for type in keys(a:alt_config_json.config[file])
+          let s:project_config[a:alt_config_json.root][file][type] = a:alt_config_json.config[file][type]
         endfor
       else
-        for type in keys(a:conf[key])
+        for type in keys(a:alt_config_json.config[key])
           let begin_end = split(key, '*')
           if len(begin_end) == 2
-            let s:project_config[a:root][file][type] = s:get_type_path(begin_end, file, a:conf[key][type])
+            let s:project_config[a:alt_config_json.root][file][type] =
+                  \ s:get_type_path(
+                  \ begin_end,
+                  \ file,
+                  \ a:alt_config_json.config[key][type]
+                  \ )
           endif
         endfor
       endif
     endfor
   endfor
+  call s:LOGGER.info('Paser done, try to cache alternate info')
   call s:cache()
 endfunction
 
@@ -100,37 +129,63 @@ function! s:get_type_path(a, f, b) abort
   return substitute(a:b, '{}', a:f[begin_len : (end_len+1) * -1], 'g')
 endfunction
 
-function! SpaceVim#plugins#a#get_alt(file, conf_path, request_paser,...) abort
-  if getftime(a:conf_path) < getftime(s:cache_path)
+function! s:is_config_changed(conf_path) abort
+  if getftime(a:conf_path) > getftime(s:cache_path)
+    call s:LOGGER.info('alt config file ('
+          \ . a:conf_path
+          \ . ') has been changed, paser required!')
+    return 1
   endif
-  if a:request_paser || !has_key(s:project_config, a:conf_path)
-    let altconfa = s:get_project_config(a:conf_path)
-    let s:project_config[a:conf_path] = {}
-    call s:paser(altconfa, a:conf_path)
+endfunction
+
+function! SpaceVim#plugins#a#get_alt(file, conf_path, request_paser,...) abort
+  call s:LOGGER.info('getting alt file for:' . a:file)
+  call s:LOGGER.info('  >   type: ' . get(a:000, 0, 'alternate'))
+  call s:LOGGER.info('  >  paser: ' . a:request_paser)
+  call s:LOGGER.info('  > config: ' . a:conf_path)
+  " @question when should the cache be loaded?
+  " if the local value s:project_config do not has the key a:conf_path
+  " and the file a:conf_path has not been updated since last cache
+  " and no request_paser specified
+  let alt_config_json = s:get_project_config(a:conf_path)
+  if !has_key(s:project_config, alt_config_json.root)
+        \ && !s:is_config_changed(a:conf_path)
+        \ && !a:request_paser
+    " config file has been cached since last update.
+    " so no need to paser the config for current config file
+    " just load the cache
+    call s:load_cache()
+    if !has_key(s:project_config, alt_config_json.root)
+          \ || !has_key(s:project_config[alt_config_json.root], a:file)
+      call s:paser(alt_config_json)
+    endif
+  else
+    call s:paser(alt_config_json)
   endif
   try
-    return s:project_config[a:conf_path][a:file][get(a:000, 0, 'alternate')]
+    return s:project_config[alt_config_json.root][a:file][get(a:000, 0, 'alternate')]
   catch
     return ''
   endtry
 endfunction
 
+function! s:get_alternate(file) abort
 
-function! SpaceVim#plugins#a#get_root() abort
-  return s:FILE.unify_path(s:conf, ':p')
+endfunction
+
+
+function! SpaceVim#plugins#a#getConfigPath() abort
+  return s:FILE.unify_path(get(s:alternate_conf, getcwd(), '_'), ':p')
 endfunction
 
 function! SpaceVim#plugins#a#complete(ArgLead, CmdLine, CursorPos) abort
   let file = s:FILE.unify_path(bufname('%'), ':.')
-  let conf = s:FILE.unify_path(s:conf, ':p')
+  let conf_file_path = s:FILE.unify_path(get(s:alternate_conf, getcwd(), '_'), ':p')
+  let alt_config_json = s:get_project_config(conf_file_path)
 
-  if !has_key(s:project_config, conf )
-    let altconfa = s:get_project_config(conf)
-    let s:project_config[conf] = {}
-    call s:paser(altconfa, conf)
-  endif
+  call SpaceVim#plugins#a#get_alt(file, conf_file_path, 0)
   try
-    let a = s:project_config[s:FILE.unify_path(s:conf, ':p')][file]
+    let a = s:project_config[alt_config_json.root][file]
   catch
     let a = {}
   endtry
diff --git a/autoload/SpaceVim/plugins/flygrep.vim b/autoload/SpaceVim/plugins/flygrep.vim
index 54b13cdcf..2328343c2 100644
--- a/autoload/SpaceVim/plugins/flygrep.vim
+++ b/autoload/SpaceVim/plugins/flygrep.vim
@@ -14,7 +14,7 @@ let s:SYS = SpaceVim#api#import('system')
 let s:BUFFER = SpaceVim#api#import('vim#buffer')
 let s:LIST = SpaceVim#api#import('data#list')
 
-let s:LOGGER =SpaceVim#logger#derive('flygrep ')
+let s:LOGGER =SpaceVim#logger#derive('FlyGrep')
 let s:HI = SpaceVim#api#import('vim#highlight')
 if has('nvim')
   let s:FLOATING = SpaceVim#api#import('neovim#floating')
@@ -88,7 +88,7 @@ function! s:grep_timer(timer) abort
         \ })
   " sometimes the flygrep command failed to run, so we need to log the jobid
   " of the grep command.
-  call SpaceVim#logger#info('flygrep job id is: ' . string(s:grepid))
+  call s:LOGGER.info('flygrep job id is: ' . string(s:grepid))
 endfunction
 
 function! s:get_search_cmd(expr) abort
@@ -833,22 +833,22 @@ function! SpaceVim#plugins#flygrep#open(argv) abort
   let s:grep_ignore_case = get(a:argv, 'ignore_case', s:grep_default_ignore_case)
   let s:grep_smart_case  = get(a:argv, 'smart_case', s:grep_default_smart_case)
   let s:grep_expr_opt  = get(a:argv, 'expr_opt', s:grep_default_expr_opt)
-  call SpaceVim#logger#info('FlyGrep startting ===========================')
-  call SpaceVim#logger#info('   executable    : ' . s:grep_exe)
-  call SpaceVim#logger#info('   option        : ' . string(s:grep_opt))
-  call SpaceVim#logger#info('   r_option      : ' . string(s:grep_ropt))
-  call SpaceVim#logger#info('   files         : ' . string(s:grep_files))
-  call SpaceVim#logger#info('   dir           : ' . string(s:grep_dir))
-  call SpaceVim#logger#info('   ignore_case   : ' . string(s:grep_ignore_case))
-  call SpaceVim#logger#info('   smart_case    : ' . string(s:grep_smart_case))
-  call SpaceVim#logger#info('   expr opt      : ' . string(s:grep_expr_opt))
+  call s:LOGGER.info('FlyGrep startting ===========================')
+  call s:LOGGER.info('   executable    : ' . s:grep_exe)
+  call s:LOGGER.info('   option        : ' . string(s:grep_opt))
+  call s:LOGGER.info('   r_option      : ' . string(s:grep_ropt))
+  call s:LOGGER.info('   files         : ' . string(s:grep_files))
+  call s:LOGGER.info('   dir           : ' . string(s:grep_dir))
+  call s:LOGGER.info('   ignore_case   : ' . string(s:grep_ignore_case))
+  call s:LOGGER.info('   smart_case    : ' . string(s:grep_smart_case))
+  call s:LOGGER.info('   expr opt      : ' . string(s:grep_expr_opt))
   " sometimes user can not see the flygrep windows, redraw only once.
   redraw
   call s:MPT.open()
   if s:SL.support_float()
     call s:close_statusline()
   endif
-  call SpaceVim#logger#info('FlyGrep ending    ===========================')
+  call s:LOGGER.info('FlyGrep ending    ===========================')
   let &t_ve = save_tve
   if has('gui_running')
     call s:HI.hi(cursor_hi)
diff --git a/config/commands.vim b/config/commands.vim
deleted file mode 100644
index 943ac7b7d..000000000
--- a/config/commands.vim
+++ /dev/null
@@ -1,12 +0,0 @@
-" Convenient command to see the difference between the current buffer and the
-" file it was loaded from, thus the changes you made.  Only define it when not
-" defined already.
-command! DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
-            \ | wincmd p | diffthis
-command! -nargs=* -complete=custom,SpaceVim#plugins#complete_plugs Plugin :call SpaceVim#plugins#Plugin(<f-args>)
-"command for open project
-command! -nargs=+ -complete=custom,SpaceVim#plugins#projectmanager#complete_project OpenProject :call SpaceVim#plugins#projectmanager#OpenProject(<f-args>)
-
-command! -nargs=* -complete=custom,SpaceVim#plugins#pmd#complete PMD :call SpaceVim#plugins#pmd#run(<f-args>)
-
-command! -nargs=? -complete=custom,SpaceVim#plugins#a#complete -bang A :call SpaceVim#plugins#a#alt(<bang>0,<f-args>)
diff --git a/doc/SpaceVim.txt b/doc/SpaceVim.txt
index c682e1e9d..45c890ca4 100644
--- a/doc/SpaceVim.txt
+++ b/doc/SpaceVim.txt
@@ -1258,6 +1258,9 @@ COMMANDS                                                   *SpaceVim-commands*
 :SPInstall                                                        *:SPInstall*
   Command for install plugins.
 
+:A[!] {type}                                                              *:A*
+  Switch to alternate file based on {type}.
+
 ==============================================================================
 FUNCTIONS                                                 *SpaceVim-functions*
 
diff --git a/docs/api/cmdlinemenu.md b/docs/api/cmdlinemenu.md
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/cn/api/cmdlinemenu.md b/docs/cn/api/cmdlinemenu.md
new file mode 100644
index 000000000..d8dfbb0c8
--- /dev/null
+++ b/docs/cn/api/cmdlinemenu.md
@@ -0,0 +1,20 @@
+---
+title: "cmdlinemenu 函数"
+description: "cmdlinemenu 函数提供了基础的文件读写相关函数,兼容不同系统平台。"
+lang: zh
+---
+
+# [公共 API](../) >> cmdlinemenu
+
+
+<!-- vim-markdown-toc GFM -->
+
+- [简介](#简介)
+
+<!-- vim-markdown-toc -->
+
+## 简介
+
+文件函数提供了基础的文件读写相关函数,兼容不同系统平台。
+
+
diff --git a/test/plugin/a.vader b/test/plugin/a.vader
index d98c24019..fb62bd5cc 100644
--- a/test/plugin/a.vader
+++ b/test/plugin/a.vader
@@ -1,6 +1,6 @@
 Execute ( SpaceVim plugin: a.vim ):
-  call SpaceVim#plugins#a#set_config_name('.projections.json')
-  let root = SpaceVim#plugins#a#get_root()
+  call SpaceVim#plugins#a#set_config_name(getcwd(), '.projections.json')
+  let root = SpaceVim#plugins#a#getConfigPath()
   AssertEqual SpaceVim#plugins#a#get_alt('docs/index.md', root, 1), 'docs/cn/index.md'
   AssertEqual SpaceVim#plugins#a#get_alt('docs/cn/index.md', root, 1), 'docs/index.md'
   AssertEqual SpaceVim#plugins#a#get_alt('docs/api/job.md', root, 1), 'docs/cn/api/job.md'