mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-20 04:47:42 +00:00
Merge pull request #15096 from keymanapp/refactor/web/textStoreInterface
refactor(web): extract minimal TextStore interface that LanguageProcessor can use 🎼
This commit is contained in:
commit
e519d12032
6 changed files with 44 additions and 21 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { LexicalModelTypes } from '@keymanapp/common-types';
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import { TextStore } from "keyman/engine/keyboard";
|
||||
import { TextStoreLanguageProcessorInterface } from "keyman/engine/keyboard";
|
||||
|
||||
export class ReadySuggestions {
|
||||
suggestions: LexicalModelTypes.Suggestion[];
|
||||
|
|
@ -48,7 +48,7 @@ export interface LanguageProcessorEventMap {
|
|||
* @param textStore The `TextStore` representation of the context the suggestion was applied to.
|
||||
* @returns
|
||||
*/
|
||||
'suggestionapplied': (textStore: TextStore) => boolean
|
||||
'suggestionapplied': (textStore: TextStoreLanguageProcessorInterface) => boolean
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export interface LanguageProcessorSpec extends EventEmitter<LanguageProcessorEve
|
|||
|
||||
get state(): StateChangeEnum;
|
||||
|
||||
invalidateContext(textStore: TextStore, layerId: string): Promise<LexicalModelTypes.Suggestion[]>;
|
||||
invalidateContext(textStore: TextStoreLanguageProcessorInterface, layerId: string): Promise<LexicalModelTypes.Suggestion[]>;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -66,9 +66,9 @@ export interface LanguageProcessorSpec extends EventEmitter<LanguageProcessorEve
|
|||
* required because layerid can be changed by PostKeystroke
|
||||
* @returns
|
||||
*/
|
||||
applySuggestion(suggestion: LexicalModelTypes.Suggestion, textStore: TextStore, getLayerId: () => string): Promise<LexicalModelTypes.Reversion>;
|
||||
applySuggestion(suggestion: LexicalModelTypes.Suggestion, textStore: TextStoreLanguageProcessorInterface, getLayerId: () => string): Promise<LexicalModelTypes.Reversion>;
|
||||
|
||||
applyReversion(reversion: LexicalModelTypes.Reversion, textStore: TextStore): Promise<LexicalModelTypes.Suggestion[]>;
|
||||
applyReversion(reversion: LexicalModelTypes.Reversion, textStore: TextStoreLanguageProcessorInterface): Promise<LexicalModelTypes.Suggestion[]>;
|
||||
|
||||
get wordbreaksAfterSuggestions(): boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export { type VariableStore, VariableStoreSerializer, VariableStoreDictionary }
|
|||
|
||||
export { SyntheticTextStore } from "./syntheticTextStore.js";
|
||||
export { TextStore } from "./textStore.js";
|
||||
export { TextStoreLanguageProcessorInterface } from "./textStoreLanguageProcessorInterface.js";
|
||||
export { findCommonSubstringEndIndex } from "./stringDivergence.js";
|
||||
export { Deadkey } from "./deadkeys.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { TextStore } from './textStore.js';
|
||||
import { TextStoreLanguageProcessorInterface } from './textStoreLanguageProcessorInterface.js';
|
||||
import { KMWString } from '@keymanapp/web-utils';
|
||||
|
||||
export class SyntheticTextStore extends TextStore {
|
||||
|
|
@ -25,17 +26,11 @@ export class SyntheticTextStore extends TextStore {
|
|||
this.selForward = this.selEnd >= this.selStart;
|
||||
}
|
||||
|
||||
static assertIsOutputTargetBase(textStore: TextStore): asserts textStore is TextStore {
|
||||
if (!(textStore instanceof TextStore)) {
|
||||
throw new TypeError("textStore is not a TextStore");
|
||||
}
|
||||
}
|
||||
|
||||
// Clones the state of an existing EditableElement, creating a SyntheticTextStore version of its state.
|
||||
static from(textStore: TextStore, readonly?: boolean): SyntheticTextStore {
|
||||
static from(textStore: TextStoreLanguageProcessorInterface, readonly?: boolean): SyntheticTextStore {
|
||||
let clone: SyntheticTextStore;
|
||||
|
||||
this.assertIsOutputTargetBase(textStore);
|
||||
this.assertIsTextStore(textStore);
|
||||
|
||||
if (textStore instanceof SyntheticTextStore) {
|
||||
// Avoids the need to run expensive kmwstring.ts `length()`
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import { findCommonSubstringEndIndex } from "./stringDivergence.js";
|
|||
import { SyntheticTextStore } from "./syntheticTextStore.js";
|
||||
|
||||
// Defines deadkey management in a manner attachable to each element interface.
|
||||
import { type KeyEvent } from 'keyman/engine/keyboard';
|
||||
import { type KeyEvent } from './keyEvent.js';
|
||||
import { TextStoreLanguageProcessorInterface } from './textStoreLanguageProcessorInterface.js';
|
||||
import { Deadkey, DeadkeyTracker } from "./deadkeys.js";
|
||||
import { LexicalModelTypes } from '@keymanapp/common-types';
|
||||
|
||||
|
|
@ -59,6 +60,13 @@ export abstract class TextStore {
|
|||
this._dks = dks.clone();
|
||||
}
|
||||
|
||||
static assertIsTextStore(textStore: TextStoreLanguageProcessorInterface): asserts textStore is TextStore {
|
||||
if (!(textStore instanceof TextStore)) {
|
||||
throw new TypeError("textStore is not a TextStore");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the basic operations needed to reconstruct the current TextStore's text from the prior state specified
|
||||
* by another TextStore based on their text and caret positions.
|
||||
|
|
@ -67,7 +75,9 @@ export abstract class TextStore {
|
|||
* As such, it assumes that the caret is immediately after any inserted text.
|
||||
* @param from An output target (preferably a SyntheticTextStore) representing the prior state of the input/output system.
|
||||
*/
|
||||
buildTransformFrom(original: TextStore): TextTransform {
|
||||
buildTransformFrom(original: TextStoreLanguageProcessorInterface): TextTransform {
|
||||
TextStore.assertIsTextStore(original);
|
||||
|
||||
const toLeft = this.getTextBeforeCaret();
|
||||
const fromLeft = original.getTextBeforeCaret();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
|
||||
import { LexicalModelTypes } from '@keymanapp/common-types';
|
||||
import { KeyEvent } from './keyEvent.js';
|
||||
import { Transcription } from './keyboards/transcription.js';
|
||||
import { Alternate } from './keyboards/textTransform.js';
|
||||
|
||||
/**
|
||||
* Interface with the methods LanguageProcessor needs from TextStore
|
||||
* for transcription building and applying transforms.
|
||||
*/
|
||||
export interface TextStoreLanguageProcessorInterface {
|
||||
buildTranscriptionFrom(original: TextStoreLanguageProcessorInterface, keyEvent: KeyEvent, readonly: boolean, alternates?: Alternate[]): Transcription;
|
||||
apply(transform: LexicalModelTypes.Transform): void;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { EventEmitter } from "eventemitter3";
|
||||
import { LMLayer, WorkerFactory } from "@keymanapp/lexical-model-layer/web";
|
||||
import { Transcription, TextStore, SyntheticTextStore } from 'keyman/engine/keyboard';
|
||||
import { Transcription, TextStoreLanguageProcessorInterface, SyntheticTextStore } from 'keyman/engine/keyboard';
|
||||
import { LanguageProcessorEventMap, ModelSpec, StateChangeEnum, ReadySuggestions } from 'keyman/engine/interfaces';
|
||||
import ContextWindow from "./contextWindow.js";
|
||||
import { TranscriptionCache } from "./transcriptionCache.js";
|
||||
|
|
@ -125,7 +125,7 @@ export class LanguageProcessor extends EventEmitter<LanguageProcessorEventMap> {
|
|||
});
|
||||
}
|
||||
|
||||
public invalidateContext(textStore: TextStore, layerId: string): Promise<Suggestion[]> {
|
||||
public invalidateContext(textStore: TextStoreLanguageProcessorInterface, layerId: string): Promise<Suggestion[]> {
|
||||
// If there's no active model, there can be no predictions.
|
||||
// We'll also be missing important data needed to even properly REQUEST the predictions.
|
||||
if(!this.currentModel || !this.configuration) {
|
||||
|
|
@ -153,7 +153,7 @@ export class LanguageProcessor extends EventEmitter<LanguageProcessorEventMap> {
|
|||
}
|
||||
}
|
||||
|
||||
public wordbreak(textStore: TextStore, layerId: string): Promise<string> {
|
||||
public wordbreak(textStore: TextStoreLanguageProcessorInterface, layerId: string): Promise<string> {
|
||||
if(!this.isActive) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ export class LanguageProcessor extends EventEmitter<LanguageProcessorEventMap> {
|
|||
* required because layerid can be changed by PostKeystroke
|
||||
* @returns
|
||||
*/
|
||||
public applySuggestion(suggestion: Suggestion, textStore: TextStore, getLayerId: ()=>string): Promise<Reversion> {
|
||||
public applySuggestion(suggestion: Suggestion, textStore: TextStoreLanguageProcessorInterface, getLayerId: ()=>string): Promise<Reversion> {
|
||||
if(!textStore) {
|
||||
throw new Error("Accepting suggestions requires a destination TextStore instance.");
|
||||
}
|
||||
|
|
@ -263,7 +263,7 @@ export class LanguageProcessor extends EventEmitter<LanguageProcessorEventMap> {
|
|||
}
|
||||
}
|
||||
|
||||
public applyReversion(reversion: Reversion, textStore: TextStore) {
|
||||
public applyReversion(reversion: Reversion, textStore: TextStoreLanguageProcessorInterface) {
|
||||
if(!textStore) {
|
||||
throw new Error("Accepting suggestions requires a destination TextStore instance.");
|
||||
}
|
||||
|
|
@ -305,7 +305,7 @@ export class LanguageProcessor extends EventEmitter<LanguageProcessorEventMap> {
|
|||
return promise;
|
||||
}
|
||||
|
||||
public predictFromTarget(textStore: TextStore, layerId: string): Promise<Suggestion[]> {
|
||||
public predictFromTarget(textStore: TextStoreLanguageProcessorInterface, layerId: string): Promise<Suggestion[]> {
|
||||
if(!this.isActive || !textStore) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue