Most Recently Used (MRU) Vim Plugin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

842 lines
28 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. " File: mru.vim
  2. " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
  3. " Version: 3.9.1
  4. " Last Modified: Aug 29, 2018
  5. " Copyright: Copyright (C) 2003-2018 Yegappan Lakshmanan
  6. " License: Permission is hereby granted to use and distribute this code,
  7. " with or without modifications, provided that this copyright
  8. " notice is copied with it. Like anything else that's free,
  9. " mru.vim is provided *as is* and comes with no warranty of any
  10. " kind, either expressed or implied. In no event will the copyright
  11. " holder be liable for any damages resulting from the use of this
  12. " software.
  13. "
  14. " ****************** Do not modify after this line ************************
  15. if exists('loaded_mru')
  16. finish
  17. endif
  18. let loaded_mru=1
  19. if v:version < 700
  20. finish
  21. endif
  22. " Line continuation used here
  23. let s:cpo_save = &cpo
  24. set cpo&vim
  25. " MRU configuration variables {{{1
  26. " Maximum number of entries allowed in the MRU list
  27. if !exists('MRU_Max_Entries')
  28. let MRU_Max_Entries = 100
  29. endif
  30. " Files to exclude from the MRU list
  31. if !exists('MRU_Exclude_Files')
  32. let MRU_Exclude_Files = ''
  33. endif
  34. " Files to include in the MRU list
  35. if !exists('MRU_Include_Files')
  36. let MRU_Include_Files = ''
  37. endif
  38. " Height of the MRU window
  39. " Default height is 8
  40. if !exists('MRU_Window_Height')
  41. let MRU_Window_Height = 8
  42. endif
  43. if !exists('MRU_Use_Current_Window')
  44. let MRU_Use_Current_Window = 0
  45. endif
  46. if !exists('MRU_Auto_Close')
  47. let MRU_Auto_Close = 1
  48. endif
  49. if !exists('MRU_Menu_Path')
  50. let MRU_Menu_Path = '&File.&Recent\ Files'
  51. endif
  52. if !exists('MRU_File')
  53. if has('unix') || has('macunix')
  54. let MRU_File = $HOME . '/.vim_mru_files'
  55. else
  56. let MRU_File = $VIM . '/_vim_mru_files'
  57. if has('win32')
  58. " MS-Windows
  59. if $USERPROFILE != ''
  60. let MRU_File = $USERPROFILE . '\_vim_mru_files'
  61. endif
  62. endif
  63. endif
  64. else
  65. let MRU_File=expand(MRU_File)
  66. endif
  67. " Option for enabling or disabling the MRU menu
  68. if !exists('MRU_Add_Menu')
  69. let MRU_Add_Menu = 1
  70. endif
  71. " Maximum number of file names to show in the MRU menu. If too many files are
  72. " listed in the menu, then Vim becomes slow when updating the menu. So set
  73. " this to a low value.
  74. if !exists('MRU_Max_Menu_Entries')
  75. let MRU_Max_Menu_Entries = 10
  76. endif
  77. " Maximum number of file names to show in a MRU sub-menu. If the MRU list
  78. " contains more file names than this setting, then the MRU menu is split into
  79. " one or more sub-menus.
  80. if !exists('MRU_Max_Submenu_Entries')
  81. let MRU_Max_Submenu_Entries = 10
  82. endif
  83. " When only a single matching filename is found in the MRU list, the following
  84. " option controls whether the file name is displayed in the MRU window or the
  85. " file is directly opened. When this variable is set to 0 and a single
  86. " matching file name is found, then the file is directly opened.
  87. if !exists('MRU_Window_Open_Always')
  88. let MRU_Window_Open_Always = 0
  89. endif
  90. " When opening a file from the MRU list, the file is opened in the current
  91. " tab. If the selected file has to be opened in a tab always, then set the
  92. " following variable to 1. If the file is already opened in a tab, then the
  93. " cursor will be moved to that tab.
  94. if !exists('MRU_Open_File_Use_Tabs')
  95. let MRU_Open_File_Use_Tabs = 0
  96. endif
  97. " Format of the file names displayed in the MRU window.
  98. " The default is to display the filename followed by the complete path to the
  99. " file in parenthesis. This variable controls the expressions used to format
  100. " and parse the path. This can be changed to display the filenames in a
  101. " different format. The 'formatter' specifies how to split/format the filename
  102. " and 'parser' specifies how to read the filename back; 'syntax' matches the
  103. " part to be highlighted.
  104. if !exists('MRU_Filename_Format')
  105. let MRU_Filename_Format = {
  106. \ 'formatter': 'fnamemodify(v:val, ":t") . " (" . v:val . ")"',
  107. \ 'parser': '(\zs.*\ze)',
  108. \ 'syntax': '^.\{-}\ze('
  109. \}
  110. endif
  111. " Control to temporarily lock the MRU list. Used to prevent files from
  112. " getting added to the MRU list when the ':vimgrep' command is executed.
  113. let s:mru_list_locked = 0
  114. " MRU_LoadList {{{1
  115. " Loads the latest list of file names from the MRU file
  116. function! s:MRU_LoadList()
  117. " If the MRU file is present, then load the list of filenames. Otherwise
  118. " start with an empty list.
  119. if filereadable(g:MRU_File)
  120. let s:MRU_files = readfile(g:MRU_File)
  121. if s:MRU_files[0] =~# '^\s*" Most recently edited files in Vim'
  122. " Generated by the previous version of the MRU plugin.
  123. " Discard the list.
  124. let s:MRU_files = []
  125. elseif s:MRU_files[0] =~# '^#'
  126. " Remove the comment line
  127. call remove(s:MRU_files, 0)
  128. else
  129. " Unsupported format
  130. let s:MRU_files = []
  131. endif
  132. else
  133. let s:MRU_files = []
  134. endif
  135. " Refresh the MRU menu with the latest list of filenames
  136. call s:MRU_Refresh_Menu()
  137. endfunction
  138. " MRU_SaveList {{{1
  139. " Saves the MRU file names to the MRU file
  140. function! s:MRU_SaveList()
  141. let l = []
  142. call add(l, '# Most recently edited files in Vim (version 3.0)')
  143. call extend(l, s:MRU_files)
  144. call writefile(l, g:MRU_File)
  145. endfunction
  146. " MRU_AddFile {{{1
  147. " Adds a file to the MRU file list
  148. " acmd_bufnr - Buffer number of the file to add
  149. function! s:MRU_AddFile(acmd_bufnr)
  150. if s:mru_list_locked
  151. " MRU list is currently locked
  152. return
  153. endif
  154. " Get the full path to the filename
  155. let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p')
  156. if fname == ''
  157. return
  158. endif
  159. " Skip temporary buffers with buftype set. The buftype is set for buffers
  160. " used by plugins.
  161. if &buftype != ''
  162. return
  163. endif
  164. if g:MRU_Include_Files != ''
  165. " If MRU_Include_Files is set, include only files matching the
  166. " specified pattern
  167. if fname !~# g:MRU_Include_Files
  168. return
  169. endif
  170. endif
  171. if g:MRU_Exclude_Files != ''
  172. " Do not add files matching the pattern specified in the
  173. " MRU_Exclude_Files to the MRU list
  174. if fname =~# g:MRU_Exclude_Files
  175. return
  176. endif
  177. endif
  178. " If the filename is not already present in the MRU list and is not
  179. " readable then ignore it
  180. let idx = index(s:MRU_files, fname)
  181. if idx == -1
  182. if !filereadable(fname)
  183. " File is not readable and is not in the MRU list
  184. return
  185. endif
  186. endif
  187. " Load the latest MRU file list
  188. call s:MRU_LoadList()
  189. " Remove the new file name from the existing MRU list (if already present)
  190. call filter(s:MRU_files, 'v:val !=# fname')
  191. " Add the new file list to the beginning of the updated old file list
  192. call insert(s:MRU_files, fname, 0)
  193. " Trim the list
  194. if len(s:MRU_files) > g:MRU_Max_Entries
  195. call remove(s:MRU_files, g:MRU_Max_Entries, -1)
  196. endif
  197. " Save the updated MRU list
  198. call s:MRU_SaveList()
  199. " Refresh the MRU menu
  200. call s:MRU_Refresh_Menu()
  201. " If the MRU window is open, update the displayed MRU list
  202. let bname = '__MRU_Files__'
  203. let winnum = bufwinnr(bname)
  204. if winnum != -1
  205. let cur_winnr = winnr()
  206. call s:MRU_Open_Window()
  207. if winnr() != cur_winnr
  208. exe cur_winnr . 'wincmd w'
  209. endif
  210. endif
  211. endfunction
  212. " MRU_escape_filename {{{1
  213. " Escape special characters in a filename. Special characters in file names
  214. " that should be escaped (for security reasons)
  215. let s:esc_filename_chars = ' *?[{`$%#"|!<>();&' . "'\t\n"
  216. function! s:MRU_escape_filename(fname)
  217. if exists("*fnameescape")
  218. return fnameescape(a:fname)
  219. else
  220. return escape(a:fname, s:esc_filename_chars)
  221. endif
  222. endfunction
  223. " MRU_Edit_File {{{1
  224. " Edit the specified file
  225. " filename - Name of the file to edit
  226. " sanitized - Specifies whether the filename is already escaped for special
  227. " characters or not.
  228. function! s:MRU_Edit_File(filename, sanitized)
  229. if !a:sanitized
  230. let esc_fname = s:MRU_escape_filename(a:filename)
  231. else
  232. let esc_fname = a:filename
  233. endif
  234. " If the user wants to always open the file in a tab, then open the file
  235. " in a tab. If it is already opened in a tab, then the cursor will be
  236. " moved to that tab.
  237. if g:MRU_Open_File_Use_Tabs
  238. call s:MRU_Open_File_In_Tab(a:filename, esc_fname)
  239. return
  240. endif
  241. " If the file is already open in one of the windows, jump to it
  242. let winnum = bufwinnr('^' . a:filename . '$')
  243. if winnum != -1
  244. if winnum != winnr()
  245. exe winnum . 'wincmd w'
  246. endif
  247. else
  248. if !&hidden && (&modified || &buftype != '' || &previewwindow)
  249. " Current buffer has unsaved changes or is a special buffer or is
  250. " the preview window. The 'hidden' option is also not set.
  251. " So open the file in a new window.
  252. exe 'split ' . esc_fname
  253. else
  254. " The current file can be replaced with the selected file.
  255. exe 'edit ' . esc_fname
  256. endif
  257. endif
  258. endfunction
  259. " MRU_Open_File_In_Tab
  260. " Open a file in a tab. If the file is already opened in a tab, jump to the
  261. " tab. Otherwise, create a new tab and open the file.
  262. " fname : Name of the file to open
  263. " esc_fname : File name with special characters escaped
  264. function! s:MRU_Open_File_In_Tab(fname, esc_fname)
  265. " If the selected file is already open in the current tab or in
  266. " another tab, jump to it. Otherwise open it in a new tab
  267. if bufwinnr('^' . a:fname . '$') == -1
  268. let tabnum = -1
  269. let i = 1
  270. let bnum = bufnr('^' . a:fname . '$')
  271. while i <= tabpagenr('$')
  272. if index(tabpagebuflist(i), bnum) != -1
  273. let tabnum = i
  274. break
  275. endif
  276. let i += 1
  277. endwhile
  278. if tabnum != -1
  279. " Goto the tab containing the file
  280. exe 'tabnext ' . i
  281. else
  282. " Open a new tab as the last tab page
  283. tablast
  284. exe 'tabnew ' . a:esc_fname
  285. endif
  286. endif
  287. " Jump to the window containing the file
  288. let winnum = bufwinnr('^' . a:fname . '$')
  289. if winnum != winnr()
  290. exe winnum . 'wincmd w'
  291. endif
  292. endfunction
  293. " MRU_Window_Edit_File {{{1
  294. " fname : Name of the file to edit. May specify single or multiple
  295. " files.
  296. " edit_type : Specifies how to edit the file. Can be one of 'edit' or 'view'.
  297. " 'view' - Open the file as a read-only file
  298. " 'edit' - Edit the file as a regular file
  299. " multi : Specifies whether a single file or multiple files need to be
  300. " opened.
  301. " open_type : Specifies where to open the file.
  302. " useopen - If the file is already present in a window, then
  303. " jump to that window. Otherwise, open the file in
  304. " the previous window.
  305. " newwin_horiz - Open the file in a new horizontal window.
  306. " newwin_vert - Open the file in a new vertical window.
  307. " newtab - Open the file in a new tab. If the file is already
  308. " opened in a tab, then jump to that tab.
  309. " preview - Open the file in the preview window
  310. function! s:MRU_Window_Edit_File(fname, multi, edit_type, open_type)
  311. let esc_fname = s:MRU_escape_filename(a:fname)
  312. if a:open_type ==# 'newwin_horiz'
  313. " Edit the file in a new horizontally split window above the previous
  314. " window
  315. wincmd p
  316. exe 'belowright new ' . esc_fname
  317. elseif a:open_type ==# 'newwin_vert'
  318. " Edit the file in a new vertically split window above the previous
  319. " window
  320. wincmd p
  321. exe 'belowright vnew ' . esc_fname
  322. elseif a:open_type ==# 'newtab' || g:MRU_Open_File_Use_Tabs
  323. call s:MRU_Open_File_In_Tab(a:fname, esc_fname)
  324. elseif a:open_type ==# 'preview'
  325. " Edit the file in the preview window
  326. exe 'topleft pedit ' . esc_fname
  327. else
  328. " If the selected file is already open in one of the windows,
  329. " jump to it
  330. let winnum = bufwinnr('^' . a:fname . '$')
  331. if winnum != -1
  332. exe winnum . 'wincmd w'
  333. else
  334. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  335. " Jump to the window from which the MRU window was opened
  336. if exists('s:MRU_last_buffer')
  337. let last_winnr = bufwinnr(s:MRU_last_buffer)
  338. if last_winnr != -1 && last_winnr != winnr()
  339. exe last_winnr . 'wincmd w'
  340. endif
  341. endif
  342. else
  343. if g:MRU_Use_Current_Window == 0
  344. " Goto the previous window
  345. " If MRU_Use_Current_Window is set to one, then the
  346. " current window is used to open the file
  347. wincmd p
  348. endif
  349. endif
  350. let split_window = 0
  351. if (!&hidden && (&modified || &previewwindow)) || a:multi
  352. " Current buffer has unsaved changes or is the preview window
  353. " or the user is opening multiple files
  354. " So open the file in a new window
  355. let split_window = 1
  356. endif
  357. if &buftype != ''
  358. " Current buffer is a special buffer (maybe used by a plugin)
  359. if g:MRU_Use_Current_Window == 0 ||
  360. \ bufnr('%') != bufnr('__MRU_Files__')
  361. let split_window = 1
  362. endif
  363. endif
  364. " Edit the file
  365. if split_window
  366. " Current buffer has unsaved changes or is a special buffer or
  367. " is the preview window. So open the file in a new window
  368. if a:edit_type ==# 'edit'
  369. exe 'split ' . esc_fname
  370. else
  371. exe 'sview ' . esc_fname
  372. endif
  373. else
  374. if a:edit_type ==# 'edit'
  375. exe 'edit ' . esc_fname
  376. else
  377. exe 'view ' . esc_fname
  378. endif
  379. endif
  380. endif
  381. endif
  382. endfunction
  383. " MRU_Select_File_Cmd {{{1
  384. " Open a file selected from the MRU window
  385. "
  386. " 'opt' has two values separated by comma. The first value specifies how to
  387. " edit the file and can be either 'edit' or 'view'. The second value
  388. " specifies where to open the file. It can take one of the following values:
  389. " 'useopen' to open file in the previous window
  390. " 'newwin_horiz' to open the file in a new horizontal split window
  391. " 'newwin_vert' to open the file in a new vertical split window.
  392. " 'newtab' to open the file in a new tab.
  393. " If multiple file names are selected using visual mode, then open multiple
  394. " files (either in split windows or tabs)
  395. function! s:MRU_Select_File_Cmd(opt) range
  396. let [edit_type, open_type] = split(a:opt, ',')
  397. let fnames = getline(a:firstline, a:lastline)
  398. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  399. " Automatically close the window if the file window is
  400. " not used to display the MRU list.
  401. silent! close
  402. endif
  403. let multi = 0
  404. for f in fnames
  405. if f == ''
  406. continue
  407. endif
  408. " The text in the MRU window contains the filename in parenthesis
  409. let file = matchstr(f, g:MRU_Filename_Format.parser)
  410. call s:MRU_Window_Edit_File(file, multi, edit_type, open_type)
  411. if a:firstline != a:lastline
  412. " Opening multiple files
  413. let multi = 1
  414. endif
  415. endfor
  416. endfunction
  417. " MRU_Warn_Msg {{{1
  418. " Display a warning message
  419. function! s:MRU_Warn_Msg(msg)
  420. echohl WarningMsg
  421. echo a:msg
  422. echohl None
  423. endfunction
  424. " MRU_Open_Window {{{1
  425. " Display the Most Recently Used file list in a temporary window.
  426. " If the optional argument is supplied, then it specifies the pattern of files
  427. " to selectively display in the MRU window.
  428. function! s:MRU_Open_Window(...)
  429. " Load the latest MRU file list
  430. call s:MRU_LoadList()
  431. " Check for empty MRU list
  432. if empty(s:MRU_files)
  433. call s:MRU_Warn_Msg('MRU file list is empty')
  434. return
  435. endif
  436. " Save the current buffer number. This is used later to open a file when a
  437. " entry is selected from the MRU window. The window number is not saved,
  438. " as the window number will change when new windows are opened.
  439. let s:MRU_last_buffer = bufnr('%')
  440. let bname = '__MRU_Files__'
  441. " If the window is already open, jump to it
  442. let winnum = bufwinnr(bname)
  443. if winnum != -1
  444. if winnr() != winnum
  445. " If not already in the window, jump to it
  446. exe winnum . 'wincmd w'
  447. endif
  448. setlocal modifiable
  449. " Delete the contents of the buffer to the black-hole register
  450. silent! %delete _
  451. else
  452. if g:MRU_Use_Current_Window
  453. " Reuse the current window
  454. "
  455. " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open
  456. " a new buffer
  457. let bufnum = bufnr(bname)
  458. if bufnum == -1
  459. let cmd = 'edit ' . bname
  460. else
  461. let cmd = 'buffer ' . bufnum
  462. endif
  463. exe cmd
  464. if bufnr('%') != bufnr(bname)
  465. " Failed to edit the MRU buffer
  466. return
  467. endif
  468. else
  469. " Open a new window at the bottom
  470. " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open
  471. " a new buffer
  472. let bufnum = bufnr(bname)
  473. if bufnum == -1
  474. let wcmd = bname
  475. else
  476. let wcmd = '+buffer' . bufnum
  477. endif
  478. exe 'silent! botright ' . g:MRU_Window_Height . 'split ' . wcmd
  479. endif
  480. endif
  481. setlocal modifiable
  482. " Mark the buffer as scratch
  483. setlocal buftype=nofile
  484. setlocal bufhidden=delete
  485. setlocal noswapfile
  486. setlocal nowrap
  487. setlocal nobuflisted
  488. " Set the 'filetype' to 'mru'. This allows the user to apply custom
  489. " syntax highlighting or other changes to the MRU bufer.
  490. setlocal filetype=mru
  491. " Use fixed height for the MRU window
  492. setlocal winfixheight
  493. " Setup the cpoptions properly for the maps to work
  494. let old_cpoptions = &cpoptions
  495. set cpoptions&vim
  496. " Create mappings to select and edit a file from the MRU list
  497. nnoremap <buffer> <silent> <CR>
  498. \ :call <SID>MRU_Select_File_Cmd('edit,useopen')<CR>
  499. vnoremap <buffer> <silent> <CR>
  500. \ :call <SID>MRU_Select_File_Cmd('edit,useopen')<CR>
  501. nnoremap <buffer> <silent> o
  502. \ :call <SID>MRU_Select_File_Cmd('edit,newwin_horiz')<CR>
  503. vnoremap <buffer> <silent> o
  504. \ :call <SID>MRU_Select_File_Cmd('edit,newwin_horiz')<CR>
  505. nnoremap <buffer> <silent> <S-CR>
  506. \ :call <SID>MRU_Select_File_Cmd('edit,newwin_horiz')<CR>
  507. vnoremap <buffer> <silent> <S-CR>
  508. \ :call <SID>MRU_Select_File_Cmd('edit,newwin_horiz')<CR>
  509. nnoremap <buffer> <silent> O
  510. \ :call <SID>MRU_Select_File_Cmd('edit,newwin_vert')<CR>
  511. vnoremap <buffer> <silent> O
  512. \ :call <SID>MRU_Select_File_Cmd('edit,newwin_vert')<CR>
  513. nnoremap <buffer> <silent> t
  514. \ :call <SID>MRU_Select_File_Cmd('edit,newtab')<CR>
  515. vnoremap <buffer> <silent> t
  516. \ :call <SID>MRU_Select_File_Cmd('edit,newtab')<CR>
  517. nnoremap <buffer> <silent> v
  518. \ :call <SID>MRU_Select_File_Cmd('view,useopen')<CR>
  519. nnoremap <buffer> <silent> p
  520. \ :call <SID>MRU_Select_File_Cmd('view,preview')<CR>
  521. vnoremap <buffer> <silent> p
  522. \ :<C-u>if line("'<") == line("'>")<Bar>
  523. \ call <SID>MRU_Select_File_Cmd('open,preview')<Bar>
  524. \ else<Bar>
  525. \ echoerr "Only a single file can be previewed"<Bar>
  526. \ endif<CR>
  527. nnoremap <buffer> <silent> u :MRU<CR>
  528. nnoremap <buffer> <silent> <2-LeftMouse>
  529. \ :call <SID>MRU_Select_File_Cmd('edit,useopen')<CR>
  530. nnoremap <buffer> <silent> q :close<CR>
  531. " Restore the previous cpoptions settings
  532. let &cpoptions = old_cpoptions
  533. " Display the MRU list
  534. if a:0 == 0
  535. " No search pattern specified. Display the complete list
  536. let m = copy(s:MRU_files)
  537. else
  538. " Display only the entries matching the specified pattern
  539. " First try using it as a literal pattern
  540. let m = filter(copy(s:MRU_files), 'stridx(v:val, a:1) != -1')
  541. if len(m) == 0
  542. " No match. Try using it as a regular expression
  543. let m = filter(copy(s:MRU_files), 'v:val =~# a:1')
  544. endif
  545. endif
  546. " Get the tail part of the file name (without the directory) and display
  547. " it along with the full path in parenthesis.
  548. let output = map(m, g:MRU_Filename_Format.formatter)
  549. silent! 0put =output
  550. " Delete the empty line at the end of the buffer
  551. silent! $delete _
  552. " Move the cursor to the beginning of the file
  553. normal! gg
  554. " Add syntax highlighting for the file names
  555. if has_key(g:MRU_Filename_Format, 'syntax')
  556. exe "syntax match MRUFileName '" . g:MRU_Filename_Format.syntax . "'"
  557. highlight default link MRUFileName Identifier
  558. endif
  559. setlocal nomodifiable
  560. endfunction
  561. " MRU_Complete {{{1
  562. " Command-line completion function used by :MRU command
  563. function! s:MRU_Complete(ArgLead, CmdLine, CursorPos)
  564. if a:ArgLead == ''
  565. " Return the complete list of MRU files
  566. return s:MRU_files
  567. else
  568. " Return only the files matching the specified pattern
  569. return filter(copy(s:MRU_files), 'v:val =~? a:ArgLead')
  570. endif
  571. endfunction
  572. " MRU_Cmd {{{1
  573. " Function to handle the MRU command
  574. " pat - File name pattern passed to the MRU command
  575. function! s:MRU_Cmd(pat)
  576. if a:pat == ''
  577. " No arguments specified. Open the MRU window
  578. call s:MRU_Open_Window()
  579. return
  580. endif
  581. " Load the latest MRU file
  582. call s:MRU_LoadList()
  583. " Empty MRU list
  584. if empty(s:MRU_files)
  585. call s:MRU_Warn_Msg('MRU file list is empty')
  586. return
  587. endif
  588. " First use the specified string as a literal string and search for
  589. " filenames containing the string. If only one filename is found,
  590. " then edit it (unless the user wants to open the MRU window always)
  591. let m = filter(copy(s:MRU_files), 'stridx(v:val, a:pat) != -1')
  592. if len(m) > 0
  593. if len(m) == 1 && !g:MRU_Window_Open_Always
  594. call s:MRU_Edit_File(m[0], 0)
  595. return
  596. endif
  597. " More than one file matches. Try find an accurate match
  598. let new_m = filter(m, 'v:val ==# a:pat')
  599. if len(new_m) == 1 && !g:MRU_Window_Open_Always
  600. call s:MRU_Edit_File(new_m[0], 0)
  601. return
  602. endif
  603. " Couldn't find an exact match, open the MRU window with all the
  604. " files matching the pattern.
  605. call s:MRU_Open_Window(a:pat)
  606. return
  607. endif
  608. " Use the specified string as a regular expression pattern and search
  609. " for filenames matching the pattern
  610. let m = filter(copy(s:MRU_files), 'v:val =~? a:pat')
  611. if len(m) == 0
  612. " If an existing file (not present in the MRU list) is specified,
  613. " then open the file.
  614. if filereadable(a:pat)
  615. call s:MRU_Edit_File(a:pat, 0)
  616. return
  617. endif
  618. " No filenames matching the specified pattern are found
  619. call s:MRU_Warn_Msg("MRU file list doesn't contain " .
  620. \ "files matching " . a:pat)
  621. return
  622. endif
  623. if len(m) == 1 && !g:MRU_Window_Open_Always
  624. call s:MRU_Edit_File(m[0], 0)
  625. return
  626. endif
  627. call s:MRU_Open_Window(a:pat)
  628. endfunction
  629. " MRU_add_files_to_menu {{{1
  630. " Adds a list of files to the "Recent Files" sub menu under the "File" menu.
  631. " prefix - Prefix to use for each of the menu entries
  632. " file_list - List of file names to add to the menu
  633. function! s:MRU_add_files_to_menu(prefix, file_list)
  634. for fname in a:file_list
  635. " Escape special characters in the filename
  636. let esc_fname = escape(fnamemodify(fname, ':t'), ".\\" .
  637. \ s:esc_filename_chars)
  638. let esc_fname = substitute(esc_fname, '&', '&&', 'g')
  639. " Truncate the directory name if it is long
  640. let dir_name = fnamemodify(fname, ':h')
  641. let len = strchars(dir_name)
  642. " Shorten long file names by adding only few characters from
  643. " the beginning and end.
  644. if len > 30
  645. let dir_name = strcharpart(dir_name, 0, 10) .
  646. \ '...' .
  647. \ strcharpart(dir_name, len - 20)
  648. endif
  649. let esc_dir_name = escape(dir_name, ".\\" . s:esc_filename_chars)
  650. let esc_dir_name = substitute(esc_dir_name, '&', '&&', 'g')
  651. let menu_path = g:MRU_Menu_Path . '.' . a:prefix . esc_fname .
  652. \ '\ (' . esc_dir_name . ')'
  653. let esc_mfname = s:MRU_escape_filename(fname)
  654. exe 'anoremenu <silent> ' . menu_path .
  655. \ " :call <SID>MRU_Edit_File('" . esc_mfname . "', 1)<CR>"
  656. exe 'tmenu ' . menu_path . ' Edit file ' . esc_mfname
  657. endfor
  658. endfunction
  659. " MRU_Refresh_Menu {{{1
  660. " Refresh the MRU menu
  661. function! s:MRU_Refresh_Menu()
  662. if !has('menu') || !g:MRU_Add_Menu
  663. " No support for menus
  664. return
  665. endif
  666. " Setup the cpoptions properly for the maps to work
  667. let old_cpoptions = &cpoptions
  668. set cpoptions&vim
  669. " Remove the MRU menu
  670. " To retain the teared-off MRU menu, we need to add a dummy entry
  671. exe 'silent! unmenu ' . g:MRU_Menu_Path
  672. " The menu priority of the File menu is 10. If the MRU plugin runs
  673. " first before menu.vim, the File menu order may not be correct.
  674. " So specify the priority of the File menu here.
  675. exe '10noremenu ' . g:MRU_Menu_Path . '.Dummy <Nop>'
  676. exe 'silent! unmenu! ' . g:MRU_Menu_Path
  677. exe 'anoremenu <silent> ' . g:MRU_Menu_Path . '.Refresh\ list \ :call <SID>MRU_LoadList()<CR>'
  678. exe 'tmenu ' . g:MRU_Menu_Path . '.Refresh\ list Reload the MRU file list from '
  679. \ . s:MRU_escape_filename(g:MRU_File)
  680. " add a separator
  681. exe 'anoremenu ' . g:MRU_Menu_Path . '.-SEP1- :'
  682. " Add the filenames in the MRU list to the menu
  683. let entry_cnt = len(s:MRU_files)
  684. if entry_cnt > g:MRU_Max_Menu_Entries
  685. " Show only MRU_Max_Menu_Entries file names in the menu
  686. let mru_list = s:MRU_files[0 : g:MRU_Max_Menu_Entries - 1]
  687. let entry_cnt = g:MRU_Max_Menu_Entries
  688. else
  689. let mru_list = s:MRU_files
  690. endif
  691. if entry_cnt > g:MRU_Max_Submenu_Entries
  692. " Split the MRU menu into sub-menus
  693. for start_idx in range(0, entry_cnt, g:MRU_Max_Submenu_Entries)
  694. let last_idx = start_idx + g:MRU_Max_Submenu_Entries - 1
  695. if last_idx >= entry_cnt
  696. let last_idx = entry_cnt - 1
  697. endif
  698. let prefix = 'Files\ (' . (start_idx + 1) . '\.\.\.' .
  699. \ (last_idx + 1) . ').'
  700. call s:MRU_add_files_to_menu(prefix,
  701. \ mru_list[start_idx : last_idx])
  702. endfor
  703. else
  704. call s:MRU_add_files_to_menu('', mru_list)
  705. endif
  706. " Remove the dummy menu entry
  707. exe 'unmenu ' . g:MRU_Menu_Path . '.Dummy'
  708. " Restore the previous cpoptions settings
  709. let &cpoptions = old_cpoptions
  710. endfunction
  711. " Load the MRU list on plugin startup
  712. call s:MRU_LoadList()
  713. " MRU autocommands {{{1
  714. " Autocommands to detect the most recently used files
  715. autocmd BufRead * call s:MRU_AddFile(expand('<abuf>'))
  716. autocmd BufNewFile * call s:MRU_AddFile(expand('<abuf>'))
  717. autocmd BufWritePost * call s:MRU_AddFile(expand('<abuf>'))
  718. " The ':vimgrep' command adds all the files searched to the buffer list.
  719. " This also modifies the MRU list, even though the user didn't edit the
  720. " files. Use the following autocmds to prevent this.
  721. autocmd QuickFixCmdPre *vimgrep* let s:mru_list_locked = 1
  722. autocmd QuickFixCmdPost *vimgrep* let s:mru_list_locked = 0
  723. " Command to open the MRU window
  724. command! -nargs=? -complete=customlist,s:MRU_Complete MRU
  725. \ call s:MRU_Cmd(<q-args>)
  726. command! -nargs=? -complete=customlist,s:MRU_Complete Mru
  727. \ call s:MRU_Cmd(<q-args>)
  728. " }}}
  729. " restore 'cpo'
  730. let &cpo = s:cpo_save
  731. unlet s:cpo_save
  732. " vim:set foldenable foldmethod=marker: