Skip to content

Commit

Permalink
Version 3.2
Browse files Browse the repository at this point in the history
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
yegappan authored and vim-scripts committed Oct 18, 2010
1 parent 17e7597 commit 3e95376
Showing 1 changed file with 127 additions and 41 deletions.
168 changes: 127 additions & 41 deletions 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
" --------
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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'
"
Expand All @@ -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.
"
Expand Down Expand Up @@ -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')
Expand All @@ -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

Expand All @@ -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 = []
Expand All @@ -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 == ''
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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'
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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')
Expand All @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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>)
Expand Down

0 comments on commit 3e95376

Please sign in to comment.