diff --git a/README.md b/README.md index c1c6fdd..a30a5a5 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,397 @@ +![](https://github.com/ruben2020/codequery/raw/master/doc/logotitle.png) + + + +> 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 +![](https://devjoe.github.io/public/cq_demo1.gif) -## Usage +`... ➙ Switch to different query ➙ Get results ... ➙ Filter them ➙ Get Results ➙ Undo ➙ Redo` + +![](https://devjoe.github.io/public/ca_demo2.gif) + +[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