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 VPDisplay from "./VPDisplay";
|
||||
import ObjectDisplay from "./ObjectDisplay";
|
||||
import { verbs } from "../../words/words";
|
||||
import { verbs as verbsRaw } from "../../words/words";
|
||||
import {
|
||||
isInvalidSubjObjCombo,
|
||||
} 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 (!verb) return undefined;
|
||||
if (verb.object === undefined) return undefined;
|
||||
return {
|
||||
type: "VPSelection",
|
||||
shrinkServant,
|
||||
subject,
|
||||
object: verb.object,
|
||||
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() {
|
||||
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
||||
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
||||
const [shrinkServant, setShrinkServant] = useState<boolean>(false);
|
||||
function handleSubjectChange(subject: NPSelection | undefined) {
|
||||
const objPronoun = (typeof verb?.object === "object" && verb.object.type === "pronoun")
|
||||
? verb.object.person
|
||||
|
@ -57,40 +59,26 @@ export function PhraseBuilder() {
|
|||
object,
|
||||
});
|
||||
}
|
||||
function handleShrinkServantChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
setShrinkServant(e.target.checked);
|
||||
}
|
||||
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb, shrinkServant });
|
||||
return <div>
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<div className="mr-2">
|
||||
<div className="h5">Subject</div>
|
||||
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb });
|
||||
return <div className="mt-3">
|
||||
<div className="row">
|
||||
<div className="col mb-2">
|
||||
<div className="h4">Subject</div>
|
||||
<NPPicker
|
||||
np={subject}
|
||||
counterPart={verb ? verb.object : undefined}
|
||||
onChange={handleSubjectChange}
|
||||
/>
|
||||
</div>
|
||||
{verb && (verb.object !== "none") && <div className="mr-2">
|
||||
<div className="h5">Object</div>
|
||||
{verb && (verb.object !== "none") && <div className="col mb-2">
|
||||
<div className="h4">Object</div>
|
||||
<ObjectDisplay object={verb.object} counterPart={subject} onChange={handleObjectChange} />
|
||||
</div>}
|
||||
<div>
|
||||
<div className="h5">Verb</div>
|
||||
<div className="col mb-2">
|
||||
<div className="h4">Verb</div>
|
||||
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
|
||||
</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>
|
||||
<VPDisplay VP={verbPhrase} />
|
||||
</div>}
|
||||
|
|
|
@ -1,21 +1,68 @@
|
|||
import { useState } from "react";
|
||||
import { renderVP, compileVP } from "../../lib/phrase-building";
|
||||
import {
|
||||
InlinePs,
|
||||
defaultTextOptions as opts,
|
||||
ButtonSelect,
|
||||
Types as T,
|
||||
} 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 }) {
|
||||
const [form, setForm] = useState<FormVersion>("full");
|
||||
// TODO: Possibly put the servant shrinking in here after the render
|
||||
const result = compileVP(renderVP(VP));
|
||||
const rPs = "long" in result.ps ? result.ps.long : result.ps;
|
||||
const result = compileVP(renderVP(VP), form);
|
||||
const servantShrinkable = VP.object && typeof VP.object === "object";
|
||||
return <div className="text-center mt-2">
|
||||
{rPs.map((r, i) => <div key={i}>
|
||||
<InlinePs opts={opts}>{r}</InlinePs>
|
||||
</div>)}
|
||||
<div className="my-3">
|
||||
<ButtonSelect
|
||||
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.map((e, i) => <div key={i}>{e}</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;
|
|
@ -6,17 +6,19 @@ import {
|
|||
getVerbBlockPosFromPerson,
|
||||
} 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 { kids, NPs } = shrinkEntitiesAndGatherKids(VP);
|
||||
const { kids, NPs } = shrinkEntitiesAndGatherKids(VP, form);
|
||||
return {
|
||||
ps: compilePs(NPs, head, rest, VP.verb.negative, kids),
|
||||
e: compileEnglish(VP),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: ISSUE off prefix-nu in the phonetics
|
||||
|
||||
function compilePs(
|
||||
nps: ListOfEntities,
|
||||
head: T.PsString | undefined,
|
||||
|
@ -49,33 +51,37 @@ function compilePs(
|
|||
}
|
||||
const entities: ListOfEntities = [
|
||||
...nps,
|
||||
...compileVerbWNegative(head, rest, negative)
|
||||
...compileVerbWNegative(head, rest, negative),
|
||||
];
|
||||
const entitiesWKids = putKidsInKidsSection(entities, kids);
|
||||
return combineEntities(entitiesWKids);
|
||||
}
|
||||
|
||||
function shrinkEntitiesAndGatherKids(VP: VPRendered): { kids: ListOfEntities, NPs: ListOfEntities } {
|
||||
function shrinkEntitiesAndGatherKids(VP: VPRendered, form: FormVersion): { kids: ListOfEntities, NPs: ListOfEntities } {
|
||||
const main = {
|
||||
subject: VP.subject.ps,
|
||||
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]
|
||||
: undefined;
|
||||
if (!toShrink || typeof toShrink !== "object") {
|
||||
return {
|
||||
kids: [],
|
||||
NPs: [main.subject, ...main.object ? [main.object] : []]
|
||||
};
|
||||
}
|
||||
const toShrink = (!shrinkCanditate || typeof shrinkCanditate !== "object")
|
||||
? undefined
|
||||
: shrinkCanditate;
|
||||
// TODO: big problem, the king removal doesn't work with grammatically transitive things
|
||||
const king = main[VP.king];
|
||||
if (!king) {
|
||||
throw new Error("lost the king in the shrinking process");
|
||||
}
|
||||
const showSubject = (VP.king === "subject" && !removeKing && king) || (VP.servant === "subject" && !shrinkServant);
|
||||
const showObject = (
|
||||
(VP.king === "object" && !removeKing && king) || (VP.servant === "object" && !shrinkServant)
|
||||
);
|
||||
return {
|
||||
kids: [shrink(toShrink)],
|
||||
NPs: [king],
|
||||
kids: [...toShrink ? [shrink(toShrink)] : []],
|
||||
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 rest = entities.slice(1);
|
||||
return [
|
||||
first,
|
||||
first.map(x => (
|
||||
x.isVerbPrefix &&
|
||||
// TODO: This isn't quite working
|
||||
(kids.length)
|
||||
) ? { ...x, prefixFollowedByParticle: true } : x),
|
||||
...kids,
|
||||
...rest,
|
||||
];
|
||||
|
@ -105,7 +115,9 @@ function combineEntities(loe: ListOfEntities): T.PsString[] {
|
|||
return combineEntities(rest).flatMap(r => (
|
||||
first.map(ps => concatPsString(
|
||||
ps,
|
||||
ps.p === "و" ? { p: "", f: "-" } : " ",
|
||||
(ps.prefixFollowedByParticle
|
||||
? { p: "", f: "-" }
|
||||
: ps.isVerbPrefix ? "" : " "),
|
||||
r,
|
||||
))
|
||||
));
|
||||
|
@ -115,7 +127,7 @@ function combineEntities(loe: ListOfEntities): T.PsString[] {
|
|||
function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[], negative: boolean): ListOfEntities {
|
||||
if (!negative) {
|
||||
return [
|
||||
...head ? [[head]] : [],
|
||||
...head ? [[{...head, isVerbPrefix: true}]] : [],
|
||||
rest,
|
||||
];
|
||||
}
|
||||
|
@ -130,7 +142,7 @@ function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[],
|
|||
// if (regularPrefix) {
|
||||
// dashes for oo-nu etc
|
||||
return [
|
||||
[removeAccents(head)],
|
||||
[{ ...removeAccents(head), isVerbPrefix: true }],
|
||||
rest.map(r => concatPsString(nu, " ", removeAccents(r)))
|
||||
];
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ export function renderVP(VP: VPSelection): VPRendered {
|
|||
servant,
|
||||
isPast,
|
||||
isTransitive,
|
||||
shrinkServant: VP.shrinkServant,
|
||||
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
||||
object: renderNPSelection(VP.object, inflectObject, true, "object"),
|
||||
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
||||
|
|
|
@ -10,7 +10,6 @@ type VPSelection = {
|
|||
subject: NPSelection,
|
||||
object: Exclude<VerbObject, undefined>,
|
||||
verb: Exclude<VerbSelection, "object">,
|
||||
shrinkServant: boolean,
|
||||
};
|
||||
|
||||
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
|
||||
|
@ -18,7 +17,6 @@ type VPRendered = {
|
|||
type: "VPRendered",
|
||||
king: "subject" | "object",
|
||||
servant: "subject" | "object" | undefined,
|
||||
shrinkServant: boolean,
|
||||
isPast: boolean,
|
||||
isTransitive: boolean,
|
||||
subject: Rendered<NPSelection>,
|
||||
|
@ -96,6 +94,7 @@ type ParticipleSelection = {
|
|||
// 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 FormVersion = "full" | "no king" | "mini servant" | "shortest"; // TODO: "all";
|
||||
|
||||
type Rendered<T extends NPSelection> = ReplaceKey<
|
||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,
|
||||
|
|
Loading…
Reference in New Issue