PKR4=M  backups.py# # backups.py # (c) Steve Cooper 2008 # # Utilities for manipulating a backup store import sublime, sublimeplugin, os, _winreg, re, datetime def base_dir(view): options = view.options() backupDir = sublime.options().getString("backupDir") if (backupDir is None): #log("no backup dir specified") # change this if you want backups to go somewhere else return os.path.join(get_shell_folder("Personal"), "Sublime Text Backups") else: return backupDir def log(message): print "Automatic backup: " + message def timestampFile(file_name): """Puts a datestamp in file_name, just before the extension.""" now = datetime.datetime.today() filepart, extensionpart = os.path.splitext(file_name) return "%s-%04d-%02d-%02d-%02d-%02d-%02d%s" % \ (filepart, now.year, now.month, now.day, now.hour, now.minute, now.second, extensionpart) def backupFilePath(view, just_dir=False): """Creates a new name for the file to back up, in the base directory, with a timestamp. Eg, turns c:\\myfile.txt into d:\\backups\\c-drive\\myfile-2008-03-20-12-44-03.txt """ buffer_file_name = view.fileName() backup_base = base_dir(view) unc_rx = re.compile('^\\\\\\\\') # unc format, eg \\svr\share drive_rx = re.compile('^[A-Za-z]\:\\\\') # drive-colon, eg c:\foo drive_match = drive_rx.match(buffer_file_name) unc_match = unc_rx.match(buffer_file_name) rewritten_path = None if just_dir: buffer_file_name = os.path.split(buffer_file_name)[0] if (drive_match): # rewrite C:\foo\baras d:\backups\c-drive\foo\bar rewritten_path = os.path.join(backup_base, buffer_file_name[0] + "-drive", buffer_file_name[3:]) elif (unc_match): # rewrite \\unc\share as d:\backups\network\unc\share rewritten_path = os.path.join(backup_base, "network", buffer_file_name[2:]) if rewritten_path: return timestampFile(rewritten_path) if not just_dir else rewritten_path else: return None # we can't save this kind of file -- what the hell is it? # # FUNCTIONS FOR ACCESSING WINDOWS REGISTRY FOR USER'S SHELL FOLDERS # def _substenv(m): return os.environ.get(m.group(1), m.group(0)) def get_shell_folder(name): """Returns the shell folder with the given name, eg "AppData", "Personal", "Programs". Environment variables in values of type REG_EXPAND_SZ are expanded if possible.""" HKCU = _winreg.HKEY_CURRENT_USER USER_SHELL_FOLDERS = \ r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders' key = _winreg.OpenKey(HKCU, USER_SHELL_FOLDERS) ret = _winreg.QueryValueEx(key, name) key.Close() if ret[1] == _winreg.REG_EXPAND_SZ and '%' in ret[0]: return re.compile(r'%([^|<>=^%]+)%').sub(_substenv, ret[0]) else: return ret[0] PKR4=main.sublime-distroPKR4=?automaticBackups.py# # AutomaticBackupsPlugin.py # (c) Steve Cooper, 2008 # This software comes with NO WARRANTIES. # from __future__ import with_statement import sublime, sublimeplugin, os, shutil, sys, re from functools import partial from subprocess import Popen import backups WINMERGE = '"C:\Program Files\WinMerge\WinMergeU.exe"' class NavigateBackupsCommand(sublimeplugin.TextCommand): def __init__(self): self.reInit() def reInit(self): self.index = None self.justReverted = False self.foundBackupFiles = None self.currentFile = None def run(self, view, args): if self.index is None: self.findBackups(view) cmd = args[0] if cmd == 'forward': self.navForwards() elif cmd == 'backward': self.navBackwards() if self.foundBackupFiles: if self.navigatedToEndOfBackups(): if cmd != 'merge' and not self.justReverted: self.revert(view) else: self.backup = self.foundBackupFiles[self.index] self.backupFullPath = os.path.join(self.backupPath, self.backup) if cmd == 'merge': self.merge() else: self.buffer(view) def navForwards(self): self.index +=1 self.index = min(len(self.foundBackupFiles)-1, self.index) def navBackwards(self): self.index -=1 self.index = max(0, self.index) self.justReverted = False def findBackups(self, view): fn = view.fileName() self.currentFile = fn f, ext = os.path.splitext(os.path.split(fn)[1]) self.backupPath = backups.backupFilePath(view, just_dir=True) dirListing = os.listdir(self.backupPath) date = "-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}" pattern = "%s%s%s" % (f, date, ext) matcher = re.compile(pattern) self.foundBackupFiles = \ filter(lambda x: matcher.match(x), dirListing) self.index = len(self.foundBackupFiles)-1 def merge(self): CMD = '%s /e /wr /s /x /ul /ur /dr "AUTOMATIC BACKUP: %s" "%s" "%s"' %\ (WINMERGE, self.backup, self.currentFile, self.backupFullPath) Popen(CMD) def buffer(self, view): with file(self.backupFullPath) as old_file: view.erase(sublime.Region(0, view.size())) view.insert(0, unicode(old_file.read(), 'utf8')) sublime.statusMessage("%s [%s of %s]" %\ (self.backup, self.index+1, len(self.foundBackupFiles)-1)) def navigatedToEndOfBackups(self): return self.index == len(self.foundBackupFiles)-1 def revert(self, view): sublime.setTimeout(partial(view.runCommand, 'revert'), 50) self.justReverted = True def onActivated(self, view): if view.fileName() != self.currentFile: self.reInit() def onLoad(self, view): self.reInit() def onPostSave(self, view): self.reInit() def isEnabled(self, view, args): return view.fileName() class AutomaticBackupsPlugin(sublimeplugin.Plugin): """Creates an automatic backup of every file you save. This gives you a rudimentary mechanism for making sure you don't lose information while working.""" def onPostSave(self, view): """When a file is saved, put a copy of the file into the backup directory""" buffer_file_name = view.fileName() # if buffer_file_name.endswith('.lnk'): return newname = backups.backupFilePath(view) if newname == None: return backup_dir, file_to_write = os.path.split(newname) # make sure that we have a directory to write into if (os.access(backup_dir, os.F_OK) == False): os.makedirs(backup_dir) backups.log("backing up to " + newname) shutil.copy(buffer_file_name, newname)PKR4=s3Default.sublime-keymap PKR4=} README.txt"Automatic Backups" is a plugin by SteveCooper. When you edit text files (scripts, prose, whatever) you often find yourself wishing for an older version. Ever accidentally deleted a chunk from an important configuration file, or wished you could roll back a document a few hours? This plugin takes a copy of every file you save and copies it into a backup directory structure, ensuring that you never lose an old version of the file. Once installed, any file you save will be copied into your documents folder, eg `\Sublime Text Backups`. For example, if you change `c:\autoexec.bat`, you'll get a backup saved to: c:\Documents and Settings\yourUserName\Sublime Text Backups\c-drive\autoexec-2008-03-22-22-22-46.bat That end bit is the timestamp, so you can see when the file was edited. If you want to back up your files somewhere other than your documents folder, you can add an option. To change where all backups are made, open the `Preferences` menu and choose `Preferences`. Then double-click `Application`, and add a line like this to the end of the file; backupDir c:\my files\archive\ To see if it's working, open the console with the `View` | `Console` menu item. When you save a file, you should see a line like this, indicating that the file has been backed up; Automatic backup: backing up to d:\backups\C-drive\Documents and Settings\steve\Application Data\Sublime Text\Packages\User\AutomaticBackupsPlugin-2008-03-22-22-22-46.py PKR4=M  backups.pyPKR4=F main.sublime-distroPKR4=?w automaticBackups.pyPKR4=s3|Default.sublime-keymapPKR4=} README.txtPK6!