Possible to make a backup of original file in vim? - vim

Is it is possible to make a copy of original file before writing the new buffer to the file without having to leave vim and copy it manually?

How about this? After editing the file, before :wq, you can do:
:!cat myfile.txt > backup.txt
and then save using :wq. The previous content would be stored in backup.txt

UPDATE
I realized that my solution might be a little complicated for beginners and unnecessary for single files backups, so if you want a simple solution just use:
:!cp % ~/
The % register keeps the name of the file and with this extern command you can copy the current file to your home folder or you can change it to any folder you want.
In Windows you can use this to send to a backup folder on C::
:!copy % \backups\
You can turn in a shortcut on your .vimrc with something like:
nnoremap .b :!cp % ~/
Old Answer:
I had the same need to backup before save the modifications, so I created a Bash and a Batch(for Windows) file that backups all the files that I want and used this conditional statement on .vimrc to choose automatically between the two systems:
if has("win32")
nnoremap <leader>bc :! C:\C\SCRIPTS\backupWIN.bat<cr>
else
nnoremap <leader>bc :!bash /home/vini/C/SCRIPTS/backup.sh<cr>
endif
Here the code for the Bash version:
#!/bin/bash
#adds the date to folder(you can change the date format)
now=$(date +"%d_%m_%Y_%H;%M;%S")
mkdir /home/vini/backups/C_BKP/pre_alpha/$now
cp -r /home/vini/C /home/vini/backups/C_BKP/pre_alpha/$now
echo "saved in: /home/vini/backups/C_BKP/pre_alpha/"$now
Here the code for the Batch file:
set start=%time%
::I didn't managed to make it print the seconds, so I choose to
::override the same files if I save twice in the same minute
#echo off
For /f "tokens=1-4 delims=/ " %%a in ('date /t') do (set mydate=%%a-%%b-%%c)
For /f "tokens=1-4 delims=/:" %%a in ('time /t') do (set mytime=%%ah%%bm%%c)
mkdir C:\Users\vini\Desktop\C\C-%mydate%-%mytime%
::careful with xcopy , read the documentation before modify it
xcopy /E /Y C:\C C:\Users\vini\Desktop\C\C-%mydate%-%mytime%\
You just need to change the name of the directories for match your folders and you are good to go.

As #Sato Katsura pointed out, it is patchmode:
:set patchmode=.orig

I just simply use:
:!cp % %.backup
Which will create a new file in the same location with .backup appended to it.

Related

Search for a file and open the path in CMD

I would like to achieve the following in CMD:
Will search for a specific filename - This I know how to do, with dir /s filename
Once found it will bring me to that path.
Example: I am now on C:\, if that file was found in C:\test then it will open C:\test in command prompt.
Alternatively, I would like just to copy the found file to a path I will specify. I just don't know how to do it, since I don't know the path where the file will be stored (it's different every time).
Thanks in advance!
I'm a liitle confused with your question but I will try to walk you through a batch code I wrote to help you with this.
dir /b /s "test.txt" > "%userprofile%/Desktop/result.txt"
::find the file path to the file you want to find and insert it in a .txt file
::you made called result.txt (also %userprofile% is a variable that brings you to
::your user directory ex C:/users/admin)
for /F "tokens=*" %%A in (%userprofile%/desktop/result.txt) do (
set var1=%%A
)
::set the variable var1 equal to the first (well... only) line in the file.
::I could explain what that for loop means in detail but just remember that %%A
::is a variable set from what was found when looping through the result.txt.
xcopy /s "%var1%" "C:/wherever/you/want/it/to/go"
did this help??

How to add files/folders to multiple zip files at once with WinRAR?

Is there any way to add files/folders to multiple zip files at once. For example:
Updates:
folder1
folder2
file1
file2
Archives:
archive1.zip
archive2.zip
archive3.zip
I need to add updates to all archives without opening all of them and pasting updates in there.
Any way to do this?
Or is there another archive program that can do this?
This can be done using a batch file and for example WinRAR.
#echo off
if not exist archive*.zip (
echo There are no archive*.zip files to update in
echo.
echo %CD%
echo.
pause
goto :EOF
)
set "ErrorCount=0"
for %%I in (archive*.zip) do (
"%ProgramFiles%\WinRAR\WinRar.exe" u -afzip -cfg- -ep1 -ibck -inul -r -y "%%I" folder1 folder2 file1 file2
if errorlevel 1 (
echo Error on updating %%I
set /A ErrorCount+=1
)
)
if not "%ErrorCount%" == "0" (
echo.
pause
)
set "ErrorCount="
For each archive*.zip file WinRAR is called to update the ZIP file with the two folders and the two files.
The batch processing finishes without printing any message and without pausing if all ZIP files found could be updated successfully. Otherwise the batch file outputs which ZIP file could not be updated for example because of read-only attribute set, and pauses the batch processing before finishing so that the user can read the error message(s).
For details on the WinRAR command u and the used switches open in WinRAR from menu Help the Help topics, open on tab Contents the item Command line mode and read at least the help pages:
Command line syntax
Commands - Alphabetic commands list
Switches - Alphabetic switches list
For understanding the other used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
goto /?
if /?
pause /?
set /?
You can do it by using 7zip command line version
7z a archive1.zip dir\ -v10k -v15k -v2m #listfile.txt
this will do archive all files and folder is in that folder named 'dir'
and first volume will be 10kb, second will be 15kb and others will be 2mb each except last
and you can use a file that has list of all files named.

Can you tell Vim to open a different file than the one passed on the commandline or to :e?

I want to teach Vim how to open Perl 5 modules from names like File::Find. I already have a wrapper script written in Perl 5 that handles the commandline (see below), but I would like to be able to say things like :tabe File::Find and have it really execute :tabe /home/cowens/apps/perlbrew/perls/perl-5.14.0/lib/5.14.0/File/Find.pm.
My current plan is to somehow use autocmd BufNewFile and/or autocmd BufPreRead, but I can't figure out how to switch the file name.
#!/usr/bin/perl
use strict;
use warnings;
my #files = #ARGV;
for my $file (#files) {
next if -f $file; #skip files that really exist
#convert from module name to module file
(my $module = $file) =~ s{::}{/}g;
$module .= ".pm";
#look for module in the include paths
for my $dir (#INC) {
my $candidate = "$dir/$module";
if (-f $candidate) {
$file = $candidate;
last;
}
}
}
#replace this script with vim
exec "vim", "-p", #files;
Doing
:verbose au BufReadCmd
Will tell you how other types of plugins do this (e.g. zip, netrw, fugitive). Sample output that should give you plenty of ideas:
zip BufReadCmd
zipfile:* call zip#Read(expand("<amatch>"), 1)
Last set from C:\Program Files\Vim\vim73\plugin\zipPlugin.vim
*.zip call zip#Browse(expand("<amatch>"))
Last set from C:\Program Files\Vim\vim73\plugin\zipPlugin.vim
Network BufReadCmd
ftp://* exe "silent doau BufReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(2,expand("<amatch>"))|exe "silent doau BufReadPost ".fnameescape(expand("<amatch>"))
Last set from C:\Program Files\Vim\vim73\plugin\netrwPlugin.vim
http://* exe "silent doau BufReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(2,expand("<amatch>"))|exe "silent doau BufReadPost ".fnameescape(expand("<amatch>"))
Last set from C:\Program Files\Vim\vim73\plugin\netrwPlugin.vim
fugitive_files BufReadCmd
*.git/index
exe s:BufReadIndex()
Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
*.git/*index*.lock
exe s:BufReadIndex()
Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
fugitive://**//[0-3]/**
exe s:BufReadIndexFile()
Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
fugitive://**//[0-9a-f][0-9a-f]*
exe s:BufReadObject()
Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
Consider using ctags. If you're able to run the ctags process over your source code, you should be able to get to a point where you simply do:
vim -t File::Find
Vim has information about this (:help vim) I think ctags probably goes well beyond what you're trying to do, allowing you to jump from the middle of one source file to the original function definition in another.
For opening those files manually I would recommend to use :find and
:tabfind commands instead of :edit and :tabedit respectively. The
difference between these two pairs of commands is that the former ones look
for a file not only in the current path, but also in directories listed in
path option (see :help 'path'). If you add your Perl #INC directories
to Vim path option, you can quickly locate a module file by using :find or
:tabfind commands. For example, to open a new tab page and edit
File::Find module file in you can type
:tabfind File/Find.pm
(You don't have to type the whole sub-path manually since :find and
:tabfind completion takes the current path value into account.)
To locating those files automatically by module name using gf, ^Wf,
^Wgf, you need to additionally change (either with filetype plugin or
autocommand) the following options for Perl files.
:set isfname+=:
:set suffixesadd+=.pm
:set includeexpr=substitute(v:fname,'::','/','g')
After these options (as well as path option containing Perl #INC
directories) are set, you can easily open module files using gf-like
commands on corresponding module names.
Lazy solution based on sehe's answer below. Current problems:
the file it writes is the original name, not the munged name
it looks like the autocommands that set the filetype are running too soon, not at all, or are confused.
it is using an external command to do the work
it is specific to the munging I want (i.e. it is not general)
When I have more downtime, I hope to fix all of the above and turn it into a plugin.
in .vimrc
autocmd BufReadCmd * r!cat_perl %
in cat_perl
#!/usr/bin/perl
use strict;
use warnings;
sub cat {
my $file = shift;
open my $fh, "<", $file
or die "could not open $file: $!";
print while <$fh>;
exit;
}
my $file = shift;
cat $file if -f $file;
#convert from module name to module file
(my $module = $file) =~ s{::}{/}g;
$module .= ".pm";
#look for module in the include paths
for my $dir (#INC) {
my $candidate = "$dir/$module";
cat $candidate if -f $candidate;
}
print "";
This may actually be possible with vim's gf command (go to file).
In your code, if you see a string like File::Find, place your cursor over it and in normal mode type gf. For me, that immediately takes me to the File::Find package.
I think this is native as part of the perl filetype libraries because it works for me when executing vim with --noplugin.
Here's a working example showing how to use the BufReadCmd autocmd to edit a file other than the one specified (in this case editing a corresponding .scss file when you open a .css file).

Is there a script that would allow me to edit multiple files as if they are one file in VIM?

I prefer to edit in one large file rather than many independent files, but due to limitations in languages, source control, and the preference of team mates I need to output to many files.
What I'm looking for would recurse through all the files in a source directory and generate a single file to edit in VIM, with special file seperator markers. On save it would save the the changes to the correct file(s) ideally in a smart manner, based only on changes made.
Does something like this exist?
shar
Well, you could use shar(1), but it puts an X in front of each line that you will probably find annoying. (Shar came with my Mac but on my Linux systems you need to add a package.)
Shar is just, itself, a short shell script, so you could modify it easily enough to work without the X.
You might try copying /usr/bin/shar to /tmp and applying this diff with patch(1).
--- /usr/bin/shar 2009-07-13 22:26:18.000000000 -0700
+++ /tmp/shar2 2010-12-24 19:05:34.000000000 -0800
## -65,8 +65,8 ##
echo "mkdir -p $i > /dev/null 2>&1"
else
echo "echo x - $i"
- echo "sed 's/^X//' >$i << 'END-of-$i'"
- sed 's/^/X/' $i
+ echo "cat >$i << 'END-of-$i'"
+ cat $i
echo "END-of-$i"
fi
done
It reminds me of vimballs format. However, it's meant to expand files into the user runtimepath directory.
In other words, you can list all the files you want join and apply :MkVimBall (here is an example).
Then, for the extraction, you will have to momentarily (i.e. save and restore its value after the extraction) set &runtimepath to the root directory of your project before extracting with :so %.
You'll also have to play with various options like the &filetype, etc.
It's a dirty hack, but well ... it shall do the job.
Instead of dumping several files into one, processing this one and then separating stuff apart again, you could use bufdo or windo to repeat a command on all opened buffers: open the buffers to be processed, then cast the bufdo command and it will work on every opened file: http://vimdoc.sourceforge.net/htmldoc/windows.html#list-repeat

Change Vim swap/backup/undo file name

Is it possible to change the way Vim names its swap/backup/undo files?
To avoid clutter, I've set options in my ~/.vimrc to dump these files in ~/.vim/tmp/{swap,backup,undo}; however, as I routinely edit files in different directories with the same name, I often end up with lots of otherwise indistinguishable files and Vim sometimes has trouble recovering.
Ideally, I'd like to use the naming scheme that the persistent undo has (%path%to%file.undo) for all these auxiliary files; there's no obvious way to set it, but can it be done with Buf{Read,Write} macros?
I have this in my .vimrc and it names the swap files with full path names and percent signs just as you describe:
" Store swap files in fixed location, not current directory.
set dir=~/.vimswap//,/var/tmp//,/tmp//,.
The key is the // at the end of the directories. See this note from :help dir:
For Unix and Win32, if a directory ends in two path separators "//"
or "\\", the swap file name will be built from the complete path to
the file with all path separators substituted to percent '%' signs.
This will ensure file name uniqueness in the preserve directory.
Here's part of my .vimrc from github.
This sets the undodir (and turns it on), sets the backupdir, and directory (used for .swp files). Note that it creates the directories if they don't already exist.
" Save your backup files to a less annoying place than the current directory.
" If you have .vim-backup in the current directory, it'll use that.
" Otherwise it saves it to ~/.vim/backup or .
if isdirectory($HOME . '/.vim/backup') == 0
:silent !mkdir -p ~/.vim/backup >/dev/null 2>&1
endif
set backupdir-=.
set backupdir+=.
set backupdir-=~/
set backupdir^=~/.vim/backup/
set backupdir^=./.vim-backup/
set backup
" Save your swap files to a less annoying place than the current directory.
" If you have .vim-swap in the current directory, it'll use that.
" Otherwise it saves it to ~/.vim/swap, ~/tmp or .
if isdirectory($HOME . '/.vim/swap') == 0
:silent !mkdir -p ~/.vim/swap >/dev/null 2>&1
endif
set directory=./.vim-swap//
set directory+=~/.vim/swap//
set directory+=~/tmp//
set directory+=.
" viminfo stores the the state of your previous editing session
set viminfo+=n~/.vim/viminfo
if exists("+undofile")
" undofile - This allows you to use undos after exiting and restarting
" This, like swap and backup files, uses .vim-undo first, then ~/.vim/undo
" :help undo-persistence
" This is only present in 7.3+
if isdirectory($HOME . '/.vim/undo') == 0
:silent !mkdir -p ~/.vim/undo > /dev/null 2>&1
endif
set undodir=./.vim-undo//
set undodir+=~/.vim/undo//
set undofile
endif
Hopefully, it's commented well enough to understand what's going on. If not, add a comment and I'll fix it.
Ciao!
Update [07/16/2012]
I got an email from Rob Kine asking these questions about the backupdir section that I wanted to answer for everyone:
It looks like you are removing the current directory, and then re-adding it. what does that do?
What does the ^= operator do?
How does the order of precedence in the use of folders checked work in Vim? (Like is the last folder added the first one it checks for?)
The first thing is to describe the different operators. These operators have different meanings for non-string-list options, so be warned!
-= removes the value from a string list;
+= appends the value to a string list;
^= prepends the value to a string list.
So the backupdir has the following operations applied:
Remove the current directory from the list.
Append the current directory to the list (this ensures it is the last thing checked).
Remove the home directory from the list (I don't like stuff being saved there).
Prepend ~/.vim/backup/.
Prepend ~/.vim-backup/.
When Vim looks for where to save the backups, it checks from first to last; so it'll check for ~/.vim-backup/, then check for ~/.vim/backup, then check the default list (except for . and ~/ which were removed), and finally check .
You can get help for all these in Vim by using (for example) :help ^= or :help backupdir.
Create the directory undo
$ mkdir ~/.vimundo
Set up your .vimrc file
set undodir=~/.vimundo

Resources