diff --git a/plugin/mru.vim b/plugin/mru.vim index 713d009..87006db 100644 --- a/plugin/mru.vim +++ b/plugin/mru.vim @@ -1,7 +1,7 @@ " File: mru.vim " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) -" Version: 3.1 -" Last Modified: February 17, 2008 +" Version: 3.2 +" Last Modified: September 22, 2008 " " Overview " -------- @@ -47,10 +47,10 @@ " " Usage " ----- -" You can use the ":MRU" command to list all the most recently edited file -" names. The file names will be listed in a temporary Vim window. If the MRU -" window is already opened, then the MRU list displayed in the window will be -" refreshed. +" To list and edit files from the MRU list, you have to use the ":MRU" +" command. The ":MRU" command displays the MRU file list in a temporary Vim +" window. If the MRU window is already opened, then the MRU list displayed in +" the window is refreshed. " " If you are using GUI Vim, then the names of the recently edited files are " added to the "File->Recent Files" menu. You can select the name of a file @@ -99,11 +99,11 @@ " plugin. Set the following variables in your .vimrc file using the 'let' " command. " -" The list of recently edit file names is stored in the file specified by the +" The list of recently edited file names is stored in the file specified by the " MRU_File variable. The default setting for this variable is -" $HOME/.vim_mru_files for Unix systems and $VIM/_vim_mru_files for non-Unix -" systems. You can change this variable to point to a file by adding the -" following line to the .vimrc file: +" $HOME/.vim_mru_files for Unix-like systems and $USERPROFILE/_vim_mru_files +" for MS-Windows systems. You can change this variable to point to a file by +" adding the following line to the .vimrc file: " " let MRU_File = 'd:\myhome\_vim_mru_files' " @@ -126,6 +126,16 @@ " " The specified pattern should be a Vim regular expression pattern. " +" If you want to add only file names matching a set of patterns to the MRU +" list, then you can set the MRU_Include_Files variable. This variable should +" be set to a Vim regular expression pattern. For example, to add only .c and +" .h files to the MRU list, you can set this variable as below: +" +" let MRU_Include_Files = '\.c$\|\.h$' +" +" By default, MRU_Include_Files is set to an empty string and all the edited +" filenames are added to the MRU list. +" " The default height of the MRU window is 8. You can set the MRU_Window_Height " variable to change the window height. " @@ -177,6 +187,11 @@ if !exists('MRU_Exclude_Files') let MRU_Exclude_Files = '' endif +" Files to include in the MRU list +if !exists('MRU_Include_Files') + let MRU_Include_Files = '' +endif + " Height of the MRU window " Default height is 8 if !exists('MRU_Window_Height') @@ -192,10 +207,16 @@ if !exists('MRU_Auto_Close') endif if !exists('MRU_File') - if has('unix') - let MRU_File = $HOME . "/.vim_mru_files" + if has('unix') || has('macunix') + let MRU_File = $HOME . '/.vim_mru_files' else - let MRU_File = $VIM . "/_vim_mru_files" + let MRU_File = $VIM . '/_vim_mru_files' + if has('win32') + " MS-Windows + if $USERPROFILE != '' + let MRU_File = $USERPROFILE . '\_vim_mru_files' + endif + endif endif endif @@ -204,19 +225,26 @@ if !exists('MRU_Add_Menu') let MRU_Add_Menu = 1 endif +" Control to temporarily lock the MRU list. Used to prevent files from +" getting added to the MRU list when the ':vimgrep' command is executed. +let s:mru_list_locked = 0 + " MRU_LoadList " Load the latest MRU file list from the MRU file function! s:MRU_LoadList() " Read the list from the MRU file. if filereadable(g:MRU_File) let s:MRU_files = readfile(g:MRU_File) - if s:MRU_files[0] =~# '^" Most recently edited files in Vim' - " Generated by the previous version of the MRU plugin. Ignore the - " list + if s:MRU_files[0] =~# '^\s*" Most recently edited files in Vim' + " Generated by the previous version of the MRU plugin. + " Discard the list. let s:MRU_files = [] elseif s:MRU_files[0] =~# '^#' " Remove the comment line call remove(s:MRU_files, 0) + else + " Unsupported format + let s:MRU_files = [] endif else let s:MRU_files = [] @@ -238,6 +266,11 @@ endfunction " MRU_AddFile " Add a file to the MRU file list function! s:MRU_AddFile(acmd_bufnr) + if s:mru_list_locked + " MRU list is currently locked + return + endif + " Get the full path to the filename let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p') if fname == '' @@ -249,16 +282,24 @@ function! s:MRU_AddFile(acmd_bufnr) return endif + if g:MRU_Include_Files != '' + " If MRU_Include_Files is set, include only files matching the + " specified pattern + if fname !~# g:MRU_Include_Files + return + endif + endif + if g:MRU_Exclude_Files != '' " Do not add files matching the pattern specified in the " MRU_Exclude_Files to the MRU list - if fname =~? g:MRU_Exclude_Files + if fname =~# g:MRU_Exclude_Files return endif endif - " If the filename is already present in the MRU list, then move - " it to the beginning of the list + " If the filename is not already present in the MRU list and is not + " readable then ignore it let idx = index(s:MRU_files, fname) if idx == -1 if !filereadable(fname) @@ -276,7 +317,7 @@ function! s:MRU_AddFile(acmd_bufnr) " Add the new file list to the beginning of the updated old file list call insert(s:MRU_files, fname, 0) - " Return the trimmed list + " Trim the list if len(s:MRU_files) > g:MRU_Max_Entries call remove(s:MRU_files, g:MRU_Max_Entries, -1) endif @@ -299,12 +340,23 @@ function! s:MRU_AddFile(acmd_bufnr) endif endfunction +" Special characters in file names that should be escaped (for security +" reasons) +let s:esc_filename_chars = ' *?[{`$%#"|!<>();&' . "'\t\n" +function! s:MRU_escape_filename(fname) + return escape(a:fname, s:esc_filename_chars) +endfunction + " MRU_Edit_File " Edit the specified file -function! s:MRU_Edit_File(filename) - let fname = escape(a:filename, ' %#"') +function! s:MRU_Edit_File(filename, sanitized) + if !a:sanitized + let esc_fname = s:MRU_escape_filename(a:filename) + else + let esc_fname = a:filename + endif " If the file is already open in one of the windows, jump to it - let winnum = bufwinnr('^' . fname . '$') + let winnum = bufwinnr('^' . a:filename . '$') if winnum != -1 if winnum != winnr() exe winnum . 'wincmd w' @@ -313,9 +365,9 @@ function! s:MRU_Edit_File(filename) if &modified || &buftype != '' || &previewwindow " Current buffer has unsaved changes or is a special buffer or is " the preview window. So open the file in a new window - exe 'split ' . fname + exe 'split ' . esc_fname else - exe 'edit ' . fname + exe 'edit ' . esc_fname endif endif endfunction @@ -332,11 +384,11 @@ function! s:MRU_Window_Edit_File(win_opt) return endif - let fname = escape(fname, ' %#"') + let esc_fname = s:MRU_escape_filename(fname) if a:win_opt == 'newwin' " Edit the file in a new window - exe 'leftabove new ' . fname + exe 'leftabove new ' . esc_fname if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0 " Go back to the MRU window and close it @@ -375,7 +427,7 @@ function! s:MRU_Window_Edit_File(win_opt) exe 'tabnext ' . i else " Open a new tab as the last tab page - exe '999tabnew ' . fname + exe '999tabnew ' . esc_fname endif endif @@ -427,9 +479,9 @@ function! s:MRU_Window_Edit_File(win_opt) if &modified || &buftype != '' || &previewwindow " Current buffer has unsaved changes or is a special buffer or " is the preview window. So open the file in a new window - exe 'split ' . fname + exe 'split ' . esc_fname else - exe 'edit ' . fname + exe 'edit ' . esc_fname endif endif endif @@ -546,11 +598,17 @@ function! s:MRU_Open_Window(...) silent! 0put =s:MRU_files else " Display only the entries matching the specified pattern - silent! 0put =filter(copy(s:MRU_files), 'v:val =~? a:1') + " First try using it as a literal pattern + let m = filter(copy(s:MRU_files), 'stridx(v:val, a:1) != -1') + if len(m) == 0 + " No match. Try using it as a regular expression + let m = filter(copy(s:MRU_files), 'v:val =~# a:1') + endif + silent! 0put =m endif " Move the cursor to the beginning of the file - exe 1 + normal! gg setlocal nomodifiable endfunction @@ -588,8 +646,21 @@ function! s:MRU_Cmd(pat) " filenames containing the string. If only one filename is found, " then edit it. let m = filter(copy(s:MRU_files), 'stridx(v:val, a:pat) != -1') - if len(m) == 1 - call s:MRU_Edit_File(m[0]) + if len(m) > 0 + if len(m) == 1 + call s:MRU_Edit_File(m[0], 0) + return + endif + + " More than one file matches. Try find an accurate match + let new_m = filter(m, 'v:val ==# a:pat') + if len(new_m) == 1 + call s:MRU_Edit_File(new_m[0], 0) + return + endif + + " Couldn't find an exact match, open the MRU window + call s:MRU_Open_Window(a:pat) return endif @@ -605,7 +676,7 @@ function! s:MRU_Cmd(pat) endif if len(m) == 1 - call s:MRU_Edit_File(m[0]) + call s:MRU_Edit_File(m[0], 0) return endif @@ -615,7 +686,9 @@ endfunction function! s:MRU_add_files_to_menu(prefix, file_list) for fname in a:file_list " Escape special characters in the filename - let esc_fname = escape(fnamemodify(fname, ':t'), ". \\|\t%#") + let esc_fname = escape(fnamemodify(fname, ':t'), ".\\" . + \ s:esc_filename_chars) + let esc_fname = substitute(esc_fname, '&', '&&', 'g') " Truncate the directory name if it is long let dir_name = fnamemodify(fname, ':h') @@ -627,11 +700,15 @@ function! s:MRU_add_files_to_menu(prefix, file_list) \ '...' . \ strpart(dir_name, len - 20) endif - let esc_dir_name = escape(dir_name, ". \\|\t") - - exe 'anoremenu &File.Recent\ Files.' . a:prefix . esc_fname . - \ '\ (' . esc_dir_name . ')' . - \ " :call MRU_Edit_File('" . fname . "')" + let esc_dir_name = escape(dir_name, ".\\" . s:esc_filename_chars) + let esc_dir_name = substitute(esc_dir_name, '&', '&&', 'g') + + let menu_path = '&File.Recent\ Files.' . a:prefix . esc_fname . + \ '\ (' . esc_dir_name . ')' + let esc_mfname = s:MRU_escape_filename(fname) + exe 'anoremenu ' . menu_path . + \ " :call MRU_Edit_File('" . esc_mfname . "', 1)" + exe 'tmenu ' . menu_path . ' Edit file ' . esc_mfname endfor endfunction @@ -658,11 +735,14 @@ function! s:MRU_Refresh_Menu() anoremenu &File.Recent\ Files.Refresh\ list \ :call MRU_LoadList() + exe 'tmenu File.Recent\ Files.Refresh\ list Reload the MRU file list from ' + \ . s:MRU_escape_filename(g:MRU_File) anoremenu File.Recent\ Files.-SEP1- : " Add the filenames in the MRU list to the menu let entry_cnt = len(s:MRU_files) if entry_cnt > 10 + " Split the MRU menu into sub-menus for start_idx in range(0, entry_cnt, 10) let last_idx = start_idx + 9 if last_idx >= entry_cnt @@ -692,6 +772,12 @@ autocmd BufRead * call s:MRU_AddFile(expand('')) autocmd BufNewFile * call s:MRU_AddFile(expand('')) autocmd BufWritePost * call s:MRU_AddFile(expand('')) +" The ':vimgrep' command adds all the files searched to the buffer list. +" This also modifies the MRU list, even though the user didn't edit the +" files. Use the following autocmds to prevent this. +autocmd QuickFixCmdPre *vimgrep* let s:mru_list_locked = 1 +autocmd QuickFixCmdPost *vimgrep* let s:mru_list_locked = 0 + " Command to open the MRU window command! -nargs=? -complete=customlist,s:MRU_Complete MRU \ call s:MRU_Cmd()