├── .gitignore ├── LICENSE ├── README.md ├── doc ├── apc.txt └── update.sh └── plugin └── apc.vim /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | /.vscode/* 131 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Linwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-auto-popmenu 2 | 3 | A tiny and portable script (169 lines) to provide you `YouCompleteMe` like experience for `buffer`, `dictionary` and `tags` completion without installing heavy completion engines and building background servers. 4 | 5 | ## What Is It ? 6 | 7 | Semantic completion is great, but sometimes, when you are coding in an obscure laguange which is lack of LSP support, or you are working in a temporary system and you don't want waste time to set up a heavyweight completion engine and build a background server. 8 | 9 | In these circumstances, vim's built-in completion system is good enough for you, it can collect keywords from buffers and dictionary or ctag files, but requires you to press `` or `` manually. 10 | 11 | This tiny little script will help you to trigger the completion menu when you have entered 1 or 2 alphabets and provide you exact the same experience like `YouCompleteMe`: 12 | 13 | ![](https://skywind3000.github.io/images/p/auto-popmenu/demo.gif) 14 | 15 | ## Features 16 | 17 | - Popup the completion menu automatically. 18 | - `Tab` or `shift`+`TAB` to cycle keywords, `` to cancel. 19 | - Same experience like `YouCompleteMe` for `buffer`, `dict` and `tags` completion. 20 | - Green, everything is local to buffer, will not pollute your vim or disturb other plugins. 21 | - Capable to co-exist with other completion plugins. 22 | - No heavy engines, no need to build background servers. 23 | - Faster and more handy than the old famous `AutoComplPop`. 24 | - Portable, just a simple `apc.vim` script, easy to be distributed. 25 | - Only **169 lines**, you can even copy it to your `vimrc`. 26 | - Convenience as a backup way for big completion plugins. 27 | 28 | ## Usage 29 | 30 | That's all you need: 31 | 32 | ```VimL 33 | Plug 'skywind3000/vim-auto-popmenu' 34 | 35 | " enable this plugin for filetypes, '*' for all files. 36 | let g:apc_enable_ft = {'text':1, 'markdown':1, 'php':1} 37 | 38 | " source for dictionary, current or other loaded buffers, see ':help cpt' 39 | set cpt=.,k,w,b 40 | 41 | " don't select the first item. 42 | set completeopt=menu,menuone,noselect 43 | 44 | " suppress annoy messages. 45 | set shortmess+=c 46 | ``` 47 | 48 | And perhaps a dictionary database plugin for many languages: 49 | 50 | ``` 51 | Plug 'skywind3000/vim-dict' 52 | ``` 53 | 54 | Then you go. 55 | 56 | ## Commands 57 | 58 | ### ApcEnable 59 | 60 | Enable plugin for the current buffer manually. Useful when you didn't set `g:apc_enable_ft`. 61 | 62 | ### ApcDisable 63 | 64 | Disable plugin for the current buffer. 65 | 66 | ## Cooperative 67 | 68 | If you are using `YouCompleteMe`, disable it for certain filetypes: 69 | 70 | ```VimL 71 | let g:ycm_filetype_blacklist = {'text':1, 'markdown':1, 'php':1} 72 | ``` 73 | 74 | and enable this plugin for these files: 75 | 76 | ```VimL 77 | let g:apc_enable_ft = {'text':1, 'markdown':1, 'php':1} 78 | ``` 79 | 80 | ## Configuration 81 | 82 | 1\) `g:apc_enable` 83 | 84 | Default: 1 85 | Set to 0 to disable this plugin. 86 | 87 | 2\) `b:apc_enable` 88 | 89 | Default: unset 90 | Set to 0 to disable this plugin for certain buffer. 91 | 92 | 3\) `g:apc_min_length` 93 | 94 | Default: 2 95 | Minimal characters to trigger the completion popup menu. 96 | 97 | 4\) `g:apc_trigger` 98 | 99 | Default: `"\"` 100 | Key to trigger the completion popup menu. 101 | Set to `"\\"` to trigger omni completion. 102 | 103 | 5\) `b:apc_trigger` 104 | 105 | Default: unset 106 | Specify trigger key for certain buffer, will override `g:apc_trigger` for certain buffer. 107 | 108 | 6\) `g:apc_cr_confirm` 109 | 110 | Default: 0 111 | 112 | Set to 1 to allow you choose the current keyword by ENTER. 113 | 114 | ## Credit 115 | 116 | - https://github.com/othree/vim-autocomplpop. 117 | -------------------------------------------------------------------------------- /doc/apc.txt: -------------------------------------------------------------------------------- 1 | *apc* vim-auto-popmenu 2 | 3 | =============================================================================== 4 | Contents ~ 5 | 6 | 1. Introduction |apc-introduction| 7 | 2. What Is It ? |apc-what-is-it| 8 | 3. Features |apc-features| 9 | 4. Usage |apc-usage| 10 | 5. Commands |apc-commands| 11 | 1. ApcEnable |apcenable| 12 | 2. ApcDisable |apcdisable| 13 | 6. Cooperative |apc-cooperative| 14 | 7. Credit |apc-credit| 15 | 8. References |apc-references| 16 | 17 | =============================================================================== 18 | *apc-introduction* 19 | Introduction ~ 20 | 21 | A tiny and portable script (169 lines) to provide you 'YouCompleteMe' like 22 | experience for 'buffer', 'dictionary' and 'tags' completion without installing 23 | heavy completion engines and building background servers. 24 | 25 | =============================================================================== 26 | *apc-what-is-it* 27 | What Is It ? ~ 28 | 29 | Semantic completion is great, but sometimes, when you are coding in an obscure 30 | laguange which is lack of LSP support, or you are working in a temporary system 31 | and you don't want waste time to set up a heavyweight completion engine and 32 | build a background server. 33 | 34 | In these circumstances, vim's built-in completion system is good enough for 35 | you, it can collect keywords from buffers and dictionary or ctag files, but 36 | requires you to press '' or '' manually. 37 | 38 | This tiny little script will help you to trigger the completion menu when you 39 | have entered 1 or 2 alphabets and provide you exact the same experience like 40 | 'YouCompleteMe': 41 | 42 | Image: (see reference [1]) 43 | 44 | =============================================================================== 45 | *apc-features* 46 | Features ~ 47 | 48 | - Popup the completion menu automatically. 49 | - 'Tab' or 'shift'+'TAB' to cycle keywords, '' to cancel. 50 | - Same experience like 'YouCompleteMe' for 'buffer', 'dict' and 'tags' 51 | completion. 52 | - Green, everything is local to buffer, will not pollute your vim or disturb 53 | other plugins. 54 | - Capable to co-exist with other completion plugins. 55 | - No heavy engines, no need to build background servers. 56 | - Faster and more handy than the old famous 'AutoComplPop'. 57 | - Portable, just a simple 'apc.vim' script, easy to be distributed. 58 | - Only **169 lines**, you can even copy it to your 'vimrc'. 59 | - Convenience as a backup way for big completion plugins. 60 | 61 | =============================================================================== 62 | *apc-usage* 63 | Usage ~ 64 | 65 | That's all you need: 66 | > 67 | Plug 'skywind3000/vim-auto-popmenu' 68 | 69 | " enable this plugin for filetypes, '*' for all files. 70 | let g:apc_enable_ft = {'text':1, 'markdown':1, 'php':1} 71 | 72 | " source for dictionary, current or other loaded buffers, see ':help cpt' 73 | set cpt=.,k,w,b 74 | 75 | " don't select the first item. 76 | set completeopt=menu,menuone,noselect 77 | 78 | " suppress annoy messages. 79 | set shortmess+=c 80 | < 81 | And perhaps a dictionary database plugin for many languages: 82 | > 83 | Plug 'skywind3000/vim-dict' 84 | < 85 | Then you go. 86 | 87 | =============================================================================== 88 | *apc-commands* 89 | Commands ~ 90 | 91 | ------------------------------------------------------------------------------- 92 | *apcenable* 93 | ApcEnable ~ 94 | 95 | Enable plugin for the current buffer manually. Useful when you didn't set 96 | 'g:apc_enable_ft'. 97 | 98 | ------------------------------------------------------------------------------- 99 | *apcdisable* 100 | ApcDisable ~ 101 | 102 | Disable plugin for the current buffer. 103 | 104 | =============================================================================== 105 | *apc-cooperative* 106 | Cooperative ~ 107 | 108 | If you are using 'YouCompleteMe', disable it for certain filetypes: 109 | > 110 | let g:ycm_filetype_blacklist = {'text':1, 'markdown':1, 'php':1} 111 | < 112 | and enable this plugin for these files: 113 | > 114 | let g:apc_enable_ft = {'text':1, 'markdown':1, 'php':1} 115 | < 116 | =============================================================================== 117 | *apc-credit* 118 | Credit ~ 119 | 120 | - https://github.com/othree/vim-autocomplpop. 121 | 122 | =============================================================================== 123 | *apc-references* 124 | References ~ 125 | 126 | [1] https://skywind3000.github.io/images/p/auto-popmenu/demo.gif 127 | 128 | vim: ft=help 129 | -------------------------------------------------------------------------------- /doc/update.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ~/github/vim-tools/html2vimdoc/bin/python ~/github/vim-tools/html2vimdoc.py -f apc -t vim-auto-popmenu ../README.md > apc.txt 3 | 4 | -------------------------------------------------------------------------------- /plugin/apc.vim: -------------------------------------------------------------------------------- 1 | " vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 : 2 | " 3 | " apc.vim - auto popup completion window 4 | " 5 | " Created by skywind on 2020/03/05 6 | " Last Modified: 2022/12/05 21:22 7 | " 8 | " Features: 9 | " 10 | " - auto popup complete window without select the first one 11 | " - tab/s-tab to cycle suggestions, to cancel 12 | " - use ApcEnable/ApcDisable to toggle for certiain file. 13 | " 14 | " Usage: 15 | " 16 | " set cpt=.,k,b 17 | " set completeopt=menu,menuone,noselect 18 | " let g:apc_enable_ft = {'text':1, 'markdown':1, 'php':1} 19 | 20 | let g:apc_enable_ft = get(g:, 'apc_enable_ft', {}) " enable filetypes 21 | let g:apc_enable_tab = get(g:, 'apc_enable_tab', 1) " remap tab 22 | let g:apc_min_length = get(g:, 'apc_min_length', 2) " minimal length to open popup 23 | let g:apc_key_ignore = get(g:, 'apc_key_ignore', []) " ignore keywords 24 | let g:apc_trigger = get(g:, 'apc_trigger', "\") " which key to trigger popmenu 25 | 26 | " get word before cursor 27 | function! s:get_context() 28 | return strpart(getline('.'), 0, col('.') - 1) 29 | endfunc 30 | 31 | function! s:meets_keyword(context) 32 | if g:apc_min_length <= 0 33 | return 0 34 | endif 35 | let matches = matchlist(a:context, '\(\k\{' . g:apc_min_length . ',}\)$') 36 | if empty(matches) 37 | return 0 38 | endif 39 | for ignore in g:apc_key_ignore 40 | if stridx(ignore, matches[1]) == 0 41 | return 0 42 | endif 43 | endfor 44 | return 1 45 | endfunc 46 | 47 | function! s:check_back_space() abort 48 | return col('.') < 2 || getline('.')[col('.') - 2] =~# '\s' 49 | endfunc 50 | 51 | function! s:on_backspace() 52 | if pumvisible() == 0 53 | return "\" 54 | endif 55 | let text = matchstr(s:get_context(), '.*\ze.') 56 | return s:meets_keyword(text)? "\" : "\\" 57 | endfunc 58 | 59 | 60 | " autocmd for CursorMovedI 61 | function! s:feed_popup() 62 | let enable = get(b:, 'apc_enable', 0) 63 | let lastx = get(b:, 'apc_lastx', -1) 64 | let lasty = get(b:, 'apc_lasty', -1) 65 | let tick = get(b:, 'apc_tick', -1) 66 | if &bt != '' || enable == 0 || &paste 67 | return -1 68 | endif 69 | let x = col('.') - 1 70 | let y = line('.') - 1 71 | if pumvisible() 72 | let context = s:get_context() 73 | if s:meets_keyword(context) == 0 74 | call feedkeys("\", 'n') 75 | endif 76 | let b:apc_lastx = x 77 | let b:apc_lasty = y 78 | let b:apc_tick = b:changedtick 79 | return 0 80 | elseif lastx == x && lasty == y 81 | return -2 82 | elseif b:changedtick == tick 83 | let lastx = x 84 | let lasty = y 85 | return -3 86 | endif 87 | let context = s:get_context() 88 | if s:meets_keyword(context) 89 | silent! call feedkeys(get(b:, 'apc_trigger', g:apc_trigger), 'n') 90 | let b:apc_lastx = x 91 | let b:apc_lasty = y 92 | let b:apc_tick = b:changedtick 93 | endif 94 | return 0 95 | endfunc 96 | 97 | " autocmd for CompleteDone 98 | function! s:complete_done() 99 | let b:apc_lastx = col('.') - 1 100 | let b:apc_lasty = line('.') - 1 101 | let b:apc_tick = b:changedtick 102 | endfunc 103 | 104 | " enable apc 105 | function! s:apc_enable() 106 | call s:apc_disable() 107 | augroup ApcEventGroup 108 | au! 109 | au CursorMovedI nested call s:feed_popup() 110 | au CompleteDone call s:complete_done() 111 | augroup END 112 | let b:apc_init_autocmd = 1 113 | if g:apc_enable_tab 114 | inoremap 115 | \ pumvisible()? "\" : 116 | \ check_back_space() ? "\" : 117 | \ get(b:, 'apc_trigger', g:apc_trigger) 118 | inoremap 119 | \ pumvisible()? "\" : "\" 120 | let b:apc_init_tab = 1 121 | endif 122 | if get(g:, 'apc_cr_confirm', 0) == 0 123 | inoremap 124 | \ pumvisible()? "\\" : "\" 125 | else 126 | inoremap 127 | \ pumvisible()? "\" : "\" 128 | endif 129 | inoremap on_backspace() 130 | let b:apc_init_bs = 1 131 | let b:apc_init_cr = 1 132 | let b:apc_save_infer = &infercase 133 | setlocal infercase 134 | let b:apc_enable = 1 135 | endfunc 136 | 137 | " disable apc 138 | function! s:apc_disable() 139 | if get(b:, 'apc_init_autocmd', 0) 140 | augroup ApcEventGroup 141 | au! 142 | augroup END 143 | endif 144 | if get(b:, 'apc_init_tab', 0) 145 | silent! iunmap 146 | silent! iunmap 147 | endif 148 | if get(b:, 'apc_init_bs', 0) 149 | silent! iunmap 150 | endif 151 | if get(b:, 'apc_init_cr', 0) 152 | silent! iunmap 153 | endif 154 | if get(b:, 'apc_save_infer', '') != '' 155 | let &l:infercase = b:apc_save_infer 156 | endif 157 | let b:apc_init_autocmd = 0 158 | let b:apc_init_tab = 0 159 | let b:apc_init_bs = 0 160 | let b:apc_init_cr = 0 161 | let b:apc_save_infer = '' 162 | let b:apc_enable = 0 163 | endfunc 164 | 165 | " check if need to be enabled 166 | function! s:apc_check_init() 167 | if &bt != '' || get(b:, 'apc_enable', 1) == 0 168 | return 169 | endif 170 | if get(g:apc_enable_ft, &ft, 0) != 0 171 | ApcEnable 172 | elseif get(g:apc_enable_ft, '*', 0) != 0 173 | ApcEnable 174 | elseif get(b:, 'apc_enable', 0) 175 | ApcEnable 176 | endif 177 | endfunc 178 | 179 | " commands & autocmd 180 | command! -nargs=0 ApcEnable call s:apc_enable() 181 | command! -nargs=0 ApcDisable call s:apc_disable() 182 | 183 | augroup ApcInitGroup 184 | au! 185 | au FileType * call s:apc_check_init() 186 | au BufEnter * call s:apc_check_init() 187 | au TabEnter * call s:apc_check_init() 188 | augroup END 189 | 190 | --------------------------------------------------------------------------------