phrase builder working better
This commit is contained in:
parent
10f78df818
commit
1bf14eb44f
|
@ -3,28 +3,30 @@ import NPPicker from "../np-picker/NPPicker";
|
||||||
import VerbPicker from "../VerbPicker";
|
import VerbPicker from "../VerbPicker";
|
||||||
import VPDisplay from "./VPDisplay";
|
import VPDisplay from "./VPDisplay";
|
||||||
import ObjectDisplay from "./ObjectDisplay";
|
import ObjectDisplay from "./ObjectDisplay";
|
||||||
import { verbs } from "../../words/words";
|
import { verbs as verbsRaw } from "../../words/words";
|
||||||
import {
|
import {
|
||||||
isInvalidSubjObjCombo,
|
isInvalidSubjObjCombo,
|
||||||
} from "../../lib/np-tools";
|
} from "../../lib/np-tools";
|
||||||
|
|
||||||
function verbPhraseComplete({ subject, verb, shrinkServant }: { subject: NPSelection | undefined, verb: VerbSelection | undefined, shrinkServant: boolean }): VPSelection | undefined {
|
const verbs = verbsRaw.filter(v => !v.entry.c?.includes("gramm."))
|
||||||
|
|
||||||
|
function verbPhraseComplete({ subject, verb }: { subject: NPSelection | undefined, verb: VerbSelection | undefined }): VPSelection | undefined {
|
||||||
if (!subject) return undefined;
|
if (!subject) return undefined;
|
||||||
if (!verb) return undefined;
|
if (!verb) return undefined;
|
||||||
if (verb.object === undefined) return undefined;
|
if (verb.object === undefined) return undefined;
|
||||||
return {
|
return {
|
||||||
type: "VPSelection",
|
type: "VPSelection",
|
||||||
shrinkServant,
|
|
||||||
subject,
|
subject,
|
||||||
object: verb.object,
|
object: verb.object,
|
||||||
verb,
|
verb,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: BIG ISSUE, IF YOU OPEN THE OBJECT PRONOUN BOX AND IT CONFLICTS WITH THE SUBJECT
|
||||||
|
// IT CAN SAY THE COMBO IS NOT ALLOWED AND SHOW SOMETHING BLANK
|
||||||
export function PhraseBuilder() {
|
export function PhraseBuilder() {
|
||||||
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
||||||
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
||||||
const [shrinkServant, setShrinkServant] = useState<boolean>(false);
|
|
||||||
function handleSubjectChange(subject: NPSelection | undefined) {
|
function handleSubjectChange(subject: NPSelection | undefined) {
|
||||||
const objPronoun = (typeof verb?.object === "object" && verb.object.type === "pronoun")
|
const objPronoun = (typeof verb?.object === "object" && verb.object.type === "pronoun")
|
||||||
? verb.object.person
|
? verb.object.person
|
||||||
|
@ -57,40 +59,26 @@ export function PhraseBuilder() {
|
||||||
object,
|
object,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function handleShrinkServantChange(e: React.ChangeEvent<HTMLInputElement>) {
|
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb });
|
||||||
setShrinkServant(e.target.checked);
|
return <div className="mt-3">
|
||||||
}
|
<div className="row">
|
||||||
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb, shrinkServant });
|
<div className="col mb-2">
|
||||||
return <div>
|
<div className="h4">Subject</div>
|
||||||
<div className="d-flex flex-row justify-content-between">
|
|
||||||
<div className="mr-2">
|
|
||||||
<div className="h5">Subject</div>
|
|
||||||
<NPPicker
|
<NPPicker
|
||||||
np={subject}
|
np={subject}
|
||||||
counterPart={verb ? verb.object : undefined}
|
counterPart={verb ? verb.object : undefined}
|
||||||
onChange={handleSubjectChange}
|
onChange={handleSubjectChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{verb && (verb.object !== "none") && <div className="mr-2">
|
{verb && (verb.object !== "none") && <div className="col mb-2">
|
||||||
<div className="h5">Object</div>
|
<div className="h4">Object</div>
|
||||||
<ObjectDisplay object={verb.object} counterPart={subject} onChange={handleObjectChange} />
|
<ObjectDisplay object={verb.object} counterPart={subject} onChange={handleObjectChange} />
|
||||||
</div>}
|
</div>}
|
||||||
<div>
|
<div className="col mb-2">
|
||||||
<div className="h5">Verb</div>
|
<div className="h4">Verb</div>
|
||||||
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
|
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* TODO: make this appear conditionally */}
|
|
||||||
{(verbPhrase?.object && typeof verbPhrase.object === "object") && <div className="form-group form-check">
|
|
||||||
<input
|
|
||||||
className="form-check-input"
|
|
||||||
name="shrinkServant"
|
|
||||||
type="checkbox"
|
|
||||||
checked={shrinkServant}
|
|
||||||
onChange={handleShrinkServantChange}
|
|
||||||
/>
|
|
||||||
<label className="form-check-label">Shrink servant</label>
|
|
||||||
</div>}
|
|
||||||
{verbPhrase && <div>
|
{verbPhrase && <div>
|
||||||
<VPDisplay VP={verbPhrase} />
|
<VPDisplay VP={verbPhrase} />
|
||||||
</div>}
|
</div>}
|
||||||
|
|
|
@ -1,21 +1,68 @@
|
||||||
|
import { useState } from "react";
|
||||||
import { renderVP, compileVP } from "../../lib/phrase-building";
|
import { renderVP, compileVP } from "../../lib/phrase-building";
|
||||||
import {
|
import {
|
||||||
InlinePs,
|
InlinePs,
|
||||||
defaultTextOptions as opts,
|
defaultTextOptions as opts,
|
||||||
|
ButtonSelect,
|
||||||
|
Types as T,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
|
||||||
|
function adjustForm(form: FormVersion, servantShrinkable: boolean): FormVersion {
|
||||||
|
if (!servantShrinkable) {
|
||||||
|
return form === "shortest"
|
||||||
|
? "no king"
|
||||||
|
: form === "mini servant"
|
||||||
|
? "full"
|
||||||
|
: form;
|
||||||
|
}
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
function VPDisplay({ VP }: { VP: VPSelection }) {
|
function VPDisplay({ VP }: { VP: VPSelection }) {
|
||||||
|
const [form, setForm] = useState<FormVersion>("full");
|
||||||
// TODO: Possibly put the servant shrinking in here after the render
|
// TODO: Possibly put the servant shrinking in here after the render
|
||||||
const result = compileVP(renderVP(VP));
|
const result = compileVP(renderVP(VP), form);
|
||||||
const rPs = "long" in result.ps ? result.ps.long : result.ps;
|
const servantShrinkable = VP.object && typeof VP.object === "object";
|
||||||
return <div className="text-center mt-2">
|
return <div className="text-center mt-2">
|
||||||
{rPs.map((r, i) => <div key={i}>
|
<div className="my-3">
|
||||||
<InlinePs opts={opts}>{r}</InlinePs>
|
<ButtonSelect
|
||||||
</div>)}
|
small
|
||||||
|
options={[
|
||||||
|
{ value: "full", label: "Full" },
|
||||||
|
{ value: "no king", label: "No King" },
|
||||||
|
...servantShrinkable ? [{ value: "mini servant", label: "Mini Servant" }] : [],
|
||||||
|
...servantShrinkable ? [{ value: "shortest", label: "Shortest" }] : [],
|
||||||
|
]}
|
||||||
|
value={adjustForm(form, servantShrinkable)}
|
||||||
|
// @ts-ignore
|
||||||
|
handleChange={setForm}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{"long" in result.ps ?
|
||||||
|
<div>
|
||||||
|
<div className="h6">Long Verb:</div>
|
||||||
|
<VariationLayer vs={result.ps.long} />
|
||||||
|
<div className="h6">Short Verb:</div>
|
||||||
|
<VariationLayer vs={result.ps.short} />
|
||||||
|
{result.ps.mini && <>
|
||||||
|
<div className="h6">Mini Verb:</div>
|
||||||
|
<VariationLayer vs={result.ps.mini} />
|
||||||
|
</>}
|
||||||
|
</div>
|
||||||
|
: <VariationLayer vs={result.ps} />
|
||||||
|
}
|
||||||
{result.e && <div className="text-muted">
|
{result.e && <div className="text-muted">
|
||||||
{result.e.map((e, i) => <div key={i}>{e}</div>)}
|
{result.e.map((e, i) => <div key={i}>{e}</div>)}
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function VariationLayer({ vs }: { vs: T.PsString[] }) {
|
||||||
|
return <div className="mb-2">
|
||||||
|
{vs.map((r, i) => <div key={i}>
|
||||||
|
<InlinePs opts={opts}>{r}</InlinePs>
|
||||||
|
</div>)}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
export default VPDisplay;
|
export default VPDisplay;
|
|
@ -6,17 +6,19 @@ import {
|
||||||
getVerbBlockPosFromPerson,
|
getVerbBlockPosFromPerson,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
|
||||||
type ListOfEntities = T.PsString[][];
|
type ListOfEntities = (T.PsString & { isVerbPrefix?: boolean, prefixFollowedByParticle?: boolean })[][];
|
||||||
|
|
||||||
export function compileVP(VP: VPRendered): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
|
export function compileVP(VP: VPRendered, form: FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
|
||||||
const { head, rest } = VP.verb.ps;
|
const { head, rest } = VP.verb.ps;
|
||||||
const { kids, NPs } = shrinkEntitiesAndGatherKids(VP);
|
const { kids, NPs } = shrinkEntitiesAndGatherKids(VP, form);
|
||||||
return {
|
return {
|
||||||
ps: compilePs(NPs, head, rest, VP.verb.negative, kids),
|
ps: compilePs(NPs, head, rest, VP.verb.negative, kids),
|
||||||
e: compileEnglish(VP),
|
e: compileEnglish(VP),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: ISSUE off prefix-nu in the phonetics
|
||||||
|
|
||||||
function compilePs(
|
function compilePs(
|
||||||
nps: ListOfEntities,
|
nps: ListOfEntities,
|
||||||
head: T.PsString | undefined,
|
head: T.PsString | undefined,
|
||||||
|
@ -49,33 +51,37 @@ function compilePs(
|
||||||
}
|
}
|
||||||
const entities: ListOfEntities = [
|
const entities: ListOfEntities = [
|
||||||
...nps,
|
...nps,
|
||||||
...compileVerbWNegative(head, rest, negative)
|
...compileVerbWNegative(head, rest, negative),
|
||||||
];
|
];
|
||||||
const entitiesWKids = putKidsInKidsSection(entities, kids);
|
const entitiesWKids = putKidsInKidsSection(entities, kids);
|
||||||
return combineEntities(entitiesWKids);
|
return combineEntities(entitiesWKids);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shrinkEntitiesAndGatherKids(VP: VPRendered): { kids: ListOfEntities, NPs: ListOfEntities } {
|
function shrinkEntitiesAndGatherKids(VP: VPRendered, form: FormVersion): { kids: ListOfEntities, NPs: ListOfEntities } {
|
||||||
const main = {
|
const main = {
|
||||||
subject: VP.subject.ps,
|
subject: VP.subject.ps,
|
||||||
object: typeof VP.object === "object" ? VP.object.ps : undefined,
|
object: typeof VP.object === "object" ? VP.object.ps : undefined,
|
||||||
}
|
}
|
||||||
const toShrink = (VP.shrinkServant && VP.servant)
|
const removeKing = form === "no king" || form === "shortest";
|
||||||
|
const shrinkServant = form === "mini servant" || form === "shortest";
|
||||||
|
const shrinkCanditate = ((form === "mini servant" || form === "shortest") && VP.servant)
|
||||||
? VP[VP.servant]
|
? VP[VP.servant]
|
||||||
: undefined;
|
: undefined;
|
||||||
if (!toShrink || typeof toShrink !== "object") {
|
const toShrink = (!shrinkCanditate || typeof shrinkCanditate !== "object")
|
||||||
return {
|
? undefined
|
||||||
kids: [],
|
: shrinkCanditate;
|
||||||
NPs: [main.subject, ...main.object ? [main.object] : []]
|
// TODO: big problem, the king removal doesn't work with grammatically transitive things
|
||||||
};
|
|
||||||
}
|
|
||||||
const king = main[VP.king];
|
const king = main[VP.king];
|
||||||
if (!king) {
|
const showSubject = (VP.king === "subject" && !removeKing && king) || (VP.servant === "subject" && !shrinkServant);
|
||||||
throw new Error("lost the king in the shrinking process");
|
const showObject = (
|
||||||
}
|
(VP.king === "object" && !removeKing && king) || (VP.servant === "object" && !shrinkServant)
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
kids: [shrink(toShrink)],
|
kids: [...toShrink ? [shrink(toShrink)] : []],
|
||||||
NPs: [king],
|
NPs: [
|
||||||
|
...showSubject ? [main.subject] : [],
|
||||||
|
...(showObject && main.object) ? [main.object] : [],
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +98,11 @@ function putKidsInKidsSection(entities: ListOfEntities, kids: ListOfEntities): L
|
||||||
const first = entities[0];
|
const first = entities[0];
|
||||||
const rest = entities.slice(1);
|
const rest = entities.slice(1);
|
||||||
return [
|
return [
|
||||||
first,
|
first.map(x => (
|
||||||
|
x.isVerbPrefix &&
|
||||||
|
// TODO: This isn't quite working
|
||||||
|
(kids.length)
|
||||||
|
) ? { ...x, prefixFollowedByParticle: true } : x),
|
||||||
...kids,
|
...kids,
|
||||||
...rest,
|
...rest,
|
||||||
];
|
];
|
||||||
|
@ -105,7 +115,9 @@ function combineEntities(loe: ListOfEntities): T.PsString[] {
|
||||||
return combineEntities(rest).flatMap(r => (
|
return combineEntities(rest).flatMap(r => (
|
||||||
first.map(ps => concatPsString(
|
first.map(ps => concatPsString(
|
||||||
ps,
|
ps,
|
||||||
ps.p === "و" ? { p: "", f: "-" } : " ",
|
(ps.prefixFollowedByParticle
|
||||||
|
? { p: "", f: "-" }
|
||||||
|
: ps.isVerbPrefix ? "" : " "),
|
||||||
r,
|
r,
|
||||||
))
|
))
|
||||||
));
|
));
|
||||||
|
@ -115,7 +127,7 @@ function combineEntities(loe: ListOfEntities): T.PsString[] {
|
||||||
function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[], negative: boolean): ListOfEntities {
|
function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[], negative: boolean): ListOfEntities {
|
||||||
if (!negative) {
|
if (!negative) {
|
||||||
return [
|
return [
|
||||||
...head ? [[head]] : [],
|
...head ? [[{...head, isVerbPrefix: true}]] : [],
|
||||||
rest,
|
rest,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -130,7 +142,7 @@ function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[],
|
||||||
// if (regularPrefix) {
|
// if (regularPrefix) {
|
||||||
// dashes for oo-nu etc
|
// dashes for oo-nu etc
|
||||||
return [
|
return [
|
||||||
[removeAccents(head)],
|
[{ ...removeAccents(head), isVerbPrefix: true }],
|
||||||
rest.map(r => concatPsString(nu, " ", removeAccents(r)))
|
rest.map(r => concatPsString(nu, " ", removeAccents(r)))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ export function renderVP(VP: VPSelection): VPRendered {
|
||||||
servant,
|
servant,
|
||||||
isPast,
|
isPast,
|
||||||
isTransitive,
|
isTransitive,
|
||||||
shrinkServant: VP.shrinkServant,
|
|
||||||
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
||||||
object: renderNPSelection(VP.object, inflectObject, true, "object"),
|
object: renderNPSelection(VP.object, inflectObject, true, "object"),
|
||||||
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
||||||
|
|
|
@ -10,7 +10,6 @@ type VPSelection = {
|
||||||
subject: NPSelection,
|
subject: NPSelection,
|
||||||
object: Exclude<VerbObject, undefined>,
|
object: Exclude<VerbObject, undefined>,
|
||||||
verb: Exclude<VerbSelection, "object">,
|
verb: Exclude<VerbSelection, "object">,
|
||||||
shrinkServant: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
|
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
|
||||||
|
@ -18,7 +17,6 @@ type VPRendered = {
|
||||||
type: "VPRendered",
|
type: "VPRendered",
|
||||||
king: "subject" | "object",
|
king: "subject" | "object",
|
||||||
servant: "subject" | "object" | undefined,
|
servant: "subject" | "object" | undefined,
|
||||||
shrinkServant: boolean,
|
|
||||||
isPast: boolean,
|
isPast: boolean,
|
||||||
isTransitive: boolean,
|
isTransitive: boolean,
|
||||||
subject: Rendered<NPSelection>,
|
subject: Rendered<NPSelection>,
|
||||||
|
@ -96,6 +94,7 @@ type ParticipleSelection = {
|
||||||
// If T has key K ("user"), replace it
|
// If T has key K ("user"), replace it
|
||||||
type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ? (Omit<T, K> & Record<K, R>) : T;
|
type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ? (Omit<T, K> & Record<K, R>) : T;
|
||||||
|
|
||||||
|
type FormVersion = "full" | "no king" | "mini servant" | "shortest"; // TODO: "all";
|
||||||
|
|
||||||
type Rendered<T extends NPSelection> = ReplaceKey<
|
type Rendered<T extends NPSelection> = ReplaceKey<
|
||||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,
|
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,
|
||||||
|
|
Loading…
Reference in New Issue