├── COPYING.CC0 ├── README.md └── plugin └── autoswap.vim /COPYING.CC0: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vim-autoswap 2 | ============ 3 | 4 | Please Vim, stop with these swap file messages. Just switch to the correct window! 5 | 6 | 7 | Why autoswap? 8 | ------------- 9 | 10 | Dealing with swap files is annoying. Most of the time you have to deal with 11 | a swap file because you either have the same file open in another 12 | window or it is a swap file left there by a previous crash. 13 | 14 | This plugin does for you what you would do in these cases: 15 | 16 | 1. Is file already open in another Vim session in some other window? 17 | 2. If so, swap to the window where we are editing that file. 18 | 3. Otherwise, if swapfile is older than file itself, just get rid of it. 19 | 4. Otherwise, open file read-only so we can have a look at it and may save it. 20 | 21 | Damian Conway presented this plugin at OSCON 2013 in his talk 22 | "[More instantly better Vim](http://programming.oreilly.com/2013/10/more-instantly-better-vim.html)". 23 | 24 | The original version of this plugin (only for MacOS) is available at , 25 | together with other plugins presented in the same talk. This version has 26 | been modified to work also on Linux systems. Both Vim and GVim are supported. 27 | 28 | Limitations 29 | ----------- 30 | 31 | At the moment this plugin does not reliably detect files open within tabs in 32 | Apple Terminal and iTerm2 as it matches based on the window name, not tab name. 33 | 34 | 35 | Installation 36 | ------------ 37 | 38 | Copy the `autoswap.vim` file in your `~/.vim/plugin` directory. 39 | 40 | Or use pathogen and just clone the git repository: 41 | 42 | $ cd ~/.vim/bundle 43 | $ git clone https://github.com/gioele/vim-autoswap.git 44 | 45 | Make sure that the `title` option is enabled and the `titlestring` 46 | variable contains the filename and the string `VIM` (the default 47 | `titlestring` will work just fine). To enable the `title` option 48 | set it in your `~/.vimrc` file: 49 | 50 | $ echo 'set title titlestring=' >> ~/.vimrc 51 | 52 | *Linux users*: you must install `wmctrl` to be able to automatically 53 | switch to the Vim window with the open file. 54 | `wmctrl` is already packaged for most distributions. 55 | 56 | *KDE/Konsole users*: in addition to `wmctrl` you must install also 57 | the [`vim-konsole`](https://github.com/gergap/vim-konsole) plugin. 58 | 59 | *tmux users*: if `tmux` is detected, autoswap can change the current 60 | pane to the one where vim is already open. `tmux` support is disabled 61 | by default. To enable support for `tmux` add 62 | `let g:autoswap_detect_tmux = 1` to your `.vimrc`. 63 | 64 | If you use Arch Linux you can install via the [`vim-autoswap-git` 65 | package in the AUR](https://aur.archlinux.org/packages/vim-autoswap-git/). 66 | The package will install this plugin and all the needed dependencies. 67 | 68 | 69 | Authors 70 | ------- 71 | 72 | * Gioele Barabucci (made the plugin Linux-compatible, maintainer) 73 | * Damian Conway (original author) 74 | * Greg Lutostanski (tmux support) 75 | 76 | 77 | Development 78 | ----------- 79 | 80 | Code 81 | : (redirects to GitHub) 82 | 83 | Report issues 84 | : 85 | 86 | 87 | License 88 | ------- 89 | 90 | This is free software released into the public domain (CC0 license). 91 | 92 | See the `COPYING.CC0` file or 93 | for more details. 94 | -------------------------------------------------------------------------------- /plugin/autoswap.vim: -------------------------------------------------------------------------------- 1 | " Vim global plugin for automating response to swapfiles 2 | " Maintainer: Gioele Barabucci 3 | " Author: Damian Conway 4 | " License: This is free software released into the public domain (CC0 license). 5 | 6 | "############################################################# 7 | "## ## 8 | "## Note that this plugin only works if your Vim ## 9 | "## configuration includes: ## 10 | "## ## 11 | "## set title titlestring= ## 12 | "## ## 13 | "## On MacOS this plugin only works fully for Vim sessions ## 14 | "## running in Apple Terminal or iTerm2. Other terminals ## 15 | "## and GUI Vims are partially supported, but detecting ## 16 | "## and switching to the active window will not work. ## 17 | "## ## 18 | "## On Linux this plugin requires the external program ## 19 | "## wmctrl, packaged for most distributions. ## 20 | "## ## 21 | "## See below for the two functions that would have to be ## 22 | "## rewritten to port this plugin to other OS's. ## 23 | "## ## 24 | "############################################################# 25 | 26 | 27 | " If already loaded, we're done... 28 | if exists("loaded_autoswap") 29 | finish 30 | endif 31 | let loaded_autoswap = 1 32 | 33 | " By default we don't try to detect tmux 34 | if !exists("g:autoswap_detect_tmux") 35 | let g:autoswap_detect_tmux = 0 36 | endif 37 | 38 | " Preserve external compatibility options, then enable full vim compatibility... 39 | let s:save_cpo = &cpo 40 | set cpo&vim 41 | 42 | " Invoke the behaviour whenever a swapfile is detected... 43 | " 44 | augroup AutoSwap 45 | autocmd! 46 | autocmd SwapExists * call AS_HandleSwapfile(expand(':p'), v:swapname) 47 | augroup END 48 | 49 | " The automatic behaviour... 50 | " 51 | function! AS_HandleSwapfile (filename, swapname) 52 | 53 | " Is file already open in another Vim session in some other window? 54 | let active_window = AS_DetectActiveWindow(a:filename, a:swapname) 55 | 56 | " If so, go there instead and terminate this attempt to open the file... 57 | if (strlen(active_window) > 0) 58 | call AS_DelayedMsg('Switched to existing session in another window') 59 | call AS_SwitchToActiveWindow(active_window) 60 | let v:swapchoice = 'q' 61 | 62 | " Otherwise, if swapfile is older than file itself, just get rid of it... 63 | elseif getftime(v:swapname) < getftime(a:filename) 64 | call AS_DelayedMsg('Old swapfile detected... and deleted') 65 | call delete(v:swapname) 66 | let v:swapchoice = 'e' 67 | 68 | " Otherwise, open file read-only... 69 | else 70 | call AS_DelayedMsg('Swapfile detected, opening read-only') 71 | let v:swapchoice = 'o' 72 | endif 73 | endfunction 74 | 75 | 76 | " Print a message after the autocommand completes 77 | " (so you can see it, but don't have to hit to continue)... 78 | " 79 | function! AS_DelayedMsg (msg) 80 | " A sneaky way of injecting a message when swapping into the new buffer... 81 | augroup AutoSwap_Msg 82 | autocmd! 83 | " Print the message on finally entering the buffer... 84 | autocmd BufWinEnter * echohl WarningMsg 85 | exec 'autocmd BufWinEnter * echon "\r'.printf("%-60s", a:msg).'"' 86 | autocmd BufWinEnter * echohl NONE 87 | 88 | " And then remove these autocmds, so it's a "one-shot" deal... 89 | autocmd BufWinEnter * augroup AutoSwap_Msg 90 | autocmd BufWinEnter * autocmd! 91 | autocmd BufWinEnter * augroup END 92 | augroup END 93 | endfunction 94 | 95 | 96 | "################################################################# 97 | "## ## 98 | "## To port this plugin to other operating systems ## 99 | "## ## 100 | "## 1. Rewrite the Detect and the Switch function ## 101 | "## 2. Add a new elseif case to the list of OS ## 102 | "## ## 103 | "################################################################# 104 | 105 | function! AS_RunningTmux () 106 | if $TMUX != "" 107 | return 1 108 | endif 109 | return 0 110 | endfunction 111 | 112 | " Return an identifier for a terminal window already editing the named file 113 | " (Should either return a string identifying the active window, 114 | " or else return an empty string to indicate "no active window")... 115 | " 116 | function! AS_DetectActiveWindow (filename, swapname) 117 | if g:autoswap_detect_tmux && AS_RunningTmux() 118 | let active_window = AS_DetectActiveWindow_Tmux(a:swapname) 119 | elseif has('macunix') 120 | let active_window = AS_DetectActiveWindow_Mac(a:filename) 121 | elseif has('unix') 122 | let active_window = AS_DetectActiveWindow_Linux(a:filename) 123 | endif 124 | return active_window 125 | endfunction 126 | 127 | " TMUX: Detection function for tmux, uses tmux 128 | function! AS_DetectActiveWindow_Tmux (swapname) 129 | let pid = systemlist('fuser '.a:swapname.' 2>/dev/null | grep -E -o "[0-9]+"') 130 | if (len(pid) == 0) 131 | return '' 132 | endif 133 | let tty = systemlist('ps -o "tt=" '.pid[0].' 2>/dev/null') 134 | if (len(tty) == 0) 135 | return '' 136 | endif 137 | let tty[0] = substitute(tty[0], '\s\+$', '', '') 138 | " The output of `ps -o tt` and `tmux-list panes` varies from 139 | " system to system. 140 | " * Linux: `pts/1`, `/dev/pts/1` 141 | " * FreeBSD: `1`, `/dev/vc/1` 142 | " * Darwin/macOS: `s001`, `/dev/ttys001` 143 | let window = systemlist('tmux list-panes -aF "#{pane_tty} #{window_index} #{pane_index}" | grep -F "'.tty[0].' " 2>/dev/null') 144 | if (len(window) == 0) 145 | return '' 146 | endif 147 | return window[0] 148 | endfunction 149 | 150 | " LINUX: Detection function for Linux, uses mwctrl 151 | function! AS_DetectActiveWindow_Linux (filename) 152 | let shortname = fnamemodify(a:filename,":t") 153 | let find_win_cmd = 'wmctrl -l | grep -i " '.shortname.' .*vim" | tail -n1 | cut -d" " -f1' 154 | let active_window = system(find_win_cmd) 155 | return (active_window =~ '0x' ? active_window : "") 156 | endfunction 157 | 158 | " MAC: Detection function for Mac OSX, uses osascript 159 | function! AS_DetectActiveWindow_Mac (filename) 160 | let shortname = fnamemodify(a:filename,":t") 161 | if ($TERM_PROGRAM == 'Apple_Terminal') 162 | let find_win_cmd = 'osascript -e ''tell application "Terminal" to get the id of every window whose (name begins with "'.shortname.' " and name contains "VIM")''' 163 | elseif ($TERM_PROGRAM == 'iTerm.app') 164 | let find_win_cmd = 'osascript -e ''tell application "iTerm2" to get the index of every window whose (name contains "'.shortname.' " and name contains "VIM")''' 165 | else 166 | return '' 167 | endif 168 | let active_window = system(find_win_cmd) 169 | let active_window = substitute(active_window, '^\d\+\zs\_.*', '', '') 170 | return (active_window =~ '\d\+' ? active_window : "") 171 | endfunction 172 | 173 | 174 | " Switch to terminal window specified... 175 | " 176 | function! AS_SwitchToActiveWindow (active_window) 177 | if g:autoswap_detect_tmux && AS_RunningTmux() 178 | call AS_SwitchToActiveWindow_Tmux(a:active_window) 179 | elseif has('macunix') 180 | call AS_SwitchToActiveWindow_Mac(a:active_window) 181 | elseif has('unix') 182 | call AS_SwitchToActiveWindow_Linux(a:active_window) 183 | endif 184 | endfunction 185 | 186 | " TMUX: Switch function for Tmux 187 | function! AS_SwitchToActiveWindow_Tmux (active_window) 188 | let pane_info = split(a:active_window) 189 | call system('tmux select-window -t '.pane_info[1].'; tmux select-pane -t '.pane_info[2]) 190 | endfunction 191 | 192 | " LINUX: Switch function for Linux, uses wmctrl 193 | function! AS_SwitchToActiveWindow_Linux (active_window) 194 | call system('wmctrl -i -a "'.a:active_window.'"') 195 | endfunction 196 | 197 | " MAC: Switch function for Mac, uses osascript 198 | function! AS_SwitchToActiveWindow_Mac (active_window) 199 | if ($TERM_PROGRAM == 'Apple_Terminal') 200 | call system('osascript -e ''tell application "Terminal" to set frontmost of window id '.a:active_window.' to true''') 201 | elseif ($TERM_PROGRAM == 'iTerm.app') 202 | let switch_win_cmd = 'osascript -e ''tell application "iTerm"'' 203 | \ -e ''repeat with mywindow in windows'' 204 | \ -e '' if index of mywindow is ' .a:active_window. ''' 205 | \ -e '' select mywindow'' 206 | \ -e '' return'' 207 | \ -e '' end if'' 208 | \ -e '' end repeat'' 209 | \ -e ''end tell''' 210 | call system(switch_win_cmd) 211 | endif 212 | endfunction 213 | 214 | " Restore previous external compatibility options 215 | let &cpo = s:save_cpo 216 | 217 | " vim: noexpandtab tabstop=4 softtabstop=4 shiftwidth=4 218 | --------------------------------------------------------------------------------