├── .gitignore ├── doc └── emacscommandline.txt └── plugin └── emacscommandline.vim /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | -------------------------------------------------------------------------------- /doc/emacscommandline.txt: -------------------------------------------------------------------------------- 1 | *emacscommandline.txt* Emacs- (or Bash-) style mappings *emacscommandline* 2 | for command-line mode 3 | 4 | Author: Houtsnip 5 | *emacscommandline-author* 6 | Licence: Same terms as Vim itself (see |license|) 7 | 8 | CONTENTS *emacscommandline-contents* 9 | 10 | 1. Introduction |emacscommandline-intro| 11 | 2. Movement commands |emacscommandline-movement| 12 | 3. Deletion commands |emacscommandline-deletion| 13 | 4. History commands |emacscommandline-history| 14 | 5. Other commands |emacscommandline-other| 15 | 6. Customization |emacscommandline-customize| 16 | 7. Old keys |emacscommandline-old-keys| 17 | 8. Limitations |emacscommandline-limit| 18 | 19 | INTRODUCTION *emacscommandline-intro* 20 | 21 | This plugin makes the command-line mode behave more like the Unix command 22 | line, by adding Emacs-style mappings (like in the Bash shell). Some of the 23 | mappings just map existing vim commands, but the rest implement functionality 24 | that is not available natively. 25 | 26 | There is another similar plugin (vim-rsi) which covers most of the same 27 | mappings, but there are differences between the two plugins. vim-rsi — 28 | 29 | • also creates mappings in insert mode 30 | • doesn’t have undo functionality 31 | • doesn’t ruin the expression register (see |emacscommandline-limit|) 32 | • doesn’t distinguish between |CTRL-W| and |META-Backspace| 33 | • uses the in-built vim behaviour for |META-B|, |META-F|, and |META-D| 34 | • doesn’t map |CTRL-K| or |CTRL-R| 35 | • has a mapping for transposing two characters 36 | 37 | MOVEMENT *emacscommandline-movement* 38 | 39 | *CTRL-A* Move cursor to beginning of line 40 | 41 | *CTRL-E* Move cursor to end of line (i.e the native vim behaviour: 42 | see |c_CTRL-E|). Not actually a re-mapping, but noted here 43 | anyway for completeness. 44 | 45 | (This mapping isn’t used when the cursor is at the end of 46 | the line — although it doesn’t over-ride anything anyway. 47 | See also |g:EmacsCommandLineEndOfLineNoMapAtEnd|.) 48 | 49 | *CTRL-B* Move cursor one character backwards 50 | 51 | *CTRL-F* Move cursor one character forwards 52 | 53 | (This mapping isn’t used when the cursor is at the end of 54 | the line. At all other times it over-rides opening the 55 | command-line window, i.e. |c_CTRL-F|. 56 | See also |g:EmacsCommandLineForwardCharNoMapAtEnd|.) 57 | 58 | *META-B* Move cursor one word backwards 59 | 60 | *META-F* Move cursor one word forwards 61 | 62 | DELETION *emacscommandline-deletion* 63 | 64 | *CTRL-D* Delete character under cursor 65 | 66 | (This mapping isn’t used when the cursor is at the end of 67 | the line. At all other times it over-rides listing names 68 | matching the pattern in front of cursor, i.e. |c_CTRL-D|. 69 | See also |g:EmacsCommandLineDeleteCharNoMapAtEnd|.) 70 | 71 | *CTRL-K* Kill line (delete from character under cursor to end of line) 72 | 73 | (This mapping isn’t used when the cursor is at the end of 74 | the line. At all other times it over-rides inserting 75 | digraphs, i.e. |c_CTRL-K|. 76 | See also |g:EmacsCommandLineKillLineNoMapAtEnd|.) 77 | 78 | *CTRL-U* Backwards kill line (delete backwards to beginning of line) 79 | (i.e. the same behaviour as in Bash: unix-line-discard) 80 | 81 | *META-D* Delete word under cursor 82 | 83 | *META-Backspace* Delete word backwards 84 | 85 | (This is subtly different from |CTRL-W|.) 86 | 87 | *CTRL-W* Delete backwards to previous white-space character 88 | (i.e. the same behaviour as in Bash: unix-word-rubout) 89 | 90 | (This is subtly different from |META-Backspace|.) 91 | 92 | HISTORY *emacscommandline-history* 93 | 94 | *CTRL-P* Previous line in history (same as |c_|) 95 | 96 | *CTRL-N* Next line in history (same as |c_|) 97 | 98 | *META-<* First line in history 99 | 100 | *META->* Last line in history 101 | 102 | *CTRL-R* Search history backwards 103 | 104 | (This mapping is only used when the command line is empty — 105 | in which case it over-rides inserting registers, 106 | i.e. |c_CTRL-R|. See also 107 | |g:EmacsCommandLineSearchCommandLineMapOnlyWhenEmpty|.) 108 | 109 | OTHER *emacscommandline-other* 110 | 111 | *CTRL-T* Transpose character under cursor with previous character 112 | 113 | *CTRL-Y* Paste (yank) last deleted text (over-rides |c_CTRL-Y|). 114 | 115 | (Note that in Emacs, ‘yank’ means ‘paste’, whereas in vim it 116 | means ‘copy’. The same text is also available in the 117 | registry ‘c’.) 118 | 119 | *CTRL-_* Undo last change (over-rides |c_CTRL-_|) 120 | *CTRL-X_CTRL-U* " " " 121 | 122 | (See also |g:EmacsCommandLineMaxUndoHistory|) 123 | 124 | *CTRL-G* Abort command and go back to normal mode (same as |c_CTRL-C|) 125 | 126 | *CTRL-Z* Toggle command-line as external command (over-rides suspend 127 | vim in the terminal) 128 | 129 | CUSTOMIZATION *emacscommandline-customize* 130 | 131 | A number of options may be set in your |.vimrc| to influence the behaviour of 132 | the plug-in. To set an option, you include a line like this in your |.vimrc|: 133 | 134 | let g:EmacsCommandLineSearchCommandLineDisable = 1 135 | 136 | All available options: 137 | 138 | *g:EmacsCommandLineMaxUndoHistory* 139 | number (default 100) 140 | |g:EmacsCommandLineMaxUndoHistory| 141 | 142 | The maximum number of undo states that will be remembered (accessible 143 | by the undo command (|CTRL-_|). (See |emacscommandline-other|) 144 | 145 | *g:EmacsCommandLineOldMapPrefix* 146 | string (default '') 147 | |g:EmacsCommandLineOldMapPrefix| 148 | 149 | The prefix to use to access the old functionality (if clobbered by the 150 | mappings made by this plugin). (See |emacscommandline-old-keys|) 151 | 152 | *g:EmacsCommandLine[Command]Disable* 153 | number (default 0) 154 | *g:EmacsCommandLineBeginningOfLineDisable* 155 | *g:EmacsCommandLineEndOfLineDisable* 156 | *g:EmacsCommandLineBackwardCharDisable* 157 | *g:EmacsCommandLineForwardCharDisable* 158 | *g:EmacsCommandLineBackwardWordDisable* 159 | *g:EmacsCommandLineForwardWordDisable* 160 | *g:EmacsCommandLineDeleteCharDisable* 161 | *g:EmacsCommandLineBackwardDeleteCharDisable* 162 | *g:EmacsCommandLineKillLineDisable* 163 | *g:EmacsCommandLineBackwardKillLineDisable* 164 | *g:EmacsCommandLineKillWordDisable* 165 | *g:EmacsCommandLineBackwardKillWordDisable* 166 | *g:EmacsCommandLineDeleteBackwardsToWhiteSpaceDisable* 167 | *g:EmacsCommandLineOlderMatchingCommandLineDisable* 168 | *g:EmacsCommandLineNewerMatchingCommandLineDisable* 169 | *g:EmacsCommandLineFirstLineInHistoryDisable* 170 | *g:EmacsCommandLineLastLineInHistoryDisable* 171 | *g:EmacsCommandLineSearchCommandLineDisable* 172 | *g:EmacsCommandLineTransposeCharDisable* 173 | *g:EmacsCommandLineYankDisable* 174 | *g:EmacsCommandLineUndoDisable* 175 | *g:EmacsCommandLineAbortCommandDisable* 176 | *g:EmacsCommandLineToggleExternalCommandDisable* 177 | 178 | These options all have the format g:EmacsCommandLine[Command]Disable, 179 | where “[Command]” refers to a specific mapping. 180 | 181 | If any option is defined and set to 1, the relevant mapping will not 182 | be made. 183 | 184 | E.g. — 185 | let g:EmacsCommandLineToggleExternalCommandDisable = 1 186 | 187 | *g:EmacsCommandLine[Command]Map* 188 | string or list of strings 189 | (defaults to mappings as above) 190 | *g:EmacsCommandLineBeginningOfLineMap* 191 | *g:EmacsCommandLineEndOfLineMap* 192 | *g:EmacsCommandLineBackwardCharMap* 193 | *g:EmacsCommandLineForwardCharMap* 194 | *g:EmacsCommandLineBackwardWordMap* 195 | *g:EmacsCommandLineForwardWordMap* 196 | *g:EmacsCommandLineDeleteCharMap* 197 | *g:EmacsCommandLineBackwardDeleteCharMap* 198 | *g:EmacsCommandLineKillLineMap* 199 | *g:EmacsCommandLineBackwardKillLineMap* 200 | *g:EmacsCommandLineKillWordMap* 201 | *g:EmacsCommandLineBackwardKillWordMap* 202 | *g:EmacsCommandLineDeleteBackwardsToWhiteSpaceMap* 203 | *g:EmacsCommandLineOlderMatchingCommandLineMap* 204 | *g:EmacsCommandLineNewerMatchingCommandLineMap* 205 | *g:EmacsCommandLineFirstLineInHistoryMap* 206 | *g:EmacsCommandLineLastLineInHistoryMap* 207 | *g:EmacsCommandLineSearchCommandLineMap* 208 | *g:EmacsCommandLineTransposeCharMap* 209 | *g:EmacsCommandLineYankMap* 210 | *g:EmacsCommandLineUndoMap* 211 | *g:EmacsCommandLineAbortCommandMap* 212 | *g:EmacsCommandLineToggleExternalCommandMap* 213 | 214 | These options all have the format g:EmacsCommandLine[Command]Map, 215 | where “[Command]” refers to a specific mapping. 216 | 217 | The option, if defined, will set the mapping used, instead of the 218 | relevant mapping as listed above. 219 | 220 | You can also set the option to a list of strings, in order to define 221 | more than one mapping for the same command. 222 | 223 | E.g. — 224 | let g:EmacsCommandLineSearchCommandLineMap = '' 225 | let g:EmacsCommandLineBeginningOfLineMap = ['', ''] 226 | 227 | *g:EmacsCommandLine[Command]MapOnlyWhenEmpty* 228 | number (default varies) 229 | *g:EmacsCommandLineBeginningOfLineMapOnlyWhenEmpty* 230 | *g:EmacsCommandLineEndOfLineMapOnlyWhenEmpty* 231 | *g:EmacsCommandLineBackwardCharMapOnlyWhenEmpty* 232 | *g:EmacsCommandLineForwardCharMapOnlyWhenEmpty* 233 | *g:EmacsCommandLineBackwardWordMapOnlyWhenEmpty* 234 | *g:EmacsCommandLineForwardWordMapOnlyWhenEmpty* 235 | *g:EmacsCommandLineDeleteCharMapOnlyWhenEmpty* 236 | *g:EmacsCommandLineBackwardDeleteCharMapOnlyWhenEmpty* 237 | *g:EmacsCommandLineKillLineMapOnlyWhenEmpty* 238 | *g:EmacsCommandLineBackwardKillLineMapOnlyWhenEmpty* 239 | *g:EmacsCommandLineKillWordMapOnlyWhenEmpty* 240 | *g:EmacsCommandLineBackwardKillWordMapOnlyWhenEmpty* 241 | *g:EmacsCommandLineDeleteBackwardsToWhiteSpaceMapOnlyWhenEmpty* 242 | *g:EmacsCommandLineOlderMatchingCommandLineMapOnlyWhenEmpty* 243 | *g:EmacsCommandLineNewerMatchingCommandLineMapOnlyWhenEmpty* 244 | *g:EmacsCommandLineFirstLineInHistoryMapOnlyWhenEmpty* 245 | *g:EmacsCommandLineLastLineInHistoryMapOnlyWhenEmpty* 246 | *g:EmacsCommandLineSearchCommandLineMapOnlyWhenEmpty* 247 | *g:EmacsCommandLineTransposeCharMapOnlyWhenEmpty* 248 | *g:EmacsCommandLineYankMapOnlyWhenEmpty* 249 | *g:EmacsCommandLineUndoMapOnlyWhenEmpty* 250 | *g:EmacsCommandLineAbortCommandMapOnlyWhenEmpty* 251 | *g:EmacsCommandLineToggleExternalCommandMapOnlyWhenEmpty* 252 | 253 | These options all have the format 254 | g:EmacsCommandLine[Command]MapOnlyWhenEmpty, where “[Command]” refers to 255 | a specific mapping. 256 | 257 | If any option is defined and set to 1, the relevant mapping will only be 258 | used when the command line is empty. Otherwise, the native vim 259 | functionality will be used. 260 | 261 | By default, the following mappings are set to 1: 262 | 263 | |g:EmacsCommandLineSearchCommandLineMapOnlyWhenEmpty| 264 | 265 | All others default to 0. 266 | 267 | *g:EmacsCommandLine[Command]NoMapAtEnd* 268 | number (default varies) 269 | *g:EmacsCommandLineBeginningOfLineNoMapAtEnd* 270 | *g:EmacsCommandLineEndOfLineNoMapAtEnd* 271 | *g:EmacsCommandLineBackwardCharNoMapAtEnd* 272 | *g:EmacsCommandLineForwardCharNoMapAtEnd* 273 | *g:EmacsCommandLineBackwardWordNoMapAtEnd* 274 | *g:EmacsCommandLineForwardWordNoMapAtEnd* 275 | *g:EmacsCommandLineDeleteCharNoMapAtEnd* 276 | *g:EmacsCommandLineBackwardDeleteCharNoMapAtEnd* 277 | *g:EmacsCommandLineKillLineNoMapAtEnd* 278 | *g:EmacsCommandLineBackwardKillLineNoMapAtEnd* 279 | *g:EmacsCommandLineKillWordNoMapAtEnd* 280 | *g:EmacsCommandLineBackwardKillWordNoMapAtEnd* 281 | *g:EmacsCommandLineDeleteBackwardsToWhiteSpaceNoMapAtEnd* 282 | *g:EmacsCommandLineOlderMatchingCommandLineNoMapAtEnd* 283 | *g:EmacsCommandLineNewerMatchingCommandLineNoMapAtEnd* 284 | *g:EmacsCommandLineFirstLineInHistoryNoMapAtEnd* 285 | *g:EmacsCommandLineLastLineInHistoryNoMapAtEnd* 286 | *g:EmacsCommandLineSearchCommandLineNoMapAtEnd* 287 | *g:EmacsCommandLineTransposeCharNoMapAtEnd* 288 | *g:EmacsCommandLineYankNoMapAtEnd* 289 | *g:EmacsCommandLineUndoNoMapAtEnd* 290 | *g:EmacsCommandLineAbortCommandNoMapAtEnd* 291 | *g:EmacsCommandLineToggleExternalCommandNoMapAtEnd* 292 | 293 | These options all have the format g:EmacsCommandLine[Command]NoMapAtEnd, 294 | where “[Command]” refers to a specific mapping. 295 | 296 | If any option is defined and set to 1, the relevant mapping will only be 297 | used when the cursor is not at the end of the command line. At the end 298 | of the command line, the native vim functionality will be used. 299 | 300 | By default, the following mappings are set to 1: 301 | 302 | |g:EmacsCommandLineForwardCharNoMapAtEnd| 303 | |g:EmacsCommandLineEndOfLineNoMapAtEnd| 304 | |g:EmacsCommandLineDeleteCharNoMapAtEnd| 305 | |g:EmacsCommandLineKillLineNoMapAtEnd| 306 | 307 | All others default to 0. 308 | 309 | OLD KEYS *emacscommandline-old-keys* 310 | 311 | The old functions are all mapped to the same combination prefixed by CTRL-O. 312 | So for example, to open the command-line window (see |c_CTRL-F|), press 313 | instead CTRL-O_CTRL-F. 314 | 315 | This can be customized using the option|g:EmacsCommandLineOldMapPrefix| (which 316 | defaults to ''). 317 | 318 | LIMITATIONS *emacscommandline-limit* 319 | 320 | This plugin buggers up the expression register (i.e. |c_CTRL-R_=|). This is 321 | a limitation of vim. I don't know how to switch these mappings off in the 322 | expression register and I don't think it's possible. However I never use the 323 | expression register except in mappings, so it doesn't affect me! 324 | 325 | vim:tw=78:et:ft=help:norl: 326 | -------------------------------------------------------------------------------- /plugin/emacscommandline.vim: -------------------------------------------------------------------------------- 1 | if !exists('g:EmacsCommandLineMaxUndoHistory') 2 | let g:EmacsCommandLineMaxUndoHistory = 100 3 | endif 4 | if !exists('g:EmacsCommandLineOldMapPrefix') 5 | let g:EmacsCommandLineOldMapPrefix = '' 6 | endif 7 | if !exists('g:EmacsCommandLineWordCharCharacterClass') 8 | " Latin-1, Latin Extended-A, Extended-B, Greek and Coptic, and Cyrillic scripts: 9 | "let g:EmacsCommandLineWordCharCharacterClass = 'a-zA-Z0-9_À-ÖØ-öø-ÿĀ-ǿȀ-ɏͰ-ͳͶͷΆΈΉΊΌΎ-ΡΣ-ώϚ-ϯϷϸϺϻЀ-ҁ' 10 | " Latin-1 (the most common European letters): 11 | let g:EmacsCommandLineWordCharCharacterClass = 'a-zA-Z0-9_À-ÖØ-öø-ÿ' 12 | " Basic Latin (unaccented) word characters: 13 | "let g:EmacsCommandLineWordCharCharacterClass = '\w' 14 | endif 15 | if !exists('g:EmacsCommandLineSearchCommandLineMapOnlyWhenEmpty') 16 | let g:EmacsCommandLineSearchCommandLineMapOnlyWhenEmpty = 1 17 | endif 18 | if !exists('g:EmacsCommandLineForwardCharNoMapAtEnd') 19 | let g:EmacsCommandLineForwardCharNoMapAtEnd = 1 20 | endif 21 | if !exists('g:EmacsCommandLineEndOfLineNoMapAtEnd') 22 | let g:EmacsCommandLineEndOfLineNoMapAtEnd = 1 23 | endif 24 | if !exists('g:EmacsCommandLineDeleteCharNoMapAtEnd') 25 | let g:EmacsCommandLineDeleteCharNoMapAtEnd = 1 26 | endif 27 | if !exists('g:EmacsCommandLineKillLineNoMapAtEnd') 28 | let g:EmacsCommandLineKillLineNoMapAtEnd = 1 29 | endif 30 | 31 | let s:mappings = { 32 | \ 'ForwardChar': ['', ''], 33 | \ 'BackwardChar': ['', ''], 34 | \ 'BeginningOfLine': ['', ''], 35 | \ 'EndOfLine': ['', ''], 36 | \ 'OlderMatchingCommandLine': ['', ''], 37 | \ 'NewerMatchingCommandLine': ['', ''], 38 | \ 'FirstLineInHistory': ['', 'gg'], 39 | \ 'LastLineInHistory': ['>', 'Gk'], 40 | \ 'SearchCommandLine': ['', '?'], 41 | \ 'AbortCommand': ['', ''] 42 | \ } 43 | if !has('gui_running') && !has('nvim') 44 | let s:mappings['FirstLineInHistory'][0] = '<' 45 | let s:mappings['LastLineInHistory'][0] = '>' 46 | endif 47 | for s:key in keys(s:mappings) 48 | if !exists('g:EmacsCommandLine' . s:key . 'Disable') || g:EmacsCommandLine{s:key}Disable != 1 49 | let s:{s:key}MapDefined = exists('g:EmacsCommandLine' . s:key . 'Map') 50 | if !s:{s:key}MapDefined 51 | let g:EmacsCommandLine{s:key}Map = s:mappings[s:key][0] 52 | endif 53 | if type(g:EmacsCommandLine{s:key}Map) == 3 54 | for s:mapping in g:EmacsCommandLine{s:key}Map 55 | if exists('g:EmacsCommandLine' . s:key . 'MapOnlyWhenEmpty') && g:EmacsCommandLine{s:key}MapOnlyWhenEmpty == 1 56 | exe 'cnoremap ' . s:mapping . ' ' . 57 | \ 'strlen(getcmdline())>0?''' . s:mapping . ''':''' . s:mappings[s:key][1] . '''' 58 | elseif exists('g:EmacsCommandLine' . s:key . 'NoMapAtEnd') && g:EmacsCommandLine{s:key}NoMapAtEnd == 1 59 | exe 'cnoremap ' . s:mapping . ' ' . 60 | \ 'getcmdpos()>strlen(getcmdline())?''' . s:mapping . ''':''' . s:mappings[s:key][1] . '''' 61 | else 62 | exe 'cnoremap ' . s:mapping . ' ' . s:mappings[s:key][1] 63 | endif 64 | if maparg(g:EmacsCommandLineOldMapPrefix . s:mapping, 'c') == '' 65 | exe 'cnoremap ' . g:EmacsCommandLineOldMapPrefix . s:mapping . ' ' . s:mapping 66 | endif 67 | endfor 68 | else 69 | if exists('g:EmacsCommandLine' . s:key . 'MapOnlyWhenEmpty') && g:EmacsCommandLine{s:key}MapOnlyWhenEmpty == 1 70 | exe 'cnoremap ' . g:EmacsCommandLine{s:key}Map . ' ' . 71 | \ 'strlen(getcmdline())>0?''' . g:EmacsCommandLine{s:key}Map . ''':''' . s:mappings[s:key][1] . '''' 72 | elseif exists('g:EmacsCommandLine' . s:key . 'NoMapAtEnd') && g:EmacsCommandLine{s:key}NoMapAtEnd == 1 73 | exe 'cnoremap ' . g:EmacsCommandLine{s:key}Map . ' ' . 74 | \ 'getcmdpos()>strlen(getcmdline())?''' . g:EmacsCommandLine{s:key}Map . ''':''' . s:mappings[s:key][1] . '''' 75 | else 76 | exe 'cnoremap ' . g:EmacsCommandLine{s:key}Map . ' ' . s:mappings[s:key][1] 77 | endif 78 | if maparg(g:EmacsCommandLineOldMapPrefix . g:EmacsCommandLine{s:key}Map, 'c') == '' 79 | exe 'cnoremap ' . g:EmacsCommandLineOldMapPrefix . g:EmacsCommandLine{s:key}Map . ' ' . g:EmacsCommandLine{s:key}Map 80 | endif 81 | endif 82 | endif 83 | endfor 84 | 85 | function! ForwardWord() 86 | let l:loc = strpart(getcmdline(), 0, getcmdpos() - 1) 87 | let l:roc = strpart(getcmdline(), getcmdpos() - 1) 88 | if l:roc =~ '\v^\s*[' . g:EmacsCommandLineWordCharCharacterClass . ']' 89 | let l:rem = matchstr(l:roc, '\v^\s*[' . g:EmacsCommandLineWordCharCharacterClass . ']+') 90 | elseif l:roc =~ '\v^\s*[^[:alnum:]_[:blank:]]' 91 | let l:rem = matchstr(l:roc, '\v^\s*[^[:alnum:]_[:blank:]]+') 92 | else 93 | call setcmdpos(strlen(getcmdline()) + 1) 94 | return getcmdline() 95 | endif 96 | call setcmdpos(strlen(l:loc) + strlen(l:rem) + 1) 97 | return getcmdline() 98 | endfunction 99 | 100 | function! BackwardWord() 101 | let l:loc = strpart(getcmdline(), 0, getcmdpos() - 1) 102 | let l:roc = strpart(getcmdline(), getcmdpos() - 1) 103 | if l:loc =~ '\v[' . g:EmacsCommandLineWordCharCharacterClass . ']\s*$' 104 | let l:rem = matchstr(l:loc, '\v[' . g:EmacsCommandLineWordCharCharacterClass . ']+\s*$') 105 | elseif l:loc =~ '\v[^[:alnum:]_[:blank:]]\s*$' 106 | let l:rem = matchstr(l:loc, '\v[^[:alnum:]_[:blank:]]+\s*$') 107 | else 108 | call setcmdpos(1) 109 | return getcmdline() 110 | endif 111 | let @c = l:rem 112 | call setcmdpos(strlen(l:loc) - strlen(l:rem) + 1) 113 | return getcmdline() 114 | endfunction 115 | 116 | function! DeleteChar() 117 | call SaveUndoHistory(getcmdline(), getcmdpos()) 118 | let l:cmd = getcmdline() 119 | " Get length of character to be deleted (in bytes) 120 | let l:charlen = strlen(matchstr(strpart(l:cmd, getcmdpos() - 1), '^.')) 121 | let l:rem = strpart(l:cmd, getcmdpos() - 1, l:charlen) 122 | if '' != l:rem 123 | let @c = l:rem 124 | endif 125 | let l:ret = strpart(l:cmd, 0, getcmdpos() - 1) . strpart(l:cmd, getcmdpos() + l:charlen - 1) 126 | call SaveUndoHistory(l:ret, getcmdpos()) 127 | return l:ret 128 | endfunction 129 | 130 | function! BackwardDeleteChar() 131 | call SaveUndoHistory(getcmdline(), getcmdpos()) 132 | if getcmdpos() < 2 133 | return getcmdline() 134 | endif 135 | let l:cmd = getcmdline() 136 | " Get length of character to be deleted (in bytes) 137 | let l:charlen = strlen(matchstr(strpart(l:cmd, 0, getcmdpos() - 1), '.$')) 138 | let l:pos = getcmdpos() - l:charlen 139 | let l:rem = strpart(l:cmd, getcmdpos() - l:charlen - 1, l:charlen) 140 | let @c = l:rem 141 | let l:ret = strpart(l:cmd, 0, l:pos - 1) . strpart(l:cmd, getcmdpos() - 1) 142 | call SaveUndoHistory(l:ret, l:pos) 143 | call setcmdpos(l:pos) 144 | return l:ret 145 | endfunction 146 | 147 | function! KillLine() 148 | call SaveUndoHistory(getcmdline(), getcmdpos()) 149 | let l:cmd = getcmdline() 150 | let l:rem = strpart(l:cmd, getcmdpos() - 1) 151 | if '' != l:rem 152 | let @c = l:rem 153 | endif 154 | let l:ret = strpart(l:cmd, 0, getcmdpos() - 1) 155 | call SaveUndoHistory(l:ret, getcmdpos()) 156 | return l:ret 157 | endfunction 158 | 159 | function! BackwardKillLine() 160 | call SaveUndoHistory(getcmdline(), getcmdpos()) 161 | let l:cmd = getcmdline() 162 | let l:rem = strpart(l:cmd, 0, getcmdpos() - 1) 163 | if '' != l:rem 164 | let @c = l:rem 165 | endif 166 | let l:ret = strpart(l:cmd, getcmdpos() - 1) 167 | call SaveUndoHistory(l:ret, 1) 168 | call setcmdpos(1) 169 | return l:ret 170 | endfunction 171 | 172 | function! KillWord() 173 | call SaveUndoHistory(getcmdline(), getcmdpos()) 174 | let l:loc = strpart(getcmdline(), 0, getcmdpos() - 1) 175 | let l:roc = strpart(getcmdline(), getcmdpos() - 1) 176 | if l:roc =~ '\v^\s*[' . g:EmacsCommandLineWordCharCharacterClass . ']' 177 | let l:rem = matchstr(l:roc, '\v^\s*[' . g:EmacsCommandLineWordCharCharacterClass . ']+') 178 | elseif l:roc =~ '\v^\s*[^[:alnum:]_[:blank:]]' 179 | let l:rem = matchstr(l:roc, '\v^\s*[^[:alnum:]_[:blank:]]+') 180 | elseif l:roc =~ '\v^\s+$' 181 | let @c = l:roc 182 | return l:loc 183 | else 184 | return getcmdline() 185 | endif 186 | let @c = l:rem 187 | let l:ret = l:loc . strpart(l:roc, strlen(l:rem)) 188 | call SaveUndoHistory(l:ret, getcmdpos()) 189 | return l:ret 190 | endfunction 191 | 192 | function! DeleteBackwardsToWhiteSpace() 193 | call SaveUndoHistory(getcmdline(), getcmdpos()) 194 | let l:loc = strpart(getcmdline(), 0, getcmdpos() - 1) 195 | let l:roc = strpart(getcmdline(), getcmdpos() - 1) 196 | if l:loc =~ '\v\S\s*$' 197 | let l:rem = matchstr(l:loc, '\v\S+\s*$') 198 | elseif l:loc =~ '\v^\s+$' 199 | let @c = l:loc 200 | call setcmdpos(1) 201 | return l:roc 202 | else 203 | return getcmdline() 204 | endif 205 | let @c = l:rem 206 | let l:pos = getcmdpos() - strlen(l:rem) 207 | let l:ret = strpart(l:loc, 0, strlen(l:loc) - strlen(l:rem)) . l:roc 208 | call SaveUndoHistory(l:ret, l:pos) 209 | call setcmdpos(l:pos) 210 | return l:ret 211 | endfunction 212 | 213 | function! BackwardKillWord() 214 | " Do same as in-built Ctrl-W, except assign deleted text to @c 215 | call SaveUndoHistory(getcmdline(), getcmdpos()) 216 | let l:loc = strpart(getcmdline(), 0, getcmdpos() - 1) 217 | let l:roc = strpart(getcmdline(), getcmdpos() - 1) 218 | if l:loc =~ '\v[' . g:EmacsCommandLineWordCharCharacterClass . ']\s*$' 219 | let l:rem = matchstr(l:loc, '\v[' . g:EmacsCommandLineWordCharCharacterClass . ']+\s*$') 220 | elseif l:loc =~ '\v[^[:alnum:]_[:blank:]]\s*$' 221 | let l:rem = matchstr(l:loc, '\v[^[:alnum:]_[:blank:]]+\s*$') 222 | elseif l:loc =~ '\v^\s+$' 223 | let @c = l:loc 224 | call setcmdpos(1) 225 | return l:roc 226 | else 227 | return getcmdline() 228 | endif 229 | let @c = l:rem 230 | let l:pos = getcmdpos() - strlen(l:rem) 231 | let l:ret = strpart(l:loc, 0, strlen(l:loc) - strlen(l:rem)) . l:roc 232 | call SaveUndoHistory(l:ret, l:pos) 233 | call setcmdpos(l:pos) 234 | return l:ret 235 | endfunction 236 | 237 | function! TransposeChar() 238 | call SaveUndoHistory(getcmdline(), getcmdpos()) 239 | let l:pos = getcmdpos() + strlen(matchstr(strpart(getcmdline(), getcmdpos() - 1), '^.' . (getcmdpos() < 2 ? '.' : ''))) 240 | let l:ret = substitute(strpart(getcmdline(), 0, l:pos - 1), '\v(.*)(.)(.)$', '\1\3\2', '') . strpart(getcmdline(), l:pos - 1) 241 | call SaveUndoHistory(l:ret, l:pos) 242 | call setcmdpos(l:pos) 243 | return l:ret 244 | endfunction 245 | 246 | function! TransposeWord() 247 | let l:loc = strpart(getcmdline(), 0, getcmdpos() - 1) . matchstr(strpart(getcmdline(), getcmdpos() - 1), '^.') 248 | let l:roc = strpart(getcmdline(), strlen(l:loc)) 249 | if l:loc !~ '\v^\s*\S+\s') 250 | return getcmdline() 251 | endi 252 | if l:loc =~ '\s$' 253 | if l:roc =~ '^\s*\S' 254 | let l:loc = l:loc . matchstr(l:roc, '\v^\s*\S+') 255 | let l:roc = strpart(getcmdline(), strlen(l:loc)) 256 | elseif l:roc =~ '^\s*$' 257 | let l:roc = matchstr(l:loc, '\v\s+$') . l:roc 258 | let l:loc = strpart(getcmdline(), 0, strlen(getcmdline()) - strlen(l:roc)) 259 | endif 260 | elseif l:loc =~ '\S$' && l:roc =~ '^\S' 261 | let l:loc = l:loc . matchstr(l:roc, '\v^\S+') 262 | let l:roc = strpart(getcmdline(), strlen(l:loc)) 263 | endif 264 | let l:pos = strlen(l:loc) + 1 265 | let l:ret = substitute(l:loc, '\v^(.{-})(\S+)(\s+)(\S+)(\s*)$', '\1\4\3\2\5', '') . l:roc 266 | call SaveUndoHistory(l:ret, l:pos) 267 | call setcmdpos(l:pos) 268 | return l:ret 269 | endfunction 270 | 271 | function! Yank() 272 | let l:cmd = getcmdline() 273 | call setcmdpos(getcmdpos() + strlen(@c)) 274 | return strpart(l:cmd, 0, getcmdpos() - 1) . @c . strpart(l:cmd, getcmdpos() - 1) 275 | endfunction 276 | 277 | cnoremap eToggleExternalCommand() 278 | function! ToggleExternalCommand() 279 | call SaveUndoHistory(getcmdline(), getcmdpos()) 280 | let l:cmd = getcmdline() 281 | if '!' == strpart(l:cmd, 0, 1) 282 | let l:pos = getcmdpos() - 1 283 | let l:ret = strpart(l:cmd, 1) 284 | else 285 | let l:pos = getcmdpos() + 1 286 | let l:ret = '!' . l:cmd 287 | endif 288 | call SaveUndoHistory(l:ret, l:pos) 289 | call setcmdpos(l:pos) 290 | return l:ret 291 | endfunction 292 | 293 | let s:oldcmdline = [ ] 294 | function! SaveUndoHistory(cmdline, cmdpos) 295 | if len(s:oldcmdline) == 0 || a:cmdline != s:oldcmdline[0][0] 296 | call insert(s:oldcmdline, [ a:cmdline, a:cmdpos ], 0) 297 | else 298 | let s:oldcmdline[0][1] = a:cmdpos 299 | endif 300 | if len(s:oldcmdline) > g:EmacsCommandLineMaxUndoHistory 301 | call remove(s:oldcmdline, g:EmacsCommandLineMaxUndoHistory) 302 | endif 303 | endfunction 304 | 305 | function! Undo() 306 | if len(s:oldcmdline) == 0 307 | return getcmdline() 308 | endif 309 | if getcmdline() ==# s:oldcmdline[0][0] 310 | call remove(s:oldcmdline, 0) 311 | if len(s:oldcmdline) == 0 312 | return getcmdline() 313 | endif 314 | endif 315 | let l:ret = s:oldcmdline[0][0] 316 | call setcmdpos(s:oldcmdline[0][1]) 317 | call remove(s:oldcmdline, 0) 318 | return l:ret 319 | endfunction 320 | 321 | let s:yanklastargno = -1 322 | let s:yanklastargloc = '' 323 | let s:yanklastargroc = '' 324 | let s:yanklastargres = '' 325 | let s:yanklastargcmdpos = 0 326 | let s:argregex = '\v.{-}(\s|^)("([^"]+|\\.)*"|''([^'']+|'''')*''|(\S+|\\\s)*)\s*$' 327 | function! YankLastArg() 328 | if histnr('cmd') < 1 329 | return getcmdline() 330 | endif 331 | if s:yanklastargno < 1 || 332 | \ getcmdline() != s:yanklastargloc . s:yanklastargres . s:yanklastargroc || 333 | \ getcmdpos() != s:yanklastargcmdpos + strlen(s:yanklastargres) 334 | let s:yanklastargno = histnr('cmd') 335 | let s:yanklastargloc = strpart(getcmdline(), 0, getcmdpos() - 1) 336 | let s:yanklastargroc = strpart(getcmdline(), getcmdpos() - 1) 337 | let s:yanklastargres = '' 338 | let s:yanklastargcmdpos = getcmdpos() 339 | else 340 | let s:yanklastargno -= 1 341 | endif 342 | while 0 < s:yanklastargno && 343 | \ ( histget('cmd', s:yanklastargno) !~ '\S' || 344 | \ substitute(histget('cmd', s:yanklastargno), s:argregex, '\2', '') ==# s:yanklastargres 345 | \ ) 346 | let s:yanklastargno = s:yanklastargno - 1 347 | endwhile 348 | if s:yanklastargno < 1 349 | return s:yanklastargloc . s:yanklastargroc 350 | endif 351 | let s:yanklastargres = substitute(histget('cmd', s:yanklastargno), s:argregex, '\2', '') 352 | call setcmdpos(s:yanklastargcmdpos + strlen(s:yanklastargres)) 353 | return s:yanklastargloc . s:yanklastargres . s:yanklastargroc 354 | endfunction 355 | 356 | let s:functions = { 357 | \ 'ForwardWord': '', 358 | \ 'BackwardWord': '', 359 | \ 'DeleteChar': ['', ''], 360 | \ 'BackwardDeleteChar': ['', ''], 361 | \ 'KillLine': '', 362 | \ 'BackwardKillLine': '', 363 | \ 'KillWord': '', 364 | \ 'DeleteBackwardsToWhiteSpace': '', 365 | \ 'BackwardKillWord': '', 366 | \ 'TransposeChar': '', 367 | \ 'TransposeWord': '', 368 | \ 'Yank': '', 369 | \ 'Undo': ['', ''], 370 | \ 'YankLastArg': ['', ''], 371 | \ 'ToggleExternalCommand': '' 372 | \ } 373 | if !has('gui_running') && !has('nvim') 374 | let s:functions['ForwardWord'] = 'f' 375 | let s:functions['BackwardWord'] = 'b' 376 | let s:functions['KillWord'] = 'd' 377 | let s:functions['BackwardKillWord'] = '' 378 | let s:functions['TransposeWord'] = 't' 379 | let s:functions['YankLastArg'] = ['.', '_'] 380 | endif 381 | for s:key in keys(s:functions) 382 | if !exists('g:EmacsCommandLine' . s:key . 'Disable') || g:EmacsCommandLine{s:key}Disable != 1 383 | let s:{s:key}MapDefined = exists('g:EmacsCommandLine' . s:key . 'Map') 384 | if !s:{s:key}MapDefined 385 | let g:EmacsCommandLine{s:key}Map = s:functions[s:key] 386 | endif 387 | if type(g:EmacsCommandLine{s:key}Map) == 3 388 | for s:mapping in g:EmacsCommandLine{s:key}Map 389 | if exists('g:EmacsCommandLine' . s:key . 'MapOnlyWhenEmpty') && g:EmacsCommandLine{s:key}MapOnlyWhenEmpty == 1 390 | exe 'cnoremap ' . s:mapping . ' ' . 391 | \ 'strlen(getcmdline())>0?''' . s:mapping . ''':''e' . s:key . '()''' 392 | elseif exists('g:EmacsCommandLine' . s:key . 'NoMapAtEnd') && g:EmacsCommandLine{s:key}NoMapAtEnd == 1 393 | exe 'cnoremap ' . s:mapping . ' ' . 394 | \ 'getcmdpos()>strlen(getcmdline())?''' . s:mapping . ''':''e' . s:key . '()''' 395 | else 396 | exe 'cnoremap ' . s:mapping . ' e' . s:key . '()' 397 | endif 398 | if maparg(g:EmacsCommandLineOldMapPrefix . s:mapping, 'c') == '' 399 | exe 'cnoremap ' . g:EmacsCommandLineOldMapPrefix . s:mapping . ' ' . s:mapping 400 | endif 401 | endfor 402 | else 403 | if exists('g:EmacsCommandLine' . s:key . 'MapOnlyWhenEmpty') && g:EmacsCommandLine{s:key}MapOnlyWhenEmpty == 1 404 | exe 'cnoremap ' . g:EmacsCommandLine{s:key}Map . ' ' . 405 | \ 'strlen(getcmdline())>0?''' . g:EmacsCommandLine{s:key}Map . ''':''e' . s:key . '()''' 406 | elseif exists('g:EmacsCommandLine' . s:key . 'NoMapAtEnd') && g:EmacsCommandLine{s:key}NoMapAtEnd == 1 407 | exe 'cnoremap ' . g:EmacsCommandLine{s:key}Map . ' ' . 408 | \ 'getcmdpos()>strlen(getcmdline())?''' . g:EmacsCommandLine{s:key}Map . ''':''e' . s:key . '()''' 409 | else 410 | exe 'cnoremap ' . g:EmacsCommandLine{s:key}Map . ' e' . s:key . '()' 411 | endif 412 | if maparg(g:EmacsCommandLineOldMapPrefix . g:EmacsCommandLine{s:key}Map, 'c') == '' 413 | exe 'cnoremap ' . g:EmacsCommandLineOldMapPrefix . g:EmacsCommandLine{s:key}Map . ' ' . g:EmacsCommandLine{s:key}Map 414 | endif 415 | endif 416 | endif 417 | endfor 418 | 419 | --------------------------------------------------------------------------------