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.

680 lines
21 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
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: 2.2
  4. " Last Modified: May 30, 2006
  5. "
  6. " Overview
  7. " --------
  8. " The Most Recently Used (MRU) plugin provides an easy access to a list of
  9. " recently opened/edited files in Vim. This plugin automatically stores the
  10. " file names as you open/edit them in Vim.
  11. "
  12. " This plugin will work on all the platforms where Vim is supported. This
  13. " plugin will work in both console and GUI Vim.
  14. "
  15. " The recently used filenames are stored in a file specified by the Vim
  16. " MRU_File variable.
  17. "
  18. " Installation
  19. " ------------
  20. " 1. Copy the mru.vim script to the $HOME/.vim/plugin or the
  21. " $HOME/vimfiles/plugin or the $VIM/vimfiles directory. Refer to the
  22. " ':help add-plugin', ':help add-global-plugin' and ':help runtimepath'
  23. " topics for more details about Vim plugins.
  24. " 2. Set the MRU_File Vim variable in the .vimrc file to the location of a
  25. " file to store the most recently edited file names.
  26. " 3. Restart Vim.
  27. " 4. You can use the ":MRU" command to list and edit the recently used files.
  28. " In GUI Vim, you can use the 'File->Recent Files' menu to access the
  29. " recently used files.
  30. "
  31. " Usage
  32. " -----
  33. " You can use the ":MRU" command to list all the most recently edited file
  34. " names. The file names will be listed in a temporary Vim window. If the MRU
  35. " window is already opened, then the MRU list displayed in the window will be
  36. " refreshed.
  37. "
  38. " If you are using GUI Vim, then the names of the recently edited files are
  39. " added to the "File->Recent Files" menu. You can select the name of a file
  40. " from this sub-menu to edit the file.
  41. "
  42. " You can use the normal Vim commands to move around the MRU window. You
  43. " cannot make changes in the MRU window.
  44. "
  45. " You can select a file name to edit by pressing the <Enter> key or by double
  46. " clicking the left mouse button on a file name. The selected file will be
  47. " opened.
  48. "
  49. " You can press the 'o' key to open the file name under the cursor in the
  50. " MRU window in a new window.
  51. "
  52. " You can press the 'u' key in the MRU window to update the file list. This is
  53. " useful if you keep the MRU window open.
  54. "
  55. " You can close the MRU window by pressing the 'q' key or using one of the Vim
  56. " window commands.
  57. "
  58. " You can use the ":MRUedit" command to edit files from the MRU list. This
  59. " command supports completion of file names from the MRU list. You can specify
  60. " the file either by the name or by the location in the MRU list.
  61. "
  62. " Whenever the MRU list changes, the MRU file is updated with the latest MRU
  63. " list. When you have multiple instances of Vim running at the same time, the
  64. " latest MRU list will show up in all the instances of Vim.
  65. "
  66. " Configuration
  67. " -------------
  68. " By changing the following variables you can configure the behavior of this
  69. " plugin. Set the following variables in your .vimrc file using the 'let'
  70. " command.
  71. "
  72. " The list of recently edit file names is stored in the file specified by the
  73. " MRU_File variable. The default setting for this variable is
  74. " $HOME/.vim_mru_files for Unix systems and $VIM/_vim_mru_files for non-Unix
  75. " systems. You can change this variable to point to a file by adding the
  76. " following line to the .vimrc file:
  77. "
  78. " let MRU_File = 'd:\myhome\_vim_mru_files'
  79. "
  80. " By default, the plugin will remember the names of the last 10 used files.
  81. " As you edit more files, old file names will be removed from the MRU list.
  82. " You can set the 'MRU_Max_Entries' variable to remember more file names. For
  83. " example, to remember 20 most recently used file names, you can use
  84. "
  85. " let MRU_Max_Entries = 20
  86. "
  87. " By default, all the edited file names will be added to the MRU list. If you
  88. " want to exclude file names matching a list of patterns, you can set the
  89. " MRU_Exclude_Files variable to a list of Vim regular expressions. By default,
  90. " this variable is set to an empty string. For example, to not include files
  91. " in the temporary (/tmp, /var/tmp and d:\temp) directories, you can set the
  92. " MRU_Exclude_Files variable to
  93. "
  94. " let MRU_Exclude_Files = '^/tmp/.*\|^/var/tmp/.*' " For Unix
  95. " let MRU_Exclude_Files = '^c:\\temp\\.*' " For MS-Windows
  96. "
  97. " The specified pattern should be a Vim regular expression pattern.
  98. "
  99. " The default height of the MRU window is 8. You can set the MRU_Window_Height
  100. " variable to change the window height.
  101. "
  102. " let MRU_Window_Height = 15
  103. "
  104. " By default, when the :MRU command is invoked, the MRU list will be displayed
  105. " in a new window. Instead, if you want the MRU plugin to reuse the current
  106. " window, then you can set the 'MRU_Use_Current_Window' variable to one.
  107. "
  108. " let MRU_Use_Current_Window = 1
  109. "
  110. " The MRU plugin will reuse the current window. When a file name is selected,
  111. " the file is also opened in the current window.
  112. "
  113. " When you select a file from the MRU window, the MRU window will be
  114. " automatically closed and the selected file will be opened in the previous
  115. " window. You can set the 'MRU_Auto_Close' variable to zero to keep the MRU
  116. " window open.
  117. "
  118. " let MRU_Auto_Close = 0
  119. "
  120. " ****************** Do not modify after this line ************************
  121. if exists('loaded_mru')
  122. finish
  123. endif
  124. let loaded_mru=1
  125. " Line continuation used here
  126. let s:cpo_save = &cpo
  127. set cpo&vim
  128. " Maximum number of entries allowed in the MRU list
  129. if !exists('MRU_Max_Entries')
  130. let MRU_Max_Entries = 10
  131. endif
  132. " Files to exclude from the MRU list
  133. if !exists('MRU_Exclude_Files')
  134. let MRU_Exclude_Files = ''
  135. endif
  136. " Height of the MRU window
  137. " Default height is 8
  138. if !exists('MRU_Window_Height')
  139. let MRU_Window_Height = 8
  140. endif
  141. if !exists('MRU_Use_Current_Window')
  142. let MRU_Use_Current_Window = 0
  143. endif
  144. if !exists('MRU_Auto_Close')
  145. let MRU_Auto_Close = 1
  146. endif
  147. if !exists('MRU_File')
  148. if has('unix')
  149. let MRU_File = $HOME . "/.vim_mru_files"
  150. else
  151. let MRU_File = $VIM . "/_vim_mru_files"
  152. endif
  153. endif
  154. " MRU_LoadList
  155. " Load the latest MRU file list from the MRU file
  156. function! s:MRU_LoadList()
  157. " Read the list from the MRU file.
  158. if filereadable(g:MRU_File)
  159. exe "source " . escape(g:MRU_File, ' ')
  160. endif
  161. if exists('g:MRU_files')
  162. " Replace file separator (|) with newline
  163. let s:MRU_files = substitute(g:MRU_files, "|", "\n", "g")
  164. unlet! g:MRU_files
  165. else
  166. let s:MRU_files = ''
  167. endif
  168. " Refresh the MRU menu
  169. call s:MRU_Refresh_Menu()
  170. endfunction
  171. " MRU_SaveList
  172. " Save the MRU list to the file
  173. function! s:MRU_SaveList()
  174. " Replace all newlines with file separator (|)
  175. let mru_list = substitute(s:MRU_files, "\n", "|", "g")
  176. " set the verbose option to zero (default). Otherwise this will
  177. " mess up the text emitted below.
  178. let old_verbose = &verbose
  179. set verbose&vim
  180. " Clear the messages displayed on the status line
  181. echo
  182. " Save the MRU list
  183. exe "redir! > " . g:MRU_File
  184. silent! echon '" Most recently edited files in Vim (auto-generated)' . "\n"
  185. silent! echon "let MRU_files='" . mru_list . "'\n"
  186. redir END
  187. " Restore the verbose setting
  188. let &verbose = old_verbose
  189. endfunction
  190. " MRU_RemoveLines()
  191. " Remove the lines matching 'one_line' from 'str'
  192. function! s:MRU_RemoveLines(str, one_line)
  193. let idx = stridx(a:str, a:one_line . "\n")
  194. if idx == -1
  195. " one_line is not present in str
  196. return a:str
  197. endif
  198. let x = a:str
  199. while idx != -1
  200. " Remove the entry from the list by extracting the text before it
  201. " and then the text after it and then concatenate them
  202. let text_before = strpart(x, 0, idx)
  203. let rem_text = strpart(x, idx)
  204. let next_idx = stridx(rem_text, "\n")
  205. let text_after = strpart(rem_text, next_idx + 1)
  206. let x = text_before . text_after
  207. let idx = stridx(x, a:one_line . "\n")
  208. endwhile
  209. return x
  210. endfunction
  211. " MRU_TrimLines()
  212. " Returns the first "lcnt" lines from "lines"
  213. function! s:MRU_TrimLines(lines, lcnt)
  214. " Retain only lcnt lines in lines. Remove the remaining lines
  215. let llist = a:lines
  216. let cnt = a:lcnt
  217. let new_llist = ''
  218. while cnt > 0 && llist != ''
  219. " Extract one filename from the list
  220. let one_line = strpart(llist, 0, stridx(llist, "\n"))
  221. " Remove the extracted line from the list
  222. let llist = strpart(llist, stridx(llist, "\n") + 1)
  223. if one_line != ''
  224. " Retain the line (if non-empty)
  225. let new_llist = new_llist . one_line . "\n"
  226. endif
  227. " One more entry used up
  228. let cnt = cnt - 1
  229. endwhile
  230. return new_llist
  231. endfunction
  232. " MRU_AddFile
  233. " Add a file to the MRU file list
  234. function! s:MRU_AddFile(filename)
  235. if a:filename == ''
  236. return
  237. endif
  238. " Get the full path to the filename
  239. let fname = fnamemodify(a:filename, ':p')
  240. " Skip temporary buffer with buftype set
  241. if &buftype != ''
  242. return
  243. endif
  244. if g:MRU_Exclude_Files != ''
  245. " Do not add files matching the pattern specified in the
  246. " MRU_Exclude_Files to the MRU list
  247. if fname =~? g:MRU_Exclude_Files
  248. return
  249. endif
  250. endif
  251. " If the filename is already present in the MRU list, then move
  252. " it to the beginning of the list
  253. let idx = stridx(s:MRU_files, fname . "\n")
  254. if idx == -1 && !filereadable(fname)
  255. " File is not readable and is not in the MRU list
  256. return
  257. endif
  258. " Load the latest MRU file list
  259. call s:MRU_LoadList()
  260. " Remove the new file name from the existing MRU list (if already present)
  261. let old_flist = s:MRU_RemoveLines(s:MRU_files, fname)
  262. " Add the new file list to the beginning of the updated old file list
  263. let s:MRU_files = fname . "\n" . old_flist
  264. " Return the trimmed list
  265. let s:MRU_files = s:MRU_TrimLines(s:MRU_files, g:MRU_Max_Entries)
  266. " Save the updated MRU list
  267. call s:MRU_SaveList()
  268. " Refresh the MRU menu
  269. call s:MRU_Refresh_Menu()
  270. " If the MRU window is open, update the displayed MRU list
  271. let bname = '__MRU_Files__'
  272. let winnum = bufwinnr(bname)
  273. if winnum != -1
  274. let cur_winnr = winnr()
  275. call s:MRU_Open_Window()
  276. if winnr() != cur_winnr
  277. exe cur_winnr . 'wincmd w'
  278. endif
  279. endif
  280. endfunction
  281. " MRU_Edit_File
  282. " Edit the specified file
  283. function! s:MRU_Edit_File(filename)
  284. let fname = escape(a:filename, ' ')
  285. " If the file is already open in one of the windows, jump to it
  286. let winnum = bufwinnr(fname)
  287. if winnum != -1
  288. if winnum != winnr()
  289. exe winnum . 'wincmd w'
  290. endif
  291. else
  292. if &modified
  293. " Current buffer has unsaved changes, so open the file in a
  294. " new window
  295. exe 'split ' . fname
  296. else
  297. exe 'edit ' . fname
  298. endif
  299. endif
  300. endfunction
  301. " MRU_Window_Edit_File
  302. " Open a file selected from the MRU window
  303. function! s:MRU_Window_Edit_File(new_window)
  304. let fname = getline('.')
  305. if fname == ''
  306. return
  307. endif
  308. let fname = escape(fname, ' ')
  309. if a:new_window
  310. " Edit the file in a new window
  311. exe 'leftabove new ' . fname
  312. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  313. " Go back to the MRU window and close it
  314. let cur_winnr = winnr()
  315. wincmd p
  316. silent! close
  317. if winnr() != cur_winnr
  318. exe cur_winnr . 'wincmd w'
  319. endif
  320. endif
  321. else
  322. " If the selected file is already open in one of the windows,
  323. " jump to it
  324. let winnum = bufwinnr(fname)
  325. if winnum != -1
  326. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  327. " Automatically close the window if the file window is
  328. " not used to display the MRU list.
  329. silent! close
  330. endif
  331. " As the window numbers will change after closing a window,
  332. " get the window number again and jump to it, if the cursor
  333. " is not already in that window
  334. let winnum = bufwinnr(fname)
  335. if winnum != winnr()
  336. exe winnum . 'wincmd w'
  337. endif
  338. else
  339. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  340. " Automatically close the window if the file window is
  341. " not used to display the MRU list.
  342. silent! close
  343. " Jump to the window from which the MRU window was opened
  344. if exists('s:MRU_last_buffer')
  345. let last_winnr = bufwinnr(s:MRU_last_buffer)
  346. if last_winnr != -1 && last_winnr != winnr()
  347. exe last_winnr . 'wincmd w'
  348. endif
  349. endif
  350. else
  351. if g:MRU_Use_Current_Window == 0
  352. " Goto the previous window
  353. " If MRU_Use_Current_Window is set to one, then the
  354. " current window is used to open the file
  355. wincmd p
  356. endif
  357. endif
  358. " Edit the file
  359. if &modified
  360. exe 'split ' . fname
  361. else
  362. exe 'edit ' . fname
  363. endif
  364. endif
  365. endif
  366. endfunction
  367. " MRU_Open_Window
  368. " Display the Most Recently Used file list in a temporary window.
  369. function! s:MRU_Open_Window()
  370. " Load the latest MRU file list
  371. call s:MRU_LoadList()
  372. " Empty MRU list
  373. if s:MRU_files == ''
  374. echohl WarningMsg | echo 'MRU file list is empty' | echohl None
  375. return
  376. endif
  377. " Save the current buffer number. This is used later to open a file when a
  378. " entry is selected from the MRU window. The window number is not saved,
  379. " as the window number will change when new windows are opened.
  380. let s:MRU_last_buffer = bufnr('%')
  381. let bname = '__MRU_Files__'
  382. " If the window is already open, jump to it
  383. let winnum = bufwinnr(bname)
  384. if winnum != -1
  385. if winnr() != winnum
  386. " If not already in the window, jump to it
  387. exe winnum . 'wincmd w'
  388. endif
  389. setlocal modifiable
  390. " Delete the contents of the buffer to the black-hole register
  391. silent! %delete _
  392. else
  393. if g:MRU_Use_Current_Window
  394. " Reuse the current window
  395. "
  396. " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open
  397. " a new buffer
  398. let bufnum = bufnr(bname)
  399. if bufnum == -1
  400. let cmd = 'edit ' . bname
  401. else
  402. let cmd = 'buffer ' . bufnum
  403. endif
  404. exe cmd
  405. if bufnr('%') != bufnr(bname)
  406. " Failed to edit the MRU buffer
  407. return
  408. endif
  409. else
  410. " Open a new window at the bottom
  411. " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open
  412. " a new buffer
  413. let bufnum = bufnr(bname)
  414. if bufnum == -1
  415. let wcmd = bname
  416. else
  417. let wcmd = '+buffer' . bufnum
  418. endif
  419. exe 'silent! botright ' . g:MRU_Window_Height . 'split ' . wcmd
  420. endif
  421. endif
  422. " Mark the buffer as scratch
  423. setlocal buftype=nofile
  424. setlocal bufhidden=delete
  425. setlocal noswapfile
  426. setlocal nowrap
  427. setlocal nobuflisted
  428. " Use fixed height for the MRU window
  429. if v:version >= 602
  430. setlocal winfixheight
  431. endif
  432. " Setup the cpoptions properly for the maps to work
  433. let old_cpoptions = &cpoptions
  434. set cpoptions&vim
  435. " Create a mapping to jump to the file
  436. nnoremap <buffer> <silent> <CR> :call <SID>MRU_Window_Edit_File(0)<CR>
  437. nnoremap <buffer> <silent> o :call <SID>MRU_Window_Edit_File(1)<CR>
  438. nnoremap <buffer> <silent> u :MRU<CR>
  439. nnoremap <buffer> <silent> <2-LeftMouse>
  440. \ :call <SID>MRU_Window_Edit_File(0)<CR>
  441. nnoremap <buffer> <silent> q :close<CR>
  442. " Restore the previous cpoptions settings
  443. let &cpoptions = old_cpoptions
  444. " Display the MRU list
  445. silent! 0put =s:MRU_files
  446. " Move the cursor to the beginning of the file
  447. exe 1
  448. setlocal nomodifiable
  449. endfunction
  450. " MRU_Edit_Complete
  451. " Command-line completion function used by :MRUedit command
  452. function! s:MRU_Edit_Complete(ArgLead, CmdLine, CursorPos)
  453. " Return the list of MRU files
  454. return s:MRU_files
  455. endfunction
  456. " MRU_Edit_File_Cmd
  457. " Function to handle the MRUedit command
  458. function! s:MRU_Edit_File_Cmd(fspec)
  459. if a:fspec == ''
  460. return
  461. endif
  462. " Load the latest MRU file
  463. call s:MRU_LoadList()
  464. " User can specify either a number of a partial file name to
  465. " edit a file from the MRU list
  466. if a:fspec =~ '\d\+'
  467. " A number is specified
  468. let fnum = a:fspec
  469. if fnum > g:MRU_Max_Entries
  470. echohl WarningMsg
  471. echo 'Maximum number of entries in MRU list = ' .
  472. \ g:MRU_Max_Entries
  473. echohl None
  474. return
  475. endif
  476. let mru_list = s:MRU_files
  477. let i = 1
  478. while mru_list != '' && i < fnum
  479. let one_fname = strpart(mru_list, 0, stridx(mru_list, "\n"))
  480. if one_fname == ''
  481. break
  482. endif
  483. let mru_list = strpart(mru_list, stridx(mru_list, "\n") + 1)
  484. let i = i + 1
  485. endwhile
  486. if i == fnum
  487. let fname = strpart(mru_list, 0, stridx(mru_list, "\n"))
  488. if fname != ''
  489. call s:MRU_Edit_File(fname)
  490. endif
  491. endif
  492. else
  493. " Locate the file name matching the supplied partial name
  494. let mru_list = s:MRU_files
  495. let fname = ''
  496. let fname_cnt = 0
  497. while mru_list != ''
  498. let one_fname = strpart(mru_list, 0, stridx(mru_list, "\n"))
  499. if one_fname == ''
  500. break
  501. endif
  502. if one_fname =~? a:fspec
  503. let fname = one_fname
  504. let fname_cnt = fname_cnt + 1
  505. endif
  506. let mru_list = strpart(mru_list, stridx(mru_list, "\n") + 1)
  507. endwhile
  508. if fname_cnt == 0
  509. echohl WarningMsg
  510. echo 'No matching file for ' . a:fspec
  511. echohl None
  512. return
  513. endif
  514. if fname_cnt > 1
  515. echohl WarningMsg
  516. echo 'More than one match for ' . a:fspec
  517. echohl None
  518. return
  519. endif
  520. call s:MRU_Edit_File(fname)
  521. endif
  522. endfunction
  523. " MRU_Refresh_Menu()
  524. " Refresh the MRU menu
  525. function! s:MRU_Refresh_Menu()
  526. if !has('gui_running') || &guioptions !~ 'm'
  527. " Not running in GUI mode
  528. return
  529. endif
  530. " Setup the cpoptions properly for the maps to work
  531. let old_cpoptions = &cpoptions
  532. set cpoptions&vim
  533. " Remove the MRU menu
  534. " To retain the teared-off MRU menu, we need to add a dummy entry
  535. silent! unmenu &File.Recent\ Files
  536. noremenu &File.Recent\ Files.Dummy <Nop>
  537. silent! unmenu! &File.Recent\ Files
  538. anoremenu <silent> &File.Recent\ Files.Refresh\ list
  539. \ :call <SID>MRU_LoadList()<CR>
  540. anoremenu File.Recent\ Files.-SEP1- :
  541. " Add the filenames in the MRU list to the menu
  542. let flist = s:MRU_files
  543. while flist != ''
  544. " Extract one filename from the list
  545. let fname = strpart(flist, 0, stridx(flist, "\n"))
  546. if fname == ''
  547. break
  548. endif
  549. " Escape special characters in the filename
  550. let esc_fname = escape(fnamemodify(fname, ':t'), ". \\|\t")
  551. " Remove the extracted line from the list
  552. let flist = strpart(flist, stridx(flist, "\n") + 1)
  553. " Truncate the directory name if it is long
  554. let dir_name = fnamemodify(fname, ':h')
  555. let len = strlen(dir_name)
  556. " Shorten long file names by adding only few characters from
  557. " the beginning and end.
  558. if len > 30
  559. let dir_name = strpart(dir_name, 0, 10) .
  560. \ '...' .
  561. \ strpart(dir_name, len - 20)
  562. endif
  563. let esc_dir_name = escape(dir_name, ". \\|\t")
  564. exe 'anoremenu <silent> &File.Recent\ Files.' . esc_fname .
  565. \ '\ (' . esc_dir_name . ')' .
  566. \ " :call <SID>MRU_Edit_File('" . fname . "')<CR>"
  567. endwhile
  568. " Remove the dummy menu entry
  569. unmenu &File.Recent\ Files.Dummy
  570. " Restore the previous cpoptions settings
  571. let &cpoptions = old_cpoptions
  572. endfunction
  573. " Load the MRU list on plugin startup
  574. call s:MRU_LoadList()
  575. " Autocommands to detect the most recently used files
  576. autocmd BufRead * call s:MRU_AddFile(expand('<afile>'))
  577. autocmd BufNewFile * call s:MRU_AddFile(expand('<afile>'))
  578. autocmd BufWritePost * call s:MRU_AddFile(expand('<afile>'))
  579. " Command to open the MRU window
  580. command! -nargs=0 MRU call s:MRU_Open_Window()
  581. command! -nargs=1 -complete=custom,s:MRU_Edit_Complete MRUedit
  582. \ call s:MRU_Edit_File_Cmd(<q-args>)
  583. " restore 'cpo'
  584. let &cpo = s:cpo_save
  585. unlet s:cpo_save