├── .reviewdog.yml ├── .travis.yml ├── autoload └── ambicmd.vim ├── doc └── ambicmd.txt └── test └── ambicmd.vimspec /.reviewdog.yml: -------------------------------------------------------------------------------- 1 | runner: 2 | vint: 3 | cmd: vint . 4 | errorformat: 5 | - "%f:%l:%c: %m" 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | git: 3 | depth: 10 4 | 5 | env: 6 | global: 7 | - THEMIS_VERSION=v1.5.4 8 | 9 | cache: 10 | directories: 11 | - &cache_dir $HOME/cache 12 | 13 | before_install: 14 | - mkdir -p ${HOME}/cache 15 | - '[[ -d ${HOME}/cache/themis-${THEMIS_VERSION} ]] || git clone --depth 1 --branch ${THEMIS_VERSION} --single-branch https://github.com/thinca/vim-themis ${HOME}/cache/themis-${THEMIS_VERSION}' 16 | 17 | anchors: 18 | linux: &linux 19 | os: linux 20 | dist: xenial 21 | install: 22 | - docker pull "thinca/vim:${VIM_VERSION}" 23 | script: 24 | - docker run --rm -it "thinca/vim:${VIM_VERSION}" --version 25 | - docker run --rm -it -v "${PWD}:/root" -v "${HOME}/cache/themis-${THEMIS_VERSION}:/tmp/themis" --entrypoint /tmp/themis/bin/themis "thinca/vim:${VIM_VERSION}" --reporter dot 26 | osx: &osx 27 | os: osx 28 | install: 29 | - | 30 | if [[ ${VIM_VERSION} = 'latest' ]]; then 31 | VIM_URL=$(curl -s --retry 3 'https://vim-jp.org/redirects/macvim-dev/macvim/latest.json' | sed 's@.*"redirect_url":"\([^"]*\)".*@\1@') 32 | if [[ -z "${VIM_URL}" ]]; then 33 | echo "Can't get Vim's URL" >&2 34 | exit 64 35 | fi 36 | VIM_VERSION=$(echo ${VIM_URL} | sed 's@.*/download/\([^/]*\).*@\1@') 37 | if [[ -z "${VIM_VERSION}" ]]; then 38 | echo "Can't detect Vim's version from URL(${VIM_URL})" >&2 39 | exit 65 40 | fi 41 | fi 42 | - | 43 | if [[ ! -d "${HOME}/cache/macvim-${VIM_VERSION}" ]]; then 44 | echo "Download from ${VIM_URL}" 45 | curl --silent --location --output "/tmp/MacVim.dmg" "${VIM_URL}" 46 | hdiutil attach -quiet -mountpoint "/Volumes/MacVim" "/tmp/MacVim.dmg" 47 | mkdir -p "${HOME}/cache/macvim-${VIM_VERSION}" 48 | cp -r "/Volumes/MacVim/MacVim.app" "${HOME}/cache/macvim-${VIM_VERSION}" 49 | hdiutil detach "/Volumes/MacVim" 50 | rm "/tmp/MacVim.dmg" 51 | fi 52 | - | 53 | if [[ -x ""${HOME}/cache/macvim-${VIM_VERSION}/MacVim.app/Contents/bin/vim"" ]]; then 54 | export THEMIS_VIM="${HOME}/cache/macvim-${VIM_VERSION}/MacVim.app/Contents/bin/vim" 55 | elif [[ -x ""${HOME}/cache/macvim-${VIM_VERSION}/MacVim.app/Contents/MacOS/Vim"" ]]; then 56 | export THEMIS_VIM="${HOME}/cache/macvim-${VIM_VERSION}/MacVim.app/Contents/MacOS/Vim" 57 | fi 58 | script: 59 | - ${THEMIS_VIM} --version 60 | - ${HOME}/cache/themis-${THEMIS_VERSION}/bin/themis --reporter dot 61 | windows: &windows 62 | os: windows 63 | language: c # 'generic' is not supported yet on windows 64 | install: 65 | - | 66 | if [[ ${VIM_VERSION} = 'latest' ]]; then 67 | VIM_URL=$(curl -s --retry 3 'https://vim-jp.org/redirects/vim/vim-win32-installer/latest/x64.json' | jq -r '.redirect_url') 68 | if [[ -z "${VIM_URL}" ]]; then 69 | echo "Can't get Vim's URL" >&2 70 | exit 64 71 | fi 72 | VIM_VERSION=$(echo ${VIM_URL} | sed 's@.*/download/\([^/]*\).*@\1@') 73 | if [[ -z "${VIM_VERSION}" ]]; then 74 | echo "Can't detect Vim's version from URL(${VIM_URL})" >&2 75 | exit 65 76 | fi 77 | fi 78 | - | 79 | if [[ ! -d ${HOME}/cache/vim-${VIM_VERSION} ]]; then 80 | if [[ -z "${VIM_URL}" ]]; then 81 | if [[ "${VIM_VERSION}" =~ "v7" ]]; then 82 | VIM_URL=https://ftp.nluug.nl/pub/vim/pc/vim$(echo ${VIM_VERSION} | sed 's/[^0-9]//g')w32.zip 83 | else 84 | VIM_URL=https://github.com/vim/vim-win32-installer/releases/download/${VIM_VERSION}/gvim_$(echo ${VIM_VERSION} | sed 's/v//')_x64.zip 85 | fi 86 | fi 87 | echo "Download from ${VIM_URL}" 88 | curl --silent --location --output "${HOME}/cache/vim-${VIM_VERSION}.zip" "${VIM_URL}" 89 | 7z x "-o${HOME}/cache/vim-${VIM_VERSION}" "${HOME}/cache/vim-${VIM_VERSION}.zip" 90 | rm "${HOME}/cache/vim-${VIM_VERSION}.zip" 91 | fi 92 | - export THEMIS_VIM=$(echo ${HOME}/cache/vim-${VIM_VERSION}/vim/*/vim.exe) 93 | script: 94 | - ${THEMIS_VIM} --version 95 | - ${HOME}/cache/themis-${THEMIS_VERSION}/bin/themis.bat --reporter dot 96 | 97 | jobs: 98 | include: 99 | - <<: *linux 100 | env: VIM_VERSION=v7.4 101 | - <<: *linux 102 | env: VIM_VERSION=v8.0.0000 103 | - <<: *linux 104 | env: VIM_VERSION=v8.1.0005 105 | - <<: *linux 106 | env: VIM_VERSION=latest 107 | - <<: *osx 108 | env: 109 | - VIM_VERSION=v7.4.903 110 | - VIM_URL=https://github.com/macvim-dev/macvim/releases/download/snapshot-79/MacVim-7.4.dmg 111 | - <<: *osx 112 | env: 113 | - VIM_VERSION=v8.0.0003 114 | - VIM_URL=https://github.com/macvim-dev/macvim/releases/download/snapshot-110/MacVim.dmg 115 | - <<: *osx 116 | env: 117 | - VIM_VERSION=v8.1.0039 118 | - VIM_URL=https://github.com/macvim-dev/macvim/releases/download/snapshot-148/MacVim.dmg 119 | - <<: *osx 120 | env: VIM_VERSION=latest 121 | - <<: *windows 122 | env: VIM_VERSION=v7.3 123 | - <<: *windows 124 | env: VIM_VERSION=v7.4 125 | - <<: *windows 126 | env: VIM_VERSION=v8.0.0003 127 | - <<: *windows 128 | env: VIM_VERSION=v8.1.0001 129 | - <<: *windows 130 | env: VIM_VERSION=latest 131 | - name: Lint 132 | if: type = pull_request 133 | os: linux 134 | dist: xenial 135 | language: python 136 | python: 3.7 137 | env: 138 | - REVIEWDOG_VERSION=v0.9.12 139 | - VINT_VERSION=0.4a1 140 | cache: 141 | pip: true 142 | directories: 143 | - *cache_dir 144 | install: 145 | - '[[ -x ~/cache/reviewdog ]] || curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s -- -b ~/cache ${REVIEWDOG_VERSION}' 146 | - pip install vim-vint=="${VINT_VERSION}" 147 | script: 148 | - ~/cache/reviewdog -reporter=github-pr-check 149 | -------------------------------------------------------------------------------- /autoload/ambicmd.vim: -------------------------------------------------------------------------------- 1 | if !exists('g:ambicmd#build_rule') 2 | let g:ambicmd#build_rule = 'ambicmd#default_rule' 3 | endif 4 | if !exists('g:ambicmd#show_completion_menu') 5 | let g:ambicmd#show_completion_menu = 0 6 | endif 7 | 8 | function! ambicmd#default_rule(cmd) abort 9 | return [ 10 | \ '\c^' . a:cmd . '$', 11 | \ '\c^' . a:cmd, 12 | \ '\c' . a:cmd, 13 | \ '\C^' . substitute(toupper(a:cmd), '.', '\0\\l*', 'g') . '$', 14 | \ '\C' . substitute(toupper(a:cmd), '.', '\0\\l*', 'g'), 15 | \ '.*' . substitute(a:cmd, '.', '\0.*', 'g') 16 | \ ] 17 | endfunction 18 | 19 | function! s:escape_for_very_magic(str) abort 20 | return escape(a:str, '\.^$?*+~()[]{@|=&') 21 | endfunction 22 | 23 | function! s:PATTERN_NON_ESCAPE_CHAR(char, ...) abort 24 | let force_escape = exists('a:1') ? a:1 : 1 25 | return '\v%(%(\_^|[^\\])%(\\\\)*)@<=' . 26 | \ (force_escape ? s:escape_for_very_magic(a:char) : a:char) 27 | endfunction 28 | 29 | function! s:generate_range_matcher() abort 30 | let range_factor_search = printf('%%(/.*%s|\?.*%s)', 31 | \ s:PATTERN_NON_ESCAPE_CHAR('/'), 32 | \ s:PATTERN_NON_ESCAPE_CHAR('?')) 33 | let range_factors = [ 34 | \ '\d+', 35 | \ '[.$%]', 36 | \ "'.", 37 | \ range_factor_search . '%(' . range_factor_search . ')?', 38 | \ '\\[/?&]', 39 | \ ] 40 | let range_specifier = '%(' . join(range_factors, '|') . 41 | \ ')%(\s*[+-]\d+)?' 42 | return '\v' . range_specifier . '%(\s*[,;]\s*' . 43 | \ range_specifier . ')?' 44 | endfunction 45 | 46 | let s:PATTERN_RANGE = s:generate_range_matcher() 47 | let s:PATTERN_NON_ESCAPE_WHITESPACE = s:PATTERN_NON_ESCAPE_CHAR('\s', 0) 48 | let s:PATTERN_NON_ESCAPE_BAR = s:PATTERN_NON_ESCAPE_CHAR('|') 49 | let s:PATTERN_SINGLE_QUOTE_PAIR = ["'", '\v%(%(\_^|[^''])%('''')*)@<=''%([^'']|$)@='] 50 | let s:PATTERN_DOUBLE_QUOTE_PAIR = ['"', s:PATTERN_NON_ESCAPE_CHAR('"')] 51 | 52 | " NOTE: Keys are evaluated under very magic. 53 | let s:TABLE_SPECIAL_CMDS = { 54 | \ 'g%[lobal]': 'global', 55 | \ 'v%[global]': 'global', 56 | \ 'exe%[cute]': 'execute', 57 | \ } 58 | 59 | 60 | function! s:has_item(list, item) abort 61 | return index(a:list, a:item) != -1 62 | endfunction 63 | 64 | function! s:str_divide_pos(string, pos) abort 65 | " NOTE: Use strpart() by considering a:pos == 0. 66 | return [strpart(a:string, 0, a:pos), a:string[a:pos :]] 67 | endfunction 68 | 69 | function! s:get_cmd_list() abort 70 | redir => cmdlistredir 71 | silent! command 72 | redir END 73 | return map(split(cmdlistredir, "\n")[1 :], 74 | \ 'matchstr(v:val, ''\u\w*'')') 75 | endfunction 76 | 77 | function! s:get_cmdline_info() abort 78 | let is_cmdline = s:has_item(['c', 'v', 'V', "\"], mode()) 79 | if !is_cmdline 80 | if exists('*getcmdwintype') 81 | let cmdtype = getcmdwintype() 82 | let is_cmdwin = (cmdtype !=# '') 83 | else 84 | if (bufname('%') ==# '[Command Line]') && (&l:filetype ==# 'vim') && 85 | \ (!&l:rightleft) && (&l:buftype ==# 'nofile') && (!&l:swapfile) 86 | let is_cmdwin = 1 87 | let cmdtype = ':' 88 | else 89 | let is_cmdwin = 0 90 | let cmdtype = '' 91 | endif 92 | endif 93 | else 94 | let is_cmdwin = 0 95 | let cmdtype = getcmdtype() 96 | endif 97 | return [is_cmdline, is_cmdwin, cmdtype] 98 | endfunction 99 | 100 | function! s:remove_range_specifier(cmdline) abort 101 | return substitute(a:cmdline, '\v^\s*\zs' . s:PATTERN_RANGE, '', '') 102 | endfunction 103 | 104 | function! s:remove_head_whitespace(cmdline) abort 105 | return substitute(a:cmdline, '^\s*', '', '') 106 | endfunction 107 | 108 | function! s:cancel_expanding() abort 109 | throw 'ambicmd: CancelExpanding' 110 | endfunction 111 | 112 | function! s:get_identifier_if_special_cmd(cmdbase) abort 113 | let cmdbase = matchstr(a:cmdbase, '^\s*\zs\w*') " Get command name 114 | if cmdbase ==# '' 115 | return '' 116 | endif 117 | for [key, identifier] in items(s:TABLE_SPECIAL_CMDS) 118 | if cmdbase =~# '\v^' . key . '$' 119 | return identifier 120 | endif 121 | endfor 122 | return '' 123 | endfunction 124 | 125 | function! s:separate_cmd_bang(cmd) abort 126 | if a:cmd[-1 :] ==# '!' 127 | let bang = '!' 128 | let target = a:cmd[: -2] 129 | else 130 | let bang = '' 131 | let target = a:cmd 132 | endif 133 | return [target, bang] 134 | endfunction 135 | 136 | function! s:parse_cmd(cmdline) abort 137 | let cmdline = a:cmdline 138 | while 1 139 | let cmdline = s:remove_range_specifier(cmdline) 140 | if cmdline =~# '^\s*$' 141 | call s:cancel_expanding() 142 | endif 143 | let identifier = s:get_identifier_if_special_cmd(cmdline) 144 | if identifier !=# '' 145 | return s:parse_cmd_{identifier}(s:remove_head_whitespace(cmdline)) 146 | endif 147 | 148 | let index = match(cmdline, s:PATTERN_NON_ESCAPE_BAR) 149 | if index == -1 150 | break 151 | endif 152 | let cmdline = cmdline[index + 1 :] 153 | endwhile 154 | 155 | if cmdline =~# '^\s' 156 | call s:cancel_expanding() 157 | endif 158 | 159 | let [target, bang] = s:separate_cmd_bang(cmdline) 160 | if match(target, '\A') == -1 161 | return [target, bang] 162 | else 163 | call s:cancel_expanding() 164 | endif 165 | endfunction 166 | 167 | function! s:parse_cmd_global(cmdline) abort 168 | let cmdargs = matchstr(a:cmdline, 169 | \ '\v^%(g%[lobal]!?|v%[global])\s*\zs.*') 170 | if cmdargs ==# '' 171 | call s:cancel_expanding() 172 | endif 173 | let pattern_separator = s:PATTERN_NON_ESCAPE_CHAR(cmdargs[0]) 174 | let arg_command = matchstr(cmdargs, 175 | \ '\v^' . pattern_separator . '.{-}' . pattern_separator . '\zs.*$') 176 | if arg_command ==# '' 177 | call s:cancel_expanding() 178 | else 179 | return s:parse_cmd(arg_command) 180 | endif 181 | endfunction 182 | 183 | function! s:parse_cmd_execute(cmdline) abort 184 | let cmdline = matchstr(a:cmdline, 185 | \ '\v^exe%[cute]\s+\zs.*') 186 | if cmdline ==# '' 187 | call s:cancel_expanding() 188 | endif 189 | while 1 190 | let pos = {} 191 | let pos.single_quote = match(cmdline, "'") 192 | let pos.double_quote = match(cmdline, '"') 193 | let pos.bar = match(cmdline, s:PATTERN_NON_ESCAPE_BAR) 194 | 195 | let closest = {'kind': '', 'pos': -1} 196 | for [kind, match_pos] in items(pos) 197 | if match_pos == -1 198 | continue 199 | elseif (closest.pos == -1) || (match_pos < closest.pos) 200 | let closest.kind = kind 201 | let closest.pos = match_pos 202 | endif 203 | endfor 204 | if closest.pos == -1 205 | call s:cancel_expanding() 206 | endif 207 | if closest.kind ==# 'bar' 208 | let cmdline = cmdline[closest.pos + 1 :] 209 | break 210 | endif 211 | let closest.kind = toupper(closest.kind) 212 | let pos_pair = match(cmdline, 213 | \ s:PATTERN_{closest.kind}_PAIR[1], closest.pos + 1) 214 | if pos_pair == -1 215 | let cmdline = cmdline[closest.pos :] 216 | 217 | " Unescape single/double quotes. 218 | let cmdline = eval(cmdline . s:PATTERN_{closest.kind}_PAIR[0]) 219 | break 220 | else 221 | let cmdline = cmdline[pos_pair + 1 :] 222 | endif 223 | endwhile 224 | 225 | return s:parse_cmd(cmdline) 226 | endfunction 227 | 228 | function! s:get_completion(target) abort 229 | if a:target ==# '' 230 | call s:cancel_expanding() 231 | endif 232 | let cmdstate = exists(':' . a:target) 233 | if (cmdstate == 2) || (a:target =~# '^\l' && cmdstate == 1) 234 | call s:cancel_expanding() 235 | endif 236 | 237 | let commands = s:get_cmd_list() 238 | let filtered_list = [] 239 | 240 | " Try to find the only completion. 241 | for pattern in call(g:ambicmd#build_rule, [a:target]) 242 | let filtered = filter(copy(commands), 'v:val =~? pattern') 243 | if len(filtered) == 1 244 | return [filtered[0], 1] 245 | endif 246 | call add(filtered_list, filtered) 247 | endfor 248 | 249 | " Emulate "longest" function of 'wildmode'. 250 | for filtered in filtered_list 251 | if empty(filtered) 252 | continue 253 | endif 254 | let common = filtered[0] 255 | for completion in filtered[1 :] 256 | let common = matchstr(common, '^\C\%[' . completion . ']') 257 | endfor 258 | if strlen(common) >= strlen(a:target) 259 | return [common, 0] 260 | endif 261 | endfor 262 | 263 | call s:cancel_expanding() 264 | endfunction 265 | 266 | function! ambicmd#expand(keys) abort 267 | let [is_cmdline, is_cmdwin, cmdtype] = s:get_cmdline_info() 268 | if (is_cmdline || is_cmdwin) && cmdtype !=# ':' 269 | return a:keys 270 | endif 271 | let [cmdline, after_cursor] = s:str_divide_pos( 272 | \ (is_cmdline ? getcmdline() : getline('.')), 273 | \ (is_cmdline ? getcmdpos() : col('.')) - 1 274 | \ ) 275 | if after_cursor =~# '^\w' || cmdline ==# '' 276 | return a:keys 277 | endif 278 | 279 | try 280 | let [target, bang] = s:parse_cmd(cmdline) 281 | let [completion, is_fullmatch] = s:get_completion(target) 282 | catch /^ambicmd\:\sCancelExpanding$/ 283 | return a:keys 284 | endtry 285 | if target ==# completion && is_fullmatch 286 | return a:keys 287 | endif 288 | 289 | let prefix = (!is_cmdline && pumvisible()) ? "\" : '' 290 | 291 | if is_fullmatch 292 | let suffix = a:keys 293 | elseif is_cmdline 294 | if g:ambicmd#show_completion_menu && &wildmenu && &wildcharm != 0 295 | let suffix = nr2char(&wildcharm) 296 | else 297 | let suffix = "\" 298 | endif 299 | elseif is_cmdwin && g:ambicmd#show_completion_menu 300 | let suffix = "\\" 301 | else 302 | let suffix = '' 303 | endif 304 | 305 | if is_fullmatch 306 | let completion .= bang 307 | endif 308 | return prefix . repeat("\", strlen(target . bang)) . completion . suffix 309 | endfunction 310 | -------------------------------------------------------------------------------- /doc/ambicmd.txt: -------------------------------------------------------------------------------- 1 | *ambicmd.txt* You can use ambiguous commands. 2 | 3 | Version: 0.6.0 4 | Authors: thinca 5 | Shougo 6 | tyru 7 | mityu 8 | License: zlib License 9 | 10 | ============================================================================== 11 | CONTENTS *ambicmd-contents* 12 | 13 | INTRODUCTION |ambicmd-introduction| 14 | INTERFACE |ambicmd-interface| 15 | FUNCTIONS |ambicmd-functions| 16 | CUSTOMIZING |ambicmd-customizing| 17 | EXPANDING RULE |ambicmd-expanding-rule| 18 | SETTING EXAMPLES |ambicmd-setting-examples| 19 | TODO |ambicmd-todo| 20 | CHANGELOG |ambicmd-changelog| 21 | 22 | 23 | 24 | ============================================================================== 25 | INTRODUCTION *ambicmd-introduction* 26 | 27 | *ambicmd* is a Vim plugin to use ambiguous commands. 28 | Some plugins provide many useful commands, but sometimes these are very long. 29 | At this time, you will define the key mappings to execute these. However: 30 | 31 | - You will have to define quite a lot of key mappings. 32 | - You should find unused key sequences for mapping. 33 | - Do you define a key mapping for a command only occasionally used? 34 | 35 | This plugin expands ambiguous {command}s into user-defined commands by some 36 | patterns when they are at: 37 | 38 | - :{command} 39 | - :{some-commands}|{command} 40 | - :global/{pattern}/{command} 41 | - :execute "{command}" 42 | 43 | The following are examples of how this plugin expands ambiguous commands when 44 | you configure this: `:cnoremap ambicmd#expand("\")` 45 | > 46 | ("|" is cursor) 47 | " Expands into the correct name from the lowercase. 48 | :ref => :Ref | 49 | 50 | " Expands from the capital letters of the command. 51 | :qr => :QuickRun | 52 | 53 | " If there are some commands with "NeoComplCache" prefix, complete it. 54 | :ncc => :NeoComplCache| 55 | < 56 | See |ambicmd-expanding-rule| about the expanding rule. 57 | Note that you need write some settings in your vimrc because this plugin does 58 | nothing by default. Please see |ambicmd-setting-examples|. 59 | 60 | 61 | Requirements: 62 | - Vim 7.3 or later 63 | 64 | Latest version: 65 | https://github.com/thinca/vim-ambicmd 66 | 67 | 68 | 69 | ============================================================================== 70 | INTERFACE *ambicmd-interface* 71 | 72 | ------------------------------------------------------------------------------ 73 | FUNCTIONS *ambicmd-functions* 74 | 75 | ambicmd#expand({key-sequence}) *ambicmd#expand()* 76 | Expands the command. 77 | - If the cursor position is not just behind a command, returns 78 | {key-sequence} directly. 79 | - If the command has spaces on its head, returns {key-sequence} 80 | directly too. (Therefore, you can avoid expanding by putting 81 | spaces.) 82 | - If the expanding succeeded, returns the command and {key-sequence}. 83 | - If the candidates of the command starts by the same phrase, returns 84 | it and keys to list or show completion. (See 85 | |g:ambicmd#show_completion_menu| for the details.) 86 | - Otherwise returns {key-sequence}. 87 | See also |ambicmd-setting-examples|. 88 | 89 | 90 | 91 | ============================================================================== 92 | CUSTOMIZING *ambicmd-customizing* 93 | 94 | g:ambicmd#build_rule *g:ambicmd#build_rule* 95 | |String| of function name or |Funcref|. The function takes an inuptted 96 | command as argument, and have to return a list of patterns to filter 97 | user-defined commands. 98 | See |ambicmd-expanding-rule| for the details. 99 | The default value is "ambicmd#default_rule". 100 | 101 | g:ambicmd#show_completion_menu *g:ambicmd#show_completion_menu* 102 | |Number|. 103 | If this value is non-zero: 104 | - When you're in command-line with 'wildmenu' enabled, and 105 | 'wildcharm' set, 'wildcharm' will be used to show the completion 106 | menu; otherwise, will be used instead in the same way as when 107 | this value is zero. (You have to set 'wildmode' and 'wildcharm' 108 | option to enable this option in command-line.) 109 | - When you're in |cmdline-window|, will be used to show the 110 | completion menu. 111 | If this value is zero: 112 | - When you're in command-line, will be used to list completion. 113 | - When you're in |cmdline-window|, nothing will be used. 114 | The default value is 0. 115 | 116 | 117 | 118 | ============================================================================== 119 | EXPANDING RULE *ambicmd-expanding-rule* 120 | 121 | The rule is a list of |regexp| patterns. All of user-defined commands are 122 | filtered by the first pattern. The pattern matching is done with |=~?|. If 123 | the command is narrowed to one, it expand to the command. Otherwise, the next 124 | pattern is tried like same. 125 | When the rule can not decide the only command, searches from the non empty 126 | first result for a common first part. It is expanded when it is found. 127 | Otherwise, nothing is done. 128 | 129 | 130 | 131 | ============================================================================== 132 | SETTING EXAMPLES *ambicmd-setting-examples* 133 | 134 | Expand ambiguous commands with and . 135 | > 136 | cnoremap ambicmd#expand("\") 137 | cnoremap ambicmd#expand("\") 138 | < 139 | Map to with ambicmd. 140 | > 141 | cnoremap ambicmd#expand("\") 142 | > 143 | Use in |cmdline-window|. 144 | > 145 | augroup init_cmdwin 146 | autocmd! 147 | autocmd CmdwinEnter * call s:init_cmdwin() 148 | augroup END 149 | function! s:init_cmdwin() 150 | inoremap ambicmd#expand("\") 151 | inoremap ambicmd#expand("\") 152 | 153 | startinsert! 154 | endfunction 155 | < 156 | 157 | 158 | ============================================================================== 159 | TODO *ambicmd-todo* 160 | 161 | - Improves the expanding rule. 162 | - Any idea? 163 | 164 | - Improves the detecting of input of commands. 165 | - If you want to avoid the expanding, please input it like . 166 | 167 | 168 | 169 | ============================================================================== 170 | CHANGELOG *ambicmd-changelog* 171 | 172 | 0.6.0 2019-05-26 173 | - Add many improvements by mityu. Thanks! 174 | - Support :{some-commands} | {command} 175 | - Support :global/{pattern}/{command} 176 | - Support :execute '{command}' 177 | - Add |g:ambicmd#show_completion_menu|. 178 | 179 | 0.5.1 2015-02-07 180 | - Fix problem in Visual-mode. 181 | 182 | 0.5.0 2011-12-24 183 | - Accepts bang(!) of command. 184 | 185 | 0.4.0 2011-09-26 186 | - Fixed for buffer-local command is not expanded. 187 | - Improved the default rule. 188 | - Improved some behavior. 189 | 190 | 0.3.0 2011-08-29 191 | - Improved some behavior. 192 | - Expands the head of common parts. 193 | - Expanding rule was made customizable. 194 | - Added this document. 195 | 196 | 0.2.0 2010-04-04 197 | - Supported |cmdline-window|. 198 | 199 | 0.1.0 2010-04-04 200 | - Initial version. 201 | 202 | 203 | ============================================================================== 204 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 205 | -------------------------------------------------------------------------------- /test/ambicmd.vimspec: -------------------------------------------------------------------------------- 1 | let s:functions = themis#helper('scope').funcs('autoload/ambicmd.vim') 2 | call themis#func_alias(s:functions) 3 | call themis#helper('command').with(themis#helper('assert')) 4 | 5 | 6 | " NOTE: Don't use `:function!` in order not to overwrite. 7 | Describe s:str_divide_pos() 8 | Before all 9 | let StrDividePos = s:functions.str_divide_pos 10 | End 11 | It separates a string into two strings by position 12 | let str = '0123456789' 13 | Assert Equals(StrDividePos(str, 4), ['0123', '456789']) 14 | Assert Equals(StrDividePos(str, 0), ['', '0123456789']) 15 | End 16 | End 17 | Describe s:separate_cmd_bang() 18 | Before all 19 | function SeparateCmdBang(cmd) 20 | return s:functions.separate_cmd_bang(a:cmd) 21 | endfunction 22 | End 23 | It separates '!' if it's given 24 | Assert Equals(SeparateCmdBang('cmd!'), ['cmd', '!']) 25 | End 26 | It does nothing if '!' isn't given 27 | Assert Equals(SeparateCmdBang('cmd'), ['cmd', '']) 28 | End 29 | After all 30 | delfunction SeparateCmdBang 31 | End 32 | End 33 | Describe s:remove_range_specifier() 34 | Before all 35 | function RemoveRange(cmdline) 36 | return s:functions.remove_range_specifier(a:cmdline) 37 | endfunction 38 | End 39 | It removes range 40 | let ranges = ['%', '$', '.', "'<,'>", '1,10', '1, 10', '4', '/hoge/', 41 | \ '?fuga?', '\/', '\?', '\&'] 42 | let extensions = ['', '+3', '-1'] 43 | for range in ranges 44 | for extension in extensions 45 | let cmdline = range . extension . 'cmd' 46 | Assert Equals(RemoveRange(cmdline), 'cmd') 47 | endfor 48 | endfor 49 | End 50 | It does nothing when range isn't provided 51 | Assert Equals(RemoveRange('cmd'), 'cmd') 52 | End 53 | After all 54 | delfunction RemoveRange 55 | End 56 | End 57 | Describe s:parse_cmd() 58 | Before all 59 | function PickTarget(cmdline) abort 60 | try 61 | return s:functions.parse_cmd(a:cmdline)[0] 62 | catch /^ambicmd\:\sCancelExpanding$/ 63 | return '' 64 | endtry 65 | endfunction 66 | End 67 | It picks the command 68 | Assert Equals(PickTarget('cmd'), 'cmd') 69 | End 70 | It picks the command with '!' 71 | Assert Equals(PickTarget('cmd!'), 'cmd') 72 | End 73 | It won't pick the command when inputting arguments 74 | Assert Equals(PickTarget('cmd hoge'), '') 75 | End 76 | It doesn't allow leading spaces 77 | Assert Equals(PickTarget(' cmd'), '') 78 | Assert Equals(PickTarget('some_cmd| cmd'), '') 79 | Assert Equals(PickTarget(' some_cmd|cmd'), 'cmd') 80 | Assert Equals(PickTarget('% cmd'), '') 81 | Assert Equals(PickTarget(' %cmd'), '') 82 | Assert Equals(PickTarget(' some_cmd|% cmd'), '') 83 | Assert Equals(PickTarget(' some_cmd| ''<,''>cmd'), '') 84 | Assert Equals(PickTarget(' g/pat/ com'), '') 85 | Assert Equals(PickTarget(' execute " com'), '') 86 | End 87 | It supports :global 88 | Assert Equals(PickTarget('g/pat/cmd'), 'cmd') 89 | Assert Equals(PickTarget('g/pat/cmd hoge'), '') 90 | Assert Equals(PickTarget('g/pat/cmd'), 'cmd') 91 | End 92 | It supports :global! 93 | Assert Equals(PickTarget('g!/pat/cmd'), 'cmd') 94 | Assert Equals(PickTarget('g!/pat/cmd hoge'), '') 95 | Assert Equals(PickTarget('g!/pat/cmd'), 'cmd') 96 | End 97 | It supports :vglobal 98 | Assert Equals(PickTarget('v/pat/cmd'), 'cmd') 99 | Assert Equals(PickTarget('v/pat/cmd hoge'), '') 100 | Assert Equals(PickTarget('v/pat/cmd'), 'cmd') 101 | End 102 | It supports :global with its separator is not '/' 103 | Assert Equals(PickTarget('g?pat?cmd'), 'cmd') 104 | End 105 | It supports :global with its separator is in {pattern} with escaped 106 | Assert Equals(PickTarget('g/pat\/tern/cmd'), 'cmd') 107 | End 108 | It supports :global even if exists in {pattern} 109 | Assert Equals(PickTarget('g/\v(pat|tern)/cmd'), 'cmd') 110 | End 111 | It picks nothing when pattern of :global hasn't finished yet 112 | Assert Equals(PickTarget('g/\v(pat|tern'), '') 113 | End 114 | Context in :execute 115 | It picks a command 116 | Assert Equals(PickTarget('execute "cmd'), 'cmd') 117 | Assert Equals(PickTarget("execute 'cmd"), 'cmd') 118 | End 119 | It picks nothing when inputting command's arguments 120 | Assert Equals(PickTarget('execute "cmd args'), '') 121 | Assert Equals(PickTarget("execute 'cmd args"), '') 122 | End 123 | It picks a command just after 124 | Assert Equals(PickTarget('execute "another_cmd args|cmd'), 'cmd') 125 | Assert Equals(PickTarget("execute 'another_cmd args|cmd"), 'cmd') 126 | End 127 | It supports string concatenation 128 | Assert Equals(PickTarget('execute "some_cmd" "cmd'), 'cmd') 129 | Assert Equals(PickTarget("execute 'some_cmd' 'cmd"), 'cmd') 130 | End 131 | It supports strings and variables in its arguments 132 | Assert Equals(PickTarget('execute "string_arg" args'), '') 133 | Assert Equals(PickTarget('execute args "string_arg"'), '') 134 | End 135 | It supports escaped quotes in arguments 136 | Assert Equals(PickTarget('execute "string\"argument"|cmd'), 'cmd') 137 | Assert Equals(PickTarget("execute 'string''argument'|cmd"), 'cmd') 138 | Assert Equals(PickTarget("execute \"'<,'>cmd"), 'cmd') 139 | Assert Equals(PickTarget("execute '''<,''>cmd"), 'cmd') 140 | End 141 | End 142 | It can find the end of :execute 143 | Assert Equals(PickTarget('execute "some_cmd"|cmd'), 'cmd') 144 | Assert Equals(PickTarget("execute 'some_cmd'|cmd"), 'cmd') 145 | Assert Equals(PickTarget("execute '%some_cmd'|cmd"), 'cmd') 146 | Assert Equals(PickTarget("execute '''<,''>some_cmd'|cmd"), 'cmd') 147 | End 148 | It can find the end of :execute strings and variables as its arguments 149 | Assert Equals(PickTarget('execute "string_arg" args|cmd'), 'cmd') 150 | Assert Equals(PickTarget('execute args "string_arg"|cmd'), 'cmd') 151 | End 152 | It can find the end of :execute with variables as its arguments 153 | Assert Equals(PickTarget('execute args|cmd'), 'cmd') 154 | Assert Equals(PickTarget('execute args'), '') 155 | End 156 | It supports single quote in double-quoted string in :execute's arguments 157 | Assert Equals(PickTarget('execute "string''arg"|cmd'), 'cmd') 158 | End 159 | It supports double quote in single-quoted string in :execute's arguments 160 | Assert Equals(PickTarget("execute 'string\"arg'|cmd"), 'cmd') 161 | End 162 | It supports nested :execute 163 | Assert Equals(PickTarget('execute "execute \"cmd'), 'cmd') 164 | Assert Equals(PickTarget("execute 'execute ''cmd"), 'cmd') 165 | Assert Equals(PickTarget('execute "execute \"some_cmd\""|cmd'), 'cmd') 166 | Assert Equals(PickTarget("execute 'execute ''some_cmd'''|cmd"), 'cmd') 167 | End 168 | It picks the latest command 169 | Assert Equals(PickTarget('before|cmd'), 'cmd') 170 | End 171 | It supports :global 172 | Assert Equals(PickTarget('g/pat/before|cmd'), 'cmd') 173 | End 174 | It supports nested :global (Is it available in Vim?) 175 | Assert Equals(PickTarget('g/pat/g/pat2/cmd'), 'cmd') 176 | Assert Equals(PickTarget('g/pat/%g/pat2/cmd'), 'cmd') 177 | Assert Equals(PickTarget('g/pat/before|g/pat2/cmd'), 'cmd') 178 | Assert Equals(PickTarget('g/pat/before|%g/pat2/cmd'), 'cmd') 179 | End 180 | After all 181 | delfunction PickTarget 182 | End 183 | End 184 | Describe s:get_completion() 185 | Before all 186 | command! Hoge echo 'Do nothing' 187 | command! FooBar echo 'Do nothing' 188 | command! FooBaz echo 'Do nothing' 189 | command! FooFoo echo 'Do nothing' 190 | 191 | function GetCompletion(target) 192 | try 193 | return s:functions.get_completion(a:target) 194 | catch /^ambicmd\:\sCancelExpanding$/ 195 | return 0 196 | endtry 197 | endfunction 198 | End 199 | It expands an ambiguous command into a user-defined command 200 | Assert Equals(GetCompletion('hoge'), ['Hoge', 1]) 201 | Assert Equals(GetCompletion('hog'), ['Hoge', 1]) 202 | Assert Equals(GetCompletion('ho'), ['Hoge', 1]) 203 | End 204 | It doesn't expand a command if it is a built-in command 205 | Assert Equals(GetCompletion('h'), 0) 206 | Assert Equals(GetCompletion('f'), 0) 207 | Assert Equals(GetCompletion('fo'), 0) 208 | End 209 | It emulates longest of 'wildmode' feature 210 | Assert Equals(GetCompletion('foo'), ['Foo', 0]) 211 | Assert Equals(GetCompletion('foob'), ['FooBa', 0]) 212 | End 213 | After all 214 | delcommand Hoge 215 | delcommand FooBar 216 | delcommand FooBaz 217 | delcommand FooFoo 218 | delfunction GetCompletion 219 | End 220 | End 221 | Describe ambicmd.vim 222 | Before all 223 | command! FooFoo put ='FooFoo' 224 | command! FooBar put ='FooBar' 225 | command! Hoge put ='Hoge' 226 | command! -nargs=1 Put put ='' 227 | 228 | cnoremap @ ambicmd#expand('') . '' 229 | End 230 | 231 | Before each 232 | silent % delete _ 233 | End 234 | 235 | Context in Command-line mode 236 | It expands ambiguous command to strict command 237 | normal :hoge@ 238 | Assert Equals(getline('.'), 'Hoge') 239 | End 240 | 241 | It completes the common head of the ambiguous commands 242 | Throws /^Vim:E464/ :normal :foo@ 243 | End 244 | 245 | It does not expand at the argument 246 | normal :Put hoge@ 247 | Assert Equals(getline('.'), 'hoge') 248 | End 249 | End 250 | 251 | Context in searching of Visual mode 252 | It does not expand 253 | 0 put = ['hoge ', 'hoge', 'Hoge'] 254 | call cursor(1, 5) 255 | normal v/hoge@ 256 | Assert Equals(line('.'), 2) 257 | End 258 | End 259 | End 260 | --------------------------------------------------------------------------------