def repeat_last_fragment(translator: Translator, stroke: Stroke, macro_args: str) -> None: ''' Macro to repeat the last fragments(s) in Plover. :param translator: The active Plover translator that is executing the macro. :type translator: plover.translation.Translator :param stroke: The current stroke (what invoked this macro). :type stroke: plover.translation.Stroke :param macro_args: The optional arguments specified to the macro as a comma-delimited string. Piece 1: The number of previous fragments to repeat. Default is 1. :type macro_args: str ''' # Get the current state translations = translator.get_state().translations if not translations: return # Process input try: num_to_repeat = int(macro_args.split(DELIM_ARGS)[0]) except: num_to_repeat = 1 # Output the new translations formatter = RetroFormatter(translations) last_fragments = formatter.last_fragments(num_to_repeat) for fragment in last_fragments: new_translation = Translation([stroke], fragment) translator.translate_translation(new_translation)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) engine = QApplication.instance().engine self._engine = engine self._dictionaries = [] self._reverse_order = False self._selected_dictionary = None engine.signal_connect('config_changed', self.on_config_changed) self.on_config_changed(engine.config) engine.signal_connect('dictionaries_loaded', self.on_dictionaries_loaded) self.on_dictionaries_loaded(self._engine.dictionaries) self._special_fmt = ( '<span style="' + 'background-color:' + self.palette().base().color().name() +';' + 'font-family:monospace;' + '">%s</span>' ) self.strokes.installEventFilter(self) self.translation.installEventFilter(self) with engine: # Pre-populate the strokes or translations with last stroke/word. last_translations = engine.translator_state.translations translation = None for t in reversed(last_translations): # Find the last undoable stroke. if t.has_undo(): translation = t break # Is it a raw stroke? if translation is not None and not translation.english: # Yes. self.strokes.setText(translation.formatting[0].text) self.on_strokes_edited() self.strokes.selectAll() else: # No, grab the last-formatted word. retro_formatter = RetroFormatter(last_translations) last_words = retro_formatter.last_words(strip=True) if last_words: self.translation.setText(last_words[0]) self.on_translation_edited() self._original_state = self.EngineState(None, engine.translator_state, engine.starting_stroke_state) engine.clear_translator_state() self._strokes_state = self.EngineState(self._dictionary_filter, engine.translator_state, StartingStrokeState(True, False)) engine.clear_translator_state() self._translations_state = self.EngineState(None, engine.translator_state, StartingStrokeState(True, False)) self._engine_state = self._original_state self._focus = None
def on_translation(self, old, new): # Check for new output. for a in reversed(new): if a.text and not a.text.isspace(): break else: return # Get previous words equal to the maximum possible search result count. with self._engine: last_translations = self._engine.translator_state.translations retro_formatter = RetroFormatter(last_translations) split_words = retro_formatter.last_words(self._word_limit, rx=self.WORD_RX) suggestion_list = [] for phrase in self.tails(split_words): phrase = ''.join(phrase) suggestion_list.extend(self._engine.get_suggestions(phrase)) if not suggestion_list and split_words: suggestion_list = [Suggestion(split_words[-1], [])] if suggestion_list and suggestion_list != self._last_suggestions: self._last_suggestions = suggestion_list self._show_suggestions(suggestion_list)
def on_translated(self, old, new): # Check for new output. for a in reversed(new): if a.text and not a.text.isspace(): break else: return last_translations = self.engine.translator_state.translations retro_formatter = RetroFormatter(last_translations) split_words = retro_formatter.last_words(10, rx=WORD_RX) suggestion_list = [] for phrase in tails(split_words): phrase = "".join(phrase) suggestion_list.extend(self.engine.get_suggestions(phrase)) if suggestion_list: self.output(format_suggestions(suggestion_list))
def _on_translated(self, _old, new): if len(new) == 0: # true if the stroke is an undo stroke return with self.engine: last_translations = self.engine.translator_state.translations retro_formatter = RetroFormatter(last_translations) split_words = retro_formatter.last_words(10, rx=self.WORD_RX) # last few "phrases", e.g. "let's go", "'s go", "s go", "go" phrases = set( ("".join(split_words[i:]) for i in range(len(split_words)))) # last translation in case it isn't shown exactly, e.g. "{#Return}{^}", {^ing} if len(last_translations) > 0: last_translation = last_translations[-1].english if last_translation is not None: phrases.add(escape_translation(last_translation)) for phrase in phrases: for suggestion in self.engine.get_suggestions(phrase): self.card_suggestions.add_suggestion(suggestion)
def on_translation(self, old, new): # verify new output exists for a in reversed(new): if a.text and not a.text.isspace(): break else: return # check for optimality last = None for phrase in self.tails( self.engine.translator_state.translations[-10:]): english = ''.join(RetroFormatter(phrase).last_fragments(999)) if english == last: continue last = english stroked = [y for x in phrase for y in x.rtfcre] suggestions = [ y for x in self.engine.get_suggestions(english) for y in x.steno_list if len(y) < len(stroked) ] if suggestions: self.f.write( f'[{datetime.now().strftime("%F %T")}] {english:15} || {"/".join(stroked)} -> {", ".join("/".join(x) for x in suggestions)}\n' ) self.f.flush()
def __init__(self, engine, on_output, on_exit): self.engine = engine self.on_exit = on_exit self.on_output = on_output self.outcome = "" self.strokes_info = "" self.translation_info = "" # we start in the strokes field add_filter(engine) self.dicts = [] for path in self.engine.dictionaries: d = self.engine.dictionaries[path] if not d.readonly: self.dicts.append(d) self.dict_index = 0 picker_kb = KeyBindings() # FormattedTextControl can't have accept_handler bound @picker_kb.add("enter") def _(event): self.accept(None) @picker_kb.add("left") def _(event): target = self.dict_index - 1 if target < 0: target = len(self.dicts) - 1 self.dict_index = target @picker_kb.add("right") def _(event): target = self.dict_index + 1 if target > len(self.dicts) - 1: target = 0 self.dict_index = target self.dictionary_picker = Window(FormattedTextControl( focusable=True, text=lambda: f"{self.dicts[self.dict_index].path}", style="class:normal", key_bindings=picker_kb), height=1) self.strokes_field = TextArea( prompt="Strokes: ", height=1, multiline=False, wrap_lines=False, accept_handler=self.accept, style="class:normal", ) self.strokes_field.buffer.on_text_changed += self.strokes_changed self.translation_field = TextArea( prompt="Output: ", height=1, multiline=False, wrap_lines=False, accept_handler=self.accept, style="class:normal", ) self.translation_field.buffer.on_text_changed += self.translation_changed last_translations = engine.translator_state.translations retro_formatter = RetroFormatter(last_translations) last_words = retro_formatter.last_words(1) if last_words: self.translation_field.text = last_words[0].replace("\n", "").rstrip() kb = KeyBindings() @kb.add("escape", eager=True) def _(event): layout = get_app().layout remove_filter(self.engine) self.outcome = "Add translation abandoned" self.update_output() on_exit() def focus(direction): layout = get_app().layout if direction == 'next': layout.focus_next() if direction == 'previous': layout.focus_previous() if layout.has_focus(self.strokes_field): add_filter(self.engine) else: remove_filter(self.engine) self.update_output() @kb.add("tab") def _(event): focus('next') @kb.add("s-tab") def _(event): focus('previous') self.container = HSplit( [ self.dictionary_picker, self.strokes_field, self.translation_field ], key_bindings=kb, )
def on_stroke(self, stroke: Stroke): if self.started: raw_steno = "" tran_text = "" paragraph = "" keys = stroke.steno_keys[:] # Contains an array of the latest dictionary entry matches formatted = self.translations[ -1].english if self.translations else [] tran_text = formatted or "" # Loop through the inputted keys to format output. (I.e. with one key, include hyphen to know which it was) for key in keys: if len(keys) == 2 and key.find("-") != -1: raw_steno += key[0] + key[1].replace("-", "") elif len(keys) > 2: raw_steno += key.replace("-", "") else: raw_steno += key if self._both_steno_realtime.isChecked(): if self.printer is not None: self._tape.appendPlainText(raw_steno + "\t\t" + tran_text) self.left_right(self.printer, raw_steno, tran_text) elif self._raw_only.isChecked(): self._tape.appendPlainText(raw_steno) try: self.printer.text(raw_steno) self.printer.text("\n") except: self._tape.setPlainText( "Printer is not connected or cannot establish communication." ) self._connect.setEnabled(True) else: tran_text = self.translations[self.starting_point:] formatter = RetroFormatter( self.translations[self.starting_point:]) or "" for word in formatter.last_words(-1): paragraph += word if word and word.find("\n" or "\r") > -1: try: self.printer.text(paragraph) self.printer.text("\n\n") # Make sure to reset the start pointer self.starting_point = len(self.translations) paragraph = "" except: self._tape.setPlainText( "Printer is not connected or establish communication." ) self._connect.setEnabled(True) self._tape.setPlainText(paragraph)