sponsor Vim development Vim logo Vim Book Ad

DuplicateWrite : Cascade the writing of a file to another location.

 script karma  Rating 1/1, Downloaded by 1975  Comments, bugs, improvements  Vim wiki

created by
Ingo Karkat
script type
Though you should use scripts for automated deployment and version control for
merges, sometimes, you need to quickly duplicate a file to another file system
location whenever it is changed.
This plugin defines a :DuplicateWrite command that sets up additional
:write targets. From then on, whenever you save that buffer, the write is
cascaded to the additional files. Thus, when editing a script in your project
directory, you can have it immediately (on only on demand, with [!]) copied to
the install directory that is in the PATH. Or, with the help of the netrw
plugin, you can even automatically upload a locally edited HTML page to the
remote web server.

The plugin hooks into the BufWritePost event to issue additional :write

- The FileSync plugin (vimscript #5064) can automatically sync files or
  directory trees on write, using a Vim command like !cp, netrw plugin, or
  custom function.
- The mirror.vim plugin (vimscript #5204) needs a mirror configuration, and
  then provides custom commands to open, diff, push, etc. mirrored files.

:DuplicateWrite[!] [++opt] [+cmd] [-cmd] {file}|{dirspec} [...]
                        Create a cascaded write of the current buffer to the
                        specified {file}, or to a file with the same filename
                        located in {dirspec}. From now on, whenever the buffer
                        is |:w|ritten, it will also be persisted to the passed
                        location. (Until you :bdelete it.)
                        With [!], duplication only happens with forced
                        :write!, not with :write. This is useful if the
                        duplication target is on a slow networked filesystem
                        or if a file write triggers other costly actions
                        (like a service restart after a config update).
                        [++opt] is passed to :write. An optional [+cmd] is
                        executed before the write; likewise, [-cmd] is
                        executed after the write; the degenerate [-] will
                        :undo any changes to the buffer done by [+cmd].
                        In the {cmd}s, spaces and also special characters
                        (cmdline-special) like % and <cword> must be
                        escaped. The plugin supports a special <tfile>
                        identifer that gets replaced with the duplicated
                        target file.

                        You can issue the command multiple times (with
                        different {file} targets) for a buffer to add cascades
                        to several concurrent locations.

:DuplicateWriteOff      Turn off all cascaded writes for the current buffer.

:DuplicateWriteList     List the cascaded write target(s) for the current

:DuplicateWriteListAll  List the cascaded write target(s) for all open
                        buffers that have any. The buffers are listed with
                        their number followed by the name; the targets are
                        listed in the following, indented lines, for example:
                        4  "DuplicateWrite.txt" ->
install details
The code is hosted in a Git repo at
You can use your favorite plugin manager, or "git clone" into a directory used
for Vim packages. Releases are on the "stable" branch, the latest unstable
development snapshot on "master".

This script is also packaged as a vimball. If you have the "gunzip"
decompressor in your PATH, simply edit the *.vmb.gz package in Vim; otherwise,
decompress the archive first, e.g. using WinZip. Inside Vim, install by
sourcing the vimball or via the :UseVimball command.
    vim DuplicateWrite*.vmb.gz
    :so %
To uninstall, use the :RmVimball command.

- Requires Vim 7.0 or higher.
- Requires the ingo-library.vim plugin (vimscript #4433), version 1.025 or

For a permanent configuration, put the following commands into your vimrc:

To avoid giving an argument to :DuplicateWrite, you can define a List of
{source-glob}, {argument-object} pairs: The part of the buffer's filespec that
matches {source-glob} will then be replaced by {argument-object}.pathspec to
yield the target:
    let g:DuplicateWrite_DefaultMirrors = [
    \   ['D:\project\foo', {'pathspec': 'X:\foo'}],
    \   ['**\src\**', {
    \                   'pathspec': 'E:\deploy',
    \                   'bang': 0,
    \                   'opt': '++ff=dos',
    \                   'preCmd': '%s/Copyright: \zsXXXX/Acme Corp/e,
    \                   'postCmd': 'UNDO'
    \                 }]
This would for example duplicate a file D:\project\foo\bin\zap.cmd to
X:\foo\bin\zap.cmd and any file anywhere inside a src/ directory directly to
E:\deploy when you execute :DuplicateWrite. A buffer-local configuration
overrides the global one. All matching {source-glob} are processed, so if you
need to duplicate to multiple locations, define several same {source-glob}s.

The duplicate writes themselves also trigger |autocmd|s; we need this nesting
to let plugins like netrw interfere and handle special (remote) filesystem
locations. However, other plugins may also be triggered, and that may be
undesirable (for example, you don't want to trigger syntax checking on the
duplicates, or add them to a MRU list in Vim). Because of this, the plugin
ignores certain events (via 'eventignore') during its execution:
    let g:DuplicateWrite_EventIgnore = 'BufWritePre,BufWritePost'

Especially when using default mirrors, the target directory for the duplicated
write may not exist yet. The following variable defines the plugin's behavior
in that case; either "no", "yes", or "ask":
    let g:DuplicateWrite_CreateNonExistingTargetDirectory = 'ask'

Remote target directories (e.g. netrw URLs like scp://path/to/file) cannot
be checked for existence; in order to be able to write to them (and skip the
useless target directory check), certain dirspecs (also local ones) can be
exempted. Any dirspec that matches the regular expression not checked:
    let g:DuplicateWrite_TargetDirectoryCheckIgnorePattern = '^\a\+://'

The filespecs of the cascaded write targets are stored in the buffer-local
List variable b:DuplicateWrite. You can use its existence / number of elements
to determine whether / how many duplications are configured, and use this e.g.
in a custom 'statusline'. To programatically add duplicate writes, use the
DuplicateWrite#Add() function.

rate this script Life Changing Helpful Unfulfilling 
script versions (upload new version)

Click on the package to download.

package script version date Vim version user release notes
DuplicateWrite-2.01.vmb.gz 2.01 2018-06-30 7.0 Ingo Karkat - The target directory check interferes with remote (netrw) targets. Add g:DuplicateWrite_TargetDirectoryCheckIgnorePattern configuration that skips URIs by default.
- BUG: A netrw target (e.g. scp://hostname/path) causes the autocmds to get lost.
- FIX: Cleanup of autocmds may not apply after :bdelete.
DuplicateWrite-2.00.vmb.gz 2.00 2016-08-24 7.0 Ingo Karkat - ENH: Support passing [++opt] [+cmd] [-cmd] before filespecs, and allow multiple filespec arguments to :DuplicateWrite.
- ENH: Add default mirror configuration in g:DuplicateWrite_DefaultMirrors.
- Use nested autocmds, but allow to suppress certain events via g:DuplicateWrite_EventIgnore.
- ENH: Check for existence of target directory, and react according to g:DuplicateWrite_CreateNonExistingTargetDirectory.
- ENH: Support duplicate write only with :write when using :DuplicateWrite! during definition. *** You need to update to ingo-library (vimscript #4433) version 1.025! ***
DuplicateWrite-1.01.vmb.gz 1.01 2013-09-13 7.0 Ingo Karkat - FIX: Use full absolute path and normalize to be immune against changes in CWD.
- *** You need to update to ingo-library (vimscript #4433) version 1.013! ***
DuplicateWrite-1.00.vmb.gz 1.00 2013-09-13 7.0 Ingo Karkat Initial upload
ip used for rating:

If you have questions or remarks about this site, visit the vimonline development pages. Please use this site responsibly.
Questions about Vim should go to the maillist. Help Bram help Uganda.
Vim at Github