mru.vim 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. " File: mru.vim
  2. " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
  3. " Version: 2.1
  4. " Last Modified: May 3, 2005
  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. "
  29. " Usage
  30. " -----
  31. " You can use the ":MRU" command to list all the most recently edited file
  32. " names. The file names will be listed in a temporary Vim window. If the MRU
  33. " list window is already opened, then the MRU list displayed in the window
  34. " will be refreshed.
  35. "
  36. " You can use the normal Vim commands to move around the MRU window. You
  37. " cannot make changes in the MRU window.
  38. "
  39. " You can select a file name to edit by pressing the <Enter> key or by double
  40. " clicking the left mouse button on a file name. The selected file will be
  41. " opened.
  42. "
  43. " You can press the 'o' key to open the file name under the cursor in the
  44. " MRU window in a new window.
  45. "
  46. " You can press the 'u' key in the MRU window to update the file list. This is
  47. " useful if you keep the MRU window open.
  48. "
  49. " You can close the MRU window by pressing the 'q' key or using one of the Vim
  50. " window commands.
  51. "
  52. " If you are using GUI Vim, then the names of the recently edited files are
  53. " added to the "File->Recent Files" menu. You can select the name of a file
  54. " from this sub-menu to edit the file.
  55. "
  56. " Configuration
  57. " -------------
  58. " By changing the following variables you can configure the behavior of this
  59. " plugin. Set the following variables in your .vimrc file using the 'let'
  60. " command.
  61. "
  62. " The list of recently edit file names is stored in the file specified by the
  63. " MRU_File variable. The default setting for this variable is
  64. " $HOME/.vim_mru_files. You can change this variable to point to a file by
  65. " adding the following line to the .vimrc file:
  66. "
  67. " let MRU_File = 'd:\myhome\_vim_mru_files'
  68. "
  69. " By default, the plugin will remember the names of the last 10 used files.
  70. " As you edit more files, old file names will be removed from the MRU list.
  71. " You can set the 'MRU_Max_Entries' variable to remember more file names. For
  72. " example, to remember 20 most recently used file names, you can use
  73. "
  74. " let MRU_Max_Entries = 20
  75. "
  76. " By default, all the edited file names will be added to the MRU list. If you
  77. " want to exclude file names matching a list of patterns, you can set the
  78. " MRU_Exclude_Files variable to a list of Vim regular expressions. By default,
  79. " this variable is set to an empty string. For example, to not include files
  80. " in the temporary (/tmp, /var/tmp and d:\temp) directories, you can set the
  81. " MRU_Exclude_Files variable to
  82. "
  83. " let MRU_Exclude_Files = '^/tmp/.*\|^/var/tmp/.*' " For Unix
  84. " let MRU_Exclude_Files = '^c:\\temp\\.*' " For MS-Windows
  85. "
  86. " The specified pattern should be a Vim regular expression pattern.
  87. "
  88. " The default height of the MRU window is 8. You can set the MRU_Window_Height
  89. " variable to change the window height.
  90. "
  91. " let MRU_Window_Height = 15
  92. "
  93. " By default, when the :MRU command is invoked, the MRU list will be displayed
  94. " in a new window. Instead, if you want the MRU plugin to reuse the current
  95. " window, then you can set the 'MRU_Use_Current_Window' variable to one.
  96. "
  97. " let MRU_Use_Current_Window = 1
  98. "
  99. " The MRU plugin will reuse the current window. When a file name is selected,
  100. " the file is also opened in the current window.
  101. "
  102. " When you select a file from the MRU window, the MRU window will be
  103. " automatically closed and the selected file will be opened in the previous
  104. " window. You can set the 'MRU_Auto_Close' variable to zero to keep the MRU
  105. " window open.
  106. "
  107. " let MRU_Auto_Close = 0
  108. "
  109. " ****************** Do not modify after this line ************************
  110. if exists('loaded_mru')
  111. finish
  112. endif
  113. let loaded_mru=1
  114. " Line continuation used here
  115. let s:cpo_save = &cpo
  116. set cpo&vim
  117. " Maximum number of entries allowed in the MRU list
  118. if !exists('MRU_Max_Entries')
  119. let MRU_Max_Entries = 10
  120. endif
  121. " Files to exclude from the MRU list
  122. if !exists('MRU_Exclude_Files')
  123. let MRU_Exclude_Files = ''
  124. endif
  125. " Height of the MRU window
  126. " Default height is 8
  127. if !exists('MRU_Window_Height')
  128. let MRU_Window_Height = 8
  129. endif
  130. if !exists('MRU_Use_Current_Window')
  131. let MRU_Use_Current_Window = 0
  132. endif
  133. if !exists('MRU_Auto_Close')
  134. let MRU_Auto_Close = 1
  135. endif
  136. if !exists('MRU_File')
  137. if has('unix')
  138. let MRU_File = $HOME . "/.vim_mru_files"
  139. else
  140. let MRU_File = $VIM . "/_vim_mru_files"
  141. endif
  142. endif
  143. " Read the saved MRU list
  144. if filereadable(MRU_File)
  145. exe "source " . escape(MRU_File, ' ')
  146. endif
  147. if exists('g:MRU_list')
  148. " Replace %MRU% with newlines
  149. let g:MRU_list = substitute(g:MRU_list, "%MRU%", "\n", "g")
  150. let s:MRU_list = g:MRU_list
  151. unlet! g:MRU_list
  152. else
  153. let s:MRU_list = ''
  154. endif
  155. " New files opened in this Vim session
  156. let s:MRU_new_list = ''
  157. " MRU_RemoveLines()
  158. " Remove the lines matching 'one_line' from 'str'
  159. function! s:MRU_RemoveLines(str, one_line)
  160. let idx = stridx(a:str, a:one_line . "\n")
  161. if idx == -1
  162. " one_line is not present in str
  163. return a:str
  164. endif
  165. let x = a:str
  166. while idx != -1
  167. " Remove the entry from the list by extracting the text before it
  168. " and then the text after it and then concatenate them
  169. let text_before = strpart(x, 0, idx)
  170. let rem_text = strpart(x, idx)
  171. let next_idx = stridx(rem_text, "\n")
  172. let text_after = strpart(rem_text, next_idx + 1)
  173. let x = text_before . text_after
  174. let idx = stridx(x, a:one_line . "\n")
  175. endwhile
  176. return x
  177. endfunction
  178. " MRU_TrimLines()
  179. " Returns the first "lcnt" lines from "lines"
  180. function! s:MRU_TrimLines(lines, lcnt)
  181. " Retain only lcnt lines in lines. Remove the remaining lines
  182. let llist = a:lines
  183. let cnt = a:lcnt
  184. let new_llist = ''
  185. while cnt > 0 && llist != ''
  186. " Extract one filename from the list
  187. let one_line = strpart(llist, 0, stridx(llist, "\n"))
  188. " Remove the extracted line from the list
  189. let llist = strpart(llist, stridx(llist, "\n") + 1)
  190. if one_line != ''
  191. " Retain the line (if non-empty)
  192. let new_llist = new_llist . one_line . "\n"
  193. endif
  194. " One more entry used up
  195. let cnt = cnt - 1
  196. endwhile
  197. return new_llist
  198. endfunction
  199. " MRU_AddNewFiles()
  200. " Adds new files from new_files to file_list at the beginning. If a file
  201. " already exists in file_list, then it is moved to the beginning.
  202. " Also trim the list, so that it contains only file_count entries
  203. function! s:MRU_AddNewFiles(file_list, new_files, file_count)
  204. let new_flist = a:new_files
  205. let old_flist = a:file_list
  206. " Remove files in new_files that are also present in the old file_list
  207. while new_flist != ''
  208. " Extract one filename from the list
  209. let one_line = strpart(new_flist, 0, stridx(new_flist, "\n"))
  210. " Remove the extracted line from the list
  211. let new_flist = strpart(new_flist, stridx(new_flist, "\n") + 1)
  212. " Remove the file from the old list
  213. let old_flist = s:MRU_RemoveLines(old_flist, one_line)
  214. endwhile
  215. " Add the new file list to the beginning of the updated old file list
  216. let x = a:new_files . old_flist
  217. " Return the trimmed list
  218. return s:MRU_TrimLines(x, a:file_count)
  219. endfunction
  220. " MRU_AddFile
  221. " Add a file to the MRU file list
  222. function! s:MRU_AddFile(filename)
  223. if a:filename == ''
  224. return
  225. endif
  226. " Get the full path to the filename
  227. let fname = fnamemodify(a:filename, ':p')
  228. " Skip temporary buffer with buftype set
  229. if &buftype != ''
  230. return
  231. endif
  232. if g:MRU_Exclude_Files != ''
  233. " Do not add files matching the pattern specified in the
  234. " MRU_Exclude_Files to the MRU list
  235. if fname =~? g:MRU_Exclude_Files
  236. return
  237. endif
  238. endif
  239. " If the filename is already present in the MRU list, then move
  240. " it to the beginning of the list
  241. let idx = stridx(s:MRU_list, fname . "\n")
  242. if idx == -1 && !filereadable(fname)
  243. " File is not readable and is not in the MRU list
  244. return
  245. endif
  246. " Add the new filename to the MRU list
  247. let s:MRU_list = s:MRU_AddNewFiles(s:MRU_list, fname . "\n",
  248. \ g:MRU_Max_Entries)
  249. " Add the new filename to the list of files edited in this Vim session
  250. let s:MRU_new_list = s:MRU_AddNewFiles(s:MRU_new_list, fname . "\n",
  251. \ g:MRU_Max_Entries)
  252. " Refresh the MRU menu
  253. call s:MRU_Refresh_Menu()
  254. " If the MRU window is open, update the displayed MRU list
  255. let bname = '__MRU_Files__'
  256. let winnum = bufwinnr(bname)
  257. if winnum != -1
  258. let cur_winnr = winnr()
  259. call s:MRU_Open_Window()
  260. if winnr() != cur_winnr
  261. exe cur_winnr . 'wincmd w'
  262. endif
  263. endif
  264. endfunction
  265. " MRU_SaveList
  266. " Save the MRU list to the file
  267. function! s:MRU_SaveList()
  268. let mru_list = s:MRU_new_list
  269. if mru_list == ''
  270. " Nothing new to save
  271. return
  272. endif
  273. " Read the list from the MRU file.
  274. if filereadable(g:MRU_File)
  275. exe "source " . escape(g:MRU_File, ' ')
  276. endif
  277. if exists('g:MRU_list')
  278. " Replace %MRU% with newline
  279. let g:MRU_list = substitute(g:MRU_list, "%MRU%", "\n", "g")
  280. " Merge the files edit in this session with the global list
  281. let mru_list = s:MRU_AddNewFiles(g:MRU_list, mru_list,
  282. \ g:MRU_Max_Entries)
  283. unlet! g:MRU_list
  284. endif
  285. " Replace all newlines with %MRU%
  286. let mru_list = substitute(mru_list, "\n", "%MRU%", "g")
  287. " Clear the messages displayed on the status line
  288. echo
  289. " Save the MRU list
  290. exe "redir! > " . g:MRU_File
  291. silent! echon '" Most recently edited files in Vim (auto-generated)' . "\n"
  292. silent! echon "let MRU_list='" . mru_list . "'\n"
  293. redir END
  294. endfunction
  295. " MRU_EditFile
  296. " Open a file selected from the MRU window
  297. function! s:MRU_EditFile(new_window)
  298. let fname = getline('.')
  299. if fname == ''
  300. return
  301. endif
  302. if a:new_window
  303. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  304. silent! close
  305. endif
  306. exe 'leftabove new ' . fname
  307. else
  308. " If the selected file is already open in one of the windows,
  309. " jump to it
  310. let winnum = bufwinnr(fname)
  311. if winnum != -1
  312. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  313. " Automatically close the window if the file window is
  314. " not used to display the MRU list.
  315. silent! close
  316. endif
  317. " As the window numbers will change after closing a window,
  318. " get the window number again and jump to it, if the cursor
  319. " is not already in that window
  320. let winnum = bufwinnr(fname)
  321. if winnum != winnr()
  322. exe winnum . 'wincmd w'
  323. endif
  324. else
  325. if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
  326. " Automatically close the window if the file window is
  327. " not used to display the MRU list.
  328. silent! close
  329. " Jump to the window from which the MRU window was opened
  330. if exists('s:MRU_last_buffer')
  331. exe 'let last_winnr = bufwinnr(' . s:MRU_last_buffer ')'
  332. if last_winnr != -1 && last_winnr != winnr()
  333. exe last_winnr . 'wincmd w'
  334. endif
  335. endif
  336. else
  337. if g:MRU_Use_Current_Window == 0
  338. " Goto the previous window
  339. " If MRU_Use_Current_Window is set to one, then the
  340. " current window is used to open the file
  341. wincmd p
  342. endif
  343. endif
  344. " Edit the file
  345. let bnum = bufnr(fname)
  346. if bnum != -1
  347. exe 'buffer ' . bnum
  348. else
  349. exe 'edit ' . fname
  350. endif
  351. endif
  352. endif
  353. endfunction
  354. " MRU_Open_Window
  355. " Display the Most Recently Used file list in a temporary window.
  356. function! s:MRU_Open_Window()
  357. " Empty MRU list
  358. if s:MRU_list == ''
  359. echohl WarningMsg | echo 'MRU List is empty' | echohl None
  360. return
  361. endif
  362. " Save the current buffer number. This is used later to open a file when a
  363. " entry is selected from the MRU window. The window number is not saved,
  364. " as the window number will change when new windows are opened.
  365. let s:MRU_last_buffer = bufnr('%')
  366. let bname = '__MRU_Files__'
  367. " If the window is already open, jump to it
  368. let winnum = bufwinnr(bname)
  369. if winnum != -1
  370. if winnr() != winnum
  371. " If not already in the window, jump to it
  372. exe winnum . 'wincmd w'
  373. endif
  374. setlocal modifiable
  375. " Delete the contents of the buffer to the black-hole register
  376. silent! %delete _
  377. else
  378. if g:MRU_Use_Current_Window
  379. " Reuse the current window
  380. "
  381. " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open
  382. " a new buffer
  383. let bufnum = bufnr(bname)
  384. if bufnum == -1
  385. let wcmd = bname
  386. else
  387. let wcmd = '+buffer' . bufnum
  388. endif
  389. exe 'silent! edit ' . wcmd
  390. else
  391. " Open a new window at the bottom
  392. " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open
  393. " a new buffer
  394. let bufnum = bufnr(bname)
  395. if bufnum == -1
  396. let wcmd = bname
  397. else
  398. let wcmd = '+buffer' . bufnum
  399. endif
  400. exe 'silent! botright ' . g:MRU_Window_Height . 'split ' . wcmd
  401. endif
  402. endif
  403. " Mark the buffer as scratch
  404. setlocal buftype=nofile
  405. setlocal bufhidden=delete
  406. setlocal noswapfile
  407. setlocal nowrap
  408. setlocal nobuflisted
  409. " Setup the cpoptions properly for the maps to work
  410. let old_cpoptions = &cpoptions
  411. set cpoptions&vim
  412. " Create a mapping to jump to the file
  413. nnoremap <buffer> <silent> <CR> :call <SID>MRU_EditFile(0)<CR>
  414. nnoremap <buffer> <silent> o :call <SID>MRU_EditFile(1)<CR>
  415. nnoremap <buffer> <silent> u :MRU<CR>
  416. nnoremap <buffer> <silent> <2-LeftMouse> :call <SID>MRU_EditFile(0)<CR>
  417. nnoremap <buffer> <silent> q :close<CR>
  418. " Restore the previous cpoptions settings
  419. let &cpoptions = old_cpoptions
  420. " Display the MRU list
  421. silent! 0put =s:MRU_list
  422. " Move the cursor to the beginning of the file
  423. exe 1
  424. setlocal nomodifiable
  425. endfunction
  426. " MRU_Refresh_Menu()
  427. " Refresh the MRU menu
  428. function! s:MRU_Refresh_Menu()
  429. if !has('gui_running') || &guioptions !~ 'm'
  430. " Not running in GUI mode
  431. return
  432. endif
  433. " Setup the cpoptions properly for the maps to work
  434. let old_cpoptions = &cpoptions
  435. set cpoptions&vim
  436. " Remove the existing MRU menu
  437. silent! aunmenu &File.Recent\ Files
  438. " Add the filenames in the MRU list to the menu
  439. let flist = s:MRU_list
  440. while flist != ''
  441. " Extract one filename from the list
  442. let fname = strpart(flist, 0, stridx(flist, "\n"))
  443. " Escape special characters in the filename
  444. let esc_fname = escape(fnamemodify(fname, ':t'), ". \\|\t")
  445. " Remove the extracted line from the list
  446. let flist = strpart(flist, stridx(flist, "\n") + 1)
  447. " Truncate the directory name if it is long
  448. let dir_name = fnamemodify(fname, ':h')
  449. let len = strlen(dir_name)
  450. " Shorten long file names by adding only few characters from
  451. " the beginning and end.
  452. if len > 30
  453. let dir_name = strpart(dir_name, 0, 10) .
  454. \ '...' .
  455. \ strpart(dir_name, len - 20)
  456. endif
  457. let esc_dir_name = escape(dir_name, ". \\|\t")
  458. exe 'amenu <silent> &File.Recent\ Files.' . esc_fname .
  459. \ '\ (' . esc_dir_name . ')' .
  460. \ ' :confirm edit ' . fname . '<CR>'
  461. endwhile
  462. " Restore the previous cpoptions settings
  463. let &cpoptions = old_cpoptions
  464. endfunction
  465. " Refresh the MRU menu at the startup
  466. call s:MRU_Refresh_Menu()
  467. " Autocommands to detect the most recently used files
  468. autocmd BufRead * call s:MRU_AddFile(expand('<afile>'))
  469. autocmd BufNewFile * call s:MRU_AddFile(expand('<afile>'))
  470. autocmd BufWritePost * call s:MRU_AddFile(expand('<afile>'))
  471. autocmd VimLeavePre * call s:MRU_SaveList()
  472. " Command to open the MRU window
  473. command! -nargs=0 MRU call s:MRU_Open_Window()
  474. " restore 'cpo'
  475. let &cpo = s:cpo_save
  476. unlet s:cpo_save