plover 5.0.0rc1__py3-none-any.whl → 5.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plover/__init__.py +5 -3
- plover/config.py +58 -14
- plover/dictionary/loading_manager.py +23 -6
- plover/engine.py +216 -48
- plover/exception.py +0 -12
- plover/formatting.py +5 -2
- plover/gui_qt/about_dialog_ui.py +1 -1
- plover/gui_qt/add_translation_dialog_ui.py +1 -1
- plover/gui_qt/add_translation_widget_ui.py +1 -1
- plover/gui_qt/appearance.py +49 -0
- plover/gui_qt/config_file_widget_ui.py +1 -1
- plover/gui_qt/config_keyboard_widget_ui.py +1 -1
- plover/gui_qt/config_plover_hid_widget_ui.py +110 -0
- plover/gui_qt/config_serial_widget_ui.py +2 -11
- plover/gui_qt/config_window.py +139 -33
- plover/gui_qt/config_window_ui.py +2 -2
- plover/gui_qt/console_widget.py +1 -1
- plover/gui_qt/console_widget_ui.py +1 -1
- plover/gui_qt/dictionaries_widget.py +9 -0
- plover/gui_qt/dictionaries_widget_ui.py +1 -1
- plover/gui_qt/dictionary_editor_ui.py +1 -1
- plover/gui_qt/engine.py +6 -1
- plover/gui_qt/lookup_dialog_ui.py +1 -1
- plover/gui_qt/machine_options.py +54 -20
- plover/gui_qt/main_window.py +13 -1
- plover/gui_qt/main_window_ui.py +15 -8
- plover/gui_qt/paper_tape_ui.py +1 -1
- plover/gui_qt/plugins_manager.py +9 -4
- plover/gui_qt/plugins_manager_ui.py +2 -2
- plover/gui_qt/resources_rc.py +29 -29
- plover/gui_qt/run_dialog_ui.py +1 -1
- plover/gui_qt/suggestions_dialog_ui.py +1 -1
- plover/gui_qt/trayicon.py +0 -2
- plover/gui_qt/utils.py +0 -1
- plover/i18n.py +1 -1
- plover/key_combo.py +3 -1
- plover/log.py +2 -2
- plover/machine/base.py +12 -2
- plover/machine/keyboard_capture/__init__.py +33 -10
- plover/machine/keymap.py +86 -10
- plover/machine/plover_hid.py +333 -0
- plover/machine/procat.py +1 -4
- plover/machine/stentura.py +5 -5
- plover/messages/es/LC_MESSAGES/plover.mo +0 -0
- plover/messages/es/LC_MESSAGES/plover.po +2 -2
- plover/messages/fr/LC_MESSAGES/plover.mo +0 -0
- plover/messages/fr/LC_MESSAGES/plover.po +2 -2
- plover/messages/it/LC_MESSAGES/plover.mo +0 -0
- plover/messages/it/LC_MESSAGES/plover.po +2 -2
- plover/messages/nl/LC_MESSAGES/plover.mo +0 -0
- plover/messages/nl/LC_MESSAGES/plover.po +2 -2
- plover/messages/plover.pot +1 -1
- plover/messages/zh_tw/LC_MESSAGES/plover.mo +0 -0
- plover/messages/zh_tw/LC_MESSAGES/plover.po +2 -2
- plover/orthography.py +2 -1
- plover/oslayer/controller.py +1 -1
- plover/oslayer/linux/keyboardcontrol.py +4 -2
- plover/oslayer/linux/keyboardcontrol_uinput.py +107 -343
- plover/oslayer/linux/keyboardcontrol_x11.py +22 -13
- plover/oslayer/linux/keyboardlayout_wayland.py +403 -0
- plover/oslayer/linux/log.py +3 -1
- plover/oslayer/linux/wayland_connection.py +293 -0
- plover/oslayer/osx/keyboardlayout.py +4 -1
- plover/oslayer/windows/log.py +28 -6
- plover/plugins_manager/registry.py +4 -3
- plover/registry.py +1 -1
- plover/scripts/main.py +6 -3
- plover/system/__init__.py +7 -7
- plover/system/english_stenotype.py +53 -0
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/METADATA +5 -3
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/RECORD +84 -79
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/WHEEL +1 -1
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/entry_points.txt +5 -3
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/licenses/LICENSE.txt +4 -5
- plover_build_utils/check_requirements.py +0 -3
- plover_build_utils/download.py +5 -2
- plover_build_utils/functions.sh +69 -17
- plover_build_utils/testing/__init__.py +9 -0
- plover_build_utils/testing/blackbox.py +3 -1
- plover_build_utils/testing/steno_dictionary.py +2 -2
- /plover/machine/{geminipr.py → gemini_pr.py} +0 -0
- /plover/machine/{txbolt.py → tx_bolt.py} +0 -0
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/top_level.txt +0 -0
- {plover-5.0.0rc1.dist-info → plover-5.2.0.dist-info}/zip-safe +0 -0
plover/__init__.py
CHANGED
|
@@ -11,9 +11,11 @@ else:
|
|
|
11
11
|
# exec from `setup.py`, package data
|
|
12
12
|
# may not be available, and we don't
|
|
13
13
|
# want to translate anyway.
|
|
14
|
-
_
|
|
14
|
+
def _(s):
|
|
15
|
+
return s
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
|
|
18
|
+
__version__ = "5.2.0"
|
|
17
19
|
__copyright__ = "(C) Open Steno Project"
|
|
18
20
|
__url__ = "http://www.openstenoproject.org/"
|
|
19
21
|
__download_url__ = "http://www.openstenoproject.org/plover"
|
|
@@ -24,7 +26,7 @@ Developers:
|
|
|
24
26
|
|
|
25
27
|
Joshua Lifton
|
|
26
28
|
Hesky Fisher
|
|
27
|
-
|
|
29
|
+
Thea Morin
|
|
28
30
|
Benoit Pierre
|
|
29
31
|
Sammi Ta
|
|
30
32
|
Martin Koerner
|
plover/config.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Copyright (c) 2010-2011 Joshua Harlan Lifton.
|
|
2
2
|
# See LICENSE.txt for details.
|
|
3
3
|
|
|
4
|
-
"""
|
|
4
|
+
"""This modules handles reading and writing Plover's configuration files, as well
|
|
5
|
+
as updating the configuration on-the-fly while Plover is running."""
|
|
5
6
|
|
|
6
7
|
from collections import ChainMap, namedtuple, OrderedDict
|
|
7
8
|
import configparser
|
|
8
9
|
import json
|
|
9
10
|
import re
|
|
11
|
+
from typing import Any, Dict
|
|
10
12
|
|
|
11
13
|
from plover.exception import InvalidConfigurationError
|
|
12
14
|
from plover.machine.keymap import Keymap
|
|
@@ -17,6 +19,7 @@ from plover import log
|
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
# General configuration sections, options and defaults.
|
|
22
|
+
APPEARANCE_CONFIG_SECTION = "Appearance"
|
|
20
23
|
MACHINE_CONFIG_SECTION = "Machine Configuration"
|
|
21
24
|
|
|
22
25
|
LEGACY_DICTIONARY_CONFIG_SECTION = "Dictionary Configuration"
|
|
@@ -36,14 +39,23 @@ SYSTEM_KEYMAP_OPTION = "keymap[%s]"
|
|
|
36
39
|
|
|
37
40
|
|
|
38
41
|
class DictionaryConfig(namedtuple("DictionaryConfig", "path enabled")):
|
|
42
|
+
"""Represents the configuration for one dictionary.
|
|
43
|
+
|
|
44
|
+
Attributes:
|
|
45
|
+
path (str): The fully qualified path to the dictionary file.
|
|
46
|
+
enabled (bool): Whether the dictionary is enabled.
|
|
47
|
+
"""
|
|
48
|
+
|
|
39
49
|
def __new__(cls, path, enabled=True):
|
|
40
50
|
return super().__new__(cls, expand_path(path), enabled)
|
|
41
51
|
|
|
42
52
|
@property
|
|
43
|
-
def short_path(self):
|
|
53
|
+
def short_path(self) -> str:
|
|
54
|
+
"""The shortened path to the dictionary file. This is automatically calculated from :attr:`path`."""
|
|
44
55
|
return shorten_path(self.path)
|
|
45
56
|
|
|
46
|
-
def to_dict(self):
|
|
57
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
58
|
+
"""Returns the ``dict`` representation of the dictionary configuration."""
|
|
47
59
|
# Note: do not use _asdict because of
|
|
48
60
|
# https://bugs.python.org/issue24931
|
|
49
61
|
return {
|
|
@@ -51,11 +63,13 @@ class DictionaryConfig(namedtuple("DictionaryConfig", "path enabled")):
|
|
|
51
63
|
"enabled": self.enabled,
|
|
52
64
|
}
|
|
53
65
|
|
|
54
|
-
def replace(self, **kwargs):
|
|
66
|
+
def replace(self, **kwargs) -> "DictionaryConfig":
|
|
67
|
+
"""Replaces the values of :attr:`path` and :attr:`enabled` with those in ``kwargs``."""
|
|
55
68
|
return self._replace(**kwargs)
|
|
56
69
|
|
|
57
70
|
@staticmethod
|
|
58
|
-
def from_dict(d):
|
|
71
|
+
def from_dict(d: Dict[str, Any]) -> "DictionaryConfig":
|
|
72
|
+
"""Returns a :class:`DictionaryConfig` constructed from its ``dict`` representation."""
|
|
59
73
|
return DictionaryConfig(**d)
|
|
60
74
|
|
|
61
75
|
def __repr__(self):
|
|
@@ -73,6 +87,11 @@ ConfigOption = namedtuple(
|
|
|
73
87
|
|
|
74
88
|
|
|
75
89
|
class InvalidConfigOption(ValueError):
|
|
90
|
+
"""An exception raised when a configuration option has been set to an invalid
|
|
91
|
+
value, such as one of the wrong type. ``fixed_value`` is the value that
|
|
92
|
+
Plover is falling back on if ``raw_value`` can't be parsed correctly.
|
|
93
|
+
"""
|
|
94
|
+
|
|
76
95
|
def __init__(self, raw_value, fixed_value, message=None):
|
|
77
96
|
super().__init__(raw_value)
|
|
78
97
|
self.raw_value = raw_value
|
|
@@ -368,14 +387,22 @@ def dictionaries_option():
|
|
|
368
387
|
|
|
369
388
|
|
|
370
389
|
class Config:
|
|
371
|
-
|
|
390
|
+
"""An object containing the entire Plover configuration. The config object
|
|
391
|
+
maintains a cache for any changes that are made while Plover is running.
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
def __init__(self, path=None) -> None:
|
|
372
395
|
self._config = None
|
|
373
396
|
self._cache = {}
|
|
374
397
|
# A convenient place for other code to store a file name.
|
|
375
398
|
self.path = path
|
|
376
399
|
self.clear()
|
|
377
400
|
|
|
378
|
-
def load(self):
|
|
401
|
+
def load(self) -> None:
|
|
402
|
+
"""Reads and parses the configuration from the configuration file. Raises an
|
|
403
|
+
:exc:`InvalidConfigurationError<plover.exception.InvalidConfigurationError>`
|
|
404
|
+
if the configuration could not be parsed correctly.
|
|
405
|
+
"""
|
|
379
406
|
self.clear()
|
|
380
407
|
with open(self.path, encoding="utf-8") as fp:
|
|
381
408
|
try:
|
|
@@ -383,11 +410,13 @@ class Config:
|
|
|
383
410
|
except configparser.Error as e:
|
|
384
411
|
raise InvalidConfigurationError(str(e))
|
|
385
412
|
|
|
386
|
-
def clear(self):
|
|
413
|
+
def clear(self) -> None:
|
|
414
|
+
"""Clears the configuration and returns to the base state."""
|
|
387
415
|
self._config = configparser.RawConfigParser()
|
|
388
416
|
self._cache.clear()
|
|
389
417
|
|
|
390
|
-
def save(self):
|
|
418
|
+
def save(self) -> None:
|
|
419
|
+
"""Writes the current state of the configuration to the configuration file."""
|
|
391
420
|
with resource_update(self.path) as temp_path:
|
|
392
421
|
with open(temp_path, mode="w", encoding="utf-8") as fp:
|
|
393
422
|
self._config.write(fp)
|
|
@@ -427,7 +456,7 @@ class Config:
|
|
|
427
456
|
),
|
|
428
457
|
choice_option(
|
|
429
458
|
"keyboard_layout",
|
|
430
|
-
("qwerty", "qwertz", "colemak", "colemak-dh", "dvorak"),
|
|
459
|
+
("qwerty", "qwertz", "colemak", "colemak-dh", "dvorak", "wayland-auto"),
|
|
431
460
|
OUTPUT_CONFIG_SECTION,
|
|
432
461
|
),
|
|
433
462
|
# Logging.
|
|
@@ -439,6 +468,13 @@ class Config:
|
|
|
439
468
|
),
|
|
440
469
|
boolean_option("enable_stroke_logging", False, LOGGING_CONFIG_SECTION),
|
|
441
470
|
boolean_option("enable_translation_logging", False, LOGGING_CONFIG_SECTION),
|
|
471
|
+
# Appearance.
|
|
472
|
+
choice_option(
|
|
473
|
+
"appearance_mode",
|
|
474
|
+
("system", "light", "dark"),
|
|
475
|
+
APPEARANCE_CONFIG_SECTION,
|
|
476
|
+
"mode",
|
|
477
|
+
),
|
|
442
478
|
# GUI.
|
|
443
479
|
boolean_option("start_minimized", False, "Startup", "Start Minimized"),
|
|
444
480
|
boolean_option("show_stroke_display", False, "Stroke Display", "show"),
|
|
@@ -471,7 +507,10 @@ class Config:
|
|
|
471
507
|
key = opt.full_key(self, key)
|
|
472
508
|
return key, opt
|
|
473
509
|
|
|
474
|
-
def __getitem__(self, key):
|
|
510
|
+
def __getitem__(self, key: str) -> Any:
|
|
511
|
+
"""Returns the value of the specified ``key`` in the cache, or in the
|
|
512
|
+
full configuration if not available.
|
|
513
|
+
"""
|
|
475
514
|
key, opt = self._lookup(key)
|
|
476
515
|
if key in self._cache:
|
|
477
516
|
return self._cache[key]
|
|
@@ -485,16 +524,21 @@ class Config:
|
|
|
485
524
|
self._cache[key] = value
|
|
486
525
|
return value
|
|
487
526
|
|
|
488
|
-
def __setitem__(self, key, value):
|
|
527
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
528
|
+
"""Sets the property ``key`` in the configuration to the specified value."""
|
|
489
529
|
key, opt = self._lookup(key)
|
|
490
530
|
value = opt.validate(self._config, key, value)
|
|
491
531
|
opt.setter(self, key, value)
|
|
492
532
|
self._cache[key] = value
|
|
493
533
|
|
|
494
|
-
def as_dict(self):
|
|
534
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
535
|
+
"""Returns the ``dict`` representation of the current state of the
|
|
536
|
+
configuration.
|
|
537
|
+
"""
|
|
495
538
|
return {opt.name: self[opt.name] for opt in self._OPTIONS.values()}
|
|
496
539
|
|
|
497
|
-
def update(self, **kwargs):
|
|
540
|
+
def update(self, **kwargs) -> None:
|
|
541
|
+
"""Update the cache to reflect the contents of the full configuration."""
|
|
498
542
|
new_settings = []
|
|
499
543
|
new_config = ChainMap({}, self)
|
|
500
544
|
for opt in self._OPTIONS.values():
|
|
@@ -7,13 +7,19 @@ import threading
|
|
|
7
7
|
import time
|
|
8
8
|
|
|
9
9
|
from plover.dictionary.base import load_dictionary
|
|
10
|
-
from plover.exception import DictionaryLoaderException
|
|
11
10
|
from plover.resource import resource_timestamp
|
|
12
11
|
from plover import log
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class DictionaryLoadingManager:
|
|
16
|
-
def __init__(self):
|
|
15
|
+
def __init__(self, state_change_callback):
|
|
16
|
+
"""
|
|
17
|
+
Parameters:
|
|
18
|
+
state_change_callback -- A function that will be called when any dictionary is loaded
|
|
19
|
+
with two parameters: the filename and the loaded StenoDictionary object
|
|
20
|
+
(or an instance of ErroredDictionary if the load fails).
|
|
21
|
+
"""
|
|
22
|
+
self._state_change_callback = state_change_callback
|
|
17
23
|
self.dictionaries = {}
|
|
18
24
|
|
|
19
25
|
def __len__(self):
|
|
@@ -32,7 +38,7 @@ class DictionaryLoadingManager:
|
|
|
32
38
|
log.info(
|
|
33
39
|
"%s dictionary: %s", "loading" if op is None else "reloading", filename
|
|
34
40
|
)
|
|
35
|
-
op = DictionaryLoadingOperation(filename)
|
|
41
|
+
op = DictionaryLoadingOperation(filename, self._state_change_callback)
|
|
36
42
|
self.dictionaries[filename] = op
|
|
37
43
|
return op
|
|
38
44
|
|
|
@@ -52,7 +58,15 @@ class DictionaryLoadingManager:
|
|
|
52
58
|
|
|
53
59
|
|
|
54
60
|
class DictionaryLoadingOperation:
|
|
55
|
-
def __init__(self, filename):
|
|
61
|
+
def __init__(self, filename, state_change_callback):
|
|
62
|
+
"""
|
|
63
|
+
Parameters:
|
|
64
|
+
filename -- Path to dictionary file.
|
|
65
|
+
state_change_callback -- A function that will be called when the load is finished
|
|
66
|
+
with two parameters: the filename and the loaded StenoDictionary object
|
|
67
|
+
(or an instance of ErroredDictionary if the load fails).
|
|
68
|
+
"""
|
|
69
|
+
self._state_change_callback = state_change_callback
|
|
56
70
|
self.loading_thread = threading.Thread(target=self.load)
|
|
57
71
|
self.filename = filename
|
|
58
72
|
self.result = None
|
|
@@ -61,7 +75,7 @@ class DictionaryLoadingOperation:
|
|
|
61
75
|
def needs_reloading(self):
|
|
62
76
|
try:
|
|
63
77
|
new_timestamp = resource_timestamp(self.filename)
|
|
64
|
-
except:
|
|
78
|
+
except Exception:
|
|
65
79
|
# Bad resource name, permission denied, path
|
|
66
80
|
# does not exist, ...
|
|
67
81
|
new_timestamp = None
|
|
@@ -87,8 +101,11 @@ class DictionaryLoadingOperation:
|
|
|
87
101
|
self.result = load_dictionary(self.filename)
|
|
88
102
|
except Exception as e:
|
|
89
103
|
log.debug("loading dictionary %s failed", self.filename, exc_info=True)
|
|
90
|
-
|
|
104
|
+
from plover.engine import ErroredDictionary
|
|
105
|
+
|
|
106
|
+
self.result = ErroredDictionary(self.filename, e)
|
|
91
107
|
self.result.timestamp = timestamp
|
|
108
|
+
self._state_change_callback(self.filename, self.result)
|
|
92
109
|
|
|
93
110
|
def get(self):
|
|
94
111
|
self.loading_thread.join()
|