mru.vim 17 KB

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