""" "" Vimacs (0.93) " " Vim-Improved eMACS " " (Oh dear, what have I got myself into?) " " " Copyright (C) 2002 Andre Pang " " Please see the documentation (vimacs.txt) for the README, installation " notes, and the ChangeLog. " " " This program is free software; you can redistribute it and/or modify " it under the terms of the GNU General Public License as published by " the Free Software Foundation; either version 2 of the License, or " (at your option) any later version. " " This program is distributed in the hope that it will be useful, " but WITHOUT ANY WARRANTY; without even the implied warranty of " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " GNU General Public License for more details. " " You should have received a copy of the GNU General Public License " along with this program; if not, write to the Free Software " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA " " This General Public License does not permit incorporating your program into " proprietary programs. If your program is a subroutine library, you may " consider it more useful to permit linking proprietary applications with the " library. If this is what you want to do, use the GNU Library General " Public License instead of this License. " " TODO: :h map-script " :h cpoptions " :h mapleader " :h map- " :h " :h undo? " :h write-plugin " Have for all maps? " Never load Vimacs if user wants true Vi! (We're not _that_ evil 8) if v:progname =~ '^vi$' finish endif if version < 600 " We require Vim 6 to work :( echoerr 'Vimacs requires Vim 6 to run :(' finish endif " We want to be able to remap <> key codes and do line continuation let s:saved_cpoptions = &cpoptions set cpoptions-=<,C " Set a default value for a variable only if it doesn't exist " (like "$foo |= 'bar'" in Perl) " " Thanks to Piet Delport for this solution, and Benji Fisher for " additional comments :) " function! LetDefault(var_name, value) if !exists(a:var_name) execute 'let ' . a:var_name . '=' . a:value endif endfunction command! -nargs=+ LetDefault call s:LetDefault() " Load Vimacs by default LetDefault g:VM_Enabled 1 " Developers may want to turn this on, to always load the file LetDefault g:VM_Dev 0 if g:VM_Enabled == 0 || (exists("loaded_vimacs") && g:VM_Dev == 0) || &cp finish endif " " Function to mark a cursor position and restore it afterward -- used in a few " functions, like FillParagraph(). Blatantly stolen from foo.vim by Benji " Fisher :) " function! Mark(...) if a:0 == 0 let mark = line(".") . "G" . virtcol(".") . "|" normal! H let mark = "normal!" . line(".") . "Gzt" . mark execute mark return mark elseif a:0 == 1 return "normal!" . a:1 . "G1|" else return "normal!" . a:1 . "G" . a:2 . "|" endif endfun " " It's a good idea to have a command height of at least 2 if showmode is on, " because many important messages will be overwritten by the mode display. " e.g. , which saves the file, will display that the file has been " saved, but the notice will be immediately overwritten by the modeline when " this happens. " " Don't fork around with cmdheight? LetDefault g:VM_CmdHeightAdj 1 if &cmdheight == 1 && &showmode == 1 && g:VM_CmdHeightAdj set cmdheight=2 endif " " Vim options essential for emulating Emacs-ish behaviour " " Turn off / pulling down GUI menu set winaltkeys=no " Emacs normally wraps everything set whichwrap=b,s,<,>,h,l,[,],~ " Emacs always has 'hidden buffers' set hidden " Backspace in Emacs normally backspaces anything :) set backspace=indent,eol,start " Want to be able to use within our mappings " (This has got to be the coolest option name ever, btw) set wildcharm= " Recognise key sequences that start with in Insert Mode set esckeys " " For the UNIX console -- make x == " " Pressing sends x? (As Unix terminals often do) LetDefault g:VM_UnixConsoleMetaSendsEsc 1 " One or two s required to go back to Normal mode? LetDefault g:VM_SingleEscToNormal 1 if has("unix") && !has("gui_running") && g:VM_UnixConsoleMetaSendsEsc " x maps to set =1 set =2 set =3 set =4 set =5 set =6 set =7 set =8 set =9 set =0 set =a set =b set =c set =d set =e set =f set =g set =h set =i set =j set =k set =l set =m set =n set =o set =p set =q set =r set =s set =t set =u set =v set =w set =x set =y set =z set = set =/ " Doing "set >=^[>" throws up an error, so we be dodgey and use Char-190 " instead, which is ASCII 62 ('>' + 128). set => set =< set =0 set =% set =* set =. set =^ " Can't set right now :( set =^[ endif " " One or two s to get back to Normal mode? " " on CmdwinLeave? if g:VM_SingleEscToNormal == 1 if &insertmode if has('unix') && !has('gui_running') && g:VM_UnixConsoleMetaSendsEsc inoremap :UseF1ForNormal else inoremap endif endif set notimeout set ttimeout set timeoutlen=50 else inoremap vnoremap set notimeout set nottimeout endif command! UseF1ForNormal echoerr "Use F1 or to return to Normal mode. :help vimacs-unix-esc-key" " " Insert mode <-> Normal mode <-> Command mode " inoremap : inoremap : inoremap inoremap inoremap inoremap :echo "Returning to Normal mode; press again to suspend Vimacs" nnoremap :call Suspend() " M-` isn't defined in Emacs inoremap 1 inoremap 2 inoremap 3 inoremap 4 inoremap 5 inoremap 6 inoremap 7 inoremap 8 inoremap 9 LetDefault g:VM_NormalMetaXRemap 1 if g:VM_NormalMetaXRemap == 1 nnoremap : endif function! Suspend() suspend! if &insertmode startinsert endif endfunction " " Leaving Vim " inoremap :confirm qall " " Files & Buffers " inoremap :hide edit inoremap :update inoremap s :wall inoremap i :read "what does C-x C-v do? inoremap :write inoremap :set invreadonly inoremap :hide view " " Help Sistemmii (hi Finns) " "inoremap :help " " Error Recovery " inoremap u inoremap u "lots of other stuff :( " " Incremental Searching and Query Replace " inoremap :call StartSearch('/')/ inoremap :call StartSearch('?')? inoremap :cnext " not in Emacs: next in QuickFix inoremap :cprevious " not in Emacs: previous in QuickFix inoremap :call StartSearch('/')/ inoremap :call StartSearch('?')? inoremap :set invhls inoremap :call QueryReplace()() inoremap :call QueryReplace()_regexp() cnoremap ? command! QueryReplace :call QueryReplace()() command! QueryReplaceRegexp :call QueryReplace()_regexp() " Searching is a bit tricky because we have to emulate Emacs's behaviour of " searching again when or is pressed _inside_ the search " commandline. Vim has no equivalent to this, so we must use a bit of " on-the-fly remap trickery (popular in Quake-style games) to provide " different functionality for , depending on whether you're in 'search " mode' or not. " " We must map and because we have to undo the map trickery that we " set up when we abort/finish the search. All in all, it's not too complex " when you actually look at what the code does. " " Note that in Emacs is functionally the same as . LetDefault g:VM_SearchRepeatHighlight 0 function! StartSearch(search_dir) let s:incsearch_status = &incsearch let s:lazyredraw_status = &lazyredraw set incsearch cmap cnoremap :call SearchAgain()/ cnoremap :call SearchAgain()? cnoremap :call StopSearch() cnoremap :call AbortSearch() cnoremap :call AbortSearch() if a:search_dir == '/' cnoremap :set invhls/ else cnoremap :set invhls? endif let s:before_search_mark = Mark() endfunction function! StopSearch() cunmap cunmap cunmap cunmap cunmap cnoremap if exists("s:incsearch_status") let &incsearch = s:incsearch_status unlet s:incsearch_status endif if g:VM_SearchRepeatHighlight == 1 if exists("s:hls_status") let &hls = s:hls_status unlet s:hls_status endif endif endfunction function! AbortSearch() call StopSearch() if exists("s:before_search_mark") execute s:before_search_mark unlet s:before_search_mark endif endfunction function! SearchAgain() if g:VM_SearchRepeatHighlight == 1 if !exists("s:hls_status") let s:hls_status = &hls endif set hls endif endfunction " Emacs' `query-replace' functions function! QueryReplace() let magic_status = &magic set nomagic let searchtext = input("Query replace: ") if searchtext == "" echo "(no text entered): exiting to Insert mode" return endif let replacetext = input("Query replace " . searchtext . " with: ") let searchtext_esc = escape(searchtext,'/\^$') let replacetext_esc = escape(replacetext,'/\') execute ".,$s/" . searchtext_esc . "/" . replacetext_esc . "/cg" let &magic = magic_status endfunction function! QueryReplaceRegexp() let searchtext = input("Query replace regexp: ") if searchtext == "" echo "(no text entered): exiting to Insert mode" return endif let replacetext = input("Query replace regexp " . searchtext . " with: ") let searchtext_esc = escape(searchtext,'/') let replacetext_esc = escape(replacetext,'/') execute ".,$s/" . searchtext_esc . "/" . replacetext_esc . "/cg" endfunction " " Command line editing " " Navigation cmap cmap cnoremap cnoremap cmap cmap " Editing cmap cmap cmap cnoremap " cnoremap cnoremap cnoremap d$ "Should really use &cedit, not just -- but how? " " Navigation " " Insert/Visual/Operator mode maps imap vmap omap imap vmap omap imap vmap omap imap vmap omap inoremap e vnoremap e onoremap e inoremap vnoremap onoremap imap vmap omap imap vmap omap inoremap ( vnoremap ( onoremap ( inoremap ) vnoremap ) onoremap ) inoremap vnoremap onoremap inoremap 1G0 vnoremap 1G0 onoremap 1G0 inoremap > G$ vnoremap > G$ onoremap > G$ inoremap vnoremap onoremap inoremap vnoremap onoremap inoremap ^ vnoremap ^ onoremap ^ inoremap = vnoremap = onoremap = inoremap :call GotoLine() vnoremap :call GotoLine() onoremap :call GotoLine() " Phear, works properly even in Visual/Operator-Pending " modes :) (It's rather dangerous with the latter, though ...) inoremap vnoremap onoremap inoremap vnoremap onoremap inoremap { vnoremap { onoremap { inoremap } vnoremap } onoremap } command! GotoLine :call GotoLine() function! GotoLine() let targetline = input("Goto line: ") if targetline =~ "^\\d\\+$" execute "normal! " . targetline . "G0" elseif targetline =~ "^\\d\\+%$" execute "normal! " . targetline . "%" elseif targetline == "" echo "(cancelled)" else echo " <- Not a Number" endif endfunction command! GotoLine :call GotoLine() " " General Editing " inoremap inoremap d0 inoremap inoremap inoremap = "" Aborting cnoremap onoremap " " Killing and Deleting " inoremap inoremap =KillWord() inoremap inoremap inoremap inoremap =KillLine() " Thanks to Benji Fisher for helping me with getting to work! inoremap d0 inoremap d) inoremap d( inoremap dt inoremap beldwi function! KillWord() if col('.') > strlen(getline('.')) return "\\dw" else return "\dw" endif endfunction function! KillLine() if col('.') > strlen(getline('.')) " At EOL; join with next line return "\" else " Not at EOL; kill until end of line return "\d$" endif endfunction " " Abbreviations " inoremap inoremap inoremap inoremap " " Visual stuff (aka 'marking' aka 'region' aka 'block' etc etc) " set sel=exclusive " Visual mode inoremap =StartVisualMode() " Unix terminals produce , not imap vnoremap vnoremap vnoremap vnoremap "1y "May have to change to "1d and paste ... " Marking blocks inoremap :call StartMarkSel()viw inoremap :call StartMarkSel()vap inoremap :call StartMarkSel()v1G0o inoremap > :call StartMarkSel()vG$o inoremap h :call StartMarkSel()1G0vGo " Block operations vnoremap "1d vnoremap "_d vnoremap o vnoremap U vnoremap : " Pasting inoremap :call ResetKillRing()" inoremap * "inoremap :echoerr "Sorry, yank-pop is not yet implemented!" inoremap :call YankPop() function! YankPop() undo if !exists("s:kill_ring_position") call ResetKillRing() endif execute "normal! i\\" . s:kill_ring_position . "\" call IncrKillRing() endfunction function! ResetKillRing() let s:kill_ring_position = 3 endfunction function! IncrKillRing() if s:kill_ring_position >= 9 let s:kill_ring_position = 2 else let s:kill_ring_position = s:kill_ring_position + 1 endif endfunction function! StartMarkSel() if &selectmode =~ 'key' set keymodel-=stopsel endif endfunction function! StartVisualMode() call StartMarkSel() if col('.') > strlen(getline('.')) " At EOL return "\\v\" else return "\v" endif endfunction " " Use to select text, ala Windows. " (XEmacs supports this) " " We need to make sure that the 'keymodel' option has stopsel before we " start the actual marking, so that the user can cancel it with any " navigational key as she normally would. This is in contrast to the " style of marking, where navigational keys do _not_ cancel " marking. " " Note that this doesn't work properly if the user remaps inoremap :call StartShiftSel() inoremap :call StartShiftSel() inoremap :call StartShiftSel() inoremap :call StartShiftSel() inoremap :call StartShiftSel() inoremap :call StartShiftSel() inoremap :call StartShiftSel() inoremap :call StartShiftSel() function! StartShiftSel() if &selectmode =~ "key" set keymodel+=stopsel endif endfunction " " Window Operations " inoremap 2 s inoremap 3 v inoremap 0 c inoremap 1 o inoremap o w " O is not defined in Emacs ... inoremap O W inoremap w inoremap W inoremap + = inoremap :ScrollOtherWindow inoremap 4 :FindFileOtherWindow inoremap 4f :FindFileOtherWindow function! number_of_windows() let i = 1 while winbufnr(i) != -1 let i = i + 1 endwhile return i - 1 endfunction function! FindFileOtherWindow(filename) let num_windows = number_of_windows() if num_windows <= 1 wincmd s endif wincmd w execute "edit " . a:filename wincmd W endfunction command! -nargs=1 -complete=file FindFileOtherWindow :call FindFileOtherWindow() command! ScrollOtherWindow silent! execute "normal! \w\\W" " " Formatting " inoremap :call FillParagraph() inoremap