diff --git a/README.md b/README.md
index c1c6fdd..a30a5a5 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,397 @@
+
+
+
+
+> Choose what you want to know! 😼
+
+```vim
+" Open menu
+:CodeQueryMenu Unite Full
+
+" Or query directly
+:CodeQuery Definition get_user_id
+```
+
+
+
# vim-codequery
+
+This Vim plugin is built on top of the great tool [CodeQuery](https://github.com/ruben2020/codequery) created by ruben2020, and aims at providing three primary functions to help you to:
+
+1. **Search source code gracefully within Vim**.
+ * You can find: `definition, call, caller, callee, symbol, class, parent, child` and more for a string.
+ * Convenient menus are created for you.
+ * Well-formated results are shown in a custom Quickfix window with usable key bindings.
+ * Support asynchronous search (Vim version >= 8.0)
+2. **Manage your database easily**.
+ * Load, make and move your database file by custom Vim commands.
+ * Support asynchronous build (Vim version >= 8.0 or NeoVim or by `Dispatch` plugin)
+ * `Note: CodeQuery's SQLite database is built on top of ctags and cscope.`
+3. **Know your code more instantly**.
+ * (TBD)
+
+
-This plugin is build on top of the great tool [CodeQuery](https://github.com/ruben2020/codequery) created by ruben2020, and aims at providing three primary functions to help you to:
+## Supported languages
+ * [x] `Python` 😎
+ * [x] `Javascript`
+ * [x] `Ruby`
+ * [x] `Go`
+ * [x] `Java`
+ * [x] `C, C++`
-1. Do CodeQuery-liked queries. (70% Done, Need to fix some bugs)
-2. Manage your database. (TBD, Release Date: Mid-August)
-3. "Know" your code instantly. (TBD, Release Date: September)
+
-## Status: Don't Install Me !
+## Demo
-**This project is still under development.**
-Completeness: 30%
+`Choose a query from menu ➙ Get results`
-## Demo
+
-## Usage
+`... ➙ Switch to different query ➙ Get results ... ➙ Filter them ➙ Get Results ➙ Undo ➙ Redo`
+
+
+
+[more demo and screenshots](https://github.com/devjoe/vim-codequery/wiki/Screenshots-and-Demo)
+
+```
+These videos are quite old.
+Now vim-codequery works better than what you see by using Vim8's async feature.
+```
+
+
+## Schedule
+> **This project is released.**
+>
+> Main TODO:
+> * ~~Use Vim8's new features to enhance usability.~~
+> * ~~Do lazy-loading.~~
+> * ~~Enhance usability.~~
+> * ~~Test it.~~
+> * ~~Support NeoVim at a certain level.~~
+> * Add **explain** command in v1.0.0
+> * Make UI be optional
+> * Doc it.
+>
+> Current Version: v0.9.2
+>
+> Welcome to try it! 👌
+
+
+
## Installation
+#### 1. Make sure these commands are in your system
+
+/bin/sh echo mkdir mv cut find awk stat git(optional)
+
+
+#### 2. Install CodeQuery
+* Linux => Install [binaries](https://sourceforge.net/projects/codequery/files/) or [build it](https://github.com/ruben2020/codequery/blob/master/doc/INSTALL-LINUX.md).
+* Mac => `brew install codequery` 🍺 (make sure codequery version >= v0.17.0)
+
+#### 3. Install additional ctags/cscope tools for your languages
+| Language | Tools | How to install |
+| --- | --- | --- |
+| Python | [PyCscope](https://github.com/portante/pycscope) | `sudo pip install pycscope` |
+| Javascript | [Starscope](https://github.com/eapache/starscope) | `sudo gem install starscope` |
+| Ruby | [Starscope](https://github.com/eapache/starscope) | `sudo gem install starscope` |
+| Go | [Starscope](https://github.com/eapache/starscope) | `sudo gem install starscope` |
+
+> `Java`, `C` and `C++` users do not need to install additional ctags/cscope tools.
+> Starscope has been [packaged for Arch Linux](https://aur.archlinux.org/packages/ruby-starscope/)
+
+#### 4. Install Vim plugins
+* Use your favorite plugins manager: [pathogen](https://github.com/tpope/vim-pathogen), [Vundle](https://github.com/VundleVim/Vundle.vim), [Plug](https://github.com/junegunn/vim-plug), [NeoBundle](https://github.com/Shougo/neobundle.vim), [Dein](https://github.com/Shougo/dein.vim), ...
+* Take Plug as an example:
+```vim
+" Required
+Plug 'Shougo/unite.vim'
+Plug 'devjoe/vim-codequery'
+
+" Optional
+" if your vim version < 8.0
+Plug 'tpope/vim-dispatch'
+" if you don't have an :Ack (or :Ag) liked command
+Plug 'mileszs/ack.vim'
+```
+* In case you prefer to use Vim8's native package manager to manage plugins manually. Here comes an installation guide for that:
+ 1. Go to `~/.vim`
+ 2. Run `mkdir -p pack/vim-codequery/start/` and then go to `start` directory
+ 3. Run `git clone https://github.com/devjoe/vim-codequery` to get latest vim-codequery code
+ 4. It's done. 😎 Now `vim-codequery` will be loaded when your Vim starts. You can install [unite](https://github.com/Shougo/unite.vim) in the same way
+ 5. Learn more about Vim8's package system by typing `:help package | only`
+
+
+
+## Usage
+
+#### 1. Setup
+
+* Go to the (git) root directory of your project. Open vim and type:
+```vim
+" Index Python files
+:CodeQueryMakeDB python
+
+" Or index Python + Javascript files
+:CodeQueryMakeDB python javascript
+```
+* That's all. `python.db`, `javascript.db` ... will be created in the root directory.
+* It's recommended that you should use `:CodeQueryMoveDBToGitDir python` to hide the DB file to `.git/codequery/` directory. If you do so, next time you can call `:CodeQueryMakeDB` directly in any opened Python buffer to rebuild the DB file.
+
+
+#### 2. Search
+* **Find symbol under your cursor**
+
+```vim
+:CodeQuery
+```
+
+* **Find word (by subcommands) under your cursor**
+
+```vim
+:CodeQuery [SubCommand]
+
+" Supported SubCommands are: `Symbol, Text, Call, Caller, Callee, Class, Parent, Child, Member, FunctionList, FileImporter`.
+```
+
+* **Find arbitrary word**
+
+```vim
+:CodeQuery [SubCommand] [word]
+```
+
+* **Find again with the same word**
+
+```vim
+:CodeQueryAgain [SubCommand]
+```
+
+* **Use fuzzy Option**
+
+```vim
+:CodeQuery [SubCommand] [word] -f
+
+" [word] can be: get_* or *user_info or find_*_by_id
+```
+
+* **Use append Option** (results will be added to the current Quickfix)
+
+```vim
+:CodeQuery [SubCommand] [word] -a
+```
+
+* **Filter Search Results**
+
+```vim
+:CodeQueryFilter [string]
+
+" [string] can be a regex
+```
+
+#### 3. Use Quickfix
+* **Move your cursor inside Quickfix window to use these key bindings**
+
+| Key | Action | Note |
+| --- | --- | --- |
+| s | `:CodeQueryAgain Symbol` | |
+| x | `:CodeQueryAgain Text` | use `:Ack!` by default. #1 |
+| c | `:CodeQueryAgain Call` | |
+| r | `:CodeQueryAgain Caller` | |
+| e | `:CodeQueryAgain Callee` | |
+| d | `:CodeQueryAgain Definition` | |
+| C | `:CodeQueryAgain Class` | |
+| M | `:CodeQueryAgain Member` | |
+| P | `:CodeQueryAgain Parent` | |
+| D | `:CodeQueryAgain Child` | |
+| m | `:CodeQueryMenu Unite Magic` | |
+| q | `:cclose` | |
+| \ | `:CodeQueryFilter` | |
+| p | `p` | Preview |
+| u | `:colder \| CodeQueryShowQF` | Older Quickfix Result |
+| \ | `:cnewer \| CodeQueryShowQF` | Newer Quickfix Result |
+
+> #1
+> You can override `g:codequery_find_text_cmd` to change it.
+
+* **Show Quickfix with above key bindings**
+
+```vim
+:CodeQueryShowQF
+
+" This command can also be used to **patch** standard Quickfix.
+```
+
+#### 4. Open Menu
+
+Currently, vim-codequery only provides [Unite](https://github.com/Shougo/unite.vim) menu because I love it ⭐. There are two types of menu:
+
+* **Full Unite menu**
+
+```vim
+:CodeQueryMenu Unite Full
+
+" The string between :: and :: is the word under cursor
+" [F] means this action is for 'function variable only'
+" [C] is for 'class variable only'
+```
+
+
+* **Magic Unite menu**
+
+```vim
+:CodeQueryMenu Unite Magic
+
+" This menu changes dynamically:
+" 1. If the word under your cursor begins with a capital letter (possible be class): show [C] actions
+" 2. Vice versa (possible be function): show [F] actions
+" 3. Show reasonable actions within Quickfix
+```
+
+
+
+
## Tips
+#### Open Menu
+```vim
+nnoremap c :CodeQueryMenu Unite Full
+nnoremap ; :CodeQueryMenu Unite Magic
+
+" Or enable typing (to search menu items) by default
+nnoremap \ :CodeQueryMenu Unite MagicA
+```
+
+#### Query
+```vim
+nnoremap :CodeQuery Symbol
+
+" Chain commands to find possible tests (for python)
+nnoremap t :CodeQuery Caller:CodeQueryFilter test_
+```
+
+#### Filter
+```vim
+" Filter reversely by adding '!'
+:CodeQueryFilter ! [word]
+```
+
+#### Build
+```vim
+" Trigger db building (in current filetype) when your query fails
+let g:codequery_trigger_build_db_when_db_not_found = 1
+```
+
+#### Find Text
+```vim
+" Custom your `CodeQuery Text` commands
+let g:codequery_find_text_cmd = 'Ack!'
+
+let g:codequery_find_text_from_current_file_dir = 0
+" 0 => search from project dir (git root directory -> then the directory containing xxx.db file)
+" 1 => search from the directory containing current file
+
+" If you use ':CodeQuery Symbol' in a txt file, of course, it will fail due to wrong filetype.
+" With the following option set to 1, ':CodeQuery Text' will be automatically sent when your query fails.
+let g:codequery_auto_switch_to_find_text_for_wrong_filetype = 0
+```
+
+#### Load Ctags File
+```vim
+" Set tags option
+set tags=./javascript_tags;/
+set tags+=./python_tags;/
+set tags+=./ruby_tags;/
+set tags+=./go_tags;/
+set tags+=./java_tags;/
+set tags+=./c_tags;/
+```
+
+#### Clean Ctags, Cscope ... Files by Languages
+```vim
+let g:codequery_enable_auto_clean_languages = ['python']
+
+" It accpepts a list of your languages written in lowercase
+```
+
+#### Custom Database Building
+```vim
+" Make sure to generate a python.db or xxxx.db file as a result
+let g:codequery_build_python_db_cmd = '...'
+let g:codequery_build_javascript_db_cmd = '...'
+let g:codequery_build_ruby_db_cmd = '...'
+let g:codequery_build_go_db_cmd = '...'
+let g:codequery_build_java_db_cmd = '...'
+let g:codequery_build_c_db_cmd = '...'
+```
+
+
+#### Others
+```vim
+" You can disable key binding within quickfix
+let g:codequery_disable_qf_key_bindings = 1
+
+" if your function usually begins with a capital letter ..., you can change your magic menu to a not-so-magic one
+let g:codequery_enable_not_so_magic_menu = 1
+```
+
+
+
+## FAQ
+
+#### Why writing this plugin?
+
+> Because I need it.
+>
+> I already shared the story of making this plugin in local Python user groups [Taipei.py](http://www.meetup.com/Taipei-py/) and [Tainan.py](http://www.meetup.com/Tainan-py-Python-Tainan-User-Group/).
+> Slides are available here: [Taipei.py](http://www.slideshare.net/excusemejoe/joe-vim-plugin-taipeipy20160825) / [Tainan.py](http://www.slideshare.net/excusemejoe/vim-plugin-20160827) (Language: Traditional Chinese)
+
+#### Why not using Ctags or Cscope directly?
+
+> Read what @ruben2020 the author of CodeQuery said: [Link](https://github.com/ruben2020/codequery#how-is-it-different-from-cscope-and-ctags-what-are-the-advantages)
+>
+> In addittion, vim-codequery provides:
+>
+> 1. Good interface.
+> 2. Separated Database Management Mechanism.
+> (You can open as many projects as you wish in a single Vim session without worrying about messing up Ctags or Cscope files or getting wrong result!)
+>
+> for Vim users.
+
+#### More Questions
+
+> Ask [here](https://docs.google.com/document/d/1gIvP9wrp1i3xLPDEKNVy76gUeYt1QkIUoqSvJDEbOfM/edit?usp=sharing) or create an issue.
+
+
+
+## How to Contribute
+#### Use It
+
+#### Fork It
+
+> And give me PR. It would be better if you open an [issue](https://github.com/devjoe/vim-codequery/issues) and discuss with me before sending PR.
+
+#### Star It
+
+> If you like it. 👍
+
+
+
+## Contributors
+* [devjoe](https://github.com/devjoe)
+* [johnzeng](https://github.com/johnzeng)
+* [syslot](https://github.com/syslot)
+
+
+
+## Credits
+
+Thank all for working on these great projects!
+
+* [CodeQuery](https://github.com/ruben2020/codequery)
+* [Starscope](https://github.com/eapache/starscope)
+* [PyCscope](https://github.com/portante/pycscope)
+* [Unite.vim](https://github.com/Shougo/unite.vim)
+* [dispatch.vim](https://github.com/tpope/vim-dispatch)
+* [ack.vim](https://github.com/mileszs/ack.vim)
+* [vim-addon-qf-layout](https://github.com/MarcWeber/vim-addon-qf-layout)
diff --git a/autoload/codequery.vim b/autoload/codequery.vim
new file mode 100644
index 0000000..e267ec8
--- /dev/null
+++ b/autoload/codequery.vim
@@ -0,0 +1,287 @@
+" =============================================================================
+" Helpers
+
+
+let g:c_family_filetype_list =
+ \ ['c', 'h', 'cpp', 'cxx', 'cc', 'hpp', 'hxx', 'hh']
+
+
+let g:codequery_supported_filetype_list = g:c_family_filetype_list +
+ \ ['python', 'javascript', 'go', 'ruby', 'java', 'c', 'cpp']
+
+
+let s:menu_subcommands = [ 'Unite' ]
+
+
+function! s:check_filetype(filetype) abort
+ if index(g:codequery_supported_filetype_list, a:filetype) == -1
+ return 0
+ endif
+ return 1
+endfunction
+
+
+function! s:set_db() abort
+ let path = codequery#db#find_db_path(&filetype)
+ if empty(path)
+ echom 'CodeQuery DB Not Found'
+ return 0
+ endif
+
+ let g:codequery_db_path = path
+ return 1
+endfunction
+
+
+function! s:save_cwd() abort
+ let g:codequery_cwd = getcwd()
+endfunction
+
+
+function! s:restore_cwd()
+ execute 'lcd ' . g:codequery_cwd
+ let g:codequery_cwd = ''
+endfunction
+
+
+
+" =============================================================================
+" Entries
+
+
+function! codequery#run_codequery(args) abort
+ call s:save_cwd()
+ if !s:check_filetype(&filetype)
+ echom 'Not Supported Filetype: ' . &filetype
+ if g:codequery_auto_switch_to_find_text_for_wrong_filetype
+ silent execute g:codequery_find_text_cmd
+ call codequery#query#prettify_qf_layout_and_map_keys(getqflist())
+ endif
+ return
+ endif
+
+ let g:codequery_last_query_word = ''
+ let g:codequery_fuzzy = 0
+ let g:codequery_append_to_qf = 0
+ let g:codequery_querytype = 1
+ let g:codequery_db_path = ''
+ if !s:set_db()
+ call s:restore_cwd()
+ if g:codequery_trigger_build_db_when_db_not_found
+ execute 'CodeQueryMakeDB ' . &filetype
+ endif
+ return
+ endif
+
+ let args = split(a:args, ' ')
+ let args_num = len(args)
+ let cword = codequery#query#get_valid_cursor_word()
+
+ if args_num == 0
+ call codequery#query#do_query(cword)
+
+ elseif index(g:codequery_subcommands, args[0]) != -1
+ call codequery#query#set_options(args)
+ let iword = codequery#query#get_valid_input_word(args)
+ let word = codequery#query#get_final_query_word(iword, cword)
+ if empty(word)
+ echom 'Invalid Args: ' . a:args
+ call s:restore_cwd()
+ return
+ endif
+
+ call codequery#query#do_query(word)
+ else
+ echom 'Wrong Subcommand !'
+ endif
+ call s:restore_cwd()
+endfunction
+
+
+function! codequery#make_codequery_db(args) abort
+ call s:save_cwd()
+ let args = split(a:args, ' ')
+ if empty(args)
+ let args = [&filetype]
+ endif
+
+ for ft in args
+ if !s:check_filetype(ft)
+ echom 'Not Supported Filetype: ' . ft
+ continue
+ endif
+
+ let db_path = codequery#db#find_db_path(ft)
+ if empty(db_path)
+ if index(g:c_family_filetype_list, ft) != -1
+ let db_path = 'c_family.db'
+ else
+ let db_path = ft . '.db'
+ endif
+ endif
+
+ if ft ==? 'python'
+ let shell_cmd = codequery#db#construct_python_db_build_cmd(db_path)
+ elseif ft ==? 'javascript'
+ let shell_cmd = codequery#db#construct_javascript_db_build_cmd(db_path)
+ elseif ft ==? 'ruby'
+ let shell_cmd = codequery#db#construct_ruby_db_build_cmd(db_path)
+ elseif ft ==? 'go'
+ let shell_cmd = codequery#db#construct_go_db_build_cmd(db_path)
+ elseif ft ==? 'java'
+ let shell_cmd = codequery#db#construct_java_db_build_cmd(db_path)
+ elseif index(g:c_family_filetype_list, ft) != -1
+ let shell_cmd = codequery#db#construct_c_db_build_cmd(db_path)
+ else
+ echom 'No Command For Building .' . ft . ' file'
+ continue
+ endif
+
+ if has('nvim')
+ echom 'Making DB ...'
+ let mydict = {'db_path': db_path,
+ \'callback': function("codequery#db#make_db_nvim_callback")}
+ let callbacks = {'on_exit': mydict.callback}
+ let s:build_job = jobstart(['/bin/sh', '-c', shell_cmd], callbacks)
+ elseif v:version >= 800
+ echom 'Making DB ...'
+ let mydict = {'db_path': db_path,
+ \'callback': function("codequery#db#make_db_callback")}
+ let options = {'out_io': 'null',
+ \'exit_cb': mydict.callback}
+ let s:build_job = job_start(['/bin/sh', '-c', shell_cmd], options)
+ let timer = timer_start(500,
+ \{-> execute("call job_status(s:build_job)","")},
+ \{'repeat': 60})
+ elseif exists(':Start')
+ silent execute 'Start! -title=Make_CodeQuery_DB -wait=error ' . shell_cmd
+ redraw!
+ echom 'Making ... ' . db_path ' => Run :CodeQueryViewDB to Check Status'
+ else
+ silent execute '!' . shell_cmd
+ redraw!
+ endif
+ endfor
+ call s:restore_cwd()
+endfunction
+
+
+function! codequery#view_codequery_db(args) abort
+ call s:save_cwd()
+ let args = split(a:args, ' ')
+ if empty(args)
+ let args = [&filetype]
+ endif
+
+ for ft in args
+ if !s:check_filetype(ft)
+ echom 'Not Supported Filetype: ' . ft
+ continue
+ endif
+
+ let db_path = codequery#db#find_db_path(ft)
+ if empty(db_path)
+ if index(g:c_family_filetype_list, ft) != -1
+ execute '!echo "\n(c family) DB Not Found"'
+ else
+ execute '!echo "\n(' . ft . ') DB Not Found"'
+ endif
+ continue
+ endif
+
+ execute '!echo "\n(' . db_path . ') is update at: " && stat -f "\%Sm" ' . db_path
+ endfor
+ call s:restore_cwd()
+endfunction
+
+
+function! codequery#move_codequery_db_to_git_hidden_dir(args) abort
+ call s:save_cwd()
+ let args = split(a:args, ' ')
+ if empty(args)
+ let args = [&filetype]
+ endif
+
+ for ft in args
+ if index(g:c_family_filetype_list, ft) != -1
+ let db_name = 'c_family.db'
+ else
+ let db_name = ft . '.db'
+ endif
+ let git_root_dir = systemlist('git rev-parse --show-toplevel')[0]
+ let db_path = codequery#db#find_db_path(ft)
+
+ if !v:shell_error && !empty(db_path)
+ let new_db_path = git_root_dir . '/.git/codequery/' . db_name
+ call system('mkdir -p ' . git_root_dir . '/.git/codequery/')
+ call system('mv ' . db_path . ' ' . new_db_path)
+ echom 'Done (' . db_name . ')'
+ else
+ echom 'Git Dir Not Found or (' . db_name . ') Not Found'
+ endif
+ endfor
+ call s:restore_cwd()
+endfunction
+
+
+function! codequery#show_menu(args) abort
+ let args = split(a:args, ' ')
+ let args_num = len(args)
+
+ if args_num > 0 && index(s:menu_subcommands, args[0]) != -1
+ if args[0] ==# 'Unite'
+ if args_num > 1 && args[1] ==# 'Magic'
+ let magic_menu = 1
+ else
+ let magic_menu = 0
+ endif
+ call codequery#menu#use_unite_menu(magic_menu)
+ return
+ endif
+ endif
+
+ echom 'Wrong Subcommands! Try: ' . join(s:menu_subcommands, ', ')
+endfunction
+
+
+function! codequery#run_codequery_again_with_different_subcmd(args) abort
+ let args = split(a:args, ' ')
+ let args_num = len(args)
+ if !empty(g:codequery_last_query_word) && args_num > 0
+ cclose
+ let again_cmd = 'CodeQuery ' . args[0] . ' ' . g:codequery_last_query_word . ' '
+ \ . (g:last_query_fuzzy ? '-f' : '')
+ execute again_cmd
+ else
+ echom 'Wrong Subcommands!'
+ endif
+endfunction
+
+
+" modify from someone's .vimrc
+function! codequery#filter_qf_results(args) abort
+ let args = split(a:args, ' ')
+ if len(args) > 1
+ let query = args[1]
+ let reverse_filter = 1
+ else
+ let query = args[0]
+ let reverse_filter = 0
+ endif
+ echom query
+
+ let results = getqflist()
+ for d in results
+ if reverse_filter
+ if bufname(d['bufnr']) =~ query || d['text'] =~ query
+ call remove(results, index(results, d))
+ endif
+ else
+ if bufname(d['bufnr']) !~ query && d['text'] !~ query
+ call remove(results, index(results, d))
+ endif
+ endif
+ endfor
+ call setqflist(results)
+ call codequery#query#prettify_qf_layout_and_map_keys(results)
+endfunction
diff --git a/autoload/codequery/db.vim b/autoload/codequery/db.vim
new file mode 100644
index 0000000..0534810
--- /dev/null
+++ b/autoload/codequery/db.vim
@@ -0,0 +1,164 @@
+" =============================================================================
+" Entries
+
+
+" `lcd` brings side effect !!
+function! codequery#db#find_db_path(filetype) abort
+ if index(g:c_family_filetype_list, a:filetype) != -1
+ let db_name = 'c_family.db'
+ else
+ let db_name = a:filetype . '.db'
+ endif
+
+ let lookup_path = findfile(expand('%:p:h') . '/' . db_name, '.')
+
+ if !empty(lookup_path)
+ lcd %:p:h
+ return lookup_path
+ endif
+
+ lcd %:p:h
+ let git_root_dir = systemlist('git rev-parse --show-toplevel')[0]
+ if !v:shell_error
+ let lookup_path = findfile(git_root_dir . '/' . db_name, '.')
+ if !empty(lookup_path)
+ execute 'lcd ' . git_root_dir
+ return lookup_path
+ else
+ let lookup_path = findfile(git_root_dir . '/.git/codequery/' .
+ \ db_name, '.')
+ if !empty(lookup_path)
+ execute 'lcd ' . git_root_dir
+ return lookup_path
+ endif
+ endif
+ endif
+endfunction
+
+
+function! codequery#db#make_db_callback(job, status) dict
+ echom 'Done! (' . self.db_path . ')'
+endfunction
+
+
+function! codequery#db#make_db_nvim_callback(job, data, status) dict
+ echom 'Done! Built codequery db!'
+endfunction
+
+
+function! codequery#db#construct_python_db_build_cmd(db_path) abort
+ let find_cmd = 'find . -iname "*.py" > python_cscope.files'
+ let pycscope_cmd = 'pycscope -f "python_cscope.out" -i python_cscope.files'
+ let ctags_cmd = 'ctags --fields=+i -n -R -f "python_tags" -L python_cscope.files'
+ let cqmakedb_cmd = 'cqmakedb -s "' . a:db_path . '" -c python_cscope.out' .
+ \ ' -t python_tags -p'
+ let shell_cmd = find_cmd . ' && ' .
+ \ pycscope_cmd . ' && ' .
+ \ ctags_cmd . ' && ' .
+ \ cqmakedb_cmd
+
+ if exists('g:codequery_enable_auto_clean_languages') &&
+ \ index(g:codequery_enable_auto_clean_languages, 'python') != -1
+ let shell_cmd .= '&& rm python_cscope.files python_cscope.out python_tags'
+ endif
+
+ return exists('g:codequery_build_python_db_cmd') ? g:codequery_build_python_db_cmd : shell_cmd
+endfunction
+
+
+function! codequery#db#construct_javascript_db_build_cmd(db_path) abort
+ let starscope_cmd = 'starscope --force-update -e ctags -e cscope **/*.js'
+ let rename_cmd = 'mv tags javascript_tags && mv cscope.out javascript_cscope.out'
+ let cqmakedb_cmd = 'cqmakedb -s "' . a:db_path .
+ \ '" -c ./javascript_cscope.out -t ./javascript_tags -p'
+
+ let shell_cmd = starscope_cmd . ' && ' . rename_cmd . ' && ' . cqmakedb_cmd
+
+ if exists('g:codequery_enable_auto_clean_languages') &&
+ \ index(g:codequery_enable_auto_clean_languages, 'javascript') != -1
+ let shell_cmd .= ' && rm javascript_cscope.out javascript_tags .starscope.db'
+ endif
+
+ return exists('g:codequery_build_javascript_db_cmd') ? g:codequery_build_javascript_db_cmd : shell_cmd
+endfunction
+
+
+function! codequery#db#construct_ruby_db_build_cmd(db_path) abort
+ let starscope_cmd = 'starscope --force-update -e ctags -e cscope **/*.rb'
+ let rename_cmd = 'mv tags ruby_tags && mv cscope.out ruby_cscope.out'
+ let cqmakedb_cmd = 'cqmakedb -s "' . a:db_path .
+ \ '" -c ./ruby_cscope.out -t ./ruby_tags -p'
+
+ let shell_cmd = starscope_cmd . ' && ' . rename_cmd . ' && ' . cqmakedb_cmd
+
+ if exists('g:codequery_enable_auto_clean_languages') &&
+ \ index(g:codequery_enable_auto_clean_languages, 'ruby') != -1
+ let shell_cmd .= ' && rm ruby_cscope.out ruby_tags .starscope.db'
+ endif
+
+ return exists('g:codequery_build_ruby_db_cmd') ? g:codequery_build_ruby_db_cmd : shell_cmd
+endfunction
+
+
+function! codequery#db#construct_go_db_build_cmd(db_path) abort
+ let starscope_cmd = 'starscope --force-update -e ctags -e cscope **/*.go'
+ let rename_cmd = 'mv tags go_tags && mv cscope.out go_cscope.out'
+ let cqmakedb_cmd = 'cqmakedb -s "' . a:db_path .
+ \ '" -c ./go_cscope.out -t ./go_tags -p'
+
+ let shell_cmd = starscope_cmd . ' && ' . rename_cmd . ' && ' . cqmakedb_cmd
+
+ if exists('g:codequery_enable_auto_clean_languages') &&
+ \ index(g:codequery_enable_auto_clean_languages, 'go') != -1
+ let shell_cmd .= ' && rm go_cscope.out go_tags .starscope.db'
+ endif
+
+ return exists('g:codequery_build_go_db_cmd') ? g:codequery_build_go_db_cmd : shell_cmd
+endfunction
+
+
+function! codequery#db#construct_java_db_build_cmd(db_path) abort
+ let find_cmd = 'find . -iname "*.java" > java_cscope.files'
+ let cscope_cmd = 'cscope -cbR -i java_cscope.files -f java_cscope.out'
+ let ctags_cmd = 'ctags --fields=+i -n -R -f "java_tags" -L java_cscope.files'
+ let cqmakedb_cmd = 'cqmakedb -s "' . a:db_path . '" -c java_cscope.out' .
+ \ ' -t java_tags -p'
+ let shell_cmd = find_cmd . ' && ' .
+ \ cscope_cmd . ' && ' .
+ \ ctags_cmd . ' && ' .
+ \ cqmakedb_cmd
+
+ if exists('g:codequery_enable_auto_clean_languages') &&
+ \ index(g:codequery_enable_auto_clean_languages, 'java') != -1
+ let shell_cmd .= '&& rm java_cscope.files java_cscope.out java_tags'
+ endif
+
+ return exists('g:codequery_build_java_db_cmd') ? g:codequery_build_java_db_cmd : shell_cmd
+endfunction
+
+
+function! codequery#db#construct_c_db_build_cmd(db_path) abort
+ let find_cmd = 'find . -iname "*.c" > c_cscope.files && ' .
+ \ 'find . -iname "*.h" >> c_cscope.files && ' .
+ \ 'find . -iname "*.cpp" >> c_cscope.files && ' .
+ \ 'find . -iname "*.cxx" >> c_cscope.files && ' .
+ \ 'find . -iname "*.cc" >> c_cscope.files && ' .
+ \ 'find . -iname "*.hpp" >> c_cscope.files && ' .
+ \ 'find . -iname "*.hxx" >> c_cscope.files && ' .
+ \ 'find . -iname "*.hh" >> c_cscope.files'
+ let cscope_cmd = 'cscope -cbk -i c_cscope.files -f c_cscope.out'
+ let ctags_cmd = 'ctags --fields=+i -n -R -f "c_tags" -L c_cscope.files'
+ let cqmakedb_cmd = 'cqmakedb -s "' . a:db_path . '" -c c_cscope.out' .
+ \ ' -t c_tags -p'
+ let shell_cmd = find_cmd . ' && ' .
+ \ cscope_cmd . ' && ' .
+ \ ctags_cmd . ' && ' .
+ \ cqmakedb_cmd
+
+ if exists('g:codequery_enable_auto_clean_languages') &&
+ \ index(g:codequery_enable_auto_clean_languages, 'c') != -1
+ let shell_cmd .= '&& rm c_cscope.files c_cscope.out c_tags'
+ endif
+
+ return exists('g:codequery_build_c_db_cmd') ? g:codequery_build_c_db_cmd : shell_cmd
+endfunction
diff --git a/autoload/codequery/menu.vim b/autoload/codequery/menu.vim
new file mode 100644
index 0000000..edfc1bc
--- /dev/null
+++ b/autoload/codequery/menu.vim
@@ -0,0 +1,118 @@
+" =============================================================================
+" Entries
+
+
+scriptencoding utf-8
+
+
+function! codequery#menu#patch_unite_magic_menu_from_qf(fre_cmds, fun_cmds, cla_cmds) abort
+ call map(a:fre_cmds, '[substitute(v:val[0], "Find", "Switch To", "g"), v:val[1]]')
+ call map(a:fun_cmds, '[substitute(v:val[0], "Find", "Switch To", "g"), v:val[1]]')
+ call map(a:cla_cmds, '[substitute(v:val[0], "Find", "Switch To", "g"), v:val[1]]')
+ call map(a:fre_cmds, '[v:val[0], substitute(v:val[1], "CodeQuery", "CodeQueryAgain", "")]')
+ call map(a:fun_cmds, '[v:val[0], substitute(v:val[1], "CodeQuery", "CodeQueryAgain", "")]')
+ call map(a:cla_cmds, '[v:val[0], substitute(v:val[1], "CodeQuery", "CodeQueryAgain", "")]')
+ call insert(a:fre_cmds, ['▷ Filter', 'call feedkeys(":CodeQueryFilter ")'], 0)
+endfunction
+
+
+
+function! codequery#menu#use_unite_menu(magic) abort
+ let cword = codequery#query#get_valid_cursor_word()
+ let menu_frequent_cmds = [['▷ Find Symbol', 'CodeQuery Symbol'],
+ \['▷ Find Text', 'CodeQuery Text']]
+ let menu_function_cmds = [['▷ Find Function Def. [F]', 'CodeQuery Definition'],
+ \['▷ Find Call [F]', 'CodeQuery Call'],
+ \['▷ Find Caller [F]', 'CodeQuery Caller'],
+ \['▷ Find Callee [F]', 'CodeQuery Callee']]
+ let menu_class_cmds = [['▷ Find Class Def. [C]', 'CodeQuery Class'],
+ \['▷ Find Class Member [C]', 'CodeQuery Member'],
+ \['▷ Find Parent [C]', 'CodeQuery Parent'],
+ \['▷ Find Child [C]', 'CodeQuery Child']]
+ let menu_other_cmds = [['▷ List Function', 'CodeQuery FunctionList'],
+ \['▷ List Imports', 'CodeQuery FileImporter']]
+ let menu_delimiter = [['* ------------------------- *', '']]
+ let menu_db_cmds = [['▷ Make DB', 'call feedkeys(":CodeQueryMakeDB ")'],
+ \['▷ View DB', 'call feedkeys(":CodeQueryViewDB ")'],
+ \['▷ Move DB', 'call feedkeys(":CodeQueryMoveDBToGitDir ")']]
+ let menu_show_qf = [['▷ Show QF ▲', 'CodeQueryShowQF'],
+ \['▷ Hide QF ▼', 'cclose']]
+ let menu_goto_magic = [['▷ Open Magic Menu ▸', 'CodeQueryMenu Unite Magic']]
+ let menu_goto_full = [['▷ Open Full Menu ▸', 'CodeQueryMenu Unite Full']]
+
+ " DB not found => remove unnecessary items from menu
+ let db_path = codequery#db#find_db_path(&filetype)
+ if empty(db_path) && &filetype !=# 'qf'
+ let menu_frequent_cmds = [['▷ Find Text', g:codequery_find_text_cmd]]
+ let menu_function_cmds = []
+ let menu_class_cmds = []
+ let menu_other_cmds = []
+ let menu_delimiter = []
+ let menu_db_cmds = [['▷ Make DB', 'call feedkeys(":CodeQueryMakeDB ' . &filetype . '")']]
+ let menu_goto_magic = []
+ let menu_goto_full = []
+ if index(g:codequery_supported_filetype_list, &filetype) == -1
+ let menu_show_qf += [['# Not Supported Filetype: [' . &filetype . ']', '']]
+ endif
+ endif
+
+ if a:magic
+ if &filetype ==# 'qf'
+ call codequery#menu#patch_unite_magic_menu_from_qf(menu_frequent_cmds,
+ \ menu_function_cmds,
+ \ menu_class_cmds)
+ let menu_other_cmds = []
+ let menu_goto_full = []
+ if exists('g:codequery_last_query_word')
+ let cword = g:codequery_last_query_word
+ endif
+ endif
+
+ let menu_description = 'CodeQuery Magic Menu'
+ if g:codequery_enable_not_so_magic_menu
+ let cmd_candidates = menu_frequent_cmds
+ \ + menu_function_cmds
+ \ + menu_class_cmds
+ \ + menu_other_cmds
+ \ + menu_show_qf
+ \ + menu_goto_full
+ elseif cword =~# '\C^[A-Z].*'
+ let cmd_candidates = menu_frequent_cmds
+ \ + menu_class_cmds
+ \ + menu_other_cmds
+ \ + menu_show_qf
+ \ + menu_goto_full
+ else
+ let cmd_candidates = menu_frequent_cmds
+ \ + menu_function_cmds
+ \ + menu_other_cmds
+ \ + menu_show_qf
+ \ + menu_goto_full
+ endif
+ else
+ if &filetype ==# 'qf'
+ echom 'Can Not Open Full Menu In QF (Use Magic Menu)'
+ return
+ endif
+ let menu_description = 'CodeQuery Full Menu'
+ let cmd_candidates = menu_frequent_cmds
+ \ + menu_function_cmds
+ \ + menu_class_cmds
+ \ + menu_other_cmds
+ \ + menu_delimiter
+ \ + menu_db_cmds
+ \ + menu_delimiter
+ \ + menu_show_qf
+ \ + menu_goto_magic
+ endif
+
+ if !exists('g:unite_source_menu_menus')
+ let g:unite_source_menu_menus = {}
+ endif
+ let g:unite_source_menu_menus.codequery = {
+ \ 'description' : menu_description,
+ \}
+ let g:unite_source_menu_menus.codequery.command_candidates = cmd_candidates
+ execute 'Unite -silent -prompt-visible -prompt=::' . cword
+ \ . ':: menu:codequery'
+endfunction
diff --git a/autoload/codequery/query.vim b/autoload/codequery/query.vim
new file mode 100644
index 0000000..c144719
--- /dev/null
+++ b/autoload/codequery/query.vim
@@ -0,0 +1,268 @@
+" =============================================================================
+" Helpers
+
+
+let s:subcmd_map = { 'Symbol' : 1,
+ \ 'Definition' : 2,
+ \ 'Caller' : 6,
+ \ 'Callee' : 7,
+ \ 'Call' : 8,
+ \ 'Class' : 3,
+ \ 'Member' : 9,
+ \ 'Parent' : 12,
+ \ 'Child' : 11,
+ \ 'FunctionList' : 13,
+ \ 'FileImporter' : 4,
+ \ 'Text' : 21 }
+
+
+function! s:create_grep_options(word) abort
+ if g:codequery_fuzzy
+ let fuzzy_option = '-f'
+ let word = '"' . a:word . '"'
+ else
+ let fuzzy_option = '-e'
+ let word = a:word
+ endif
+
+ let pipeline_script_option = ' \| cut -f 2,3'
+
+ let grepformat = '%f:%l%m'
+ let grepprg = 'cqsearch -s ' . g:codequery_db_path . ' -p ' . g:codequery_querytype . ' -t '
+ \ . word . ' -u ' . fuzzy_option . pipeline_script_option
+
+ if g:codequery_querytype == s:subcmd_map['FileImporter']
+ let grepprg = 'cqsearch -s ' . g:codequery_db_path . ' -p ' . g:codequery_querytype . ' -t '
+ \ . word . ' -u ' . fuzzy_option
+
+ elseif g:codequery_querytype == s:subcmd_map['Callee'] ||
+ \ g:codequery_querytype == s:subcmd_map['Caller'] ||
+ \ g:codequery_querytype == s:subcmd_map['Member']
+ let grepprg = 'cqsearch -s ' . g:codequery_db_path . ' -p ' . g:codequery_querytype . ' -t '
+ \ . word . ' -u ' . fuzzy_option . ' \| awk ''{ print $2 " " $1 }'''
+
+ elseif g:codequery_querytype == s:subcmd_map['Text']
+ let grepformat = ''
+ let grepprg = g:codequery_find_text_cmd . ' ' . a:word
+ endif
+
+ return [grepformat, grepprg]
+endfunction
+
+
+function! s:show_result(word) abort
+ let results = getqflist()
+ call codequery#query#prettify_qf_layout_and_map_keys(results)
+ if !empty(results)
+ echom 'Found ' . len(results) . ' result' . (len(results) > 1 ? 's' : '')
+ \. ' /' . a:word . '/'
+ else
+ echom 'Result Not Found /' . a:word . '/'
+ endif
+endfunction
+
+
+
+" =============================================================================
+" Entries
+
+
+function! codequery#query#is_valid_word(word) abort
+ return strlen(matchstr(a:word, '\v^[a-z|A-Z|0-9|_|*|?]+$')) > 0
+endfunction
+
+
+function! codequery#query#get_valid_cursor_word() abort
+ return codequery#query#is_valid_word(expand('')) ? expand('') : ''
+endfunction
+
+
+function! codequery#query#get_valid_input_word(args) abort
+ let args = deepcopy(a:args)
+ if g:codequery_fuzzy
+ call remove(args, index(args, '-f'))
+ endif
+ if g:codequery_append_to_qf
+ call remove(args, index(args, '-a'))
+ endif
+
+ if len(args) <= 1
+ return ''
+ endif
+
+ return codequery#query#is_valid_word(args[1]) ? args[1] : ''
+endfunction
+
+
+function! codequery#query#get_final_query_word(iword, cword) abort
+ if empty(a:iword) && g:codequery_querytype == s:subcmd_map['FunctionList']
+ return expand('%')
+ elseif empty(a:iword) && g:codequery_querytype == s:subcmd_map['FileImporter']
+ return expand('%:r')
+ elseif empty(a:iword) && !empty(a:cword)
+ return a:cword
+ elseif empty(a:iword)
+ return ''
+ else
+ return a:iword
+ endif
+endfunction
+
+
+" Ref: MarcWeber's vim-addon-qf-layout
+function! codequery#query#prettify_qf_layout_and_map_keys(results) abort
+ if &filetype !=# 'qf'
+ if !empty(g:codequery_cwd)
+ execute 'lcd ' . g:codequery_cwd
+ endif
+ copen
+ execute 'lcd ' . g:codequery_cwd
+ endif
+
+ " unlock qf to make changes
+ setlocal modifiable
+ setlocal nolist
+ setlocal nowrap
+
+ " delete all the text in qf
+ silent %delete
+
+ " insert new text with pretty layout
+ let max_fn_len = 0
+ let max_lnum_len = 0
+ for d in a:results
+ let d['filename'] = bufname(d['bufnr'])
+ let max_fn_len = max([max_fn_len, len(d['filename'])])
+ let max_lnum_len = max([max_lnum_len, len(d['lnum'])])
+ endfor
+ let reasonable_max_len = 60
+ let max_fn_len = min([max_fn_len, reasonable_max_len])
+ let qf_format = '"%-' . max_fn_len . 'S | %' . max_lnum_len . 'S | %s"'
+ let evaluating_str = 'printf(' . qf_format .
+ \ ', v:val["filename"], v:val["lnum"], v:val["text"])'
+ call append('0', map(a:results, evaluating_str))
+
+ " delete empty line
+ global/^$/delete
+
+ " put the cursor back
+ normal! gg
+
+ " map shortcuts
+ if !g:codequery_disable_qf_key_bindings
+ nnoremap s :CodeQueryAgain Symbol
+ nnoremap x :CodeQueryAgain Text
+ nnoremap c :CodeQueryAgain Call
+ nnoremap r :CodeQueryAgain Caller
+ nnoremap e :CodeQueryAgain Callee
+ nnoremap d :CodeQueryAgain Definition
+ nnoremap C :CodeQueryAgain Class
+ nnoremap M :CodeQueryAgain Member
+ nnoremap P :CodeQueryAgain Parent
+ nnoremap D :CodeQueryAgain Child
+
+ nnoremap m :CodeQueryMenu Unite Magic
+ nnoremap q :cclose
+ nnoremap \ :CodeQueryFilter
+
+ nnoremap p p
+ nnoremap u :colder \| CodeQueryShowQF
+ nnoremap :cnewer \| CodeQueryShowQF
+ endif
+
+ " lock qf again
+ setlocal nomodifiable
+ setlocal nomodified
+endfunction
+
+
+function! codequery#query#do_query(word) abort
+ if empty(a:word)
+ echom 'Invalid Search Term: ' . a:word
+ return
+ endif
+
+ let grep_options = s:create_grep_options(a:word)
+ let [grepformat, grepprg] = grep_options
+
+ " Find Text
+ if empty(grepformat)
+ if g:codequery_find_text_from_current_file_dir == 1
+ lcd %:p:h
+ endif
+ silent execute grepprg
+ call codequery#query#prettify_qf_layout_and_map_keys(getqflist())
+ let g:codequery_last_query_word = a:word
+ let g:last_query_fuzzy = g:codequery_fuzzy
+ return
+ endif
+
+ if v:version >= 800 && !has('nvim')
+ echom 'Searching ... [' . a:word . ']'
+
+ let job_dict = {'is_append': g:codequery_append_to_qf ? 1 : 0,
+ \'target_file': tempname(),
+ \'backup_ef': &errorformat,
+ \'word' : a:word,
+ \'callback': function("codequery#query#do_query_callback")}
+ let options = {'out_io': 'file',
+ \'out_name': job_dict.target_file,
+ \'exit_cb': job_dict.callback}
+
+ let &errorformat = '%f:%l%m'
+ let grepprg .= ' \| awk "{ sub(/.*\/\.\//,x) }1"'
+ let shell_cmd = substitute(grepprg, '\\|', '|', "g")
+ let shell_cmd = substitute(shell_cmd, "''", "'", "g")
+
+ let s:query_job = job_start(['/bin/sh', '-c', shell_cmd], options)
+ let timer = timer_start(50,
+ \{-> execute("call job_status(s:query_job)", "")},
+ \{'repeat': 200})
+ else
+ let grepcmd = g:codequery_append_to_qf ? 'grepadd!' : 'grep!'
+ let l:grepprg_bak = &l:grepprg
+ let l:grepformat_bak = &grepformat
+ try
+ let &l:grepformat = grepformat
+ let &l:grepprg = grepprg . ' \| awk "{ sub(/.*\/\.\//,x) }1"'
+ silent execute grepcmd
+ redraw!
+ call s:show_result(a:word)
+ finally
+ let &l:grepprg = l:grepprg_bak
+ let &grepformat = l:grepformat_bak
+ let g:codequery_last_query_word = a:word
+ let g:last_query_fuzzy = g:codequery_fuzzy
+ endtry
+ endif
+endfunction
+
+
+function! codequery#query#do_query_callback(job, status) dict
+ try
+ if self.is_append
+ execute "caddfile " . self.target_file
+ else
+ execute "cgetfile " . self.target_file
+ endif
+ call s:show_result(self.word)
+ finally
+ let g:codequery_last_query_word = self.word
+ let g:last_query_fuzzy = g:codequery_fuzzy
+ let &errorformat = self.backup_ef
+ call delete(self.target_file)
+ endtry
+endfunction
+
+
+function! codequery#query#set_options(args) abort
+ let g:codequery_querytype = get(s:subcmd_map, a:args[0])
+
+ if index(a:args, '-f') != -1
+ let g:codequery_fuzzy = 1
+ endif
+
+ if index(a:args, '-a') != -1
+ let g:codequery_append_to_qf = 1
+ endif
+endfunction
diff --git a/plugin/codequery.vim b/plugin/codequery.vim
index a984b83..adfb665 100644
--- a/plugin/codequery.vim
+++ b/plugin/codequery.vim
@@ -1,14 +1,67 @@
" Copyright (c) 2016 excusemejoe
" MIT License
-" =============================================================================
-" Menu
+if exists('g:loaded_loaded_codequery')
+ finish
+endif
+let g:loaded_codequery = 1
+
+
+" =============================================================================
+" Options
+
+" Init with default value
+if !exists('g:codequery_find_text_cmd')
+ let g:codequery_find_text_cmd = 'Ack!'
+endif
+if !exists('g:codequery_find_text_from_current_file_dir')
+ let g:codequery_find_text_from_current_file_dir = 0
+endif
+if !exists('g:codequery_auto_switch_to_find_text_for_wrong_filetype')
+ let g:codequery_auto_switch_to_find_text_for_wrong_filetype = 0
+endif
+if !exists('g:codequery_trigger_build_db_when_db_not_found')
+ let g:codequery_trigger_build_db_when_db_not_found = 0
+endif
+if !exists('g:codequery_disable_qf_key_bindings')
+ let g:codequery_disable_qf_key_bindings = 0
+endif
+if !exists('g:codequery_enable_not_so_magic_menu')
+ let g:codequery_enable_not_so_magic_menu = 0
+endif
+
+
+
+" No need to init
+"let g:codequery_build_python_db_cmd = ''
+"let g:codequery_build_javascript_db_cmd = ''
+"let g:codequery_build_ruby_db_cmd = ''
+"let g:codequery_build_go_db_cmd = ''
+"let g:codequery_build_java_db_cmd = ''
+"let g:codequery_build_c_db_cmd = ''
+"let g:codequery_enable_auto_clean_languages = []
-command! -nargs=* -complete=customlist,s:complete_function CodeQuery call s:run_codequery()
-let s:subcommands = [ 'Symbol',
- \ 'Definition', 'DefinitionGroup',
+" =============================================================================
+" Commands
+
+
+command! -nargs=* -complete=customlist,s:complete_function CodeQuery
+ \ call codequery#run_codequery()
+command! -nargs=* -complete=customlist,s:complete_function CodeQueryAgain
+ \ call codequery#run_codequery_again_with_different_subcmd()
+command! -nargs=* CodeQueryFilter call codequery#filter_qf_results()
+command! -nargs=* CodeQueryMakeDB call codequery#make_codequery_db()
+command! -nargs=* CodeQueryViewDB call codequery#view_codequery_db()
+command! -nargs=* CodeQueryMoveDBToGitDir
+ \ call codequery#move_codequery_db_to_git_hidden_dir()
+command! -nargs=* CodeQueryMenu call codequery#show_menu()
+command! -nargs=0 CodeQueryShowQF call
+ \ codequery#query#prettify_qf_layout_and_map_keys(getqflist())
+
+let g:codequery_subcommands = [ 'Symbol', 'Text',
+ \ 'Definition',
\ 'Caller', 'Callee', 'Call',
\ 'Class', 'Member', 'Parent', 'Child',
\ 'FunctionList',
@@ -16,164 +69,5 @@ let s:subcommands = [ 'Symbol',
\ ]
function! s:complete_function(arg_lead, cmd_line, cursor_pos)
- return s:subcommands
-endfunction
-
-
-
-" =============================================================================
-" Helpers
-
-
-let s:subcmd_map = { 'Symbol' : 1,
- \ 'Definition' : 2,
- \ 'Caller' : 6,
- \ 'Callee' : 7,
- \ 'Call' : 8,
- \ 'Class' : 3,
- \ 'Member' : 9,
- \ 'Parent' : 12,
- \ 'Child' : 11,
- \ 'FunctionList' : 13,
- \ 'FileImporter' : 4 ,
- \ 'DefinitionGroup' : 20 }
-
-
-function! s:is_valid_word(word)
- return strlen(matchstr(a:word, '\v[a-z|A-Z|0-9|_]+')) > 0
-endfunction
-
-
-function! s:get_valid_cursor_word()
- return s:is_valid_word(expand('')) ? expand('') : ''
-endfunction
-
-
-function! s:get_valid_input_word(args)
- let args = deepcopy(a:args)
- if s:fuzzy
- call remove(args, index(args, '-f'))
- endif
- if s:append_to_quickfix
- call remove(args, index(args, '-a'))
- endif
-
- if len(args) <= 1
- return ''
- endif
-
- return s:is_valid_word(args[1]) ? args[1] : ''
-endfunction
-
-
-function! s:do_grep(word)
- if empty(a:word)
- echom 'Invalid Search Term: ' . a:word
- return
- endif
-
- let fuzzy_option = s:fuzzy ? '-f' : '-e'
- let pipeline_script_option = ' \| cut -f 2,3'
-
- let grepformat = '%f:%l%m'
- let grepprg = 'cqsearch -s myproject.db -p ' . s:querytype . ' -t ' .
- \ a:word . ' -u ' . fuzzy_option
- \ . pipeline_script_option
-
- if s:querytype == s:subcmd_map['FileImporter']
-
- let grepprg = 'cqsearch -s myproject.db -p ' . s:querytype . ' -t ' .
- \ a:word . ' -u ' . fuzzy_option
-
- elseif s:querytype == s:subcmd_map['Callee'] ||
- \ s:querytype == s:subcmd_map['Caller'] ||
- \ s:querytype == s:subcmd_map['Member']
-
- let grepprg = 'cqsearch -s myproject.db -p ' . s:querytype . ' -t ' .
- \ a:word . ' -u ' . fuzzy_option . ' \| awk ''{ print $2 " " $1 }'''
-
- elseif s:querytype == s:subcmd_map['DefinitionGroup']
- echom 'Not Implement !'
- return
- endif
-
- let grepcmd = s:append_to_quickfix ? 'grepadd!' : 'grep!'
- let l:grepprg_bak = &l:grepprg
- let l:grepformat_bak = &grepformat
- try
- let &l:grepformat = grepformat
- let &l:grepprg = grepprg . ' \| awk "{ sub(/.*\/\.\//,x) }1"'
- silent execute grepcmd
- redraw!
- copen
- finally
- let &l:grepprg = l:grepprg_bak
- let &grepformat = l:grepformat_bak
- endtry
-endfunction
-
-
-function! s:set_options(args)
- let s:querytype = get(s:subcmd_map, a:args[0])
-
- if index(a:args, '-f') != -1
- let s:fuzzy = 1
- endif
-
- if index(a:args, '-a') != -1
- let s:append_to_quickfix = 1
- endif
-endfunction
-
-
-
-" =============================================================================
-" Entries
-
-
-function! s:run_codequery(args)
- let s:fuzzy = 0
- let s:append_to_quickfix = 0
- let s:querytype = 1
-
- let args = split(a:args, ' ')
- let args_num = len(args)
- let cword = s:get_valid_cursor_word()
-
- if args_num == 0
- " Example:
- " :CodeQuery
- call s:do_grep(cword)
-
- elseif index(s:subcommands, args[0]) != -1
- " Examples:
- " :CodeQuery Symbol
- " :CodeQuery Symbol -f -a
- " :CodeQuery Symbol search_term -f -a
- call s:set_options(args)
- let iword = s:get_valid_input_word(args)
-
- if empty(iword) && s:querytype == s:subcmd_map['FunctionList']
- let iword = expand('%')
- elseif empty(iword) && s:querytype == s:subcmd_map['FileImporter']
- let iword = expand('%:r')
- elseif empty(iword) && !empty(cword)
- let iword = cword
- elseif empty(iword)
- echom 'Invalid Args: ' . a:args
- return
- endif
-
- call s:do_grep(iword)
- else
- echo 'Wrong Subcommand !'
- endif
+ return g:codequery_subcommands
endfunction
-
-
-
-" =============================================================================
-" Debugging
-
-
-"nnoremap c :CodeQuery