Beispiel #1
0
 def build_keymap(config, key, mappings=None):
     system = registry.get_plugin('system', key[1]).obj
     machine_class = registry.get_plugin('machine', key[2]).obj
     keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions())
     if mappings is None:
         mappings = system.KEYMAPS.get(key[2])
     if mappings is None:
         if machine_class.KEYMAP_MACHINE_TYPE is not None:
             # Try fallback.
             return build_keymap(config, (key[0], key[1], machine_class.KEYMAP_MACHINE_TYPE))
         # No fallback...
         mappings = {}
     keymap.set_mappings(mappings)
     return keymap
Beispiel #2
0
 def build_keymap(config, key, mappings=None):
     system = registry.get_plugin('system', key[1]).obj
     machine_class = registry.get_plugin('machine', key[2]).obj
     keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions())
     if mappings is None:
         mappings = system.KEYMAPS.get(key[2])
     if mappings is None:
         if machine_class.KEYMAP_MACHINE_TYPE is not None:
             # Try fallback.
             return build_keymap(config, (key[0], key[1], machine_class.KEYMAP_MACHINE_TYPE))
         # No fallback...
         mappings = {}
     keymap.set_mappings(mappings)
     return keymap
Beispiel #3
0
 def _consume_engine_command(self, command):
     # The first commands can be used whether plover has output enabled or not.
     if command == 'RESUME':
         self._set_output(True)
         return True
     elif command == 'TOGGLE':
         self._toggle_output()
         return True
     elif command == 'QUIT':
         self.quit()
         return True
     if not self._is_running:
         return False
     # These commands can only be run when plover has output enabled.
     if command == 'SUSPEND':
         self._set_output(False)
     elif command == 'CONFIGURE':
         self._trigger_hook('configure')
     elif command == 'FOCUS':
         self._trigger_hook('focus')
     elif command == 'ADD_TRANSLATION':
         self._trigger_hook('add_translation')
     elif command == 'LOOKUP':
         self._trigger_hook('lookup')
     else:
         command_args = command.split(':', 1)
         command_fn = registry.get_plugin('command', command_args[0]).obj
         command_fn(self, command_args[1] if len(command_args) == 2 else '')
     return False
Beispiel #4
0
 def get_dictionaries(self):
     system_name = self.get_system_name()
     try:
         system = registry.get_plugin('system', system_name).obj
     except:
         log.error("invalid system name: %s", system_name, exc_info=True)
         return []
     section = SYSTEM_CONFIG_SECTION % system_name
     option = SYSTEM_DICTIONARIES_OPTION
     dictionaries = self._get(section, option, None)
     if dictionaries is None:
         dictionaries = self._legacy_get_dictionary_file_names()
         if dictionaries is None:
             dictionaries = [
                 DictionaryConfig(path)
                 for path in system.DEFAULT_DICTIONARIES
             ]
         return dictionaries
     try:
         return [
             DictionaryConfig.from_dict(d) for d in json.loads(dictionaries)
         ]
     except:
         log.error("invalid system dictionaries, resetting to default",
                   exc_info=True)
         self.set_dictionaries(None)
         return self.get_dictionaries()
Beispiel #5
0
 def _consume_engine_command(self, command):
     # The first commands can be used whether plover has output enabled or not.
     if command == 'RESUME':
         self._set_output(True)
         return True
     elif command == 'TOGGLE':
         self._toggle_output()
         return True
     elif command == 'QUIT':
         self.quit()
         return True
     if not self._is_running:
         return False
     # These commands can only be run when plover has output enabled.
     if command == 'SUSPEND':
         self._set_output(False)
     elif command == 'CONFIGURE':
         self._trigger_hook('configure')
     elif command == 'FOCUS':
         self._trigger_hook('focus')
     elif command == 'ADD_TRANSLATION':
         self._trigger_hook('add_translation')
     elif command == 'LOOKUP':
         self._trigger_hook('lookup')
     else:
         command_args = command.split(':', 1)
         command_fn = registry.get_plugin('command', command_args[0]).obj
         command_fn(self, command_args[1] if len(command_args) == 2 else '')
     return False
Beispiel #6
0
def setup(system_name):
    system_symbols = {}
    mod = registry.get_plugin('system', system_name).obj
    for symbol, init in _EXPORTS.items():
        system_symbols[symbol] = init(mod)
    system_symbols['NAME'] = system_name
    globals().update(system_symbols)
 def sub_commands(self):
     machine_name = self.engine.config["machine_type"]
     machine_class = registry.get_plugin("machine", machine_name).obj
     return [
         SetMachineOption(self.output, name, default, self.engine)
         for name, default in machine_class.get_option_info().items()
     ]
Beispiel #8
0
def setup(system_name):
    system_symbols = {}
    mod = registry.get_plugin('system', system_name).obj
    for symbol, init in _EXPORTS.items():
        system_symbols[symbol] = init(mod)
    system_symbols['NAME'] = system_name
    globals().update(system_symbols)
Beispiel #9
0
 def _consume_engine_command(self, command):
     # The first commands can be used whether plover has output enabled or not.
     if command == "RESUME":
         self._set_output(True)
         return True
     elif command == "TOGGLE":
         self._toggle_output()
         return True
     elif command == "QUIT":
         self._trigger_hook("quit")
         return True
     if not self._is_running:
         return False
     # These commands can only be run when plover has output enabled.
     if command == "SUSPEND":
         self._set_output(False)
     elif command == "CONFIGURE":
         self._trigger_hook("configure")
     elif command == "FOCUS":
         self._trigger_hook("focus")
     elif command == "ADD_TRANSLATION":
         self._trigger_hook("add_translation")
     elif command == "LOOKUP":
         self._trigger_hook("lookup")
     else:
         command_args = command.split(":", 2)
         command_fn = registry.get_plugin("command", command_args[0]).resolve()
         command_fn(self, command_args[1] if len(command_args) == 2 else "")
     return False
Beispiel #10
0
 def _consume_engine_command(self, command, force=False):
     # The first commands can be used whether plover has output enabled or not.
     command_name, *command_args = command.split(':', 1)
     command_name = command_name.lower()
     if command_name == 'resume':
         self._set_output(True)
         return True
     elif command_name == 'toggle':
         self._toggle_output()
         return True
     elif command_name == 'quit':
         self.quit()
         return True
     if not force and not self._is_running:
         return False
     # These commands can only be run when plover has output enabled.
     if command_name == 'suspend':
         self._set_output(False)
     elif command_name == 'configure':
         self._trigger_hook('configure')
     elif command_name == 'focus':
         self._trigger_hook('focus')
     elif command_name == 'add_translation':
         self._trigger_hook('add_translation')
     elif command_name == 'lookup':
         self._trigger_hook('lookup')
     elif command_name == 'suggestions':
         self._trigger_hook('suggestions')
     else:
         command_fn = registry.get_plugin('command', command_name).obj
         command_fn(self, command_args[0] if command_args else '')
     return False
Beispiel #11
0
def _meta_to_action(meta, ctx):
    meta_name, meta_arg = _parse_meta(meta)
    if meta_name is not None:
        meta_fn = registry.get_plugin('meta', meta_name).obj
        action = meta_fn(ctx, meta_arg)
    else:
        action = ctx.new_action()
    return action
Beispiel #12
0
def _get_dictionary_module(filename):
    extension = splitext(filename)[1].lower()[1:]
    try:
        entrypoint = registry.get_plugin('dictionary', extension)
    except KeyError:
        raise DictionaryLoaderException(
            'Unsupported extension: %s. Supported extensions: %s' %
            (extension, ', '.join(sorted(registry.list_plugins('dictionary')))))
    return entrypoint.resolve()
Beispiel #13
0
def setup(system_name):
    system_symbols = {}
    mod = registry.get_plugin('system', system_name).obj
    for symbol in _DIRECT_EXPORTS:
        system_symbols[symbol] = getattr(mod, symbol)
    for symbol, init in _CALCULATED_EXPORTS.items():
        system_symbols[symbol] = init(mod)
    system_symbols['NAME'] = system_name
    globals().update(system_symbols)
Beispiel #14
0
def setup(system_name):
    system_symbols = {}
    system_mod = registry.get_plugin('system', system_name).obj
    for symbol, init in _EXPORTS.items():
        system_symbols[symbol] = init(system_mod)
    system_symbols['NAME'] = system_name
    globals().update(system_symbols)
    Stroke.setup(KEYS, IMPLICIT_HYPHEN_KEYS, NUMBER_KEY, NUMBERS,
                 UNDO_STROKE_STENO)
Beispiel #15
0
 def _machine_option(self, *args):
     machine_type = self._config['machine_type']
     machine_class = registry.get_plugin('machine', machine_type).obj
     if issubclass(machine_class, Keyboard):
         opt_class = KeyboardOption
     elif issubclass(machine_class, SerialStenotypeBase):
         opt_class = SerialOption
     else:
         opt_class = NopeOption
     return opt_class(*args)
Beispiel #16
0
def setup(system_name, system_mod=None, system_dict=None):
    system_symbols = {}
    if system_mod is None:
        system_mod = registry.get_plugin('system', system_name).obj
    for symbol, init in _EXPORTS.items():
        system_symbols[symbol] = init(system_mod)
    system_symbols['NAME'] = system_name
    if system_dict is None:
        system_dict = globals()
    system_dict.update(system_symbols)
Beispiel #17
0
def _get_dictionary_class(filename):
    extension = splitext(filename)[1].lower()[1:]
    try:
        dict_module = registry.get_plugin('dictionary', extension).obj
    except KeyError:
        raise ValueError(
            'Unsupported extension: %s. Supported extensions: %s' %
            (extension, ', '.join(plugin.name for plugin in
                                  registry.list_plugins('dictionary'))))
    return dict_module
Beispiel #18
0
def _get_dictionary_class(filename):
    extension = splitext(filename)[1].lower()[1:]
    try:
        dict_module = registry.get_plugin('dictionary', extension).obj
    except KeyError:
        raise ValueError(
            'Unsupported extension: %s. Supported extensions: %s' %
            (extension, ', '.join(plugin.name for plugin in
                                  registry.list_plugins('dictionary'))))
    return dict_module
Beispiel #19
0
 def _machine_option(self, *args):
     machine_type = self._config['machine_type']
     machine_class = registry.get_plugin('machine', machine_type).obj
     if issubclass(machine_class, Keyboard):
         opt_class = KeyboardOption
     elif issubclass(machine_class, SerialStenotypeBase):
         opt_class = SerialOption
     else:
         opt_class = NopeOption
     return opt_class(*args)
Beispiel #20
0
def _get_dictionary_module(filename):
    extension = splitext(filename)[1].lower()[1:]
    try:
        entrypoint = registry.get_plugin('dictionary', extension)
    except KeyError:
        raise DictionaryLoaderException(
            'Unsupported extension: %s. Supported extensions: %s' %
            (extension, ', '.join(sorted(
                registry.list_plugins('dictionary')))))
    return entrypoint.resolve()
Beispiel #21
0
 def _start_extensions(self, extension_list):
     for extension_name in extension_list:
         log.info('starting `%s` extension', extension_name)
         try:
             extension = registry.get_plugin('extension', extension_name).obj(self)
             extension.start()
         except Exception:
             log.error('initializing extension `%s` failed', extension_name, exc_info=True)
         else:
             self._running_extensions[extension_name] = extension
Beispiel #22
0
 def _start_extensions(self, extension_list):
     for extension_name in extension_list:
         log.info('starting `%s` extension', extension_name)
         try:
             extension = registry.get_plugin('extension', extension_name).obj(self)
             extension.start()
         except Exception:
             log.error('initializing extension `%s` failed', extension_name, exc_info=True)
         else:
             self._running_extensions[extension_name] = extension
Beispiel #23
0
 def get_system_keymap(self, machine_type=None, system_name=None):
     if machine_type is None:
         machine_type = self.get_machine_type()
     try:
         machine_class = registry.get_plugin('machine',
                                             machine_type).resolve()
     except:
         log.error("invalid machine type: %s", machine_type, exc_info=True)
         return None
     if system_name is None:
         system_name = self.get_system_name()
     try:
         system = registry.get_plugin('system', system_name).resolve()
     except:
         log.error("invalid system name: %s", system_name, exc_info=True)
         return None
     section = SYSTEM_CONFIG_SECTION % system_name
     option = SYSTEM_KEYMAP_OPTION % machine_type
     mappings = self._get(section, option, None)
     if mappings is None:
         # No user mappings, use system default.
         mappings = system.KEYMAPS.get(machine_type)
     else:
         try:
             mappings = dict(json.loads(mappings))
         except ValueError as e:
             log.error("invalid machine keymap, resetting to default",
                       exc_info=True)
             self.set_system_keymap(None, machine_type)
             mappings = system.KEYMAPS.get(machine_type)
     if mappings is None:
         if machine_class.KEYMAP_MACHINE_TYPE is not None:
             # Try fallback.
             return self.get_system_keymap(
                 machine_type=machine_class.KEYMAP_MACHINE_TYPE,
                 system_name=system_name)
         # No fallback...
         mappings = {}
     keymap = Keymap(machine_class.get_keys(),
                     system.KEYS + machine_class.get_actions())
     keymap.set_mappings(mappings)
     return keymap
Beispiel #24
0
 def get_system_keymap(self, machine_type=None, system_name=None):
     if machine_type is None:
         machine_type = self.get_machine_type()
     try:
         machine_class = registry.get_plugin('machine', machine_type).obj
     except:
         log.error("invalid machine type: %s", machine_type, exc_info=True)
         return None
     if system_name is None:
         system_name = self.get_system_name()
     try:
         system = registry.get_plugin('system', system_name).obj
     except:
         log.error("invalid system name: %s", system_name, exc_info=True)
         return None
     section = SYSTEM_CONFIG_SECTION % system_name
     option = SYSTEM_KEYMAP_OPTION % machine_type
     mappings = self._get(section, option, None)
     if mappings is None:
         # No user mappings, use system default.
         mappings = system.KEYMAPS.get(machine_type)
     else:
         try:
             mappings = dict(json.loads(mappings))
         except ValueError:
             log.error("invalid machine keymap, resetting to default",
                       exc_info=True)
             self.set_system_keymap(None, machine_type)
             mappings = system.KEYMAPS.get(machine_type)
     if mappings is None:
         if machine_class.KEYMAP_MACHINE_TYPE is not None:
             # Try fallback.
             return self.get_system_keymap(
                 machine_type=machine_class.KEYMAP_MACHINE_TYPE,
                 system_name=system_name
             )
         # No fallback...
         mappings = {}
     keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions())
     keymap.set_mappings(mappings)
     return keymap
Beispiel #25
0
 def get_system_name(self):
     system_name = self._get(BASE_SYSTEM_SECTION, SYSTEM_NAME_OPTION, None)
     if system_name is not None:
         try:
             system_name = registry.get_plugin('system', system_name).name
         except:
             log.error("invalid system name: %s",
                       system_name,
                       exc_info=True)
             self.set_system_name(DEFAULT_SYSTEM_NAME)
             system_name = None
     if system_name is None:
         system_name = DEFAULT_SYSTEM_NAME
     return system_name
Beispiel #26
0
 def get_system_name(self):
     system_name = self._get(BASE_SYSTEM_SECTION,
                             SYSTEM_NAME_OPTION,
                             None)
     if system_name is not None:
         try:
             system_name = registry.get_plugin('system', system_name).name
         except:
             log.error("invalid system name: %s",
                       system_name, exc_info=True)
             self.set_system_name(DEFAULT_SYSTEM_NAME)
             system_name = None
     if system_name is None:
         system_name = DEFAULT_SYSTEM_NAME
     return system_name
Beispiel #27
0
 def get_machine_type(self):
     machine_type = self._get(MACHINE_CONFIG_SECTION,
                              MACHINE_TYPE_OPTION,
                              None)
     if machine_type is not None:
         try:
             machine_type = registry.get_plugin('machine', machine_type).name
         except:
             log.error("invalid machine type: %s",
                       machine_type, exc_info=True)
             self.set_machine_type(DEFAULT_MACHINE_TYPE)
             machine_type = None
     if machine_type is None:
         machine_type = DEFAULT_MACHINE_TYPE
     return machine_type
Beispiel #28
0
 def get_machine_type(self):
     machine_type = self._get(MACHINE_CONFIG_SECTION, MACHINE_TYPE_OPTION,
                              None)
     if machine_type is not None:
         try:
             machine_type = registry.get_plugin('machine',
                                                machine_type).name
         except:
             log.error("invalid machine type: %s",
                       machine_type,
                       exc_info=True)
             self.set_machine_type(DEFAULT_MACHINE_TYPE)
             machine_type = None
     if machine_type is None:
         machine_type = DEFAULT_MACHINE_TYPE
     return machine_type
Beispiel #29
0
def main():
    """Launch plover."""
    description = "Run the plover stenotype engine. This is a graphical application."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('--version',
                        action='version',
                        version='%s %s' %
                        (__software_name__.capitalize(), __version__))
    parser.add_argument('-l',
                        '--log-level',
                        choices=['debug', 'info', 'warning', 'error'],
                        default=None,
                        help='set log level')
    parser.add_argument('-g', '--gui', default='qt', help='set gui')
    args = parser.parse_args(args=sys.argv[1:])
    if args.log_level is not None:
        log.set_level(args.log_level.upper())
    log.setup_platform_handler()

    registry.load_plugins()
    registry.update()

    gui = registry.get_plugin('gui', args.gui).obj

    try:
        # Ensure only one instance of Plover is running at a time.
        with plover.oslayer.processlock.PloverLock():
            if sys.platform.startswith('darwin'):
                appnope.nope()
            init_config_dir()
            # This must be done after calling init_config_dir, so
            # Plover's configuration directory actually exists.
            log.setup_logfile()
            log.info('Plover %s', __version__)
            config = Config()
            config.target_file = CONFIG_FILE
            code = gui.main(config)
            with open(config.target_file, 'wb') as f:
                config.save(f)
    except plover.oslayer.processlock.LockNotAcquiredException:
        gui.show_error('Error',
                       'Another instance of Plover is already running.')
        code = 1
    except:
        gui.show_error('Unexpected error', traceback.format_exc())
        code = 2
    os._exit(code)
Beispiel #30
0
 def _machine_option(self, *args):
     machine_options = {
         plugin.name: plugin.obj
         for plugin in registry.list_plugins('gui.qt.machine_option')
     }
     machine_type = self._config['machine_type']
     machine_class = registry.get_plugin('machine', machine_type).obj
     for klass in machine_class.mro():
         # Look for `module_name:class_name` before `class_name`.
         for name in (
                 '%s:%s' % (klass.__module__, klass.__name__),
                 klass.__name__,
         ):
             opt_class = machine_options.get(name)
             if opt_class is not None:
                 return opt_class(*args)
     return NopeOption(*args)
Beispiel #31
0
 def _machine_option(self, *args):
     machine_options = {
         plugin.name: plugin.obj
         for plugin in registry.list_plugins('gui.qt.machine_option')
     }
     machine_type = self._config['machine_type']
     machine_class = registry.get_plugin('machine', machine_type).obj
     for klass in machine_class.mro():
         # Look for `module_name:class_name` before `class_name`.
         for name in (
             '%s:%s' % (klass.__module__, klass.__name__),
             klass.__name__,
         ):
             opt_class = machine_options.get(name)
             if opt_class is not None:
                 return opt_class(*args)
     return NopeOption(*args)
Beispiel #32
0
 def get_machine_specific_options(self, machine_type=None):
     if machine_type is None:
         machine_type = self.get_machine_type()
     def convert(p, v):
         try:
             return p[1](v)
         except ValueError:
             return p[0]
     machine_class = registry.get_plugin('machine', machine_type).obj
     info = machine_class.get_option_info()
     defaults = {k: v[0] for k, v in info.items()}
     if self._config.has_section(machine_type):
         options = {o: self._config.get(machine_type, o)
                    for o in self._config.options(machine_type)
                    if o in info}
         options = {k: convert(info[k], v) for k, v in options.items()}
         defaults.update(options)
     return defaults
Beispiel #33
0
def main():
    """Launch plover."""
    description = "Run the plover stenotype engine. This is a graphical application."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('--version', action='version', version='%s %s'
                        % (__software_name__.capitalize(), __version__))
    parser.add_argument('-l', '--log-level', choices=['debug', 'info', 'warning', 'error'],
                        default=None, help='set log level')
    parser.add_argument('-g', '--gui', default='qt', help='set gui')
    args = parser.parse_args(args=sys.argv[1:])
    if args.log_level is not None:
        log.set_level(args.log_level.upper())
    log.setup_platform_handler()

    registry.load_plugins()
    registry.update()

    gui = registry.get_plugin('gui', args.gui).obj

    try:
        # Ensure only one instance of Plover is running at a time.
        with plover.oslayer.processlock.PloverLock():
            if sys.platform.startswith('darwin'):
                appnope.nope()
            init_config_dir()
            # This must be done after calling init_config_dir, so
            # Plover's configuration directory actually exists.
            log.setup_logfile()
            log.info('Plover %s', __version__)
            config = Config()
            config.target_file = CONFIG_FILE
            code = gui.main(config)
            with open(config.target_file, 'wb') as f:
                config.save(f)
    except plover.oslayer.processlock.LockNotAcquiredException:
        gui.show_error('Error', 'Another instance of Plover is already running.')
        code = 1
    except:
        gui.show_error('Unexpected error', traceback.format_exc())
        code = 2
    os._exit(code)
Beispiel #34
0
    def get_machine_specific_options(self, machine_type=None):
        if machine_type is None:
            machine_type = self.get_machine_type()

        def convert(p, v):
            try:
                return p[1](v)
            except ValueError:
                return p[0]

        machine_class = registry.get_plugin('machine', machine_type).resolve()
        info = machine_class.get_option_info()
        defaults = {k: v[0] for k, v in info.items()}
        if self._config.has_section(machine_type):
            options = {
                o: self._config.get(machine_type, o)
                for o in self._config.options(machine_type) if o in info
            }
            options = {k: convert(info[k], v) for k, v in options.items()}
            defaults.update(options)
        return defaults
Beispiel #35
0
 def validate(config, key, raw_options):
     if not isinstance(raw_options, (dict, configparser.SectionProxy)):
         raise InvalidConfigOption(raw_options, default(config, key))
     machine_options = OrderedDict()
     invalid_options = OrderedDict()
     machine_class = registry.get_plugin('machine', key[1]).obj
     for name, params in sorted(machine_class.get_option_info().items()):
         fallback, convert = params
         try:
             raw_value = raw_options[name]
         except KeyError:
             value = fallback
         else:
             try:
                 value = convert(raw_value)
             except ValueError:
                 invalid_options[name] = raw_value
                 value = fallback
         machine_options[name] = value
     if invalid_options:
         raise InvalidConfigOption(invalid_options, machine_options)
     return machine_options
Beispiel #36
0
 def validate(config, key, raw_options):
     if not isinstance(raw_options, (dict, configparser.SectionProxy)):
         raise InvalidConfigOption(raw_options, default(config, key))
     machine_options = OrderedDict()
     invalid_options = OrderedDict()
     machine_class = registry.get_plugin('machine', key[1]).obj
     for name, params in sorted(machine_class.get_option_info().items()):
         fallback, convert = params
         try:
             raw_value = raw_options[name]
         except KeyError:
             value = fallback
         else:
             try:
                 value = convert(raw_value)
             except ValueError:
                 invalid_options[name] = raw_value
                 value = fallback
         machine_options[name] = value
     if invalid_options:
         raise InvalidConfigOption(invalid_options, machine_options)
     return machine_options
Beispiel #37
0
 def get_dictionary_file_names(self):
     system_name = self.get_system_name()
     try:
         system = registry.get_plugin('system', system_name).resolve()
     except:
         log.error("invalid system name: %s", system_name, exc_info=True)
         return []
     section = SYSTEM_CONFIG_SECTION % system_name
     option = SYSTEM_DICTIONARIES_OPTION
     filenames = self._get(section, option, None)
     if filenames is None:
         filenames = self._legacy_get_dictionary_file_names()
         if filenames is None:
             filenames = system.DEFAULT_DICTIONARIES
     else:
         try:
             filenames = tuple(json.loads(filenames))
         except ValueError as e:
             log.error("invalid system dictionaries, resetting to default",
                       exc_info=True)
             self.set_dictionary_file_names(None)
             filenames = system.DEFAULT_DICTIONARIES
     return [expand_path(path) for path in filenames]
Beispiel #38
0
 def get_dictionaries(self):
     system_name = self.get_system_name()
     try:
         system = registry.get_plugin('system', system_name).obj
     except:
         log.error("invalid system name: %s", system_name, exc_info=True)
         return []
     section = SYSTEM_CONFIG_SECTION % system_name
     option = SYSTEM_DICTIONARIES_OPTION
     dictionaries = self._get(section, option, None)
     if dictionaries is None:
         dictionaries = self._legacy_get_dictionary_file_names()
         if dictionaries is None:
             dictionaries = [DictionaryConfig(path)
                             for path in system.DEFAULT_DICTIONARIES]
         return dictionaries
     try:
         return [DictionaryConfig.from_dict(d)
                 for d in json.loads(dictionaries)]
     except:
         log.error("invalid system dictionaries, resetting to default", exc_info=True)
         self.set_dictionaries(None)
         return self.get_dictionaries()
Beispiel #39
0
 def get_dictionary_file_names(self):
     system_name = self.get_system_name()
     try:
         system = registry.get_plugin('system', system_name).resolve()
     except:
         log.error("invalid system name: %s", system_name, exc_info=True)
         return []
     section = SYSTEM_CONFIG_SECTION % system_name
     option = SYSTEM_DICTIONARIES_OPTION
     filenames = self._get(section, option, None)
     if filenames is None:
         filenames = self._legacy_get_dictionary_file_names()
         if filenames is None:
             filenames = system.DEFAULT_DICTIONARIES
     else:
         try:
             filenames = tuple(json.loads(filenames))
         except ValueError as e:
             log.error("invalid system dictionaries, resetting to default",
                       exc_info=True)
             self.set_dictionary_file_names(None)
             filenames = system.DEFAULT_DICTIONARIES
     return [expand_path(path) for path in filenames]
Beispiel #40
0
def main():
    """Launch plover."""
    description = "Run the plover stenotype engine. This is a graphical application."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('--version',
                        action='version',
                        version='%s %s' %
                        (__software_name__.capitalize(), __version__))
    parser.add_argument(
        '-s',
        '--script',
        default=None,
        nargs=argparse.REMAINDER,
        help='use another plugin console script as main entrypoint, '
        'passing in the rest of the command line arguments, '
        'print list of available scripts when no argument is given')
    parser.add_argument('-l',
                        '--log-level',
                        choices=['debug', 'info', 'warning', 'error'],
                        default=None,
                        help='set log level')
    parser.add_argument('-g', '--gui', default=None, help='set gui')
    args = parser.parse_args(args=sys.argv[1:])
    if args.log_level is not None:
        log.set_level(args.log_level.upper())
    log.setup_platform_handler()

    log.info('Plover %s', __version__)
    log.info('configuration directory: %s', CONFIG_DIR)
    log.info('plugins directory: %s', PLUGINS_DIR)

    registry.update()

    if args.gui is None:
        gui_priority = {
            'qt': 1,
            'none': -1,
        }
        gui_list = sorted(registry.list_plugins('gui'),
                          reverse=True,
                          key=lambda gui: gui_priority.get(gui.name, 0))
        gui = gui_list[0].obj
    else:
        gui = registry.get_plugin('gui', args.gui).obj

    try:
        if args.script is not None:
            if args.script:
                # Create a mapping of available console script,
                # with the following priorities (highest first):
                # - {project_name}-{version}:{script_name}
                # - {project_name}:{script_name}
                # - {script_name}
                console_scripts = {}
                for e in sorted(
                        pkg_resources.iter_entry_points('console_scripts'),
                        key=lambda e: (e.dist, e.name)):
                    for key in (
                            '%s-%s:%s' %
                        (e.dist.project_name, e.dist.version, e.name),
                            '%s:%s' % (e.dist.project_name, e.name),
                            e.name,
                    ):
                        console_scripts[key] = e
                entrypoint = console_scripts.get(args.script[0])
                if entrypoint is None:
                    log.error('no such script: %s', args.script[0])
                    code = 1
                else:
                    sys.argv = args.script
                    try:
                        code = entrypoint.load()()
                    except SystemExit as e:
                        code = e.code
                if code is None:
                    code = 0
            else:
                print('available script(s):')
                dist = None
                for e in sorted(
                        pkg_resources.iter_entry_points('console_scripts'),
                        key=lambda e: (str(e.dist), e.name)):
                    if dist != e.dist:
                        dist = e.dist
                        print('%s:' % dist)
                    print('- %s' % e.name)
                code = 0
            os._exit(code)

        # Ensure only one instance of Plover is running at a time.
        with plover.oslayer.processlock.PloverLock():
            if sys.platform.startswith('darwin'):
                appnope.nope()
            init_config_dir()
            # This must be done after calling init_config_dir, so
            # Plover's configuration directory actually exists.
            log.setup_logfile()
            config = Config()
            config.target_file = CONFIG_FILE
            code = gui.main(config)
            with open(config.target_file, 'wb') as f:
                config.save(f)
    except plover.oslayer.processlock.LockNotAcquiredException:
        gui.show_error('Error',
                       'Another instance of Plover is already running.')
        code = 1
    except:
        gui.show_error('Unexpected error', traceback.format_exc())
        code = 2
    if code == -1:
        # Restart.
        args = sys.argv[:]
        if args[0].endswith('.py') or args[0].endswith('.pyc'):
            # We're running from source.
            assert args[0] == __file__
            args[0:1] = [sys.executable, '-m', __spec__.name]
        # Execute atexit handlers.
        atexit._run_exitfuncs()
        if sys.platform.startswith('win32'):
            # Workaround https://bugs.python.org/issue19066
            subprocess.Popen(args, cwd=os.getcwd())
            code = 0
        else:
            os.execv(args[0], args)
    os._exit(code)
Beispiel #41
0
 def translate_macro(self, macro):
     macro_fn = registry.get_plugin('macro', macro.name).obj
     macro_fn(self, macro.stroke, macro.cmdline)
Beispiel #42
0
 def default(config, key):
     system = registry.get_plugin('system', key[1]).obj
     return [DictionaryConfig(path) for path in system.DEFAULT_DICTIONARIES]
Beispiel #43
0
 def _update(self, config_update=None, full=False, reset_machine=False):
     original_config = self._config.as_dict()
     # Update configuration.
     if config_update is not None:
         self._config.update(**config_update)
         config = self._config.as_dict()
     else:
         config = original_config
     # Create configuration update.
     if full:
         config_update = config
     else:
         config_update = {
             option: value
             for option, value in config.items()
             if value != original_config[option]
         }
     # Update logging.
     log.set_stroke_filename(config['log_file_name'])
     log.enable_stroke_logging(config['enable_stroke_logging'])
     log.enable_translation_logging(config['enable_translation_logging'])
     # Update output.
     self._formatter.set_space_placement(config['space_placement'])
     self._formatter.start_attached = config['start_attached']
     self._formatter.start_capitalized = config['start_capitalized']
     self._translator.set_min_undo_length(config['undo_levels'])
     # Update system.
     system_name = config['system_name']
     if system.NAME != system_name:
         log.info('loading system: %s', system_name)
         system.setup(system_name)
     # Update machine.
     update_keymap = False
     start_machine = False
     machine_params = MachineParams(config['machine_type'],
                                    config['machine_specific_options'],
                                    config['system_keymap'])
     # Do not reset if only the keymap changed.
     if self._machine_params is None or \
        self._machine_params.type != machine_params.type or \
        self._machine_params.options != machine_params.options:
         reset_machine = True
     if reset_machine:
         if self._machine is not None:
             self._machine.stop_capture()
             self._machine = None
         machine_type = config['machine_type']
         machine_options = config['machine_specific_options']
         machine_class = registry.get_plugin('machine', machine_type).obj
         log.info('setting machine: %s', machine_type)
         self._machine = machine_class(machine_options)
         self._machine.set_suppression(self._is_running)
         self._machine.add_state_callback(self._machine_state_callback)
         self._machine.add_stroke_callback(self._machine_stroke_callback)
         self._machine_params = machine_params
         update_keymap = True
         start_machine = True
     elif self._machine is not None:
         update_keymap = 'system_keymap' in config_update
     if update_keymap:
         machine_keymap = config['system_keymap']
         if machine_keymap is not None:
             self._machine.set_keymap(machine_keymap)
     if start_machine:
         self._machine.start_capture()
     # Update running extensions.
     enabled_extensions = config['enabled_extensions']
     running_extensions = set(self._running_extensions)
     self._stop_extensions(running_extensions - enabled_extensions)
     self._start_extensions(enabled_extensions - running_extensions)
     # Trigger `config_changed` hook.
     if config_update:
         self._trigger_hook('config_changed', config_update)
     # Update dictionaries.
     config_dictionaries = OrderedDict(
         (d.path, d) for d in config['dictionaries'])
     copy_default_dictionaries(config_dictionaries.keys())
     # Start by unloading outdated dictionaries.
     self._dictionaries_manager.unload_outdated()
     self._set_dictionaries([
         d for d in self._dictionaries.dicts
         if d.path in config_dictionaries and \
            d.path in self._dictionaries_manager
     ])
     # And then (re)load all dictionaries.
     dictionaries = []
     for result in self._dictionaries_manager.load(
             config_dictionaries.keys()):
         if isinstance(result, DictionaryLoaderException):
             d = ErroredDictionary(result.path, result.exception)
             # Only show an error if it's new.
             if d != self._dictionaries.get(result.path):
                 log.error('loading dictionary `%s` failed: %s',
                           shorten_path(result.path), str(result.exception))
         else:
             d = result
         d.enabled = config_dictionaries[d.path].enabled
         dictionaries.append(d)
     self._set_dictionaries(dictionaries)
Beispiel #44
0
 def __init__(self, engine, use_qt_notifications):
     super(MainWindow, self).__init__()
     self.setupUi(self)
     if hasattr(self, 'setUnifiedTitleAndToolBarOnMac'):
         self.setUnifiedTitleAndToolBarOnMac(True)
     self._engine = engine
     self._active_dialogs = {}
     self._dialog_class = {
         'about'             : AboutDialog,
         'configuration'     : ConfigWindow,
     }
     self.action_Quit.triggered.connect(QCoreApplication.quit)
     all_actions = find_menu_actions(self.menubar)
     # Dictionaries.
     self.dictionaries = DictionariesWidget(engine)
     self.dictionaries.add_translation.connect(self._add_translation)
     self.scroll_area.setWidget(self.dictionaries)
     self.dictionaries.setFocus()
     edit_menu = all_actions['menu_Edit'].menu()
     edit_menu.addAction(self.dictionaries.action_Undo)
     edit_menu.addSeparator()
     edit_menu.addAction(self.dictionaries.action_AddDictionaries)
     edit_menu.addAction(self.dictionaries.action_EditDictionaries)
     edit_menu.addAction(self.dictionaries.action_RemoveDictionaries)
     edit_menu.addSeparator()
     edit_menu.addAction(self.dictionaries.action_MoveDictionariesUp)
     edit_menu.addAction(self.dictionaries.action_MoveDictionariesDown)
     # Tray icon.
     self._trayicon = TrayIcon()
     self._trayicon.enable()
     self._trayicon.clicked.connect(self._engine.toggle_output)
     if use_qt_notifications:
         handler = NotificationHandler()
         handler.emitSignal.connect(self._trayicon.log)
         log.add_handler(handler)
     popup_menu = QMenu()
     for action_name in (
         'action_ToggleOutput',
         'action_Reconnect',
         '',
         'menu_Tools',
         '',
         'action_Configure',
         '',
         'menu_Help',
         '',
         'action_Show',
         'action_Quit',
     ):
         if action_name:
             popup_menu.addAction(all_actions[action_name])
         else:
             popup_menu.addSeparator()
     self._trayicon.set_menu(popup_menu)
     engine.signal_connect('machine_state_changed', self._trayicon.update_machine_state)
     # Populate tools bar/menu.
     tools_menu = all_actions['menu_Tools'].menu()
     # Toolbar popup menu for selecting which tools are shown.
     self.toolbar_menu = QMenu()
     self.toolbar.setContextMenuPolicy(Qt.CustomContextMenu)
     self.toolbar.customContextMenuRequested.connect(
         lambda: self.toolbar_menu.popup(QCursor.pos())
     )
     for tool_name in sorted(registry.list_plugins('gui.qt.tool')):
         tool = registry.get_plugin('gui.qt.tool', tool_name).resolve()
         action_parameters = []
         if tool.ICON is not None:
             icon = tool.ICON
             # Internal QT resources start with a `:`.
             if not icon.startswith(':'):
                 icon = resource_filename(icon)
             action_parameters.append(QIcon(icon))
         action_parameters.append(tool.TITLE)
         toolbar_action = None
         for parent in (tools_menu, self.toolbar, self.toolbar_menu):
             action = parent.addAction(*action_parameters)
             action.setObjectName(tool_name)
             if tool.__doc__ is not None:
                 action.setToolTip(tool.__doc__)
             if tool.SHORTCUT is not None:
                 action.setShortcut(QKeySequence.fromString(tool.SHORTCUT))
             if parent == self.toolbar_menu:
                 action.setCheckable(True)
                 action.setChecked(True)
                 assert toolbar_action is not None
                 action.toggled.connect(toolbar_action.setVisible)
             else:
                 if parent == self.toolbar:
                     toolbar_action = action
                 action.triggered.connect(partial(self._activate_dialog,
                                                  tool_name,
                                                  args=()))
         self._dialog_class[tool_name] = tool
     engine.signal_connect('output_changed', self.on_output_changed)
     # Machine.
     self.machine_type.addItems(
         _(machine)
         for machine in engine.list_plugins('machine')
     )
     engine.signal_connect('config_changed', self.on_config_changed)
     engine.signal_connect('machine_state_changed',
         lambda machine, state:
         self.machine_state.setText(_(state.capitalize()))
     )
     self.restore_state()
     # Commands.
     engine.signal_connect('add_translation', partial(self._add_translation, manage_windows=True))
     engine.signal_connect('focus', self._focus)
     engine.signal_connect('configure', partial(self._configure, manage_windows=True))
     engine.signal_connect('lookup', partial(self._activate_dialog, 'lookup',
                                             manage_windows=True))
     # Load the configuration (but do not start the engine yet).
     if not engine.load_config():
         self.on_configure()
     # Apply configuration settings.
     config = self._engine.config
     self._configured = False
     self.dictionaries.on_config_changed(config)
     self.set_visible(not config['start_minimized'])
     # Start the engine.
     engine.start()
Beispiel #45
0
 def translate_macro(self, macro):
     macro_fn = registry.get_plugin('macro', macro.name).obj
     macro_fn(self, macro.stroke, macro.cmdline)
Beispiel #46
0
def main():
    """Launch plover."""
    description = "Run the plover stenotype engine. This is a graphical application."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('--version', action='version', version='%s %s'
                        % (__software_name__.capitalize(), __version__))
    parser.add_argument('-s', '--script', default=None, nargs=argparse.REMAINDER,
                        help='use another plugin console script as main entrypoint, '
                        'passing in the rest of the command line arguments, '
                        'print list of available scripts when no argument is given')
    parser.add_argument('-l', '--log-level', choices=['debug', 'info', 'warning', 'error'],
                        default=None, help='set log level')
    parser.add_argument('-g', '--gui', default=None, help='set gui')
    args = parser.parse_args(args=sys.argv[1:])
    if args.log_level is not None:
        log.set_level(args.log_level.upper())
    log.setup_platform_handler()

    log.info('Plover %s', __version__)
    log.info('configuration directory: %s', CONFIG_DIR)

    registry.update()

    if args.gui is None:
        gui_priority = {
            'qt': 1,
            'none': -1,
        }
        gui_list = sorted(registry.list_plugins('gui'), reverse=True,
                          key=lambda gui: gui_priority.get(gui.name, 0))
        gui = gui_list[0].obj
    else:
        gui = registry.get_plugin('gui', args.gui).obj

    try:
        if args.script is not None:
            if args.script:
                # Create a mapping of available console script,
                # with the following priorities (highest first):
                # - {project_name}-{version}:{script_name}
                # - {project_name}:{script_name}
                # - {script_name}
                console_scripts = {}
                for e in sorted(pkg_resources.iter_entry_points('console_scripts'),
                                key=lambda e: (e.dist, e.name)):
                    for key in (
                        '%s-%s:%s' % (e.dist.project_name, e.dist.version, e.name),
                        '%s:%s' % (e.dist.project_name, e.name),
                        e.name,
                    ):
                        console_scripts[key] = e
                entrypoint = console_scripts.get(args.script[0])
                if entrypoint is None:
                    log.error('no such script: %s', args.script[0])
                    code = 1
                else:
                    sys.argv = args.script
                    try:
                        code = entrypoint.load()()
                    except SystemExit as e:
                        code = e.code
                if code is None:
                    code = 0
            else:
                print('available script(s):')
                dist = None
                for e in sorted(pkg_resources.iter_entry_points('console_scripts'),
                                key=lambda e: (str(e.dist), e.name)):
                    if dist != e.dist:
                        dist = e.dist
                        print('%s:' % dist)
                    print('- %s' % e.name)
                code = 0
            os._exit(code)

        # Ensure only one instance of Plover is running at a time.
        with processlock.PloverLock():
            if sys.platform.startswith('darwin'):
                appnope.nope()
            init_config_dir()
            # This must be done after calling init_config_dir, so
            # Plover's configuration directory actually exists.
            log.setup_logfile()
            config = Config()
            config.target_file = CONFIG_FILE
            code = gui.main(config)
            with open(config.target_file, 'wb') as f:
                config.save(f)
    except processlock.LockNotAcquiredException:
        gui.show_error('Error', 'Another instance of Plover is already running.')
        code = 1
    except:
        gui.show_error('Unexpected error', traceback.format_exc())
        code = 2
    if code == -1:
        # Restart.
        args = sys.argv[:]
        if args[0].endswith('.py') or args[0].endswith('.pyc'):
            # We're running from source.
            assert args[0] == __file__
            args[0:1] = [sys.executable, '-m', __spec__.name]
        # Execute atexit handlers.
        atexit._run_exitfuncs()
        if sys.platform.startswith('win32'):
            # Workaround https://bugs.python.org/issue19066
            subprocess.Popen(args, cwd=os.getcwd())
            code = 0
        else:
            os.execv(args[0], args)
    os._exit(code)
Beispiel #47
0
def _atom_to_action(atom, ctx):
    """Convert an atom into an action.

    Arguments:

    atom -- A string holding an atom. An atom is an irreducible string that is
    either entirely a single meta command or entirely text containing no meta
    commands.

    last_action -- The context in which the new action takes place.

    Returns: An action for the atom.

    """
    meta = _get_meta(atom)
    if meta is not None:
        meta = _unescape_atom(meta)
        if meta in META_COMMAS:
            action = _apply_meta_comma(meta, ctx)
        elif meta in META_STOPS:
            action = _apply_meta_stop(meta, ctx)
        elif meta == META_CAPITALIZE:
            action = _apply_meta_case(CASE_CAP_FIRST_WORD, ctx)
        elif meta == META_LOWER:
            action = _apply_meta_case(CASE_LOWER_FIRST_CHAR, ctx)
        elif meta == META_UPPER:
            action = _apply_meta_case(CASE_UPPER_FIRST_WORD, ctx)
        elif meta == META_RETRO_CAPITALIZE:
            action = _apply_meta_retro_case(CASE_CAP_FIRST_WORD, ctx)
        elif meta == META_RETRO_LOWER:
            action = _apply_meta_retro_case(CASE_LOWER_FIRST_CHAR, ctx)
        elif meta == META_RETRO_UPPER:
            action = _apply_meta_retro_case(CASE_UPPER_FIRST_WORD, ctx)
        elif (meta.startswith(META_CARRY_CAPITALIZATION) or
              meta.startswith(META_ATTACH_FLAG + META_CARRY_CAPITALIZATION)):
            action = _apply_meta_carry_capitalize(meta, ctx)
        elif meta.startswith(META_RETRO_FORMAT):
            action = _apply_meta_currency(meta, ctx)
        elif meta.startswith(META_COMMAND):
            action = _apply_meta_command(meta, ctx)
        elif meta.startswith(META_MODE):
            action = _apply_meta_mode(meta, ctx)
        elif meta.startswith(META_GLUE_FLAG):
            action = _apply_meta_glue(meta, ctx)
        elif (meta.startswith(META_ATTACH_FLAG)
              or meta.endswith(META_ATTACH_FLAG)):
            action = _apply_meta_attach(meta, ctx)
        elif meta.startswith(META_KEY_COMBINATION):
            action = _apply_meta_combo(meta, ctx)
        elif meta.startswith(META_CUSTOM):
            meta_args = meta[1:].split(':', 1)
            meta_fn = registry.get_plugin('meta', meta_args[0]).obj
            action = meta_fn(ctx, meta_args[1] if len(meta_args) == 2 else '')
        else:
            action = ctx.new_action()
    else:
        action = ctx.new_action()
        action.text = _unescape_atom(atom)
    # Finalize action's text.
    text = action.text
    if text is not None:
        # Update word.
        if action.word is None:
            last_word = None
            if action.glue and ctx.last_action.glue:
                last_word = ctx.last_action.word
            action.word = _rightmost_word((last_word or '') + text)
        # Apply case.
        case = ctx.last_action.next_case
        if case is None and action.prev_attach and ctx.last_action.upper_carry:
            case = CASE_UPPER_FIRST_WORD
        text = _apply_case(text, case)
        if case == CASE_UPPER_FIRST_WORD:
            action.upper_carry = not _has_word_boundary(text)
        # Apply mode.
        action.text = _apply_mode(text, action.case, action.space_char,
                                  action.prev_attach, ctx.last_action)
        # Update trailing space.
        action.trailing_space = '' if action.next_attach else action.space_char
Beispiel #48
0
 def _update(self, config_update=None, full=False, reset_machine=False):
     original_config = self._config.as_dict()
     # Update configuration.
     if config_update is not None:
         self._config.update(**config_update)
         config = self._config.as_dict()
     else:
         config = original_config
     # Create configuration update.
     if full:
         config_update = config
     else:
         config_update = {option: value for option, value in config.items() if value != original_config[option]}
         if "machine_type" in config_update:
             for opt in ("machine_specific_options", "system_keymap"):
                 config_update[opt] = config[opt]
     # Update logging.
     log.set_stroke_filename(config["log_file_name"])
     log.enable_stroke_logging(config["enable_stroke_logging"])
     log.enable_translation_logging(config["enable_translation_logging"])
     # Update output.
     self._formatter.set_space_placement(config["space_placement"])
     self._formatter.start_attached = config["start_attached"]
     self._formatter.start_capitalized = config["start_capitalized"]
     self._translator.set_min_undo_length(config["undo_levels"])
     # Update system.
     system_name = config["system_name"]
     if system.NAME != system_name:
         log.info("loading system: %s", system_name)
         system.setup(system_name)
     # Update machine.
     update_keymap = False
     start_machine = False
     machine_params = MachineParams(
         config["machine_type"], config["machine_specific_options"], config["system_keymap"]
     )
     if reset_machine or machine_params != self._machine_params:
         if self._machine is not None:
             self._machine.stop_capture()
             self._machine = None
         machine_type = config["machine_type"]
         machine_options = config["machine_specific_options"]
         try:
             machine_class = registry.get_plugin("machine", machine_type).resolve()
         except Exception as e:
             raise InvalidConfigurationError(str(e))
         log.info("setting machine: %s", machine_type)
         self._machine = machine_class(machine_options)
         self._machine.set_suppression(self._is_running)
         self._machine.add_state_callback(self._machine_state_callback)
         self._machine.add_stroke_callback(self._machine_stroke_callback)
         self._machine_params = machine_params
         update_keymap = True
         start_machine = True
     elif self._machine is not None:
         update_keymap = "system_keymap" in config_update
     if update_keymap:
         machine_keymap = config["system_keymap"]
         if machine_keymap is not None:
             self._machine.set_keymap(machine_keymap)
     if start_machine:
         self._machine.start_capture()
     # Update dictionaries.
     dictionaries_files = config["dictionary_file_names"]
     copy_default_dictionaries(dictionaries_files)
     dictionaries = self._dictionaries_manager.load(dictionaries_files)
     self._dictionaries.set_dicts(dictionaries)
     # Trigger `config_changed` hook.
     if config_update:
         self._trigger_hook("config_changed", config_update)
Beispiel #49
0
def main():
    """Launch plover."""
    description = "Run the plover stenotype engine. This is a graphical application."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('--version',
                        action='version',
                        version='%s %s' %
                        (__software_name__.capitalize(), __version__))
    parser.add_argument(
        '-s',
        '--script',
        default=None,
        nargs=argparse.REMAINDER,
        help='use another plugin console script as main entrypoint, '
        'passing in the rest of the command line arguments, '
        'print list of available scripts when no argument is given')
    parser.add_argument('-l',
                        '--log-level',
                        choices=['debug', 'info', 'warning', 'error'],
                        default=None,
                        help='set log level')
    parser.add_argument('-g', '--gui', default=None, help='set gui')
    args = parser.parse_args(args=sys.argv[1:])
    if args.log_level is not None:
        log.set_level(args.log_level.upper())
    log.setup_platform_handler()

    log.info('Plover %s', __version__)
    log.info('configuration directory: %s', CONFIG_DIR)

    if PLATFORM == 'mac':
        # Fixes PyQt issue on macOS Big Sur.
        os.environ['QT_MAC_WANTS_LAYER'] = '1'

    registry.update()

    if args.gui is None:
        gui_priority = {
            'qt': 1,
            'none': -1,
        }
        gui_list = sorted(registry.list_plugins('gui'),
                          reverse=True,
                          key=lambda gui: gui_priority.get(gui.name, 0))
        gui = gui_list[0].obj
    else:
        gui = registry.get_plugin('gui', args.gui).obj

    try:
        if args.script is not None:
            if args.script:
                # Create a mapping of available console script,
                # with the following priorities (highest first):
                # - {project_name}-{version}:{script_name}
                # - {project_name}:{script_name}
                # - {script_name}
                console_scripts = {}
                for e in sorted(
                        pkg_resources.iter_entry_points('console_scripts'),
                        key=lambda e: (e.dist, e.name)):
                    for key in (
                            '%s-%s:%s' %
                        (e.dist.project_name, e.dist.version, e.name),
                            '%s:%s' % (e.dist.project_name, e.name),
                            e.name,
                    ):
                        console_scripts[key] = e
                entrypoint = console_scripts.get(args.script[0])
                if entrypoint is None:
                    log.error('no such script: %s', args.script[0])
                    code = 1
                else:
                    sys.argv = args.script
                    try:
                        code = entrypoint.load()()
                    except SystemExit as e:
                        code = e.code
                if code is None:
                    code = 0
            else:
                print('available script(s):')
                dist = None
                for e in sorted(
                        pkg_resources.iter_entry_points('console_scripts'),
                        key=lambda e: (str(e.dist), e.name)):
                    if dist != e.dist:
                        dist = e.dist
                        print('%s:' % dist)
                    print('- %s' % e.name)
                code = 0
            os._exit(code)

        # Ensure only one instance of Plover is running at a time.
        with Controller() as controller:
            if controller.is_owner:
                # Not other instance, regular startup.
                if PLATFORM == 'mac':
                    import appnope
                    appnope.nope()
                init_config_dir()
                # This must be done after calling init_config_dir, so
                # Plover's configuration directory actually exists.
                log.setup_logfile()
                config = Config(CONFIG_FILE)
                code = gui.main(config, controller)
            else:
                log.info(
                    'another instance is running, sending `focus` command')
                # Other instance? Try focusing the main window.
                try:
                    controller.send_command('focus')
                except ConnectionRefusedError:
                    log.error('connection to existing instance failed, '
                              'force cleaning before restart')
                    # Assume the previous instance died, leaving
                    # a stray socket, try cleaning it...
                    if not controller.force_cleanup():
                        raise
                    # ...and restart.
                    code = -1
                else:
                    code = 0
    except:
        gui.show_error('Unexpected error', traceback.format_exc())
        code = 2
    if code == -1:
        # Restart.
        args = sys.argv[:]
        if args[0].endswith('.py') or args[0].endswith('.pyc'):
            # We're running from source.
            spec = sys.modules['__main__'].__spec__
            assert sys.argv[0] == spec.origin
            args[0:1] = [sys.executable, '-m', spec.name]
        # Execute atexit handlers.
        atexit._run_exitfuncs()
        if PLATFORM == 'win':
            # Workaround https://bugs.python.org/issue19066
            subprocess.Popen(args, cwd=os.getcwd())
            code = 0
        else:
            os.execv(args[0], args)
    os._exit(code)
Beispiel #50
0
 def validate(config, key, value):
     try:
         return registry.get_plugin(plugin_type, value).name
     except KeyError as e:
         raise InvalidConfigOption(value, default) from e
Beispiel #51
0
 def default(config, key):
     machine_class = registry.get_plugin('machine', key[1]).obj
     return {
         name: params[0]
         for name, params in machine_class.get_option_info().items()
     }
Beispiel #52
0
 def validate(config, key, value):
     try:
         return registry.get_plugin(plugin_type, value).name
     except KeyError as e:
         raise InvalidConfigOption(value, default) from e
Beispiel #53
0
 def _update(self, config_update=None, full=False, reset_machine=False):
     original_config = self._config.as_dict()
     # Update configuration.
     if config_update is not None:
         self._config.update(**config_update)
         config = self._config.as_dict()
     else:
         config = original_config
     # Create configuration update.
     if full:
         config_update = config
     else:
         config_update = {
             option: value
             for option, value in config.items()
             if value != original_config[option]
         }
         if 'machine_type' in config_update:
             for opt in (
                 'machine_specific_options',
                 'system_keymap',
             ):
                 config_update[opt] = config[opt]
     # Update logging.
     log.set_stroke_filename(config['log_file_name'])
     log.enable_stroke_logging(config['enable_stroke_logging'])
     log.enable_translation_logging(config['enable_translation_logging'])
     # Update output.
     self._formatter.set_space_placement(config['space_placement'])
     self._formatter.start_attached = config['start_attached']
     self._formatter.start_capitalized = config['start_capitalized']
     self._translator.set_min_undo_length(config['undo_levels'])
     # Update system.
     system_name = config['system_name']
     if system.NAME != system_name:
         log.info('loading system: %s', system_name)
         system.setup(system_name)
     # Update machine.
     update_keymap = False
     start_machine = False
     machine_params = MachineParams(config['machine_type'],
                                    config['machine_specific_options'],
                                    config['system_keymap'])
     # Do not reset if only the keymap changed.
     if self._machine_params is None or \
        self._machine_params.type != machine_params.type or \
        self._machine_params.options != machine_params.options:
         reset_machine = True
     if reset_machine:
         if self._machine is not None:
             self._machine.stop_capture()
             self._machine = None
         machine_type = config['machine_type']
         machine_options = config['machine_specific_options']
         try:
             machine_class = registry.get_plugin('machine', machine_type).obj
         except Exception as e:
             raise InvalidConfigurationError(str(e))
         log.info('setting machine: %s', machine_type)
         self._machine = machine_class(machine_options)
         self._machine.set_suppression(self._is_running)
         self._machine.add_state_callback(self._machine_state_callback)
         self._machine.add_stroke_callback(self._machine_stroke_callback)
         self._machine_params = machine_params
         update_keymap = True
         start_machine = True
     elif self._machine is not None:
         update_keymap = 'system_keymap' in config_update
     if update_keymap:
         machine_keymap = config['system_keymap']
         if machine_keymap is not None:
             self._machine.set_keymap(machine_keymap)
     if start_machine:
         self._machine.start_capture()
     # Update running extensions.
     enabled_extensions = config['enabled_extensions']
     running_extensions = set(self._running_extensions)
     self._stop_extensions(running_extensions - enabled_extensions)
     self._start_extensions(enabled_extensions - running_extensions)
     # Trigger `config_changed` hook.
     if config_update:
         self._trigger_hook('config_changed', config_update)
     # Update dictionaries.
     config_dictionaries = OrderedDict(
         (d.path, d)
         for d in config['dictionaries']
     )
     copy_default_dictionaries(config_dictionaries.keys())
     # Start by unloading outdated dictionaries.
     self._dictionaries_manager.unload_outdated()
     self._set_dictionaries([
         d for d in self._dictionaries.dicts
         if d.path in config_dictionaries and \
            d.path in self._dictionaries_manager
     ])
     # And then (re)load all dictionaries.
     dictionaries = []
     for result in self._dictionaries_manager.load(config_dictionaries.keys()):
         if isinstance(result, DictionaryLoaderException):
             d = ErroredDictionary(result.path, result.exception)
             # Only show an error if it's new.
             if d != self._dictionaries.get(result.path):
                 log.error('loading dictionary `%s` failed: %s',
                           shorten_path(result.path), str(result.exception))
         else:
             d = result
         d.enabled = config_dictionaries[d.path].enabled
         dictionaries.append(d)
     self._set_dictionaries(dictionaries)
Beispiel #54
0
 def default(config, key):
     machine_class = registry.get_plugin('machine', key[1]).obj
     return {
         name: params[0]
         for name, params in machine_class.get_option_info().items()
     }
Beispiel #55
0
 def default(config, key):
     system = registry.get_plugin('system', key[1]).obj
     return [DictionaryConfig(path) for path in system.DEFAULT_DICTIONARIES]
Beispiel #56
0
def _atom_to_action(atom, ctx):
    """Convert an atom into an action.

    Arguments:

    atom -- A string holding an atom. An atom is an irreducible string that is
    either entirely a single meta command or entirely text containing no meta
    commands.

    last_action -- The context in which the new action takes place.

    Returns: An action for the atom.

    """
    meta = _get_meta(atom)
    if meta is not None:
        meta = _unescape_atom(meta)
        if meta in META_COMMAS:
            action = _apply_meta_comma(meta, ctx)
        elif meta in META_STOPS:
            action = _apply_meta_stop(meta, ctx)
        elif meta == META_CAPITALIZE:
            action = _apply_meta_case(CASE_CAP_FIRST_WORD, ctx)
        elif meta == META_LOWER:
            action = _apply_meta_case(CASE_LOWER_FIRST_CHAR, ctx)
        elif meta == META_UPPER:
            action = _apply_meta_case(CASE_UPPER_FIRST_WORD, ctx)
        elif meta == META_RETRO_CAPITALIZE:
            action = _apply_meta_retro_case(CASE_CAP_FIRST_WORD, ctx)
        elif meta == META_RETRO_LOWER:
            action = _apply_meta_retro_case(CASE_LOWER_FIRST_CHAR, ctx)
        elif meta == META_RETRO_UPPER:
            action = _apply_meta_retro_case(CASE_UPPER_FIRST_WORD, ctx)
        elif (meta.startswith(META_CARRY_CAPITALIZATION) or
              meta.startswith(META_ATTACH_FLAG + META_CARRY_CAPITALIZATION)):
            action = _apply_meta_carry_capitalize(meta, ctx)
        elif meta.startswith(META_RETRO_FORMAT):
            action = _apply_meta_currency(meta, ctx)
        elif meta.startswith(META_COMMAND):
            action = _apply_meta_command(meta, ctx)
        elif meta.startswith(META_MODE):
            action = _apply_meta_mode(meta, ctx)
        elif meta.startswith(META_GLUE_FLAG):
            action = _apply_meta_glue(meta, ctx)
        elif (meta.startswith(META_ATTACH_FLAG) or
              meta.endswith(META_ATTACH_FLAG)):
            action = _apply_meta_attach(meta, ctx)
        elif meta.startswith(META_KEY_COMBINATION):
            action = _apply_meta_combo(meta, ctx)
        elif meta.startswith(META_CUSTOM):
            meta_args = meta[1:].split(':', 1)
            meta_fn = registry.get_plugin('meta', meta_args[0]).obj
            action = meta_fn(ctx, meta_args[1] if len(meta_args) == 2 else '')
        else:
            action = ctx.new_action()
    else:
        action = ctx.new_action()
        action.text = _unescape_atom(atom)
    # Finalize action's text.
    text = action.text
    if text is not None:
        # Update word.
        if action.word is None:
            last_word = None
            if action.glue and ctx.last_action.glue:
                last_word = ctx.last_action.word
            action.word = _rightmost_word((last_word or '') + text)
        # Apply case.
        case = ctx.last_action.next_case
        if case is None and action.prev_attach and ctx.last_action.upper_carry:
            case = CASE_UPPER_FIRST_WORD
        text = _apply_case(text, case)
        if case == CASE_UPPER_FIRST_WORD:
            action.upper_carry = not _has_word_boundary(text)
        # Apply mode.
        action.text = _apply_mode(text, action.case, action.space_char,
                                  action.prev_attach, ctx.last_action)
        # Update trailing space.
        action.trailing_space = '' if action.next_attach else action.space_char
    return action