diff --git a/sublime/Packages/LineEndings/LineEndings.py b/sublime/Packages/LineEndings/LineEndings.py index 85f8434..7500831 100644 --- a/sublime/Packages/LineEndings/LineEndings.py +++ b/sublime/Packages/LineEndings/LineEndings.py @@ -48,7 +48,7 @@ class SetLineEndingWindowCommand(sublime_plugin.TextCommand): sublime.active_window().focus_view(active_view); def is_enabled(self): - return len(sublime.active_window().views()) + return len(sublime.active_window().views()) > 0 class ConvertIndentationWindowCommand(sublime_plugin.TextCommand): @@ -64,4 +64,4 @@ class ConvertIndentationWindowCommand(sublime_plugin.TextCommand): def is_enabled(self): - return len(sublime.active_window().views()) \ No newline at end of file + return len(sublime.active_window().views()) > 0 diff --git a/sublime/Packages/LineEndings/package-metadata.json b/sublime/Packages/LineEndings/package-metadata.json index ab85b4a..5f10e27 100644 --- a/sublime/Packages/LineEndings/package-metadata.json +++ b/sublime/Packages/LineEndings/package-metadata.json @@ -1 +1 @@ -{"url": "https://github.com/SublimeText/LineEndings", "version": "2013.02.23.18.50.15", "description": "On statusbar and on command palete."} \ No newline at end of file +{"url": "https://github.com/SublimeText/LineEndings", "version": "2013.03.16.11.27.12", "description": "On statusbar and on command palete."} \ No newline at end of file diff --git a/sublime/Packages/LineEndings/readme.md b/sublime/Packages/LineEndings/readme.md index 35fb387..b3157c3 100644 --- a/sublime/Packages/LineEndings/readme.md +++ b/sublime/Packages/LineEndings/readme.md @@ -22,4 +22,5 @@ Install this repository via "Package Control" http://wbond.net/sublime_packages/ # Contributors - * polyvertex \ No newline at end of file + * polyvertex + * Nicholas Buse \ No newline at end of file diff --git a/sublime/Packages/SFTP/Context.sublime-menu b/sublime/Packages/SFTP/Context.sublime-menu new file mode 100644 index 0000000..e70c5de --- /dev/null +++ b/sublime/Packages/SFTP/Context.sublime-menu @@ -0,0 +1,34 @@ +[ + { "caption": "-" }, + { + "caption": "SFTP/FTP", + "children": + [ + { "caption": "Upload File", "command": "sftp_upload_file" }, + { "caption": "Upload Open Files", "command": "sftp_upload_open_files" }, + { "caption": "Download File", "command": "sftp_download_file" }, + { "caption": "-" }, + { "caption": "Upload Folder", "command": "sftp_upload_folder" }, + { "caption": "Download Folder", "command": "sftp_download_folder" }, + { "caption": "-" }, + { "caption": "Diff Remote File", "command": "sftp_diff_remote_file" }, + { "caption": "Rename Local and Remote Files", "command": "sftp_rename_local_and_remote_paths" }, + { "caption": "-" }, + { "caption": "Delete Local and Remote Files", "command": "sftp_delete_local_and_remote_paths" }, + { "caption": "Delete Remote File", "command": "sftp_delete_remote_path" }, + { "caption": "-" }, + { "caption": "Sync Local -> Remote…", "command": "sftp_sync_up" }, + { "caption": "Sync Remote -> Local…", "command": "sftp_sync_down" }, + { "caption": "Sync Both Directions…", "command": "sftp_sync_both" }, + { "caption": "-" }, + { "caption": "Monitor File (Upload on External Save)", "command": "sftp_monitor_file" }, + { "caption": "-" }, + { "caption": "Browse Remote…", "command": "sftp_browse" }, + { "caption": "-" }, + { "caption": "Map to Remote…", "command": "sftp_create_config" }, + { "caption": "Edit Remote Mapping…", "command": "sftp_edit_config" }, + { "caption": "Add Alternate Remote Mapping…", "command": "sftp_create_alt_config" }, + { "caption": "Switch Remote Mapping…", "command": "sftp_switch_config" } + ] + } +] diff --git a/sublime/Packages/SFTP/Default (Linux).sublime-keymap b/sublime/Packages/SFTP/Default (Linux).sublime-keymap new file mode 100644 index 0000000..de8211b --- /dev/null +++ b/sublime/Packages/SFTP/Default (Linux).sublime-keymap @@ -0,0 +1,26 @@ +[ + { "keys": ["ctrl+alt+u","ctrl+alt+f"], "command": "sftp_upload_file" }, + { "keys": ["ctrl+alt+u","ctrl+alt+r"], "command": "sftp_upload_folder" }, + { "keys": ["ctrl+alt+u","ctrl+alt+y"], "command": "sftp_sync_up" }, + { "keys": ["ctrl+alt+u","ctrl+alt+n"], "command": "sftp_upload_open_files" }, + { "keys": ["ctrl+alt+u","ctrl+alt+m"], "command": "sftp_monitor_file" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+o"], "command": "sftp_download_file" }, + { "keys": ["ctrl+alt+u","ctrl+alt+e"], "command": "sftp_download_folder" }, + { "keys": ["ctrl+alt+u","ctrl+alt+d"], "command": "sftp_sync_down" }, + { "keys": ["ctrl+alt+u","ctrl+alt+i"], "command": "sftp_diff_remote_file" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+b"], "command": "sftp_sync_both" }, + { "keys": ["ctrl+alt+u","ctrl+alt+c"], "command": "sftp_vcs_changed_files" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+w"], "command": "sftp_browse" }, + + { "keys": ["ctrl+alt+r","ctrl+alt+s"], "command": "sftp_create_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+b"], "command": "sftp_browse_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+n"], "command": "sftp_last_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+e"], "command": "sftp_edit_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+d"], "command": "sftp_delete_server" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+s"], "command": "sftp_show_panel" }, + { "keys": ["ctrl+alt+u","ctrl+alt+x"], "command": "sftp_cancel_upload" } +] \ No newline at end of file diff --git a/sublime/Packages/SFTP/Default (OSX).sublime-keymap b/sublime/Packages/SFTP/Default (OSX).sublime-keymap new file mode 100644 index 0000000..210799a --- /dev/null +++ b/sublime/Packages/SFTP/Default (OSX).sublime-keymap @@ -0,0 +1,26 @@ +[ + { "keys": ["super+ctrl+u","super+ctrl+f"], "command": "sftp_upload_file" }, + { "keys": ["super+ctrl+u","super+ctrl+r"], "command": "sftp_upload_folder" }, + { "keys": ["super+ctrl+u","super+ctrl+y"], "command": "sftp_sync_up" }, + { "keys": ["super+ctrl+u","super+ctrl+n"], "command": "sftp_upload_open_files" }, + { "keys": ["super+ctrl+u","super+ctrl+m"], "command": "sftp_monitor_file" }, + + { "keys": ["super+ctrl+u","super+ctrl+o"], "command": "sftp_download_file" }, + { "keys": ["super+ctrl+u","super+ctrl+e"], "command": "sftp_download_folder" }, + { "keys": ["super+ctrl+u","super+ctrl+d"], "command": "sftp_sync_down" }, + { "keys": ["super+ctrl+u","super+ctrl+i"], "command": "sftp_diff_remote_file" }, + + { "keys": ["super+ctrl+u","super+ctrl+b"], "command": "sftp_sync_both" }, + { "keys": ["super+ctrl+u","super+ctrl+c"], "command": "sftp_vcs_changed_files" }, + + { "keys": ["super+ctrl+u","super+ctrl+w"], "command": "sftp_browse" }, + + { "keys": ["super+ctrl+r","super+ctrl+s"], "command": "sftp_create_server" }, + { "keys": ["super+ctrl+r","super+ctrl+b"], "command": "sftp_browse_server" }, + { "keys": ["super+ctrl+r","super+ctrl+n"], "command": "sftp_last_server" }, + { "keys": ["super+ctrl+r","super+ctrl+e"], "command": "sftp_edit_server" }, + { "keys": ["super+ctrl+r","super+ctrl+d"], "command": "sftp_delete_server" }, + + { "keys": ["super+ctrl+u","super+ctrl+s"], "command": "sftp_show_panel" }, + { "keys": ["super+ctrl+u","super+ctrl+x"], "command": "sftp_cancel_upload" } +] \ No newline at end of file diff --git a/sublime/Packages/SFTP/Default (Windows).sublime-keymap b/sublime/Packages/SFTP/Default (Windows).sublime-keymap new file mode 100644 index 0000000..de8211b --- /dev/null +++ b/sublime/Packages/SFTP/Default (Windows).sublime-keymap @@ -0,0 +1,26 @@ +[ + { "keys": ["ctrl+alt+u","ctrl+alt+f"], "command": "sftp_upload_file" }, + { "keys": ["ctrl+alt+u","ctrl+alt+r"], "command": "sftp_upload_folder" }, + { "keys": ["ctrl+alt+u","ctrl+alt+y"], "command": "sftp_sync_up" }, + { "keys": ["ctrl+alt+u","ctrl+alt+n"], "command": "sftp_upload_open_files" }, + { "keys": ["ctrl+alt+u","ctrl+alt+m"], "command": "sftp_monitor_file" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+o"], "command": "sftp_download_file" }, + { "keys": ["ctrl+alt+u","ctrl+alt+e"], "command": "sftp_download_folder" }, + { "keys": ["ctrl+alt+u","ctrl+alt+d"], "command": "sftp_sync_down" }, + { "keys": ["ctrl+alt+u","ctrl+alt+i"], "command": "sftp_diff_remote_file" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+b"], "command": "sftp_sync_both" }, + { "keys": ["ctrl+alt+u","ctrl+alt+c"], "command": "sftp_vcs_changed_files" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+w"], "command": "sftp_browse" }, + + { "keys": ["ctrl+alt+r","ctrl+alt+s"], "command": "sftp_create_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+b"], "command": "sftp_browse_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+n"], "command": "sftp_last_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+e"], "command": "sftp_edit_server" }, + { "keys": ["ctrl+alt+r","ctrl+alt+d"], "command": "sftp_delete_server" }, + + { "keys": ["ctrl+alt+u","ctrl+alt+s"], "command": "sftp_show_panel" }, + { "keys": ["ctrl+alt+u","ctrl+alt+x"], "command": "sftp_cancel_upload" } +] \ No newline at end of file diff --git a/sublime/Packages/SFTP/Default.sublime-commands b/sublime/Packages/SFTP/Default.sublime-commands new file mode 100644 index 0000000..baaf037 --- /dev/null +++ b/sublime/Packages/SFTP/Default.sublime-commands @@ -0,0 +1,132 @@ +[ + { + "caption": "SFTP: Upload File", + "command": "sftp_upload_file" + }, + { + "caption": "SFTP: Upload Open Files", + "command": "sftp_upload_open_files" + }, + { + "caption": "SFTP: Download File", + "command": "sftp_download_file" + }, + { + "caption": "SFTP: Upload Folder", + "command": "sftp_upload_folder" + }, + { + "caption": "SFTP: Download Folder", + "command": "sftp_download_folder" + }, + { + "caption": "SFTP: Diff Remote File", + "command": "sftp_diff_remote_file" + }, + { + "caption": "Rename Local and Remote Files", + "command": "sftp_rename_local_and_remote_paths" + }, + { + "caption": "Delete Local and Remote Files", + "command": "sftp_delete_local_and_remote_paths" + }, + { + "caption": "Delete Remote File", + "command": "sftp_delete_remote_path" + }, + { + "caption": "SFTP: Sync Local -> Remote…", + "command": "sftp_sync_up" + }, + { + "caption": "SFTP: Sync Remote -> Local…", + "command": "sftp_sync_down" + }, + { + "caption": "SFTP: Sync Both Directions…", + "command": "sftp_sync_both" + }, + { + "caption": "SFTP: Monitor File (Upload on External Save)", + "command": "sftp_monitor_file" + }, + { + "caption": "SFTP: Upload VCS Changed Files", + "command": "sftp_vcs_changed_files" + }, + { + "caption": "SFTP: Browse Remote…", + "command": "sftp_browse" + }, + { + "caption": "SFTP: Setup Server…", + "command": "sftp_create_server" + }, + { + "caption": "SFTP: Browse Server…", + "command": "sftp_browse_server" + }, + { + "caption": "SFTP: Edit Server…", + "command": "sftp_edit_server" + }, + { + "caption": "SFTP: Delete Server…", + "command": "sftp_delete_server" + }, + { + "caption": "SFTP: Map to Remote…", + "command": "sftp_create_config" + }, + { + "caption": "SFTP: Edit Remote Mapping…", + "command": "sftp_edit_config" + }, + { + "caption": "SFTP: Add Alternate Remote Mapping…", + "command": "sftp_create_alt_config" + }, + { + "caption": "SFTP: Switch Remote Mapping…", + "command": "sftp_switch_config" + }, + { + "caption": "SFTP: Show Panel", + "command": "sftp_show_panel" + }, + { + "caption": "SFTP: Cancel Upload", + "command": "sftp_cancel_upload" + }, + { + "caption": "Preferences: SFTP Settings", + "command": "open_file", "args": + { + "file": "${packages}/SFTP/SFTP.sublime-settings"} + }, + { + "caption": "Preferences: SFTP Key Bindings", + "command": "open_file", "args": + { + "file": "${packages}/SFTP/Default (Windows).sublime-keymap", + "platform": "Windows" + } + }, + { + "caption": "Preferences: SFTP Key Bindings", + "command": "open_file", "args": + { + "file": "${packages}/SFTP/Default (OSX).sublime-keymap", + "platform": "OSX" + } + }, + { + "caption": "Preferences: SFTP Key Bindings", + "command": "open_file", "args": + { + "file": "${packages}/SFTP/Default (Linux).sublime-keymap", + "platform": "Linux" + } + } +] diff --git a/sublime/Packages/SFTP/Main.sublime-menu b/sublime/Packages/SFTP/Main.sublime-menu new file mode 100644 index 0000000..ead032b --- /dev/null +++ b/sublime/Packages/SFTP/Main.sublime-menu @@ -0,0 +1,93 @@ +[ + { + "id": "file", + "children": + [ + { + "caption": "SFTP/FTP", + "mnemonic": "b", + "children": + [ + { "command": "sftp_create_server", "caption": "Setup Server…" }, + { "command": "sftp_browse_server", "caption": "Browse Server…" }, + { "command": "sftp_edit_server", "caption": "Edit Server…" }, + { "command": "sftp_delete_server", "caption": "Delete Server…" } + ] + } + ] + }, + { + "caption": "Preferences", + "mnemonic": "n", + "id": "preferences", + "children": + [ + { + "caption": "Package Settings", + "mnemonic": "P", + "id": "package-settings", + "children": + [ + { + "caption": "SFTP", + "children": + [ + { "command": "open_file", "args": {"file": "${packages}/SFTP/SFTP.sublime-settings"}, "caption": "Settings – Default" }, + { "command": "open_file", "args": {"file": "${packages}/User/SFTP.sublime-settings"}, "caption": "Settings – User" }, + { "caption": "-" }, + { + "command": "open_file", "args": + { + "file": "${packages}/SFTP/Default (Windows).sublime-keymap", + "platform": "Windows" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", "args": + { + "file": "${packages}/SFTP/Default (OSX).sublime-keymap", + "platform": "OSX" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", "args": + { + "file": "${packages}/SFTP/Default (Linux).sublime-keymap", + "platform": "Linux" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", "args": + { + "file": "${packages}/User/Default (Windows).sublime-keymap", + "platform": "Windows" + }, + "caption": "Key Bindings – User" + }, + { + "command": "open_file", "args": + { + "file": "${packages}/User/Default (OSX).sublime-keymap", + "platform": "OSX" + }, + "caption": "Key Bindings – User" + }, + { + "command": "open_file", "args": + { + "file": "${packages}/User/Default (Linux).sublime-keymap", + "platform": "Linux" + }, + "caption": "Key Bindings – User" + }, + { "caption": "-" } + ] + } + ] + } + ] + } +] diff --git a/sublime/Packages/SFTP/SFTP.default-config b/sublime/Packages/SFTP/SFTP.default-config new file mode 100644 index 0000000..5633dfe --- /dev/null +++ b/sublime/Packages/SFTP/SFTP.default-config @@ -0,0 +1,42 @@ +{ + // The tab key will cycle through the settings when first created + // Visit http://wbond.net/sublime_packages/sftp/settings for help + + // sftp, ftp or ftps + "type": "${1:sftp}", + + "save_before_upload": ${2:true}, + "upload_on_save": ${3:false}, + "sync_down_on_open": ${4:false}, + "sync_skip_deletes": ${5:false}, + "confirm_downloads": ${6:false}, + "confirm_sync": ${7:true}, + "confirm_overwrite_newer": ${8:false}, + + "host": "${9:example.com}", + "user": "${10:username}", + ${11://}"password": "${12:password}", + ${13://}"port": "${14:22}", + + "remote_path": "${15:/example/path/}", + "ignore_regexes": [${16: + "\\\.sublime-(project|workspace)", "sftp-config(-alt\\\d?)?\\\.json", + "sftp-settings\\\.json", "/venv/", "\\\.svn", "\\\.hg", "\\\.git", + "\\\.bzr", "_darcs", "CVS", "\\\.DS_Store", "Thumbs\\\.db", "desktop\\\.ini" + }], + ${17://}"file_permissions": "${18:664}", + ${19://}"dir_permissions": "${20:775}", + + ${21://}"extra_list_connections": ${22:0}, + + "connect_timeout": ${23:30}, + ${24://}"keepalive": ${25:120}, + ${26://}"ftp_passive_mode": ${27:true}, + ${28://}"ssh_key_file": "${29:~/.ssh/id_rsa}", + ${30://}"sftp_flags": [${31:"-F", "/path/to/ssh_config"}], + + ${32://}"preserve_modification_times": ${33:false}, + ${34://}"remote_time_offset_in_hours": ${35:0}, + ${36://}"remote_encoding": "${37:utf-8}", + ${38://}"remote_locale": "${39:C}", +} \ No newline at end of file diff --git a/sublime/Packages/SFTP/SFTP.py b/sublime/Packages/SFTP/SFTP.py new file mode 100644 index 0000000..ccb8698 --- /dev/null +++ b/sublime/Packages/SFTP/SFTP.py @@ -0,0 +1,184 @@ +import sublime +import traceback +import os +import sys +import time +import imp +import re + +settings = sublime.load_settings('SFTP.sublime-settings') + +if sublime.platform() == 'linux' and settings.get('linux_enable_ssl'): + print 'SFTP: enabling custom linux ssl module' + arch_lib_path = os.path.join(sublime.packages_path(), 'SFTP', 'lib', + 'linux-' + sublime.arch()) + for ssl_ver in ['0.9.8', '1.0.0', '10']: + lib_path = os.path.join(arch_lib_path, 'libssl-' + ssl_ver) + try: + m_info = imp.find_module('_ssl', [lib_path]) + m = imp.load_module('_ssl', *m_info) + print 'SFTP: successfully loaded _ssl module for libssl.so.%s' % ssl_ver + break + except (ImportError) as (e): + print 'SFTP: _ssl module import error - ' + str(e) + if '_ssl' in sys.modules: + plat_lib_path = os.path.join(sublime.packages_path(), 'SFTP', 'lib', + 'linux') + try: + m_info = imp.find_module('ssl', [plat_lib_path]) + m = imp.load_module('ssl', *m_info) + except (ImportError) as (e): + print 'SFTP: ssl module import error - ' + str(e) + +reloading = { + 'happening': False, + 'shown': False +} + +reload_mods = [] +for mod in sys.modules: + if (mod[0:5] == 'sftp.' or mod == 'sftp') and sys.modules[mod] != None: + reload_mods.append(mod) + reloading['happening'] = True + +# Prevent popups during reload, saving the callbacks for re-adding later +if reload_mods: + old_callbacks = {} + hook_match = re.search("", str(sys.excepthook)) + if hook_match: + _temp = __import__(hook_match.group(1), globals(), locals(), + ['ExcepthookChain'], -1) + ExcepthookChain = _temp.ExcepthookChain + old_callbacks = ExcepthookChain.names + sys.excepthook = sys.__excepthook__ + +mods_load_order = [ + 'sftp', + 'sftp.times', + 'sftp.views', + 'sftp.paths', + 'sftp.debug', + 'sftp.errors', + 'sftp.threads', + 'sftp.secure_input', + 'sftp.proc', + 'sftp.vcs', + 'sftp.config', + 'sftp.panel_printer', + 'sftp.file_transfer', + 'sftp.ftplib2', + 'sftp.ftp_transport', + 'sftp.ftps_transport', + 'sftp.sftp_transport', + 'sftp.commands', + 'sftp.listeners' +] + +for mod in mods_load_order: + if mod in reload_mods: + reload(sys.modules[mod]) + +from sftp.commands import (SftpShowPanelCommand, SftpCreateServerCommand, + SftpBrowseServerCommand, SftpLastServerCommand, SftpEditServerCommand, + SftpDeleteServerCommand, SftpBrowseCommand, SftpUploadFileCommand, + SftpMonitorFileCommand, SftpUploadOpenFilesCommand, + SftpDiffRemoteFileCommand, SftpRenameLocalAndRemotePathsCommand, + SftpDeleteRemotePathCommand, SftpDownloadFileCommand, + SftpUploadFolderCommand, SftpSyncUpCommand, SftpSyncDownCommand, + SftpSyncBothCommand, SftpDownloadFolderCommand, SftpVcsChangedFilesCommand, + SftpCancelUploadCommand, SftpEditConfigCommand, SftpCreateConfigCommand, + SftpCreateSubConfigCommand, SftpThread, + SftpDeleteLocalAndRemotePathsCommand, SftpSwitchConfigCommand, + SftpCreateAltConfigCommand) +from sftp.listeners import (SftpCloseListener, SftpLoadListener, + SftpFocusListener, SftpAutoUploadListener, SftpAutoConnectListener) + +import sftp.debug +import sftp.paths +import sftp.times + +sftp.debug.set_debug(settings.get('debug', False)) + + +hook_match = re.search("", str(sys.excepthook)) + +if not hook_match: + class ExcepthookChain(object): + callbacks = [] + names = {} + + @classmethod + def add(cls, name, callback): + if name == 'sys.excepthook': + if name in cls.names: + return + cls.callbacks.append(callback) + else: + if name in cls.names: + cls.callbacks.remove(cls.names[name]) + cls.callbacks.insert(0, callback) + cls.names[name] = callback + + @classmethod + def hook(cls, type, value, tb): + for callback in cls.callbacks: + callback(type, value, tb) + + @classmethod + def remove(cls, name): + if name not in cls.names: + return + callback = cls.names[name] + del cls.names[name] + cls.callbacks.remove(callback) +else: + _temp = __import__(hook_match.group(1), globals(), locals(), + ['ExcepthookChain'], -1) + ExcepthookChain = _temp.ExcepthookChain + + +# Override default uncaught exception handler +def sftp_uncaught_except(type, value, tb): + message = ''.join(traceback.format_exception(type, value, tb)) + + if message.find('/sftp/') != -1 or message.find('\\sftp\\') != -1: + def append_log(): + log_file_path = os.path.join(sublime.packages_path(), 'User', + 'SFTP.errors.log') + send_log_path = log_file_path + timestamp = sftp.times.timestamp_to_string(time.time(), + '%Y-%m-%d %H:%M:%S\n') + with open(log_file_path, 'a') as f: + f.write(timestamp) + f.write(message) + if sftp.debug.get_debug() and sftp.debug.get_debug_log_file(): + send_log_path = sftp.debug.get_debug_log_file() + sftp.debug.debug_print(message) + sublime.error_message(('%s: An unexpected error occurred, ' + + 'please send the file %s to support@wbond.net') % ('SFTP', + send_log_path)) + sublime.active_window().run_command('open_file', + {'file': sftp.paths.fix_windows_path(send_log_path)}) + if reloading['happening']: + if not reloading['shown']: + sublime.error_message('SFTP: Sublime SFTP was just upgraded' + + ', please restart Sublime to finish the upgrade') + reloading['shown'] = True + else: + sublime.set_timeout(append_log, 10) + +if reload_mods and old_callbacks: + for name in old_callbacks: + ExcepthookChain.add(name, old_callbacks[name]) + +ExcepthookChain.add('sys.excepthook', sys.__excepthook__) +ExcepthookChain.add('sftp_uncaught_except', sftp_uncaught_except) + +if sys.excepthook != ExcepthookChain.hook: + sys.excepthook = ExcepthookChain.hook + + +def unload_handler(): + SftpThread.cleanup() + + ExcepthookChain.remove('sftp_uncaught_except') diff --git a/sublime/Packages/SFTP/SFTP.sublime-settings b/sublime/Packages/SFTP/SFTP.sublime-settings new file mode 100644 index 0000000..f87cb75 --- /dev/null +++ b/sublime/Packages/SFTP/SFTP.sublime-settings @@ -0,0 +1,61 @@ +{ + // Hide the output panel: + // - false = never + // - number = seconds after completion + // - true = always + "hide_output_panel": 1, + + // Frequency in milliseconds that sftp_monitor_file command checks + // modification time of file. This uses lstat, so it is not an I/O + // intensive operation, especially since the OS has a filesystem cache + "monitoring_frequency": 200, + + // Number of milliseconds to wait after a file change is detected before + // starting the upload. This can help if the old version of a file is + // being uploaded. + "monitoring_upload_delay": 500, + + // If you want to use ftps on Linux you need the ssl module, which does + // not come included with Sublime due to compatiblity issues. I've compiled + // different ssl modules for both 32bit and 64bit and included them. + // You can try enabling this, but if Sublime starts crashing, you know + // what to disable. Sublime must be restarted after changing this setting. + "linux_enable_ssl": false, + + // If the temp folder created for diff operations should be deleted when + // the diff completes. If this is set to false, the user is responsible + // for cleaning up temp folders. This only applies to situations when + // diff_command is set. + "delete_temp_diff_folder": true, + + // If debug output should be printed to the console + // True or 1 outputs FTP/SFTP commands, 2 is more verbose + "debug": false + //,"debug_log_file": "C:\\Users\\Username\\Desktop\\sublime_sftp_debug.txt" + //,"debug_log_file": "/Users/username/Desktop/sublime_sftp_debug.txt" + //,"debug_log_file": "/home/username/Desktop/sublime_sftp_debug.txt" + + // The command line arguments to open an external diff tool. The local file + // path will replace any parameter equal to %1$s and the file path of the + // local temp file representing the remote file will replace any parameter + // equal to %2$s + //,"diff_command": ["/usr/bin/meld", "%1$s", "%2$s"] + //,"diff_command": ["C:\\Program Files (x86)\\WinMerge\\WinMergeU.exe", "%1$s", "%2$s"] + //,"diff_command": ["/usr/bin/opendiff", "%1$s", "%2$s"] + + // On Windows machines, git and hg are often not in the path and if they + // are not in one of the default install locations, their path must be + // specified here for the VCS-based commands to work + //,"git_binary_path": "C:\\Program Files\\Msysgit\\bin\\git.exe" + //,"hg_binary_path": "C:\\Program Files\\Mercurial\\hg.exe" + //,"svn_binary_path": "/usr/bin/svn" + + // On OS X, tabs don't instantly get rendered when opening a file, which + // can have the side effect of the sync_down_on_open setting not properly + // detecting a file open. SFTP uses a slight delay before checking to see + // if a file has been completely opened before syncing down. Depending on + // the machine, it may be necessary to tweak this value if sometimes files + // do not sync down on open. The number of milliseconds to wait after a + // file load event is triggered before checking if the file has a tab. + //,"osx_sync_down_on_open_delay": 500 +} \ No newline at end of file diff --git a/sublime/Packages/SFTP/Side Bar.sublime-menu b/sublime/Packages/SFTP/Side Bar.sublime-menu new file mode 100644 index 0000000..5dcec0e --- /dev/null +++ b/sublime/Packages/SFTP/Side Bar.sublime-menu @@ -0,0 +1,36 @@ +[ + { "caption": "-" }, + { + "caption": "SFTP/FTP", + "children": + [ + { "caption": "Upload File", "command": "sftp_upload_file", "args": {"paths": []} }, + { "caption": "Download File", "command": "sftp_download_file", "args": {"paths": []} }, + { "caption": "-" }, + { "caption": "Upload Folder", "command": "sftp_upload_folder", "args": {"paths": []} }, + { "caption": "Download Folder", "command": "sftp_download_folder", "args": {"paths": []} }, + { "caption": "-" }, + { "caption": "Diff Remote File", "command": "sftp_diff_remote_file", "args": {"paths": []} }, + { "caption": "Rename Local and Remote Files", "command": "sftp_rename_local_and_remote_paths", "args": {"files": []} }, + { "caption": "Rename Local and Remote Folders", "command": "sftp_rename_local_and_remote_paths", "args": {"dirs": []} }, + { "caption": "-" }, + { "caption": "Delete Local and Remote Files", "command": "sftp_delete_local_and_remote_paths", "args": {"files": []} }, + { "caption": "Delete Local and Remote Folders", "command": "sftp_delete_local_and_remote_paths", "args": {"dirs": []} }, + { "caption": "Delete Remote File", "command": "sftp_delete_remote_path", "args": {"files": []} }, + { "caption": "Delete Remote Folder", "command": "sftp_delete_remote_path", "args": {"dirs": []} }, + { "caption": "-" }, + { "caption": "Sync Local -> Remote…", "command": "sftp_sync_up", "args": {"paths": []} }, + { "caption": "Sync Remote -> Local…", "command": "sftp_sync_down", "args": {"paths": []} }, + { "caption": "Sync Both Directions…", "command": "sftp_sync_both", "args": {"paths": []} }, + { "caption": "-" }, + { "caption": "Monitor File (Upload on External Save)", "command": "sftp_monitor_file", "args": {"paths": []} }, + { "caption": "-" }, + { "caption": "Browse Remote…", "command": "sftp_browse", "args": {"paths": []} }, + { "caption": "-" }, + { "caption": "Map to Remote…", "command": "sftp_create_config", "args": {"paths": []} }, + { "caption": "Edit Remote Mapping…", "command": "sftp_edit_config", "args": {"paths": []} }, + { "caption": "Add Alternate Remote Mapping…", "command": "sftp_create_alt_config", "args": {"paths": []} }, + { "caption": "Switch Remote Mapping…", "command": "sftp_switch_config", "args": {"paths": []} } + ] + } +] \ No newline at end of file diff --git a/sublime/Packages/SFTP/Tab Context.sublime-menu b/sublime/Packages/SFTP/Tab Context.sublime-menu new file mode 100644 index 0000000..336fa10 --- /dev/null +++ b/sublime/Packages/SFTP/Tab Context.sublime-menu @@ -0,0 +1,5 @@ +[ + { "caption": "-" }, + { "command": "sftp_upload_file", "args": { "group": -1, "index": -1 }, "caption": "Upload File" }, + { "command": "sftp_upload_open_files", "caption": "Upload Open Files" } +] \ No newline at end of file diff --git a/sublime/Packages/SFTP/lang/clock.json b/sublime/Packages/SFTP/lang/clock.json new file mode 100644 index 0000000..952847e --- /dev/null +++ b/sublime/Packages/SFTP/lang/clock.json @@ -0,0 +1,32 @@ +{ + "C": {"am": 0, "pm": 12}, + "af_ZA": {"vm": 0, "nm": 12}, + "am_ET": {"\u1321\u12cb\u1275": 0, "\u12a8\u1230\u12d3\u1275": 12}, + "bn_BD": {"\u09aa\u09c2\u09b0\u09cd\u09ac\u09be\u09b9\u09cd\u09a3": 0, "\u0985\u09aa\u09b0\u09be\u09b9\u09cd\u09a3": 12}, + "bn_IN": {"\u09aa\u09c2\u09b0\u09cd\u09ac\u09be\u09b9\u09cd\u09a3": 0, "\u0985\u09aa\u09b0\u09be\u09b9\u09cd\u09a3": 12}, + "el_GR": {"\u03c0\u03bc": 0, "\u03bc\u03bc": 12}, + "en_AU": {"am": 0, "pm": 12}, + "en_CA": {"am": 0, "pm": 12}, + "en_GB": {"am": 0, "pm": 12}, + "en_NZ": {"am": 0, "pm": 12}, + "en_US": {"am": 0, "pm": 12}, + "es_CO": {"am": 0, "pm": 12}, + "es_CR": {"am": 0, "pm": 12}, + "es_NI": {"am": 0, "pm": 12}, + "es_PE": {"am": 0, "pm": 12}, + "es_VE": {"am": 0, "pm": 12}, + "he_IL": {"am": 0, "pm": 12}, + "ja_JP": {"\u5348\u524d": 0, "\u5348\u5f8c": 12}, + "km_KH": {"\u1796\u17d2\u179a\u17b9\u1780": 0, "\u179b\u17d2\u1784\u17b6\u1785": 12}, + "ko_KR": {"\uc624\uc804": 0, "\uc624\ud6c4": 12}, + "my_MM": {"\u1014\u1036\u1014\u1000\u103a": 0, "\u100a\u1014\u1031": 12}, + "si_LK": {"\u0db4\u0dd9.\u0dc0": 0, "\u0db4.\u0dc0": 12}, + "sq_AL": {"pd": 0, "md": 12}, + "ta_IN": {"\u0b95\u0bbe\u0bb2\u0bc8": 0, "\u0bae\u0bbe\u0bb2\u0bc8": 12}, + "th_TH": {"am": 0, "pm": 12}, + "ur_PK": {"\u0635": 0, "\u0634": 12}, + "vi_VN": {"am": 0, "pm": 12}, + "zh_CN": {"\u4e0a\u5348": 0, "\u4e0b\u5348": 12}, + "zh_HK": {"\u4e0a\u5348": 0, "\u4e0b\u5348": 12}, + "zh_TW": {"\u4e0a\u5348": 0, "\u4e0b\u5348": 12} +} \ No newline at end of file diff --git a/sublime/Packages/SFTP/lang/months.json b/sublime/Packages/SFTP/lang/months.json new file mode 100644 index 0000000..4e8d085 --- /dev/null +++ b/sublime/Packages/SFTP/lang/months.json @@ -0,0 +1,86 @@ +{ + "C": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "af_ZA": {"jan": 1, "feb": 2, "mrt": 3, "apr": 4, "mei": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "des": 12}, + "am_ET": {"\u1303\u1295\u12e9": 1, "\u134c\u1265\u1229": 2, "\u121b\u122d\u127d": 3, "\u12a4\u1355\u1228": 4, "\u121c\u12ed": 5, "\u1301\u1295": 6, "\u1301\u120b\u12ed": 7, "\u12a6\u1308\u1235": 8, "\u1234\u1355\u1274": 9, "\u12a6\u12ad\u1270": 10, "\u1296\u126c\u121d": 11, "\u12f2\u1234\u121d": 12}, + "ast_ES": {"xin": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "xun": 6, "xnt": 7, "ago": 8, "set": 9, "och": 10, "pay": 11, "avi": 12}, + "bg_BG": {"\u044f\u043d\u0443": 1, "\u0444\u0435\u0432": 2, "\u043c\u0430\u0440": 3, "\u0430\u043f\u0440": 4, "\u043c\u0430\u0439": 5, "\u044e\u043d\u0438": 6, "\u044e\u043b\u0438": 7, "\u0430\u0432\u0433": 8, "\u0441\u0435\u043f": 9, "\u043e\u043a\u0442": 10, "\u043d\u043e\u0435": 11, "\u0434\u0435\u043a": 12}, + "bn_BD": {"\u099c\u09be\u09a8\u09c1": 1, "\u09ab\u09c7\u09ac\u09cd\u09b0\u09c1": 2, "\u09ae\u09be\u09b0\u09cd\u099a": 3, "\u098f\u09aa\u09cd\u09b0\u09bf": 4, "\u09ae\u09c7": 5, "\u099c\u09c1\u09a8": 6, "\u099c\u09c1\u09b2": 7, "\u0986\u0997": 8, "\u09b8\u09c7\u09aa\u09cd\u099f\u09c7": 9, "\u0985\u0995\u09cd\u099f\u09cb": 10, "\u09a8\u09ad\u09c7": 11, "\u09a1\u09bf\u09b8\u09c7": 12}, + "bn_IN": {"\u099c\u09be\u09a8\u09c1\u09df\u09be\u09b0\u09bf": 1, "\u09ab\u09c7\u09ac\u09cd\u09b0\u09c1\u09df\u09be\u09b0\u09bf": 2, "\u09ae\u09be\u09b0\u09cd\u099a": 3, "\u098f\u09aa\u09cd\u09b0\u09bf\u09b2": 4, "\u09ae\u09c7": 5, "\u099c\u09c1\u09a8": 6, "\u099c\u09c1\u09b2\u09be\u0987": 7, "\u0986\u0997\u09b8\u09cd\u099f": 8, "\u09b8\u09c7\u09aa\u09cd\u099f\u09c7\u09ae\u09cd\u09ac\u09b0": 9, "\u0985\u0995\u09cd\u099f\u09cb\u09ac\u09b0": 10, "\u09a8\u09ad\u09c7\u09ae\u09cd\u09ac\u09b0": 11, "\u09a1\u09bf\u09b8\u09c7\u09ae\u09cd\u09ac\u09b0": 12}, + "ca_ES": {"gen": 1, "feb": 2, "mar": 3, "abr": 4, "mai": 5, "jun": 6, "jul": 7, "ago": 8, "set": 9, "oct": 10, "nov": 11, "des": 12}, + "cs_CZ": {"led": 1, "\u00fano": 2, "b\u0159e": 3, "dub": 4, "kv\u011b": 5, "\u010den": 6, "\u010dec": 7, "srp": 8, "z\u00e1\u0159": 9, "\u0159\u00edj": 10, "lis": 11, "pro": 12}, + "cs_CZ2": {"led": 1, "\u00fano": 2, "b\u0159e": 3, "dub": 4, "kv\u011b": 5, "\u010drn": 6, "\u010drc": 7, "srp": 8, "z\u00e1\u0159": 9, "\u0159\u00edj": 10, "lis": 11, "pro": 12}, + "da_DK": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "maj": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "de_AT": {"j\u00e4n": 1, "feb": 2, "m\u00e4r": 3, "apr": 4, "mai": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dez": 12}, + "de_CH": {"jan": 1, "feb": 2, "m\u00e4r": 3, "apr": 4, "mai": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dez": 12}, + "de_DE": {"jan": 1, "feb": 2, "m\u00e4r": 3, "apr": 4, "mai": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dez": 12}, + "el_GR": {"\u0399\u03b1\u03bd": 1, "\u03a6\u03b5\u03b2": 2, "\u039c\u03ac\u03c1": 3, "\u0391\u03c0\u03c1": 4, "\u039c\u03ac\u03b9": 5, "\u0399\u03bf\u03cd\u03bd": 6, "\u0399\u03bf\u03cd\u03bb": 7, "\u0391\u03cd\u03b3": 8, "\u03a3\u03b5\u03c0": 9, "\u039f\u03ba\u03c4": 10, "\u039d\u03bf\u03ad": 11, "\u0394\u03b5\u03ba": 12}, + "en_AU": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "en_CA": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "en_GB": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "en_NZ": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "en_US": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "es_AR": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_CL": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_CO": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_CR": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_DO": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_EC": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_ES": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_GT": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_HN": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_MX": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_NI": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_PA": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_PE": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_PR": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_SV": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_UY": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "es_VE": {"ene": 1, "feb": 2, "mar": 3, "abr": 4, "may": 5, "jun": 6, "jul": 7, "ago": 8, "sep": 9, "oct": 10, "nov": 11, "dic": 12}, + "et_EE": {"jaan": 1, "veebr": 2, "m\u00e4rts": 3, "apr": 4, "mai": 5, "juuni": 6, "juuli": 7, "aug": 8, "sept": 9, "okt": 10, "nov": 11, "dets": 12}, + "eu_ES": {"urt": 1, "ots": 2, "mar": 3, "api": 4, "mai": 5, "eka": 6, "uzt": 7, "abu": 8, "ira": 9, "urr": 10, "aza": 11, "abe": 12}, + "fa_IR": {"\u0698\u0627\u0646\u0648\u06cc\u0647": 1, "\u0641\u0648\u0631\u06cc\u0647": 2, "\u0645\u0627\u0631\u0633": 3, "\u0622\u0648\u0631\u06cc\u0644": 4, "\u0645\u0647": 5, "\u0698\u0648\u0626\u0646": 6, "\u0698\u0648\u0626\u06cc\u0647": 7, "\u0627\u0648\u062a": 8, "\u0633\u067e\u062a\u0627\u0645\u0628\u0631": 9, "\u0627\u0643\u062a\u0628\u0631": 10, "\u0646\u0648\u0627\u0645\u0628\u0631": 11, "\u062f\u0633\u0627\u0645\u0628\u0631": 12}, + "fi_FI": {"tammi\u00a0": 1, "helmi\u00a0": 2, "maalis": 3, "huhti\u00a0": 4, "touko\u00a0": 5, "kes\u00e4\u00a0\u00a0": 6, "hein\u00e4\u00a0": 7, "elo\u00a0\u00a0\u00a0": 8, "syys\u00a0\u00a0": 9, "loka\u00a0\u00a0": 10, "marras": 11, "joulu\u00a0": 12}, + "fr_BE": {"jan": 1, "f\u00e9v": 2, "mar": 3, "avr": 4, "mai": 5, "jun": 6, "jui": 7, "ao\u00fb": 8, "sep": 9, "oct": 10, "nov": 11, "d\u00e9c": 12}, + "fr_CA": {"jan": 1, "f\u00e9v": 2, "mar": 3, "avr": 4, "mai": 5, "jun": 6, "jui": 7, "ao\u00fb": 8, "sep": 9, "oct": 10, "nov": 11, "d\u00e9c": 12}, + "fr_CH": {"jan": 1, "f\u00e9v": 2, "mar": 3, "avr": 4, "mai": 5, "jun": 6, "jui": 7, "ao\u00fb": 8, "sep": 9, "oct": 10, "nov": 11, "d\u00e9c": 12}, + "fr_FR": {"janv": 1, "f\u00e9vr": 2, "mars": 3, "avril": 4, "mai": 5, "juin": 6, "juil": 7, "ao\u00fbt": 8, "sept": 9, "oct": 10, "nov": 11, "d\u00e9c": 12}, + "gl_ES": {"xan": 1, "feb": 2, "mar": 3, "abr": 4, "mai": 5, "xu\u00f1": 6, "xul": 7, "ago": 8, "set": 9, "out": 10, "nov": 11, "dec": 12}, + "he_IL": {"\u05d9\u05e0\u05d5": 1, "\u05e4\u05d1\u05e8": 2, "\u05de\u05e8\u05e5": 3, "\u05d0\u05e4\u05e8": 4, "\u05de\u05d0\u05d9": 5, "\u05d9\u05d5\u05e0": 6, "\u05d9\u05d5\u05dc": 7, "\u05d0\u05d5\u05d2": 8, "\u05e1\u05e4\u05d8": 9, "\u05d0\u05d5\u05e7": 10, "\u05e0\u05d5\u05d1": 11, "\u05d3\u05e6\u05de": 12}, + "hr_HR": {"sij": 1, "vel": 2, "o\u017eu": 3, "tra": 4, "svi": 5, "lip": 6, "srp": 7, "kol": 8, "ruj": 9, "lis": 10, "stu": 11, "pro": 12}, + "hu_HU": {"jan": 1, "febr": 2, "m\u00e1rc": 3, "\u00e1pr": 4, "m\u00e1j": 5, "j\u00fan": 6, "j\u00fal": 7, "aug": 8, "szept": 9, "okt": 10, "nov": 11, "dec": 12}, + "id_ID": {"jan": 1, "peb": 2, "mar": 3, "apr": 4, "mei": 5, "jun": 6, "jul": 7, "agu": 8, "sep": 9, "okt": 10, "nov": 11, "des": 12}, + "it_CH": {"gen": 1, "feb": 2, "mar": 3, "apr": 4, "mag": 5, "giu": 6, "lug": 7, "ago": 8, "set": 9, "ott": 10, "nov": 11, "dic": 12}, + "it_IT": {"gen": 1, "feb": 2, "mar": 3, "apr": 4, "mag": 5, "giu": 6, "lug": 7, "ago": 8, "set": 9, "ott": 10, "nov": 11, "dic": 12}, + "ja_JP": {"1\u6708": 1, "2\u6708": 2, "3\u6708": 3, "4\u6708": 4, "5\u6708": 5, "6\u6708": 6, "7\u6708": 7, "8\u6708": 8, "9\u6708": 9, "10\u6708": 10, "11\u6708": 11, "12\u6708": 12}, + "km_KH": {"\u17e1": 1, "\u17e2": 2, "\u17e3": 3, "\u17e4": 4, "\u17e5": 5, "\u17e6": 6, "\u17e7": 7, "\u17e8": 8, "\u17e9": 9, "\u17e1\u17e0": 10, "\u17e1\u17e1": 11, "\u17e1\u17e2": 12}, + "ko_KR": {"1\uc6d4": 1, "2\uc6d4": 2, "3\uc6d4": 3, "4\uc6d4": 4, "5\uc6d4": 5, "6\uc6d4": 6, "7\uc6d4": 7, "8\uc6d4": 8, "9\uc6d4": 9, "10\uc6d4": 10, "11\uc6d4": 11, "12\uc6d4": 12}, + "lt_LT": {"sau": 1, "vas": 2, "kov": 3, "bal": 4, "geg": 5, "bir": 6, "lie": 7, "rgp": 8, "rgs": 9, "spa": 10, "lap": 11, "grd": 12}, + "lv_LV": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "mai": 5, "j\u016bn": 6, "j\u016bl": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "mk_MK": {"\u0458\u0430\u043d": 1, "\u0444\u0435\u0432": 2, "\u043c\u0430\u0440": 3, "\u0430\u043f\u0440": 4, "\u043c\u0430\u0458": 5, "\u0458\u0443\u043d": 6, "\u0458\u0443\u043b": 7, "\u0430\u0432\u0433": 8, "\u0441\u0435\u043f": 9, "\u043e\u043a\u0442": 10, "\u043d\u043e\u0435": 11, "\u0434\u0435\u043a": 12}, + "ms_MY": {"jan": 1, "feb": 2, "mac": 3, "apr": 4, "mei": 5, "jun": 6, "jul": 7, "ogos": 8, "sep": 9, "okt": 10, "nov": 11, "dis": 12}, + "my_MM": {"\u1007\u1014\u103a": 1, "\u1016\u1031": 2, "\u1019\u1010\u103a": 3, "\u1027\u1015\u103c\u102e": 4, "\u1019\u1031": 5, "\u1007\u103d\u1014\u103a": 6, "\u1007\u1030": 7, "\u1029": 8, "\u1005\u1000\u103a": 9, "\u1021\u1031\u102c\u1000\u103a": 10, "\u1014\u102d\u102f": 11, "\u1012\u102e": 12}, + "nb_NO": {"jan": 1, "feb": 2, "mars": 3, "april": 4, "mai": 5, "juni": 6, "juli": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "des": 12}, + "nds_DE": {"jan": 1, "feb": 2, "m\u00e4r": 3, "apr": 4, "mai": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dez": 12}, + "nl_BE": {"jan": 1, "feb": 2, "mrt": 3, "apr": 4, "mei": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "nl_NL": {"jan": 1, "feb": 2, "mrt": 3, "apr": 4, "mei": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "nn_NO": {"jan": 1, "feb": 2, "mars": 3, "april": 4, "mai": 5, "juni": 6, "juli": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "des": 12}, + "pl_PL": {"sty": 1, "lut": 2, "mar": 3, "kwi": 4, "maj": 5, "cze": 6, "lip": 7, "sie": 8, "wrz": 9, "pa\u017a": 10, "lis": 11, "gru": 12}, + "pt_BR": {"jan": 1, "fev": 2, "mar": 3, "abr": 4, "mai": 5, "jun": 6, "jul": 7, "ago": 8, "set": 9, "out": 10, "nov": 11, "dez": 12}, + "pt_PT": {"jan": 1, "fev": 2, "mar": 3, "abr": 4, "mai": 5, "jun": 6, "jul": 7, "ago": 8, "set": 9, "out": 10, "nov": 11, "dez": 12}, + "ro_RO": {"ian": 1, "feb": 2, "mar": 3, "apr": 4, "mai": 5, "iun": 6, "iul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12}, + "ru_RU": {"\u044f\u043d\u0432": 1, "\u0444\u0435\u0432\u0440": 2, "\u043c\u0430\u0440\u0442\u0430": 3, "\u0430\u043f\u0440": 4, "\u043c\u0430\u044f": 5, "\u0438\u044e\u043d\u044f": 6, "\u0438\u044e\u043b\u044f": 7, "\u0430\u0432\u0433": 8, "\u0441\u0435\u043d\u0442": 9, "\u043e\u043a\u0442": 10, "\u043d\u043e\u044f\u0431": 11, "\u0434\u0435\u043a": 12}, + "si_LK": {"\u0da2\u0db1": 1, "\u0db4\u0dd9\u0db6": 2, "\u0db8\u0dcf\u0dbb\u0dca": 3, "\u0d85\u0db4\u0dca\u200d\u0dbb\u0dd2": 4, "\u0db8\u0dd0\u0dba\u0dd2": 5, "\u0da2\u0dd6\u0db1\u0dd2": 6, "\u0da2\u0dd6\u0dbd\u0dd2": 7, "\u0d85\u0d9c\u0ddd": 8, "\u0dc3\u0dd0\u0db4\u0dca": 9, "\u0d94\u0d9a\u0dca": 10, "\u0db1\u0dd9\u0dc0\u0dd0": 11, "\u0daf\u0dd9\u0dc3\u0dd0": 12}, + "sk_SK": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "m\u00e1j": 5, "j\u00fan": 6, "j\u00fal": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "sl_SI": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "maj": 5, "jun": 6, "jul": 7, "avg": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "sq_AL": {"jan": 1, "shk": 2, "mar": 3, "pri": 4, "maj": 5, "qer": 6, "kor": 7, "gsh": 8, "sht": 9, "tet": 10, "n\u00ebn": 11, "dhj": 12}, + "sr_RS": {"\u0458\u0430\u043d": 1, "\u0444\u0435\u0431": 2, "\u043c\u0430\u0440": 3, "\u0430\u043f\u0440": 4, "\u043c\u0430\u0458": 5, "\u0458\u0443\u043d": 6, "\u0458\u0443\u043b": 7, "\u0430\u0432\u0433": 8, "\u0441\u0435\u043f": 9, "\u043e\u043a\u0442": 10, "\u043d\u043e\u0432": 11, "\u0434\u0435\u0446": 12}, + "sv_SE": {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "maj": 5, "jun": 6, "jul": 7, "aug": 8, "sep": 9, "okt": 10, "nov": 11, "dec": 12}, + "ta_IN": {"\u0b9c\u0ba9": 1, "\u0baa\u0bbf\u0baa\u0bcd": 2, "\u0bae\u0bbe\u0bb0\u0bcd": 3, "\u0b8f\u0baa\u0bcd": 4, "\u0bae\u0bc7": 5, "\u0b9c\u0bc2\u0ba9\u0bcd": 6, "\u0b9c\u0bc2\u0bb2\u0bc8": 7, "\u0b86\u0b95": 8, "\u0b9a\u0bc6\u0baa\u0bcd": 9, "\u0b85\u0b95\u0bcd": 10, "\u0ba8\u0bb5": 11, "\u0b9f\u0bbf\u0b9a": 12}, + "th_TH": {"\u0e21.\u0e04": 1, "\u0e01.\u0e1e": 2, "\u0e21\u0e35.\u0e04": 3, "\u0e40\u0e21.\u0e22": 4, "\u0e1e.\u0e04": 5, "\u0e21\u0e34.\u0e22": 6, "\u0e01.\u0e04": 7, "\u0e2a.\u0e04": 8, "\u0e01.\u0e22": 9, "\u0e15.\u0e04": 10, "\u0e1e.\u0e22": 11, "\u0e18.\u0e04": 12}, + "uk_UA": {"\u0441\u0456\u0447": 1, "\u043b\u044e\u0442": 2, "\u0431\u0435\u0440": 3, "\u043a\u0432\u0456": 4, "\u0442\u0440\u0430": 5, "\u0447\u0435\u0440": 6, "\u043b\u0438\u043f": 7, "\u0441\u0435\u0440": 8, "\u0432\u0435\u0440": 9, "\u0436\u043e\u0432": 10, "\u043b\u0438\u0441": 11, "\u0433\u0440\u0443": 12}, + "ur_PK": {"\u062c\u0646\u0648\u0631\u064a": 1, "\u0641\u0631\u0648\u0631\u064a": 2, "\u0645\u0627\u0631\u0686": 3, "\u0627\u067e\u0631\u064a\u0644": 4, "\u0645\u0653\u06cc": 5, "\u062c\u0648\u0646": 6, "\u062c\u0648\u0644\u0627\u064a": 7, "\u0627\u06af\u0633\u062a": 8, "\u0633\u062a\u0645\u0628\u0631": 9, "\u0627\u0643\u062a\u0648\u0628\u0631": 10, "\u0646\u0648\u0645\u0628\u0631": 11, "\u062f\u0633\u0645\u0628\u0631": 12}, + "vi_VN": {"th01": 1, "th02": 2, "th03": 3, "th04": 4, "th05": 5, "th06": 6, "th07": 7, "th08": 8, "th09": 9, "th10": 10, "th11": 11, "th12": 12}, + "zh_CN": {"1\u6708": 1, "2\u6708": 2, "3\u6708": 3, "4\u6708": 4, "5\u6708": 5, "6\u6708": 6, "7\u6708": 7, "8\u6708": 8, "9\u6708": 9, "10\u6708": 10, "11\u6708": 11, "12\u6708": 12}, + "zh_HK": {"1\u6708": 1, "2\u6708": 2, "3\u6708": 3, "4\u6708": 4, "5\u6708": 5, "6\u6708": 6, "7\u6708": 7, "8\u6708": 8, "9\u6708": 9, "10\u6708": 10, "11\u6708": 11, "12\u6708": 12}, + "zh_TW": {"1\u6708": 1, "2\u6708": 2, "3\u6708": 3, "4\u6708": 4, "5\u6708": 5, "6\u6708": 6, "7\u6708": 7, "8\u6708": 8, "9\u6708": 9, "10\u6708": 10, "11\u6708": 11, "12\u6708": 12} +} \ No newline at end of file diff --git a/sublime/Packages/SFTP/lib/linux-x32/libssl-0.9.8/_ssl.so b/sublime/Packages/SFTP/lib/linux-x32/libssl-0.9.8/_ssl.so new file mode 100644 index 0000000..8e3ac9a Binary files /dev/null and b/sublime/Packages/SFTP/lib/linux-x32/libssl-0.9.8/_ssl.so differ diff --git a/sublime/Packages/SFTP/lib/linux-x32/libssl-1.0.0/_ssl.so b/sublime/Packages/SFTP/lib/linux-x32/libssl-1.0.0/_ssl.so new file mode 100644 index 0000000..1ff704b Binary files /dev/null and b/sublime/Packages/SFTP/lib/linux-x32/libssl-1.0.0/_ssl.so differ diff --git a/sublime/Packages/SFTP/lib/linux-x32/libssl-10/_ssl.so b/sublime/Packages/SFTP/lib/linux-x32/libssl-10/_ssl.so new file mode 100644 index 0000000..d28147b Binary files /dev/null and b/sublime/Packages/SFTP/lib/linux-x32/libssl-10/_ssl.so differ diff --git a/sublime/Packages/SFTP/lib/linux-x64/libssl-0.9.8/_ssl.so b/sublime/Packages/SFTP/lib/linux-x64/libssl-0.9.8/_ssl.so new file mode 100644 index 0000000..83501ef Binary files /dev/null and b/sublime/Packages/SFTP/lib/linux-x64/libssl-0.9.8/_ssl.so differ diff --git a/sublime/Packages/SFTP/lib/linux-x64/libssl-1.0.0/_ssl.so b/sublime/Packages/SFTP/lib/linux-x64/libssl-1.0.0/_ssl.so new file mode 100644 index 0000000..697f33a Binary files /dev/null and b/sublime/Packages/SFTP/lib/linux-x64/libssl-1.0.0/_ssl.so differ diff --git a/sublime/Packages/SFTP/lib/linux-x64/libssl-10/_ssl.so b/sublime/Packages/SFTP/lib/linux-x64/libssl-10/_ssl.so new file mode 100644 index 0000000..70622d4 Binary files /dev/null and b/sublime/Packages/SFTP/lib/linux-x64/libssl-10/_ssl.so differ diff --git a/sublime/Packages/SFTP/lib/linux/ssl.py b/sublime/Packages/SFTP/lib/linux/ssl.py new file mode 100644 index 0000000..4db47ca --- /dev/null +++ b/sublime/Packages/SFTP/lib/linux/ssl.py @@ -0,0 +1,437 @@ +# Wrapper module for _ssl, providing some additional facilities +# implemented in Python. Written by Bill Janssen. + +"""\ +This module provides some more Pythonic support for SSL. + +Object types: + + SSLSocket -- subtype of socket.socket which does SSL over the socket + +Exceptions: + + SSLError -- exception raised for I/O errors + +Functions: + + cert_time_to_seconds -- convert time string used for certificate + notBefore and notAfter functions to integer + seconds past the Epoch (the time values + returned from time.time()) + + fetch_server_certificate (HOST, PORT) -- fetch the certificate provided + by the server running on HOST at port PORT. No + validation of the certificate is performed. + +Integer constants: + +SSL_ERROR_ZERO_RETURN +SSL_ERROR_WANT_READ +SSL_ERROR_WANT_WRITE +SSL_ERROR_WANT_X509_LOOKUP +SSL_ERROR_SYSCALL +SSL_ERROR_SSL +SSL_ERROR_WANT_CONNECT + +SSL_ERROR_EOF +SSL_ERROR_INVALID_ERROR_CODE + +The following group define certificate requirements that one side is +allowing/requiring from the other side: + +CERT_NONE - no certificates from the other side are required (or will + be looked at if provided) +CERT_OPTIONAL - certificates are not required, but if provided will be + validated, and if validation fails, the connection will + also fail +CERT_REQUIRED - certificates are required, and will be validated, and + if validation fails, the connection will also fail + +The following constants identify various SSL protocol variants: + +PROTOCOL_SSLv2 +PROTOCOL_SSLv3 +PROTOCOL_SSLv23 +PROTOCOL_TLSv1 +""" + +import textwrap + +import _ssl # if we can't import it, let the error propagate + +from _ssl import SSLError +from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED +from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +from _ssl import RAND_status, RAND_egd, RAND_add +from _ssl import \ + SSL_ERROR_ZERO_RETURN, \ + SSL_ERROR_WANT_READ, \ + SSL_ERROR_WANT_WRITE, \ + SSL_ERROR_WANT_X509_LOOKUP, \ + SSL_ERROR_SYSCALL, \ + SSL_ERROR_SSL, \ + SSL_ERROR_WANT_CONNECT, \ + SSL_ERROR_EOF, \ + SSL_ERROR_INVALID_ERROR_CODE + +from socket import socket, _fileobject, _delegate_methods +from socket import error as socket_error +from socket import getnameinfo as _getnameinfo +import base64 # for DER-to-PEM translation +import errno + +class SSLSocket(socket): + + """This class implements a subtype of socket.socket that wraps + the underlying OS socket in an SSL context when necessary, and + provides read and write methods over that channel.""" + + def __init__(self, sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, + suppress_ragged_eofs=True): + socket.__init__(self, _sock=sock._sock) + # The initializer for socket overrides the methods send(), recv(), etc. + # in the instancce, which we don't need -- but we want to provide the + # methods defined in SSLSocket. + for attr in _delegate_methods: + try: + delattr(self, attr) + except AttributeError: + pass + + if certfile and not keyfile: + keyfile = certfile + # see if it's connected + try: + socket.getpeername(self) + except socket_error, e: + if e.errno != errno.ENOTCONN: + raise + # no, no connection yet + self._sslobj = None + else: + # yes, create the SSL object + self._sslobj = _ssl.sslwrap(self._sock, server_side, + keyfile, certfile, + cert_reqs, ssl_version, ca_certs) + if do_handshake_on_connect: + self.do_handshake() + self.keyfile = keyfile + self.certfile = certfile + self.cert_reqs = cert_reqs + self.ssl_version = ssl_version + self.ca_certs = ca_certs + self.do_handshake_on_connect = do_handshake_on_connect + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + + def read(self, len=1024): + + """Read up to LEN bytes and return them. + Return zero-length string on EOF.""" + + try: + return self._sslobj.read(len) + except SSLError, x: + if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: + return '' + else: + raise + + def write(self, data): + + """Write DATA to the underlying SSL channel. Returns + number of bytes of DATA actually transmitted.""" + + return self._sslobj.write(data) + + def getpeercert(self, binary_form=False): + + """Returns a formatted version of the data in the + certificate provided by the other end of the SSL channel. + Return None if no certificate was provided, {} if a + certificate was provided, but not validated.""" + + return self._sslobj.peer_certificate(binary_form) + + def cipher(self): + + if not self._sslobj: + return None + else: + return self._sslobj.cipher() + + def send(self, data, flags=0): + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to send() on %s" % + self.__class__) + while True: + try: + v = self._sslobj.write(data) + except SSLError, x: + if x.args[0] == SSL_ERROR_WANT_READ: + return 0 + elif x.args[0] == SSL_ERROR_WANT_WRITE: + return 0 + else: + raise + else: + return v + else: + return socket.send(self, data, flags) + + def sendto(self, data, addr, flags=0): + if self._sslobj: + raise ValueError("sendto not allowed on instances of %s" % + self.__class__) + else: + return socket.sendto(self, data, addr, flags) + + def sendall(self, data, flags=0): + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to sendall() on %s" % + self.__class__) + amount = len(data) + count = 0 + while (count < amount): + v = self.send(data[count:]) + count += v + return amount + else: + return socket.sendall(self, data, flags) + + def recv(self, buflen=1024, flags=0): + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to recv() on %s" % + self.__class__) + return self.read(buflen) + else: + return socket.recv(self, buflen, flags) + + def recv_into(self, buffer, nbytes=None, flags=0): + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: + nbytes = 1024 + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to recv_into() on %s" % + self.__class__) + tmp_buffer = self.read(nbytes) + v = len(tmp_buffer) + buffer[:v] = tmp_buffer + return v + else: + return socket.recv_into(self, buffer, nbytes, flags) + + def recvfrom(self, addr, buflen=1024, flags=0): + if self._sslobj: + raise ValueError("recvfrom not allowed on instances of %s" % + self.__class__) + else: + return socket.recvfrom(self, addr, buflen, flags) + + def recvfrom_into(self, buffer, nbytes=None, flags=0): + if self._sslobj: + raise ValueError("recvfrom_into not allowed on instances of %s" % + self.__class__) + else: + return socket.recvfrom_into(self, buffer, nbytes, flags) + + def pending(self): + if self._sslobj: + return self._sslobj.pending() + else: + return 0 + + def unwrap(self): + if self._sslobj: + s = self._sslobj.shutdown() + self._sslobj = None + return s + else: + raise ValueError("No SSL wrapper around " + str(self)) + + def shutdown(self, how): + self._sslobj = None + socket.shutdown(self, how) + + def close(self): + if self._makefile_refs < 1: + self._sslobj = None + socket.close(self) + else: + self._makefile_refs -= 1 + + def do_handshake(self): + + """Perform a TLS/SSL handshake.""" + + self._sslobj.do_handshake() + + def connect(self, addr): + + """Connects to remote ADDR, and then wraps the connection in + an SSL channel.""" + + # Here we assume that the socket is client-side, and not + # connected at the time of the call. We connect it, then wrap it. + if self._sslobj: + raise ValueError("attempt to connect already-connected SSLSocket!") + socket.connect(self, addr) + self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, + self.cert_reqs, self.ssl_version, + self.ca_certs) + if self.do_handshake_on_connect: + self.do_handshake() + + def accept(self): + + """Accepts a new connection from a remote client, and returns + a tuple containing that new connection wrapped with a server-side + SSL channel, and the address of the remote client.""" + + newsock, addr = socket.accept(self) + return (SSLSocket(newsock, + keyfile=self.keyfile, + certfile=self.certfile, + server_side=True, + cert_reqs=self.cert_reqs, + ssl_version=self.ssl_version, + ca_certs=self.ca_certs, + do_handshake_on_connect=self.do_handshake_on_connect, + suppress_ragged_eofs=self.suppress_ragged_eofs), + addr) + + def makefile(self, mode='r', bufsize=-1): + + """Make and return a file-like object that + works with the SSL connection. Just use the code + from the socket module.""" + + self._makefile_refs += 1 + # close=True so as to decrement the reference count when done with + # the file-like object. + return _fileobject(self, mode, bufsize, close=True) + + + +def wrap_socket(sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, + suppress_ragged_eofs=True): + + return SSLSocket(sock, keyfile=keyfile, certfile=certfile, + server_side=server_side, cert_reqs=cert_reqs, + ssl_version=ssl_version, ca_certs=ca_certs, + do_handshake_on_connect=do_handshake_on_connect, + suppress_ragged_eofs=suppress_ragged_eofs) + + +# some utility functions + +def cert_time_to_seconds(cert_time): + + """Takes a date-time string in standard ASN1_print form + ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return + a Python time value in seconds past the epoch.""" + + import time + return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT")) + +PEM_HEADER = "-----BEGIN CERTIFICATE-----" +PEM_FOOTER = "-----END CERTIFICATE-----" + +def DER_cert_to_PEM_cert(der_cert_bytes): + + """Takes a certificate in binary DER format and returns the + PEM version of it as a string.""" + + if hasattr(base64, 'standard_b64encode'): + # preferred because older API gets line-length wrong + f = base64.standard_b64encode(der_cert_bytes) + return (PEM_HEADER + '\n' + + textwrap.fill(f, 64) + '\n' + + PEM_FOOTER + '\n') + else: + return (PEM_HEADER + '\n' + + base64.encodestring(der_cert_bytes) + + PEM_FOOTER + '\n') + +def PEM_cert_to_DER_cert(pem_cert_string): + + """Takes a certificate in ASCII PEM format and returns the + DER-encoded version of it as a byte sequence""" + + if not pem_cert_string.startswith(PEM_HEADER): + raise ValueError("Invalid PEM encoding; must start with %s" + % PEM_HEADER) + if not pem_cert_string.strip().endswith(PEM_FOOTER): + raise ValueError("Invalid PEM encoding; must end with %s" + % PEM_FOOTER) + d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)] + return base64.decodestring(d) + +def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None): + + """Retrieve the certificate from the server at the specified address, + and return it as a PEM-encoded string. + If 'ca_certs' is specified, validate the server cert against it. + If 'ssl_version' is specified, use it in the connection attempt.""" + + host, port = addr + if (ca_certs is not None): + cert_reqs = CERT_REQUIRED + else: + cert_reqs = CERT_NONE + s = wrap_socket(socket(), ssl_version=ssl_version, + cert_reqs=cert_reqs, ca_certs=ca_certs) + s.connect(addr) + dercert = s.getpeercert(True) + s.close() + return DER_cert_to_PEM_cert(dercert) + +def get_protocol_name(protocol_code): + if protocol_code == PROTOCOL_TLSv1: + return "TLSv1" + elif protocol_code == PROTOCOL_SSLv23: + return "SSLv23" + elif protocol_code == PROTOCOL_SSLv3: + return "SSLv3" + else: + return "" + + +# a replacement for the old socket.ssl function + +def sslwrap_simple(sock, keyfile=None, certfile=None): + + """A replacement for the old socket.ssl function. Designed + for compability with Python 2.5 and earlier. Will disappear in + Python 3.0.""" + + if hasattr(sock, "_sock"): + sock = sock._sock + + ssl_sock = _ssl.sslwrap(sock, 0, keyfile, certfile, CERT_NONE, + PROTOCOL_SSLv23, None) + try: + sock.getpeername() + except: + # no, no connection yet + pass + else: + # yes, do the handshake + ssl_sock.do_handshake() + + return ssl_sock diff --git a/sublime/Packages/SFTP/license.txt b/sublime/Packages/SFTP/license.txt new file mode 100644 index 0000000..3c1e38f --- /dev/null +++ b/sublime/Packages/SFTP/license.txt @@ -0,0 +1,33 @@ +Software contained in the "bin" directory is subject to the licenses in the +"licenses" subdirectory. "sftp/ftplib2.pyc" is subject to the +"python_license.txt" in this directory. All other files are subject to the +following copyright. + +-------- + +Sublime SFTP +Copyright (c) 2011-2012 William Bond + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software to use it for an evaluation period for the purpose of +testing prior to purchase. + +Extended use of Sublime SFTP requires a license, which can be purchased from +http://sublime.wbond.net. Any person who has purchased a license from William +Bond and enters the provided product key is granted use of Sublime SFTP on +any number of computers, of any supported operating system. Licences are +valid for only a single person, and are valid for all upgrades to the +major version purchased. For example, purchasing a license for version 1.1 will +allow for free upgrades until version 2.0. + +Redistribution, modification, merging, publication, distribution, sublicensing, +and/or selling copies of Sublime SFTP is prohibited. Please contact +support@wbond.net with any questions. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/sublime/Packages/SFTP/messages.json b/sublime/Packages/SFTP/messages.json new file mode 100644 index 0000000..3bac59c --- /dev/null +++ b/sublime/Packages/SFTP/messages.json @@ -0,0 +1,11 @@ +{ + "install": "messages/install.txt", + "1.10.0": "messages/1.10.0.txt", + "1.9.0": "messages/1.9.0.txt", + "1.8.0": "messages/1.8.0.txt", + "1.7.0": "messages/1.7.0.txt", + "1.6.0": "messages/1.6.0.txt", + "1.5.0": "messages/1.5.0.txt", + "1.4.0": "messages/1.4.0.txt", + "1.3.0": "messages/1.3.0.txt" +} \ No newline at end of file diff --git a/sublime/Packages/SFTP/messages/1.10.0.txt b/sublime/Packages/SFTP/messages/1.10.0.txt new file mode 100644 index 0000000..caa65a9 --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.10.0.txt @@ -0,0 +1,86 @@ +Sublime SFTP 1.10.0 Changelog: + +New Features + + - Added the "extra_list_connections" setting which allows spawning multiple + connections to the server for vastly improved performance when determining + files to be synced. + + This setting is set to the number of additional connections to open, and is + ONLY used for the list operation that is perfomed when determining what files + should be synced. + + - The "Chmod" operation is now available for files and folders when browsing a + remote + + - Added the "keepalive" setting for users who experience frequent disconnects. + + This will send a command to the server every specified number of seconds in + an effort to keep the connection open. + + - File ignoring is now slightly simpler - the "ignore_regex" setting has been + deprecated, and replaced with "ignore_regexes", which is a list of smaller + regular expressions. This should make adding file and folder paths easier. + + - Sync commands now perform file operations in a specific order for users that + perform deployments via sync: + + 1. Upload/download new files + 2. Upload/download existing files + 3. Remove old files + + - Added a new version of psftp.exe on Windows that supports the -s flag via + "sftp_flags" to allow a custom subsystem to be specified + + - Changed SFTP connections on OS X and Linux to use compression by default for + better performance + + - The ignore regex patterns are now checked against both Linux/OS X and + Windows style file and folder paths so users may more easily write ignore + rules that must work across different operating systems + + +Bug Fixes + + - Added multiple new file listing formats, including support for IIS FTP v7.5 + and IIS servers that respond with four digit years + + - Tweaked the delay of performing the "sync_down_on_open" feature on OS X in + order to ensure that it happens. Also added a new editor-wide setting + called "osx_sync_down_on_open_delay" that allows tweaking the delay for + users still experiencing issues. + + - Fixed an issue where in specific situations the root folder of a sync would + be listed twice when using the FTP protocol + + - Added error handling for encoding errors + + - Fixed an issue on OS X where an sftp-config.json file in a folder with a + non-ASCII character would cause mapping to be broken, and the remote path + to be the same as the local path + + - Added error handling for errors when checking symlinks on certain FTP servers + + - Added trapping for multiple errors related to re-opening Sublime with a + remote file after the local operating system and wiped the temp directory + + - Added checks for remote files that were opened on a copy of Sublime Text + that has been synced between two different machines (such as via Dropbox) + where temp folders are incompatible (e.g. Windows vs Linux/OS X) + + - Fixed a bug with NotFoundErrors when trying to reset the local working + directory after a remote operation + + - Fixed an error with downloading a symlinked file when + "preserve_modiciation_times" is set to true + + - Added another FTP passive mode error handler condition + + - Resolved a working directory (pwd) error caused by the Tornado-vxWorks fix + from v1.9.7 + + - Added a check for disk full messages + + - Added support for a new (previously unreported) FTP password prompt + + - The "sftp_flags" setting now accepts a list by default instead of a string diff --git a/sublime/Packages/SFTP/messages/1.3.0.txt b/sublime/Packages/SFTP/messages/1.3.0.txt new file mode 100644 index 0000000..6e52fcd --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.3.0.txt @@ -0,0 +1,21 @@ +Sublime SFTP 1.3.0 Changelog: + +** Backwards Compatibility Breaks ** + - Changed OS X key bindings to use Ctrl+Cmd instead of Cmd+Alt + - The commands sftp_file and sftp_file_context were merged into a new command + sftp_upload_file. Custom key bindings will need to be updated to reference + this new command name. + +New Features + - Added the ability to download individual files + - Added the ability to diff a file with the remote version + - Diffs are generated and viewed in ST2 by default, but the diff_command + setting may be used for an external diff viewer + - Ignores .DS_Store, Thumbs.db, sftp-settings.json and desktop.ini by default + +Bug Fixes + - Added support for SSH keys with passphrases on Windows when the key file is + specified via the ssh_key_file setting + - Improved Cancel command to work consistently, even if triggered in between + two files being uploaded during a directory upload + - Fixed a number of small errors that showed on the console \ No newline at end of file diff --git a/sublime/Packages/SFTP/messages/1.4.0.txt b/sublime/Packages/SFTP/messages/1.4.0.txt new file mode 100644 index 0000000..4ae8db0 --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.4.0.txt @@ -0,0 +1,14 @@ +Sublime SFTP 1.4.0 Changelog: + +New Features + - Added FTP protocol support + - Updated the plugin to automatically retry operations when a + disconnection occurs + +Bug Fixes + - Fixed handling of diffs on Windows for files not in the + root of the remote + - Made SFTP remote folder list parsing more robust when Sublime + is run on a machine with a different locale than the server + - Fixed issue with connecting to an SFTP server for the + first time on Windows \ No newline at end of file diff --git a/sublime/Packages/SFTP/messages/1.5.0.txt b/sublime/Packages/SFTP/messages/1.5.0.txt new file mode 100644 index 0000000..d526aa4 --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.5.0.txt @@ -0,0 +1,21 @@ +Sublime SFTP 1.5.0 Changelog: + +Please be sure to restart Sublime Text 2 to start using this new version. + +** Backwards Compatibility Breaks ** + - Global "timeout" setting was moved to sftp-settings.json and renamed to + "connect_timeout" + - Global "save_before_upload" setting was moved to sftp-settings.json + +New Features + - Added sync functionality - see side bar and context menus + - Rewrote FTP backend to be faster and use one connection instead of two + - Changed initial remote configuration into a snippet, allowing for navigation + between settings via the tab key + - Added timestamps to debug messages + +Bug Fixes + - Fixed handling of idle timeouts for FTP on all platforms and SFTP on Windows + - Fixed display of connection timeouts for Windows SFTP connections + - Fixed a bug with Save All not uploading all documents when upload_on_save + is set to true diff --git a/sublime/Packages/SFTP/messages/1.6.0.txt b/sublime/Packages/SFTP/messages/1.6.0.txt new file mode 100644 index 0000000..a6de576 --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.6.0.txt @@ -0,0 +1,13 @@ +Sublime SFTP 1.6.0 Changelog: + +Please be sure to restart Sublime Text 2 to start using this new version. + +New Features + - Added remote browsing functionality - see File menu for standalone browsing, + or use the context menus for existing local projects. Open + Preferences > Package Settings > SFTP > Key Bindings - Default to see + the new key bindings. + +Bug Fixes + - More idle timeout fixes for FTP + - Fixed download of 0-byte files via FTP diff --git a/sublime/Packages/SFTP/messages/1.7.0.txt b/sublime/Packages/SFTP/messages/1.7.0.txt new file mode 100644 index 0000000..d7c9b3c --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.7.0.txt @@ -0,0 +1,89 @@ +Sublime SFTP 1.7.0 Changelog: + +Please be sure to restart Sublime Text 2 to start using this new version. + +** Backwards Compatibility Breaks ** + + - Newly created remote configs will be called sftp-config.json instead of + sftp-settings.json. You may need to update your VCS ignore settings. + Existing sftp-settings.json files will continue to function. + + - The sftp_remotes folder in the Packages/User/ folder has been renamed to + sftp_servers. You may need to update your VCS ignore settings. + + - The following commands were renamed: + sftp_browse_remote -> sftp_browse_server + sftp_edit_remote -> sftp_edit_server + sftp_delete_remote -> sftp_delete_server + Custom key bindings may need to be updated. + +New Features + + - Added sync_down_on_open setting that will prompt to download the remote + version of a file when opening a file, if the remote version is newer. + + - Added confirm_overwrite_newer setting that will prompt if the file being + uploaded is older than the file on the server. This only affects single + file uploads and causes uploads to be a little slower since a remote + file listing is required on each upload. + + - Added Monitor File command that will periodically check file modification + time and upload the file if it changes. This is intended to work with + programs such as CodeKit and CSS compilers that will modify a + file externally to Sublime. Frequency of checks can be controlled via + SFTP settings. + + - Added preserve_modification_times setting to preserve the modification time + of files when uploading and downloading. This does not work on all servers. + The plugin will notify if a server is incompatible. Can be set to + "download_only" if remote/server does not support it. + + - Added password prompting with asterisk password hiding, eliminating the + requirement of saving passwords + + - Added context menu entry to delete the remote version of a file + + - Added context menu entry to rename the local and remote versions of a file + + - Default remote/server configuration can now be edited by copying the file + Packages/SFTP/SFTP.default-config to Packages/User/ and customizing + + - Restructured the menus to have a single entry labelled SFTP/FTP in + the file menu, side bar content menu and editor context menu + + - Changed Windows to use Sublime Text interface for SSH key passphrase + entry instead of Pageant + + - Improved performance of reconnecting after a disconnect when the + remote_time_offset_in_hours setting is not set + + - Added uncaught exception handling to help debugging unreported errors + +Bug Fixes + + - Added checks for required configuration information to prevent + silent failures + + - Fixed a bug with deleting remote folders that would cause a not found error + + - Added a missing Upload Folder entry to the side bar context menu + + - Now properly parses MS FTP server file listings that include file + names with spaces + + - Fixed a crash on some OS X machines when using upload_on_save or + editing remote files + + - Changed passphrase prompting on Windows to not disappear after one second + + - Activity indicator in status area is properly cleared after uploading a + file via its preview + + - Fixed sync commands to function properly when syncing a single file and + perform only a single file listing when syncing a single file + + - Fixed a bug with sync operations disconnecting while listing local files + for SFTP remote with short idle timeout and many local folders + + - Updated plugin to ignore .DS_Store, desktop.ini and Thumbs.db files in + the Packages/User/sftp_servers folder to prevent parsing errors diff --git a/sublime/Packages/SFTP/messages/1.8.0.txt b/sublime/Packages/SFTP/messages/1.8.0.txt new file mode 100644 index 0000000..31f5af7 --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.8.0.txt @@ -0,0 +1,26 @@ +Sublime SFTP 1.8.0 Changelog: + +New Features + + - Added FTPS support + + Sublime Text does not include SSL support for Linux builds due to the + different versions of OpenSSL. Linux users may enable experimental ftps + support by opening Preferences > Package Settings > SFTP > Settings - User + and setting "linux_enable_ssl": true. + + Once Sublime Text is restarted, Sublime SFTP will attempt to load one of + several pre-compiled _ssl modules. The console will contain debug + information. If for some reason Sublime is unstable with this enabled, + please set "linux_enable_ssl": false and contact support@wbond.net for + help in compiling a custom _ssl.so for Python 2.6.6. + + +Bug Fixes + + - Fixed the SFTP > Map to Remote... menu entry in the editor context menu + + - Fixed parsing of directory listings with users or group names containing + a space character + + - Improved compatibility with Filezilla Server diff --git a/sublime/Packages/SFTP/messages/1.9.0.txt b/sublime/Packages/SFTP/messages/1.9.0.txt new file mode 100644 index 0000000..47621da --- /dev/null +++ b/sublime/Packages/SFTP/messages/1.9.0.txt @@ -0,0 +1,41 @@ +Sublime SFTP 1.9.0 Changelog: + +New Features + + - Added support for multiple remote configurations and switching them + + New menu items were added to the side bar and editor context menus and the + command palette to Add Alternate Remote Mapping... and Switch Remote + Mapping... + + This functionality is intended for users who need to upload from the same + local folder to multiple remote environments. It is not possible, however, + to upload to multiple environments simultaneously - the remote mapping must + be switched and the files/folders uploaded to each in turn. + + - Added the Delete Local and Remote Files/Folders menu entries to the side bar + and editor context menus and the command palette + + - Added confirm_downloads option to sftp-config.json files + + +Bug Fixes + + - Fixed the sync_down_on_open setting to obey the ignore_regex setting + + - Fixed a bug with FTP disconnections sometimes causing crashes on OS X + + - Added the cs_CZ2 remote_locale for servers using slightly different Czech + month name abbreviations + + - Fixed handling of files and folder names that consist only of a space, or + that end with a space + + - Corrected a bug where a connection error while performing a sync would + causes an error popup + + - Removed some debugging information that was being printed to the console + when connecting to MS FTP servers + + - Fixed FTPS connections to fallback to cleartext mode for data transfers when + the remote server rejects the encrypted mode command diff --git a/sublime/Packages/SFTP/messages/install.txt b/sublime/Packages/SFTP/messages/install.txt new file mode 100644 index 0000000..be8c113 --- /dev/null +++ b/sublime/Packages/SFTP/messages/install.txt @@ -0,0 +1,48 @@ +Thanks for installing Sublime SFTP! Below are some quick notes to get you +started with the plugin. Please see http://wbond.net/sublime_packages/sftp for +the full documentation. + + +There are two major modes of operation: +1. Mapping a local folder to a remote folder +2. Working off of a server + + +Mapping a Local Folder to a Remote Folder +---- + +To map a local folder to a remote folder, right-click on it in the side bar +and select the SFTP/SFTP > Map to Remote... You will enter your connection +parameters and a new file will be created named sftp-config.json. + +Once this file has been saved, all files in that folder and all subfolders +will have various operations available via the side bar context menu, editor +context menu and command palette. + + +Working off of a Server +---- + +To work off of a server, use the File menu and select SFTP/FTP > Setup Server... +You will enter your connection parameters and options then save the file with +the name you want to give the connection. + +Once the server config is saved, you will be automatically connected to the +server and you can browse and perform actions via the quick panel. + +Unfortunely due to limitations of the Sublime Text 2 API, it is not possible +to present the remote filesystem in the side bar. There are, however, key +bindings for connecting to servers to help reduce the amount of time remote +file operations take. + + +Support +---- + +To learn more about the features and settings, please visit +http://wbond.net/sublime_packages/sftp. + +If you are having trouble, please contact me at support@wbond.net. The Support +page, http://wbond.net/sublime_packages/sftp/support, includes instructions +for capturing a debug log that will be useful if you believe you are +experiencing a bug. diff --git a/sublime/Packages/SFTP/package-metadata.json b/sublime/Packages/SFTP/package-metadata.json new file mode 100644 index 0000000..8e9fe04 --- /dev/null +++ b/sublime/Packages/SFTP/package-metadata.json @@ -0,0 +1 @@ +{"url": "http://wbond.net/sublime_packages/sftp", "version": "1.10.2", "description": "Commercial SFTP/FTP plugin - upload, sync, browse, remote edit, diff and vcs integration"} \ No newline at end of file diff --git a/sublime/Packages/SFTP/python_license.txt b/sublime/Packages/SFTP/python_license.txt new file mode 100644 index 0000000..d174031 --- /dev/null +++ b/sublime/Packages/SFTP/python_license.txt @@ -0,0 +1,58 @@ +ftplib2.pyc is subject to the following license. Modifications have been made +from the original ftplib that is included with the Python programming language +in order to provide a better way to handle debugging messages. + +Specifically, the set_debuglevel() method of the ftplib.FTP class accepts a +second optional parameter, "callback", that can specific a callback that will +recieve all debug messages. This callback should accept a single parameter, +the debug message. + +-------- + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +Python Software Foundation; All Rights Reserved" are retained in Python alone or +in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. \ No newline at end of file diff --git a/sublime/Packages/SFTP/schemes/All Hallow's Eve.sftpTheme b/sublime/Packages/SFTP/schemes/All Hallow's Eve.sftpTheme new file mode 100644 index 0000000..2d29321 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/All Hallow's Eve.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #000000 + foreground + #FFFFFF + + + + name + Success + scope + success + settings + + foreground + #66CC33 + + + + name + Failure + scope + failure + settings + + foreground + #C83730 + + + + name + String + scope + string + settings + + foreground + #AAAAAA + + + + name + Date + scope + datediff + settings + + foreground + #9933CC + + + + name + Date + scope + date + settings + + foreground + #555555 + + + + name + Response + scope + response + settings + + foreground + #3387CC + + + + name + dots + scope + dots + settings + + foreground + #434242 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Amy.sftpTheme b/sublime/Packages/SFTP/schemes/Amy.sftpTheme new file mode 100644 index 0000000..354c460 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Amy.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #200020 + foreground + #D0D0FF + + + + name + Success + scope + success + settings + + foreground + #70E0A0 + + + + name + Failure + scope + failure + settings + + foreground + #A00050 + + + + name + String + scope + string + settings + + foreground + #A080FF + + + + name + Date + scope + datediff + settings + + foreground + #BFBFBF + + + + name + Date + scope + date + settings + + foreground + #805080 + + + + name + Response + scope + response + settings + + foreground + #80A0FF + + + + name + dots + scope + dots + settings + + foreground + #999999 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Blackboard.sftpTheme b/sublime/Packages/SFTP/schemes/Blackboard.sftpTheme new file mode 100644 index 0000000..20e9177 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Blackboard.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #0C1021 + foreground + #F8F8F8 + + + + name + Success + scope + success + settings + + foreground + #61CE3C + + + + name + Failure + scope + failure + settings + + foreground + #AB2A1D + + + + name + String + scope + string + settings + + foreground + #D5E0F3 + + + + name + Date + scope + datediff + settings + + foreground + #AEAEAE + + + + name + Date + scope + date + settings + + foreground + #7F90AA + + + + name + Response + scope + response + settings + + foreground + #8DA6CE + + + + name + dots + scope + dots + settings + + foreground + #7F90AA + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Cobalt.sftpTheme b/sublime/Packages/SFTP/schemes/Cobalt.sftpTheme new file mode 100644 index 0000000..f941ead --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Cobalt.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #002240 + foreground + #FFFFFF + + + + name + Success + scope + success + settings + + foreground + #3AD900 + + + + name + Failure + scope + failure + settings + + foreground + #FF1E00 + + + + name + String + scope + string + settings + + foreground + #C8E4FD + + + + name + Date + scope + datediff + settings + + foreground + #FFDD00 + + + + name + Date + scope + date + settings + + foreground + #73817D + + + + name + Response + scope + response + settings + + foreground + #0088FF + + + + name + dots + scope + dots + settings + + foreground + #8996A8 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Custom Output.hidden-tmLanguage b/sublime/Packages/SFTP/schemes/Custom Output.hidden-tmLanguage new file mode 100644 index 0000000..13c60ad --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Custom Output.hidden-tmLanguage @@ -0,0 +1,102 @@ + + + + + fileTypes + + sftp-out + + keyEquivalent + ^~S + name + SFTP Output Panel - Custom + patterns + + + match + ( Yes|No)\n + name + support.constant.sftp + + + match + \.+ + name + comment.sftp + + + match + (?i:\bfailure\b) + name + constant.language.sftp + + + match + (?i:\bsuccess\b) + name + constant.language.sftp + + + captures + + 1 + + name + punctuation.definition.string.begin.sftp + + 2 + + name + punctuation.definition.string.end.sftp + + + match + (")[^"#]*(") + name + string.sftp + + + captures + + 1 + + name + datediff.begin.sftp + + 2 + + name + datediff.end.sftp + + + match + (\()(\d+|same age)[^\)]*(\)) + name + constant.numeric.sftp + + + captures + + 1 + + name + date.begin.sftp + + 2 + + name + date.end.sftp + + + match + (\[)(\d+|same age)[^\]]*(\]) + name + comment.sftp + + + scopeName + output.sftp + uuid + E3A415F0-3F50-11E0-9207-0800200C9A68 + + \ No newline at end of file diff --git a/sublime/Packages/SFTP/schemes/Dawn.sftpTheme b/sublime/Packages/SFTP/schemes/Dawn.sftpTheme new file mode 100644 index 0000000..c5d04cf --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Dawn.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #F9F9F9 + foreground + #080808 + + + + name + Success + scope + success + settings + + foreground + #0B6125 + + + + name + Failure + scope + failure + settings + + foreground + #B4371F + + + + name + String + scope + string + settings + + foreground + #5A525F + + + + name + Date + scope + datediff + settings + + foreground + #691C97 + + + + name + Date + scope + date + settings + + foreground + #808080 + + + + name + Response + scope + response + settings + + foreground + #234A97 + + + + name + dots + scope + dots + settings + + foreground + #808080 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Eiffel.sftpTheme b/sublime/Packages/SFTP/schemes/Eiffel.sftpTheme new file mode 100644 index 0000000..20c230a --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Eiffel.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #FFFFFF + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #26B31A + + + + name + Failure + scope + failure + settings + + foreground + #D80800 + + + + name + String + scope + string + settings + + foreground + #6D79DE + + + + name + Date + scope + datediff + settings + + foreground + #B90690 + + + + name + Date + scope + date + settings + + foreground + #BFBFBF + + + + name + Response + scope + response + settings + + foreground + #0206FF + + + + name + dots + scope + dots + settings + + foreground + #BFBFBF + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Espresso Libre.sftpTheme b/sublime/Packages/SFTP/schemes/Espresso Libre.sftpTheme new file mode 100644 index 0000000..76093e7 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Espresso Libre.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #2A211C + foreground + #BDAE9D + + + + name + Success + scope + success + settings + + foreground + #44AA43 + + + + name + Failure + scope + failure + settings + + foreground + #990000 + + + + name + String + scope + string + settings + + foreground + #BFBFBF + + + + name + Date + scope + datediff + settings + + foreground + #FF9358 + + + + name + Date + scope + date + settings + + foreground + #8F7E65 + + + + name + Response + scope + response + settings + + foreground + #0066FF + + + + name + dots + scope + dots + settings + + foreground + #8F7E65 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/IDLE.sftpTheme b/sublime/Packages/SFTP/schemes/IDLE.sftpTheme new file mode 100644 index 0000000..d96966d --- /dev/null +++ b/sublime/Packages/SFTP/schemes/IDLE.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #FFFFFF + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #00A33F + + + + name + Failure + scope + failure + settings + + foreground + #990000 + + + + name + String + scope + string + settings + + foreground + #21439C + + + + name + Date + scope + datediff + settings + + foreground + #A535AE + + + + name + Date + scope + date + settings + + foreground + #BFBFBF + + + + name + Response + scope + response + settings + + foreground + #FF5600 + + + + name + dots + scope + dots + settings + + foreground + #BFBFBF + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/LAZY.sftpTheme b/sublime/Packages/SFTP/schemes/LAZY.sftpTheme new file mode 100644 index 0000000..ed83db0 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/LAZY.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #FFFFFF + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #409B1C + + + + name + Failure + scope + failure + settings + + foreground + #D62A28 + + + + name + String + scope + string + settings + + foreground + #3B5BB5 + + + + name + Date + scope + datediff + settings + + foreground + #671EBB + + + + name + Date + scope + date + settings + + foreground + #7C7C7C + + + + name + Response + scope + response + settings + + foreground + #FF7800 + + + + name + dots + scope + dots + settings + + foreground + #B6B6B6 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Mac Classic.sftpTheme b/sublime/Packages/SFTP/schemes/Mac Classic.sftpTheme new file mode 100644 index 0000000..6685c2d --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Mac Classic.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #FFFFFF + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #036A07 + + + + name + Failure + scope + failure + settings + + foreground + #C5060B + + + + name + String + scope + string + settings + + foreground + #3C4C72 + + + + name + Date + scope + datediff + settings + + foreground + #585CF6 + + + + name + Date + scope + date + settings + + foreground + #888888 + + + + name + Response + scope + response + settings + + foreground + #B90690 + + + + name + dots + scope + dots + settings + + foreground + #888888 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/MagicWB (Amiga).sftpTheme b/sublime/Packages/SFTP/schemes/MagicWB (Amiga).sftpTheme new file mode 100644 index 0000000..eea9d96 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/MagicWB (Amiga).sftpTheme @@ -0,0 +1,103 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #969696 + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #3A68A3 + + + + name + Failure + scope + failure + settings + + foreground + #FF38FF + + + + name + String + scope + string + settings + + foreground + #FFFFFF + background + #FF000033 + + + + name + Date + scope + datediff + settings + + foreground + #FFA995 + + + + name + Date + scope + date + settings + + foreground + #4D4E60 + + + + name + Response + scope + response + settings + + foreground + #0000FF + + + + name + dots + scope + dots + settings + + foreground + #4D4E60 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Monokai Bright.sftpTheme b/sublime/Packages/SFTP/schemes/Monokai Bright.sftpTheme new file mode 100644 index 0000000..56f3a0b --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Monokai Bright.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #272822 + foreground + #F8F8F2 + + + + name + Success + scope + success + settings + + foreground + #A6E22E + + + + name + Failure + scope + failure + settings + + foreground + #F92672 + + + + name + String + scope + string + settings + + foreground + #E6DB74 + + + + name + Date + scope + datediff + settings + + foreground + #AE81FF + + + + name + Date + scope + date + settings + + foreground + #75715E + + + + name + Response + scope + response + settings + + foreground + #66D9EF + + + + name + dots + scope + dots + settings + + foreground + #75715E + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Monokai.sftpTheme b/sublime/Packages/SFTP/schemes/Monokai.sftpTheme new file mode 100644 index 0000000..56f3a0b --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Monokai.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #272822 + foreground + #F8F8F2 + + + + name + Success + scope + success + settings + + foreground + #A6E22E + + + + name + Failure + scope + failure + settings + + foreground + #F92672 + + + + name + String + scope + string + settings + + foreground + #E6DB74 + + + + name + Date + scope + datediff + settings + + foreground + #AE81FF + + + + name + Date + scope + date + settings + + foreground + #75715E + + + + name + Response + scope + response + settings + + foreground + #66D9EF + + + + name + dots + scope + dots + settings + + foreground + #75715E + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Output.hidden-tmLanguage b/sublime/Packages/SFTP/schemes/Output.hidden-tmLanguage new file mode 100644 index 0000000..84cc66c --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Output.hidden-tmLanguage @@ -0,0 +1,108 @@ + + + + + fileTypes + + sftp-out + + keyEquivalent + ^~S + name + SFTP Output Panel + patterns + + + match + ( Yes|No)\n + name + response.sftp + + + match + \.+ + name + dots.sftp + + + match + (?i:\bfailure\b) + name + failure.sftp + + + match + (?i:\bsuccess\b) + name + success.sftp + + + match + ^UNREGISTERED: Please visit http://sublime.wbond.net/sftp + name + failure.sftp + + + captures + + 1 + + name + punctuation.definition.string.begin.sftp + + 2 + + name + punctuation.definition.string.end.sftp + + + match + (")[^"#]*(") + name + string.sftp + + + captures + + 1 + + name + datediff.begin.sftp + + 2 + + name + datediff.end.sftp + + + match + (\()(\d+|same age)[^\)]*(\)) + name + datediff.sftp + + + captures + + 1 + + name + date.begin.sftp + + 2 + + name + date.end.sftp + + + match + (\[)(\d+|same age)[^\]]*(\]) + name + date.sftp + + + scopeName + output.sftp + uuid + E3A415F0-3F50-11E0-9207-0800200C9A67 + + \ No newline at end of file diff --git a/sublime/Packages/SFTP/schemes/Output.tmLanguage b/sublime/Packages/SFTP/schemes/Output.tmLanguage new file mode 100644 index 0000000..84cc66c --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Output.tmLanguage @@ -0,0 +1,108 @@ + + + + + fileTypes + + sftp-out + + keyEquivalent + ^~S + name + SFTP Output Panel + patterns + + + match + ( Yes|No)\n + name + response.sftp + + + match + \.+ + name + dots.sftp + + + match + (?i:\bfailure\b) + name + failure.sftp + + + match + (?i:\bsuccess\b) + name + success.sftp + + + match + ^UNREGISTERED: Please visit http://sublime.wbond.net/sftp + name + failure.sftp + + + captures + + 1 + + name + punctuation.definition.string.begin.sftp + + 2 + + name + punctuation.definition.string.end.sftp + + + match + (")[^"#]*(") + name + string.sftp + + + captures + + 1 + + name + datediff.begin.sftp + + 2 + + name + datediff.end.sftp + + + match + (\()(\d+|same age)[^\)]*(\)) + name + datediff.sftp + + + captures + + 1 + + name + date.begin.sftp + + 2 + + name + date.end.sftp + + + match + (\[)(\d+|same age)[^\]]*(\]) + name + date.sftp + + + scopeName + output.sftp + uuid + E3A415F0-3F50-11E0-9207-0800200C9A67 + + \ No newline at end of file diff --git a/sublime/Packages/SFTP/schemes/Pastels on Dark.sftpTheme b/sublime/Packages/SFTP/schemes/Pastels on Dark.sftpTheme new file mode 100644 index 0000000..fca2949 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Pastels on Dark.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #211E1E + foreground + #DADADA + + + + name + Success + scope + success + settings + + foreground + #B8CD06 + + + + name + Failure + scope + failure + settings + + foreground + #C82255 + + + + name + String + scope + string + settings + + foreground + #AD9361 + + + + name + Date + scope + datediff + settings + + foreground + #6969FA + + + + name + Date + scope + date + settings + + foreground + #909090 + + + + name + Response + scope + response + settings + + foreground + #47B8D6 + + + + name + dots + scope + dots + settings + + foreground + #777777 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Slush & Poppies.sftpTheme b/sublime/Packages/SFTP/schemes/Slush & Poppies.sftpTheme new file mode 100644 index 0000000..e98e168 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Slush & Poppies.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #F1F1F1 + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #008080 + + + + name + Failure + scope + failure + settings + + foreground + #C03030 + + + + name + String + scope + string + settings + + foreground + #2060A0 + + + + name + Date + scope + datediff + settings + + foreground + #0080FF + + + + name + Date + scope + date + settings + + foreground + #999999 + + + + name + Response + scope + response + settings + + foreground + #8000C0 + + + + name + dots + scope + dots + settings + + foreground + #666666 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Solarized (Dark).sftpTheme b/sublime/Packages/SFTP/schemes/Solarized (Dark).sftpTheme new file mode 100644 index 0000000..e063973 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Solarized (Dark).sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #042029 + foreground + #839496 + + + + name + Success + scope + success + settings + + foreground + #748B00 + + + + name + Failure + scope + failure + settings + + foreground + #B81D1C + + + + name + String + scope + string + settings + + foreground + #2AA198 + + + + name + Date + scope + datediff + settings + + foreground + #B58900 + + + + name + Date + scope + date + settings + + foreground + #536871 + + + + name + Response + scope + response + settings + + foreground + #5A74CF + + + + name + dots + scope + dots + settings + + foreground + #536871 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Solarized (Light).sftpTheme b/sublime/Packages/SFTP/schemes/Solarized (Light).sftpTheme new file mode 100644 index 0000000..4b7b10e --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Solarized (Light).sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #FDF6E3 + foreground + #586E75 + + + + name + Success + scope + success + settings + + foreground + #738A05 + + + + name + Failure + scope + failure + settings + + foreground + #BB3700 + + + + name + String + scope + string + settings + + foreground + #2AA198 + + + + name + Date + scope + datediff + settings + + foreground + #5A74CF + + + + name + Date + scope + date + settings + + foreground + #819090 + + + + name + Response + scope + response + settings + + foreground + #268BD2 + + + + name + dots + scope + dots + settings + + foreground + #B58900 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/SpaceCadet.sftpTheme b/sublime/Packages/SFTP/schemes/SpaceCadet.sftpTheme new file mode 100644 index 0000000..796d1a9 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/SpaceCadet.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #0D0D0D + foreground + #DDE6CF + + + + name + Success + scope + success + settings + + foreground + #9EBF60 + + + + name + Failure + scope + failure + settings + + foreground + #7F005D + + + + name + String + scope + string + settings + + foreground + #805978 + + + + name + Date + scope + datediff + settings + + foreground + #A8885A + + + + name + Date + scope + date + settings + + foreground + #999999 + + + + name + Response + scope + response + settings + + foreground + #6078BF + + + + name + dots + scope + dots + settings + + foreground + #596380 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Sunburst.sftpTheme b/sublime/Packages/SFTP/schemes/Sunburst.sftpTheme new file mode 100644 index 0000000..e16704b --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Sunburst.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #000000 + foreground + #F8F8F8 + + + + name + Success + scope + success + settings + + foreground + #99CF50 + + + + name + Failure + scope + failure + settings + + foreground + #DD7B3B + + + + name + String + scope + string + settings + + foreground + #89BDFF + + + + name + Date + scope + datediff + settings + + foreground + #8693A5 + + + + name + Date + scope + date + settings + + foreground + #AEAEAE + + + + name + Response + scope + response + settings + + foreground + #CF7D34 + + + + name + dots + scope + dots + settings + + foreground + #676767 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Twilight.sftpTheme b/sublime/Packages/SFTP/schemes/Twilight.sftpTheme new file mode 100644 index 0000000..ed12f9a --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Twilight.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #141414 + foreground + #F8F8F8 + + + + name + Success + scope + success + settings + + foreground + #8F9D6A + + + + name + Failure + scope + failure + settings + + foreground + #CF6A4C + + + + name + String + scope + string + settings + + foreground + #C5AF75 + + + + name + Date + scope + datediff + settings + + foreground + #9B703F + + + + name + Date + scope + date + settings + + foreground + #9B859D + + + + name + Response + scope + response + settings + + foreground + #7587A6 + + + + name + dots + scope + dots + settings + + foreground + #5F5A60 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/Zenburnesque.sftpTheme b/sublime/Packages/SFTP/schemes/Zenburnesque.sftpTheme new file mode 100644 index 0000000..a563be4 --- /dev/null +++ b/sublime/Packages/SFTP/schemes/Zenburnesque.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #404040 + foreground + #DEDEDE + + + + name + Success + scope + success + settings + + foreground + #709070 + + + + name + Failure + scope + failure + settings + + foreground + #FF2020 + + + + name + String + scope + string + settings + + foreground + #A8A8A8 + + + + name + Date + scope + datediff + settings + + foreground + #FFFFA0 + + + + name + Date + scope + date + settings + + foreground + #A0A0C0 + + + + name + Response + scope + response + settings + + foreground + #6080FF + + + + name + dots + scope + dots + settings + + foreground + #676767 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/SFTP/schemes/iPlastic.sftpTheme b/sublime/Packages/SFTP/schemes/iPlastic.sftpTheme new file mode 100644 index 0000000..118162c --- /dev/null +++ b/sublime/Packages/SFTP/schemes/iPlastic.sftpTheme @@ -0,0 +1,101 @@ + + + + + author + Will Bond + name + SFTP Output + settings + + + settings + + background + #EEEEEE + foreground + #000000 + + + + name + Success + scope + success + settings + + foreground + #009933 + + + + name + Failure + scope + failure + settings + + foreground + #FF0000 + + + + name + String + scope + string + settings + + foreground + #0066FF + + + + name + Date + scope + datediff + settings + + foreground + #9700CC + + + + name + Date + scope + date + settings + + foreground + #666666 + + + + name + Response + scope + response + settings + + foreground + #FF8000 + + + + name + dots + scope + dots + settings + + foreground + #999999 + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/sublime/Packages/User/Package Control.last-run b/sublime/Packages/User/Package Control.last-run index b24d6be..9d0c6f6 100644 --- a/sublime/Packages/User/Package Control.last-run +++ b/sublime/Packages/User/Package Control.last-run @@ -1 +1 @@ -1363369577 \ No newline at end of file +1370390066 \ No newline at end of file diff --git a/sublime/Packages/User/Package Control.sublime-settings b/sublime/Packages/User/Package Control.sublime-settings index 2d6ff63..17079bf 100644 --- a/sublime/Packages/User/Package Control.sublime-settings +++ b/sublime/Packages/User/Package Control.sublime-settings @@ -5,6 +5,8 @@ "AAAPackageDev", "LESS", "LineEndings", - "Package Control" + "Package Control", + "SFTP", + "Web Inspector" ] } diff --git a/sublime/Packages/User/Preferences.sublime-settings b/sublime/Packages/User/Preferences.sublime-settings index 08e836a..6da9b68 100644 --- a/sublime/Packages/User/Preferences.sublime-settings +++ b/sublime/Packages/User/Preferences.sublime-settings @@ -48,7 +48,8 @@ "highlight_modified_tabs": true, "ignored_packages": [ - "Vintage" + "Vintage", + "SFTP" ], "indent_to_bracket": true, "open_files_in_new_window": true, diff --git a/sublime/Packages/User/sftp_servers/dev.tapfortap.com b/sublime/Packages/User/sftp_servers/dev.tapfortap.com new file mode 100644 index 0000000..a308fa7 --- /dev/null +++ b/sublime/Packages/User/sftp_servers/dev.tapfortap.com @@ -0,0 +1,31 @@ +{ + // The tab key will cycle through the settings when first created + // Visit http://wbond.net/sublime_packages/sftp/settings for help + + // sftp, ftp or ftps + "type": "sftp", + + "sync_down_on_open": true, + + "host": "dev.tapfortap.com", + "user": "sjs", + //"password": "password", + //"port": "22", + + "remote_path": "/home/sjs/Dropbox/tapfortap/server-v2", + //"file_permissions": "664", + //"dir_permissions": "775", + + //"extra_list_connections": 0, + + "connect_timeout": 30, + //"keepalive": 120, + //"ftp_passive_mode": true, + "ssh_key_file": "~/.ssh/id_rsa", + //"sftp_flags": ["-F", "/path/to/ssh_config"], + + //"preserve_modification_times": false, + //"remote_time_offset_in_hours": 0, + //"remote_encoding": "utf-8", + //"remote_locale": "C", +} diff --git a/sublime/Packages/User/swi.sublime-settings b/sublime/Packages/User/swi.sublime-settings new file mode 100644 index 0000000..7c21565 --- /dev/null +++ b/sublime/Packages/User/swi.sublime-settings @@ -0,0 +1,5 @@ +{ + "breaks": + { + } +} diff --git a/sublime/Packages/Web Inspector/.gitignore b/sublime/Packages/Web Inspector/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/sublime/Packages/Web Inspector/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/sublime/Packages/Web Inspector/Default (Linux).sublime-keymap b/sublime/Packages/Web Inspector/Default (Linux).sublime-keymap new file mode 100644 index 0000000..e4e2bbd --- /dev/null +++ b/sublime/Packages/Web Inspector/Default (Linux).sublime-keymap @@ -0,0 +1,3 @@ +[ + {"keys": ["ctrl+shift+r"], "command": "swi_debug" } +] diff --git a/sublime/Packages/Web Inspector/Default (OSX).sublime-keymap b/sublime/Packages/Web Inspector/Default (OSX).sublime-keymap new file mode 100644 index 0000000..8684bd4 --- /dev/null +++ b/sublime/Packages/Web Inspector/Default (OSX).sublime-keymap @@ -0,0 +1,3 @@ +[ + {"keys": ["super+shift+r"], "command": "swi_debug" } +] diff --git a/sublime/Packages/Web Inspector/Default (Windows).sublime-keymap b/sublime/Packages/Web Inspector/Default (Windows).sublime-keymap new file mode 100644 index 0000000..e4e2bbd --- /dev/null +++ b/sublime/Packages/Web Inspector/Default (Windows).sublime-keymap @@ -0,0 +1,3 @@ +[ + {"keys": ["ctrl+shift+r"], "command": "swi_debug" } +] diff --git a/sublime/Packages/Web Inspector/Default.sublime-commands b/sublime/Packages/Web Inspector/Default.sublime-commands new file mode 100644 index 0000000..da4f7da --- /dev/null +++ b/sublime/Packages/Web Inspector/Default.sublime-commands @@ -0,0 +1,6 @@ +[ + { + "caption": "Web Inspector", + "command": "swi_debug" + } +] diff --git a/sublime/Packages/Web Inspector/Main.sublime-menu b/sublime/Packages/Web Inspector/Main.sublime-menu new file mode 100644 index 0000000..fec0139 --- /dev/null +++ b/sublime/Packages/Web Inspector/Main.sublime-menu @@ -0,0 +1,85 @@ +[ + { + "caption": "Preferences", + "mnemonic": "n", + "id": "preferences", + "children": + [ + { + "caption": "Package Settings", + "mnemonic": "P", + "id": "package-settings", + "children": + [ + { + "caption": "Web Inspector", + "children": + [ + { + "command": "open_file", + "args": { + "file": "${packages}/Web Inspector/Default (OSX).sublime-keymap", + "platform": "OSX" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/Web Inspector/Default (Linux).sublime-keymap", + "platform": "Linux" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/Web Inspector/Default (Windows).sublime-keymap", + "platform": "Windows" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/User/Default (OSX).sublime-keymap", + "platform": "OSX" + }, + "caption": "Key Bindings – User" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/User/Default (Linux).sublime-keymap", + "platform": "Linux" + }, + "caption": "Key Bindings – User" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/User/Default (Windows).sublime-keymap", + "platform": "Windows" + }, + "caption": "Key Bindings – User" + }, + { "caption": "-" }, + { + "command": "open_file", + "args": {"file": "${packages}/Web Inspector/swi.sublime-settings"}, + "caption": "Settings – Default" + }, + { + "command": "open_file", + "args": {"file": "${packages}/User/swi.sublime-settings"}, + "caption": "Settings – User" + }, + { "caption": "-" } + + ] + } + ] + } + ] + } +] diff --git a/sublime/Packages/Web Inspector/README.markdown b/sublime/Packages/Web Inspector/README.markdown new file mode 100644 index 0000000..05a246a --- /dev/null +++ b/sublime/Packages/Web Inspector/README.markdown @@ -0,0 +1,51 @@ +# Sublime Web Inpsector (SWI) + +Sublime Web Inspector works on top of WebInspectorProtocol. All information is displayed in console and text files. You can click on objects from console or stack trace to evaluate them. You can click on file name to goto file and line instantly. All clickable zone have borders to simply vizualize them. + +All feature request and bugs you can add to https://github.com/sokolovstas/SublimeWebInspector/issues + +*Thanks XDebug Authors for inspiration* + +## Instalation +Do in your Packages folder: +```git clone git://github.com/sokolovstas/SublimeWebInspector.git Web\ Inpsector``` + +I prepare plugin to Package Manager after some testing + +## Features + +- Breakpoints for project stored in user settings with absolute paths. +- Console. +- Debugger steps and breakpoints. +- Stack trace. +- You can see object properties and values in console and stack trace. + +## Commands + +All commands you can find in "Sublime Web Inspector" command. And here a complete list: + +### Command for controlling debugger +- swi\_debug\_resume +- swi\_debug\_step\_into +- swi\_debug\_step\_out +- swi\_debug\_step\_over + +### Breakpoints +- swi\_debug\_breakpoint + +### Page +- swi\_debug\_reload + +### Start-stop +- swi\_debug\_start +- swi\_debug\_stop + +### Utils +- swi\_debug\_start\_chrome + +## Settings + +In settings you can change layouts for debugger, some color and path to Google Chrome + +## PS +*Close Google Chrome befor run it in remote debugger mode.* diff --git a/sublime/Packages/Web Inspector/icons/breakpoint_active.png b/sublime/Packages/Web Inspector/icons/breakpoint_active.png new file mode 100644 index 0000000..c25cb18 Binary files /dev/null and b/sublime/Packages/Web Inspector/icons/breakpoint_active.png differ diff --git a/sublime/Packages/Web Inspector/icons/breakpoint_active.psd b/sublime/Packages/Web Inspector/icons/breakpoint_active.psd new file mode 100644 index 0000000..db6aa5b Binary files /dev/null and b/sublime/Packages/Web Inspector/icons/breakpoint_active.psd differ diff --git a/sublime/Packages/Web Inspector/icons/breakpoint_current.png b/sublime/Packages/Web Inspector/icons/breakpoint_current.png new file mode 100644 index 0000000..22ae0c1 Binary files /dev/null and b/sublime/Packages/Web Inspector/icons/breakpoint_current.png differ diff --git a/sublime/Packages/Web Inspector/icons/breakpoint_inactive.png b/sublime/Packages/Web Inspector/icons/breakpoint_inactive.png new file mode 100644 index 0000000..b8a47bb Binary files /dev/null and b/sublime/Packages/Web Inspector/icons/breakpoint_inactive.png differ diff --git a/sublime/Packages/Web Inspector/messages.json b/sublime/Packages/Web Inspector/messages.json new file mode 100644 index 0000000..d405454 --- /dev/null +++ b/sublime/Packages/Web Inspector/messages.json @@ -0,0 +1,4 @@ +{ + "install": "messages/install.txt", + "1.2.1": "messages/1.2.1.txt" +} \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/messages/1.2.1.txt b/sublime/Packages/Web Inspector/messages/1.2.1.txt new file mode 100644 index 0000000..38b690f --- /dev/null +++ b/sublime/Packages/Web Inspector/messages/1.2.1.txt @@ -0,0 +1,4 @@ +Added stack trace to console +Fix message displaying in console + +Moved to custom packages.json \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/messages/1.4.txt b/sublime/Packages/Web Inspector/messages/1.4.txt new file mode 100644 index 0000000..fb8a6b6 --- /dev/null +++ b/sublime/Packages/Web Inspector/messages/1.4.txt @@ -0,0 +1,3 @@ +Moved to packages.json +Fixes some bugs +Fix fall out on resume \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/messages/install.txt b/sublime/Packages/Web Inspector/messages/install.txt new file mode 100644 index 0000000..f831228 --- /dev/null +++ b/sublime/Packages/Web Inspector/messages/install.txt @@ -0,0 +1,3 @@ +Use Web Inspector command. + +More details http://sokolovstas.github.com/SublimeWebInspector/ \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/package-metadata.json b/sublime/Packages/Web Inspector/package-metadata.json new file mode 100644 index 0000000..595aacd --- /dev/null +++ b/sublime/Packages/Web Inspector/package-metadata.json @@ -0,0 +1 @@ +{"url": "http://sokolovstas.github.com/SublimeWebInspector", "version": "1.4", "description": "JavaScript debbuging in Sublime Text"} \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/packages.json b/sublime/Packages/Web Inspector/packages.json new file mode 100644 index 0000000..d797b82 --- /dev/null +++ b/sublime/Packages/Web Inspector/packages.json @@ -0,0 +1,20 @@ +{ + "schema_version": "1.2", + "packages": [ + { + "name": "Web Inspector", + "description": "JavaScript debbuging in Sublime Text", + "author": "Stanislav Sokolov", + "homepage": "http://sokolovstas.github.com/SublimeWebInspector", + "last_modified": "2012-02-28 00:00:00", + "platforms": { + "*": [ + { + "version": "1.4", + "url": "https://nodeload.github.com/sokolovstas/SublimeWebInspector/zip/1.4" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/swi.py b/sublime/Packages/Web Inspector/swi.py new file mode 100644 index 0000000..bac70b3 --- /dev/null +++ b/sublime/Packages/Web Inspector/swi.py @@ -0,0 +1,1264 @@ +import hashlib +import functools +import glob +import sublime +import sublime_plugin +import websocket +import urllib2 +import threading +import json +import types +import os +import re +import wip +import time +from wip import utils +from wip import Console +from wip import Runtime +from wip import Debugger +from wip import Network +from wip import Page +import sys + +reload(sys.modules['wip.utils']) +reload(sys.modules['wip.Console']) +reload(sys.modules['wip.Runtime']) +reload(sys.modules['wip.Debugger']) +reload(sys.modules['wip.Network']) +reload(sys.modules['wip.Page']) + +brk_object = {} +buffers = {} +protocol = None +original_layout = None +window = None +debug_view = None +debug_url = None +file_to_scriptId = [] +project_folders = [] +last_clicked = None +paused = False +current_line = None +reload_on_start = False +reload_on_save = False +set_script_source = False +current_call_frame = None +current_call_frame_position = None +open_stack_current_in_new_tab = True +timing = time.time() + + +# scriptId_fileName = {} + +breakpoint_active_icon = '../Web Inspector/icons/breakpoint_active' +breakpoint_inactive_icon = '../Web Inspector/icons/breakpoint_inactive' +breakpoint_current_icon = '../Web Inspector/icons/breakpoint_current' + + +#################################################################################### +# PROTOCOL +#################################################################################### + +# Define protocol to communicate with remote debugger by web sockets +class Protocol(object): + def __init__(self): + self.next_id = 0 + self.commands = {} + self.notifications = {} + self.last_log_object = None + + def connect(self, url, on_open=None, on_close=None): + print 'SWI: Connecting to ' + url + websocket.enableTrace(False) + self.last_break = None + self.last_log_object = None + self.url = url + self.on_open = on_open + self.on_close = on_close + thread = threading.Thread(target=self.thread_callback) + thread.start() + + # start connect with new thread + def thread_callback(self): + print 'SWI: Thread started' + self.socket = websocket.WebSocketApp(self.url, on_message=self.message_callback, on_open=self.open_callback, on_close=self.close_callback) + self.socket.run_forever() + print 'SWI: Thread stoped' + + # send command and increment command counter + def send(self, command, callback=None, options=None): + command.id = self.next_id + command.callback = callback + command.options = options + self.commands[command.id] = command + self.next_id += 1 + # print 'SWI: ->> ' + json.dumps(command.request) + self.socket.send(json.dumps(command.request)) + + # subscribe to notification with callback + def subscribe(self, notification, callback): + notification.callback = callback + self.notifications[notification.name] = notification + + # unsubscribe + def unsubscribe(self, notification): + del self.notifications[notification.name] + + # unsubscribe + def message_callback(self, ws, message): + parsed = json.loads(message) + # print 'SWI: <<- ' + message + # print '' + if 'method' in parsed: + if parsed['method'] in self.notifications: + notification = self.notifications[parsed['method']] + if 'params' in parsed: + data = notification.parser(parsed['params']) + else: + data = None + notification.callback(data, notification) + # else: + # print 'SWI: New unsubscrib notification --- ' + parsed['method'] + else: + if parsed['id'] in self.commands: + + command = self.commands[parsed['id']] + + if 'error' in parsed: + sublime.set_timeout(lambda: sublime.error_message(parsed['error']['message']), 0) + else: + if 'result' in parsed: + command.data = command.parser(parsed['result']) + else: + command.data = None + + if command.callback: + command.callback(command) + # print 'SWI: Command response with ID ' + str(parsed['id']) + + def open_callback(self, ws): + if self.on_open: + self.on_open() + print 'SWI: WebSocket opened' + + def close_callback(self, ws): + if self.on_close: + self.on_close() + print 'SWI: WebSocket closed' + + +#################################################################################### +# COMMANDS +#################################################################################### + +class SwiDebugCommand(sublime_plugin.TextCommand): + ''' + The SWIdebug main quick panel menu + ''' + def run(self, editswi): + mapping = {} + try: + urllib2.urlopen('http://127.0.0.1:' + get_setting('chrome_remote_port') + '/json') + + mapping = {} + + if paused: + mapping['swi_debug_resume'] = 'Resume execution' + mapping['swi_debug_evaluate_on_call_frame'] = 'Evaluate selection' + #mapping['swi_debug_step_into'] = 'Step into' + #mapping['swi_debug_step_out'] = 'Step out' + #mapping['swi_debug_step_over'] = 'Step over' + else: + #mapping['swi_debug_clear_all_breakpoint'] = 'Clear all Breakpoints' + mapping['swi_debug_breakpoint'] = 'Add/Remove Breakpoint' + + if protocol: + mapping['swi_debug_clear_console'] = 'Clear console' + mapping['swi_debug_stop'] = 'Stop debugging' + mapping['swi_debug_reload'] = 'Reload page' + else: + mapping['swi_debug_start'] = 'Start debugging' + except: + mapping['swi_debug_start_chrome'] = 'Start Google Chrome with remote debug port ' + get_setting('chrome_remote_port') + + self.cmds = mapping.keys() + self.items = mapping.values() + self.view.window().show_quick_panel(self.items, self.command_selected) + + def command_selected(self, index): + if index == -1: + return + + command = self.cmds[index] + + if command == 'swi_debug_start': + response = urllib2.urlopen('http://127.0.0.1:' + get_setting('chrome_remote_port') + '/json') + pages = json.loads(response.read()) + mapping = {} + for page in pages: + if 'webSocketDebuggerUrl' in page: + if page['url'].find('chrome-extension://') == -1: + mapping[page['webSocketDebuggerUrl']] = page['url'] + + self.urls = mapping.keys() + items = mapping.values() + self.view.window().show_quick_panel(items, self.remote_debug_url_selected) + return + + self.view.run_command(command) + + def remote_debug_url_selected(self, index): + if index == -1: + return + + url = self.urls[index] + + global window + window = sublime.active_window() + + global original_layout + original_layout = window.get_layout() + + global debug_view + debug_view = window.active_view() + + window.set_layout(get_setting('console_layout')) + + load_breaks() + self.view.run_command('swi_debug_start', {'url': url}) + + +class SwiDebugStartChromeCommand(sublime_plugin.TextCommand): + def run(self, edit): + window = sublime.active_window() + + window.run_command('exec', { + "cmd": [os.getenv('GOOGLE_CHROME_PATH', '')+get_setting('chrome_path')[sublime.platform()], '--remote-debugging-port=' + get_setting('chrome_remote_port')] + }) + + +class SwiDebugStartCommand(sublime_plugin.TextCommand): + + def run(self, edit, url): + global file_to_scriptId + file_to_scriptId = [] + window = sublime.active_window() + global project_folders + project_folders = window.folders() + print 'Starting SWI' + self.url = url + global protocol + if(protocol): + print 'SWI: Socket closed' + protocol.socket.close() + else: + print 'SWI: Creating protocol' + protocol = Protocol() + protocol.connect(self.url, self.connected, self.disconnected) + + global reload_on_start + reload_on_start = get_setting('reload_on_start') + + global reload_on_save + reload_on_save = get_setting('reload_on_save') + + global set_script_source + set_script_source = get_setting('set_script_source') + + global open_stack_current_in_new_tab + open_stack_current_in_new_tab = get_setting('open_stack_current_in_new_tab') + + def connected(self): + protocol.subscribe(wip.Console.messageAdded(), self.messageAdded) + protocol.subscribe(wip.Console.messageRepeatCountUpdated(), self.messageRepeatCountUpdated) + protocol.subscribe(wip.Console.messagesCleared(), self.messagesCleared) + protocol.subscribe(wip.Debugger.scriptParsed(), self.scriptParsed) + protocol.subscribe(wip.Debugger.paused(), self.paused) + protocol.subscribe(wip.Debugger.resumed(), self.resumed) + protocol.send(wip.Debugger.enable()) + protocol.send(wip.Console.enable()) + protocol.send(wip.Debugger.canSetScriptSource(), self.canSetScriptSource) + if reload_on_start: + protocol.send(wip.Network.clearBrowserCache()) + protocol.send(wip.Page.reload(), on_reload) + + def disconnected(self): + sublime.set_timeout(lambda: debug_view.run_command('swi_debug_stop'), 0) + + def messageAdded(self, data, notification): + sublime.set_timeout(lambda: console_add_message(data), 0) + + def messageRepeatCountUpdated(self, data, notification): + sublime.set_timeout(lambda: console_repeat_message(data['count']), 0) + + def messagesCleared(self, data, notification): + sublime.set_timeout(lambda: clear_view('console'), 0) + + def scriptParsed(self, data, notification): + url = data['url'] + if url != '': + url_parts = url.split("/") + scriptId = str(data['scriptId']) + file_name = '' + + script = get_script(data['url']) + + if script: + script['scriptId'] = str(scriptId) + file_name = script['file'] + else: + del url_parts[0:3] + while len(url_parts) > 0: + for folder in project_folders: + if sublime.platform() == "windows": + files = glob.glob(folder + "\\" + "\\".join(url_parts)) + else: + files = glob.glob(folder + "/" + "/".join(url_parts)) + + if len(files) > 0 and files[0] != '': + file_name = files[0] + file_to_scriptId.append({'file': file_name, 'scriptId': str(scriptId), 'sha1': hashlib.sha1(data['url']).hexdigest()}) + del url_parts[0] + + if get_breakpoints_by_full_path(file_name): + for line in get_breakpoints_by_full_path(file_name).keys(): + location = wip.Debugger.Location({'lineNumber': int(line), 'scriptId': scriptId}) + protocol.send(wip.Debugger.setBreakpoint(location), self.breakpointAdded) + + def paused(self, data, notification): + sublime.set_timeout(lambda: window.set_layout(get_setting('stack_layout')), 0) + + sublime.set_timeout(lambda: console_show_stack(data['callFrames']), 0) + + scriptId = data['callFrames'][0].location.scriptId + line_number = data['callFrames'][0].location.lineNumber + file_name = find_script(str(scriptId)) + first_scope = data['callFrames'][0].scopeChain[0] + + if open_stack_current_in_new_tab: + title = {'objectId': first_scope.object.objectId, 'name': "%s:%s (%s)" % (file_name, line_number, first_scope.type)} + else: + title = {'objectId': first_scope.object.objectId, 'name': "Breakpoint Local"} + + global current_call_frame + current_call_frame = data['callFrames'][0].callFrameId + + global current_call_frame_position + current_call_frame_position = "%s:%s" % (file_name, line_number) + + sublime.set_timeout(lambda: protocol.send(wip.Runtime.getProperties(first_scope.object.objectId, True), console_add_properties, title), 30) + sublime.set_timeout(lambda: open_script_and_focus_line(scriptId, line_number), 100) + + global paused + paused = True + + def resumed(self, data, notification): + sublime.set_timeout(lambda: clear_view('stack'), 0) + + global current_line + current_line = None + + global current_call_frame + current_call_frame = None + + global current_call_frame_position + current_call_frame_position = None + + sublime.set_timeout(lambda: lookup_view(self.view).view_breakpoints(), 50) + + global paused + paused = False + + def breakpointAdded(self, command): + breakpointId = command.data['breakpointId'] + scriptId = command.data['actualLocation'].scriptId + lineNumber = command.data['actualLocation'].lineNumber + + try: + breakpoint = get_breakpoints_by_scriptId(str(scriptId))[str(lineNumber)] + breakpoint['status'] = 'enabled' + breakpoint['breakpointId'] = str(breakpointId) + except: + pass + + try: + breaks = get_breakpoints_by_scriptId(str(scriptId))[str(lineNumber)] + + lineNumber = str(lineNumber) + lineNumberSend = str(command.params['lineNumber']) + + if lineNumberSend in breaks and lineNumber != lineNumberSend: + breaks[lineNumber] = breaks[lineNumberSend].copy() + del breaks[lineNumberSend] + + breaks[lineNumber]['status'] = 'enabled' + breaks[lineNumber]['breakpointId'] = str(breakpointId) + except: + pass + + sublime.set_timeout(lambda: save_breaks(), 0) + sublime.set_timeout(lambda: lookup_view(self.view).view_breakpoints(), 0) + + def canSetScriptSource(self, command): + global set_script_source + if set_script_source: + set_script_source = command.data['result'] + + +class SwiDebugResumeCommand(sublime_plugin.TextCommand): + + def run(self, edit): + protocol.send(wip.Debugger.resume()) + + +class SwiDebugStepIntoCommand(sublime_plugin.TextCommand): + + def run(self, edit): + protocol.send(wip.Debugger.stepInto()) + + +class SwiDebugStepOutCommand(sublime_plugin.TextCommand): + + def run(self, edit): + protocol.send(wip.Debugger.stepOut()) + + +class SwiDebugStepOverCommand(sublime_plugin.TextCommand): + + def run(self, edit): + protocol.send(wip.Debugger.stepOver()) + + +class SwiDebugClearConsoleCommand(sublime_plugin.TextCommand): + + def run(self, edit): + sublime.set_timeout(lambda: clear_view('console'), 0) + + +class SwiDebugEvaluateOnCallFrameCommand(sublime_plugin.TextCommand): + + def run(self, edit): + for region in self.view.sel(): + title = self.view.substr(region) + if current_call_frame_position: + title = "%s on %s" % (self.view.substr(region), current_call_frame_position) + protocol.send(wip.Debugger.evaluateOnCallFrame(current_call_frame, self.view.substr(region)), self.evaluated, {'name': title}) + + def evaluated(self, command): + if command.data.type == 'object': + protocol.send(wip.Runtime.getProperties(command.data.objectId, True), console_add_properties, command.options) + else: + sublime.set_timeout(lambda: console_add_evaluate(command.data), 0) + + +class SwiDebugBreakpointCommand(sublime_plugin.TextCommand): + ''' + Toggle a breakpoint + ''' + def run(self, edit): + view = lookup_view(self.view) + row = str(view.rows(view.lines())[0]) + init_breakpoint_for_file(view.file_name()) + breaks = get_breakpoints_by_full_path(view.file_name()) + if row in breaks: + if protocol: + if row in breaks: + protocol.send(wip.Debugger.removeBreakpoint(breaks[row]['breakpointId'])) + + del_breakpoint_by_full_path(view.file_name(), row) + else: + if protocol: + scriptId = find_script(view.file_name()) + if scriptId: + location = wip.Debugger.Location({'lineNumber': int(row), 'scriptId': scriptId}) + protocol.send(wip.Debugger.setBreakpoint(location), self.breakpointAdded, view.file_name()) + else: + set_breakpoint_by_full_path(view.file_name(), row) + + view.view_breakpoints() + + def breakpointAdded(self, command): + breakpointId = command.data['breakpointId'] + scriptId = command.data['actualLocation'].scriptId + lineNumber = command.data['actualLocation'].lineNumber + + init_breakpoint_for_file(command.options) + + sublime.set_timeout(lambda: set_breakpoint_by_scriptId(str(scriptId), str(lineNumber), 'enabled', breakpointId), 0) + # Scroll to position where breakpoints have resolved + sublime.set_timeout(lambda: lookup_view(self.view).view_breakpoints(), 0) + + +class SwiDebugStopCommand(sublime_plugin.TextCommand): + + def run(self, edit): + global window + + window.focus_group(1) + for view in window.views_in_group(1): + window.run_command("close") + + window.focus_group(2) + for view in window.views_in_group(2): + window.run_command("close") + + window.set_layout(original_layout) + + disable_all_breakpoints() + + lookup_view(self.view).view_breakpoints() + + global paused + paused = False + + global current_line + current_line = None + sublime.set_timeout(lambda: lookup_view(self.view).view_breakpoints(), 0) + + global protocol + if protocol: + try: + protocol.socket.close() + except: + print 'SWI: Can\'t close soket' + finally: + protocol = None + + +class SwiDebugReloadCommand(sublime_plugin.TextCommand): + def run(self, view): + if(protocol): + protocol.send(wip.Network.clearBrowserCache()) + protocol.send(wip.Page.reload(), on_reload) + + +#################################################################################### +# VIEW +#################################################################################### + +class SwiDebugView(object): + ''' + The SWIDebugView is sort of a normal view with some convenience methods. + + See lookup_view. + ''' + def __init__(self, view): + self.view = view + self.context_data = {} + self.clicks = [] + self.prev_click_position = 0 + + def __getattr__(self, attr): + if hasattr(self.view, attr): + return getattr(self.view, attr) + if attr.startswith('on_'): + return self + raise(AttributeError, "%s does not exist" % attr) + + def __call__(self, *args, **kwargs): + pass + + def uri(self): + return 'file://' + os.path.realpath(self.view.file_name()) + + def lines(self, data=None): + lines = [] + if data is None: + regions = self.view.sel() + else: + if type(data) != types.ListType: + data = [data] + regions = [] + for item in data: + if type(item) == types.IntType or item.isdigit(): + regions.append(self.view.line(self.view.text_point(int(item) - 1, 0))) + else: + regions.append(item) + for region in regions: + lines.extend(self.view.split_by_newlines(region)) + return [self.view.line(line) for line in lines] + + def rows(self, lines): + if not type(lines) == types.ListType: + lines = [lines] + return [self.view.rowcol(line.begin())[0] + 1 for line in lines] + + def insert_click(self, a, b, click_type, data): + insert_before = 0 + new_region = sublime.Region(a, b) + regions = self.view.get_regions('swi_log_clicks') + for region in regions: + if new_region.b < region.a: + break + insert_before += 1 + + self.clicks.insert(insert_before, {'click_type': click_type, 'data': data}) + + regions.append(new_region) + self.view.add_regions('swi_log_clicks', regions, get_setting('interactive_scope'), sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED) + + def print_click(self, edit, position, text, click_type, data): + insert_length = self.insert(edit, position, text) + self.insert_click(position, position + insert_length, click_type, data) + + def remove_click(self, index): + regions = self.view.get_regions('swi_log_clicks') + del regions[index] + self.view.add_regions('swi_log_clicks', regions, get_setting('interactive_scope'), sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED) + + def clear_clicks(self): + self.clicks = [] + + def view_breakpoints(self): + self.view.erase_regions('swi_breakpoint_inactive') + self.view.erase_regions('swi_breakpoint_active') + self.view.erase_regions('swi_breakpoint_current') + + if not self.view.file_name(): + return + + breaks = get_breakpoints_by_full_path(self.view.file_name()) + + if not breaks: + return + + enabled = [] + disabled = [] + + for key in breaks.keys(): + if breaks[key]['status'] == 'enabled' and str(current_line) != key: + enabled.append(key) + if breaks[key]['status'] == 'disabled' and str(current_line) != key: + disabled.append(key) + + self.view.add_regions('swi_breakpoint_active', self.lines(enabled), get_setting('breakpoint_scope'), breakpoint_active_icon, sublime.HIDDEN) + self.view.add_regions('swi_breakpoint_inactive', self.lines(disabled), get_setting('breakpoint_scope'), breakpoint_inactive_icon, sublime.HIDDEN) + if current_line: + self.view.add_regions('swi_breakpoint_current', self.lines([current_line]), get_setting('current_line_scope'), breakpoint_current_icon, sublime.DRAW_EMPTY) + + def check_click(self): + if not self.name().startswith('SWI'): + return + + cursor = self.sel()[0].a + + if cursor == self.prev_click_position: + return + + self.prev_click_position = cursor + click_counter = 0 + click_regions = self.get_regions('swi_log_clicks') + for click in click_regions: + if cursor > click.a and cursor < click.b: + + if click_counter < len(self.clicks): + click = self.clicks[click_counter] + + if click['click_type'] == 'goto_file_line': + open_script_and_focus_line(click['data']['scriptId'], click['data']['line']) + + if click['click_type'] == 'goto_call_frame': + callFrame = click['data']['callFrame'] + + scriptId = callFrame.location.scriptId + line_number = callFrame.location.lineNumber + file_name = find_script(str(scriptId)) + + open_script_and_focus_line(scriptId, line_number) + + first_scope = callFrame.scopeChain[0] + + if open_stack_current_in_new_tab: + title = {'objectId': first_scope.object.objectId, 'name': "%s:%s (%s)" % (file_name.split('/')[-1], line_number, first_scope.type)} + else: + title = {'objectId': first_scope.object.objectId, 'name': "Breakpoint Local"} + + sublime.set_timeout(lambda: protocol.send(wip.Runtime.getProperties(first_scope.object.objectId, True), console_add_properties, title), 30) + + global current_call_frame + current_call_frame = callFrame.callFrameId + + global current_call_frame_position + current_call_frame_position = "%s:%s" % (file_name.split('/')[-1], line_number) + + if click['click_type'] == 'get_params': + if protocol: + protocol.send(wip.Runtime.getProperties(click['data']['objectId'], True), console_add_properties, click['data']) + + if click['click_type'] == 'command': + self.remove_click(click_counter) + self.run_command(click['data']) + + click_counter += 1 + + +def lookup_view(v): + ''' + Convert a Sublime View into an SWIDebugView + ''' + if isinstance(v, SwiDebugView): + return v + if isinstance(v, sublime.View): + id = v.buffer_id() + if id in buffers: + buffers[id].view = v + else: + buffers[id] = SwiDebugView(v) + return buffers[id] + return None + + +#################################################################################### +# EventListener +#################################################################################### + +class EventListener(sublime_plugin.EventListener): + def on_new(self, view): + lookup_view(view).on_new() + + def on_clone(self, view): + lookup_view(view).on_clone() + + def on_load(self, view): + lookup_view(view).view_breakpoints() + lookup_view(view).on_load() + + def on_close(self, view): + lookup_view(view).on_close() + + def on_pre_save(self, view): + lookup_view(view).on_pre_save() + + def on_post_save(self, view): + print view.file_name().find('.js') + if protocol and reload_on_save: + protocol.send(wip.Network.clearBrowserCache()) + if view.file_name().find('.css') > 0 or view.file_name().find('.less') > 0 or view.file_name().find('.sass') > 0 or view.file_name().find('.scss') > 0: + protocol.send(wip.Runtime.evaluate("var files = document.getElementsByTagName('link');var links = [];for (var a = 0, l = files.length; a < l; a++) {var elem = files[a];var rel = elem.rel;if (typeof rel != 'string' || rel.length === 0 || rel === 'stylesheet') {links.push({'elem': elem,'href': elem.getAttribute('href').split('?')[0],'last': false});}}for ( a = 0, l = links.length; a < l; a++) {var link = links[a];link.elem.setAttribute('href', (link.href + '?x=' + Math.random()));}")) + elif view.file_name().find('.js') > 0: + scriptId = find_script(view.file_name()) + if scriptId and set_script_source: + scriptSource = view.substr(sublime.Region(0, view.size())) + protocol.send(wip.Debugger.setScriptSource(scriptId, scriptSource), self.paused) + else: + protocol.send(wip.Page.reload(), on_reload) + else: + protocol.send(wip.Page.reload(), on_reload) + lookup_view(view).on_post_save() + + def on_modified(self, view): + lookup_view(view).on_modified() + lookup_view(view).view_breakpoints() + + def on_selection_modified(self, view): + #lookup_view(view).on_selection_modified() + global timing + now = time.time() + if now - timing > 0.08: + timing = now + sublime.set_timeout(lambda: lookup_view(view).check_click(), 0) + else: + timing = now + + def on_activated(self, view): + lookup_view(view).on_activated() + lookup_view(view).view_breakpoints() + + def on_deactivated(self, view): + lookup_view(view).on_deactivated() + + def on_query_context(self, view, key, operator, operand, match_all): + lookup_view(view).on_query_context(key, operator, operand, match_all) + + def paused(self, command): + global paused + + if not paused: + return + + data = command.data + sublime.set_timeout(lambda: window.set_layout(get_setting('stack_layout')), 0) + + sublime.set_timeout(lambda: console_show_stack(data['callFrames']), 0) + + scriptId = data['callFrames'][0].location.scriptId + line_number = data['callFrames'][0].location.lineNumber + file_name = find_script(str(scriptId)) + first_scope = data['callFrames'][0].scopeChain[0] + + if open_stack_current_in_new_tab: + title = {'objectId': first_scope.object.objectId, 'name': "%s:%s (%s)" % (file_name, line_number, first_scope.type)} + else: + title = {'objectId': first_scope.object.objectId, 'name': "Breakpoint Local"} + + sublime.set_timeout(lambda: protocol.send(wip.Runtime.getProperties(first_scope.object.objectId, True), console_add_properties, title), 30) + sublime.set_timeout(lambda: open_script_and_focus_line(scriptId, line_number), 100) + + +#################################################################################### +# GLOBAL HANDLERS +#################################################################################### + +def on_reload(command): + global file_to_scriptId + file_to_scriptId = [] + + +#################################################################################### +# Console +#################################################################################### + +def find_view(console_type, title=''): + found = False + v = None + window = sublime.active_window() + + if console_type.startswith('console'): + group = 1 + fullName = "SWI Console" + + if console_type == 'stack': + group = 2 + fullName = "SWI Breakpoint stack" + + if console_type.startswith('eval'): + group = 1 + fullName = "SWI Object evaluate" + + fullName = fullName + ' ' + title + + for v in window.views(): + if v.name() == fullName: + found = True + break + + if not found: + v = window.new_file() + v.set_scratch(True) + v.set_read_only(False) + v.set_name(fullName) + v.settings().set('word_wrap', False) + + window.set_view_index(v, group, 0) + + if console_type.startswith('console'): + v.set_syntax_file('Packages/Web Inspector/swi_log.tmLanguage') + + if console_type == 'stack': + v.set_syntax_file('Packages/Web Inspector/swi_stack.tmLanguage') + + if console_type.startswith('eval'): + v.set_syntax_file('Packages/Web Inspector/swi_log.tmLanguage') + + window.focus_view(v) + + v.set_read_only(False) + + return lookup_view(v) + + +def clear_view(view): + v = find_view(view) + + edit = v.begin_edit() + + v.erase(edit, sublime.Region(0, v.size())) + + v.end_edit(edit) + v.show(v.size()) + window.focus_group(0) + lookup_view(v).clear_clicks() + + +def console_repeat_message(count): + v = find_view('console') + + edit = v.begin_edit() + + if count > 2: + erase_to = v.size() - len(u' \u21AA Repeat:' + str(count - 1) + '\n') + v.erase(edit, sublime.Region(erase_to, v.size())) + v.insert(edit, v.size(), u' \u21AA Repeat:' + str(count) + '\n') + + v.end_edit(edit) + v.show(v.size()) + window.focus_group(0) + + +def console_add_evaluate(eval_object): + v = find_view('console') + + edit = v.begin_edit() + + insert_position = v.size() + v.insert(edit, insert_position, str(eval_object) + ' ') + + v.insert(edit, v.size(), "\n") + + v.end_edit(edit) + v.show(v.size()) + window.focus_group(0) + + +def console_add_message(message): + v = find_view('console') + + edit = v.begin_edit() + + if message.level == 'debug': + level = "D" + if message.level == 'error': + level = "E" + if message.level == 'log': + level = "L" + if message.level == 'tip': + level = "T" + if message.level == 'warning': + level = "W" + + v.insert(edit, v.size(), "[%s] " % (level)) + # Add file and line + scriptId = None + if message.url: + scriptId = find_script(message.url) + if scriptId: + url = message.url.split("/")[-1] + else: + url = message.url + else: + url = '---' + + if message.line: + line = message.line + else: + line = 0 + + insert_position = v.size() + insert_length = v.insert(edit, insert_position, "%s:%d" % (url, line)) + + if scriptId and line > 0: + v.insert_click(insert_position, insert_position + insert_length, 'goto_file_line', {'scriptId': scriptId, 'line': str(line)}) + + v.insert(edit, v.size(), " ") + + # Add text + if len(message.parameters) > 0: + for param in message.parameters: + insert_position = v.size() + insert_length = v.insert(edit, insert_position, str(param) + ' ') + if param.type == 'object': + v.insert_click(insert_position, insert_position + insert_length - 1, 'get_params', {'objectId': param.objectId}) + else: + v.insert(edit, v.size(), message.text) + + v.insert(edit, v.size(), "\n") + + if level == "E" and message.stackTrace: + stack_start = v.size() + + for callFrame in message.stackTrace: + scriptId = find_script(callFrame.url) + file_name = callFrame.url.split('/')[-1] + + v.insert(edit, v.size(), u'\t\u21E1 ') + + if scriptId: + v.print_click(edit, v.size(), "%s:%s %s" % (file_name, callFrame.lineNumber, callFrame.functionName), 'goto_file_line', {'scriptId': scriptId, 'line': str(callFrame.lineNumber)}) + else: + v.insert(edit, v.size(), "%s:%s %s" % (file_name, callFrame.lineNumber, callFrame.functionName)) + + v.insert(edit, v.size(), "\n") + + v.fold(sublime.Region(stack_start-1, v.size()-1)) + + v.end_edit(edit) + v.show(v.size()) + window.focus_group(0) + + +def console_add_properties(command): + sublime.set_timeout(lambda: console_print_properties(command), 0) + + +def console_print_properties(command): + + if 'name' in command.options: + name = command.options['name'] + else: + name = str(command.options['objectId']) + + if 'prev' in command.options: + prev = command.options['prev'] + ' -> ' + name + else: + prev = name + + v = find_view('eval', name) + + edit = v.begin_edit() + v.erase(edit, sublime.Region(0, v.size())) + + v.insert(edit, v.size(), prev) + + v.insert(edit, v.size(), "\n\n") + + for prop in command.data: + v.insert(edit, v.size(), prop.name + ': ') + insert_position = v.size() + if(prop.value): + insert_length = v.insert(edit, insert_position, str(prop.value) + '\n') + if prop.value.type == 'object': + v.insert_click(insert_position, insert_position + insert_length - 1, 'get_params', {'objectId': prop.value.objectId, 'name': prop.name, 'prev': prev}) + + v.end_edit(edit) + v.show(0) + window.focus_group(0) + + +def console_show_stack(callFrames): + + v = find_view('stack') + + edit = v.begin_edit() + v.erase(edit, sublime.Region(0, v.size())) + + v.insert(edit, v.size(), "\n") + v.print_click(edit, v.size(), "\tResume\t", 'command', 'swi_debug_resume') + v.print_click(edit, v.size(), "\tStep Over\t", 'command', 'swi_debug_step_over') + v.print_click(edit, v.size(), "\tStep Into\t", 'command', 'swi_debug_step_into') + v.print_click(edit, v.size(), "\tStep Out\t", 'command', 'swi_debug_step_out') + v.insert(edit, v.size(), "\n\n") + + for callFrame in callFrames: + line = str(callFrame.location.lineNumber) + file_name = find_script(str(callFrame.location.scriptId)) + + if file_name: + file_name = file_name.split('/')[-1] + else: + file_name = '-' + + insert_position = v.size() + insert_length = v.insert(edit, insert_position, "%s:%s" % (file_name, line)) + + if file_name != '-': + v.insert_click(insert_position, insert_position + insert_length, 'goto_call_frame', {'callFrame': callFrame}) + + v.insert(edit, v.size(), " %s\n" % (callFrame.functionName)) + + for scope in callFrame.scopeChain: + v.insert(edit, v.size(), "\t") + insert_position = v.size() + insert_length = v.insert(edit, v.size(), "%s\n" % (scope.type)) + if scope.object.type == 'object': + v.insert_click(insert_position, insert_position + insert_length - 1, 'get_params', {'objectId': scope.object.objectId, 'name': "%s:%s (%s)" % (file_name, line, scope.type)}) + + v.end_edit(edit) + v.show(0) + window.focus_group(0) + + +#################################################################################### +# All about breaks +#################################################################################### + + +def get_project(): + if not sublime.active_window(): + return None + win_id = sublime.active_window().id() + project = None + reg_session = os.path.join(sublime.packages_path(), "..", "Settings", "Session.sublime_session") + auto_save = os.path.join(sublime.packages_path(), "..", "Settings", "Auto Save Session.sublime_session") + session = auto_save if os.path.exists(auto_save) else reg_session + + if not os.path.exists(session) or win_id == None: + return project + + try: + with open(session, 'r') as f: + # Tabs in strings messes things up for some reason + j = json.JSONDecoder(strict=False).decode(f.read()) + for w in j['windows']: + if w['window_id'] == win_id: + if "workspace_name" in w: + if sublime.platform() == "windows": + # Account for windows specific formatting + project = os.path.normpath(w["workspace_name"].lstrip("/").replace("/", ":/", 1)) + else: + project = w["workspace_name"] + break + except: + pass + + # Throw out empty project names + if project == None or re.match(".*\\.sublime-project", project) == None or not os.path.exists(project): + project = None + + return project + + +def load_breaks(): + # if not get_project(): + # sublime.error_message('Can\' load breaks') + # brk_object = {} + # return + # breaks_file = os.path.splitext(get_project())[0] + '-breaks.json' + # global brk_object + # if not os.path.exists(breaks_file): + # with open(breaks_file, 'w') as f: + # f.write('{}') + + # try: + # with open(breaks_file, 'r') as f: + # brk_object = json.loads(f.read()) + # except: + # brk_object = {} + global brk_object + brk_object = get_setting('breaks') + + +def save_breaks(): + # try: + # breaks_file = os.path.splitext(get_project())[0] + '-breaks.json' + # with open(breaks_file, 'w') as f: + # f.write(json.dumps(brk_object, sort_keys=True, indent=4, separators=(',', ': '))) + # except: + # pass + s = sublime.load_settings("swi.sublime-settings") + s.set('breaks', brk_object) + sublime.save_settings("swi.sublime-settings") + + #print breaks + + +def full_path_to_file_name(path): + return os.path.basename(os.path.realpath(path)) + + +def set_breakpoint_by_full_path(file_name, line, status='disabled', breakpointId=None): + breaks = get_breakpoints_by_full_path(file_name) + + if not line in breaks: + breaks[line] = {} + breaks[line]['status'] = status + breaks[line]['breakpointId'] = str(breakpointId) + else: + breaks[line]['status'] = status + breaks[line]['breakpointId'] = str(breakpointId) + save_breaks() + + +def del_breakpoint_by_full_path(file_name, line): + breaks = get_breakpoints_by_full_path(file_name) + + if line in breaks: + del breaks[line] + save_breaks() + + +def get_breakpoints_by_full_path(file_name): + if file_name in brk_object: + return brk_object[file_name] + + return None + + +def set_breakpoint_by_scriptId(scriptId, line, status='disabled', breakpointId=None): + file_name = find_script(str(scriptId)) + if file_name: + set_breakpoint_by_full_path(file_name, line, status, breakpointId) + + +def del_breakpoint_by_scriptId(scriptId, line): + file_name = find_script(str(scriptId)) + if file_name: + del_breakpoint_by_full_path(file_name, line) + + +def get_breakpoints_by_scriptId(scriptId): + file_name = find_script(str(scriptId)) + if file_name: + return get_breakpoints_by_full_path(file_name) + + return None + + +def init_breakpoint_for_file(file_path): + if not file_path in brk_object: + brk_object[file_path] = {} + + +def disable_all_breakpoints(): + for file_name in brk_object: + for line in brk_object[file_name]: + brk_object[file_name][line]['status'] = 'disabled' + if 'breakpointId' in brk_object[file_name][line]: + del brk_object[file_name][line]['breakpointId'] + + save_breaks() + + +#################################################################################### +# Utils +#################################################################################### + +def get_setting(key): + s = sublime.load_settings("swi.sublime-settings") + if s and s.has(key): + return s.get(key) + + +def find_script(scriptId_or_file_or_url): + sha = hashlib.sha1(scriptId_or_file_or_url).hexdigest() + for item in file_to_scriptId: + if item['scriptId'] == scriptId_or_file_or_url: + return item['file'] + if item['file'] == scriptId_or_file_or_url: + return item['scriptId'] + if item['sha1'] == sha: + return item['scriptId'] + + return None + +def get_script(scriptId_or_file_or_url): + sha = hashlib.sha1(scriptId_or_file_or_url).hexdigest() + for item in file_to_scriptId: + if item['scriptId'] == scriptId_or_file_or_url: + return item + if item['file'] == scriptId_or_file_or_url: + return item + if item['sha1'] == sha: + return item + + return None + + +def do_when(conditional, callback, *args, **kwargs): + if conditional(): + return callback(*args, **kwargs) + sublime.set_timeout(functools.partial(do_when, conditional, callback, *args, **kwargs), 50) + + +def open_script_and_focus_line(scriptId, line_number): + file_name = find_script(str(scriptId)) + window = sublime.active_window() + window.focus_group(0) + view = window.open_file(file_name, sublime.TRANSIENT) + do_when(lambda: not view.is_loading(), lambda: view.run_command("goto_line", {"line": line_number})) + + +def open_script_and_show_current_breakpoint(scriptId, line_number): + file_name = find_script(str(scriptId)) + window.focus_group(0) + view = window.open_file(file_name, sublime.TRANSIENT) + do_when(lambda: not view.is_loading(), lambda: view.run_command("goto_line", {"line": line_number})) + #do_when(lambda: not view.is_loading(), lambda: focus_line_and_highlight(view, line_number)) + + +def focus_line_and_highlight(view, line_number): + view.run_command("goto_line", {"line": line_number}) + global current_line + current_line = line_number + lookup_view(view).view_breakpoints() + +sublime.set_timeout(lambda: load_breaks(), 1000) \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/swi.sublime-settings b/sublime/Packages/Web Inspector/swi.sublime-settings new file mode 100644 index 0000000..7449cbb --- /dev/null +++ b/sublime/Packages/Web Inspector/swi.sublime-settings @@ -0,0 +1,26 @@ +{ + "chrome_path": { + "osx": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + "windows": "C:\\Program Files\\Google\\Chrome\\chrome.exe", + "linux": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" + }, + "chrome_remote_port": "9222", + "breakpoint_scope": "swi.breakpoint", + "current_line_scope": "swi.current", + "interactive_scope": "mcol_0088CCFF.settings", + "stack_layout": { + "cols": [0.0, 0.6, 1.0], + "rows": [0.0, 0.7, 1.0], + "cells": [[0, 0, 2, 1], [0, 1, 1, 2], [1, 1, 2, 2]] + }, + "console_layout": { + "cols": [0.0, 0.6, 1.0], + "rows": [0.0, 0.7, 1.0], + "cells": [[0, 0, 2, 1], [0, 1, 1, 2], [1, 1, 2, 2]] + }, + "reload_on_start": true, + "reload_on_save": true, + "set_script_source": false, + "open_stack_current_in_new_tab": false, + "breaks": {} +} \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/swi_log.JSON-tmLanguage b/sublime/Packages/Web Inspector/swi_log.JSON-tmLanguage new file mode 100644 index 0000000..6b02529 --- /dev/null +++ b/sublime/Packages/Web Inspector/swi_log.JSON-tmLanguage @@ -0,0 +1,115 @@ +{ + "name": "Web Inspector (Log)", + "scopeName": "jsd.log", + "patterns": [ + { + "match": "^(\\[D\\])\\s(.*?):(\\d+)\\s", + "name": "jsd.log.debug", + "captures": { + "1": { + "name": "mcol_339900FF.settings" + }, + "2": { + "name": "support.type.settings" + }, + "3": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^(\\[E\\])\\s(.*?):(\\d+)\\s", + "name": "jsd.log.error", + "captures": { + "1": { + "name": "mcol_CC0000FF.settings" + }, + "2": { + "name": "support.type.settings" + }, + "3": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^(\\[W\\])\\s(.*?):(\\d+)\\s", + "name": "jsd.log.warn", + "captures": { + "1": { + "name": "mcol_F93F07FF.settings" + }, + "2": { + "name": "support.type.settings" + }, + "3": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^(\\[L\\])\\s(.*?):(\\d+)\\s", + "name": "jsd.log.log", + "captures": { + "1": { + "name": "mcol_0088CCFF.settings" + }, + "2": { + "name": "support.type.settings" + }, + "3": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^(\\[T\\])\\s(.*?):(\\d+)\\s", + "name": "jsd.log.tip", + "captures": { + "1": { + "name": "mcol_800080FF.settings" + }, + "2": { + "name": "support.type.settings" + }, + "3": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^\\t(.+)\\s(.*?):(\\d+)", + "name": "jsd.log.object", + "captures": { + "1": { + "name": "mcol_CC0000FF.settings" + }, + "2": { + "name": "support.type.settings" + }, + "3": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^(.*?:)\\s(.*?)$", + "name": "jsd.log.property", + "captures": { + "1": { + "name": "variable.parameter.settings" + } + } + }, + { + "match": "^(.*?)$", + "name": "jsd.log.property_object_name", + "captures": { + "1": { + "name": "entity.name.function" + } + } + } + ], + "uuid": "ca03e751-04ef-4330-9a6b-9b99aae1c418" +} \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/swi_log.tmLanguage b/sublime/Packages/Web Inspector/swi_log.tmLanguage new file mode 100644 index 0000000..a5c436b --- /dev/null +++ b/sublime/Packages/Web Inspector/swi_log.tmLanguage @@ -0,0 +1,187 @@ + + + + + name + Web Inspector (Log) + patterns + + + captures + + 1 + + name + mcol_339900FF.settings + + 2 + + name + support.type.settings + + 3 + + name + variable.parameter.settings + + + match + ^(\[D\])\s(.*?):(\d+)\s + name + jsd.log.debug + + + captures + + 1 + + name + mcol_CC0000FF.settings + + 2 + + name + support.type.settings + + 3 + + name + variable.parameter.settings + + + match + ^(\[E\])\s(.*?):(\d+)\s + name + jsd.log.error + + + captures + + 1 + + name + mcol_F93F07FF.settings + + 2 + + name + support.type.settings + + 3 + + name + variable.parameter.settings + + + match + ^(\[W\])\s(.*?):(\d+)\s + name + jsd.log.warn + + + captures + + 1 + + name + mcol_0088CCFF.settings + + 2 + + name + support.type.settings + + 3 + + name + variable.parameter.settings + + + match + ^(\[L\])\s(.*?):(\d+)\s + name + jsd.log.log + + + captures + + 1 + + name + mcol_800080FF.settings + + 2 + + name + support.type.settings + + 3 + + name + variable.parameter.settings + + + match + ^(\[T\])\s(.*?):(\d+)\s + name + jsd.log.tip + + + captures + + 1 + + name + mcol_CC0000FF.settings + + 2 + + name + support.type.settings + + 3 + + name + variable.parameter.settings + + + match + ^\t(.+)\s(.*?):(\d+) + name + jsd.log.object + + + captures + + 1 + + name + variable.parameter.settings + + + match + ^(.*?:)\s(.*?)$ + name + jsd.log.property + + + captures + + 1 + + name + entity.name.function + + + match + ^(.*?)$ + name + jsd.log.property_object_name + + + scopeName + jsd.log + uuid + ca03e751-04ef-4330-9a6b-9b99aae1c418 + + diff --git a/sublime/Packages/Web Inspector/swi_stack.JSON-tmLanguage b/sublime/Packages/Web Inspector/swi_stack.JSON-tmLanguage new file mode 100644 index 0000000..c9c61c9 --- /dev/null +++ b/sublime/Packages/Web Inspector/swi_stack.JSON-tmLanguage @@ -0,0 +1,17 @@ +{ "name": "Web Inspector (Stack)", + "scopeName": "jsd.stack", + "patterns": [ + { "match": "^(.*?):(\\d+)(.*?)$", + "name": "jsd.log.debug", + "captures": { + "1": { "name": "support.type.settings" }, + "2": { "name": "variable.parameter.settings" }, + "3": { "name": "entity.name.function" } + } + }, + { "match": "local|global|closure", + "name": "keyword" + } + ], + "uuid": "ca03e751-04ef-4330-9a6b-9b99aae1c418" +} \ No newline at end of file diff --git a/sublime/Packages/Web Inspector/swi_stack.tmLanguage b/sublime/Packages/Web Inspector/swi_stack.tmLanguage new file mode 100644 index 0000000..6b7fb4b --- /dev/null +++ b/sublime/Packages/Web Inspector/swi_stack.tmLanguage @@ -0,0 +1,45 @@ + + + + + name + Web Inspector (Stack) + patterns + + + captures + + 1 + + name + support.type.settings + + 2 + + name + variable.parameter.settings + + 3 + + name + entity.name.function + + + match + ^(.*?):(\d+)(.*?)$ + name + jsd.log.debug + + + match + local|global|closure + name + keyword + + + scopeName + jsd.stack + uuid + ca03e751-04ef-4330-9a6b-9b99aae1c418 + + diff --git a/sublime/Packages/Web Inspector/websocket.py b/sublime/Packages/Web Inspector/websocket.py new file mode 100644 index 0000000..71d8b7e --- /dev/null +++ b/sublime/Packages/Web Inspector/websocket.py @@ -0,0 +1,742 @@ +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" + + +import socket +from urlparse import urlparse +import os +import struct +import uuid +import sha +import base64 +import logging + +""" +websocket python client. +========================= + +This version support only hybi-13. +Please see http://tools.ietf.org/html/rfc6455 for protocol. +""" + + +# websocket supported version. +VERSION = 13 + +# closing frame status codes. +STATUS_NORMAL = 1000 +STATUS_GOING_AWAY = 1001 +STATUS_PROTOCOL_ERROR = 1002 +STATUS_UNSUPPORTED_DATA_TYPE = 1003 +STATUS_STATUS_NOT_AVAILABLE = 1005 +STATUS_ABNORMAL_CLOSED = 1006 +STATUS_INVALID_PAYLOAD = 1007 +STATUS_POLICY_VIOLATION = 1008 +STATUS_MESSAGE_TOO_BIG = 1009 +STATUS_INVALID_EXTENSION = 1010 +STATUS_UNEXPECTED_CONDITION = 1011 +STATUS_TLS_HANDSHAKE_ERROR = 1015 + +logger = logging.getLogger() + +class WebSocketException(Exception): + """ + websocket exeception class. + """ + pass + +default_timeout = None +traceEnabled = False + +def enableTrace(tracable): + """ + turn on/off the tracability. + + tracable: boolean value. if set True, tracability is enabled. + """ + global traceEnabled + traceEnabled = tracable + if tracable: + if not logger.handlers: + logger.addHandler(logging.StreamHandler()) + logger.setLevel(logging.DEBUG) + +def setdefaulttimeout(timeout): + """ + Set the global timeout setting to connect. + + timeout: default socket timeout time. This value is second. + """ + global default_timeout + default_timeout = timeout + +def getdefaulttimeout(): + """ + Return the global timeout setting(second) to connect. + """ + return default_timeout + +def _parse_url(url): + """ + parse url and the result is tuple of + (hostname, port, resource path and the flag of secure mode) + + url: url string. + """ + if ":" not in url: + raise ValueError("url is invalid") + + scheme, url = url.split(":", 1) + url = url.rstrip("/") + + parsed = urlparse(url, scheme="http") + if parsed.hostname: + hostname = parsed.hostname + else: + raise ValueError("hostname is invalid") + port = 0 + if parsed.port: + port = parsed.port + + is_secure = False + if scheme == "ws": + if not port: + port = 80 + elif scheme == "wss": + is_secure = True + if not port: + port = 443 + else: + raise ValueError("scheme %s is invalid" % scheme) + + if parsed.path: + resource = parsed.path + else: + resource = "/" + + return (hostname, port, resource, is_secure) + +def create_connection(url, timeout=None, **options): + """ + connect to url and return websocket object. + + Connect to url and return the WebSocket object. + Passing optional timeout parameter will set the timeout on the socket. + If no timeout is supplied, the global default timeout setting returned by getdefauttimeout() is used. + You can customize using 'options'. + If you set "headers" dict object, you can set your own custom header. + + >>> conn = create_connection("ws://echo.websocket.org/", + ... headers={"User-Agent": "MyProgram"}) + + timeout: socket timeout time. This value is integer. + if you set None for this value, it means "use default_timeout value" + + options: current support option is only "header". + if you set header as dict value, the custom HTTP headers are added. + """ + websock = WebSocket() + websock.settimeout(timeout != None and timeout or default_timeout) + websock.connect(url, **options) + return websock + +_MAX_INTEGER = (1 << 32) -1 +_AVAILABLE_KEY_CHARS = range(0x21, 0x2f + 1) + range(0x3a, 0x7e + 1) +_MAX_CHAR_BYTE = (1<<8) -1 + +# ref. Websocket gets an update, and it breaks stuff. +# http://axod.blogspot.com/2010/06/websocket-gets-update-and-it-breaks.html + +def _create_sec_websocket_key(): + uid = uuid.uuid4() + return base64.encodestring(uid.bytes).strip() + +_HEADERS_TO_CHECK = { + "upgrade": "websocket", + "connection": "upgrade", + } + +class _SSLSocketWrapper(object): + def __init__(self, sock): + self.ssl = socket.ssl(sock) + + def recv(self, bufsize): + return self.ssl.read(bufsize) + + def send(self, payload): + return self.ssl.write(payload) + +_BOOL_VALUES = (0, 1) +def _is_bool(*values): + for v in values: + if v not in _BOOL_VALUES: + return False + + return True + +class ABNF(object): + """ + ABNF frame class. + see http://tools.ietf.org/html/rfc5234 + and http://tools.ietf.org/html/rfc6455#section-5.2 + """ + + # operation code values. + OPCODE_TEXT = 0x1 + OPCODE_BINARY = 0x2 + OPCODE_CLOSE = 0x8 + OPCODE_PING = 0x9 + OPCODE_PONG = 0xa + + # available operation code value tuple + OPCODES = (OPCODE_TEXT, OPCODE_BINARY, OPCODE_CLOSE, + OPCODE_PING, OPCODE_PONG) + + # opcode human readable string + OPCODE_MAP = { + OPCODE_TEXT: "text", + OPCODE_BINARY: "binary", + OPCODE_CLOSE: "close", + OPCODE_PING: "ping", + OPCODE_PONG: "pong" + } + + # data length threashold. + LENGTH_7 = 0x7d + LENGTH_16 = 1 << 16 + LENGTH_63 = 1 << 63 + + def __init__(self, fin = 0, rsv1 = 0, rsv2 = 0, rsv3 = 0, + opcode = OPCODE_TEXT, mask = 1, data = ""): + """ + Constructor for ABNF. + please check RFC for arguments. + """ + self.fin = fin + self.rsv1 = rsv1 + self.rsv2 = rsv2 + self.rsv3 = rsv3 + self.opcode = opcode + self.mask = mask + self.data = data + self.get_mask_key = os.urandom + + @staticmethod + def create_frame(data, opcode): + """ + create frame to send text, binary and other data. + + data: data to send. This is string value(byte array). + if opcode is OPCODE_TEXT and this value is uniocde, + data value is conveted into unicode string, automatically. + + opcode: operation code. please see OPCODE_XXX. + """ + if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode): + data = data.encode("utf-8") + # mask must be set if send data from client + return ABNF(1, 0, 0, 0, opcode, 1, data) + + def format(self): + """ + format this object to string(byte array) to send data to server. + """ + if not _is_bool(self.fin, self.rsv1, self.rsv2, self.rsv3): + raise ValueError("not 0 or 1") + if self.opcode not in ABNF.OPCODES: + raise ValueError("Invalid OPCODE") + length = len(self.data) + if length >= ABNF.LENGTH_63: + raise ValueError("data is too long") + + frame_header = chr(self.fin << 7 + | self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 + | self.opcode) + if length < ABNF.LENGTH_7: + frame_header += chr(self.mask << 7 | length) + elif length < ABNF.LENGTH_16: + frame_header += chr(self.mask << 7 | 0x7e) + frame_header += struct.pack("!H", length) + else: + frame_header += chr(self.mask << 7 | 0x7f) + frame_header += struct.pack("!Q", length) + + if not self.mask: + return frame_header + self.data + else: + mask_key = self.get_mask_key(4) + return frame_header + self._get_masked(mask_key) + + def _get_masked(self, mask_key): + s = ABNF.mask(mask_key, self.data) + return mask_key + "".join(s) + + @staticmethod + def mask(mask_key, data): + """ + mask or unmask data. Just do xor for each byte + + mask_key: 4 byte string(byte). + + data: data to mask/unmask. + """ + _m = map(ord, mask_key) + _d = map(ord, data) + for i in range(len(_d)): + _d[i] ^= _m[i % 4] + s = map(chr, _d) + return "".join(s) + +class WebSocket(object): + """ + Low level WebSocket interface. + This class is based on + The WebSocket protocol draft-hixie-thewebsocketprotocol-76 + http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 + + We can connect to the websocket server and send/recieve data. + The following example is a echo client. + + >>> import websocket + >>> ws = websocket.WebSocket() + >>> ws.connect("ws://echo.websocket.org") + >>> ws.send("Hello, Server") + >>> ws.recv() + 'Hello, Server' + >>> ws.close() + + get_mask_key: a callable to produce new mask keys, see the set_mask_key + function's docstring for more details + """ + def __init__(self, get_mask_key = None): + """ + Initalize WebSocket object. + """ + self.connected = False + self.io_sock = self.sock = socket.socket() + self.get_mask_key = get_mask_key + + def set_mask_key(self, func): + """ + set function to create musk key. You can custumize mask key generator. + Mainly, this is for testing purpose. + + func: callable object. the fuct must 1 argument as integer. + The argument means length of mask key. + This func must be return string(byte array), + which length is argument specified. + """ + self.get_mask_key = func + + def settimeout(self, timeout): + """ + Set the timeout to the websocket. + + timeout: timeout time(second). + """ + self.sock.settimeout(timeout) + + def gettimeout(self): + """ + Get the websocket timeout(second). + """ + return self.sock.gettimeout() + + def connect(self, url, **options): + """ + Connect to url. url is websocket url scheme. ie. ws://host:port/resource + You can customize using 'options'. + If you set "headers" dict object, you can set your own custom header. + + >>> ws = WebSocket() + >>> ws.connect("ws://echo.websocket.org/", + ... headers={"User-Agent": "MyProgram"}) + + timeout: socket timeout time. This value is integer. + if you set None for this value, + it means "use default_timeout value" + + options: current support option is only "header". + if you set header as dict value, + the custom HTTP headers are added. + + """ + hostname, port, resource, is_secure = _parse_url(url) + # TODO: we need to support proxy + self.sock.connect((hostname, port)) + if is_secure: + self.io_sock = _SSLSocketWrapper(self.sock) + self._handshake(hostname, port, resource, **options) + + def _handshake(self, host, port, resource, **options): + sock = self.io_sock + headers = [] + headers.append("GET %s HTTP/1.1" % resource) + headers.append("Upgrade: websocket") + headers.append("Connection: Upgrade") + if port == 80: + hostport = host + else: + hostport = "%s:%d" % (host, port) + headers.append("Host: %s" % hostport) + headers.append("Origin: %s" % hostport) + + key = _create_sec_websocket_key() + headers.append("Sec-WebSocket-Key: %s" % key) + headers.append("Sec-WebSocket-Protocol: chat, superchat") + headers.append("Sec-WebSocket-Version: %s" % VERSION) + if "header" in options: + headers.extend(options["header"]) + + headers.append("") + headers.append("") + + header_str = "\r\n".join(headers) + sock.send(header_str) + if traceEnabled: + logger.debug( "--- request header ---") + logger.debug( header_str) + logger.debug("-----------------------") + + status, resp_headers = self._read_headers() + if status != 101: + self.close() + raise WebSocketException("Handshake Status %d" % status) + + success = self._validate_header(resp_headers, key) + if not success: + self.close() + raise WebSocketException("Invalid WebSocket Header") + + self.connected = True + + def _validate_header(self, headers, key): + for k, v in _HEADERS_TO_CHECK.iteritems(): + r = headers.get(k, None) + if not r: + return False + r = r.lower() + if v != r: + return False + + result = headers.get("sec-websocket-accept", None) + if not result: + return False + result = result.lower() + + value = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + hashed = base64.encodestring(sha.sha(value).digest()).strip().lower() + return hashed == result + + def _read_headers(self): + status = None + headers = {} + if traceEnabled: + logger.debug("--- response header ---") + + while True: + line = self._recv_line() + if line == "\r\n": + break + line = line.strip() + if traceEnabled: + logger.debug(line) + if not status: + status_info = line.split(" ", 2) + status = int(status_info[1]) + else: + kv = line.split(":", 1) + if len(kv) == 2: + key, value = kv + headers[key.lower()] = value.strip().lower() + else: + raise WebSocketException("Invalid header") + + if traceEnabled: + logger.debug("-----------------------") + + return status, headers + + def send(self, payload, opcode = ABNF.OPCODE_TEXT): + """ + Send the data as string. + + payload: Payload must be utf-8 string or unicoce, + if the opcode is OPCODE_TEXT. + Otherwise, it must be string(byte array) + + opcode: operation code to send. Please see OPCODE_XXX. + """ + frame = ABNF.create_frame(payload, opcode) + if self.get_mask_key: + frame.get_mask_key = self.get_mask_key + data = frame.format() + self.io_sock.send(data) + if traceEnabled: + logger.debug("send: " + repr(data)) + + def ping(self, payload = ""): + """ + send ping data. + + payload: data payload to send server. + """ + self.send(payload, ABNF.OPCODE_PING) + + def pong(self, payload): + """ + send pong data. + + payload: data payload to send server. + """ + self.send(payload, ABNF.OPCODE_PONG) + + def recv(self): + """ + Receive string data(byte array) from the server. + + return value: string(byte array) value. + """ + opcode, data = self.recv_data() + return data + + def recv_data(self): + """ + Recieve data with operation code. + + return value: tuple of operation code and string(byte array) value. + """ + while True: + frame = self.recv_frame() + if not frame: + # handle error: + # 'NoneType' object has no attribute 'opcode' + raise WebSocketException("Not a valid frame %s" % frame) + elif frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY): + return (frame.opcode, frame.data) + elif frame.opcode == ABNF.OPCODE_CLOSE: + self.send_close() + return (frame.opcode, None) + elif frame.opcode == ABNF.OPCODE_PING: + self.pong("Hi!") + + + def recv_frame(self): + """ + recieve data as frame from server. + + return value: ABNF frame object. + """ + header_bytes = self._recv(2) + if not header_bytes: + return None + b1 = ord(header_bytes[0]) + fin = b1 >> 7 & 1 + rsv1 = b1 >> 6 & 1 + rsv2 = b1 >> 5 & 1 + rsv3 = b1 >> 4 & 1 + opcode = b1 & 0xf + b2 = ord(header_bytes[1]) + mask = b2 >> 7 & 1 + length = b2 & 0x7f + + length_data = "" + if length == 0x7e: + length_data = self._recv(2) + length = struct.unpack("!H", length_data)[0] + elif length == 0x7f: + length_data = self._recv(8) + length = struct.unpack("!Q", length_data)[0] + + mask_key = "" + if mask: + mask_key = self._recv(4) + data = self._recv_strict(length) + if traceEnabled: + recieved = header_bytes + length_data + mask_key + data + logger.debug("recv: " + repr(recieved)) + + if mask: + data = ABNF.mask(mask_key, data) + + frame = ABNF(fin, rsv1, rsv2, rsv3, opcode, mask, data) + return frame + + def send_close(self, status = STATUS_NORMAL, reason = ""): + """ + send close data to the server. + + status: status code to send. see STATUS_XXX. + + reason: the reason to close. This must be string. + """ + if status < 0 or status >= ABNF.LENGTH_16: + raise ValueError("code is invalid range") + self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) + + + + def close(self, status = STATUS_NORMAL, reason = ""): + """ + Close Websocket object + + status: status code to send. see STATUS_XXX. + + reason: the reason to close. This must be string. + """ + if self.connected: + if status < 0 or status >= ABNF.LENGTH_16: + raise ValueError("code is invalid range") + + try: + self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) + timeout = self.sock.gettimeout() + self.sock.settimeout(3) + try: + frame = self.recv_frame() + if logger.isEnabledFor(logging.DEBUG): + logger.error("close status: " + repr(frame.data)) + except: + pass + self.sock.settimeout(timeout) + self.sock.shutdown(socket.SHUT_RDWR) + except: + pass + self._closeInternal() + + def _closeInternal(self): + self.connected = False + self.sock.close() + self.io_sock = self.sock + + def _recv(self, bufsize): + bytes = self.io_sock.recv(bufsize) + return bytes + + def _recv_strict(self, bufsize): + remaining = bufsize + bytes = "" + while remaining: + bytes += self._recv(remaining) + remaining = bufsize - len(bytes) + + return bytes + + def _recv_line(self): + line = [] + while True: + c = self._recv(1) + line.append(c) + if c == "\n": + break + return "".join(line) + +class WebSocketApp(object): + """ + Higher level of APIs are provided. + The interface is like JavaScript WebSocket object. + """ + def __init__(self, url, + on_open = None, on_message = None, on_error = None, + on_close = None, keep_running = True, get_mask_key = None): + """ + url: websocket url. + on_open: callable object which is called at opening websocket. + this function has one argument. The arugment is this class object. + on_message: callbale object which is called when recieved data. + on_message has 2 arguments. + The 1st arugment is this class object. + The passing 2nd arugment is utf-8 string which we get from the server. + on_error: callable object which is called when we get error. + on_error has 2 arguments. + The 1st arugment is this class object. + The passing 2nd arugment is exception object. + on_close: callable object which is called when closed the connection. + this function has one argument. The arugment is this class object. + keep_running: a boolean flag indicating whether the app's main loop should + keep running, defaults to True + get_mask_key: a callable to produce new mask keys, see the WebSocket.set_mask_key's + docstring for more information + """ + self.url = url + self.on_open = on_open + self.on_message = on_message + self.on_error = on_error + self.on_close = on_close + self.keep_running = keep_running + self.get_mask_key = get_mask_key + self.sock = None + + def send(self, data): + """ + send message. data must be utf-8 string or unicode. + """ + self.sock.send(data) + + def close(self): + """ + close websocket connection. + """ + self.keep_running = False + self.sock.close() + + def run_forever(self): + """ + run event loop for WebSocket framework. + This loop is infinite loop and is alive during websocket is available. + """ + if self.sock: + raise WebSocketException("socket is already opened") + try: + self.sock = WebSocket(self.get_mask_key) + self.sock.connect(self.url) + self._run_with_no_err(self.on_open) + while self.keep_running: + data = self.sock.recv() + if data is None: + break + self._run_with_no_err(self.on_message, data) + except Exception, e: + self._run_with_no_err(self.on_error, e) + finally: + self.sock.close() + self._run_with_no_err(self.on_close) + self.sock = None + + def _run_with_no_err(self, callback, *args): + if callback: + try: + callback(self, *args) + except Exception, e: + if logger.isEnabledFor(logging.DEBUG): + logger.error(e) + + +if __name__ == "__main__": + enableTrace(True) + ws = create_connection("ws://echo.websocket.org/") + print "Sending 'Hello, World'..." + ws.send("Hello, World") + print "Sent" + print "Receiving..." + result = ws.recv() + print "Received '%s'" % result + ws.close() diff --git a/sublime/Packages/Web Inspector/wip/Console.py b/sublime/Packages/Web Inspector/wip/Console.py new file mode 100644 index 0000000..e3f2ac7 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/Console.py @@ -0,0 +1,77 @@ +from utils import Command, Notification, WIPObject +from Runtime import RemoteObject +from Network import RequestId + + +### Console.clearMessages +def clearMessages(): + command = Command('Console.clearMessages') + return command + + +### Console.disable +def disable(): + command = Command('Console.disable') + return command + + +### Console.enable +def enable(): + command = Command('Console.enable') + return command + + +### Console.messageAdded +def messageAdded(): + notification = Notification('Console.messageAdded') + return notification + + +def messageAdded_parser(params): + result = ConsoleMessage(params['message']) + return result + + +### Console.messageRepeatCountUpdated +def messageRepeatCountUpdated(): + notification = Notification('Console.messageRepeatCountUpdated') + return notification + + +def messageRepeatCountUpdate_parser(params): + return params['count'] + + +### Console.messagesCleared +def messagesCleared(): + notification = Notification('Console.messagesCleared') + return notification + + +class CallFrame(WIPObject): + def __init__(self, value): + self.set(value, 'columnNumber') + self.set(value, 'functionName') + self.set(value, 'lineNumber') + self.set(value, 'url') + + +class ConsoleMessage(WIPObject): + def __init__(self, value): + self.set(value, 'level') + self.set(value, 'line') + self.set_class(value, 'networkRequestId', RequestId) + self.parameters = [] + if 'parameters' in value: + for param in value['parameters']: + self.parameters.append(RemoteObject(param)) + self.set(value, 'repeatCount', 1) + self.set_class(value, 'stackTrace', StackTrace) + self.set(value, 'text') + self.set(value, 'url') + + +class StackTrace(list): + def __init__(self, value): + for callFrame in value: + self.append(CallFrame(callFrame)) diff --git a/sublime/Packages/Web Inspector/wip/DOM.py b/sublime/Packages/Web Inspector/wip/DOM.py new file mode 100644 index 0000000..3523130 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/DOM.py @@ -0,0 +1 @@ +# not implemented now diff --git a/sublime/Packages/Web Inspector/wip/DOMDebugger.py b/sublime/Packages/Web Inspector/wip/DOMDebugger.py new file mode 100644 index 0000000..3523130 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/DOMDebugger.py @@ -0,0 +1 @@ +# not implemented now diff --git a/sublime/Packages/Web Inspector/wip/Debugger.py b/sublime/Packages/Web Inspector/wip/Debugger.py new file mode 100644 index 0000000..7356734 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/Debugger.py @@ -0,0 +1,219 @@ +from utils import Command, Notification, WIPObject +from Runtime import RemoteObject +import json + + +### Console.clearMessages +def canSetScriptSource(): + command = Command('Debugger.canSetScriptSource', {}) + return command + + +def enable(): + command = Command('Debugger.enable', {}) + return command + + +def evaluateOnCallFrame(callFrameId, expression): + params = {} + params['callFrameId'] = callFrameId() + params['expression'] = expression + command = Command('Debugger.evaluateOnCallFrame', params) + return command + + +def evaluateOnCallFrame_parser(result): + data = RemoteObject(result['result']) + return data + + +def disable(): + command = Command('Debugger.disable', {}) + return command + + +def resume(): + command = Command('Debugger.resume', {}) + return command + + +def stepInto(): + command = Command('Debugger.stepInto', {}) + return command + + +def stepOut(): + command = Command('Debugger.stepOut', {}) + return command + + +def stepOver(): + command = Command('Debugger.stepOver', {}) + return command + + +def removeBreakpoint(breakpointId): + params = {} + params['breakpointId'] = breakpointId + command = Command('Debugger.removeBreakpoint', params) + return command + + +def setBreakpoint(location, condition=None): + params = {} + params['location'] = location() + + if condition: + params['condition'] = condition + + command = Command('Debugger.setBreakpoint', params) + return command + + +def setBreakpoint_parser(result): + data = {} + data['breakpointId'] = BreakpointId(result['breakpointId']) + data['actualLocation'] = Location(result['actualLocation']) + return data + + +def setScriptSource(scriptId, scriptSource): + params = {} + params['scriptId'] = scriptId + params['scriptSource'] = scriptSource + + command = Command('Debugger.setScriptSource', params) + return command + + +def setScriptSource_parser(result): + data = {} + data['callFrames'] = [] + for callFrame in result['callFrames']: + data['callFrames'].append(CallFrame(callFrame)) + return data + + +def setBreakpointByUrl(lineNumber, url=None, urlRegex=None, columnNumber=None, condition=None): + params = {} + params['lineNumber'] = lineNumber + if url: + params['url'] = url + + if urlRegex: + params['urlRegex'] = urlRegex + + if columnNumber: + params['columnNumber'] = columnNumber + + if condition: + params['condition'] = condition + + command = Command('Debugger.setBreakpointByUrl', params) + return command + + +def setBreakpointByUrl_parser(result): + data = {} + data['breakpointId'] = BreakpointId(result['breakpointId']) + data['locations'] = [] + for location in result['locations']: + data['locations'].append(Location(location)) + return data + + +def scriptParsed(): + notification = Notification('Debugger.scriptParsed') + return notification + + +def scriptParsed_parser(params): + return {'scriptId': ScriptId(params['scriptId']), 'url': params['url']} + + +def paused(): + notification = Notification('Debugger.paused') + return notification + + +def paused_parser(params): + data = {} + data['callFrames'] = [] + for callFrame in params['callFrames']: + data['callFrames'].append(CallFrame(callFrame)) + data['reason'] = params['reason'] + return data + + +def resumed(): + notification = Notification('Debugger.resumed') + return notification + + +class BreakpointId(WIPObject): + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + + def __call__(self): + return self.value + + +class CallFrameId(WIPObject): + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + + def __call__(self): + return self.value + + +class ScriptId(WIPObject): + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + + def __call__(self): + return self.value + + +class Scope(WIPObject): + def __init__(self, value): + self.set_class(value, 'object', RemoteObject) + self.set(value, 'type') + + +class Location(WIPObject): + def __init__(self, value): + self.set(value, 'columnNumber') + self.set(value, 'lineNumber') + self.set_class(value, 'scriptId', ScriptId) + + def __call__(self): + obj = {} + if self.columnNumber: + obj['columnNumber'] = self.columnNumber + obj['lineNumber'] = self.lineNumber + obj['scriptId'] = self.scriptId() + return obj + + +class CallFrame(WIPObject): + def __init__(self, value): + self.set_class(value, 'callFrameId', CallFrameId) + self.set(value, 'functionName') + self.set_class(value, 'location', Location) + self.scopeChain = [] + if 'scopeChain' in value: + for scope in value['scopeChain']: + self.scopeChain.append(Scope(scope)) + self.set_class(value, 'this', RemoteObject) + + def __str__(self): + return "%s:%d %s" % (self.location.scriptId, self.location.lineNumber, self.functionName) diff --git a/sublime/Packages/Web Inspector/wip/Network.py b/sublime/Packages/Web Inspector/wip/Network.py new file mode 100644 index 0000000..4a6d317 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/Network.py @@ -0,0 +1,27 @@ +from utils import WIPObject, Command + + +def clearBrowserCache(): + command = Command('Network.clearBrowserCache', {}) + return command + + +def canClearBrowserCache(): + command = Command('Network.canClearBrowserCache', {}) + return command + + +def setCacheDisabled(value): + command = Command('Network.setCacheDisabled', {'cacheDisabled': value}) + return command + + +class RequestId(WIPObject): + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + + def __repr__(self): + return self.value diff --git a/sublime/Packages/Web Inspector/wip/Page.py b/sublime/Packages/Web Inspector/wip/Page.py new file mode 100644 index 0000000..c31be32 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/Page.py @@ -0,0 +1,6 @@ +from utils import Command + + +def reload(): + command = Command('Page.reload', {}) + return command diff --git a/sublime/Packages/Web Inspector/wip/Runtime.py b/sublime/Packages/Web Inspector/wip/Runtime.py new file mode 100644 index 0000000..2b812a0 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/Runtime.py @@ -0,0 +1,100 @@ +import json +from utils import WIPObject, Command + + +def evaluate(expression, objectGroup=None, returnByValue=None): + params = {} + + params['expression'] = expression + + if(objectGroup): + params['objectGroup'] = objectGroup + + if(returnByValue): + params['returnByValue'] = returnByValue + + command = Command('Runtime.evaluate', params) + return command + + +def getProperties(objectId, ownProperties=False): + params = {} + + params['objectId'] = str(objectId) + params['ownProperties'] = ownProperties + + command = Command('Runtime.getProperties', params) + return command + + +def getProperties_parser(result): + data = [] + for propertyDescriptor in result['result']: + data.append(PropertyDescriptor(propertyDescriptor)) + return data + + +class RemoteObject(WIPObject): + def __init__(self, value): + self.set(value, 'className') + self.set(value, 'description') + self.set_class(value, 'objectId', RemoteObjectId) + self.set(value, 'subtype') + self.set(value, 'type') + self.set(value, 'value') + + def __str__(self): + if self.type == 'boolean': + return str(self.value) + if self.type == 'string': + return str(self.value) + if self.type == 'undefined': + return 'undefined' + if self.type == 'number': + return str(self.value) + if self.type == 'object': + if not self.objectId(): + return 'null' + else: + if self.className: + return self.className + if self.description: + return self.description + return '{ ... }' + if self.type == 'function': + return self.description.split('\n')[0] + + +class PropertyDescriptor(WIPObject): + def __init__(self, _value): + self.set(_value, 'configurable') + self.set(_value, 'enumerable') + #self.set_class(_value, 'get', RemoteObject) + #self.set_class(_value, 'set', RemoteObject) + self.set(_value, 'name') + self.set_class(_value, 'value', RemoteObject) + self.set(_value, 'wasThrown') + self.set(_value, 'writable') + + def __str__(self): + return self.name + + +class RemoteObjectId(WIPObject): + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + + def __call__(self): + return self.value + + def dumps(self): + objid = json.loads(self.value) + return "Object_%d_%d" % (objid['injectedScriptId'], objid['id']) + + def loads(self, text): + parts = text.split('_') + self.value = '{"injectedScriptId":%s,"id":%s}' % (parts[1], parts[2]) + return self.value diff --git a/sublime/Packages/Web Inspector/wip/__init__.py b/sublime/Packages/Web Inspector/wip/__init__.py new file mode 100644 index 0000000..4f2484c --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/__init__.py @@ -0,0 +1,5 @@ +""" +WIP Protocol - WebInspectorProtocol implementation for python + +Copyright (C) 2013 Sokolov Stansilav +""" diff --git a/sublime/Packages/Web Inspector/wip/utils.py b/sublime/Packages/Web Inspector/wip/utils.py new file mode 100644 index 0000000..8eb2935 --- /dev/null +++ b/sublime/Packages/Web Inspector/wip/utils.py @@ -0,0 +1,66 @@ +class WIPObject(object): + def set(self, obj, name, default=None): + setattr(self, name, obj.get(name, default)) + + def set_class(self, obj, name, classObject): + if name in obj: + setattr(self, name, classObject(obj[name])) + else: + setattr(self, name, None) + + def parse_to_class(self, obj, name, classObject): + if name in obj: + setattr(self, name, classObject.parse(obj[name])) + else: + setattr(self, name, None) + + +class Notification(object): + def __init__(self, notification_name): + self.name = notification_name + try: + self.parser = eval('wip.' + notification_name + '_parser', {'wip': __import__('wip')}) + except: + self.parser = Notification.default_parser + self.lastResponse = None + self.callback = None + + @staticmethod + def default_parser(params): + print params + return params + + +class Command(object): + def __init__(self, method_name, params={}): + self.request = {'id': 0, 'method': '', 'params': params} + self.method = method_name + try: + self.parser = eval('wip.' + method_name + '_parser', {'wip': __import__('wip')}) + except: + self.parser = Command.default_parser + self.params = params + self.options = None + self.callback = None + self.response = None + self.error = None + self.data = None + + def get_id(self): + return self.request['id'] + + def set_id(self, value): + self.request['id'] = value + + def get_method(self): + return self.request['method'] + + def set_method(self, value): + self.request['method'] = value + + id = property(get_id, set_id) + method = property(get_method, set_method) + + @staticmethod + def default_parser(params): + return params