fix performance problem caused by too much async
This commit is contained in:
1 parent
d5c78782ca
commit
029cb16836
2 files changed
+627
-636
No files matched your search
+598
-15
@@ -9,8 +9,8 @@
|
|||||||
// Seriously.
|
// Seriously.
|
||||||
|
|
||||||
let dict = undefined;
|
let dict = undefined;
|
||||||
let lookup_kan = {};
|
let lookup_kan = new Map();
|
||||||
let lookup_kana = {};
|
let lookup_kana = new Map();
|
||||||
|
|
||||||
function builddict()
|
function builddict()
|
||||||
{
|
{
|
||||||
@@ -29,18 +29,18 @@ function builddict()
|
|||||||
if (entry.k_ele != undefined) for (let j = 0; j < entry.k_ele.length; j++)
|
if (entry.k_ele != undefined) for (let j = 0; j < entry.k_ele.length; j++)
|
||||||
{
|
{
|
||||||
let s = entry.k_ele[j];
|
let s = entry.k_ele[j];
|
||||||
if (lookup_kan[s.keb] == undefined)
|
if (!lookup_kan.has(s.keb))
|
||||||
lookup_kan[s.keb] = [i];
|
lookup_kan.set(s.keb, [i]);
|
||||||
else
|
else
|
||||||
lookup_kan[s.keb].push(i);
|
lookup_kan.get(s.keb).push(i);
|
||||||
}
|
}
|
||||||
for (let j = 0; j < entry.r_ele.length; j++)
|
for (let j = 0; j < entry.r_ele.length; j++)
|
||||||
{
|
{
|
||||||
let s = entry.r_ele[j];
|
let s = entry.r_ele[j];
|
||||||
if (lookup_kana[s.reb] == undefined)
|
if (!lookup_kana.has(s.reb))
|
||||||
lookup_kana[s.reb] = [i];
|
lookup_kana.set(s.reb, [i]);
|
||||||
else
|
else
|
||||||
lookup_kana[s.reb].push(i);
|
lookup_kana.get(s.reb).push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = 0; i < 5; i++)
|
for (let i = 0; i < 5; i++)
|
||||||
@@ -133,10 +133,10 @@ function replace_kata_with_hira(text)
|
|||||||
|
|
||||||
function search_inner(text)
|
function search_inner(text)
|
||||||
{
|
{
|
||||||
if (lookup_kan[text])
|
if (lookup_kan.has(text))
|
||||||
return getfromdict(lookup_kan[text]);
|
return getfromdict(lookup_kan.get(text));
|
||||||
else if (lookup_kana[text])
|
else if (lookup_kana.has(text))
|
||||||
return getfromdict(lookup_kana[text]);
|
return getfromdict(lookup_kana.get(text));
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -152,11 +152,594 @@ function search(text)
|
|||||||
if(ret) return ret;
|
if(ret) return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.runtime.onMessage.addListener((request, sender, sendResponse) =>
|
// deconjugation rules
|
||||||
|
let rules = [];
|
||||||
|
|
||||||
|
// TODO: load rules from an underlay
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// verb stems
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
// "e" stem used for potential and ba
|
||||||
|
rules.push({type: "neverfinalrule"
|
||||||
|
, dec_end:
|
||||||
|
["く","す","つ","う","る","る","ぐ","ぶ","ぬ","む","る","う","く"]
|
||||||
|
, con_end:
|
||||||
|
["け","せ","て","え","れ","れ","げ","べ","ね","め","れ","え","け"]
|
||||||
|
, dec_tag:
|
||||||
|
["v5k","v5s","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v1","v5u_s","v5k_s"]
|
||||||
|
, con_tag:"stem_e", detail:"(izenkei)"});
|
||||||
|
|
||||||
|
// true imperative
|
||||||
|
rules.push({type: "onlyfinalrule"
|
||||||
|
, dec_end:
|
||||||
|
["く","す","つ","う","る","る","ぐ","ぶ","ぬ","む","る","る","う","く"]
|
||||||
|
, con_end:
|
||||||
|
["け","せ","て","え","れ","れ","げ","べ","ね","め","ろ","よ","え","け"] // ichidan has two imperatives FIXME: don't let potential conjugate to よ
|
||||||
|
, dec_tag:
|
||||||
|
["v5k","v5s","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v1","v1","v5u_s","v5k_s"]
|
||||||
|
, con_tag:"uninflectable", detail:"imperative"});
|
||||||
|
|
||||||
|
// ~a stem
|
||||||
|
rules.push({type: "neverfinalrule"
|
||||||
|
, dec_end:
|
||||||
|
["く","す","つ","う","る","ぐ","ぶ","ぬ","む","う","く"]
|
||||||
|
, con_end:
|
||||||
|
["か","せ","て","わ","ら","が","ば","な","ま","わ","か"]
|
||||||
|
, dec_tag:
|
||||||
|
["v5k","v5s","v5t","v5u","v5r","v5g","v5b","v5n","v5m","v5u_s","v5k_s"] // TODO: support あらへん, あらぬ, etc
|
||||||
|
, con_tag:"stem_a", detail:"('a' stem)"});
|
||||||
|
|
||||||
|
// unvoiced past stems
|
||||||
|
rules.push({type: "neverfinalrule"
|
||||||
|
, dec_end:
|
||||||
|
["く","す","つ","う","る","る","る","う","く"]
|
||||||
|
, con_end:
|
||||||
|
["い","し","っ","っ","っ","っ","","う","っ"]
|
||||||
|
, dec_tag:
|
||||||
|
["v5k","v5s","v5t","v5u","v5r","v5r-i","v1","v5u_s","v5k_s"]
|
||||||
|
, con_tag:"stem_ren_less", detail:"(unstressed infinitive)"});
|
||||||
|
// voiced past stems
|
||||||
|
rules.push({type: "neverfinalrule"
|
||||||
|
, dec_end:
|
||||||
|
["ぐ","ぶ","ぬ","む"]
|
||||||
|
, con_end:
|
||||||
|
["い","ん","ん","ん"]
|
||||||
|
, dec_tag:
|
||||||
|
["v5g","v5b","v5n","v5m"]
|
||||||
|
, con_tag:"stem_ren_less_v", detail:"(unstressed infinitive)"});
|
||||||
|
|
||||||
|
// infinitives (ren'youkei) that are different than the corresponding past stem
|
||||||
|
rules.push({type: "stdrule"
|
||||||
|
, dec_end:
|
||||||
|
["く","つ","う","る","る","ぐ","ぶ","ぬ","む","う","く"]
|
||||||
|
, con_end:
|
||||||
|
["き","ち","い","り","り","ぎ","び","に","み","い","き"]
|
||||||
|
, dec_tag:
|
||||||
|
["v5k","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v5u_s","v5k_s"]
|
||||||
|
, con_tag:"stem_ren", detail:"(infinitive)"});
|
||||||
|
// ones that need the te trap
|
||||||
|
rules.push({type: "contextrule", contextrule:"tetrap"
|
||||||
|
, dec_end:
|
||||||
|
["す","る"]
|
||||||
|
, con_end:
|
||||||
|
["し",""]
|
||||||
|
, dec_tag:
|
||||||
|
["v5s","v1"]
|
||||||
|
, con_tag:"stem_ren", detail:"(infinitive)"});
|
||||||
|
|
||||||
|
// stem for negatives proper
|
||||||
|
rules.push({type: "neverfinalrule"
|
||||||
|
, dec_end:
|
||||||
|
["","る"]
|
||||||
|
, con_end:
|
||||||
|
["",""]
|
||||||
|
, dec_tag:
|
||||||
|
["stem_a","v1"]
|
||||||
|
, con_tag:"stem_mizenkei", detail:"(mizenkei)"});
|
||||||
|
|
||||||
|
// ~a stem
|
||||||
|
rules.push({type: "stdrule"
|
||||||
|
, dec_end:
|
||||||
|
["く","す","つ","う","る","る","ぐ","ぶ","ぬ","む","る","う","く"]
|
||||||
|
, con_end:
|
||||||
|
["こう","そう","とう","おう","ろう","ろう","ごう","ぼう","のう","もう","よう","おう","こう"]
|
||||||
|
, dec_tag:
|
||||||
|
["v5k","v5s","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v1","v5u_s","v5k_s"]
|
||||||
|
, con_tag:"form_volition", detail:"volitional"});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// adjective stems
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
rules.push({type: "stdrule", dec_end:"い", con_end:"く", dec_tag:"adj_i", con_tag:"stem_ku", detail:"(adverbial stem)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"い", con_end:"か", dec_tag:"adj_i", con_tag:"stek_ka", detail:"(ka stem)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"い", con_end:"け", dec_tag:"adj_i", con_tag:"stek_ke", detail:"(ke stem)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"い", con_end:"", dec_tag:"adj_i", con_tag:"stem_adj_base", detail:"(stem)"});
|
||||||
|
|
||||||
|
// TODO move these
|
||||||
|
// Forms based on the bare adjective stem
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"すぎる", dec_tag:"stem_adj_base", con_tag:"v1", detail:"excess"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"そう", dec_tag:"stem_adj_base", con_tag:"adj_na", detail:"seemingness"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"がる", dec_tag:"stem_adj_base", con_tag:"v5r", detail:"garu"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"さ", dec_tag:"stem_adj_base", con_tag:"n", detail:"noun form"});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// common forms
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
// rules.push({type: "stdrule", dec_end:"", con_end:"た", dec_tag:"stem_ren", con_tag:"stem_past", detail:"past"}); // unusual but real but don't necessarily want it yet
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"た", dec_tag:"stem_ren_less", con_tag:"stem_past", detail:"past"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"だ", dec_tag:"stem_ren_less_v", con_tag:"stem_past", detail:"past"});
|
||||||
|
//rules.push({type: "stdrule", dec_end:"", con_end:"て", dec_tag:"stem_ren", con_tag:"stem_te", detail:"(te form)"}); // unusual but real but don't necessarily want it yet
|
||||||
|
|
||||||
|
// we want some te forms to only apply to verbs, not adjectives
|
||||||
|
// FIXME: need a way to not break ~ないでください, ~ないでいく, etc
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"て", dec_tag:"stem_ren_less", con_tag:"stem_te_verbal", detail:"(te form)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"で", dec_tag:"stem_ren_less_v", con_tag:"stem_te_verbal", detail:"(te form)"});
|
||||||
|
// tag alias
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"", dec_tag:"stem_te_verbal", con_tag:"stem_te", detail:""});
|
||||||
|
// now the te form for adjectives
|
||||||
|
// adjectives have two te forms, one of which is not used synthetically
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"で", dec_tag:"adj_i", con_tag:"stem_te", detail:"(te form)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"で", dec_tag:"stem_ku", con_tag:"stem_te_defective", detail:"(te form)"});
|
||||||
|
|
||||||
|
// doesn't have anywhere else to go
|
||||||
|
rules.push({type: "rewriterule", dec_end:"です", con_end:"でした", dec_tag:"exp", con_tag:"stem_past", detail:"past"});
|
||||||
|
// TODO: add te form of です? or would it be too confusing to have?
|
||||||
|
// e.g. it would let people find "でしている" in "自分でしている" as です instead of で + conjugated する
|
||||||
|
|
||||||
|
// negatives
|
||||||
|
rules.push({type: "contextrule", contextrule: "adjspecial", dec_end:"", con_end:"ない", dec_tag:"stem_mizenkei", con_tag:"adj_i", detail:"negative"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"ん", dec_tag:"stem_a", con_tag:"adj_i", detail:"slurred negative"}); // causes problems with ichidan verbs but they can't conjugate to stem_a
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ず", dec_tag:"stem_mizenkei", con_tag:"uninflectable", detail:"adverbial negative"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ずに", dec_tag:"stem_mizenkei", con_tag:"uninflectable", detail:"without doing so"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ぬ", dec_tag:"stem_mizenkei", con_tag:"uninflectable", detail:"archaic negative"});
|
||||||
|
|
||||||
|
rules.push({type: "contextrule", contextrule: "adjspecial", dec_end:"", con_end:"ない", dec_tag:"stem_ku", con_tag:"adj_i", detail:"negative"});
|
||||||
|
|
||||||
|
// masu and its conjugations (allowing it to conjugate recursively causes problems because its grammar is unlike typical declarative verbs)
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ます", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"polite"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ません", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"negative polite"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ました", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"past polite"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"まして", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"te polite"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ませんでした", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"past negative polite"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ましょう", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"polite volitional"});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// conditional forms
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"たら", dec_tag:"stem_ren_less", con_tag:"uninflectable", detail:"conditional"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"だた", dec_tag:"stem_ren_less_v", con_tag:"uninflectable", detail:"conditional"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ったり", dec_tag:"stem_ka", con_tag:"uninflectable", detail:"conditional"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"たらば", dec_tag:"stem_ren_less", con_tag:"uninflectable", detail:"formal conditional"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"だたば", dec_tag:"stem_ren_less_v", con_tag:"uninflectable", detail:"formal conditional"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ったりば", dec_tag:"stem_ka", con_tag:"uninflectable", detail:"formal conditional"});
|
||||||
|
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"ば", dec_tag:"stem_e", con_tag:"uninflectable", detail:"provisional conditional"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"れば", dec_tag:"stem_ke", con_tag:"uninflectable", detail:"provisional conditional"});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// non-analytical forms
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
//passive and potential
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"る", dec_tag:"stem_e", con_tag:"v1", detail:"potential"}); // FIXME don't allow to attach to the short causative
|
||||||
|
// note: ichidan (i.e. v1) verbs cannot conjugate to stem_a
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"れる", dec_tag:"stem_a", con_tag:"v1", detail:"passive"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"る", con_end:"られる", dec_tag:"v1", con_tag:"v1", detail:"passive/potential"});
|
||||||
|
|
||||||
|
// causative
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"せる", dec_tag:"stem_a", con_tag:"v1", detail:"causative"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"る", con_end:"させる", dec_tag:"v1", con_tag:"v1", detail:"causative"});
|
||||||
|
rules.push({type: "contextrule", contextrule: "saspecial", dec_end:"", con_end:"す", dec_tag:"stem_a", con_tag:"v5s", detail:"short causative"});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// te-based forms
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
// mere te auxiliaries
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"しまう", dec_tag:"stem_te", con_tag:"v5u", detail:"completely/end up/perfect"});
|
||||||
|
// personal te auxiliaries
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"ください", dec_tag:"stem_te", con_tag:"adj_i", detail:"polite request"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"あげる", dec_tag:"stem_te", con_tag:"v5r", detail:"do for someone"});
|
||||||
|
// garmmatical aspect forms
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"いる", dec_tag:"stem_te", con_tag:"v1", detail:"teiru"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"おる", dec_tag:"stem_te", con_tag:"v5r", detail:"teoru"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"ある", dec_tag:"stem_te", con_tag:"v5r_i", detail:"tearu"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"いく", dec_tag:"stem_te", con_tag:"v5k_s", detail:"teiku"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"くる", dec_tag:"stem_te", con_tag:"vk", detail:"tekuru"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"おく", dec_tag:"stem_te", con_tag:"v5k", detail:"for now"});
|
||||||
|
// nonverbal functions of the te form
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"は", dec_tag:"stem_te", con_tag:"uninflectable", detail:"topic"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"は", dec_tag:"stem_te_defective", con_tag:"uninflectable", detail:"topic"});
|
||||||
|
// TODO: ても too?
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// ren'youkei based forms
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"なさい", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"kind request"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"な", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"casual kind request"});
|
||||||
|
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ながら", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"while"});
|
||||||
|
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"たり", dec_tag:"stem_ren_less", con_tag:"uninflectable", detail:"tari"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"だり", dec_tag:"stem_ren_less_v", con_tag:"uninflectable", detail:"tari"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ったり", dec_tag:"stem_ka", con_tag:"uninflectable", detail:"tari"});
|
||||||
|
|
||||||
|
rules.push({type: "contextrule", contextrule:"adjspecial", dec_end:"", con_end:"たい", dec_tag:"stem_ren", con_tag:"adj_i", detail:"want"});
|
||||||
|
|
||||||
|
rules.push({type: "stdrule", dec_end:"", con_end:"すぎる", dec_tag:"stem_ren", con_tag:"v1", detail:"too much"});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// transparent contractions
|
||||||
|
////////////////////
|
||||||
|
rules.push({type: "stdrule", dec_end:"てしまう", con_end:"ちゃう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"でしまう", con_end:"じゃう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"てしまう", con_end:"ちまう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"でしまう", con_end:"じまう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
||||||
|
|
||||||
|
rules.push({type: "stdrule", dec_end:"ては", con_end:"ちゃ", dec_tag:"stem_te", con_tag:"uninflectable", detail:"(contraction)"});
|
||||||
|
rules.push({type: "stdrule", dec_end:"では", con_end:"じゃ", dec_tag:"stem_te", con_tag:"uninflectable", detail:"(contraction)"});
|
||||||
|
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"ければ", con_end:"きゃ", dec_tag:"uninflectable", con_tag:"uninflectable", detail:"(contraction)"});
|
||||||
|
|
||||||
|
// other
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"v1", con_tag:"uninflectable", detail:"slurred"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"v5r", con_tag:"uninflectable", detail:"slurred"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"v5aru", con_tag:"uninflectable", detail:"slurred"});
|
||||||
|
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"vk", con_tag:"uninflectable", detail:"slurred"}); // FIXME: ?
|
||||||
|
|
||||||
|
// TODO: a bunch of missing contractions, vk, vs_i, v5aru, v4r,
|
||||||
|
|
||||||
|
//rules.push({type: "stdrule", dec_end:"", con_end:"たい", dec_tag:"stem_ren", con_tag:"adj_i", detail:"want"});
|
||||||
|
|
||||||
|
// FIXME implement un-deconjugation to show the actual reading of the deconjugated word - this is what furigana rules are for
|
||||||
|
|
||||||
|
// return deconjugated form if stdrule applies to form, return otherwise
|
||||||
|
function stdrule_deconjugate_inner(my_form, my_rule)
|
||||||
{
|
{
|
||||||
if (request.type == 'search')
|
// can't deconjugate nothingness
|
||||||
|
if(my_form.text == "")
|
||||||
|
return;
|
||||||
|
// ending doesn't match
|
||||||
|
if(!my_form.text.endsWith(my_rule.con_end))
|
||||||
|
return;
|
||||||
|
// deconjugated form too much longer than conjugated form
|
||||||
|
if(my_form.text.length > my_form.original_text.length+10)
|
||||||
|
return;
|
||||||
|
// impossibly information-dense
|
||||||
|
if(my_form.tags.length > my_form.original_text.length+6)
|
||||||
|
return;
|
||||||
|
// tag doesn't match
|
||||||
|
if(my_form.tags.length > 0 && my_form.tags[my_form.tags.length-1] != my_rule.con_tag)
|
||||||
{
|
{
|
||||||
sendResponse(search(request.text));
|
if(false)//my_rule.detail=="potential")
|
||||||
|
{
|
||||||
|
console.log("Returning from deconjugation: tag doesn't match");
|
||||||
|
console.log(my_form);
|
||||||
|
console.log(my_rule);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newtext = my_form.text.substring(0, my_form.text.length-my_rule.con_end.length)+my_rule.dec_end;
|
||||||
|
|
||||||
|
// I hate javascript reeeeeeeeeeeeeee
|
||||||
|
let newform = {};//new Object();
|
||||||
|
newform.text = newtext;
|
||||||
|
newform.original_text = my_form.original_text;
|
||||||
|
newform.tags = my_form.tags.slice();
|
||||||
|
newform.seentext = new Set([...my_form.seentext]);
|
||||||
|
newform.process = my_form.process.slice();
|
||||||
|
|
||||||
|
newform.text = newtext;
|
||||||
|
|
||||||
|
newform.process.push(my_rule.detail);
|
||||||
|
|
||||||
|
if(newform.tags.length == 0)
|
||||||
|
newform.tags.push(my_rule.con_tag);
|
||||||
|
newform.tags.push(my_rule.dec_tag);
|
||||||
|
|
||||||
|
if(newform.seentext.size == 0)
|
||||||
|
newform.seentext.add(my_form.text);
|
||||||
|
newform.seentext.add(newtext);
|
||||||
|
|
||||||
|
return newform;
|
||||||
|
};
|
||||||
|
function stdrule_deconjugate(my_form, my_rule)
|
||||||
|
{
|
||||||
|
let array = undefined;
|
||||||
|
// pick the first one that is an array
|
||||||
|
// FIXME: use minimum length for safety reasons? assert all arrays equal length?
|
||||||
|
if(Array.isArray(my_rule.dec_end))
|
||||||
|
array = my_rule.dec_end;
|
||||||
|
else if(Array.isArray(my_rule.con_end))
|
||||||
|
array = my_rule.con_end;
|
||||||
|
else if(Array.isArray(my_rule.dec_tag))
|
||||||
|
array = my_rule.dec_tag;
|
||||||
|
else if(Array.isArray(my_rule.con_tag))
|
||||||
|
array = my_rule.con_tag;
|
||||||
|
|
||||||
|
if(array == undefined)
|
||||||
|
return stdrule_deconjugate_inner(my_form, my_rule);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let collection = new Set();
|
||||||
|
for(let i = 0; i < array.length; i++)
|
||||||
|
{
|
||||||
|
let virtual_rule = {};
|
||||||
|
virtual_rule.type = my_rule.type;
|
||||||
|
|
||||||
|
let index_or_value = function (variable, index)
|
||||||
|
{
|
||||||
|
if(Array.isArray(variable))
|
||||||
|
return variable[index];
|
||||||
|
else
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual_rule.dec_end = index_or_value(my_rule.dec_end, i);
|
||||||
|
virtual_rule.con_end = index_or_value(my_rule.con_end, i);
|
||||||
|
virtual_rule.dec_tag = index_or_value(my_rule.dec_tag, i);
|
||||||
|
virtual_rule.con_tag = index_or_value(my_rule.con_tag, i);
|
||||||
|
virtual_rule.detail = my_rule.detail;
|
||||||
|
|
||||||
|
let ret = stdrule_deconjugate_inner(my_form, virtual_rule);
|
||||||
|
if(ret) collection.add(ret);
|
||||||
|
}
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function rewriterule_deconjugate(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(my_form.text != my_rule.con_end)
|
||||||
|
return;
|
||||||
|
return stdrule_deconjugate(my_form, my_rule);
|
||||||
|
};
|
||||||
|
function onlyfinalrule_deconjugate(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(my_form.tags.length != 0)
|
||||||
|
return;
|
||||||
|
return stdrule_deconjugate(my_form, my_rule);
|
||||||
|
};
|
||||||
|
function neverfinalrule_deconjugate(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(my_form.tags.length == 0)
|
||||||
|
return;
|
||||||
|
return stdrule_deconjugate(my_form, my_rule);
|
||||||
|
};
|
||||||
|
function contextrule_deconjugate(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(!context_functions[my_rule.contextrule](my_form, my_rule))
|
||||||
|
return;
|
||||||
|
return stdrule_deconjugate(my_form, my_rule);
|
||||||
|
};
|
||||||
|
|
||||||
|
let rule_functions = {
|
||||||
|
stdrule: stdrule_deconjugate,
|
||||||
|
rewriterule: rewriterule_deconjugate,
|
||||||
|
onlyfinalrule: onlyfinalrule_deconjugate,
|
||||||
|
neverfinalrule: neverfinalrule_deconjugate,
|
||||||
|
contextrule: contextrule_deconjugate,
|
||||||
|
};
|
||||||
|
|
||||||
|
function adjspecial_check(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(my_form.tags.length != 2) return true;
|
||||||
|
let my_tag = my_form.tags[my_form.tags.length-2];
|
||||||
|
if(my_tag == "stem_adj_base")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
function tetrap_check(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(my_form.tags.length < 2) return true;
|
||||||
|
let my_tag = my_form.tags[my_form.tags.length-2];
|
||||||
|
if(my_tag == "stem_te")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
function saspecial_check(my_form, my_rule)
|
||||||
|
{
|
||||||
|
if(my_form.text == "") return false;
|
||||||
|
if(!my_form.text.endsWith(my_rule.con_end)) return false;
|
||||||
|
let base_text = my_form.text.substring(0, my_form.text.length-my_rule.con_end.length);
|
||||||
|
if(base_text.endsWith("さ"))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
let context_functions = {
|
||||||
|
adjspecial: adjspecial_check,
|
||||||
|
tetrap: tetrap_check,
|
||||||
|
saspecial: saspecial_check,
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.union = function(setB)
|
||||||
|
{
|
||||||
|
let union = new Set(this);
|
||||||
|
for (let elem of setB)
|
||||||
|
union.add(elem);
|
||||||
|
return union;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a set of objects, each containing the "final form" of a series of deconjugations
|
||||||
|
// The majority of these objects will fail being compared to the dictionary forms
|
||||||
|
// The algorithm is a right-edge rule checker that finds all applicable series of rules.
|
||||||
|
// TODO: add all underlay rule types
|
||||||
|
function deconjugate(mytext)
|
||||||
|
{
|
||||||
|
let processed = new Set();
|
||||||
|
let novel = new Set();
|
||||||
|
|
||||||
|
let start_form = {text: mytext, original_text: mytext, tags: [], seentext: new Set(), process: [] };
|
||||||
|
novel.add(start_form);
|
||||||
|
|
||||||
|
while(novel.size > 0)
|
||||||
|
{
|
||||||
|
//print_object(novel);
|
||||||
|
let new_novel = new Set();
|
||||||
|
for(let form of novel)
|
||||||
|
{
|
||||||
|
for(let i = 0; i < rules.length; i++)
|
||||||
|
{
|
||||||
|
let rule = rules[i];
|
||||||
|
|
||||||
|
let newform = rule_functions[rule.type](form, rule);
|
||||||
|
|
||||||
|
if(newform != undefined && newform.constructor === Set)
|
||||||
|
{
|
||||||
|
for(let myform of newform)
|
||||||
|
{
|
||||||
|
if(myform != undefined && !processed.has(myform) && !novel.has(myform) && !new_novel.has(myform))
|
||||||
|
new_novel.add(myform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(newform != undefined && !processed.has(newform) && !novel.has(newform) && !new_novel.has(newform))
|
||||||
|
new_novel.add(newform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processed = processed.union(novel);
|
||||||
|
novel = new_novel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes deconjugated forms and looks them up in a dictionary
|
||||||
|
// building a list of all matches
|
||||||
|
function build_lookup_comb (forms)
|
||||||
|
{
|
||||||
|
// FIXME: dumpster fire that shouldn't be anywhere near as complicated as I made it
|
||||||
|
|
||||||
|
// This is the only part of this function that doesn't look like a garbage fire.
|
||||||
|
// Looks for dictionary definitions of each deconjugated form.
|
||||||
|
let looked_up = {};
|
||||||
|
for(let form of forms)
|
||||||
|
{
|
||||||
|
if(!looked_up.hasOwnProperty(form.text))
|
||||||
|
{
|
||||||
|
let result = search(form.text);
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
for(let r = 0; r < result.length; r++)
|
||||||
|
{
|
||||||
|
let entry = result[r];
|
||||||
|
entry.deconj = undefined; // clear if something set it before, we need this later
|
||||||
|
// store all the parts of speech that this dictionary entry can apply to
|
||||||
|
// normally, they're scattered across its senses
|
||||||
|
// FIXME: care about senses with restricted spellings when building part-of-speech tags list
|
||||||
|
entry.allpos = new Set();
|
||||||
|
for(let i = 0; i < entry.sense.length; i++)
|
||||||
|
{
|
||||||
|
let sense = entry.sense[i];
|
||||||
|
for(let j = 0; j < sense.pos.length; j++)
|
||||||
|
entry.allpos.add(sense.pos[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
looked_up[form.text] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: This is garbage.
|
||||||
|
// Add deconjugation field to all those entries
|
||||||
|
for(let form of forms)
|
||||||
|
{
|
||||||
|
if(looked_up.hasOwnProperty(form.text))
|
||||||
|
{
|
||||||
|
let result = looked_up[form.text];
|
||||||
|
for(let entry of result)
|
||||||
|
{
|
||||||
|
// If the form requires definition to have a particular POS tag, check for it
|
||||||
|
if(form.tags.length > 0)
|
||||||
|
{
|
||||||
|
if(entry.allpos.has(form.tags[form.tags.length-1]))
|
||||||
|
{
|
||||||
|
if(entry.deconj)
|
||||||
|
entry.deconj.add(form);
|
||||||
|
else
|
||||||
|
entry.deconj = new Set([form]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(entry.deconj)
|
||||||
|
entry.deconj.add(form);
|
||||||
|
else
|
||||||
|
entry.deconj = new Set([form]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: This should merge based on map from JMdict entity ID to entry.
|
||||||
|
// FIXME: Because it's theoretically possible to get the same definition from different spellings from different deconjugations of the same string.
|
||||||
|
// Make a list of each definition that has an associated deconjugation (even if it's a zero-depth deconjugation)
|
||||||
|
let merger = [];
|
||||||
|
for(let result of Object.values(looked_up))
|
||||||
|
{
|
||||||
|
for(let entry of result)
|
||||||
|
{
|
||||||
|
//console.log("testing A");
|
||||||
|
//print_object(entry);
|
||||||
|
if(entry.deconj)
|
||||||
|
merger.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//print_object(merger);
|
||||||
|
if(merger.length > 0)
|
||||||
|
return merger;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_lookup = "";
|
||||||
|
let last_time_lookup = Date.now();
|
||||||
|
|
||||||
|
function lookup_indirect(text, time)
|
||||||
|
{
|
||||||
|
if(text == "")
|
||||||
|
return;
|
||||||
|
//if(time < last_time_lookup+20) // reduces lag buildup
|
||||||
|
// return;
|
||||||
|
if(text == last_lookup)// && (exists_div()))// || time < last_time_lookup+100)) // helps reduce double-lookups
|
||||||
|
return;
|
||||||
|
last_lookup = text;
|
||||||
|
last_time_lookup = time;
|
||||||
|
|
||||||
|
// try to look up successively shorter substrings of text
|
||||||
|
// deconjugate() returns possible deconjugations, one of which has zero deconjugations, i.e. the plain text
|
||||||
|
// build_lookup_comb looks for dictionary definitions matching any deconjugation, returning a list of them
|
||||||
|
let forms = deconjugate(text);
|
||||||
|
let result = build_lookup_comb(forms);
|
||||||
|
while(result === undefined && text.length > 0)
|
||||||
|
{
|
||||||
|
//console.log("trying to look up " + text);
|
||||||
|
text = text.substring(0, text.length-1);
|
||||||
|
forms = deconjugate(text);
|
||||||
|
result = build_lookup_comb(forms);
|
||||||
|
}
|
||||||
|
if(result !== undefined)
|
||||||
|
{
|
||||||
|
//console.log("found lookup");
|
||||||
|
//console.log(text)
|
||||||
|
return {text:text, result:result};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//console.log("did not find lookup");
|
||||||
|
//console.log(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener((req, sender, sendResponse) =>
|
||||||
|
{
|
||||||
|
if (req.type == "search")
|
||||||
|
{
|
||||||
|
sendResponse(lookup_indirect(req.text, req.time));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+29
-621
@@ -3,9 +3,9 @@
|
|||||||
/*
|
/*
|
||||||
* TODO:
|
* TODO:
|
||||||
*
|
*
|
||||||
* ! Port all of Spark Reader's deconjugation rules https://github.com/wareya/Spark-Reader/blob/master/preferences/underlay https://github.com/wareya/Spark-Reader/tree/master/src/language/deconjugator
|
* ! Finish porting the underlay's deconjugation rules
|
||||||
|
* ! Definition priority handling (prefer words with any commonness tags, shorter deconjugations, expressions, non-archaic/non-obscure words, high frequencies)
|
||||||
* - Fix katakana-hiragana matching (only happens in lookups right now, not display generation)
|
* - Fix katakana-hiragana matching (only happens in lookups right now, not display generation)
|
||||||
* - Definition priority handling (prefer words with any commonness tags, shorter deconjugations, expressions, non-archaic/non-obscure words, high frequencies)
|
|
||||||
* - More configurability
|
* - More configurability
|
||||||
* - VNstats frequency data
|
* - VNstats frequency data
|
||||||
* - Load deconjugation rules from an advanced setting, with a reset button
|
* - Load deconjugation rules from an advanced setting, with a reset button
|
||||||
@@ -14,8 +14,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ~~~~ interesting stuff happens a few hundred lines down at stdrule_deconjugate(), get past the DOM-writing-related stuff ~~~~
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function print_object(message)
|
function print_object(message)
|
||||||
@@ -421,601 +419,32 @@ function build_div (text, result)
|
|||||||
return middle;
|
return middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// deconjugation rules
|
|
||||||
let rules = [];
|
|
||||||
|
|
||||||
// TODO: load rules from an underlay
|
let settings_reload_rate = 200;
|
||||||
|
let settings_reloader = undefined;
|
||||||
////////////////////
|
async function settings_reload()
|
||||||
// verb stems
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
// "e" stem used for potential and ba
|
|
||||||
rules.push({type: "neverfinalrule"
|
|
||||||
, dec_end:
|
|
||||||
["く","す","つ","う","る","る","ぐ","ぶ","ぬ","む","る","う","く"]
|
|
||||||
, con_end:
|
|
||||||
["け","せ","て","え","れ","れ","げ","べ","ね","め","れ","え","け"]
|
|
||||||
, dec_tag:
|
|
||||||
["v5k","v5s","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v1","v5u_s","v5k_s"]
|
|
||||||
, con_tag:"stem_e", detail:"(izenkei)"});
|
|
||||||
|
|
||||||
// true imperative
|
|
||||||
rules.push({type: "onlyfinalrule"
|
|
||||||
, dec_end:
|
|
||||||
["く","す","つ","う","る","る","ぐ","ぶ","ぬ","む","る","る","う","く"]
|
|
||||||
, con_end:
|
|
||||||
["け","せ","て","え","れ","れ","げ","べ","ね","め","ろ","よ","え","け"] // ichidan has two imperatives FIXME: don't let potential conjugate to よ
|
|
||||||
, dec_tag:
|
|
||||||
["v5k","v5s","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v1","v1","v5u_s","v5k_s"]
|
|
||||||
, con_tag:"uninflectable", detail:"imperative"});
|
|
||||||
|
|
||||||
// ~a stem
|
|
||||||
rules.push({type: "neverfinalrule"
|
|
||||||
, dec_end:
|
|
||||||
["く","す","つ","う","る","ぐ","ぶ","ぬ","む","う","く"]
|
|
||||||
, con_end:
|
|
||||||
["か","せ","て","わ","ら","が","ば","な","ま","わ","か"]
|
|
||||||
, dec_tag:
|
|
||||||
["v5k","v5s","v5t","v5u","v5r","v5g","v5b","v5n","v5m","v5u_s","v5k_s"] // TODO: support あらへん, あらぬ, etc
|
|
||||||
, con_tag:"stem_a", detail:"('a' stem)"});
|
|
||||||
|
|
||||||
// unvoiced past stems
|
|
||||||
rules.push({type: "neverfinalrule"
|
|
||||||
, dec_end:
|
|
||||||
["く","す","つ","う","る","る","る","う","く"]
|
|
||||||
, con_end:
|
|
||||||
["い","し","っ","っ","っ","っ","","う","っ"]
|
|
||||||
, dec_tag:
|
|
||||||
["v5k","v5s","v5t","v5u","v5r","v5r-i","v1","v5u_s","v5k_s"]
|
|
||||||
, con_tag:"stem_ren_less", detail:"(unstressed infinitive)"});
|
|
||||||
// voiced past stems
|
|
||||||
rules.push({type: "neverfinalrule"
|
|
||||||
, dec_end:
|
|
||||||
["ぐ","ぶ","ぬ","む"]
|
|
||||||
, con_end:
|
|
||||||
["い","ん","ん","ん"]
|
|
||||||
, dec_tag:
|
|
||||||
["v5g","v5b","v5n","v5m"]
|
|
||||||
, con_tag:"stem_ren_less_v", detail:"(unstressed infinitive)"});
|
|
||||||
|
|
||||||
// infinitives (ren'youkei) that are different than the corresponding past stem
|
|
||||||
rules.push({type: "stdrule"
|
|
||||||
, dec_end:
|
|
||||||
["く","つ","う","る","る","ぐ","ぶ","ぬ","む","う","く"]
|
|
||||||
, con_end:
|
|
||||||
["き","ち","い","り","り","ぎ","び","に","み","い","き"]
|
|
||||||
, dec_tag:
|
|
||||||
["v5k","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v5u_s","v5k_s"]
|
|
||||||
, con_tag:"stem_ren", detail:"(infinitive)"});
|
|
||||||
// ones that need the te trap
|
|
||||||
rules.push({type: "contextrule", contextrule:"tetrap"
|
|
||||||
, dec_end:
|
|
||||||
["す","る"]
|
|
||||||
, con_end:
|
|
||||||
["し",""]
|
|
||||||
, dec_tag:
|
|
||||||
["v5s","v1"]
|
|
||||||
, con_tag:"stem_ren", detail:"(infinitive)"});
|
|
||||||
|
|
||||||
// stem for negatives proper
|
|
||||||
rules.push({type: "neverfinalrule"
|
|
||||||
, dec_end:
|
|
||||||
["","る"]
|
|
||||||
, con_end:
|
|
||||||
["",""]
|
|
||||||
, dec_tag:
|
|
||||||
["stem_a","v1"]
|
|
||||||
, con_tag:"stem_mizenkei", detail:"(mizenkei)"});
|
|
||||||
|
|
||||||
// ~a stem
|
|
||||||
rules.push({type: "stdrule"
|
|
||||||
, dec_end:
|
|
||||||
["く","す","つ","う","る","る","ぐ","ぶ","ぬ","む","る","う","く"]
|
|
||||||
, con_end:
|
|
||||||
["こう","そう","とう","おう","ろう","ろう","ごう","ぼう","のう","もう","よう","おう","こう"]
|
|
||||||
, dec_tag:
|
|
||||||
["v5k","v5s","v5t","v5u","v5r","v5r-i","v5g","v5b","v5n","v5m","v1","v5u_s","v5k_s"]
|
|
||||||
, con_tag:"form_volition", detail:"volitional"});
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// adjective stems
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
rules.push({type: "stdrule", dec_end:"い", con_end:"く", dec_tag:"adj_i", con_tag:"stem_ku", detail:"(adverbial stem)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"い", con_end:"か", dec_tag:"adj_i", con_tag:"stek_ka", detail:"(ka stem)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"い", con_end:"け", dec_tag:"adj_i", con_tag:"stek_ke", detail:"(ke stem)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"い", con_end:"", dec_tag:"adj_i", con_tag:"stem_adj_base", detail:"(stem)"});
|
|
||||||
|
|
||||||
// TODO move these
|
|
||||||
// Forms based on the bare adjective stem
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"すぎる", dec_tag:"stem_adj_base", con_tag:"v1", detail:"excess"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"そう", dec_tag:"stem_adj_base", con_tag:"adj_na", detail:"seemingness"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"がる", dec_tag:"stem_adj_base", con_tag:"v5r", detail:"garu"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"さ", dec_tag:"stem_adj_base", con_tag:"n", detail:"noun form"});
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// common forms
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
// rules.push({type: "stdrule", dec_end:"", con_end:"た", dec_tag:"stem_ren", con_tag:"stem_past", detail:"past"}); // unusual but real but don't necessarily want it yet
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"た", dec_tag:"stem_ren_less", con_tag:"stem_past", detail:"past"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"だ", dec_tag:"stem_ren_less_v", con_tag:"stem_past", detail:"past"});
|
|
||||||
//rules.push({type: "stdrule", dec_end:"", con_end:"て", dec_tag:"stem_ren", con_tag:"stem_te", detail:"(te form)"}); // unusual but real but don't necessarily want it yet
|
|
||||||
|
|
||||||
// we want some te forms to only apply to verbs, not adjectives
|
|
||||||
// FIXME: need a way to not break ~ないでください, ~ないでいく, etc
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"て", dec_tag:"stem_ren_less", con_tag:"stem_te_verbal", detail:"(te form)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"で", dec_tag:"stem_ren_less_v", con_tag:"stem_te_verbal", detail:"(te form)"});
|
|
||||||
// tag alias
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"", dec_tag:"stem_te_verbal", con_tag:"stem_te", detail:""});
|
|
||||||
// now the te form for adjectives
|
|
||||||
// adjectives have two te forms, one of which is not used synthetically
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"で", dec_tag:"adj_i", con_tag:"stem_te", detail:"(te form)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"で", dec_tag:"stem_ku", con_tag:"stem_te_defective", detail:"(te form)"});
|
|
||||||
|
|
||||||
// doesn't have anywhere else to go
|
|
||||||
rules.push({type: "rewriterule", dec_end:"です", con_end:"でした", dec_tag:"exp", con_tag:"stem_past", detail:"past"});
|
|
||||||
// TODO: add te form of です? or would it be too confusing to have?
|
|
||||||
// e.g. it would let people find "でしている" in "自分でしている" as です instead of で + conjugated する
|
|
||||||
|
|
||||||
// negatives
|
|
||||||
rules.push({type: "contextrule", contextrule: "adjspecial", dec_end:"", con_end:"ない", dec_tag:"stem_mizenkei", con_tag:"adj_i", detail:"negative"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"ん", dec_tag:"stem_a", con_tag:"adj_i", detail:"slurred negative"}); // causes problems with ichidan verbs but they can't conjugate to stem_a
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ず", dec_tag:"stem_mizenkei", con_tag:"uninflectable", detail:"adverbial negative"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ずに", dec_tag:"stem_mizenkei", con_tag:"uninflectable", detail:"without doing so"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ぬ", dec_tag:"stem_mizenkei", con_tag:"uninflectable", detail:"archaic negative"});
|
|
||||||
|
|
||||||
rules.push({type: "contextrule", contextrule: "adjspecial", dec_end:"", con_end:"ない", dec_tag:"stem_ku", con_tag:"adj_i", detail:"negative"});
|
|
||||||
|
|
||||||
// masu and its conjugations (allowing it to conjugate recursively causes problems because its grammar is unlike typical declarative verbs)
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ます", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"polite"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ません", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"negative polite"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ました", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"past polite"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"まして", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"te polite"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ませんでした", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"past negative polite"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ましょう", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"polite volitional"});
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// conditional forms
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"たら", dec_tag:"stem_ren_less", con_tag:"uninflectable", detail:"conditional"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"だた", dec_tag:"stem_ren_less_v", con_tag:"uninflectable", detail:"conditional"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ったり", dec_tag:"stem_ka", con_tag:"uninflectable", detail:"conditional"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"たらば", dec_tag:"stem_ren_less", con_tag:"uninflectable", detail:"formal conditional"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"だたば", dec_tag:"stem_ren_less_v", con_tag:"uninflectable", detail:"formal conditional"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ったりば", dec_tag:"stem_ka", con_tag:"uninflectable", detail:"formal conditional"});
|
|
||||||
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"ば", dec_tag:"stem_e", con_tag:"uninflectable", detail:"provisional conditional"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"れば", dec_tag:"stem_ke", con_tag:"uninflectable", detail:"provisional conditional"});
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// non-analytical forms
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
//passive and potential
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"る", dec_tag:"stem_e", con_tag:"v1", detail:"potential"});
|
|
||||||
// note: ichidan (i.e. v1) verbs cannot conjugate to stem_a
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"れる", dec_tag:"stem_a", con_tag:"v1", detail:"passive"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"る", con_end:"られる", dec_tag:"v1", con_tag:"v1", detail:"passive/potential"});
|
|
||||||
|
|
||||||
// causative
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"せる", dec_tag:"stem_a", con_tag:"v1", detail:"causative"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"る", con_end:"させる", dec_tag:"v1", con_tag:"v1", detail:"causative"});
|
|
||||||
rules.push({type: "contextrule", contextrule: "saspecial", dec_end:"", con_end:"す", dec_tag:"stem_a", con_tag:"v5s", detail:"short causative"});
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// te-based forms
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
// mere te auxiliaries
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"しまう", dec_tag:"stem_te", con_tag:"v5u", detail:"completely"});
|
|
||||||
// personal te auxiliaries
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"ください", dec_tag:"stem_te", con_tag:"adj_i", detail:"polite request"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"あげる", dec_tag:"stem_te", con_tag:"v5r", detail:"do for someone"});
|
|
||||||
// garmmatical aspect forms
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"いる", dec_tag:"stem_te", con_tag:"v1", detail:"teiru"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"おる", dec_tag:"stem_te", con_tag:"v5r", detail:"teoru"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"ある", dec_tag:"stem_te", con_tag:"v5r_i", detail:"tearu"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"いく", dec_tag:"stem_te", con_tag:"v5k_s", detail:"teiku"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"くる", dec_tag:"stem_te", con_tag:"vk", detail:"tekuru"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"おく", dec_tag:"stem_te", con_tag:"v5k", detail:"for now"});
|
|
||||||
// nonverbal functions of the te form
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"は", dec_tag:"stem_te", con_tag:"uninflectable", detail:"topic"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"は", dec_tag:"stem_te_defective", con_tag:"uninflectable", detail:"topic"});
|
|
||||||
// TODO: ても too?
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// ren'youkei based forms
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"なさい", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"kind request"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"な", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"casual kind request"});
|
|
||||||
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ながら", dec_tag:"stem_ren", con_tag:"uninflectable", detail:"while"});
|
|
||||||
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"たり", dec_tag:"stem_ren_less", con_tag:"uninflectable", detail:"tari"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"だり", dec_tag:"stem_ren_less_v", con_tag:"uninflectable", detail:"tari"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"", con_end:"ったり", dec_tag:"stem_ka", con_tag:"uninflectable", detail:"tari"});
|
|
||||||
|
|
||||||
rules.push({type: "contextrule", contextrule:"adjspecial", dec_end:"", con_end:"たい", dec_tag:"stem_ren", con_tag:"adj_i", detail:"want"});
|
|
||||||
|
|
||||||
rules.push({type: "stdrule", dec_end:"", con_end:"すぎる", dec_tag:"stem_ren", con_tag:"v1", detail:"too much"});
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// transparent contractions
|
|
||||||
////////////////////
|
|
||||||
rules.push({type: "stdrule", dec_end:"てしまう", con_end:"ちゃう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"でしまう", con_end:"じゃう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"てしまう", con_end:"ちまう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"でしまう", con_end:"じまう", dec_tag:"v5u", con_tag:"v5u", detail:"(contraction)"});
|
|
||||||
|
|
||||||
rules.push({type: "stdrule", dec_end:"ては", con_end:"ちゃ", dec_tag:"stem_te", con_tag:"uninflectable", detail:"(contraction)"});
|
|
||||||
rules.push({type: "stdrule", dec_end:"では", con_end:"じゃ", dec_tag:"stem_te", con_tag:"uninflectable", detail:"(contraction)"});
|
|
||||||
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"ければ", con_end:"きゃ", dec_tag:"uninflectable", con_tag:"uninflectable", detail:"(contraction)"});
|
|
||||||
|
|
||||||
// other
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"v1", con_tag:"uninflectable", detail:"slurred"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"v5r", con_tag:"uninflectable", detail:"slurred"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"v5aru", con_tag:"uninflectable", detail:"slurred"});
|
|
||||||
rules.push({type: "onlyfinalrule", dec_end:"る", con_end:"ん", dec_tag:"vk", con_tag:"uninflectable", detail:"slurred"}); // FIXME: ?
|
|
||||||
|
|
||||||
// TODO: a bunch of missing contractions, vk, vs_i, v5aru, v4r,
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//rules.push({type: "stdrule", dec_end:"", con_end:"たい", dec_tag:"stem_ren", con_tag:"adj_i", detail:"want"});
|
|
||||||
|
|
||||||
// FIXME implement un-deconjugation to show the actual reading of the deconjugated word - this is what furigana rules are for
|
|
||||||
|
|
||||||
// return deconjugated form if stdrule applies to form, return otherwise
|
|
||||||
function stdrule_deconjugate_inner(my_form, my_rule)
|
|
||||||
{
|
{
|
||||||
// can't deconjugate nothingness
|
try
|
||||||
if(my_form.text == "")
|
|
||||||
return;
|
|
||||||
// ending doesn't match
|
|
||||||
if(!my_form.text.endsWith(my_rule.con_end))
|
|
||||||
return;
|
|
||||||
// deconjugated form too much longer than conjugated form
|
|
||||||
if(my_form.text.length > my_form.original_text.length+10)
|
|
||||||
return;
|
|
||||||
// impossibly information-dense
|
|
||||||
if(my_form.tags.length > my_form.original_text.length+6)
|
|
||||||
return;
|
|
||||||
// tag doesn't match
|
|
||||||
if(my_form.tags.length > 0 && my_form.tags[my_form.tags.length-1] != my_rule.con_tag)
|
|
||||||
{
|
{
|
||||||
if(false)//my_rule.detail=="potential")
|
settings.enabled = (await browser.storage.local.get("enabled")).enabled;
|
||||||
{
|
if(settings.enabled == undefined)
|
||||||
console.log("Returning from deconjugation: tag doesn't match");
|
settings.enabled = false;
|
||||||
console.log(my_form);
|
settings.compact = (await browser.storage.local.get("compact")).compact;
|
||||||
console.log(my_rule);
|
if(settings.compact == undefined)
|
||||||
}
|
settings.compact = true;
|
||||||
return;
|
//console.log("set settings");
|
||||||
}
|
//console.log(settings.enabled);
|
||||||
|
//console.log(settings.compact);
|
||||||
let newtext = my_form.text.substring(0, my_form.text.length-my_rule.con_end.length)+my_rule.dec_end;
|
|
||||||
|
|
||||||
// I hate javascript reeeeeeeeeeeeeee
|
|
||||||
let newform = {};//new Object();
|
|
||||||
newform.text = newtext;
|
|
||||||
newform.original_text = my_form.original_text;
|
|
||||||
newform.tags = my_form.tags.slice();
|
|
||||||
newform.seentext = new Set([...my_form.seentext]);
|
|
||||||
newform.process = my_form.process.slice();
|
|
||||||
|
|
||||||
newform.text = newtext;
|
|
||||||
|
|
||||||
newform.process.push(my_rule.detail);
|
|
||||||
|
|
||||||
if(newform.tags.length == 0)
|
|
||||||
newform.tags.push(my_rule.con_tag);
|
|
||||||
newform.tags.push(my_rule.dec_tag);
|
|
||||||
|
|
||||||
if(newform.seentext.size == 0)
|
|
||||||
newform.seentext.add(my_form.text);
|
|
||||||
newform.seentext.add(newtext);
|
|
||||||
|
|
||||||
return newform;
|
|
||||||
};
|
|
||||||
function stdrule_deconjugate(my_form, my_rule)
|
|
||||||
{
|
|
||||||
let array = undefined;
|
|
||||||
// pick the first one that is an array
|
|
||||||
// FIXME: use minimum length for safety reasons? assert all arrays equal length?
|
|
||||||
if(Array.isArray(my_rule.dec_end))
|
|
||||||
array = my_rule.dec_end;
|
|
||||||
else if(Array.isArray(my_rule.con_end))
|
|
||||||
array = my_rule.con_end;
|
|
||||||
else if(Array.isArray(my_rule.dec_tag))
|
|
||||||
array = my_rule.dec_tag;
|
|
||||||
else if(Array.isArray(my_rule.con_tag))
|
|
||||||
array = my_rule.con_tag;
|
|
||||||
|
|
||||||
if(array == undefined)
|
|
||||||
return stdrule_deconjugate_inner(my_form, my_rule);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
let collection = new Set();
|
|
||||||
for(let i = 0; i < array.length; i++)
|
|
||||||
{
|
|
||||||
let virtual_rule = {};
|
|
||||||
virtual_rule.type = my_rule.type;
|
|
||||||
|
|
||||||
let index_or_value = function (variable, index)
|
|
||||||
{
|
|
||||||
if(Array.isArray(variable))
|
|
||||||
return variable[index];
|
|
||||||
else
|
|
||||||
return variable;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual_rule.dec_end = index_or_value(my_rule.dec_end, i);
|
|
||||||
virtual_rule.con_end = index_or_value(my_rule.con_end, i);
|
|
||||||
virtual_rule.dec_tag = index_or_value(my_rule.dec_tag, i);
|
|
||||||
virtual_rule.con_tag = index_or_value(my_rule.con_tag, i);
|
|
||||||
virtual_rule.detail = my_rule.detail;
|
|
||||||
|
|
||||||
let ret = stdrule_deconjugate_inner(my_form, virtual_rule);
|
|
||||||
if(ret) collection.add(ret);
|
|
||||||
}
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function rewriterule_deconjugate(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(my_form.text != my_rule.con_end)
|
|
||||||
return;
|
|
||||||
return stdrule_deconjugate(my_form, my_rule);
|
|
||||||
};
|
|
||||||
function onlyfinalrule_deconjugate(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(my_form.tags.length != 0)
|
|
||||||
return;
|
|
||||||
return stdrule_deconjugate(my_form, my_rule);
|
|
||||||
};
|
|
||||||
function neverfinalrule_deconjugate(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(my_form.tags.length == 0)
|
|
||||||
return;
|
|
||||||
return stdrule_deconjugate(my_form, my_rule);
|
|
||||||
};
|
|
||||||
function contextrule_deconjugate(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(!context_functions[my_rule.contextrule](my_form, my_rule))
|
|
||||||
return;
|
|
||||||
return stdrule_deconjugate(my_form, my_rule);
|
|
||||||
};
|
|
||||||
|
|
||||||
let rule_functions = {
|
|
||||||
stdrule: stdrule_deconjugate,
|
|
||||||
rewriterule: rewriterule_deconjugate,
|
|
||||||
onlyfinalrule: onlyfinalrule_deconjugate,
|
|
||||||
neverfinalrule: neverfinalrule_deconjugate,
|
|
||||||
contextrule: contextrule_deconjugate,
|
|
||||||
};
|
|
||||||
|
|
||||||
function adjspecial_check(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(my_form.tags.length != 2) return true;
|
|
||||||
let my_tag = my_form.tags[my_form.tags.length-2];
|
|
||||||
if(my_tag == "stem_adj_base")
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
function tetrap_check(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(my_form.tags.length < 2) return true;
|
|
||||||
let my_tag = my_form.tags[my_form.tags.length-2];
|
|
||||||
if(my_tag == "stem_te")
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
function saspecial_check(my_form, my_rule)
|
|
||||||
{
|
|
||||||
if(my_form.text == "") return false;
|
|
||||||
if(!my_form.text.endsWith(my_rule.con_end)) return false;
|
|
||||||
let base_text = my_form.text.substring(0, my_form.text.length-my_rule.con_end.length);
|
|
||||||
if(base_text.endsWith("さ"))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
let context_functions = {
|
|
||||||
adjspecial: adjspecial_check,
|
|
||||||
tetrap: tetrap_check,
|
|
||||||
saspecial: saspecial_check,
|
|
||||||
};
|
|
||||||
|
|
||||||
Set.prototype.union = function(setB)
|
|
||||||
{
|
|
||||||
let union = new Set(this);
|
|
||||||
for (let elem of setB)
|
|
||||||
union.add(elem);
|
|
||||||
return union;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a set of objects, each containing the "final form" of a series of deconjugations
|
|
||||||
// The majority of these objects will fail being compared to the dictionary forms
|
|
||||||
// The algorithm is a right-edge rule checker that finds all applicable series of rules.
|
|
||||||
// TODO: add all underlay rule types
|
|
||||||
function deconjugate(mytext)
|
|
||||||
{
|
|
||||||
let processed = new Set();
|
|
||||||
let novel = new Set();
|
|
||||||
|
|
||||||
let start_form = {text: mytext, original_text: mytext, tags: [], seentext: new Set(), process: [] };
|
|
||||||
novel.add(start_form);
|
|
||||||
|
|
||||||
while(novel.size > 0)
|
|
||||||
{
|
|
||||||
//print_object(novel);
|
|
||||||
let new_novel = new Set();
|
|
||||||
for(let form of novel)
|
|
||||||
{
|
|
||||||
for(let i = 0; i < rules.length; i++)
|
|
||||||
{
|
|
||||||
let rule = rules[i];
|
|
||||||
|
|
||||||
let newform = rule_functions[rule.type](form, rule);
|
|
||||||
|
|
||||||
if(newform != undefined && newform.constructor === Set)
|
|
||||||
{
|
|
||||||
for(let myform of newform)
|
|
||||||
{
|
|
||||||
if(myform != undefined && !processed.has(myform) && !novel.has(myform) && !new_novel.has(myform))
|
|
||||||
new_novel.add(myform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(newform != undefined && !processed.has(newform) && !novel.has(newform) && !new_novel.has(newform))
|
|
||||||
new_novel.add(newform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processed = processed.union(novel);
|
|
||||||
novel = new_novel;
|
|
||||||
}
|
|
||||||
|
|
||||||
return processed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ask background thread for a list of definitions
|
|
||||||
async function lookup_word(text)
|
|
||||||
{
|
|
||||||
return browser.runtime.sendMessage({type: "search", text: text});
|
|
||||||
}
|
|
||||||
|
|
||||||
// takes deconjugated forms and looks them up in a dictionary
|
|
||||||
// building a list of all matches
|
|
||||||
async function build_lookup_comb (forms)
|
|
||||||
{
|
|
||||||
// FIXME: dumpster fire that shouldn't be anywhere near as complicated as I made it
|
|
||||||
|
|
||||||
// This is the only part of this function that doesn't look like a garbage fire.
|
|
||||||
// Looks for dictionary definitions of each deconjugated form.
|
|
||||||
let looked_up = {};
|
|
||||||
for(let form of forms)
|
|
||||||
{
|
|
||||||
if(!looked_up.hasOwnProperty(form.text))
|
|
||||||
{
|
|
||||||
let result = await lookup_word(form.text);
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
for(let r = 0; r < result.length; r++)
|
|
||||||
{
|
|
||||||
let entry = result[r];
|
|
||||||
entry.deconj = undefined; // clear if something set it before, we need this later
|
|
||||||
// store all the parts of speech that this dictionary entry can apply to
|
|
||||||
// normally, they're scattered across its senses
|
|
||||||
// FIXME: care about senses with restricted spellings when building part-of-speech tags list
|
|
||||||
entry.allpos = new Set();
|
|
||||||
for(let i = 0; i < entry.sense.length; i++)
|
|
||||||
{
|
|
||||||
let sense = entry.sense[i];
|
|
||||||
for(let j = 0; j < sense.pos.length; j++)
|
|
||||||
entry.allpos.add(sense.pos[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
looked_up[form.text] = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// FIXME: This is garbage.
|
|
||||||
// Add deconjugation field to all those entries
|
|
||||||
for(let form of forms)
|
|
||||||
{
|
|
||||||
if(looked_up.hasOwnProperty(form.text))
|
|
||||||
{
|
|
||||||
let result = looked_up[form.text];
|
|
||||||
for(let entry of result)
|
|
||||||
{
|
|
||||||
// If the form requires definition to have a particular POS tag, check for it
|
|
||||||
if(form.tags.length > 0)
|
|
||||||
{
|
|
||||||
if(entry.allpos.has(form.tags[form.tags.length-1]))
|
|
||||||
{
|
|
||||||
if(entry.deconj)
|
|
||||||
entry.deconj.add(form);
|
|
||||||
else
|
|
||||||
entry.deconj = new Set([form]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(entry.deconj)
|
|
||||||
entry.deconj.add(form);
|
|
||||||
else
|
|
||||||
entry.deconj = new Set([form]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// FIXME: This should merge based on map from JMdict entity ID to entry.
|
|
||||||
// FIXME: Because it's theoretically possible to get the same definition from different spellings from different deconjugations of the same string.
|
|
||||||
// Make a list of each definition that has an associated deconjugation (even if it's a zero-depth deconjugation)
|
|
||||||
let merger = [];
|
|
||||||
for(let result of Object.values(looked_up))
|
|
||||||
{
|
|
||||||
for(let entry of result)
|
|
||||||
{
|
|
||||||
//console.log("testing A");
|
|
||||||
//print_object(entry);
|
|
||||||
if(entry.deconj)
|
|
||||||
merger.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//print_object(merger);
|
|
||||||
if(merger.length > 0)
|
|
||||||
return merger;
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let last_lookup = "";
|
|
||||||
let last_time_lookup = Date.now();
|
|
||||||
|
|
||||||
// FIXME: Use a queue of lookups to look for or something. This is really crappy.
|
|
||||||
// FIXME: Because we want to skip every lookup except the most recent one, and never run lookups more than once at the same "time".
|
|
||||||
async function lookup_indirect (text, x, y, x2, y2, time)
|
|
||||||
{
|
|
||||||
if(text == "")
|
|
||||||
return;
|
|
||||||
//if(time < last_time_lookup+20) // reduces lag buildup
|
|
||||||
// return;
|
|
||||||
if(text == last_lookup && (exists_div()))// || time < last_time_lookup+100)) // helps reduce double-lookups
|
|
||||||
return;
|
|
||||||
last_lookup = text;
|
|
||||||
last_time_lookup = time;
|
|
||||||
|
|
||||||
// try to look up successively shorter substrings of text
|
|
||||||
// deconjugate() returns possible deconjugations, one of which has zero deconjugations, i.e. the plain text
|
|
||||||
// build_lookup_comb looks for dictionary definitions matching any deconjugation, returning a list of them
|
|
||||||
let forms = deconjugate(text);
|
|
||||||
let result = await build_lookup_comb(forms);
|
|
||||||
while(result === undefined && text.length > 0)
|
|
||||||
{
|
|
||||||
//console.log("trying to look up " + text);
|
|
||||||
text = text.substring(0, text.length-1);
|
|
||||||
forms = deconjugate(text);
|
|
||||||
result = await build_lookup_comb(forms);
|
|
||||||
}
|
|
||||||
if(result !== undefined)
|
|
||||||
{
|
|
||||||
//console.log("found lookup");
|
|
||||||
//console.log(text)
|
|
||||||
let mydiv = build_div(text, result);
|
|
||||||
if(mydiv)
|
|
||||||
display_div(mydiv, x2, y2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//console.log("did not find lookup");
|
|
||||||
//console.log(text);
|
|
||||||
}
|
}
|
||||||
|
catch(error)
|
||||||
|
{
|
||||||
|
console.log("failed to set settings, maybe not stored yet?");
|
||||||
|
} // not stored yet, probably
|
||||||
|
|
||||||
|
settings_reloader = setTimeout(settings_reload, settings_reload_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings_reloader = setTimeout(settings_reload, settings_reload_rate);
|
||||||
|
|
||||||
// look up words on a timer loop that only uses the most recent lookup request and ignores all the others
|
// look up words on a timer loop that only uses the most recent lookup request and ignores all the others
|
||||||
|
|
||||||
@@ -1035,7 +464,13 @@ async function lookup_loop()
|
|||||||
//console.log("queue not empty");
|
//console.log("queue not empty");
|
||||||
let lookup = lookup_queue.pop();
|
let lookup = lookup_queue.pop();
|
||||||
lookup_queue = [];
|
lookup_queue = [];
|
||||||
await lookup_indirect(lookup[0], lookup[1], lookup[2], lookup[3], lookup[4], Date.now());
|
let response = await browser.runtime.sendMessage({type:"search", text:lookup[0], time:Date.now()});
|
||||||
|
if(response)
|
||||||
|
{
|
||||||
|
let mydiv = build_div(response.text, response.result);
|
||||||
|
if(mydiv)
|
||||||
|
display_div(mydiv, lookup[3], lookup[4]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let t_end = Date.now();
|
let t_end = Date.now();
|
||||||
let t_to_wait = lookup_rate - (t_end - t_start);
|
let t_to_wait = lookup_rate - (t_end - t_start);
|
||||||
@@ -1071,33 +506,6 @@ function lookup_cancel()
|
|||||||
delete_div();
|
delete_div();
|
||||||
}
|
}
|
||||||
|
|
||||||
let settings_reload_rate = 200;
|
|
||||||
let settings_reloader = undefined;
|
|
||||||
async function settings_reload()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
settings.enabled = (await browser.storage.local.get("enabled")).enabled;
|
|
||||||
if(settings.enabled == undefined)
|
|
||||||
settings.enabled = false;
|
|
||||||
settings.compact = (await browser.storage.local.get("compact")).compact;
|
|
||||||
if(settings.compact == undefined)
|
|
||||||
settings.compact = true;
|
|
||||||
//console.log("set settings");
|
|
||||||
//console.log(settings.enabled);
|
|
||||||
//console.log(settings.compact);
|
|
||||||
}
|
|
||||||
catch(error)
|
|
||||||
{
|
|
||||||
console.log("failed to set settings, maybe not stored yet?");
|
|
||||||
} // not stored yet, probably
|
|
||||||
|
|
||||||
settings_reloader = setTimeout(settings_reload, settings_reload_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
settings_reloader = setTimeout(settings_reload, settings_reload_rate);
|
|
||||||
|
|
||||||
|
|
||||||
let max_search_len = 25;
|
let max_search_len = 25;
|
||||||
let time_of_last = Date.now();
|
let time_of_last = Date.now();
|
||||||
let throttle = 8;
|
let throttle = 8;
|
||||||
|
|||||||
Reference in new issue
Block a user