Skip to content

Commit

Permalink
add support for macros
Browse files Browse the repository at this point in the history
  • Loading branch information
benoit-pierre committed Nov 22, 2017
1 parent 99a9590 commit ce40f8e
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 84 deletions.
5 changes: 4 additions & 1 deletion plover/gui_qt/add_translation_widget.py
Expand Up @@ -112,7 +112,10 @@ def _set_engine_state(self, state):

@staticmethod
def _dictionary_filter(key, value):
# Only allow translations with special entries. Do this by looking for
# Allow undo...
if value == '=undo':
return False
# ...and translations with special entries. Do this by looking for
# braces but take into account escaped braces and slashes.
escaped = value.replace('\\\\', '').replace('\\{', '')
special = '{#' in escaped or '{PLOVER:' in escaped
Expand Down
Empty file added plover/macro/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions plover/macro/repeat.py
@@ -0,0 +1,11 @@

from plover.steno import Stroke


def last_stroke(translator, stroke, cmdline):
# Repeat last stroke
translations = translator.get_state().translations
if not translations:
return
stroke = Stroke(translations[-1].strokes[-1].steno_keys)
translator.translate_stroke(stroke)
56 changes: 56 additions & 0 deletions plover/macro/retrospective.py
@@ -0,0 +1,56 @@

from plover.translation import Translation
from plover.steno import Stroke


def toggle_asterisk(translator, stroke, cmdline):
# Toggle asterisk of previous stroke
translations = translator.get_state().translations
if not translations:
return
t = translations[-1]
translator.untranslate_translation(t)
keys = set(t.strokes[-1].steno_keys)
if '*' in keys:
keys.remove('*')
else:
keys.add('*')
translator.translate_stroke(Stroke(keys))

def delete_space(translator, stroke, cmdline):
# Retrospective delete space
translations = translator.get_state().translations
if len(translations) < 2:
return
replaced = translations[-2:]
if replaced[1].is_retrospective_command:
return
english = []
for t in replaced:
if t.english is not None:
english.append(t.english)
elif len(t.rtfcre) == 1 and t.rtfcre[0].isdigit():
english.append('{&%s}' % t.rtfcre[0])
if len(english) > 1:
t = Translation([stroke], '{^~|^}'.join(english))
t.replaced = replaced
t.is_retrospective_command = True
translator.translate_translation(t)

def insert_space(translator, stroke, cmdline):
# Retrospective insert space
translations = translator.get_state().translations
if not translations:
return
replaced = translations[-1]
if replaced.is_retrospective_command:
return
lookup_stroke = replaced.strokes[-1]
english = [t.english or '/'.join(t.rtfcre)
for t in replaced.replaced]
if english:
english.append(translator.lookup([lookup_stroke]) or lookup_stroke.rtfcre)
t = Translation([stroke], ' '.join(english))
t.replaced = [replaced]
t.is_retrospective_command = True
translator.translate_translation(t)
20 changes: 20 additions & 0 deletions plover/macro/undo.py
@@ -0,0 +1,20 @@

import sys

from plover.translation import Translation


if sys.platform.startswith('darwin'):
BACK_STRING = '{#Alt_L(BackSpace)}{^}'
else:
BACK_STRING = '{#Control_L(BackSpace)}{^}'

def undo(translator, stroke, cmdline):
for t in reversed(translator.get_state().translations):
translator.untranslate_translation(t)
if t.has_undo():
return
# There is no more buffer to delete from -- remove undo and add a
# stroke that removes last word on the user's OS, but don't add it
# to the state history.
translator.flush([Translation([stroke], BACK_STRING)])
1 change: 1 addition & 0 deletions plover/registry.py
Expand Up @@ -32,6 +32,7 @@ class Registry(object):
'gui.qt.machine_option',
'gui.qt.tool',
'machine',
'macro',
'system',
)

Expand Down
111 changes: 28 additions & 83 deletions plover/translation.py
Expand Up @@ -17,11 +17,11 @@
"""

from collections import namedtuple
import sys
import re

from plover.steno import Stroke
from plover.steno_dictionary import StenoDictionaryCollection
from plover.registry import registry
from plover import system


Expand Down Expand Up @@ -52,14 +52,30 @@ def unescape_translation(translation):
return _UNESCAPE_RX.sub(lambda m: _UNESCAPE_REPLACEMENTS[m.group(0)], translation)


_MACROS = {
'{*}', # retrospective toggle asterisk
'{*!}', # retrospective delete space
'{*?}', # retrospective insert space
'{*+}', # repeat last stroke
_LEGACY_MACROS_ALIASES = {
'{*}': 'retrospective_toggle_asterisk',
'{*!}': 'retrospective_delete_space',
'{*?}': 'retrospective_insert_space',
'{*+}': 'repeat_last_stroke',
}

Macro = namedtuple('Macro', 'name stroke args')
Macro = namedtuple('Macro', 'name stroke cmdline')

def _mapping_to_macro(mapping, stroke):
'''Return a macro/stroke if mapping is one, or None otherwise.'''
macro, cmdline = None, ''
if mapping is None:
if stroke.is_correction:
macro = 'undo'
else:
if mapping in _LEGACY_MACROS_ALIASES:
macro = _LEGACY_MACROS_ALIASES[mapping]
elif mapping.startswith('=') and len(mapping) > 1:
args = mapping[1:].split(':', 1)
macro = args[0]
if len(args) == 2:
cmdline = args[1]
return Macro(macro, stroke, cmdline) if macro else None


class Translation(object):
Expand Down Expand Up @@ -281,19 +297,10 @@ def translate_stroke(self, stroke):
stroke -- The Stroke object to process.
"""
if stroke.is_correction:
for t in reversed(self._state.translations):
self.untranslate_translation(t)
if t.has_undo():
return
# There is no more buffer to delete from -- remove undo and add a
# stroke that removes last word on the user's OS, but don't add it
# to the state history.
self.flush([Translation([stroke], _back_string())])
return
mapping = self.lookup([stroke])
if mapping in _MACROS:
self.translate_macro(Macro(mapping, stroke, ''))
macro = _mapping_to_macro(mapping, stroke)
if macro is not None:
self.translate_macro(macro)
return
t = (
self._find_translation_helper(stroke) or
Expand All @@ -303,59 +310,8 @@ def translate_stroke(self, stroke):
self.translate_translation(t)

def translate_macro(self, macro):
translations = self._state.translations
if macro.name == '{*}':
# Toggle asterisk of previous stroke
if not translations:
return
t = translations[-1]
self.untranslate_translation(t)
keys = set(t.strokes[-1].steno_keys)
if '*' in keys:
keys.remove('*')
else:
keys.add('*')
self.translate_stroke(Stroke(keys))
elif macro.name == '{*+}':
# Repeat last stroke
if not translations:
return
stroke = Stroke(translations[-1].strokes[-1].steno_keys)
self.translate_stroke(stroke)
elif macro.name == '{*?}':
# Retrospective insert space
if not translations:
return
replaced = translations[-1]
if replaced.is_retrospective_command:
return
lookup_stroke = replaced.strokes[-1]
english = [t.english or '/'.join(t.rtfcre)
for t in replaced.replaced]
if english:
english.append(self.lookup([lookup_stroke]) or lookup_stroke.rtfcre)
t = Translation([macro.stroke], ' '.join(english))
t.replaced = [replaced]
t.is_retrospective_command = True
self.translate_translation(t)
elif macro.name == '{*!}':
# Retrospective delete space
if len(translations) < 2:
return
replaced = translations[-2:]
if replaced[1].is_retrospective_command:
return
english = []
for t in replaced:
if t.english is not None:
english.append(t.english)
elif len(t.rtfcre) == 1 and t.rtfcre[0].isdigit():
english.append('{&%s}' % t.rtfcre[0])
if len(english) > 1:
t = Translation([macro.stroke], '{^~|^}'.join(english))
t.replaced = replaced
t.is_retrospective_command = True
self.translate_translation(t)
macro_fn = registry.get_plugin('macro', macro.name).obj
macro_fn(self, macro.stroke, macro.cmdline)

def translate_translation(self, t):
self._undo(*t.replaced)
Expand Down Expand Up @@ -465,14 +421,3 @@ def restrict_size(self, n):
if translation_index:
self.tail = self.translations[translation_index - 1]
del self.translations[:translation_index]


def _back_string():
# Provides the correct translation to undo a word
# depending on the operating system and stores it
if 'mapping' not in _back_string.__dict__:
if sys.platform.startswith('darwin'):
_back_string.mapping = '{#Alt_L(BackSpace)}{^}'
else:
_back_string.mapping = '{#Control_L(BackSpace)}{^}'
return _back_string.mapping
7 changes: 7 additions & 0 deletions setup.cfg
Expand Up @@ -45,6 +45,7 @@ packages =
plover.gui_none
plover.gui_qt
plover.machine
plover.macro
plover.oslayer
plover.system
plover_build_utils
Expand Down Expand Up @@ -73,6 +74,12 @@ plover.machine =
ProCAT = plover.machine.procat:ProCAT
Stentura = plover.machine.stentura:Stentura
TX Bolt = plover.machine.txbolt:TxBolt
plover.macro =
repeat_last_stroke = plover.macro.repeat:last_stroke
retrospective_delete_space = plover.macro.retrospective:delete_space
retrospective_insert_space = plover.macro.retrospective:insert_space
retrospective_toggle_asterisk = plover.macro.retrospective:toggle_asterisk
undo = plover.macro.undo:undo
plover.system =
English Stenotype = plover.system.english_stenotype
setuptools.installation =
Expand Down
26 changes: 26 additions & 0 deletions test/test_blackbox.py
Expand Up @@ -199,6 +199,32 @@ def test_bug535_spaces_after(self):
1/P-P/2/KR*UR "$1.20 "
'''

def test_undo_not_defined(self):
r'''
'TEFT': 'test',
TEFT ' test'
* ''
'''

def test_undo_overriden(self):
r'''
'TEFT': 'test',
'*': 'not undo',
TEFT ' test'
* ' test not undo'
'''

def test_undo_macro(self):
r'''
'TEFT': 'test',
'TPH-D': '=undo',
TEFT ' test'
TPH-D ''
'''

def test_undo_fingerspelling_1(self):
r'''
'T*': '{>}{&t}',
Expand Down

0 comments on commit ce40f8e

Please sign in to comment.