Add inline character portraits and dictionary search workflow (#83)

This commit is contained in:
2026-05-25 03:16:25 -07:00
committed by GitHub
parent 7e6f9672cf
commit 807c0ff3db
54 changed files with 2306 additions and 178 deletions
@@ -124,6 +124,8 @@ function hasAnnotationRuntimeHotReload(diff: ConfigHotReloadDiff): boolean {
'ankiConnect.knownWords',
'ankiConnect.nPlusOne',
'ankiConnect.fields.word',
'subtitleStyle.nameMatchEnabled',
'subtitleStyle.nameMatchImagesEnabled',
]);
}
@@ -36,6 +36,9 @@ test('tokenizer deps builder records known-word lookups and maps readers', () =>
getJlptLevel: () => 'N2',
getJlptEnabled: () => true,
getNameMatchEnabled: () => false,
getNameMatchImagesEnabled: () => true,
getCharacterNameImage: (term) =>
term === 'name' ? { src: 'data:image/png;base64,AAAA', alt: 'Name' } : null,
getFrequencyDictionaryEnabled: () => true,
getFrequencyDictionaryMatchMode: () => 'surface',
getFrequencyRank: () => 5,
@@ -52,6 +55,11 @@ test('tokenizer deps builder records known-word lookups and maps readers', () =>
assert.equal(deps.getNPlusOneEnabled?.(), true);
assert.equal(deps.getMinSentenceWordsForNPlusOne?.(), 3);
assert.equal(deps.getNameMatchEnabled?.(), false);
assert.equal(deps.getNameMatchImagesEnabled?.(), true);
assert.deepEqual(deps.getCharacterNameImage?.('name'), {
src: 'data:image/png;base64,AAAA',
alt: 'Name',
});
assert.equal(deps.getFrequencyDictionaryMatchMode?.(), 'surface');
assert.deepEqual(calls, ['lookup:true', 'lookup:false', 'set-window', 'set-ready', 'set-init']);
});
@@ -74,6 +82,7 @@ test('tokenizer deps builder disables name matching when character dictionary is
getJlptEnabled: () => true,
getCharacterDictionaryEnabled: () => false,
getNameMatchEnabled: () => true,
getNameMatchImagesEnabled: () => true,
getFrequencyDictionaryEnabled: () => true,
getFrequencyDictionaryMatchMode: () => 'surface',
getFrequencyRank: () => 5,
@@ -82,6 +91,7 @@ test('tokenizer deps builder disables name matching when character dictionary is
})();
assert.equal(deps.getNameMatchEnabled?.(), false);
assert.equal(deps.getNameMatchImagesEnabled?.(), false);
});
test('mecab tokenizer check creates tokenizer once and runs availability check', async () => {
@@ -4,6 +4,8 @@ type TokenizerMainDeps = TokenizerDepsRuntimeOptions & {
getJlptEnabled: NonNullable<TokenizerDepsRuntimeOptions['getJlptEnabled']>;
getCharacterDictionaryEnabled?: () => boolean;
getNameMatchEnabled?: NonNullable<TokenizerDepsRuntimeOptions['getNameMatchEnabled']>;
getNameMatchImagesEnabled?: NonNullable<TokenizerDepsRuntimeOptions['getNameMatchImagesEnabled']>;
getCharacterNameImage?: NonNullable<TokenizerDepsRuntimeOptions['getCharacterNameImage']>;
getFrequencyDictionaryEnabled: NonNullable<
TokenizerDepsRuntimeOptions['getFrequencyDictionaryEnabled']
>;
@@ -57,6 +59,17 @@ export function createBuildTokenizerDepsMainHandler(deps: TokenizerMainDeps) {
deps.getCharacterDictionaryEnabled?.() !== false && deps.getNameMatchEnabled!(),
}
: {}),
...(deps.getNameMatchImagesEnabled
? {
getNameMatchImagesEnabled: () =>
deps.getCharacterDictionaryEnabled?.() !== false && deps.getNameMatchImagesEnabled!(),
}
: {}),
...(deps.getCharacterNameImage
? {
getCharacterNameImage: (term: string) => deps.getCharacterNameImage!(term),
}
: {}),
getFrequencyDictionaryEnabled: () => deps.getFrequencyDictionaryEnabled(),
getFrequencyDictionaryMatchMode: () => deps.getFrequencyDictionaryMatchMode(),
getFrequencyRank: (text: string) => deps.getFrequencyRank(text),