Skip to content
Browse files

Version 3.2

Escape special characters in filenames for security reasons. On MS-Windows, use the _vim_mru_files file from the $USERPROFILE directory. When the ':vimgrep' command is used, don't add the files to the MRU list. When getting the files matching a pattern, first try it as a literal string. Show tooltip text for MRU menu entries.
  • Loading branch information...
1 parent 17e7597 commit 3e95376cc9f44e4dcb82e35d783ea3c79f1ae6c5 @yegappan yegappan committed with Sep 23, 2008
Showing with 127 additions and 41 deletions.
  1. +127 −41 plugin/mru.vim
View
168 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 <silent> &File.Recent\ Files.' . a:prefix . esc_fname .
- \ '\ (' . esc_dir_name . ')' .
- \ " :call <SID>MRU_Edit_File('" . fname . "')<CR>"
+ 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 <silent> ' . menu_path .
+ \ " :call <SID>MRU_Edit_File('" . esc_mfname . "', 1)<CR>"
+ exe 'tmenu ' . menu_path . ' Edit file ' . esc_mfname
endfor
endfunction
@@ -658,11 +735,14 @@ function! s:MRU_Refresh_Menu()
anoremenu <silent> &File.Recent\ Files.Refresh\ list
\ :call <SID>MRU_LoadList()<CR>
+ 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('<abuf>'))
autocmd BufNewFile * call s:MRU_AddFile(expand('<abuf>'))
autocmd BufWritePost * call s:MRU_AddFile(expand('<abuf>'))
+" 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(<q-args>)

0 comments on commit 3e95376

Please sign in to comment.
Something went wrong with that request. Please try again.