├── .github └── workflows │ ├── coverage.yml │ └── unittests.yml ├── .gitignore ├── LICENSE ├── README.md ├── doc └── mru.txt ├── plugin └── mru.vim └── test ├── .coveragerc ├── run_mru_tests.cmd ├── run_mru_tests.sh └── unit_tests.vim /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | on: [push, pull_request] 3 | jobs: 4 | linux: 5 | name: linux 6 | runs-on: ubuntu-22.04 7 | steps: 8 | - name: Checkout Code 9 | uses: actions/checkout@v3 10 | - name: Run Tests 11 | run: | 12 | uname -a 13 | export MRU_PROFILE=1 14 | export VIMPRG=vim 15 | $VIMPRG --version 16 | cd ./test 17 | ./run_mru_tests.sh 18 | - name: Install Python 19 | uses: actions/setup-python@v3 20 | with: 21 | python-version: 3.7.14 22 | - name: Install covimerage 23 | run: | 24 | pip install covimerage 25 | covimerage --version 26 | - name: Run covimerage 27 | run: | 28 | cd ./test 29 | covimerage write_coverage mru_profile.txt 30 | - name: Take coverage 31 | run: | 32 | cd ./test 33 | coverage report 34 | coverage xml 35 | - name: Upload coverage to codecov 36 | uses: codecov/codecov-action@v3 37 | with: 38 | token: ${{ secrets.CODECOV_TOKEN }} 39 | file: ./test/coverage.xml 40 | -------------------------------------------------------------------------------- /.github/workflows/unittests.yml: -------------------------------------------------------------------------------- 1 | name: unit-tests 2 | on: [push, pull_request] 3 | jobs: 4 | linux: 5 | name: linux 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | vim: 10 | - nightly 11 | - v9.0.0000 12 | - v8.2.0000 13 | - v8.0.0000 14 | - v7.4 15 | steps: 16 | - name: Checkout Code 17 | uses: actions/checkout@v3 18 | - name: Setup Vim 19 | uses: rhysd/action-setup-vim@v1 20 | id: vim 21 | with: 22 | version: ${{ matrix.vim }} 23 | - name: Run Tests 24 | run: | 25 | uname -a 26 | export VIMPRG=${{ steps.vim.outputs.executable }} 27 | $VIMPRG --version 28 | cd test 29 | ./run_mru_tests.sh 30 | windows: 31 | name: windows 32 | runs-on: windows-latest 33 | steps: 34 | - uses: actions/checkout@v3 35 | - name: Download Vim 36 | shell: PowerShell 37 | run: Invoke-WebRequest -Uri https://github.com/vim/vim-win32-installer/releases/download/v9.0.0769/gvim_9.0.0769_x64.zip -OutFile vim.zip 38 | - name: Extract vim 39 | shell: PowerShell 40 | run: Expand-Archive -Path vim.zip -DestinationPath $env:USERPROFILE 41 | - name: Run Tests 42 | run: | 43 | $env:PATH = $env:PATH + ';' + $env:USERPROFILE + '\vim\vim90' 44 | Get-ComputerInfo -Property Windows* 45 | vim --version 46 | cd test 47 | .\run_mru_tests.cmd 48 | neovim-linux: 49 | name: neovim-linux 50 | runs-on: ubuntu-latest 51 | steps: 52 | - name: Checkout Code 53 | uses: actions/checkout@v3 54 | - name: Setup Neovim 55 | uses: rhysd/action-setup-vim@v1 56 | id: vim 57 | with: 58 | version: stable 59 | neovim: true 60 | - name: Run Tests 61 | run: | 62 | uname -a 63 | export VIMPRG=${{ steps.vim.outputs.executable }} 64 | $VIMPRG --version 65 | cd test 66 | ./run_mru_tests.sh 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | test/results.txt 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | License: MIT License 2 | Copyright (c) 2003-2022 Yegappan Lakshmanan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to 6 | deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![unit-tests](https://github.com/yegappan/mru/workflows/unit-tests/badge.svg?branch=master) ![Coverage Status](https://codecov.io/gh/yegappan/mru/coverage.svg?branch=master) 2 | 3 | # Most Recently Used (MRU) Vim plugin 4 | 5 | The Most Recently Used (MRU) plugin provides an easy access to a list of 6 | recently opened/edited files in Vim. This plugin automatically stores the 7 | file names as you open/edit them in Vim. 8 | 9 | This plugin works with both Vim and Neovim and will work on all the platforms 10 | where Vim/Neovim are supported. This plugin will work in both console and GUI 11 | Vim. This version of the MRU plugin needs Vim 7.0 and above. 12 | 13 | ## Installation 14 | 15 | You can install this plugin by downloading the .zip or the .tar.gz file for the latest MRU release from the following page: 16 | 17 | https://github.com/yegappan/mru/releases/latest 18 | 19 | For Vim 8.0 and above, you can expand the .zip file in the following directory (on Unix/Linux/MacOS systems): 20 | 21 | $ mkdir -p $HOME/.vim/pack/downloads/start/mru 22 | $ cd $HOME/.vim/pack/downloads/start/mru 23 | $ unzip 24 | 25 | For Vim 7.4 and before, you can use the following steps (on Unix/Linux/MacOS systems): 26 | 27 | $ mkdir $HOME/.vim 28 | $ cd $HOME/.vim 29 | $ unzip 30 | 31 | You can also install this plugin directly from github using the following steps (for Vim 8.0 and above): 32 | 33 | $ mkdir -p $HOME/.vim/pack/downloads/start/mru 34 | $ cd $HOME/.vim/pack/downloads/start 35 | $ git clone https://github.com/yegappan/mru 36 | 37 | For NeoVim: 38 | 39 | $ mkdir -p $HOME/.config/nvim/pack/downloads/start/mru 40 | $ cd $HOME/.config/nvim/pack/downloads/start 41 | $ git clone https://github.com/yegappan/mru 42 | 43 | or you can use any one of the Vim plugin managers ([vim-plug](https://github.com/junegunn/vim-plug), [dein.vim](https://github.com/Shougo/dein.vim), [pathogen](https://github.com/tpope/vim-pathogen), [minpac](https://github.com/k-takata/minpac), [vam](https://github.com/MarcWeber/vim-addon-manager), [volt](https://github.com/vim-volt/volt), [Vundle](https://github.com/VundleVim/Vundle.vim), etc.) to install and manage this plugin. 44 | 45 | ## Usage 46 | After the plugin is installed, it will automatically start to record the names of all the recently used files in the `$HOME/.vim_mru_files` text file. 47 | 48 | To open a file from the recently used file list, enter the following command: 49 | 50 | :MRU 51 | 52 | This will open a temporary window with the list of file names in the MRU list where you can press `` to open a file. 53 | 54 | You can fuzzy search a text in the list of file names, by passing a search text to the `:MRU` command: 55 | 56 | :MRU 57 | 58 | This will open the MRU window with only the file names fuzzy matching the supplied search string. 59 | 60 | The user manual is available at: 61 | https://github.com/yegappan/mru/wiki/User-Manual 62 | -------------------------------------------------------------------------------- /doc/mru.txt: -------------------------------------------------------------------------------- 1 | *mru.txt* Plugin for accessing most recently used files 2 | 3 | Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) 4 | For Vim version 7.0 and above 5 | Last change: October 16, 2022 6 | 7 | ============================================================================== 8 | *mru-license* 9 | License: MIT License 10 | Copyright (c) 2003-2022 Yegappan Lakshmanan 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to 14 | deal in the Software without restriction, including without limitation the 15 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | sell copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 28 | IN THE SOFTWARE. 29 | ============================================================================== 30 | CONTENTS~ 31 | 32 | 1. Overview |mru-overview| 33 | 2. Installation |mru-installation| 34 | 3. Usage |mru-usage| 35 | 4. Configuration |mru-configuration| 36 | 5. FZF Integration |mru-fzf| 37 | 38 | ============================================================================== 39 | 1. Overview *mru-overview* 40 | 41 | The Most Recently Used (MRU) plugin provides an easy access to a list of 42 | recently opened/edited files in Vim. This plugin automatically stores the 43 | file names as you open/edit them in Vim. 44 | 45 | This plugin works with both Vim and Neovim and will work on all the platforms 46 | where Vim/Neovim are supported. This plugin will work in both console and GUI 47 | Vim. This version of the MRU plugin needs Vim 7.0 and above. 48 | 49 | The recently used filenames are stored in a file specified by the Vim 50 | MRU_File variable. 51 | 52 | The Github repository for the MRU plugin is available at: 53 | 54 | https://github.com/yegappan/mru 55 | 56 | ============================================================================== 57 | 2. Installation *mru-installation* 58 | 59 | You can use any one of the Vim plugin managers (dein.vim, pathogen, vam, 60 | vim-plug, volt, Vundle, etc.) to install and manage this plugin. 61 | 62 | Alternatively, you can also manually download and install the plugin 63 | using the following steps. 64 | 65 | 1. Download the mru.zip file from https://github.com/yegappan/mru/releases 66 | 2. Unzip the mru.zip file into the $HOME/.vim directory for Linux/MacOS/Unix 67 | systems or the %HOMEPATH%/vimfiles directory for MS-Windows. After this 68 | step, you should have the following files (the directory structure should 69 | be preserved): 70 | 71 | plugin/mru.vim - MRU plugin 72 | doc/mru.txt - documentation (help) file 73 | 74 | 3. Start Vim and run the ":helptags ALL" command to process the help file. 75 | Without this step, you cannot jump to the MRU help topics. 76 | 4. Restart Vim. 77 | 5. You can use the |:MRU| command to list and edit the recently used files. 78 | In GUI Vim, you can use the 'File->Recent Files' menu to access the 79 | recently used files. 80 | 81 | To uninstall the MRU plugin, either use the uninstall command provided by the 82 | plugin manager or manually remove the plugin/mru.vim, and doc/mru.txt 83 | files from either the $HOME/.vim or $HOME/vimfiles directory. 84 | 85 | You can also install the latest version of the plugin directly from github 86 | using the following steps (in Vim 8.0 and above): > 87 | 88 | $ mkdir -p $HOME/.vim/pack/downloads/start/mru 89 | $ cd $HOME/.vim/pack/downloads/start 90 | $ git clone https://github.com/yegappan/mru.git 91 | < 92 | For Neovim: > 93 | 94 | $ mkdir -p $HOME/.config/nvim/pack/downloads/start/mru 95 | $ cd $HOME/.config/nvim/pack/downloads/start 96 | $ git clone https://github.com/yegappan/mru.git 97 | < 98 | ============================================================================== 99 | 3. Usage *mru-usage* 100 | 101 | *:MRU* 102 | To list and edit files from the Most Recently Used (MRU) list, you can use the 103 | ":MRU" command. The |:MRU| command displays the list of recently used files 104 | in a temporary Vim window. If the MRU window is already opened, then the MRU 105 | list currently displayed in the window is refreshed. 106 | 107 | *:MRUToggle* 108 | Alternatively, you can use the ":MRUToggle" command to toggle (open or close) 109 | the MRU window. If the window is already opened, then running the ":MRUToggle" 110 | command will close the window. 111 | 112 | If you are using GUI Vim, then the names of the recently edited files are 113 | added to the "File->Recent Files" menu. You can select the name of a file 114 | from this sub-menu to edit the file. 115 | 116 | You can use the normal Vim commands to move around in the MRU window. You 117 | cannot make changes in the MRU window. 118 | 119 | In the MRU window, the following keys can be used: 120 | 121 | - open the file under cursor 122 | o - open the file under cursor in a horizontally split window 123 | - idem 124 | O - open the file under cursor in a vertically split window 125 | v - open the file under cursor in read-only mode 126 | t - open the file under cursor in a tab page 127 | p - open the file under cursor in the preview window 128 | u - update (refresh) the MRU list 129 | d - delete the file name under cursor from the MRU list 130 | q - close the MRU window 131 | - idem 132 | 133 | You can select a file name to edit by pressing the key or by double 134 | clicking the left mouse button on a file name. The selected file will be 135 | opened. If the file is already opened in a window, the cursor will be moved 136 | to that window. Otherwise, the file is opened in the previous window. If the 137 | previous window has a modified buffer or is the preview window or is used by 138 | some other plugin, then the file is opened in a new window. 139 | 140 | You can press the 'o' key to open the file name under the cursor in the 141 | MRU window in a new window. You can also press instead of 'o' 142 | to open the file in a new window. 143 | 144 | To open a file from the MRU window in read-only mode (view), press the 'v' 145 | key. 146 | 147 | To open a file from the MRU window in a new tab, press the 't' key. If the 148 | file is already opened in a window in the current or in another tab, then 149 | the cursor is moved to that tab. Otherwise, a new tab is opened. 150 | 151 | You can open multiple files from the MRU window by specifying a count before 152 | pressing '' or 'v' or 'o' or 't'. You can also visually (using 153 | linewise visual mode) select multiple filenames and invoke the commands to 154 | open the files. Each selected file will be opened in a separate window or 155 | tab. 156 | 157 | You can press the 'u' key in the MRU window to update/refresh the file list. 158 | This is useful if you keep the MRU window open always. 159 | 160 | You can press the 'd' key to remove the entry under the cursor in the MRU 161 | window from the MRU list. 162 | 163 | You can close the MRU window by pressing the 'q' key or the key or 164 | using one of the Vim window commands. 165 | 166 | By default, the MRU window is opened as the bottom-most window. If you are 167 | using Vim version 8.0 and above, then you can use command modifiers like 168 | |:topleft| or |:botright| or |:vertical| with the :MRU command to control 169 | where the window is opened. Example: > 170 | 171 | :topleft MRU " horizontally split topmost window 172 | :botright MRU " horizontally split bottommost window 173 | :vertical topleft MRU " vertically split far-left window 174 | :vertical botright MRU " vertically split far-right window 175 | < 176 | By default, the height of the MRU window is 8 or the value specified by the 177 | g:MRU_Window_Height variable. You can pass a count to the :MRU command to use 178 | a different height. Example: > 179 | 180 | :15MRU 181 | :vertical topleft 20MRU 182 | < 183 | To display only files matching a pattern from the MRU list in the MRU window, 184 | you can specify a pattern to the |:MRU| command. Example: > 185 | 186 | :MRU mystr 187 | < 188 | The above command displays only the file names containing the string "mystr" 189 | in them. When you specify a partial file name and only one matching filename 190 | is found, then the |:MRU| command will edit that file. If you are using Vim 191 | version 8.2.1665 and above, then the MRU plugin will use fuzzy matching to get 192 | the list of file names matching the supplied string. 193 | 194 | The |:MRU| command supports command-line completion of file names from 195 | the MRU list. You can enter a partial file name and then press 196 | or to complete or list all the matching file names. Note that 197 | after typing the |:MRU| command, you have to enter a space before completing 198 | the file names with . 199 | 200 | When the search pattern supplied to the |:MRU| command matches only one file, 201 | then the file will be opened in the current window if it contains an 202 | unmodified buffer. Otherwise it will be opened in a new window. You can use 203 | command-line completion to select a file and directly open the file without 204 | opening the MRU window. If you are using Vim version 8.0 and above, you can 205 | use the command modifiers (|:leftabove|, |:rightbelow|, |:vertical|, |:tab|, 206 | etc.) to open the file in a horizontally or vertically split window or a tab 207 | page. Example: > 208 | 209 | :topleft MRU myfile.py " horizontally split topmost window 210 | :botright MRU myfile.py " horizontally split bottommost window 211 | :vertical MRU myfile.py " vertically split window 212 | :vertical topleft MRU myfile.py " vertically split far-left window 213 | :vertical botright MRU myfile.py " vertically split far-right window 214 | :tab MRU myfile.py " new tab page 215 | < 216 | When a file supplied to the |:MRU| command is not present in the MRU list, 217 | but it is a readable file, then the file will be opened (even though it is 218 | not present in the MRU list). This is useful if you want to open a file 219 | present in the same directory as a file in the MRU list. You can use the 220 | command-line completion of the |:MRU| command to complete the full path of a 221 | file and then modify the path to open another file present in the same path. 222 | 223 | Whenever the MRU list changes, the MRU file is updated with the latest MRU 224 | list. When you have multiple instances of Vim running at the same time, the 225 | latest MRU list will show up in all the instances of Vim. 226 | 227 | The MRUFilename syntax group is used to highlight the file names in the MRU 228 | window. By default, this syntax group is linked to the Identifier highlight 229 | group. You can change the highlight group by adding the following line in 230 | your .vimrc: 231 | > 232 | highlight link MRUFileName LineNr 233 | < 234 | The MRU buffer uses the 'mru file type. You can use this file type to add 235 | custom auto commands, syntax highlighting, etc. 236 | 237 | *:MruRefresh* 238 | After using the MRU plugin for a period of time, the MRU list may contain 239 | files which are no longer present in the system. The |:MruRefresh| command can 240 | be used to remove non-existing files from the MRU list. 241 | 242 | *MruGetFiles()* 243 | The MruGetFiles() function can be used to get the current list of file names 244 | in the MRU list as a |List|. This can be used with Ex commands that accept one 245 | or more file names as argument. Some example uses for this function are below: 246 | > 247 | " search for 'my_text' in all the files in the MRU list 248 | :vimgrep my_text `=MruGetFiles()` 249 | " search for 'my_text' in the files ending in .java in the MRU list 250 | :vimgrep my_text `=MruGetFiles('.java')` 251 | " add all the .py files in the MRU list to the argument list 252 | :n `=MruGetFiles('.py')` 253 | " Create a quickfix list with the files in MRU list 254 | :call setqflist([], ' ', {'efm' : '%f', 'lines' : MruGetFiles()}) 255 | < 256 | ============================================================================== 257 | 4. Configuration *mru-configuration* 258 | 259 | The MRU plugin supports many configurable features. These can be enabled or 260 | disabled by setting one or more variables in your .vimrc file using the |:let| 261 | command. For Neovim, set these variables in the $HOME/.config/nvim/init.vim 262 | file. A summary of these variables is below: 263 | 264 | |MRU_File| name of the file containing the MRU list 265 | |MRU_Max_Entries| size of the MRU list 266 | |MRU_Exclude_Files| pattern to exclude files from MRU list 267 | |MRU_Include_Files| pattern to include files in the MRU list 268 | |MRU_Window_Height| height of the MRU window 269 | |MRU_Use_Current_Window| use current window to display MRU list 270 | |MRU_Auto_Close| close the MRU window when a file is selected 271 | |MRU_Window_Open_Always| open the MRU window even for a single file 272 | |MRU_Open_File_Relative| open files using relative paths 273 | |MRU_Open_File_Use_Tabs| open files in separate tab pages 274 | |MRU_FuzzyMatch| use fuzzy match for filtering file names 275 | |MRU_Add_Menu| add MRU files to the "Recent Files" menu 276 | |MRU_Max_Menu_Entries| maximum number of entries in the MRU menu 277 | |MRU_Max_Submenu_Entries| maximum number of entries in the MRU submenu 278 | |MRU_Set_Alternate_File| set the alternate file on plugin startup 279 | |MRU_Filename_Format| patterns to populate and parse file names in 280 | the MRU window 281 | 282 | These variables are described in more detail below. 283 | 284 | *MRU_File* 285 | The list of recently edited file names is stored in the file specified by the 286 | MRU_File variable. The default setting for this variable is 287 | $HOME/.vim_mru_files for Unix-like systems and $USERPROFILE/_vim_mru_files 288 | for MS-Windows systems. You can change this variable to point to a file by 289 | adding the following line to the .vimrc file: 290 | > 291 | let MRU_File = 'd:\myhome\_vim_mru_files' 292 | < 293 | *MRU_Max_Entries* 294 | By default, the plugin will remember the names of the last 100 used files. 295 | As you edit more files, old file names will be removed from the MRU list. 296 | You can set the 'MRU_Max_Entries' variable to remember more file names. For 297 | example, to remember 1000 most recently used file names, you can use 298 | > 299 | let MRU_Max_Entries = 1000 300 | < 301 | *MRU_Exclude_Files* 302 | By default, all the edited file names are added to the MRU list. If you want 303 | to exclude file names matching a pattern, then you can set the 304 | MRU_Exclude_Files variable to a Vim regular expression. If any part of a 305 | file name matches the regular expression, then it is not added to the MRU 306 | list. By default, this variable is set to an empty string. For example, to 307 | not include files in the temporary (/tmp, /var/tmp and D:\temp) directories, 308 | you can set the MRU_Exclude_Files variable to 309 | > 310 | let MRU_Exclude_Files = '^/tmp/.*\|^/var/tmp/.*' " For Unix 311 | let MRU_Exclude_Files = '^D:\\temp\\.*' " For MS-Windows 312 | < 313 | The specified pattern should be a Vim regular expression pattern. Note that 314 | you can specify multiple patterns using '\|'. 315 | 316 | *MRU_Include_Files* 317 | If you want to add only file names matching a pattern to the MRU list, then 318 | you can set the MRU_Include_Files variable. This variable should be set to a 319 | Vim regular expression pattern. If the regular expression matches any part 320 | of a file name, then it is added to the MRU list. For example, to add only 321 | .c and .h files to the MRU list, you can set this variable as below: 322 | > 323 | let MRU_Include_Files = '\.c$\|\.h$' 324 | < 325 | By default, MRU_Include_Files is set to an empty string and all the edited 326 | filenames are added to the MRU list. Note that you can specify multiple 327 | patterns using '\|'. 328 | 329 | *MRU_Window_Height* 330 | The default height of the MRU window is 8. You can set the MRU_Window_Height 331 | variable to change the window height. You can also set the height of the MRU 332 | window by passing a count to the :MRU command. 333 | > 334 | let MRU_Window_Height = 15 335 | < 336 | *MRU_Use_Current_Window* 337 | By default, when the |:MRU| command is invoked, the MRU list will be displayed 338 | in a new window. Instead, if you want the MRU plugin to reuse the current 339 | window, then you can set the 'MRU_Use_Current_Window' variable to one. 340 | > 341 | let MRU_Use_Current_Window = 1 342 | < 343 | The MRU plugin will reuse the current window. When a file name is selected, 344 | the file is also opened in the current window. 345 | 346 | *MRU_Auto_Close* 347 | When you select a file from the MRU window, the MRU window will be 348 | automatically closed and the selected file will be opened in the previous 349 | window. You can set the 'MRU_Auto_Close' variable to zero to keep the MRU 350 | window open. 351 | > 352 | let MRU_Auto_Close = 0 353 | < 354 | *MRU_Window_Open_Always* 355 | When a search pattern is supplied to the :MRU command, the MRU window is 356 | opened if multiple files matching the pattern are found in the MRU list. If 357 | only one matching file is found, instead of opening the MRU window the file is 358 | directly opened. To force open the MRU window always, you can set the 359 | MRU_Window_Open_Always variable to 1. By default this variable is set to 0. 360 | > 361 | let MRU_Window_Open_Always = 1 362 | < 363 | *MRU_Open_File_Relative* 364 | When opening a file from the MRU list, the file is normally opened using the 365 | path shown in the list, which defaults to the full path. To always try and 366 | open files relative to the home directory or current directory, you can set 367 | the MRU_Open_File_Relative variable to 1. By default this is set to 0. 368 | > 369 | let MRU_Open_File_Relative = 1 370 | < 371 | *MRU_Open_File_Use_Tabs* 372 | When opening a file from the MRU list, the file is opened in the current 373 | tab. If the selected file has to be opened in a tab always, then set the 374 | following variable to 1. If the file is already opened in a tab, then the 375 | cursor will be moved to that tab. 376 | > 377 | let MRU_Open_File_Use_Tabs = 1 378 | < 379 | *MRU_FuzzyMatch* 380 | The :MRU command accepts a string that is used to filter the file names 381 | displayed in the MRU window. The MRU command also supports command-line 382 | completion using the supplied string. If Vim supports fuzzy matching 383 | (supported from Vim 8.2.1665), then the :MRU command will fuzzy match the 384 | supplied string against the file names. Otherwise it will use regular 385 | expression matching. To always use regular expression matching, you can set 386 | the MRU_FuzzyMatch variable to 0: 387 | > 388 | let MRU_FuzzyMatch = 0 389 | < 390 | *MRU_Add_Menu* 391 | If you don't use the "File->Recent Files" menu and want to disable it, 392 | then you can set the 'MRU_Add_Menu' variable to zero. By default, the 393 | menu is enabled. 394 | > 395 | let MRU_Add_Menu = 0 396 | < 397 | *MRU_Max_Menu_Entries* 398 | If too many file names are present in the MRU list, then updating the MRU 399 | menu to list all the file names makes Vim slow. To avoid this, the 400 | MRU_Max_Menu_Entries variable controls the number of file names to show in 401 | the MRU menu. By default, this is set to 10. You can change this to show 402 | more entries in the menu. 403 | > 404 | let MRU_Max_Menu_Entries = 20 405 | < 406 | *MRU_Max_Submenu_Entries* 407 | If many file names are present in the MRU list, then the MRU menu is split 408 | into sub-menus. Each sub-menu contains MRU_Max_Submenu_Entries file names. 409 | The default setting for this is 10. You can change this to increase the 410 | number of file names displayed in a single sub-menu: 411 | > 412 | let MRU_Max_Submenu_Entries = 15 413 | < 414 | *MRU_Set_Alternate_File* 415 | When the MRU plugin starts up, if the MRU_Set_Alternate_File variable is set 416 | to 1, then it sets the alternate file (|alternate-file|) to the first file in 417 | the MRU list. You can edit this file using the ":e #" command. By default this 418 | variable is set to 0. You can enable this behavior, by setting the 419 | MRU_Set_Alternate_File variable to 1: 420 | > 421 | let MRU_Set_Alternate_File = 1 422 | < 423 | *MRU_Filename_Format* 424 | In the MRU window, the filenames are displayed in two parts. The first part 425 | contains the file name without the path and the second part contains the 426 | full path to the file in parenthesis. This format is controlled by the 427 | MRU_Filename_Format variable. If you prefer to change this to some other 428 | format, then you can modify the MRU_Filename_Format variable. 429 | 430 | The MRU_Filename_Format variable contains a |Dict| with the following keys: 431 | formatter: a string value containing an expression that specifies how to 432 | split/format the filename. In the expression v:val refers to the 433 | complete path to a file in the MRU list. 434 | parser : a string value containing an regular expression that specifies 435 | how to read the filename back from a line in the MRU window. 436 | syntax : a string value with a regular expression that matches the part to 437 | be highlighted in the MRU window. 438 | 439 | For example, to display the full path of the files without splitting it, you 440 | can set this variable as shown below: 441 | > 442 | let MRU_Filename_Format = { 443 | \ 'formatter':'v:val', 444 | \ 'parser':'.*', 445 | \ 'syntax': '[^/\\]\+$'} 446 | < 447 | ============================================================================== 448 | 5. FZF Integration *mru-fzf* 449 | 450 | You can use the MRU plugin with FZF (command-line fuzzy finder). You can 451 | download and install FZF from https://github.com/junegunn/fzf. 452 | 453 | To select a file from the MRU file list using FZF, run the following command: 454 | > 455 | :FZFMru 456 | < 457 | This will invoke FZF to select a file from the MRU list. With a bang :FZFMru! 458 | the FZF menu will open fullscreen. With 459 | 460 | let MRU_FZF_Preview = 1 461 | 462 | a preview window is shown if the fzf.vim plug-in is installed. 463 | 464 | ============================================================================== 465 | 466 | vim:tw=78:ts=8:noet:ft=help: 467 | -------------------------------------------------------------------------------- /plugin/mru.vim: -------------------------------------------------------------------------------- 1 | " File: mru.vim 2 | " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) 3 | " Version: 3.11 4 | " Last Modified: June 06, 2024 5 | " Copyright: Copyright (C) 2003-2022 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 | 20 | if v:version < 700 21 | " Needs Vim version 7.0 and above 22 | finish 23 | endif 24 | 25 | " Line continuation used here 26 | let s:cpo_save = &cpoptions 27 | set cpoptions&vim 28 | 29 | " MRU configuration variables {{{1 30 | " Maximum number of file names stored in the MRU list 31 | if !exists('MRU_Max_Entries') 32 | let MRU_Max_Entries = 100 33 | endif 34 | 35 | " Files to exclude from the MRU list 36 | if !exists('MRU_Exclude_Files') 37 | let MRU_Exclude_Files = '' 38 | endif 39 | 40 | " Files to include in the MRU list 41 | if !exists('MRU_Include_Files') 42 | let MRU_Include_Files = '' 43 | endif 44 | 45 | " Height of the MRU window 46 | " Default height is 8 47 | if !exists('MRU_Window_Height') 48 | let MRU_Window_Height = 8 49 | endif 50 | 51 | if !exists('MRU_Use_Current_Window') 52 | let MRU_Use_Current_Window = 0 53 | endif 54 | 55 | if !exists('MRU_Auto_Close') 56 | let MRU_Auto_Close = 1 57 | endif 58 | 59 | if !exists("MRU_Open_File_Relative ") 60 | let MRU_Open_File_Relative = 0 61 | endif 62 | 63 | if !exists('g:MRU_File') 64 | if has('unix') || has('macunix') 65 | let s:MRU_File = $HOME . '/.vim_mru_files' 66 | else 67 | let s:MRU_File = $VIM . '/_vim_mru_files' 68 | if has('win32') 69 | " MS-Windows 70 | if !empty($USERPROFILE) 71 | let s:MRU_File = $USERPROFILE . '\_vim_mru_files' 72 | endif 73 | endif 74 | endif 75 | else 76 | let s:MRU_File = expand(g:MRU_File) 77 | endif 78 | 79 | " Option for enabling or disabling the MRU menu 80 | if !exists('MRU_Add_Menu') 81 | let MRU_Add_Menu = 1 82 | endif 83 | 84 | " Maximum number of file names to show in the MRU menu. If too many files are 85 | " listed in the menu, then Vim becomes slow when updating the menu. So set 86 | " this to a low value. 87 | if !exists('MRU_Max_Menu_Entries') 88 | let MRU_Max_Menu_Entries = 10 89 | endif 90 | 91 | " Maximum number of file names to show in a MRU sub-menu. If the MRU list 92 | " contains more file names than this setting, then the MRU menu is split into 93 | " one or more sub-menus. 94 | if !exists('MRU_Max_Submenu_Entries') 95 | let MRU_Max_Submenu_Entries = 10 96 | endif 97 | 98 | " When only a single matching filename is found in the MRU list, the following 99 | " option controls whether the file name is displayed in the MRU window or the 100 | " file is directly opened. When this variable is set to 0 and a single 101 | " matching file name is found, then the file is directly opened. 102 | if !exists('MRU_Window_Open_Always') 103 | let MRU_Window_Open_Always = 0 104 | endif 105 | 106 | " When opening a file from the MRU list, the file is opened in the current 107 | " tab. If the selected file has to be opened in a tab always, then set the 108 | " following variable to 1. If the file is already opened in a tab, then the 109 | " cursor will be moved to that tab. 110 | if !exists('MRU_Open_File_Use_Tabs') 111 | let MRU_Open_File_Use_Tabs = 0 112 | endif 113 | 114 | " Controls whether fuzzy matching is used for matching a user supplied pattern 115 | " against the file names in the MRU list. 116 | if !exists('MRU_FuzzyMatch') 117 | if exists('*matchfuzzy') 118 | " Fuzzy matching is supported only when matchfuzzy() function is present 119 | let MRU_FuzzyMatch = 1 120 | else 121 | let MRU_FuzzyMatch = 0 122 | endif 123 | endif 124 | 125 | if !exists('MRU_FZF_Preview') 126 | let MRU_FZF_Preview = 0 127 | endif 128 | 129 | " Controls whether the alternate file (:help alternate-file) is set when the 130 | " plugin is loaded to the first file in the MRU list. Default is to set the 131 | " alternate file. 132 | if !exists('MRU_Set_Alternate_File') 133 | let MRU_Set_Alternate_File = 0 134 | endif 135 | 136 | " Format of the file names displayed in the MRU window. 137 | " The default is to display the filename followed by the complete path to the 138 | " file in parenthesis. This variable controls the expressions used to format 139 | " and parse the path. This can be changed to display the filenames in a 140 | " different format. The 'formatter' specifies how to split/format the filename 141 | " and 'parser' specifies how to read the filename back; 'syntax' matches the 142 | " part to be highlighted. 143 | if !exists('MRU_Filename_Format') 144 | let MRU_Filename_Format = { 145 | \ 'formatter': 'fnamemodify(v:val, ":t") . " (" . v:val . ")"', 146 | \ 'parser': '(\zs.*\ze)', 147 | \ 'syntax': '^.\{-}\ze(' 148 | \} 149 | endif 150 | 151 | let s:MRU_buf_name = '-RecentFiles-' 152 | 153 | " Control to temporarily lock the MRU list. Used to prevent files from 154 | " getting added to the MRU list when the ':vimgrep' command is executed. 155 | let s:mru_list_locked = 0 156 | 157 | " MRU_LoadList {{{1 158 | " Loads the latest list of file names from the MRU file 159 | func! s:MRU_LoadList() abort 160 | " If the MRU file is present, then load the list of filenames. Otherwise 161 | " start with an empty list. 162 | if filereadable(s:MRU_File) 163 | let s:MRU_files = readfile(s:MRU_File) 164 | if empty(s:MRU_files) 165 | " empty MRU file 166 | let s:MRU_files = [] 167 | elseif s:MRU_files[0] =~# '^\s*" Most recently edited files in Vim' 168 | " Generated by the previous version of the MRU plugin. 169 | " Discard the list. 170 | let s:MRU_files = [] 171 | elseif s:MRU_files[0] =~# '^#' 172 | " Remove the comment line 173 | call remove(s:MRU_files, 0) 174 | else 175 | " Unsupported format 176 | let s:MRU_files = [] 177 | endif 178 | else 179 | let s:MRU_files = [] 180 | endif 181 | 182 | " Refresh the MRU menu with the latest list of filenames 183 | call s:MRU_Refresh_Menu() 184 | endfunc 185 | 186 | " MRU_SaveList {{{1 187 | " Saves the MRU file names to the MRU file 188 | func! s:MRU_SaveList() abort 189 | let l = [] 190 | call add(l, '# Most recently edited files in Vim (version 3.0)') 191 | call extend(l, s:MRU_files) 192 | call writefile(l, s:MRU_File) 193 | endfunc 194 | 195 | " MRU_AddFile {{{1 196 | " Adds a file to the MRU file list 197 | " acmd_bufnr - Buffer number of the file to add 198 | func! s:MRU_AddFile(acmd_bufnr) abort 199 | if s:mru_list_locked 200 | " MRU list is currently locked 201 | return 202 | endif 203 | 204 | " Get the full path to the filename 205 | let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p') 206 | if empty(fname) 207 | return 208 | endif 209 | 210 | " Skip temporary buffers with buftype set. The buftype is set for buffers 211 | " used by plugins. 212 | if !empty(&buftype) 213 | return 214 | endif 215 | 216 | if !empty(g:MRU_Include_Files) 217 | " If MRU_Include_Files is set, include only files matching the 218 | " specified pattern 219 | if fname !~# g:MRU_Include_Files 220 | return 221 | endif 222 | endif 223 | 224 | if !empty(g:MRU_Exclude_Files) 225 | " Do not add files matching the pattern specified in the 226 | " MRU_Exclude_Files to the MRU list 227 | if fname =~# g:MRU_Exclude_Files 228 | return 229 | endif 230 | endif 231 | 232 | " If the filename is not already present in the MRU list and is not 233 | " readable then ignore it 234 | let idx = index(s:MRU_files, fname) 235 | if idx == -1 236 | if !filereadable(fname) 237 | " File is not readable and is not in the MRU list 238 | return 239 | endif 240 | endif 241 | 242 | " Load the latest MRU file list 243 | call s:MRU_LoadList() 244 | 245 | " Remove the new file name from the existing MRU list (if already present) 246 | call filter(s:MRU_files, 'v:val !=# fname') 247 | 248 | " Add the new file list to the beginning of the updated old file list 249 | call insert(s:MRU_files, fname, 0) 250 | 251 | " Trim the list 252 | if len(s:MRU_files) > g:MRU_Max_Entries 253 | call remove(s:MRU_files, g:MRU_Max_Entries, -1) 254 | endif 255 | 256 | " Save the updated MRU list 257 | call s:MRU_SaveList() 258 | 259 | " Refresh the MRU menu 260 | call s:MRU_Refresh_Menu() 261 | 262 | " If the MRU window is open, update the displayed MRU list 263 | let bname = s:MRU_buf_name 264 | let winnum = bufwinnr(bname) 265 | if winnum != -1 266 | let cur_winnr = winnr() 267 | call s:MRU_Open_Window('', '', 0) 268 | if winnr() != cur_winnr 269 | exe cur_winnr . 'wincmd w' 270 | endif 271 | endif 272 | endfunc 273 | 274 | " MRU_escape_filename {{{1 275 | " Escape special characters in a filename. Special characters in file names 276 | " that should be escaped (for security reasons) 277 | let s:esc_filename_chars = ' *?[{`$%#"|!<>();&' . "'\t\n" 278 | func! s:MRU_escape_filename(fname) abort 279 | if exists('*fnameescape') 280 | return fnameescape(a:fname) 281 | else 282 | return escape(a:fname, s:esc_filename_chars) 283 | endif 284 | endfunc 285 | 286 | " MRU_Edit_File {{{1 287 | " Edit the specified file 288 | " filename - Name of the file to edit 289 | " sanitized - Specifies whether the filename is already escaped for special 290 | " characters or not. 291 | " splitdir - command modifier for a split (topleft, belowright, etc.) 292 | " Used by the :MRU command and the "Recent Files" menu item 293 | func! s:MRU_Edit_File(filename, sanitized, splitdir) abort 294 | if !a:sanitized 295 | let esc_fname = s:MRU_escape_filename(a:filename) 296 | else 297 | let esc_fname = a:filename 298 | endif 299 | 300 | " If the user wants to always open the file in a tab, then open the file 301 | " in a tab. If it is already opened in a tab, then the cursor will be 302 | " moved to that tab. 303 | if g:MRU_Open_File_Use_Tabs 304 | call s:MRU_Open_File_In_Tab(a:filename, esc_fname) 305 | return 306 | endif 307 | 308 | " If the file is already open in one of the windows, jump to it 309 | let winnum = bufwinnr('^' . a:filename . '$') 310 | if winnum != -1 311 | if winnum != winnr() 312 | exe winnum . 'wincmd w' 313 | endif 314 | else 315 | if !empty(a:splitdir) || (!&hidden && (&modified || !empty(&buftype) 316 | \ || &previewwindow)) 317 | " If a split command modifier is specified, always open the file 318 | " in a new window. 319 | " Or if the current buffer has unsaved changes or is a special buffer or 320 | " is the preview window. The 'hidden' option is also not set. So open 321 | " the file in a new window. 322 | if bufexists(esc_fname) 323 | exe a:splitdir . ' sbuffer ' . esc_fname 324 | else 325 | exe a:splitdir . ' split ' . esc_fname 326 | endif 327 | else 328 | " The current file can be replaced with the selected file. 329 | if bufexists(esc_fname) 330 | exe 'buffer ' . esc_fname 331 | else 332 | exe 'edit ' . esc_fname 333 | endif 334 | endif 335 | " Make the buffer a listed buffer (in case it was deleted before) 336 | setlocal buflisted 337 | endif 338 | endfunc 339 | 340 | " MRU_Open_File_In_Tab 341 | " Open a file in a tab. If the file is already opened in a tab, jump to the 342 | " tab. Otherwise, create a new tab and open the file. 343 | " fname : Name of the file to open 344 | " esc_fname : File name with special characters escaped 345 | func! s:MRU_Open_File_In_Tab(fname, esc_fname) abort 346 | " If the selected file is already open in the current tab or in 347 | " another tab, jump to it. Otherwise open it in a new tab 348 | if bufwinnr('^' . a:fname . '$') == -1 349 | let tabnum = -1 350 | let i = 1 351 | let bnum = bufnr('^' . a:fname . '$') 352 | while i <= tabpagenr('$') 353 | if index(tabpagebuflist(i), bnum) != -1 354 | let tabnum = i 355 | break 356 | endif 357 | let i += 1 358 | endwhile 359 | 360 | if tabnum != -1 361 | " Goto the tab containing the file 362 | exe 'tabnext ' . i 363 | else 364 | if (winnr('$') == 1) && empty(@%) && !&modified 365 | " Reuse the current tab if it contains a single new unmodified 366 | " file. 367 | if bufexists(a:esc_fname) 368 | exe 'buffer ' . a:esc_fname 369 | else 370 | exe 'edit ' . a:esc_fname 371 | endif 372 | else 373 | " Open a new tab as the last tab page 374 | if v:version >= 800 375 | if bufexists(a:esc_fname) 376 | exe '$tab sbuffer ' . a:esc_fname 377 | else 378 | exe '$tabnew ' . a:esc_fname 379 | endif 380 | else 381 | if bufexists(a:esc_fname) 382 | exe '99999tab sbuffer ' . a:esc_fname 383 | else 384 | exe '99999tabnew ' . a:esc_fname 385 | endif 386 | endif 387 | endif 388 | endif 389 | endif 390 | 391 | " Jump to the window containing the file 392 | let winnum = bufwinnr('^' . a:fname . '$') 393 | if winnum != winnr() 394 | exe winnum . 'wincmd w' 395 | endif 396 | endfunc 397 | 398 | " MRU_Window_Edit_File {{{1 399 | " fname : Name of the file to edit. May specify single or multiple 400 | " files. 401 | " edit_type : Specifies how to edit the file. Can be one of 'edit' or 'view'. 402 | " 'view' - Open the file as a read-only file 403 | " 'edit' - Edit the file as a regular file 404 | " multi : Specifies whether a single file or multiple files need to be 405 | " opened. 406 | " open_type : Specifies where to open the file. 407 | " useopen - If the file is already present in a window, then 408 | " jump to that window. Otherwise, open the file in 409 | " the previous window. 410 | " newwin_horiz - Open the file in a new horizontal window. 411 | " newwin_vert - Open the file in a new vertical window. 412 | " newtab - Open the file in a new tab. If the file is already 413 | " opened in a tab, then jump to that tab. 414 | " preview - Open the file in the preview window 415 | func! s:MRU_Window_Edit_File(fname, multi, edit_type, open_type) abort 416 | let esc_fname = s:MRU_escape_filename(a:fname) 417 | 418 | if a:open_type ==# 'newwin_horiz' 419 | " Edit the file in a new horizontally split window below the previous 420 | " window 421 | wincmd p 422 | if bufexists(esc_fname) 423 | exe 'belowright sbuffer ' . esc_fname 424 | else 425 | exe 'belowright new ' . esc_fname 426 | endif 427 | elseif a:open_type ==# 'newwin_vert' 428 | " Edit the file in a new vertically split window right of the previous 429 | " window 430 | wincmd p 431 | if bufexists(esc_fname) 432 | exe 'vertical belowright sbuffer ' . esc_fname 433 | else 434 | exe 'belowright vnew ' . esc_fname 435 | endif 436 | elseif a:open_type ==# 'newtab' || g:MRU_Open_File_Use_Tabs 437 | call s:MRU_Open_File_In_Tab(a:fname, esc_fname) 438 | elseif a:open_type ==# 'preview' 439 | " Edit the file in the preview window 440 | exe 'topleft pedit ' . esc_fname 441 | else 442 | " If the selected file is already open in one of the windows, 443 | " jump to it 444 | let winnum = bufwinnr('^' . a:fname . '$') 445 | if winnum != -1 && g:MRU_Use_Current_Window == 0 446 | exe winnum . 'wincmd w' 447 | else 448 | if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0 449 | " Jump to the window from which the MRU window was opened 450 | if exists('s:MRU_last_buffer') 451 | let last_winnr = bufwinnr(s:MRU_last_buffer) 452 | if last_winnr != -1 && last_winnr != winnr() 453 | exe last_winnr . 'wincmd w' 454 | endif 455 | endif 456 | else 457 | if g:MRU_Use_Current_Window == 0 458 | " Goto the previous window 459 | " If MRU_Use_Current_Window is set to one, then the 460 | " current window is used to open the file 461 | wincmd p 462 | endif 463 | endif 464 | 465 | let split_window = 0 466 | 467 | if (!&hidden && (&modified || &previewwindow)) || a:multi 468 | " Current buffer has unsaved changes or is the preview window 469 | " or the user is opening multiple files 470 | " So open the file in a new window 471 | let split_window = 1 472 | endif 473 | 474 | if !empty(&buftype) 475 | " Current buffer is a special buffer (maybe used by a plugin) 476 | if g:MRU_Use_Current_Window == 0 || 477 | \ bufnr('%') != bufnr(s:MRU_buf_name) 478 | let split_window = 1 479 | endif 480 | endif 481 | 482 | " Edit the file 483 | if split_window 484 | " Current buffer has unsaved changes or is a special buffer or 485 | " is the preview window. So open the file in a new window 486 | if a:edit_type ==# 'edit' 487 | if bufexists(esc_fname) 488 | exe 'sbuffer ' . esc_fname 489 | else 490 | exe 'split ' . esc_fname 491 | endif 492 | else 493 | exe 'sview ' . esc_fname 494 | endif 495 | else 496 | let mod = '' 497 | if g:MRU_Use_Current_Window 498 | let mod = 'keepalt ' 499 | endif 500 | if a:edit_type ==# 'edit' 501 | if bufexists(esc_fname) 502 | exe mod . 'buffer ' . esc_fname 503 | else 504 | exe mod . 'edit ' . esc_fname 505 | endif 506 | else 507 | exe mod . 'view ' . esc_fname 508 | endif 509 | endif 510 | endif 511 | endif 512 | 513 | " Make the buffer a listed buffer (in case it was deleted before) 514 | setlocal buflisted 515 | endfunc 516 | 517 | " MRU_Select_File_Cmd {{{1 518 | " Open a file selected from the MRU window 519 | " 520 | " 'opt' has two values separated by comma. The first value specifies how to 521 | " edit the file and can be either 'edit' or 'view'. The second value 522 | " specifies where to open the file. It can take one of the following values: 523 | " 'useopen' to open file in the previous window 524 | " 'newwin_horiz' to open the file in a new horizontal split window 525 | " 'newwin_vert' to open the file in a new vertical split window. 526 | " 'newtab' to open the file in a new tab. 527 | " If multiple file names are selected using visual mode, then open multiple 528 | " files (either in split windows or tabs) 529 | func! s:MRU_Select_File_Cmd(opt) range abort 530 | let [edit_type, open_type] = split(a:opt, ',') 531 | 532 | if has('patch-8.2.1978') && mode() ==# 'n' 533 | let l:firstline = line('.') 534 | let l:lastline = l:firstline + v:count 535 | if l:lastline > line('$') 536 | let l:lastline = line('$') 537 | endif 538 | elseif has('patch-8.2.1978') && mode() !=# 'n' 539 | let l:firstline = line('.') 540 | let l:lastline = line('v') 541 | if l:firstline > l:lastline 542 | let [l:firstline, l:lastline] = [l:lastline, l:firstline] 543 | endif 544 | else 545 | let l:firstline = a:firstline 546 | let l:lastline = a:lastline 547 | endif 548 | 549 | let fnames = getline(l:firstline, l:lastline) 550 | 551 | if g:MRU_Auto_Close == 1 && g:MRU_Use_Current_Window == 0 552 | " Automatically close the window if the file window is 553 | " not used to display the MRU list. 554 | silent! close 555 | endif 556 | 557 | let multi = 0 558 | 559 | for f in fnames 560 | if empty(f) 561 | continue 562 | endif 563 | 564 | " The text in the MRU window contains the filename in parenthesis 565 | let file = matchstr(f, g:MRU_Filename_Format.parser) 566 | 567 | if g:MRU_Open_File_Relative == 1 568 | " Open relative to home directory or current directory if possible 569 | let file = fnamemodify(file, ":~:.") 570 | endif 571 | 572 | call s:MRU_Window_Edit_File(file, multi, edit_type, open_type) 573 | 574 | if l:firstline != l:lastline 575 | " Opening multiple files 576 | let multi = 1 577 | endif 578 | endfor 579 | endfunc 580 | 581 | " MRU_Warn_Msg {{{1 582 | " Display a warning message 583 | func! s:MRU_Warn_Msg(msg) abort 584 | echohl WarningMsg 585 | echo a:msg 586 | echohl None 587 | endfunc 588 | 589 | " MRU_Open_Window {{{1 590 | " Display the Most Recently Used file list in a temporary window. 591 | " If the 'pat' argument is not empty, then it specifies the pattern of files 592 | " to selectively display in the MRU window. 593 | " The 'splitdir' argument specifies the location (topleft, belowright, etc.) 594 | " of the MRU window. 595 | func! s:MRU_Open_Window(pat, splitdir, winsz) abort 596 | 597 | " Load the latest MRU file list 598 | call s:MRU_LoadList() 599 | 600 | " Check for empty MRU list 601 | if empty(s:MRU_files) 602 | call s:MRU_Warn_Msg('MRU file list is empty') 603 | return 604 | endif 605 | 606 | " Save the current buffer number. This is used later to open a file when a 607 | " entry is selected from the MRU window. The window number is not saved, 608 | " as the window number will change when new windows are opened. 609 | let s:MRU_last_buffer = bufnr('%') 610 | 611 | let bname = s:MRU_buf_name 612 | 613 | " If the window is already open, jump to it 614 | let winnum = bufwinnr(bname) 615 | if winnum != -1 616 | if winnr() != winnum 617 | " If not already in the window, jump to it 618 | exe winnum . 'wincmd w' 619 | endif 620 | 621 | setlocal modifiable 622 | 623 | " Delete the contents of the buffer to the black-hole register 624 | silent! %delete _ 625 | else 626 | if g:MRU_Use_Current_Window 627 | " Reuse the current window 628 | 629 | " If the current buffer has unsaved changes or is a special buffer 630 | " or is the preview window and 'hidden' is not set, then open a 631 | " new window. Otherwise, open in the current window. 632 | if !&hidden && (&modified || !empty(&buftype) || &previewwindow) 633 | let split_window = 1 634 | else 635 | let split_window = 0 636 | endif 637 | 638 | " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open 639 | " a new buffer 640 | let bufnum = bufnr(bname) 641 | if bufnum == -1 642 | if split_window 643 | let cmd = 'botright split ' . bname 644 | else 645 | let cmd = 'edit ' . bname 646 | endif 647 | else 648 | if split_window 649 | let cmd = 'botright sbuffer ' . bufnum 650 | else 651 | let cmd = 'buffer ' . bufnum 652 | endif 653 | endif 654 | 655 | exe cmd 656 | 657 | if bufnr('%') != bufnr(bname) 658 | " Failed to edit the MRU buffer 659 | return 660 | endif 661 | else 662 | " Open a new window at the bottom 663 | let cmd = 'silent! ' 664 | if empty(a:splitdir) 665 | let cmd .= 'botright ' 666 | else 667 | let cmd .= a:splitdir . ' ' 668 | endif 669 | let sz = a:winsz 670 | if sz == 0 671 | let sz = g:MRU_Window_Height 672 | endif 673 | let cmd .= sz . 'split ' 674 | 675 | " If the __MRU_Files__ buffer exists, then reuse it. Otherwise open 676 | " a new buffer 677 | let bufnum = bufnr(bname) 678 | if bufnum == -1 679 | let cmd .= bname 680 | else 681 | let cmd .= '+buffer' . bufnum 682 | endif 683 | 684 | exe cmd 685 | endif 686 | endif 687 | 688 | setlocal modifiable 689 | 690 | " Mark the buffer as scratch 691 | setlocal buftype=nofile 692 | if g:MRU_Use_Current_Window 693 | " avoid using mru buffer as alternate file 694 | setlocal bufhidden=wipe 695 | else 696 | setlocal bufhidden=delete 697 | endif 698 | setlocal noswapfile 699 | setlocal nobuflisted 700 | setlocal nowrap 701 | setlocal nonumber 702 | if exists('&relativenumber') 703 | setlocal norelativenumber 704 | endif 705 | if exists('&signcolumn') 706 | setlocal signcolumn=no 707 | endif 708 | setlocal foldcolumn=0 709 | " Set the 'filetype' to 'mru'. This allows the user to apply custom 710 | " syntax highlighting or other changes to the MRU bufer. 711 | setlocal filetype=mru 712 | if !g:MRU_Use_Current_Window 713 | " Use fixed height and width for the MRU window 714 | setlocal winfixheight winfixwidth 715 | endif 716 | 717 | " Setup the cpoptions properly for the maps to work 718 | let old_cpoptions = &cpoptions 719 | set cpoptions&vim 720 | 721 | " Create mappings to select and edit a file from the MRU list 722 | let l:cmd = has('patch-8.2.1978') ? '' : ':' 723 | let l:silent = has('patch-8.2.1978') ? '' : ' ' 724 | execute 'nnoremap ' . l:silent . ' ' . 725 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,useopen")' 726 | execute 'vnoremap ' . l:silent . ' ' . 727 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,useopen")' 728 | execute 'nnoremap ' . l:silent . 'o ' . 729 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newwin_horiz")' 730 | execute 'vnoremap ' . l:silent . 'o ' . 731 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newwin_horiz")' 732 | execute 'nnoremap ' . l:silent . ' ' . 733 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newwin_horiz")' 734 | execute 'vnoremap ' . l:silent . ' ' . 735 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newwin_horiz")' 736 | execute 'nnoremap ' . l:silent . 'O ' . 737 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newwin_vert")' 738 | execute 'vnoremap ' . l:silent . 'O ' . 739 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newwin_vert")' 740 | execute 'nnoremap ' . l:silent . 't ' . 741 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newtab")' 742 | execute 'vnoremap ' . l:silent . 't ' . 743 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,newtab")' 744 | execute 'nnoremap ' . l:silent . 'v ' . 745 | \ l:cmd . 'call MRU_Select_File_Cmd("view,useopen")' 746 | execute 'nnoremap ' . l:silent . 'p ' . 747 | \ l:cmd . 'call MRU_Select_File_Cmd("view,preview")' 748 | vnoremap p 749 | \ :if line("'<") == line("'>") 750 | \ call MRU_Select_File_Cmd('open,preview') 751 | \ else 752 | \ echoerr "Only a single file can be previewed" 753 | \ endif 754 | execute 'nnoremap ' . l:silent . 'u ' . l:cmd . 'MRU' 755 | execute 'nnoremap ' . l:silent . '<2-LeftMouse> ' . 756 | \ l:cmd . 'call MRU_Select_File_Cmd("edit,useopen")' 757 | nnoremap d 758 | \ :call MRU_Delete_From_List() 759 | nnoremap q :close 760 | 761 | " Restore the previous cpoptions settings 762 | let &cpoptions = old_cpoptions 763 | 764 | " Display the MRU list 765 | if empty(a:pat) 766 | " No search pattern specified. Display the complete list 767 | let m = copy(s:MRU_files) 768 | else 769 | " Display only the entries matching the specified pattern. First try 770 | " fuzzy matching or as a literal pattern. 771 | if g:MRU_FuzzyMatch 772 | let m = filter(copy(s:MRU_files), '!empty(matchfuzzy([v:val], a:pat))') 773 | else 774 | " do case insensitive file name comparison 775 | let spat = tolower(a:pat) 776 | let m = filter(copy(s:MRU_files), 'stridx(tolower(v:val), spat) != -1') 777 | endif 778 | if len(m) == 0 779 | " No match. Try using it as a regular expression 780 | let m = filter(copy(s:MRU_files), 'v:val =~# a:pat') 781 | endif 782 | endif 783 | 784 | " Get the tail part of the file name (without the directory) and display 785 | " it along with the full path in parenthesis. 786 | let output = map(m, g:MRU_Filename_Format.formatter) 787 | silent! 0put =output 788 | 789 | " Delete the empty line at the end of the buffer 790 | silent! $delete _ 791 | 792 | " Move the cursor to the beginning of the file 793 | normal! gg 794 | 795 | " Add syntax highlighting for the file names 796 | if has_key(g:MRU_Filename_Format, 'syntax') 797 | exe "syntax match MRUFileName '" . g:MRU_Filename_Format.syntax . "'" 798 | highlight default link MRUFileName Identifier 799 | endif 800 | 801 | setlocal nomodifiable 802 | endfunc 803 | 804 | " MRU_Complete {{{1 805 | " Command-line completion function used by :MRU command 806 | func! s:MRU_Complete(ArgLead, CmdLine, CursorPos) abort 807 | " Load the latest MRU file 808 | call s:MRU_LoadList() 809 | 810 | if empty(a:ArgLead) 811 | " Return the complete list of MRU files 812 | return s:MRU_files 813 | else 814 | if g:MRU_FuzzyMatch 815 | " Return only the files fuzzy matching the specified pattern 816 | return filter(copy(s:MRU_files), '!empty(matchfuzzy([v:val], a:ArgLead))') 817 | else 818 | " Return only the files matching the specified pattern 819 | return filter(copy(s:MRU_files), 'v:val =~? a:ArgLead') 820 | endif 821 | endif 822 | endfunc 823 | 824 | " MRU_Cmd {{{1 825 | " Function to handle the MRU command 826 | " pat - File name pattern passed to the MRU command 827 | func! s:MRU_Cmd(pat, splitdir, winsz) abort 828 | if empty(a:pat) 829 | " No arguments specified. Open the MRU window 830 | call s:MRU_Open_Window('', a:splitdir, a:winsz) 831 | return 832 | endif 833 | 834 | " Load the latest MRU file 835 | call s:MRU_LoadList() 836 | 837 | " Empty MRU list 838 | if empty(s:MRU_files) 839 | call s:MRU_Warn_Msg('MRU file list is empty') 840 | return 841 | endif 842 | 843 | " If Vim supports fuzzy matching, then try fuzzy matching the pattern 844 | " against the file names. Otherwise, use the specified string as a literal 845 | " string and search for filenames containing the string. If only one 846 | " filename is found, then edit it (unless the user wants to open the MRU 847 | " window always) 848 | if g:MRU_FuzzyMatch 849 | let m = filter(copy(s:MRU_files), '!empty(matchfuzzy([v:val], a:pat))') 850 | else 851 | " do case insensitive file name comparison 852 | let spat = tolower(a:pat) 853 | let m = filter(copy(s:MRU_files), 'stridx(tolower(v:val), spat) != -1') 854 | endif 855 | if len(m) > 0 856 | if len(m) == 1 && !g:MRU_Window_Open_Always 857 | call s:MRU_Edit_File(m[0], 0, a:splitdir) 858 | return 859 | endif 860 | 861 | " More than one file matches. Try to find an accurate match 862 | let new_m = filter(m, 'v:val ==# a:pat') 863 | if len(new_m) == 1 && !g:MRU_Window_Open_Always 864 | call s:MRU_Edit_File(new_m[0], 0, a:splitdir) 865 | return 866 | endif 867 | 868 | " Couldn't find an exact match, open the MRU window with all the 869 | " files matching the pattern. 870 | call s:MRU_Open_Window(a:pat, a:splitdir, a:winsz) 871 | return 872 | endif 873 | 874 | " Use the specified string as a regular expression pattern and search 875 | " for filenames matching the pattern 876 | let m = filter(copy(s:MRU_files), 'v:val =~? a:pat') 877 | 878 | if len(m) == 0 879 | " If an existing file (not present in the MRU list) is specified, 880 | " then open the file. 881 | if filereadable(a:pat) 882 | call s:MRU_Edit_File(a:pat, 0, a:splitdir) 883 | return 884 | endif 885 | 886 | " No filenames matching the specified pattern are found 887 | call s:MRU_Warn_Msg("MRU file list doesn't contain " . 888 | \ 'files matching ' . a:pat) 889 | return 890 | endif 891 | 892 | if len(m) == 1 && !g:MRU_Window_Open_Always 893 | call s:MRU_Edit_File(m[0], 0, a:splitdir) 894 | return 895 | endif 896 | 897 | call s:MRU_Open_Window(a:pat, a:splitdir, a:winsz) 898 | endfunc 899 | 900 | " MRU_Toggle {{{1 901 | " Toggle MRU 902 | " pat - File name pattern passed to the MRU command 903 | func! s:MRU_Toggle(pat, splitdir) abort 904 | " If the MRU window is open, close it 905 | let winnum = bufwinnr(s:MRU_buf_name) 906 | if winnum != -1 907 | exe winnum . 'wincmd w' 908 | if g:MRU_Use_Current_Window && !empty(expand('#')) 909 | silent! b # 910 | else 911 | silent! close 912 | endif 913 | else 914 | call s:MRU_Cmd(a:pat, a:splitdir, '') 915 | endif 916 | endfunction 917 | 918 | " MRU_add_files_to_menu {{{1 919 | " Adds a list of files to the "Recent Files" sub menu under the "File" menu. 920 | " prefix - Prefix to use for each of the menu entries 921 | " file_list - List of file names to add to the menu 922 | func! s:MRU_add_files_to_menu(prefix, file_list) abort 923 | for fname in a:file_list 924 | " Escape special characters in the filename 925 | let esc_fname = escape(fnamemodify(fname, ':t'), ".\\" . 926 | \ s:esc_filename_chars) 927 | let esc_fname = substitute(esc_fname, '&', '&&', 'g') 928 | 929 | " Truncate the directory name if it is long 930 | let dir_name = fnamemodify(fname, ':h') 931 | if v:version >= 800 || has('patch-7.4.1730') 932 | let len = strchars(dir_name) 933 | " Shorten long file names by adding only few characters from 934 | " the beginning and end. 935 | if len > 30 936 | let dir_name = strcharpart(dir_name, 0, 10) . 937 | \ '...' . 938 | \ strcharpart(dir_name, len - 20) 939 | endif 940 | else 941 | let len = strlen(dir_name) 942 | " Shorten long file names by adding only few characters from 943 | " the beginning and end. 944 | if len > 30 945 | let dir_name = strpart(dir_name, 0, 10) . 946 | \ '...' . 947 | \ strpart(dir_name, len - 20) 948 | endif 949 | endif 950 | let esc_dir_name = escape(dir_name, ".\\" . s:esc_filename_chars) 951 | let esc_dir_name = substitute(esc_dir_name, '&', '&&', 'g') 952 | 953 | let menu_path = '&File.&Recent\ Files.' . a:prefix . esc_fname . 954 | \ '\ (' . esc_dir_name . ')' 955 | let esc_mfname = s:MRU_escape_filename(fname) 956 | exe 'anoremenu ' . menu_path . 957 | \ " :call MRU_Edit_File('" . esc_mfname . "', 1, '')" 958 | exe 'tmenu ' . menu_path . ' Edit file ' . esc_mfname 959 | endfor 960 | endfunc 961 | 962 | " MRU_Refresh_Menu {{{1 963 | " Refresh the MRU menu 964 | func! s:MRU_Refresh_Menu() abort 965 | if !has('menu') || !g:MRU_Add_Menu 966 | " No support for menus 967 | return 968 | endif 969 | 970 | " Setup the cpoptions properly for the maps to work 971 | let old_cpoptions = &cpoptions 972 | set cpoptions&vim 973 | 974 | " Remove the MRU menu 975 | " To retain the teared-off MRU menu, we need to add a dummy entry 976 | silent! unmenu &File.&Recent\ Files 977 | " The menu priority of the File menu is 10. If the MRU plugin runs 978 | " first before menu.vim, the File menu order may not be correct. 979 | " So specify the priority of the File menu here. 980 | 10noremenu &File.&Recent\ Files.Dummy 981 | silent! unmenu! &File.&Recent\ Files 982 | 983 | anoremenu &File.&Recent\ Files.Refresh\ list 984 | \ :call MRU_LoadList() 985 | exe 'tmenu File.&Recent\ Files.Refresh\ list Reload the MRU file list from ' 986 | \ . s:MRU_escape_filename(s:MRU_File) 987 | anoremenu File.&Recent\ Files.-SEP1- : 988 | 989 | " Add the filenames in the MRU list to the menu 990 | let entry_cnt = len(s:MRU_files) 991 | if entry_cnt > g:MRU_Max_Menu_Entries 992 | " Show only MRU_Max_Menu_Entries file names in the menu 993 | let mru_list = s:MRU_files[0 : g:MRU_Max_Menu_Entries - 1] 994 | let entry_cnt = g:MRU_Max_Menu_Entries 995 | else 996 | let mru_list = s:MRU_files 997 | endif 998 | if entry_cnt > g:MRU_Max_Submenu_Entries 999 | " Split the MRU menu into sub-menus 1000 | for start_idx in range(0, entry_cnt, g:MRU_Max_Submenu_Entries) 1001 | let last_idx = start_idx + g:MRU_Max_Submenu_Entries - 1 1002 | if last_idx >= entry_cnt 1003 | let last_idx = entry_cnt - 1 1004 | endif 1005 | let prefix = 'Files\ (' . (start_idx + 1) . '\.\.\.' . 1006 | \ (last_idx + 1) . ').' 1007 | call s:MRU_add_files_to_menu(prefix, 1008 | \ mru_list[start_idx : last_idx]) 1009 | endfor 1010 | else 1011 | call s:MRU_add_files_to_menu('', mru_list) 1012 | endif 1013 | 1014 | " Remove the dummy menu entry 1015 | unmenu &File.&Recent\ Files.Dummy 1016 | 1017 | " Restore the previous cpoptions settings 1018 | let &cpoptions = old_cpoptions 1019 | endfunc 1020 | 1021 | " MRU_Refresh {{{1 1022 | " Remove non-existing files from the MRU list 1023 | func s:MRU_Refresh() 1024 | call filter(s:MRU_files, 'filereadable(v:val)') 1025 | call s:MRU_SaveList() 1026 | call s:MRU_Refresh_Menu() 1027 | endfunc 1028 | 1029 | " MRU_Delete_From_List {{{1 1030 | " remove the entry under cursor in the MRU window from the MRU list 1031 | func s:MRU_Delete_From_List() 1032 | call filter(s:MRU_files, 1033 | \ 'v:val != matchstr(getline("."), g:MRU_Filename_Format.parser)') 1034 | setlocal modifiable 1035 | del _ 1036 | setlocal nomodifiable 1037 | call s:MRU_SaveList() 1038 | call s:MRU_Refresh_Menu() 1039 | endfunc 1040 | 1041 | " Return the list of file names in the MRU list {{{1 1042 | func MruGetFiles(...) 1043 | " Load the latest MRU list 1044 | call s:MRU_LoadList() 1045 | if a:0 == 1 1046 | if g:MRU_FuzzyMatch 1047 | " Return only the files fuzzy matching the specified pattern 1048 | return filter(copy(s:MRU_files), '!empty(matchfuzzy([v:val], a:1))') 1049 | endif 1050 | " Return only the files matching the specified pattern 1051 | return filter(copy(s:MRU_files), 'v:val =~? a:1') 1052 | endif 1053 | return copy(s:MRU_files) 1054 | endfunc 1055 | 1056 | " Load the MRU list on plugin startup 1057 | call s:MRU_LoadList() 1058 | 1059 | " Set the first entry in the MRU list as the alternate file 1060 | " Credit to Martin Roa Villescas (https://github.com/mroavi) for the patch. 1061 | " bufadd() is available starting from Vim 8.1.1610 1062 | if g:MRU_Set_Alternate_File == 1 && 1063 | \ (v:version >= 802 || has('patch-8.1.1610') || has('nvim')) 1064 | if !empty(s:MRU_files) 1065 | let first_mru_file = s:MRU_files[0] 1066 | if filereadable(first_mru_file) 1067 | call bufadd(first_mru_file) 1068 | let @# = first_mru_file 1069 | endif 1070 | endif 1071 | endif 1072 | 1073 | " MRU autocommands {{{1 1074 | " Autocommands to update the most recently used files 1075 | augroup MRUAutoCmds 1076 | au! 1077 | autocmd BufRead * call s:MRU_AddFile(expand('')) 1078 | autocmd BufWritePost * call s:MRU_AddFile(expand('')) 1079 | autocmd BufEnter * call s:MRU_AddFile(expand('')) 1080 | 1081 | " The ':vimgrep' command adds all the files searched to the buffer list. 1082 | " This also modifies the MRU list, even though the user didn't edit the 1083 | " files. Use the following autocmds to prevent this. 1084 | autocmd QuickFixCmdPre *vimgrep* let s:mru_list_locked = 1 1085 | autocmd QuickFixCmdPost *vimgrep* let s:mru_list_locked = 0 1086 | augroup END 1087 | 1088 | " MRU custom commands {{{1 1089 | if v:version >= 800 1090 | command! -nargs=? -complete=customlist,s:MRU_Complete -count=0 MRU 1091 | \ call s:MRU_Cmd(, , ) 1092 | command! -nargs=? -complete=customlist,s:MRU_Complete -count=0 Mru 1093 | \ call s:MRU_Cmd(, , ) 1094 | command! -nargs=? -complete=customlist,s:MRU_Complete MRUToggle 1095 | \ call s:MRU_Toggle(, ) 1096 | else 1097 | command! -nargs=? -complete=customlist,s:MRU_Complete -count=0 MRU 1098 | \ call s:MRU_Cmd(, '', ) 1099 | command! -nargs=? -complete=customlist,s:MRU_Complete -count=0 Mru 1100 | \ call s:MRU_Cmd(, '', ) 1101 | command! -nargs=? -complete=customlist,s:MRU_Complete MRUToggle 1102 | \ call s:MRU_Toggle(, '') 1103 | endif 1104 | command! -nargs=0 MruRefresh call s:MRU_Refresh() 1105 | 1106 | " FZF (fuzzy finder) integration {{{1 1107 | 1108 | func s:MRU_FZF_Run(bang) abort 1109 | if !exists('*fzf#run') 1110 | call s:MRU_Warn_Msg('FZF plugin is not present') 1111 | return 1112 | endif 1113 | 1114 | " Load the latest MRU list 1115 | call s:MRU_LoadList() 1116 | 1117 | let dict = {'source' : s:MRU_files, 1118 | \ 'options' : '--no-sort --prompt="MRU> " ' .. $FZF_DEFAULT_OPTS} 1119 | if g:MRU_FZF_Preview && exists('*fzf#complete') " fzf.vim plugin present 1120 | call fzf#vim#files('', fzf#vim#with_preview(dict), a:bang) 1121 | else 1122 | call fzf#run(fzf#wrap(dict, a:bang)) 1123 | endif 1124 | endfunc 1125 | command! -bang -nargs=0 FZFMru call s:MRU_FZF_Run(0) 1126 | 1127 | " }}} 1128 | 1129 | " restore 'cpoptions' 1130 | let &cpoptions = s:cpo_save 1131 | unlet s:cpo_save 1132 | 1133 | " vim:set sw=2 sts=2 foldenable foldmethod=marker: 1134 | -------------------------------------------------------------------------------- /test/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | plugins = covimerage 3 | data_file = .coverage_covimerage 4 | -------------------------------------------------------------------------------- /test/run_mru_tests.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Script to run the unit-tests for the MRU Vim plugin on MS-Windows 4 | 5 | SETLOCAL 6 | SET VIMPRG="vim.exe" 7 | REM SET VIMPRG="C:\Program Files (x86)\vim\vim82\vim.exe" 8 | REM SET VIMPRG="C:\Program Files (x86)\vim\vim73\vim.exe" 9 | SET VIM_CMD=%VIMPRG% -N -u NONE -U NONE -i NONE 10 | 11 | %VIM_CMD% -S unit_tests.vim 12 | 13 | echo MRU unit test results 14 | type test.log 15 | 16 | findstr /I FAIL test.log > nul 2>&1 17 | if %ERRORLEVEL% EQU 0 echo ERROR: Some test failed. 18 | if %ERRORLEVEL% NEQ 0 echo SUCCESS: All the tests passed. 19 | -------------------------------------------------------------------------------- /test/run_mru_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to run the unit-tests for the MRU Vim plugin 4 | 5 | VIMPRG=${VIMPRG:=/usr/bin/vim} 6 | VIM_CMD="$VIMPRG -N -u NONE -U NONE -i NONE --noplugin" 7 | 8 | rm -f test.log 9 | 10 | $VIM_CMD -S unit_tests.vim 11 | 12 | if [ ! -f test.log ] 13 | then 14 | echo "ERROR: Test results file 'test.log' is not found" 15 | exit 1 16 | fi 17 | 18 | echo "MRU unit test results:" 19 | echo "=====================" 20 | cat test.log 21 | echo 22 | 23 | grep FAIL test.log > /dev/null 2>&1 24 | if [ $? -eq 0 ] 25 | then 26 | echo "ERROR: Some test(s) failed." 27 | exit 1 28 | fi 29 | 30 | echo "SUCCESS: All the tests passed." 31 | exit 0 32 | -------------------------------------------------------------------------------- /test/unit_tests.vim: -------------------------------------------------------------------------------- 1 | " MRU plugin unit-tests 2 | 3 | " MRU plugin settings 4 | let MRU_File='vim_mru_file' 5 | let MRU_Auto_Close=1 6 | let MRU_Max_Entries=10 7 | let MRU_buffer_name = '-RecentFiles-' 8 | 9 | " Set the $MRU_PROFILE environment variable to profile the MRU plugin 10 | let s:do_profile = 0 11 | if exists('$MRU_PROFILE') 12 | let s:do_profile = 1 13 | endif 14 | 15 | " Profile the MRU plugin 16 | if s:do_profile 17 | profile start mru_profile.txt 18 | profile! file */mru.vim 19 | endif 20 | 21 | " Tests assume that 'hidden' option is not set 22 | set nohidden 23 | 24 | source ../plugin/mru.vim 25 | 26 | let s:builtin_assert = 0 27 | if exists('*assert_match') 28 | " Vim supports builtin assert_xxx() functions 29 | let s:builtin_assert = 1 30 | endif 31 | 32 | " Function to log test results 33 | func! LogResult(test, result) 34 | call add(g:results, a:test . ': ' . a:result) 35 | endfunc 36 | 37 | let s:errors = [] 38 | 39 | func! MRU_assert_compare(match, expected, actual, msg) 40 | if a:match 41 | let passed = a:actual =~# a:expected 42 | else 43 | let passed = a:actual ==# a:expected 44 | endif 45 | if !passed 46 | let t = '' 47 | if msg != '' 48 | let t = msg . ': ' 49 | endif 50 | if a:match 51 | let t = t . 'Pattern ' . string(a:expected) . ' does not match ' . 52 | \ string(a:actual) 53 | else 54 | let t = t . 'Expected ' . string(a:expected) . ', but got ' . 55 | \ string(a:actual) 56 | endif 57 | call add(s:errors, t) 58 | endif 59 | endfunc 60 | 61 | func! MRU_assert_equal(expected, actual, ...) 62 | let msg = '' 63 | if a:0 == 1 64 | let msg = a:1 65 | endif 66 | call MRU_assert_compare(0, a:expected, a:actual, msg) 67 | endfunc 68 | 69 | func! MRU_assert_match(expected, actual, ...) 70 | let msg = '' 71 | if a:0 == 1 72 | let msg = a:1 73 | endif 74 | call MRU_assert_compare(1, a:expected, a:actual, msg) 75 | endfunc 76 | 77 | func! MRU_assert_true(result, ...) 78 | let msg = '' 79 | if a:0 == 1 80 | let msg = a:1 81 | endif 82 | if !a:result 83 | let t = '' 84 | if msg != '' 85 | let t = msg . ': ' 86 | endif 87 | let t = t . "Expected 'True' but got " . string(a:result) 88 | call add(s:errors, t) 89 | endif 90 | endfunc 91 | 92 | if s:builtin_assert 93 | " Vim has support for the assert_xxx() functions 94 | let s:Assert_equal = function('assert_equal') 95 | let s:Assert_match = function('assert_match') 96 | let s:Assert_true = function('assert_true') 97 | else 98 | " Vim doesn't have support for the assert_xxx() functions 99 | let s:Assert_equal = function('MRU_assert_equal') 100 | let s:Assert_match = function('MRU_assert_match') 101 | let s:Assert_true = function('MRU_assert_true') 102 | endif 103 | 104 | " ========================================================================== 105 | " Test1 106 | " When the MRU list is empty, invoking the MRU command should return an error 107 | " ========================================================================== 108 | func Test_01() 109 | redir => msg 110 | MRU 111 | redir END 112 | 113 | call s:Assert_match('MRU file list is empty', msg) 114 | endfunc 115 | 116 | " ========================================================================== 117 | " Test2 118 | " Open the MRU window and check the order of files listed in the window 119 | " Open the MRU window when the window is already opened. 120 | " ========================================================================== 121 | func Test_02() 122 | edit file1.txt 123 | edit file2.txt 124 | edit file3.txt 125 | edit file2.txt 126 | edit file1.txt 127 | 128 | MRU 129 | MRU 130 | 131 | let l = getline(1, '$') 132 | call s:Assert_match('file1.txt', l[0]) 133 | call s:Assert_match('file2.txt', l[1]) 134 | call s:Assert_match('file3.txt', l[2]) 135 | endfunc 136 | 137 | " ========================================================================== 138 | " Test3 139 | " Select a file from the MRU window and check whether it is opened 140 | " ========================================================================== 141 | func Test_03() 142 | " Go to the last but one line 143 | $ 144 | 145 | " Select the last file in the MRU window 146 | exe "normal \" 147 | 148 | call s:Assert_equal('file3.txt', expand('%:p:t')) 149 | 150 | " Make sure the MRU window is closed 151 | call s:Assert_equal(-1, bufwinnr(g:MRU_buffer_name)) 152 | endfunc 153 | 154 | " ========================================================================== 155 | " Test4 156 | " MRU opens a selected file in the previous/last window 157 | " ========================================================================== 158 | func Test_04() 159 | " Edit a file and then open a new window, open the MRU window and select the 160 | " file 161 | split file1.txt 162 | only 163 | below new 164 | 165 | MRU 166 | call search('file2.txt') 167 | exe "normal \" 168 | 169 | call s:Assert_equal(2, winnr()) 170 | close 171 | endfunc 172 | 173 | " ========================================================================== 174 | " Test5 175 | " MRU opens a selected file in the same window if the file is already opened 176 | " ========================================================================== 177 | func Test_05() 178 | edit file1.txt 179 | only 180 | below split file2.txt 181 | below split file3.txt 182 | 183 | MRU 184 | call search('file1.txt') 185 | exe "normal \" 186 | 187 | call s:Assert_equal(1, winnr()) 188 | call s:Assert_equal('file1.txt', expand('%:p:t')) 189 | 190 | MRU 191 | call search('file2.txt') 192 | exe "normal \" 193 | call s:Assert_equal(2, winnr()) 194 | call s:Assert_equal('file2.txt', expand('%:p:t')) 195 | 196 | MRU 197 | call search('file3.txt') 198 | exe "normal \" 199 | call s:Assert_equal(3, winnr()) 200 | call s:Assert_equal('file3.txt', expand('%:p:t')) 201 | endfunc 202 | 203 | " ========================================================================== 204 | " Test6 205 | " MRU opens a file selected with 'o' command in a new window 206 | " ========================================================================== 207 | func Test_06() 208 | enew | only 209 | 210 | edit file1.txt 211 | below new 212 | 213 | MRU 214 | normal o 215 | 216 | call s:Assert_equal(3, winnr()) 217 | call s:Assert_equal('file1.txt', expand('%:p:t')) 218 | endfunc 219 | 220 | " ========================================================================== 221 | " Test7 222 | " MRU opens the selected file in a new window if the previous buffer is 223 | " modified. 224 | " ========================================================================== 225 | func Test_07() 226 | enew | only 227 | 228 | call setline(1, ['MRU plugin test']) 229 | MRU 230 | call search('file3.txt') 231 | exe "normal \" 232 | call s:Assert_equal(1, winnr()) 233 | call s:Assert_equal(2, winnr('$')) 234 | call s:Assert_equal('file3.txt', expand('%:p:t')) 235 | 236 | " Discard changes in the new buffer 237 | wincmd b 238 | enew! 239 | only 240 | endfunc 241 | 242 | " ========================================================================== 243 | " Test8 244 | " MRU opens a file selected with 'v' command in read-only mode in the current 245 | " window. 246 | " ========================================================================== 247 | func Test_08() 248 | enew | only 249 | 250 | MRU 251 | call search('file1.txt') 252 | normal v 253 | call s:Assert_true(&readonly) 254 | MRU 255 | call search('file2.txt') 256 | exe "normal \" 257 | call s:Assert_true(!&readonly) 258 | MRU 259 | call search('file1.txt') 260 | exe "normal \" 261 | call s:Assert_true(&readonly) 262 | endfunc 263 | 264 | " ========================================================================== 265 | " Test9 266 | " Use 'O' in the MRU window to open a file in a vertically split window 267 | " ========================================================================== 268 | func Test_09() 269 | enew | only 270 | 271 | edit file1.txt 272 | MRU 273 | call search('file2.txt') 274 | normal O 275 | call s:Assert_equal('file2.txt', @%) 276 | wincmd h 277 | call s:Assert_equal('file1.txt', @%) 278 | wincmd l 279 | call s:Assert_equal('file2.txt', @%) 280 | call s:Assert_equal(2, winnr('$')) 281 | endfunc 282 | 283 | " ========================================================================== 284 | " Test10 285 | " Use 'p' in the MRU window to open a file in the preview window 286 | " ========================================================================== 287 | func Test_10() 288 | enew | only 289 | 290 | MRU 291 | call search('file3.txt') 292 | normal p 293 | wincmd P 294 | let p1 = &previewwindow 295 | let b1 = @% 296 | call s:Assert_equal(2, winnr('$')) 297 | call s:Assert_true(&previewwindow) 298 | call s:Assert_match('file3.txt', @%) 299 | pclose 300 | endfunc 301 | 302 | " ========================================================================== 303 | " Test11 304 | " MRU opens a file selected with 't' command in a new tab and the tab 305 | " is opened at the end 306 | " ========================================================================== 307 | func Test_11() 308 | enew | only 309 | 310 | edit a1.txt 311 | tabnew a2.txt 312 | tabnew a3.txt 313 | tabnew a4.txt 314 | tabfirst 315 | MRU 316 | call search('file3.txt') 317 | normal t 318 | call s:Assert_equal('file3.txt', expand('%:p:t')) 319 | call s:Assert_equal(5, tabpagenr()) 320 | 321 | tabonly 322 | endfunc 323 | 324 | " ========================================================================== 325 | " Test12 326 | " The 'q' command closes the MRU window 327 | " ========================================================================== 328 | func Test_12() 329 | enew | only 330 | 331 | MRU 332 | normal q 333 | call s:Assert_equal(-1, bufwinnr(g:MRU_buffer_name)) 334 | endfunc 335 | 336 | " ========================================================================== 337 | " Test13 338 | " A selected file is opened in a new window if the previous window is a 339 | " preview window 340 | " ========================================================================== 341 | func Test_13() 342 | enew | only 343 | 344 | setlocal previewwindow 345 | MRU 346 | call search('file2.txt') 347 | exe "normal \" 348 | call s:Assert_equal(1, winnr()) 349 | call s:Assert_equal(2, winnr('$')) 350 | call s:Assert_true(!&previewwindow) 351 | call s:Assert_equal('file2.txt', expand('%:p:t')) 352 | 353 | " Close the preview window created by this test 354 | new 355 | only 356 | endfunc 357 | 358 | " ========================================================================== 359 | " Test14 360 | " A selected file is opened in a new window if the previous window contains 361 | " a special buffer (used by some other plugin) 362 | " ========================================================================== 363 | func Test_14() 364 | enew | only 365 | 366 | setlocal buftype=nofile 367 | MRU 368 | call search('file3.txt') 369 | exe "normal \" 370 | call s:Assert_equal(1, winnr()) 371 | call s:Assert_equal(2, winnr('$')) 372 | call s:Assert_equal('', &buftype) 373 | call s:Assert_equal('file3.txt', expand('%:p:t')) 374 | 375 | " Discard the special buffer 376 | enew 377 | endfunc 378 | 379 | " ========================================================================== 380 | " Test15 381 | " If a file selected using the 't' command is already opened in a tab, 382 | " then jump to that tab (instead of opening a new tab) 383 | " ========================================================================== 384 | func Test_15() 385 | enew | only 386 | 387 | " Open the test files in the middle window with empty windows at the top and 388 | " bottom 389 | edit file1.txt 390 | above new 391 | botright new 392 | tabedit file2.txt 393 | above new 394 | botright new 395 | tabedit file3.txt 396 | above new 397 | botright new 398 | tabfirst 399 | 400 | MRU 401 | call search('file3.txt') 402 | exe 'normal t' 403 | call s:Assert_equal(3, tabpagenr()) 404 | call s:Assert_equal('file3.txt', expand('%:p:t')) 405 | call s:Assert_equal(2, winnr()) 406 | 407 | MRU 408 | call search('file1.txt') 409 | exe 'normal t' 410 | call s:Assert_equal(1, tabpagenr()) 411 | call s:Assert_equal('file1.txt', expand('%:p:t')) 412 | call s:Assert_equal(2, winnr()) 413 | 414 | MRU 415 | call search('file2.txt') 416 | exe 'normal t' 417 | call s:Assert_equal(2, tabpagenr()) 418 | call s:Assert_equal('file2.txt', expand('%:p:t')) 419 | call s:Assert_equal(2, winnr()) 420 | 421 | " Close all the other tabs 422 | tabonly 423 | enew 424 | only 425 | endfunc 426 | 427 | " ========================================================================== 428 | " Test16 429 | " Open multiple files from the MRU window using the visual mode and by using a 430 | " count. Each file should be opened in a separate window. 431 | " ========================================================================== 432 | func Test_16() 433 | enew | only 434 | 435 | edit file3.txt 436 | edit file2.txt 437 | edit file1.txt 438 | enew 439 | MRU 440 | exe "normal 3\" 441 | call s:Assert_equal(3, winnr('$')) 442 | call s:Assert_equal(1, bufwinnr('file3.txt')) 443 | call s:Assert_equal(2, bufwinnr('file2.txt')) 444 | call s:Assert_equal(3, bufwinnr('file1.txt')) 445 | 446 | only | enew 447 | 448 | MRU 449 | exe "normal V2j\" 450 | call s:Assert_equal(3, winnr('$')) 451 | call s:Assert_equal(1, bufwinnr('file1.txt')) 452 | call s:Assert_equal(2, bufwinnr('file2.txt')) 453 | call s:Assert_equal(3, bufwinnr('file3.txt')) 454 | endfunc 455 | 456 | " ========================================================================== 457 | " Test17 458 | " When the MRU list is updated, the MRU file also should updated. 459 | " ========================================================================== 460 | func Test_17() 461 | enew | only 462 | 463 | edit file1.txt 464 | let l = readfile(g:MRU_File) 465 | call s:Assert_match('file1.txt', l[1]) 466 | 467 | edit file2.txt 468 | let l = readfile(g:MRU_File) 469 | call s:Assert_match('file2.txt', l[1]) 470 | 471 | edit file3.txt 472 | let l = readfile(g:MRU_File) 473 | call s:Assert_match('file3.txt', l[1]) 474 | endfunc 475 | 476 | " MRU_Test_Add_Files 477 | " Add the supplied List of files to the beginning of the MRU file 478 | func! s:MRU_Test_Add_Files(fnames) 479 | let l = readfile(g:MRU_File) 480 | call extend(l, a:fnames, 1) 481 | call writefile(l, g:MRU_File) 482 | endfunc 483 | 484 | " ========================================================================== 485 | " Test18 486 | " When the MRU file is updated by another Vim instance, the MRU plugin 487 | " should update the MRU list 488 | " ========================================================================== 489 | func Test_18() 490 | enew | only 491 | 492 | call s:MRU_Test_Add_Files(['/software/editors/vim', 493 | \ '/software/editors/emacs', 494 | \ '/software/editors/nano']) 495 | MRU 496 | call s:Assert_equal('vim (/software/editors/vim)', getline(1)) 497 | call s:Assert_equal('emacs (/software/editors/emacs)', getline(2)) 498 | call s:Assert_equal('nano (/software/editors/nano)', getline(3)) 499 | 500 | " Close the MRU window 501 | close 502 | endfunc 503 | 504 | " ========================================================================== 505 | " Test19 506 | " When the MRU file is updated by another Vim instance, the MRU file names 507 | " from the current instance should be merged with that list 508 | " ========================================================================== 509 | func Test_19() 510 | enew | only 511 | 512 | " Remove all the files from the MRU file 513 | let l = readfile(g:MRU_File) 514 | call remove(l, 1, -1) 515 | call writefile(l, g:MRU_File) 516 | edit file1.txt 517 | call s:MRU_Test_Add_Files(['/software/os/unix']) 518 | edit file2.txt 519 | call s:MRU_Test_Add_Files(['/software/os/windows']) 520 | edit file3.txt 521 | call s:MRU_Test_Add_Files(['/software/os/osx']) 522 | MRU 523 | call s:Assert_equal('osx (/software/os/osx)', getline(1)) 524 | call s:Assert_match('file3.txt', getline(2)) 525 | call s:Assert_equal('windows (/software/os/windows)', getline(3)) 526 | call s:Assert_match('file2.txt', getline(4)) 527 | call s:Assert_equal('unix (/software/os/unix)', getline(5)) 528 | call s:Assert_match('file1.txt', getline(6)) 529 | close 530 | endfunc 531 | 532 | " ========================================================================== 533 | " Test20 534 | " When the MRU list has more than g:MRU_Max_Entries, the list should be 535 | " trimmed. The last entries should be removed. 536 | " ========================================================================== 537 | func Test_20() 538 | enew | only 539 | 540 | " Create a MRU list with MRU_Max_Entries 541 | let flist = [] 542 | for i in range(1, g:MRU_Max_Entries) 543 | let flist += ['/usr/share/mru_test/mru_file' . i . '.abc'] 544 | endfor 545 | 546 | " Modify the MRU file to contain max entries 547 | let l = readfile(g:MRU_File) 548 | call remove(l, 1, -1) 549 | call extend(l, flist) 550 | call writefile(l, g:MRU_File) 551 | 552 | enew 553 | edit file1.txt 554 | let l = readfile(g:MRU_File) 555 | call s:Assert_equal((g:MRU_Max_Entries + 1), len(l)) 556 | call s:Assert_equal('/usr/share/mru_test/mru_file9.abc', 557 | \ l[g:MRU_Max_Entries]) 558 | 559 | edit file2.txt 560 | let l = readfile(g:MRU_File) 561 | call s:Assert_equal((g:MRU_Max_Entries + 1), len(l)) 562 | call s:Assert_equal('/usr/share/mru_test/mru_file8.abc', 563 | \ l[g:MRU_Max_Entries]) 564 | 565 | edit file3.txt 566 | let l = readfile(g:MRU_File) 567 | call s:Assert_equal((g:MRU_Max_Entries + 1), len(l)) 568 | call s:Assert_equal('/usr/share/mru_test/mru_file7.abc', 569 | \ l[g:MRU_Max_Entries]) 570 | endfunc 571 | 572 | " ========================================================================== 573 | " Test21 574 | " When an filename (already present in the MRU list) is specified to the MRU 575 | " command, it should edit the file. 576 | " ========================================================================== 577 | func Test_21() 578 | enew | only 579 | edit file1.txt 580 | edit file2.txt 581 | edit file3.txt 582 | enew 583 | MRU file2.txt 584 | call s:Assert_equal('file2.txt', expand('%:p:t')) 585 | call s:Assert_equal(1, winnr('$')) 586 | endfunc 587 | 588 | " ========================================================================== 589 | " Test22 590 | " When a pattern (matching multiple filenames) is specified to the MRU 591 | " command, then the MRU window should be opened with all the matching 592 | " filenames 593 | " ========================================================================== 594 | func Test_22() 595 | enew | only 596 | edit file1.txt 597 | edit file2.txt 598 | edit file3.txt 599 | only 600 | MRU file.* 601 | call s:Assert_equal(g:MRU_buffer_name, @%) 602 | 603 | let l = getline(1, '$') 604 | call s:Assert_match('file3.txt', l[0]) 605 | call s:Assert_match('file2.txt', l[1]) 606 | call s:Assert_match('file1.txt', l[2]) 607 | close 608 | endfunc 609 | 610 | " ========================================================================== 611 | " Test23 612 | " When a partial filename (matching multiple filenames) is specified to the 613 | " MRU command, then the MRU window should be opened with all the matching 614 | " filenames 615 | " ========================================================================== 616 | func Test_23() 617 | enew | only 618 | let g:MRU_FuzzyMatch = 0 619 | edit file1.txt 620 | edit file2.txt 621 | edit file3.txt 622 | only 623 | MRU file 624 | call s:Assert_equal(g:MRU_buffer_name, @%) 625 | let l = getline(1, '$') 626 | call s:Assert_match('file3.txt' , l[0]) 627 | call s:Assert_match('file2.txt' , l[1]) 628 | call s:Assert_match('file1.txt' , l[2]) 629 | close 630 | endfunc 631 | 632 | " ========================================================================== 633 | " Test24 634 | " When a non-existing filename is specified to the MRU command, an error 635 | " message should be displayed. 636 | " ========================================================================== 637 | func Test_24() 638 | let g:MRU_FuzzyMatch = 0 639 | redir => msg 640 | MRU nonexistingfile.txt 641 | redir END 642 | call s:Assert_true(g:MRU_buffer_name !=? @%) 643 | call s:Assert_match("MRU file list doesn't contain files " . 644 | \ 'matching nonexistingfile.txt', msg) 645 | endfunc 646 | 647 | " ========================================================================== 648 | " Test25 649 | " The MRU command should support filename completion. Supply a partial file 650 | " name to the MRU command and complete the filenames. 651 | " ========================================================================== 652 | func Test_25() 653 | enew | only 654 | edit file1.txt 655 | edit file2.txt 656 | edit file3.txt 657 | exe 'normal! :MRU file' . "\" . "\let m='\'\" 658 | let fnames = split(m) 659 | call s:Assert_match('file3.txt', fnames[1]) 660 | call s:Assert_match('file2.txt', fnames[2]) 661 | call s:Assert_match('file1.txt', fnames[3]) 662 | endfunc 663 | 664 | " ========================================================================== 665 | " Test26 666 | " When trying to complete filenames for the MRU command without specifying 667 | " any text should return the entire MRU list. 668 | " ========================================================================== 669 | func Test_26() 670 | enew | only 671 | call delete(g:MRU_File) 672 | edit file1.txt 673 | edit file2.txt 674 | edit file3.txt 675 | exe 'normal! :MRU ' . "\" . "\let m='\'\" 676 | let fnames = split(m) 677 | call s:Assert_match('file3.txt', fnames[1]) 678 | call s:Assert_match('file2.txt', fnames[2]) 679 | call s:Assert_match('file1.txt', fnames[3]) 680 | endfunc 681 | 682 | " ========================================================================== 683 | " Test27 684 | " When the current file/buffer has unsaved changes, MRU should open a selected 685 | " file in a new window (if the 'hidden' option is not set) 686 | " ========================================================================== 687 | func Test_27() 688 | enew | only 689 | edit file1.txt 690 | edit file2.txt 691 | call append(line('$'), 'Temporary changes to buffer') 692 | MRU 693 | call search('file1.txt') 694 | exe "normal \" 695 | call s:Assert_equal(1, winnr()) 696 | call s:Assert_equal(2, winnr('$')) 697 | call s:Assert_equal('file1.txt', expand('%:p:t')) 698 | close 699 | edit! 700 | endfunc 701 | 702 | " ========================================================================== 703 | " Test28 704 | " When the current file/buffer has unsaved changes and the 'hidden' option is 705 | " set, then MRU should open a selected file in the current window 706 | " ========================================================================== 707 | func Test_28() 708 | enew | only 709 | edit file2.txt 710 | edit file1.txt 711 | call append(line('$'), 'Temporary changes to buffer') 712 | set hidden 713 | MRU 714 | call search('file2.txt') 715 | exe "normal \" 716 | call s:Assert_equal(1, winnr('$')) 717 | call s:Assert_equal('file2.txt', expand('%:p:t')) 718 | edit file1.txt 719 | edit! 720 | set nohidden 721 | %bw! 722 | endfunc 723 | 724 | " ========================================================================== 725 | " Test29 726 | " Every edited file is added to the top of the MRU list. If a file is already 727 | " present in the MRU list, then it is moved to the top of the list. 728 | " ========================================================================== 729 | func Test_29() 730 | enew | only 731 | edit file1.txt 732 | let f1 = readfile(g:MRU_File, '', 2) 733 | call s:Assert_match('file1.txt', f1[1]) 734 | edit file2.txt 735 | let f2 = readfile(g:MRU_File, '', 2) 736 | call s:Assert_match('file2.txt', f2[1]) 737 | edit file3.txt 738 | let f3 = readfile(g:MRU_File, '', 2) 739 | call s:Assert_match('file3.txt', f3[1]) 740 | edit file1.txt 741 | let f4 = readfile(g:MRU_File, '', 2) 742 | call s:Assert_match('file1.txt', f4[1]) 743 | endfunc 744 | 745 | " ========================================================================== 746 | " Test30 747 | " Only file names matching the regular expression in the MRU_Include_Files 748 | " variable should be added to the MRU list. 749 | " ========================================================================== 750 | func Test_30() 751 | enew | only 752 | edit file1.txt 753 | let g:MRU_Include_Files='\.c' 754 | edit abc.c 755 | let f1 = readfile(g:MRU_File, '', 2) 756 | call s:Assert_match('abc.c', f1[1]) 757 | edit file1.txt 758 | let f2 = readfile(g:MRU_File, '', 2) 759 | call s:Assert_match('abc.c', f2[1]) 760 | edit def.c 761 | let f3 = readfile(g:MRU_File, '', 2) 762 | call s:Assert_match('def.c', f3[1]) 763 | let g:MRU_Include_Files='' 764 | endfunc 765 | 766 | " ========================================================================== 767 | " Test31 768 | " File names matching the regular expression in the MRU_Exclude_Files 769 | " variable should not be added to the MRU list. 770 | " ========================================================================== 771 | func Test_31() 772 | enew | only 773 | let g:MRU_Exclude_Files='\.txt' 774 | edit abc.c 775 | let f1 = readfile(g:MRU_File, '', 2) 776 | call s:Assert_match('abc.c', f1[1]) 777 | edit file1.txt 778 | edit file2.txt 779 | edit file3.txt 780 | let f2 = readfile(g:MRU_File, '', 2) 781 | call s:Assert_match('abc.c', f2[1]) 782 | edit def.c 783 | let f3 = readfile(g:MRU_File, '', 2) 784 | call s:Assert_match('def.c', f3[1]) 785 | let g:MRU_Exclude_Files='' 786 | edit file1.txt 787 | let f4 = readfile(g:MRU_File, '', 2) 788 | call s:Assert_match('file1.txt', f4[1]) 789 | endfunc 790 | 791 | " ========================================================================== 792 | " Test32 793 | " If the MRU window is open, when adding a file name to the list, the MRU 794 | " window should be refreshed. 795 | " ========================================================================== 796 | func Test_32() 797 | enew | only 798 | MRU 799 | wincmd p 800 | edit abc.c 801 | wincmd p 802 | let s1 = getline(1) 803 | call s:Assert_match('abc.c', s1) 804 | wincmd p 805 | edit file1.txt 806 | wincmd p 807 | let s2 = getline(1) 808 | call s:Assert_match('file1.txt', s2) 809 | close 810 | endfunc 811 | 812 | " ========================================================================== 813 | " Test33 814 | " When MRU_Use_Current_Window is set, the MRU list should be displayed in 815 | " the current window. 816 | " Selecting a file from the MRU window should replace 817 | " the MRU buffer with the selected file. 818 | " ========================================================================== 819 | func Test_33() 820 | enew | only 821 | edit file1.txt 822 | let g:MRU_Use_Current_Window=1 823 | MRU 824 | call s:Assert_equal(1, winnr('$')) 825 | call s:Assert_equal(g:MRU_buffer_name, @%) 826 | let g:MRU_Use_Current_Window=0 827 | endfunc 828 | 829 | " ========================================================================== 830 | " Test34 831 | " When MRU_Use_Current_Window is set, selecting a file from the MRU window 832 | " should replace the MRU buffer with the selected file. 833 | " ========================================================================== 834 | func Test_34() 835 | enew | only 836 | let g:MRU_Use_Current_Window=1 837 | let w:marker=1 838 | MRU 839 | call s:Assert_equal(1, winnr('$')) 840 | call s:Assert_equal(g:MRU_buffer_name, @%) 841 | call search('file2.txt') 842 | exe "normal \" 843 | call s:Assert_equal(1, winnr('$')) 844 | call s:Assert_equal(1, w:marker) 845 | call s:Assert_equal('file2.txt', @%) 846 | unlet w:marker 847 | let g:MRU_Use_Current_Window=0 848 | endfunc 849 | 850 | " ========================================================================== 851 | " Test35 852 | " When MRU_Use_Current_Window is set, if the current buffer has unsaved 853 | " changes, then the MRU window should be opened in a split window 854 | " ========================================================================== 855 | func Test_35() 856 | enew | only 857 | let g:MRU_Use_Current_Window=1 858 | set modified 859 | MRU 860 | call s:Assert_equal(2, winnr('$')) 861 | call s:Assert_equal(2, winnr()) 862 | call s:Assert_equal(g:MRU_buffer_name, @%) 863 | close 864 | set nomodified 865 | let g:MRU_Use_Current_Window=0 866 | enew | only 867 | endfunc 868 | 869 | " ========================================================================== 870 | " Test36 871 | " When MRU_Auto_Close is not set, the MRU window should not automatically 872 | " close when a file is selected. The MRU window should be kept open. 873 | " ========================================================================== 874 | func Test_36() 875 | enew | only 876 | let g:MRU_Auto_Close=0 877 | new 878 | MRU 879 | call search('file1.txt') 880 | exe "normal \" 881 | 2wincmd w 882 | MRU 883 | call search('file2.txt') 884 | exe "normal \" 885 | call s:Assert_equal(3, winnr('$')) 886 | call s:Assert_equal(1, bufwinnr('file1.txt')) 887 | call s:Assert_equal(2, bufwinnr('file2.txt')) 888 | call s:Assert_equal(3, bufwinnr(g:MRU_buffer_name)) 889 | wincmd b 890 | close 891 | let g:MRU_Auto_Close=1 892 | only 893 | endfunc 894 | 895 | " ========================================================================== 896 | " Test37 897 | " When MRU_Open_File_Use_Tabs is set, a selected file should be opened in a 898 | " tab. If the file is already opened in a tab, then the focus should be moved 899 | " to that tab. 900 | " ========================================================================== 901 | func Test_37() 902 | enew | only 903 | let g:MRU_Open_File_Use_Tabs=1 904 | edit file1.txt 905 | MRU 906 | call search('file2.txt') 907 | exe "normal \" 908 | MRU 909 | call search('file3.txt') 910 | exe "normal \" 911 | MRU file1.txt 912 | call s:Assert_equal(1, tabpagenr()) 913 | MRU 914 | call search('file2.txt') 915 | exe "normal \" 916 | call s:Assert_equal(2, tabpagenr()) 917 | MRU 918 | call search('file3.txt') 919 | exe "normal \" 920 | call s:Assert_equal(3, tabpagenr()) 921 | tabonly | enew 922 | let g:MRU_Open_File_Use_Tabs=0 923 | endfunc 924 | 925 | " ========================================================================== 926 | " Test38 927 | " If the MRU_Window_Open_Always is set to 0, when the MRU command finds a 928 | " single matching file name, then it should open the MRU window. If this 929 | " variable is set to 1, then the file should be opened without opening the MRU 930 | " window. 931 | " ========================================================================== 932 | func Test_38() 933 | enew | only 934 | 935 | edit file3.txt 936 | enew 937 | let g:MRU_Window_Open_Always=1 938 | MRU file3.txt 939 | call s:Assert_equal(2, winnr('$')) 940 | call s:Assert_equal(2, bufwinnr(g:MRU_buffer_name)) 941 | close 942 | 943 | enew | only 944 | let g:MRU_Window_Open_Always=0 945 | MRU file3.txt 946 | call s:Assert_equal(1, winnr('$')) 947 | call s:Assert_equal(1, bufwinnr('file3.txt')) 948 | 949 | let g:MRU_Window_Open_Always=0 950 | endfunc 951 | 952 | " ========================================================================== 953 | " Test39 954 | " If the current tabpage is empty, then pressing 't' in the MRU window 955 | " should open the file in the current tabpage. 956 | " ========================================================================== 957 | func Test_39() 958 | enew | only | tabonly 959 | tabnew 960 | tabnew 961 | tabnext 2 962 | MRU 963 | call search('file2.txt') 964 | normal t 965 | call s:Assert_equal('file2.txt', expand('%:p:t')) 966 | call s:Assert_equal(2, tabpagenr()) 967 | tabonly 968 | endfunc 969 | 970 | " ========================================================================== 971 | " Test40 972 | " Pressing 'd' in the MRU window should delete the file under the cursor 973 | " from the MRU list 974 | " ========================================================================== 975 | func Test_40() 976 | edit file2.txt 977 | enew 978 | MRU 979 | call search('file2.txt') 980 | normal d 981 | close 982 | let l = readfile(g:MRU_File) 983 | call s:Assert_true(match(l, 'file2.txt') == -1) 984 | endfunc 985 | 986 | " ========================================================================== 987 | " Test41 988 | " Running the :vimgrep command should not add the files to the MRU list 989 | " ========================================================================== 990 | func Test_41() 991 | call writefile(['bright'], 'dummy1.txt') 992 | call writefile(['bright'], 'dummy2.txt') 993 | vimgrep /bright/j dummy* 994 | let l = readfile(g:MRU_File) 995 | call s:Assert_equal(-1, match(l, 'dummy')) 996 | call delete('dummy1.txt') 997 | call delete('dummy2.txt') 998 | endfunc 999 | 1000 | " ========================================================================== 1001 | " Test42 1002 | " Using a command modifier with the MRU command to open the MRU window 1003 | " ========================================================================== 1004 | func Test_42() 1005 | if v:version < 800 1006 | " The command modifier is supported only by Vim 8.0 and above 1007 | return 1008 | endif 1009 | enew | only 1010 | topleft MRU 1011 | call s:Assert_equal(1, winnr()) 1012 | call s:Assert_equal(2, winnr('$')) 1013 | enew | only 1014 | botright MRU 1015 | call s:Assert_equal(2, winnr()) 1016 | call s:Assert_equal(2, winnr('$')) 1017 | enew | only 1018 | botright MRU 1019 | call s:Assert_equal(2, winnr()) 1020 | call s:Assert_equal(2, winnr('$')) 1021 | enew | only 1022 | endfunc 1023 | 1024 | " ========================================================================== 1025 | " Test43 1026 | " Opening a file using the MRU command should jump to the window containing 1027 | " the file (if it is already opened). 1028 | " ========================================================================== 1029 | func Test_43() 1030 | only 1031 | edit file3.txt 1032 | below split file2.txt 1033 | below split file1.txt 1034 | wincmd t 1035 | MRU file1.txt 1036 | call s:Assert_equal(3, winnr()) 1037 | call s:Assert_equal('file1.txt', expand('%:p:t')) 1038 | MRU file2.txt 1039 | call s:Assert_equal(2, winnr()) 1040 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1041 | MRU file3.txt 1042 | call s:Assert_equal(1, winnr()) 1043 | call s:Assert_equal('file3.txt', expand('%:p:t')) 1044 | enew | only 1045 | endfunc 1046 | 1047 | " ========================================================================== 1048 | " Test44 1049 | " Opening a file using the MRU command should open the file in a new window if 1050 | " the current buffer has unsaved changes. 1051 | " ========================================================================== 1052 | func Test_44() 1053 | only 1054 | set modified 1055 | MRU file2.txt 1056 | call s:Assert_equal(2, winnr('$')) 1057 | call s:Assert_equal(1, winnr()) 1058 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1059 | close 1060 | set nomodified 1061 | endfunc 1062 | 1063 | " ========================================================================== 1064 | " Test45 1065 | " Opening a file from the MRU window using 'v' should open the file in a new 1066 | " window if the current buffer has unsaved changes. 1067 | " ========================================================================== 1068 | func Test_45() 1069 | only 1070 | set modified 1071 | MRU 1072 | call search('file3.txt') 1073 | normal v 1074 | call s:Assert_equal(2, winnr('$')) 1075 | call s:Assert_equal(1, winnr()) 1076 | call s:Assert_equal('file3.txt', expand('%:p:t')) 1077 | call s:Assert_true(&readonly) 1078 | close 1079 | set nomodified 1080 | endfunc 1081 | 1082 | " ========================================================================== 1083 | " Test46 1084 | " Specify a count to the :MRU command to set the MRU window height/width 1085 | " ========================================================================== 1086 | func Test_46() 1087 | only 1088 | " default height is 8 1089 | MRU 1090 | call s:Assert_equal(2, winnr()) 1091 | call s:Assert_equal(8, winheight(0)) 1092 | close 1093 | 1094 | " use a specific height value 1095 | 15MRU 1096 | call s:Assert_equal(2, winnr()) 1097 | call s:Assert_equal(15, winheight(0)) 1098 | close 1099 | 1100 | if v:version >= 800 1101 | " use a specific height value with a command modifier 1102 | topleft 12MRU 1103 | call s:Assert_equal(1, winnr()) 1104 | call s:Assert_equal(12, winheight(0)) 1105 | close 1106 | 1107 | " check for the width (leftmost window) 1108 | vertical topleft 20MRU 1109 | call s:Assert_equal(1, winnr()) 1110 | call s:Assert_equal(20, winwidth(0)) 1111 | close 1112 | 1113 | " check for the width (rightmost window) 1114 | vertical botright 25MRU 1115 | call s:Assert_equal(2, winnr()) 1116 | call s:Assert_equal(25, winwidth(0)) 1117 | close 1118 | endif 1119 | endfunc 1120 | 1121 | " ========================================================================== 1122 | " Test47 1123 | " The height of the MRU window should be MRU_Window_Height 1124 | " ========================================================================== 1125 | func Test_47() 1126 | only 1127 | 1128 | " default height is 8 1129 | MRU 1130 | call s:Assert_equal(8, winheight(0)) 1131 | close 1132 | let g:MRU_Window_Height = 2 1133 | MRU 1134 | call s:Assert_equal(2, winheight(0)) 1135 | close 1136 | let g:MRU_Window_Height = 12 1137 | MRU 1138 | call s:Assert_equal(12, winheight(0)) 1139 | close 1140 | let g:MRU_Window_Height = 8 1141 | endfunc 1142 | 1143 | " ========================================================================== 1144 | " Test48 1145 | " Fuzzy search file names with MRU_FuzzyMatch set to 1. 1146 | " ========================================================================== 1147 | func Test_48() 1148 | if !exists('*matchfuzzy') 1149 | return 1150 | endif 1151 | 1152 | enew | only 1153 | let g:MRU_FuzzyMatch = 1 1154 | MRU F1 1155 | call s:Assert_equal('file1.txt', expand('%:p:t')) 1156 | call s:Assert_equal(1, winnr('$')) 1157 | 1158 | let g:MRU_FuzzyMatch = 0 1159 | redir => msg 1160 | MRU F1 1161 | redir END 1162 | call s:Assert_match("MRU file list doesn't contain files matching F1", msg) 1163 | let g:MRU_FuzzyMatch = 1 1164 | endfunc 1165 | 1166 | " ========================================================================== 1167 | " Test49 1168 | " Test for creating a new file by saving an unnamed buffer. 1169 | " ========================================================================== 1170 | func Test_49() 1171 | enew | only 1172 | call setline(1, 'sample file') 1173 | write sample.txt 1174 | let l = readfile(g:MRU_File) 1175 | call s:Assert_true(match(l, 'sample.txt') != -1) 1176 | call delete('sample.txt') 1177 | bwipe sample.txt 1178 | endfunc 1179 | 1180 | " ========================================================================== 1181 | " Test50 1182 | " Test for the MruGetFiles() function 1183 | " ========================================================================== 1184 | func Test_50() 1185 | enew | only 1186 | let list1 = MruGetFiles() 1187 | let list2 = readfile(g:MRU_File) 1188 | call s:Assert_equal(list2[1:], list1) 1189 | call s:Assert_equal([], MruGetFiles('x1y2z3')) 1190 | endfunc 1191 | 1192 | " ========================================================================== 1193 | " Test51 1194 | " Test for the :MruRefresh command 1195 | " ========================================================================== 1196 | func Test_51() 1197 | enew | only 1198 | call s:Assert_true(match(MruGetFiles(), 'sample.txt') != -1) 1199 | MruRefresh 1200 | call s:Assert_equal(-1, match(MruGetFiles(), 'sample.txt')) 1201 | endfunc 1202 | 1203 | " ========================================================================== 1204 | " Test52 1205 | " Test for the re-opening a deleted buffer from the MRU list 1206 | " ========================================================================== 1207 | func Test_52() 1208 | edit file1.txt 1209 | edit file2.txt 1210 | bd 1211 | " select the file from the MRU window 1212 | MRU 1213 | call search('file2.txt') 1214 | exe "normal \" 1215 | call s:Assert_true(&buflisted) 1216 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1217 | " open the file directly using the command 1218 | bw file1.txt file2.txt 1219 | edit file2.txt 1220 | edit file1.txt 1221 | bd 1222 | MRU file1.txt 1223 | call s:Assert_true(&buflisted) 1224 | call s:Assert_equal('file1.txt', expand('%:p:t')) 1225 | endfunc 1226 | 1227 | " ========================================================================== 1228 | " Test53 1229 | " Test for using a command modifier when directly opening a file using the 1230 | " MRU command. 1231 | " ========================================================================== 1232 | func Test_53() 1233 | if v:version < 800 1234 | return 1235 | endif 1236 | %bw! 1237 | topleft MRU file2.txt 1238 | call s:Assert_equal(2, winnr('$')) 1239 | call s:Assert_equal(1, winnr()) 1240 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1241 | wincmd j 1242 | call s:Assert_equal(2, winnr()) 1243 | %bw 1244 | belowright MRU file2.txt 1245 | call s:Assert_equal(2, winnr('$')) 1246 | call s:Assert_equal(2, winnr()) 1247 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1248 | wincmd k 1249 | call s:Assert_equal(1, winnr()) 1250 | %bw 1251 | vertical topleft MRU file2.txt 1252 | call s:Assert_equal(2, winnr('$')) 1253 | call s:Assert_equal(1, winnr()) 1254 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1255 | wincmd l 1256 | call s:Assert_equal(2, winnr()) 1257 | %bw 1258 | vertical belowright MRU file2.txt 1259 | call s:Assert_equal(2, winnr('$')) 1260 | call s:Assert_equal(2, winnr()) 1261 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1262 | wincmd h 1263 | call s:Assert_equal(1, winnr()) 1264 | %bw 1265 | tab MRU file2.txt 1266 | call s:Assert_equal(2, tabpagenr()) 1267 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1268 | %bw 1269 | endfunc 1270 | 1271 | " ========================================================================== 1272 | " Test54 1273 | " Test for the :MRUToggle command. 1274 | " ========================================================================== 1275 | func Test_54() 1276 | only 1277 | " open the MRU window 1278 | MRUToggle 1279 | call s:Assert_equal(2, bufwinnr(g:MRU_buffer_name)) 1280 | call s:Assert_equal(2, winnr()) 1281 | " close the MRU window 1282 | MRUToggle 1283 | call s:Assert_equal(-1, bufwinnr(g:MRU_buffer_name)) 1284 | call s:Assert_equal(1, winnr()) 1285 | " close the MRU window from some other window 1286 | MRUToggle 1287 | wincmd k 1288 | MRUToggle 1289 | call s:Assert_equal(-1, bufwinnr(g:MRU_buffer_name)) 1290 | call s:Assert_equal(1, winnr()) 1291 | endfunc 1292 | 1293 | " ========================================================================== 1294 | " Test55 1295 | " Editing a file selected from the MRU window should set the current file to 1296 | " be the alternate file. 1297 | " ========================================================================== 1298 | func Test_55() 1299 | silent! bw file1.txt file2.txt file3.txt 1300 | new 1301 | edit file1.txt 1302 | edit file2.txt 1303 | MRU 1304 | call search('file3.txt') 1305 | exe "normal \" 1306 | call s:Assert_equal('file3.txt', expand('%:p:t')) 1307 | call s:Assert_equal('file2.txt', expand('#:p:t')) 1308 | endfunc 1309 | 1310 | " ========================================================================== 1311 | " Test56 1312 | " With MRU_Use_Current_Window set to 1, editing a file from the MRU list 1313 | " should not change the alternate file. 1314 | " ========================================================================== 1315 | func Test_56() 1316 | let g:MRU_Use_Current_Window = 1 1317 | bw file1.txt file2.txt file3.txt 1318 | new 1319 | edit file3.txt 1320 | edit file1.txt 1321 | edit file2.txt 1322 | MRU 1323 | call search('file3.txt') 1324 | exe "normal \" 1325 | call s:Assert_equal('file3.txt', expand('%:p:t')) 1326 | call s:Assert_equal('file2.txt', expand('#:p:t')) 1327 | " try viewing a file 1328 | MRU 1329 | call search('file1.txt') 1330 | normal v 1331 | call s:Assert_equal('file1.txt', expand('%:p:t')) 1332 | call s:Assert_equal('file3.txt', expand('#:p:t')) 1333 | call s:Assert_true(&readonly) 1334 | " try opening a wiped out buffer 1335 | bw file2.txt 1336 | MRU 1337 | call search('file2.txt') 1338 | exe "normal \" 1339 | call s:Assert_equal('file2.txt', expand('%:p:t')) 1340 | call s:Assert_equal('file1.txt', expand('#:p:t')) 1341 | call s:Assert_true(!&readonly) 1342 | let g:MRU_Use_Current_Window = 0 1343 | bw! 1344 | endfunc 1345 | 1346 | " ========================================================================== 1347 | " Test57 1348 | " When the MRU window is closed, the MRU buffer should be unloaded. 1349 | " If 'MRU_Use_Current_Window' is set, then the MRU buffer should be wiped out. 1350 | " ========================================================================== 1351 | func Test_57() 1352 | MRU 1353 | let mrubnum = bufnr('') 1354 | close 1355 | call s:Assert_true(!bufloaded(mrubnum)) 1356 | let g:MRU_Use_Current_Window = 1 1357 | new 1358 | edit Xfile 1359 | MRU 1360 | let mrubnum = bufnr('') 1361 | edit # 1362 | call s:Assert_true(!bufexists(mrubnum)) 1363 | call s:Assert_equal('Xfile', @%) 1364 | let g:MRU_Use_Current_Window = 0 1365 | bw! 1366 | endfunc 1367 | 1368 | " ========================================================================== 1369 | " Test58 1370 | " When the MRU window is toggled with MRU_Use_Current_Window set to 1, the 1371 | " previous buffer should be loaded. 1372 | " ========================================================================== 1373 | func Test_58() 1374 | let g:MRU_Use_Current_Window = 1 1375 | new 1376 | edit Xfile 1377 | MRUToggle 1378 | call s:Assert_equal(g:MRU_buffer_name, @%) 1379 | call s:Assert_equal(2, winnr('$')) 1380 | MRUToggle 1381 | call s:Assert_equal('Xfile', @%) 1382 | call s:Assert_equal(2, winnr('$')) 1383 | let g:MRU_Use_Current_Window = 0 1384 | bw! 1385 | endfunc 1386 | 1387 | " ========================================================================== 1388 | " Test59 1389 | " When the MRU_Set_Alternate_File is set to 1, on plugin startup, the 1390 | " alternate file should be set to the first file in the MRU list. 1391 | " ========================================================================== 1392 | func Test_59() 1393 | if v:version < 802 1394 | return 1395 | endif 1396 | call writefile([], 'Xfirstfile') 1397 | edit Xfirstfile 1398 | call writefile([ 1399 | \ "let MRU_File='vim_mru_file'", 1400 | \ 'let MRU_Set_Alternate_File=1', 1401 | \ 'source ../plugin/mru.vim', 1402 | \ "call writefile([@#], 'Xoutput')" 1403 | \ ], 'Xscript') 1404 | silent! !vim -u NONE --noplugin -i NONE -N -S Xscript -c "qa" 1405 | call s:Assert_true(filereadable('Xoutput')) 1406 | let lines = readfile('Xoutput') 1407 | call s:Assert_true(1, len(lines)) 1408 | call s:Assert_match('Xfirstfile$', lines[0]) 1409 | call delete('Xscript') 1410 | call delete('Xoutput') 1411 | call delete('Xfirstfile') 1412 | endfunc 1413 | 1414 | " ========================================================================== 1415 | " Test60 1416 | " With MRU_Use_Current_Window set to 1, MRU opens a selected file in the 1417 | " current window, even when the file is already open in another window 1418 | " ========================================================================== 1419 | func Test_60() 1420 | let g:MRU_Use_Current_Window = 1 1421 | 1422 | edit file1.txt 1423 | let bnum = bufnr('') 1424 | only 1425 | below split file2.txt 1426 | 1427 | MRU 1428 | call search('file1.txt') 1429 | exe "normal \" 1430 | 1431 | call s:Assert_equal(2, winnr()) 1432 | call s:Assert_equal(bnum, winbufnr(1)) 1433 | call s:Assert_equal(bnum, winbufnr(2)) 1434 | 1435 | let g:MRU_Use_Current_Window = 0 1436 | endfunc 1437 | 1438 | " ========================================================================== 1439 | " Test61 1440 | " The :MRU command should do case-insensitive file name comparison 1441 | " Works only in Unix-like systems. 1442 | " ========================================================================== 1443 | func Test_61() 1444 | if !has('unix') 1445 | return 1446 | endif 1447 | 1448 | let l = readfile(g:MRU_File) 1449 | call remove(l, 1, -1) 1450 | call writefile(l, g:MRU_File) 1451 | call s:MRU_Test_Add_Files(['/my/home/my1298file', 1452 | \ '/my/home/mY1298fIlE', '/my/home/MY1298FILE', '/my/home/My1298File']) 1453 | 1454 | let expected = [ 1455 | \ 'my1298file (/my/home/my1298file)', 1456 | \ 'mY1298fIlE (/my/home/mY1298fIlE)', 1457 | \ 'MY1298FILE (/my/home/MY1298FILE)', 1458 | \ 'My1298File (/my/home/My1298File)' 1459 | \ ] 1460 | 1461 | let g:MRU_FuzzyMatch = 0 1462 | 1463 | try 1464 | for p in ['my12', 'mY1298', 'MY1298', 'My1298File'] 1465 | exe 'MRU ' . p 1466 | let lines = getline(1, '$') 1467 | call s:Assert_equal(expected, lines, p) 1468 | close 1469 | endfor 1470 | finally 1471 | let g:MRU_FuzzyMatch = 1 1472 | endtry 1473 | endfunc 1474 | 1475 | " ========================================================================== 1476 | " Test62 1477 | " When using fuzzy match, the order of the file names in the MRU list should 1478 | " be maintained in the returned list. 1479 | " Works only in Unix-like systems. 1480 | " ========================================================================== 1481 | func Test_62() 1482 | if !has('unix') || !exists('*matchfuzzy') 1483 | return 1484 | endif 1485 | 1486 | let l = readfile(g:MRU_File) 1487 | call remove(l, 1, -1) 1488 | call writefile(l, g:MRU_File) 1489 | call s:MRU_Test_Add_Files(['a111b222c', 'a11b22c', 'abc123', 'a1b2c']) 1490 | 1491 | " Test for command-line expansion 1492 | exe 'normal! :MRU abc' . "\\let m='\'\" 1493 | call s:Assert_equal('MRU a111b222c a11b22c abc123 a1b2c', m) 1494 | 1495 | " Test for MruGetFiles() 1496 | let l = MruGetFiles('abc') 1497 | call s:Assert_equal(['a111b222c', 'a11b22c', 'abc123', 'a1b2c'], l) 1498 | 1499 | " Test for MRU window 1500 | MRU abc 1501 | let l = getline(1, '$') 1502 | call s:Assert_match('a111b222c', l[0]) 1503 | call s:Assert_match('a11b22c', l[1]) 1504 | call s:Assert_match('abc123', l[2]) 1505 | call s:Assert_match('a1b2c', l[3]) 1506 | close 1507 | endfunc 1508 | 1509 | " ========================================================================== 1510 | " Test63 1511 | " With MRU_Open_File_Relative set to 1, MRU opens a selected file relative to 1512 | " the current working directory (or home directory, but that's hard to test) 1513 | " ========================================================================== 1514 | func Test_63() 1515 | let g:MRU_Open_File_Relative = 1 1516 | edit file1.txt 1517 | edit file2.txt 1518 | bwipe file1.txt 1519 | MRU 1520 | call search('file1.txt') 1521 | exe "normal \" 1522 | call s:Assert_equal('file1.txt', expand('%')) 1523 | let g:MRU_Open_File_Relative = 0 1524 | endfunc 1525 | 1526 | " ========================================================================== 1527 | 1528 | " Create the files used by the tests 1529 | call writefile(['MRU test file1'], 'file1.txt') 1530 | call writefile(['MRU test file2'], 'file2.txt') 1531 | call writefile(['MRU test file3'], 'file3.txt') 1532 | 1533 | call writefile(['#include