瀏覽代碼

Version 3.0 (Jan 12, 2008)

Yegappan Lakshmanan 12 年之前
父節點
當前提交
c5cb082356
共有 1 個文件被更改,包括 129 次插入162 次删除
  1. 129 162
      plugin/mru.vim

+ 129 - 162
plugin/mru.vim

@@ -1,7 +1,7 @@
 " File: mru.vim
 " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
-" Version: 2.5
-" Last Modified: October 30, 2007
+" Version: 3.0
+" Last Modified: January 12, 2008
 "
 " Overview
 " --------
@@ -10,7 +10,9 @@
 " file names as you open/edit them in Vim.
 "
 " This plugin will work on all the platforms where Vim is supported. This
-" plugin will work in both console and GUI Vim.
+" plugin will work in both console and GUI Vim. This version of the MRU
+" plugin needs Vim 7.0 and above. If you are using an earlier version of
+" Vim, then you should use an older version of the MRU plugin.
 "
 " The recently used filenames are stored in a file specified by the Vim
 " MRU_File variable.
@@ -53,15 +55,24 @@
 " You can press the 'o' key to open the file name under the cursor in the
 " MRU window in a new window.
 "
+" To open a file from the MRU window in a new tab, press the 't' key.  If the
+" file is already opened in a window in the current or in another tab, then
+" the cursor is moved to that tab. Othewrise, a new tab is opened.
+"
 " You can press the 'u' key in the MRU window to update the file list. This is
-" useful if you keep the MRU window open.
+" useful if you keep the MRU window open always.
 "
 " You can close the MRU window by pressing the 'q' key or using one of the Vim
 " window commands.
 "
+" To display only files matching a pattern from the MRU list in the MRU
+" window, you can specify a pattern to the ":MRU" command. For example, to
+" display only file names containing "vim" in them, you can use the following
+" command ":MRU vim"
+"
 " You can use the ":MRUedit" command to edit files from the MRU list. This
 " command supports completion of file names from the MRU list. You can specify
-" the file either by the name or by the location in the MRU list.
+" a file either by the name or by the location in the MRU list.
 "
 " Whenever the MRU list changes, the MRU file is updated with the latest MRU
 " list. When you have multiple instances of Vim running at the same time, the
@@ -122,10 +133,14 @@
 "       let MRU_Auto_Close = 0
 "
 " ****************** Do not modify after this line ************************
-if exists('loaded_mru')
+if exists('loaded_mru_autoload')
+    finish
+endif
+let loaded_mru_autoload=1
+
+if v:version < 700
     finish
 endif
-let loaded_mru=1
 
 " Line continuation used here
 let s:cpo_save = &cpo
@@ -168,15 +183,17 @@ endif
 function! s:MRU_LoadList()
     " Read the list from the MRU file.
     if filereadable(g:MRU_File)
-        exe "source " . escape(g:MRU_File, ' ')
-    endif
-
-    if exists('g:MRU_files')
-        " Replace file separator (|) with newline
-        let s:MRU_files = substitute(g:MRU_files, "|", "\n", "g")
-        unlet! g:MRU_files
+        let s:MRU_files = readfile(g:MRU_File)
+        if s:MRU_files[0] =~# '^" Most recently edited files in Vim'
+            " Generated by the previous version of the MRU plugin. Ignore the
+            " list
+            let s:MRU_files = []
+        elseif s:MRU_files[0] =~# '^#'
+            " Remove the comment line
+            call remove(s:MRU_files, 0)
+        endif
     else
-        let s:MRU_files = ''
+        let s:MRU_files = []
     endif
 
     " Refresh the MRU menu
@@ -186,79 +203,10 @@ endfunction
 " MRU_SaveList
 " Save the MRU list to the file
 function! s:MRU_SaveList()
-    " Replace all newlines with file separator (|)
-    let mru_list = substitute(s:MRU_files, "\n", "|", "g")
-    " Escape single quote in filenames with double single quotes
-    let mru_list = substitute(mru_list, "'", "''", "g")
-
-    " set the verbose option to zero (default). Otherwise this will
-    " mess up the text emitted below.
-    let old_verbose = &verbose
-    set verbose&vim
-
-    " Clear the messages displayed on the status line
-    echo
-
-    " Save the MRU list
-    exe "redir! > " . g:MRU_File
-    silent! echon '" Most recently edited files in Vim (auto-generated)' . "\n"
-    silent! echon "let MRU_files='" . mru_list . "'\n"
-    redir END
-
-    " Restore the verbose setting
-    let &verbose = old_verbose
-endfunction
-
-" MRU_RemoveLines()
-" Remove the lines matching 'one_line' from 'str'
-function! s:MRU_RemoveLines(str, one_line)
-    let idx = stridx(a:str, a:one_line . "\n")
-    if idx == -1
-        " one_line is not present in str
-        return a:str
-    endif
-
-    let x = a:str
-
-    while idx != -1
-        " Remove the entry from the list by extracting the text before it
-        " and then the text after it and then concatenate them
-        let text_before = strpart(x, 0, idx)
-        let rem_text = strpart(x, idx)
-        let next_idx = stridx(rem_text, "\n")
-        let text_after = strpart(rem_text, next_idx + 1)
-
-        let x = text_before . text_after
-        let idx = stridx(x, a:one_line . "\n")
-    endwhile
-
-    return x
-endfunction
-
-" MRU_TrimLines()
-" Returns the first "lcnt" lines from "lines"
-function! s:MRU_TrimLines(lines, lcnt)
-    " Retain only  lcnt lines in lines. Remove the remaining lines
-    let llist = a:lines
-    let cnt = a:lcnt
-    let new_llist = ''
-    while cnt > 0 && llist != ''
-        " Extract one filename from the list
-        let one_line = strpart(llist, 0, stridx(llist, "\n"))
-
-        " Remove the extracted line from the list
-        let llist = strpart(llist, stridx(llist, "\n") + 1)
-
-        if one_line != ''
-            " Retain the line (if non-empty)
-            let new_llist = new_llist . one_line . "\n"
-        endif
-
-        " One more entry used up
-        let cnt = cnt - 1
-    endwhile
-
-    return new_llist
+    let l = []
+    call add(l, '# Most recently edited files in Vim (version 3.0)')
+    call extend(l, s:MRU_files)
+    call writefile(l, g:MRU_File)
 endfunction
 
 " MRU_AddFile
@@ -285,23 +233,27 @@ function! s:MRU_AddFile(acmd_bufnr)
 
     " If the filename is already present in the MRU list, then move
     " it to the beginning of the list
-    let idx = stridx(s:MRU_files, fname . "\n")
-    if idx == -1 && !filereadable(fname)
-        " File is not readable and is not in the MRU list
-        return
+    let idx = index(s:MRU_files, fname)
+    if idx == -1
+        if !filereadable(fname)
+            " File is not readable and is not in the MRU list
+            return
+        endif
     endif
 
     " Load the latest MRU file list
     call s:MRU_LoadList()
 
     " Remove the new file name from the existing MRU list (if already present)
-    let old_flist = s:MRU_RemoveLines(s:MRU_files, fname)
+    call filter(s:MRU_files, 'v:val !=# fname')
 
     " Add the new file list to the beginning of the updated old file list
-    let s:MRU_files = fname . "\n" . old_flist
+    call insert(s:MRU_files, fname, 0)
 
     " Return the trimmed list
-    let s:MRU_files = s:MRU_TrimLines(s:MRU_files, g:MRU_Max_Entries)
+    if len(s:MRU_files) > g:MRU_Max_Entries
+        call remove(s:MRU_files, g:MRU_Max_Entries, -1)
+    endif
 
     " Save the updated MRU list
     call s:MRU_SaveList()
@@ -344,7 +296,10 @@ endfunction
 
 " MRU_Window_Edit_File
 " Open a file selected from the MRU window
-function! s:MRU_Window_Edit_File(new_window)
+"   win_opt == useopen, open file in previous window
+"   win_opt == newwin, open file in new window
+"   win_opt == newtab, open file in new tab
+function! s:MRU_Window_Edit_File(win_opt)
     let fname = getline('.')
 
     if fname == ''
@@ -353,7 +308,7 @@ function! s:MRU_Window_Edit_File(new_window)
 
     let fname = escape(fname, ' %#')
 
-    if a:new_window
+    if a:win_opt == 'newwin'
         " Edit the file in a new window
         exe 'leftabove new ' . fname
 
@@ -368,6 +323,41 @@ function! s:MRU_Window_Edit_File(new_window)
                 exe cur_winnr . 'wincmd w'
             endif
         endif
+    elseif a:win_opt == 'newtab'
+        if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0
+            " Automatically close the window if the file window is
+            " not used to display the MRU list.
+            silent! close
+        endif
+
+        " If the selected file is already open in the current tab or in
+        " another tab, jump to it. Otherwise open it in a new tab
+        if bufwinnr('^' . fname . '$') == -1
+            let tabnum = -1
+            let i = 1
+            let bnum = bufnr('^' . fname . '$')
+            while i <= tabpagenr('$')
+                if index(tabpagebuflist(i), bnum) != -1
+                    let tabnum = i
+                    break
+                endif
+                let i += 1
+            endwhile
+
+            if tabnum != -1
+                " Goto the tab containing the file
+                exe 'tabnext ' . i
+            else
+                " Open a new tab as the last tab page
+                exe '999tabnew ' . escape(fname, ' ')
+            endif
+        endif
+
+        " Jump to the window containing the file
+        let winnum = bufwinnr('^' . fname . '$')
+        if winnum != winnr()
+            exe winnum . 'wincmd w'
+        endif
     else
         " If the selected file is already open in one of the windows,
         " jump to it
@@ -421,13 +411,13 @@ endfunction
 
 " MRU_Open_Window
 " Display the Most Recently Used file list in a temporary window.
-function! s:MRU_Open_Window()
+function! s:MRU_Open_Window(...)
 
     " Load the latest MRU file list
     call s:MRU_LoadList()
 
     " Empty MRU list
-    if s:MRU_files == ''
+    if empty(s:MRU_files)
         echohl WarningMsg | echo 'MRU file list is empty' | echohl None
         return
     endif
@@ -502,18 +492,28 @@ function! s:MRU_Open_Window()
     set cpoptions&vim
 
     " Create a mapping to jump to the file
-    nnoremap <buffer> <silent> <CR> :call <SID>MRU_Window_Edit_File(0)<CR>
-    nnoremap <buffer> <silent> o :call <SID>MRU_Window_Edit_File(1)<CR>
+    nnoremap <buffer> <silent> <CR>
+                \ :call <SID>MRU_Window_Edit_File('useopen')<CR>
+    nnoremap <buffer> <silent> o
+                \ :call <SID>MRU_Window_Edit_File('newwin')<CR>
+    nnoremap <buffer> <silent> t
+                \ :call <SID>MRU_Window_Edit_File('newtab')<CR>
     nnoremap <buffer> <silent> u :MRU<CR>
     nnoremap <buffer> <silent> <2-LeftMouse>
-                \ :call <SID>MRU_Window_Edit_File(0)<CR>
+                \ :call <SID>MRU_Window_Edit_File('useopen')<CR>
     nnoremap <buffer> <silent> q :close<CR>
 
     " Restore the previous cpoptions settings
     let &cpoptions = old_cpoptions
 
     " Display the MRU list
-    silent! 0put =s:MRU_files
+    if a:0 == 0
+        " No search pattern specified. Display the complete list
+        silent! 0put =s:MRU_files
+    else
+        " Display only the entries matching the specified pattern
+        silent! 0put =filter(copy(s:MRU_files), 'v:val =~? a:1')
+    endif
 
     " Move the cursor to the beginning of the file
     exe 1
@@ -524,8 +524,12 @@ endfunction
 " MRU_Edit_Complete
 " Command-line completion function used by :MRUedit command
 function! s:MRU_Edit_Complete(ArgLead, CmdLine, CursorPos)
-    " Return the list of MRU files
-    return s:MRU_files
+    if a:ArgLead == ''
+        " Return the list of MRU files
+        return s:MRU_files
+    else
+        return filter(copy(s:MRU_files), 'v:val =~? a:ArgLead')
+    endif
 endfunction
 
 " MRU_Edit_File_Cmd
@@ -543,71 +547,44 @@ function! s:MRU_Edit_File_Cmd(fspec)
     if a:fspec =~ '^\d\+$'
         " A number is specified
         let fnum = a:fspec
-        if fnum > g:MRU_Max_Entries
+        if fnum <= 0 || fnum > len(s:MRU_files)
             echohl WarningMsg
-            echo 'Maximum number of entries in MRU list = ' .
-                        \ g:MRU_Max_Entries 
+            echo 'Error: valid range of values is 1 - ' . len(s:MRU_files)
             echohl None
             return
         endif
 
-        let mru_list = s:MRU_files
-
-        let i = 1
-        while mru_list != '' && i < fnum
-            let one_fname = strpart(mru_list, 0, stridx(mru_list, "\n"))
-            if one_fname == ''
-                break
-            endif
-
-            let mru_list = strpart(mru_list, stridx(mru_list, "\n") + 1)
-            let i = i + 1
-        endwhile
+        " User index is 1 based, but the internal index is 0 based
+        let fnum -= 1
 
-        if i == fnum
-            let fname = strpart(mru_list, 0, stridx(mru_list, "\n"))
-            if fname != ''
-                call s:MRU_Edit_File(fname)
-            endif
+        let fname = s:MRU_files[fnum]
+        if fname != ''
+            call s:MRU_Edit_File(fname)
         endif
     else
         " Locate the file name matching the supplied partial name
-        let mru_list = s:MRU_files
-        let fname = ''
-        let fname_cnt = 0
 
         " Escape backslash in the partial filename, otherwise regexp
         " comparison will fail
         let fpat = escape(a:fspec, '\')
 
-        while mru_list != ''
-            let one_fname = strpart(mru_list, 0, stridx(mru_list, "\n"))
-            if one_fname == ''
-                break
-            endif
-
-            if one_fname =~? fpat
-                let fname = one_fname
-                let fname_cnt = fname_cnt + 1
-            endif
-
-            let mru_list = strpart(mru_list, stridx(mru_list, "\n") + 1)
-        endwhile
-
-        if fname_cnt == 0
+        let l = filter(copy(s:MRU_files), 'v:val =~ fpat')
+        if len(l) == 0
             echohl WarningMsg
-            echo 'No matching file for ' . a:fspec
+            echo 'Error: No matching file for ' . a:fspec
             echohl None
             return
         endif
 
-        if fname_cnt > 1
+        if len(l) > 1
             echohl WarningMsg
-            echo 'More than one match for ' . a:fspec
+            echo 'Error: More than one match for ' . a:fspec
             echohl None
             return
         endif
 
+        let fname = l[0]
+
         call s:MRU_Edit_File(fname)
     endif
 endfunction
@@ -615,8 +592,8 @@ endfunction
 " MRU_Refresh_Menu()
 " Refresh the MRU menu
 function! s:MRU_Refresh_Menu()
-    if !has('gui_running') || &guioptions !~ 'm'
-        " Not running in GUI mode
+    if !has('menu')
+        " No support for menus
         return
     endif
 
@@ -635,20 +612,10 @@ function! s:MRU_Refresh_Menu()
     anoremenu File.Recent\ Files.-SEP1-           :
 
     " Add the filenames in the MRU list to the menu
-    let flist = s:MRU_files
-    while flist != ''
-        " Extract one filename from the list
-        let fname = strpart(flist, 0, stridx(flist, "\n"))
-        if fname == ''
-            break
-        endif
-
+    for fname in s:MRU_files
         " Escape special characters in the filename
         let esc_fname = escape(fnamemodify(fname, ':t'), ". \\|\t%#")
 
-        " Remove the extracted line from the list
-        let flist = strpart(flist, stridx(flist, "\n") + 1)
-
         " Truncate the directory name if it is long
         let dir_name = fnamemodify(fname, ':h')
         let len = strlen(dir_name)
@@ -664,7 +631,7 @@ function! s:MRU_Refresh_Menu()
         exe 'anoremenu <silent> &File.Recent\ Files.' . esc_fname .
                     \ '\ (' . esc_dir_name . ')' .
                     \ " :call <SID>MRU_Edit_File('" . fname . "')<CR>"
-    endwhile
+    endfor
 
     " Remove the dummy menu entry
     unmenu &File.Recent\ Files.Dummy
@@ -682,8 +649,8 @@ autocmd BufNewFile * call s:MRU_AddFile(expand('<abuf>'))
 autocmd BufWritePost * call s:MRU_AddFile(expand('<abuf>'))
 
 " Command to open the MRU window
-command! -nargs=0 MRU call s:MRU_Open_Window()
-command! -nargs=1 -complete=custom,s:MRU_Edit_Complete MRUedit
+command! -nargs=? MRU call s:MRU_Open_Window(<q-args>)
+command! -nargs=1 -complete=customlist,s:MRU_Edit_Complete MRUedit
             \ call s:MRU_Edit_File_Cmd(<q-args>)
 
 " restore 'cpo'