1
1
" File: mru.vim
2
2
" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
3
- " Version: 3.1
4
- " Last Modified: February 17 , 2008
3
+ " Version: 3.2
4
+ " Last Modified: September 22 , 2008
5
5
"
6
6
" Overview
7
7
" --------
47
47
"
48
48
" Usage
49
49
" -----
50
- " You can use the ":MRU" command to list all the most recently edited file
51
- " names . The file names will be listed in a temporary Vim window. If the MRU
52
- " window is already opened, then the MRU list displayed in the window will be
53
- " refreshed.
50
+ " To list and edit files from the MRU list, you have to use the ":MRU"
51
+ " command . The ":MRU" command displays the MRU file list in a temporary Vim
52
+ " window. If the MRU window is already opened, then the MRU list displayed in
53
+ " the window is refreshed.
54
54
"
55
55
" If you are using GUI Vim, then the names of the recently edited files are
56
56
" added to the "File->Recent Files" menu. You can select the name of a file
99
99
" plugin. Set the following variables in your .vimrc file using the 'let'
100
100
" command.
101
101
"
102
- " The list of recently edit file names is stored in the file specified by the
102
+ " The list of recently edited file names is stored in the file specified by the
103
103
" MRU_File variable. The default setting for this variable is
104
- " $HOME/.vim_mru_files for Unix systems and $VIM /_vim_mru_files for non-Unix
105
- " systems. You can change this variable to point to a file by adding the
106
- " following line to the .vimrc file:
104
+ " $HOME/.vim_mru_files for Unix-like systems and $USERPROFILE /_vim_mru_files
105
+ " for MS-Windows systems. You can change this variable to point to a file by
106
+ " adding the following line to the .vimrc file:
107
107
"
108
108
" let MRU_File = 'd:\myhome\_vim_mru_files'
109
109
"
126
126
"
127
127
" The specified pattern should be a Vim regular expression pattern.
128
128
"
129
+ " If you want to add only file names matching a set of patterns to the MRU
130
+ " list, then you can set the MRU_Include_Files variable. This variable should
131
+ " be set to a Vim regular expression pattern. For example, to add only .c and
132
+ " .h files to the MRU list, you can set this variable as below:
133
+ "
134
+ " let MRU_Include_Files = '\.c$\|\.h$'
135
+ "
136
+ " By default, MRU_Include_Files is set to an empty string and all the edited
137
+ " filenames are added to the MRU list.
138
+ "
129
139
" The default height of the MRU window is 8. You can set the MRU_Window_Height
130
140
" variable to change the window height.
131
141
"
@@ -177,6 +187,11 @@ if !exists('MRU_Exclude_Files')
177
187
let MRU_Exclude_Files = ' '
178
188
endif
179
189
190
+ " Files to include in the MRU list
191
+ if ! exists (' MRU_Include_Files' )
192
+ let MRU_Include_Files = ' '
193
+ endif
194
+
180
195
" Height of the MRU window
181
196
" Default height is 8
182
197
if ! exists (' MRU_Window_Height' )
@@ -192,10 +207,16 @@ if !exists('MRU_Auto_Close')
192
207
endif
193
208
194
209
if ! exists (' MRU_File' )
195
- if has (' unix' )
196
- let MRU_File = $HOME . " /.vim_mru_files"
210
+ if has (' unix' ) || has ( ' macunix ' )
211
+ let MRU_File = $HOME . ' /.vim_mru_files'
197
212
else
198
- let MRU_File = $VIM . " /_vim_mru_files"
213
+ let MRU_File = $VIM . ' /_vim_mru_files'
214
+ if has (' win32' )
215
+ " MS-Windows
216
+ if $USERPROFILE != ' '
217
+ let MRU_File = $USERPROFILE . ' \_vim_mru_files'
218
+ endif
219
+ endif
199
220
endif
200
221
endif
201
222
@@ -204,19 +225,26 @@ if !exists('MRU_Add_Menu')
204
225
let MRU_Add_Menu = 1
205
226
endif
206
227
228
+ " Control to temporarily lock the MRU list. Used to prevent files from
229
+ " getting added to the MRU list when the ':vimgrep' command is executed.
230
+ let s: mru_list_locked = 0
231
+
207
232
" MRU_LoadList
208
233
" Load the latest MRU file list from the MRU file
209
234
function ! s: MRU_LoadList ()
210
235
" Read the list from the MRU file.
211
236
if filereadable (g: MRU_File )
212
237
let s: MRU_files = readfile (g: MRU_File )
213
- if s: MRU_files [0 ] = ~# ' ^" Most recently edited files in Vim'
214
- " Generated by the previous version of the MRU plugin. Ignore the
215
- " list
238
+ if s: MRU_files [0 ] = ~# ' ^\s* " Most recently edited files in Vim'
239
+ " Generated by the previous version of the MRU plugin.
240
+ " Discard the list.
216
241
let s: MRU_files = []
217
242
elseif s: MRU_files [0 ] = ~# ' ^#'
218
243
" Remove the comment line
219
244
call remove (s: MRU_files , 0 )
245
+ else
246
+ " Unsupported format
247
+ let s: MRU_files = []
220
248
endif
221
249
else
222
250
let s: MRU_files = []
@@ -238,6 +266,11 @@ endfunction
238
266
" MRU_AddFile
239
267
" Add a file to the MRU file list
240
268
function ! s: MRU_AddFile (acmd_bufnr)
269
+ if s: mru_list_locked
270
+ " MRU list is currently locked
271
+ return
272
+ endif
273
+
241
274
" Get the full path to the filename
242
275
let fname = fnamemodify (bufname (a: acmd_bufnr + 0 ), ' :p' )
243
276
if fname == ' '
@@ -249,16 +282,24 @@ function! s:MRU_AddFile(acmd_bufnr)
249
282
return
250
283
endif
251
284
285
+ if g: MRU_Include_Files != ' '
286
+ " If MRU_Include_Files is set, include only files matching the
287
+ " specified pattern
288
+ if fname !~# g: MRU_Include_Files
289
+ return
290
+ endif
291
+ endif
292
+
252
293
if g: MRU_Exclude_Files != ' '
253
294
" Do not add files matching the pattern specified in the
254
295
" MRU_Exclude_Files to the MRU list
255
- if fname = ~? g: MRU_Exclude_Files
296
+ if fname = ~# g: MRU_Exclude_Files
256
297
return
257
298
endif
258
299
endif
259
300
260
- " If the filename is already present in the MRU list, then move
261
- " it to the beginning of the list
301
+ " If the filename is not already present in the MRU list and is not
302
+ " readable then ignore it
262
303
let idx = index (s: MRU_files , fname)
263
304
if idx == -1
264
305
if ! filereadable (fname)
@@ -276,7 +317,7 @@ function! s:MRU_AddFile(acmd_bufnr)
276
317
" Add the new file list to the beginning of the updated old file list
277
318
call insert (s: MRU_files , fname, 0 )
278
319
279
- " Return the trimmed list
320
+ " Trim the list
280
321
if len (s: MRU_files ) > g: MRU_Max_Entries
281
322
call remove (s: MRU_files , g: MRU_Max_Entries , -1 )
282
323
endif
@@ -299,12 +340,23 @@ function! s:MRU_AddFile(acmd_bufnr)
299
340
endif
300
341
endfunction
301
342
343
+ " Special characters in file names that should be escaped (for security
344
+ " reasons)
345
+ let s: esc_filename_chars = ' *?[{`$%#"|!<>();&' . " '\t \n "
346
+ function ! s: MRU_escape_filename (fname)
347
+ return escape (a: fname , s: esc_filename_chars )
348
+ endfunction
349
+
302
350
" MRU_Edit_File
303
351
" Edit the specified file
304
- function ! s: MRU_Edit_File (filename)
305
- let fname = escape (a: filename , ' %#"' )
352
+ function ! s: MRU_Edit_File (filename, sanitized)
353
+ if ! a: sanitized
354
+ let esc_fname = s: MRU_escape_filename (a: filename )
355
+ else
356
+ let esc_fname = a: filename
357
+ endif
306
358
" If the file is already open in one of the windows, jump to it
307
- let winnum = bufwinnr (' ^' . fname . ' $' )
359
+ let winnum = bufwinnr (' ^' . a: filename . ' $' )
308
360
if winnum != -1
309
361
if winnum != winnr ()
310
362
exe winnum . ' wincmd w'
@@ -313,9 +365,9 @@ function! s:MRU_Edit_File(filename)
313
365
if &modified || &buftype != ' ' || &previewwindow
314
366
" Current buffer has unsaved changes or is a special buffer or is
315
367
" the preview window. So open the file in a new window
316
- exe ' split ' . fname
368
+ exe ' split ' . esc_fname
317
369
else
318
- exe ' edit ' . fname
370
+ exe ' edit ' . esc_fname
319
371
endif
320
372
endif
321
373
endfunction
@@ -332,11 +384,11 @@ function! s:MRU_Window_Edit_File(win_opt)
332
384
return
333
385
endif
334
386
335
- let fname = escape (fname, ' %#" ' )
387
+ let esc_fname = s: MRU_escape_filename (fname)
336
388
337
389
if a: win_opt == ' newwin'
338
390
" Edit the file in a new window
339
- exe ' leftabove new ' . fname
391
+ exe ' leftabove new ' . esc_fname
340
392
341
393
if g: MRU_Auto_Close == 1 && g: MRU_Use_Current_Window == 0
342
394
" Go back to the MRU window and close it
@@ -375,7 +427,7 @@ function! s:MRU_Window_Edit_File(win_opt)
375
427
exe ' tabnext ' . i
376
428
else
377
429
" Open a new tab as the last tab page
378
- exe ' 999tabnew ' . fname
430
+ exe ' 999tabnew ' . esc_fname
379
431
endif
380
432
endif
381
433
@@ -427,9 +479,9 @@ function! s:MRU_Window_Edit_File(win_opt)
427
479
if &modified || &buftype != ' ' || &previewwindow
428
480
" Current buffer has unsaved changes or is a special buffer or
429
481
" is the preview window. So open the file in a new window
430
- exe ' split ' . fname
482
+ exe ' split ' . esc_fname
431
483
else
432
- exe ' edit ' . fname
484
+ exe ' edit ' . esc_fname
433
485
endif
434
486
endif
435
487
endif
@@ -546,11 +598,17 @@ function! s:MRU_Open_Window(...)
546
598
silent ! 0 put = s: MRU_files
547
599
else
548
600
" Display only the entries matching the specified pattern
549
- silent ! 0 put = filter (copy (s: MRU_files ), ' v:val =~? a:1' )
601
+ " First try using it as a literal pattern
602
+ let m = filter (copy (s: MRU_files ), ' stridx(v:val, a:1) != -1' )
603
+ if len (m ) == 0
604
+ " No match. Try using it as a regular expression
605
+ let m = filter (copy (s: MRU_files ), ' v:val =~# a:1' )
606
+ endif
607
+ silent ! 0 put = m
550
608
endif
551
609
552
610
" Move the cursor to the beginning of the file
553
- exe 1
611
+ normal ! gg
554
612
555
613
setlocal nomodifiable
556
614
endfunction
@@ -588,8 +646,21 @@ function! s:MRU_Cmd(pat)
588
646
" filenames containing the string. If only one filename is found,
589
647
" then edit it.
590
648
let m = filter (copy (s: MRU_files ), ' stridx(v:val, a:pat) != -1' )
591
- if len (m ) == 1
592
- call s: MRU_Edit_File (m [0 ])
649
+ if len (m ) > 0
650
+ if len (m ) == 1
651
+ call s: MRU_Edit_File (m [0 ], 0 )
652
+ return
653
+ endif
654
+
655
+ " More than one file matches. Try find an accurate match
656
+ let new_m = filter (m , ' v:val ==# a:pat' )
657
+ if len (new_m) == 1
658
+ call s: MRU_Edit_File (new_m[0 ], 0 )
659
+ return
660
+ endif
661
+
662
+ " Couldn't find an exact match, open the MRU window
663
+ call s: MRU_Open_Window (a: pat )
593
664
return
594
665
endif
595
666
@@ -605,7 +676,7 @@ function! s:MRU_Cmd(pat)
605
676
endif
606
677
607
678
if len (m ) == 1
608
- call s: MRU_Edit_File (m [0 ])
679
+ call s: MRU_Edit_File (m [0 ], 0 )
609
680
return
610
681
endif
611
682
@@ -615,7 +686,9 @@ endfunction
615
686
function ! s: MRU_add_files_to_menu (prefix, file_list)
616
687
for fname in a: file_list
617
688
" Escape special characters in the filename
618
- let esc_fname = escape (fnamemodify (fname, ' :t' ), " . \\ |\t %#" )
689
+ let esc_fname = escape (fnamemodify (fname, ' :t' ), " .\\ " .
690
+ \ s: esc_filename_chars )
691
+ let esc_fname = substitute (esc_fname, ' &' , ' &&' , ' g' )
619
692
620
693
" Truncate the directory name if it is long
621
694
let dir_name = fnamemodify (fname, ' :h' )
@@ -627,11 +700,15 @@ function! s:MRU_add_files_to_menu(prefix, file_list)
627
700
\ ' ...' .
628
701
\ strpart (dir_name, len - 20 )
629
702
endif
630
- let esc_dir_name = escape (dir_name, " . \\ |\t " )
631
-
632
- exe ' anoremenu <silent> &File.Recent\ Files.' . a: prefix . esc_fname .
633
- \ ' \ (' . esc_dir_name . ' )' .
634
- \ " :call <SID>MRU_Edit_File('" . fname . " ')<CR>"
703
+ let esc_dir_name = escape (dir_name, " .\\ " . s: esc_filename_chars )
704
+ let esc_dir_name = substitute (esc_dir_name, ' &' , ' &&' , ' g' )
705
+
706
+ let menu_path = ' &File.Recent\ Files.' . a: prefix . esc_fname .
707
+ \ ' \ (' . esc_dir_name . ' )'
708
+ let esc_mfname = s: MRU_escape_filename (fname)
709
+ exe ' anoremenu <silent> ' . menu_path .
710
+ \ " :call <SID>MRU_Edit_File('" . esc_mfname . " ', 1)<CR>"
711
+ exe ' tmenu ' . menu_path . ' Edit file ' . esc_mfname
635
712
endfor
636
713
endfunction
637
714
@@ -658,11 +735,14 @@ function! s:MRU_Refresh_Menu()
658
735
659
736
anoremenu <silent> &File.Recent\ Files.Refresh\ list
660
737
\ :call <SID> MRU_LoadList ()<CR>
738
+ exe ' tmenu File.Recent\ Files.Refresh\ list Reload the MRU file list from '
739
+ \ . s: MRU_escape_filename (g: MRU_File )
661
740
anoremenu File.Recent\ Files.- SEP1- :
662
741
663
742
" Add the filenames in the MRU list to the menu
664
743
let entry_cnt = len (s: MRU_files )
665
744
if entry_cnt > 10
745
+ " Split the MRU menu into sub-menus
666
746
for start_idx in range (0 , entry_cnt, 10 )
667
747
let last_idx = start_idx + 9
668
748
if last_idx >= entry_cnt
@@ -692,6 +772,12 @@ autocmd BufRead * call s:MRU_AddFile(expand('<abuf>'))
692
772
autocmd BufNewFile * call s: MRU_AddFile (expand (' <abuf>' ))
693
773
autocmd BufWritePost * call s: MRU_AddFile (expand (' <abuf>' ))
694
774
775
+ " The ':vimgrep' command adds all the files searched to the buffer list.
776
+ " This also modifies the MRU list, even though the user didn't edit the
777
+ " files. Use the following autocmds to prevent this.
778
+ autocmd QuickFixCmdPre *vimgrep* let s: mru_list_locked = 1
779
+ autocmd QuickFixCmdPost *vimgrep* let s: mru_list_locked = 0
780
+
695
781
" Command to open the MRU window
696
782
command ! -nargs =? -complete =customlist ,s: MRU_Complete MRU
697
783
\ call s: MRU_Cmd (<q-args> )
0 commit comments