diff options
author | Alex Yatskov <FooSoft@users.noreply.github.com> | 2019-11-13 18:51:50 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-13 18:51:50 -0800 |
commit | b1659522b30cecc0583745da5a44fdd75660274a (patch) | |
tree | 89c17fa51f91ee43b1a206a9ae2d7b5721892ae9 | |
parent | 7d9d45ae10302582ce7431bd72ec4f8604dc5e65 (diff) | |
parent | 7333873244ccaeeefe01bd3a63447f39dd4f3bbe (diff) |
Merge pull request #274 from toasted-nutbread/lookup-wildcards
Lookup wildcards
-rw-r--r-- | ext/bg/js/api.js | 29 | ||||
-rw-r--r-- | ext/bg/js/backend.js | 2 | ||||
-rw-r--r-- | ext/bg/js/database.js | 9 | ||||
-rw-r--r-- | ext/bg/js/dictionary.js | 40 | ||||
-rw-r--r-- | ext/bg/js/search.js | 9 | ||||
-rw-r--r-- | ext/bg/js/translator.js | 96 | ||||
-rw-r--r-- | ext/fg/js/api.js | 4 | ||||
-rw-r--r-- | ext/fg/js/frontend.js | 2 | ||||
-rw-r--r-- | ext/mixed/js/display.js | 2 |
9 files changed, 103 insertions, 90 deletions
diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 9fed99a1..df73aa2a 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -72,33 +72,18 @@ async function apiOptionsSave(source) { backend.onOptionsUpdated(source); } -async function apiTermsFind(text, optionsContext) { +async function apiTermsFind(text, details, optionsContext) { const options = await apiOptionsGet(optionsContext); - const translator = utilBackend().translator; - - const searcher = { - 'merge': translator.findTermsMerged, - 'split': translator.findTermsSplit, - 'group': translator.findTermsGrouped - }[options.general.resultOutputMode].bind(translator); - - const {definitions, length} = await searcher( - text, - dictEnabledSet(options), - options.scanning.alphanumeric, - options - ); - - return { - length, - definitions: definitions.slice(0, options.general.maxResults) - }; + const [definitions, length] = await utilBackend().translator.findTerms(text, details, options); + definitions.splice(options.general.maxResults); + return {length, definitions}; } async function apiKanjiFind(text, optionsContext) { const options = await apiOptionsGet(optionsContext); - const definitions = await utilBackend().translator.findKanji(text, dictEnabledSet(options)); - return definitions.slice(0, options.general.maxResults); + const definitions = await utilBackend().translator.findKanji(text, options); + definitions.splice(options.general.maxResults); + return definitions; } async function apiDefinitionAdd(definition, mode, context, optionsContext) { diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 71393467..efad153a 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -179,7 +179,7 @@ Backend.messageHandlers = { optionsGet: ({optionsContext}) => apiOptionsGet(optionsContext), optionsSet: ({changedOptions, optionsContext, source}) => apiOptionsSet(changedOptions, optionsContext, source), kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext), - termsFind: ({text, optionsContext}) => apiTermsFind(text, optionsContext), + termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext), definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext), definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext), noteView: ({noteId}) => apiNoteView(noteId), diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js index b6cf9063..9b560f78 100644 --- a/ext/bg/js/database.js +++ b/ext/bg/js/database.js @@ -130,7 +130,7 @@ class Database { await Promise.all(promises); } - async findTermsBulk(termList, titles) { + async findTermsBulk(termList, titles, wildcard) { this.validate(); const promises = []; @@ -149,10 +149,11 @@ class Database { const dbIndex2 = dbTerms.index('reading'); for (let i = 0; i < termList.length; ++i) { - const only = IDBKeyRange.only(termList[i]); + const term = termList[i]; + const query = wildcard ? IDBKeyRange.bound(term, `${term}\uffff`, false, false) : IDBKeyRange.only(term); promises.push( - Database.getAll(dbIndex1, only, i, processRow), - Database.getAll(dbIndex2, only, i, processRow) + Database.getAll(dbIndex1, query, i, processRow), + Database.getAll(dbIndex2, query, i, processRow) ); } diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index a4cf34ed..9aa0af9c 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -55,39 +55,23 @@ function dictRowsSort(rows, options) { function dictTermsSort(definitions, dictionaries=null) { return definitions.sort((v1, v2) => { + let i; if (dictionaries !== null) { - const p1 = (dictionaries[v1.dictionary] || {}).priority || 0; - const p2 = (dictionaries[v2.dictionary] || {}).priority || 0; - if (p1 > p2) { - return -1; - } else if (p1 < p2) { - return 1; - } + i = ( + ((dictionaries[v2.dictionary] || {}).priority || 0) - + ((dictionaries[v1.dictionary] || {}).priority || 0) + ); + if (i !== 0) { return i; } } - const sl1 = v1.source.length; - const sl2 = v2.source.length; - if (sl1 > sl2) { - return -1; - } else if (sl1 < sl2) { - return 1; - } + i = v2.source.length - v1.source.length; + if (i !== 0) { return i; } - const rl1 = v1.reasons.length; - const rl2 = v2.reasons.length; - if (rl1 < rl2) { - return -1; - } else if (rl1 > rl2) { - return 1; - } + i = v2.reasons.length - v1.reasons.length; + if (i !== 0) { return i; } - const s1 = v1.score; - const s2 = v2.score; - if (s1 > s2) { - return -1; - } else if (s1 < s2) { - return 1; - } + i = v2.score - v1.score; + if (i !== 0) { return i; } return v2.expression.toString().localeCompare(v1.expression.toString()); }); diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index dccc7da7..56316217 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -203,11 +203,18 @@ class DisplaySearch extends Display { async onSearchQueryUpdated(query, animate) { try { + const details = {}; + const match = /[\*\uff0a]+$/.exec(query); + if (match !== null) { + details.wildcard = true; + query = query.substr(0, query.length - match[0].length); + } + const valid = (query.length > 0); this.setIntroVisible(!valid, animate); this.updateSearchButton(); if (valid) { - const {definitions} = await apiTermsFind(query, this.optionsContext); + const {definitions} = await apiTermsFind(query, details, this.optionsContext); this.setContentTerms(definitions, { focus: false, sentence: null, diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index ff1d24f3..583d6e31 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -47,22 +47,6 @@ class Translator { await this.database.deleteDictionary(dictionaryName); } - async findTermsGrouped(text, dictionaries, alphanumeric, options) { - const titles = Object.keys(dictionaries); - const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric); - - const definitionsGrouped = dictTermsGroup(definitions, dictionaries); - await this.buildTermFrequencies(definitionsGrouped, titles); - - if (options.general.compactTags) { - for (const definition of definitionsGrouped) { - dictTermsCompressTags(definition.definitions); - } - } - - return {length, definitions: definitionsGrouped}; - } - async getSequencedDefinitions(definitions, mainDictionary) { const definitionsBySequence = dictTermsMergeBySequence(definitions, mainDictionary); const defaultDefinitions = definitionsBySequence['-1']; @@ -157,10 +141,41 @@ class Translator { return result; } - async findTermsMerged(text, dictionaries, alphanumeric, options) { + async findTerms(text, details, options) { + switch (options.general.resultOutputMode) { + case 'group': + return await this.findTermsGrouped(text, details, options); + case 'merge': + return await this.findTermsMerged(text, details, options); + case 'split': + return await this.findTermsSplit(text, details, options); + default: + return [[], 0]; + } + } + + async findTermsGrouped(text, details, options) { + const dictionaries = dictEnabledSet(options); + const titles = Object.keys(dictionaries); + const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); + + const definitionsGrouped = dictTermsGroup(definitions, dictionaries); + await this.buildTermFrequencies(definitionsGrouped, titles); + + if (options.general.compactTags) { + for (const definition of definitionsGrouped) { + dictTermsCompressTags(definition.definitions); + } + } + + return [definitionsGrouped, length]; + } + + async findTermsMerged(text, details, options) { + const dictionaries = dictEnabledSet(options); const secondarySearchTitles = Object.keys(options.dictionaries).filter(dict => options.dictionaries[dict].allowSecondarySearches); const titles = Object.keys(dictionaries); - const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric); + const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); const {sequencedDefinitions, defaultDefinitions} = await this.getSequencedDefinitions(definitions, options.general.mainDictionary); const definitionsMerged = []; const mergedByTermIndices = new Set(); @@ -191,29 +206,33 @@ class Translator { } } - return {length, definitions: dictTermsSort(definitionsMerged)}; + return [dictTermsSort(definitionsMerged), length]; } - async findTermsSplit(text, dictionaries, alphanumeric) { + async findTermsSplit(text, details, options) { + const dictionaries = dictEnabledSet(options); const titles = Object.keys(dictionaries); - const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric); + const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); await this.buildTermFrequencies(definitions, titles); - return {length, definitions}; + return [definitions, length]; } - async findTerms(text, dictionaries, alphanumeric) { + async findTermsInternal(text, dictionaries, alphanumeric, details) { if (!alphanumeric && text.length > 0) { const c = text[0]; if (!jpIsKana(c) && !jpIsKanji(c)) { - return {length: 0, definitions: []}; + return [[], 0]; } } - const textHiragana = jpKatakanaToHiragana(text); const titles = Object.keys(dictionaries); - const deinflections = await this.findTermDeinflections(text, textHiragana, titles); + const deinflections = ( + details.wildcard ? + await this.findTermWildcard(text, titles) : + await this.findTermDeinflections(text, titles) + ); let definitions = []; for (const deinflection of deinflections) { @@ -246,10 +265,26 @@ class Translator { length = Math.max(length, definition.source.length); } - return {length, definitions}; + return [definitions, length]; + } + + async findTermWildcard(text, titles) { + const definitions = await this.database.findTermsBulk([text], titles, true); + if (definitions.length === 0) { + return []; + } + + return [{ + source: text, + term: text, + rules: 0, + definitions, + reasons: [] + }]; } - async findTermDeinflections(text, text2, titles) { + async findTermDeinflections(text, titles) { + const text2 = jpKatakanaToHiragana(text); const deinflections = (text === text2 ? this.getDeinflections(text) : this.getDeinflections2(text, text2)); if (deinflections.length === 0) { @@ -273,7 +308,7 @@ class Translator { deinflectionArray.push(deinflection); } - const definitions = await this.database.findTermsBulk(uniqueDeinflectionTerms, titles); + const definitions = await this.database.findTermsBulk(uniqueDeinflectionTerms, titles, false); for (const definition of definitions) { const definitionRules = Deinflector.rulesToRuleFlags(definition.rules); @@ -314,7 +349,8 @@ class Translator { return deinflections; } - async findKanji(text, dictionaries) { + async findKanji(text, options) { + const dictionaries = dictEnabledSet(options); const titles = Object.keys(dictionaries); const kanjiUnique = {}; const kanjiList = []; diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index 54818702..945ba076 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -25,8 +25,8 @@ function apiOptionsSet(changedOptions, optionsContext, source) { return utilInvoke('optionsSet', {changedOptions, optionsContext, source}); } -function apiTermsFind(text, optionsContext) { - return utilInvoke('termsFind', {text, optionsContext}); +function apiTermsFind(text, details, optionsContext) { + return utilInvoke('termsFind', {text, details, optionsContext}); } function apiKanjiFind(text, optionsContext) { diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 7c62b51b..6002dfcb 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -413,7 +413,7 @@ class Frontend { const searchText = textSource.text(); if (searchText.length === 0) { return null; } - const {definitions, length} = await apiTermsFind(searchText, this.getOptionsContext()); + const {definitions, length} = await apiTermsFind(searchText, {}, this.getOptionsContext()); if (definitions.length === 0) { return null; } textSource.setEndOffset(length); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 801011df..8ad3ee1b 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -112,7 +112,7 @@ class Display { try { textSource.setEndOffset(this.options.scanning.length); - ({definitions, length} = await apiTermsFind(textSource.text(), this.getOptionsContext())); + ({definitions, length} = await apiTermsFind(textSource.text(), {}, this.getOptionsContext())); if (definitions.length === 0) { return false; } |