def add_method(cls_name, selector_name, fn, type_encoding): cls = ObjCClass(cls_name).ptr selector = sel(selector_name) if c.class_getInstanceMethod(cls, selector): error( 'Failed to add method, class {} already provides method {}'.format( cls_name, selector_name)) return parsed_types = parse_types(type_encoding) restype = parsed_types[0] argtypes = parsed_types[1] IMPTYPE = CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(fn) retain_global(imp) did_add = c.class_addMethod(cls, selector, imp, c_char_p(type_encoding.encode('utf-8'))) if not did_add: error('Failed to add class method') return did_add
def _flake8_annotations(path, options): import os _tmp = os.environ.get('TMPDIR', os.environ.get('TMP')) _output_file = os.path.join(_tmp, 'blackmamba.flake8.txt') annotations = [] for o in options: try: from flake8.main import application if os.path.exists(_output_file): os.remove(_output_file) o = list(o) o.insert(0, path) o.extend([ '-j', '0', # Disable subprocess '--output-file={}'.format(_output_file) ]) app = application.Application() app.run(o) del app annotations.extend(_parse_flake8_output(path, _output_file)) except Exception as e: log.error('flake8 failed: {}'.format(str(e))) if os.path.exists(_output_file): os.remove(_output_file) return annotations
def run_script(script_name, full_path=False, delay=None): if not full_path and script_name.startswith('/'): script_name = script_name[1:] if not script_exists(script_name, full_path): error('run_script: script does not exist {}'.format(script_name)) return if full_path: docs_root = os.path.expanduser('~/Documents/') script_name = script_name[len(docs_root):] encoded_name = urllib.parse.quote_plus(script_name, safe='', encoding=None, errors=None) url = 'pythonista3://{}?action=run'.format(encoded_name) if delay: def make_open_url(url): def open(): webbrowser.open(url) return open ui.delay(make_open_url(url), delay) else: webbrowser.open(url)
def check(): if not get_config_value('update.enabled', True): return timestamp = _timestamp() last_check = _get_last_update_check() or timestamp if last_check + get_config_value('update.interval', 86400) > timestamp: return _set_last_update_check(timestamp) info('Checking for Black Mamba updates...') local_release = get_local_release() latest_release = _get_latest_release() if not latest_release: error('Failed to fetch latest release version info') return if local_release: if local_release['tag_name'] == latest_release['tag_name']: info('No updates available, you are up to date') return info('New version available, selfupdate.py will be executed') import blackmamba.ide.script as script if system.PYTHONISTA_BUNDLE_VERSION >= 311015: # 311015 introduced script queues, no need for delay delay = None else: delay = 0.5 script.run_script('site-packages-3/blackmamba/script/selfupdate.py', delay=delay) else: info('Missing installed version info, you should use the installer')
def swizzle(cls_name, selector_name, fn): cls = ObjCClass(cls_name).ptr new_selector_name = SWIZZLED_SELECTOR_PREFIX + selector_name new_selector = sel(new_selector_name) if c.class_getInstanceMethod(cls, new_selector): error('Skipping swizzling, already responds to {} selector'.format( new_selector_name)) return selector = sel(selector_name) method = c.class_getInstanceMethod(cls, selector) if not method: error('Failed to get {} instance method'.format(selector_name)) return type_encoding = c.method_getTypeEncoding(method) parsed_types = parse_types(type_encoding) restype = parsed_types[0] argtypes = parsed_types[1] IMPTYPE = CFUNCTYPE(restype, *argtypes) imp = IMPTYPE(fn) retain_global(imp) did_add = c.class_addMethod(cls, new_selector, imp, type_encoding) if not did_add: error('Failed to add {} method'.format(new_selector_name)) return new_method = c.class_getInstanceMethod(cls, new_selector) method_exchangeImplementations(method, new_method)
def _register_key_command(input, modifier_flags, function, title=None): if not UIApplication.sharedApplication().respondsToSelector_( sel('originalkeyCommands')): swizzle('UIApplication', 'keyCommands', _blackmamba_keyCommands) selector_name = _key_command_selector_name(input, modifier_flags) selector = sel(selector_name) obj = UIApplication.sharedApplication() info('Registering key command "{}" ({})'.format( _shortcut_name(input, modifier_flags), title or 'No discoverability title')) if not callable(function): error('Skipping, provided function is not callable') return False if obj.respondsToSelector_(selector): error('Skipping, method {} already registered'.format(selector_name)) return False def key_command_action(_sel, _cmd, sender): function() IMPTYPE = CFUNCTYPE(None, c_void_p, c_void_p, c_void_p) imp = IMPTYPE(key_command_action) retain_global(imp) cls = c.object_getClass(obj.ptr) type_encoding = c_char_p('v@:@'.encode('utf-8')) did_add = c.class_addMethod(cls, selector, imp, type_encoding) if not did_add: error('Failed to add key command method {}'.format(selector_name)) return False if isinstance(modifier_flags, UIKeyModifier): modifier_flags = modifier_flags.value if title: kc = UIKeyCommand.keyCommandWithInput_modifierFlags_action_discoverabilityTitle_( ns(input), modifier_flags, selector, ns(title)) else: kc = UIKeyCommand.keyCommandWithInput_modifierFlags_action_( ns(input), modifier_flags, selector) _key_commands.append(kc) return True
def tableView_itemsForBeginningDragSession_atIndexPath_( _self, _cmd, tv_ptr, session_ptr, index_path_ptr): global _dragged_item_path if not _path_items: return ns([]).ptr section = ObjCInstance(index_path_ptr).section() row = ObjCInstance(index_path_ptr).row() if section >= 0 and section < len(_path_items) and row >= 0 and row < len( _path_items[section]): path = _path_items[section][row] type_identifier = _type_identifier(path) if not type_identifier: error('Failed to provide data, file does not exists?') return ns([]).ptr suggested_name = _suggested_name(path) provider = NSItemProvider.alloc().init() provider.registerFileRepresentationForTypeIdentifier_fileOptions_visibility_loadHandler_( type_identifier, 0, 0, _load_data) if not provider: error('Failed to create item provider.') return ns([]).ptr if suggested_name: provider.setSuggestedName(suggested_name) item = UIDragItem.alloc().initWithItemProvider_(provider) if not item: error('Failed to create drag item.') return ns([]).ptr _dragged_item_path = path return ns([item]).ptr return ns([]).ptr
def _check_compatibility(): import blackmamba.update info('Pythonista {} ({})'.format(system.PYTHONISTA_VERSION, system.PYTHONISTA_BUNDLE_VERSION)) local_release = blackmamba.update.get_local_release() if local_release: info('Black Mamba {} (tag {})'.format(__version__, local_release['tag_name'])) else: info( 'Black Mamba {} (tag unknown, not installed via installation script)' .format(__version__)) if system.PYTHONISTA_BUNDLE_VERSION > _LATEST_VERSION_COMPATIBILITY_TEST[0]: error( 'Installed Black Mamba version is not tested with current version of Pythonista' ) error('Latest compatibility tests were made with Pythonista {} ({})'. format(_LATEST_VERSION_COMPATIBILITY_TEST[1], _LATEST_VERSION_COMPATIBILITY_TEST[0])) error('Update Black Mamba or use at your own risk')
def _main(config=None): # It's here because Sphinx doesn't show documentation for decorated # functions from blackmamba.config import update_config_with_dict, get_config_value import sys info('Black Mamba initialization...') if system.PYTHONISTA_BUNDLE_VERSION < 320000: error('Black Mamba supports Pythonista >= 3.2 only.') return if not sys.version_info.major == 3: error('Black Mamba supports Python 3 only') return if sys.version_info.minor < 6: error('Black Mamba support Python 3.6+ only') return if config: update_config_with_dict(config) _check_compatibility() if get_config_value('general.register_key_commands', True): _register_default_key_commands() _register_ios11_default_key_commands() info('Black Mamba initialized') _check_for_updates()
#!python3 import requests import traceback from blackmamba.log import error try: exec(requests.get('http://bit.ly/get-blackmamba').text) except Exception: error('Failed to fetch & execute installer') error(traceback.format_exc())
def __call__(self, *args): if self._regular_calling_convention(): # First arg is pointer to block, hide it from user return self._func(self._block_ptr, *args) error('Not implemented calling convention, block not called')