├── LICENSE ├── README.md └── plugin └── vim-arsync.vim /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-arsync :octopus: 2 | vim plugin for asynchronous synchronisation of remote files and local files using rsync 3 | 4 | ## Main features 5 | - sync up or down project folder using rsync (with compression options etc. -> -avzhe ssh ) 6 | - ignore certains files or folder based on configuration file 7 | - asynchronous operation 8 | - project based configuration file 9 | - auto sync up on file save 10 | - works with ssh-keys (recommended) or plaintext password in config file 11 | 12 | ## Installation 13 | ### Dependencies 14 | - rsync 15 | - *vim8* or *neovim* 16 | - sshpass (optional: only needed when using plaintext password in config file) 17 | 18 | 19 | ### Using vim-plug 20 | Place this in your .vimrc: 21 | 22 | ```vim 23 | Plug 'kenn7/vim-arsync' 24 | 25 | " vim-arsync depedencies 26 | Plug 'prabirshrestha/async.vim' 27 | ``` 28 | ... then run the following in Vim: 29 | 30 | ```vim 31 | :source % 32 | :PlugInstall 33 | ``` 34 | 35 | ### Using Packer 36 | 37 | ```lua 38 | use {'kenn7/vim-arsync', 39 | requires = { 40 | {'prabirshrestha/async.vim'} 41 | } 42 | } 43 | ``` 44 | 45 | ... then run the following in Vim: 46 | 47 | ```vim 48 | :source % 49 | :PackerSync 50 | ``` 51 | 52 | ### Configuration 53 | Create a ```.vim-arsync``` file on the root of your project that contains the following: 54 | 55 | ``` 56 | remote_host example.com 57 | remote_user john 58 | remote_port 22 59 | remote_passwd secret 60 | remote_path ~/temp/ 61 | local_path /home/ken/temp/vuetest/ 62 | ignore_path ["build/","test/"] 63 | ignore_dotfiles 1 64 | auto_sync_up 0 65 | remote_or_local remote 66 | sleep_before_sync 0 67 | ``` 68 | 69 | Required fields are: 70 | - ```remote_host``` remote host to connect (must have ssh enabled) 71 | - ```remote_path``` remote folder to be synced 72 | 73 | Optional fields are: 74 | - ```remote_user``` username to connect with 75 | - ```remote_passwd``` password to connect with (requires sshpass) (needed if not using ssh-keys) 76 | - ```remote_port``` remote ssh port to connect to (default is 22) 77 | - ```local_path``` local folder to be synced (defaults to folder of .vim-arsync) 78 | - ```ignore_path``` list of ingored files/folders 79 | - ```ignore_dotfiles``` set to 1 to not sync dotfiles (e.g. .vim-arsync) 80 | - ```auto_sync_up``` set to 1 for activating automatic upload syncing on file save 81 | - ```remote_or_local``` set to 'local' if you want to perform syncing localy 82 | - ```sleep_before_sync``` set to x seconds if you want to sleep before sync(like compiling a file before syncing) 83 | - ```local_options``` overrides the default rsync options for case where `remote_or_local` is local 84 | - ```remote_options``` overrides the default rsync options for case where `remote_or_local` is remote 85 | 86 | **NOTE:** 87 | - fields can be commented out with ```#``` 88 | - rsync will receive the flags `-varze` for remote syncing and `-var` for local syncing by default. Any flags you set using `rsync_flags` will override these flags. 89 | 90 | ## Usage 91 | If ```auto_sync_up``` is set to 1, the plugin will automatically launch the ```:ARsyncUP``` command 92 | everytime a buffer is saved. 93 | 94 | Setting ```rsync_flags``` to include `-ul`, for example, will use rsync's 'update' feature and will also copy over symlinks. Check out rsync's man page to see all the options it supports. 95 | 96 | ### Commands 97 | 98 | - ```:ARshowConf``` shows detected configuration 99 | - ```:ARsyncUp``` Syncs files up to the remote (upload local to remote) 100 | - ```:ARsyncUpDelete``` Syncs files up to the remote (upload local to remote) 101 | and delete remote files not existing on local (be careful with that) 102 | - ```:ARsyncDown``` Syncs files down from the remote (download remote to local) 103 | 104 | Commands can be mapped to keyboard shortcuts enhance operations 105 | 106 | ## TODO 107 | 108 | - [ ] run more tests 109 | - [ ] deactivate auto sync on error 110 | - [ ] better handle comments in conf file 111 | 112 | ## Acknowledgements 113 | 114 | This plugin was inspired by [vim-hsftp](https://github.com/hesselbom/vim-hsftp) but vim-arsync offers more (rsync, ignore, async...). 115 | 116 | This plugins uses the [async.vim](https://github.com/prabirshrestha/async.vim) library for async operation with vim and neovim. 117 | 118 | ## Similar projects 119 | 120 | - [coffebar/transfer.nvim](https://github.com/coffebar/transfer.nvim) 121 | - [OscarCreator/rsync.nvim](https://github.com/OscarCreator/rsync.nvim) 122 | -------------------------------------------------------------------------------- /plugin/vim-arsync.vim: -------------------------------------------------------------------------------- 1 | " Vim plugin to handle async rsync synchronisation between hosts 2 | " Title: vim-arsync 3 | " Author: Ken Hasselmann 4 | " Date: 08/2019 5 | " License: MIT 6 | 7 | function! LoadConf() 8 | let l:conf_dict = {} 9 | let l:file_exists = filereadable('.vim-arsync') 10 | 11 | if l:file_exists > 0 12 | let l:conf_options = readfile('.vim-arsync') 13 | for i in l:conf_options 14 | let l:var_name = substitute(i[0:stridx(i, ' ')], '^\s*\(.\{-}\)\s*$', '\1', '') 15 | if l:var_name == 'ignore_path' 16 | let l:var_value = eval(substitute(i[stridx(i, ' '):], '^\s*\(.\{-}\)\s*$', '\1', '')) 17 | " echo substitute(i[stridx(i, ' '):], '^\s*\(.\{-}\)\s*$', '\1', '') 18 | elseif l:var_name == 'remote_passwd' 19 | " Do not escape characters in passwords. 20 | let l:var_value = substitute(i[stridx(i, ' '):], '^\s*\(.\{-}\)\s*$', '\1', '') 21 | else 22 | let l:var_value = escape(substitute(i[stridx(i, ' '):], '^\s*\(.\{-}\)\s*$', '\1', ''), '%#!') 23 | endif 24 | let l:conf_dict[l:var_name] = l:var_value 25 | endfor 26 | endif 27 | if !has_key(l:conf_dict, "local_path") 28 | let l:conf_dict['local_path'] = getcwd() 29 | endif 30 | if !has_key(l:conf_dict, "remote_port") 31 | let l:conf_dict['remote_port'] = 22 32 | endif 33 | if !has_key(l:conf_dict, "remote_or_local") 34 | let l:conf_dict['remote_or_local'] = "remote" 35 | endif 36 | if !has_key(l:conf_dict, "local_options") 37 | let l:conf_dict['local_options'] = "-var" 38 | endif 39 | if !has_key(l:conf_dict, "remote_options") 40 | let l:conf_dict['remote_options'] = "-vazre" 41 | endif 42 | return l:conf_dict 43 | endfunction 44 | 45 | function! JobHandler(job_id, data, event_type) 46 | " redraw | echom a:job_id . ' ' . a:event_type 47 | if a:event_type == 'stdout' || a:event_type == 'stderr' 48 | " redraw | echom string(a:data) 49 | if has_key(getqflist({'id' : g:qfid}), 'id') 50 | call setqflist([], 'a', {'id' : g:qfid, 'lines' : a:data}) 51 | endif 52 | elseif a:event_type == 'exit' 53 | if a:data != 0 54 | copen 55 | endif 56 | if a:data == 0 57 | echo "vim-arsync success." 58 | endif 59 | " echom string(a:data) 60 | endif 61 | endfunction 62 | 63 | function! ShowConf() 64 | let l:conf_dict = LoadConf() 65 | echo l:conf_dict 66 | echom string(getqflist()) 67 | endfunction 68 | 69 | function! ARsync(direction) 70 | let l:conf_dict = LoadConf() 71 | if has_key(l:conf_dict, 'remote_host') 72 | let l:user_passwd = '' 73 | if has_key(l:conf_dict, 'remote_user') 74 | let l:user_passwd = l:conf_dict['remote_user'] . '@' 75 | if has_key(l:conf_dict, 'remote_passwd') 76 | if !executable('sshpass') 77 | echoerr 'You need to install sshpass to use plain text password, otherwise please use ssh-key auth.' 78 | return 79 | endif 80 | let sshpass_passwd = l:conf_dict['remote_passwd'] 81 | endif 82 | endif 83 | if l:conf_dict['remote_or_local'] == 'remote' 84 | if a:direction == 'down' 85 | let l:cmd = [ 'rsync', l:conf_dict['remote_options'], 'ssh -p '.l:conf_dict['remote_port'], l:user_passwd . l:conf_dict['remote_host'] . ':' . l:conf_dict['remote_path'] . '/', l:conf_dict['local_path'] . '/'] 86 | elseif a:direction == 'up' 87 | let l:cmd = [ 'rsync', l:conf_dict['remote_options'], 'ssh -p '.l:conf_dict['remote_port'], l:conf_dict['local_path'] . '/', l:user_passwd . l:conf_dict['remote_host'] . ':' . l:conf_dict['remote_path'] . '/'] 88 | else " updelete 89 | let l:cmd = [ 'rsync', l:conf_dict['remote_options'], 'ssh -p '.l:conf_dict['remote_port'], l:conf_dict['local_path'] . '/', l:user_passwd . l:conf_dict['remote_host'] . ':' . l:conf_dict['remote_path'] . '/', '--delete'] 90 | endif 91 | elseif l:conf_dict['remote_or_local'] == 'local' 92 | if a:direction == 'down' 93 | let l:cmd = [ 'rsync', l:conf_dict['local_options'], l:conf_dict['remote_path'] , l:conf_dict['local_path']] 94 | elseif a:direction == 'up' 95 | let l:cmd = [ 'rsync', l:conf_dict['local_options'], l:conf_dict['local_path'] , l:conf_dict['remote_path']] 96 | else " updelete 97 | let l:cmd = [ 'rsync', l:conf_dict['local_options'], l:conf_dict['local_path'] , l:conf_dict['remote_path'] . '/', '--delete'] 98 | endif 99 | endif 100 | if has_key(l:conf_dict, 'ignore_path') 101 | for file in l:conf_dict['ignore_path'] 102 | let l:cmd = l:cmd + ['--exclude', file] 103 | endfor 104 | endif 105 | if has_key(l:conf_dict, 'ignore_dotfiles') 106 | if l:conf_dict['ignore_dotfiles'] == 1 107 | let l:cmd = l:cmd + ['--exclude', '.*'] 108 | endif 109 | endif 110 | if has_key(l:conf_dict, 'remote_passwd') 111 | let l:cmd = ['sshpass', '-p', sshpass_passwd] + l:cmd 112 | endif 113 | 114 | " create qf for job 115 | call setqflist([], ' ', {'title' : 'vim-arsync'}) 116 | let g:qfid = getqflist({'id' : 0}).id 117 | " redraw | echom join(cmd) 118 | let l:job_id = async#job#start(cmd, { 119 | \ 'on_stdout': function('JobHandler'), 120 | \ 'on_stderr': function('JobHandler'), 121 | \ 'on_exit': function('JobHandler'), 122 | \ }) 123 | " TODO: handle errors 124 | else 125 | echoerr 'Could not locate a .vim-arsync configuration file. Aborting...' 126 | endif 127 | endfunction 128 | 129 | function! AutoSync() 130 | let l:conf_dict = LoadConf() 131 | if has_key(l:conf_dict, 'auto_sync_up') 132 | if l:conf_dict['auto_sync_up'] == 1 133 | if has_key(l:conf_dict, 'sleep_before_sync') 134 | let g:sleep_time = l:conf_dict['sleep_before_sync']*1000 135 | autocmd BufWritePost,FileWritePost * call timer_start(g:sleep_time, { -> execute("call ARsync('up')", "")}) 136 | else 137 | autocmd BufWritePost,FileWritePost * ARsyncUp 138 | endif 139 | " echo 'Setting up auto sync to remote' 140 | endif 141 | endif 142 | endfunction 143 | 144 | if !executable('rsync') 145 | echoerr 'You need to install rsync to be able to use the vim-arsync plugin' 146 | finish 147 | endif 148 | 149 | command! ARsyncUp call ARsync('up') 150 | command! ARsyncUpDelete call ARsync('upDelete') 151 | command! ARsyncDown call ARsync('down') 152 | command! ARshowConf call ShowConf() 153 | 154 | augroup vimarsync 155 | autocmd! 156 | autocmd VimEnter * call AutoSync() 157 | autocmd DirChanged * call AutoSync() 158 | augroup END 159 | --------------------------------------------------------------------------------