From 9f82e6d085869732d3ddb258849774d426471637 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 25 May 2022 18:47:19 -0500 Subject: [PATCH] APs and moveable blocks for verb phrases! --- package.json | 2 +- src/components/ConjugationViewer.tsx | 3 +- src/components/ep-explorer/EPExplorer.tsx | 4 +- src/components/ep-explorer/eps-reducer.ts | 33 +-- src/components/np-picker/AdjectiveManager.tsx | 4 +- src/components/np-picker/AdjectivePicker.tsx | 6 +- src/components/np-picker/picker-tools.tsx | 8 +- src/components/vp-explorer/VPDisplay.tsx | 25 +- src/components/vp-explorer/VPExplorer.tsx | 148 +++++---- src/components/vp-explorer/VPExplorerQuiz.tsx | 86 ++++-- src/components/vp-explorer/verb-selection.ts | 30 +- src/components/vp-explorer/vps-reducer.ts | 79 ++++- src/lib/np-tools.ts | 4 +- src/lib/phrase-building/blocks-utils.ts | 120 +++++++- src/lib/phrase-building/compile.ts | 280 +++++++++--------- src/lib/phrase-building/np-tools.ts | 1 - src/lib/phrase-building/render-ep.ts | 4 +- src/lib/phrase-building/render-vp.ts | 55 +++- src/lib/phrase-building/vp-tools.ts | 75 +++-- src/lib/sandwiches.ts | 6 + src/nouns-adjs.ts | 2 +- src/types.ts | 30 +- 22 files changed, 633 insertions(+), 372 deletions(-) diff --git a/package.json b/package.json index 48742a9..34b8301 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "2.5.9", + "version": "2.6.0", "author": "lingdocs.com", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "homepage": "https://verbs.lingdocs.com", diff --git a/src/components/ConjugationViewer.tsx b/src/components/ConjugationViewer.tsx index 05cb77e..5ce44db 100644 --- a/src/components/ConjugationViewer.tsx +++ b/src/components/ConjugationViewer.tsx @@ -195,11 +195,10 @@ function ConjugationViewer({ entry, complement, textOptions, showOnly, highlight try { return conjugateVerb(entry, complement); } catch(e) { - console.log("conjugation error", e); + console.error("conjugation error", e); return undefined; } })(); - console.log(conjugation); if (conjugation === undefined) { // don't show the conjugation viewer if the verb can't be conjugated return null; diff --git a/src/components/ep-explorer/EPExplorer.tsx b/src/components/ep-explorer/EPExplorer.tsx index 0a76547..e912d97 100644 --- a/src/components/ep-explorer/EPExplorer.tsx +++ b/src/components/ep-explorer/EPExplorer.tsx @@ -40,7 +40,7 @@ function EPExplorer(props: { const parent = useRef(null); useEffect(() => { parent.current && autoAnimate(parent.current); - }, [parent]) + }, [parent]); const subject = getSubjectSelection(eps.blocks).selection; const king = subject?.type === "pronoun" ? "subject" @@ -65,7 +65,7 @@ function EPExplorer(props: { handleChange={setMode} /> -
adjustEps({ type: "insert new AP" })}>+ AP
+ {mode === "phrases" &&
adjustEps({ type: "insert new AP" })}>+ AP
}
{mode === "phrases" && <> {eps.blocks.map(({ block, key }, i) => ( diff --git a/src/components/ep-explorer/eps-reducer.ts b/src/components/ep-explorer/eps-reducer.ts index f43a526..f3e4fb2 100644 --- a/src/components/ep-explorer/eps-reducer.ts +++ b/src/components/ep-explorer/eps-reducer.ts @@ -5,8 +5,7 @@ import { } from "../../lib/misc-helpers"; import { isUnisexNounEntry } from "../../lib/type-predicates"; import { checkForMiniPronounsError } from "../../lib/phrase-building/compile"; -import { adjustSubjectSelection, getSubjectSelection, makeAPBlock } from "../../lib/phrase-building/blocks-utils"; -import { assertNever } from "assert-never"; +import { adjustSubjectSelection, getSubjectSelection, insertNewAP, removeAP, setAP, shiftBlock } from "../../lib/phrase-building/blocks-utils"; type EpsReducerAction = { type: "set predicate type", @@ -151,50 +150,30 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc if (action.type === "insert new AP") { return { ...eps, - blocks: [makeAPBlock(), ...eps.blocks], + blocks: insertNewAP(eps.blocks), }; - // const index = action.payload; - // const newAP = undefined; - // return { - // ...eps, - // blocks: [...eps.blocks].splice(index, 0, newAP), - // }; } if (action.type === "set AP") { - const blocks = [...eps.blocks]; const { index, AP } = action.payload; - blocks[index].block = AP; return { ...eps, - blocks, + blocks: setAP(eps.blocks, index, AP), }; } if (action.type === "remove AP") { - const blocks = [...eps.blocks]; - blocks.splice(action.payload, 1); return { ...eps, - blocks, + blocks: removeAP(eps.blocks, action.payload), }; } if (action.type === "shift block") { const { index, direction } = action.payload; - const newIndex = index + (direction === "forward" ? 1 : -1); - const blocks = [...eps.blocks]; - if (newIndex >= blocks.length || newIndex < 0) { - return eps; - // var k = newIndex - blocks.length + 1; - // while (k--) { - // blocks.push(undefined); - // } - } - blocks.splice(newIndex, 0, blocks.splice(index, 1)[0]); return { ...eps, - blocks, + blocks: shiftBlock(eps.blocks, index, direction), }; } - assertNever(action); + throw new Error("unknown epsReducer action"); } function ensureMiniPronounsOk(old: T.EPSelectionState, eps: T.EPSelectionState, sendAlert?: (msg: string) => void): T.EPSelectionState { diff --git a/src/components/np-picker/AdjectiveManager.tsx b/src/components/np-picker/AdjectiveManager.tsx index e8fc08f..b46314b 100644 --- a/src/components/np-picker/AdjectiveManager.tsx +++ b/src/components/np-picker/AdjectiveManager.tsx @@ -58,7 +58,7 @@ function AdjectiveManager(props: {
Adjective
{!!props.adjectives.length && !adding &&
-
setAdding(true)}>+ Adj.
+
setAdding(true)}>+ Adj.
}
@@ -76,7 +76,7 @@ function AdjectiveManager(props: { />
)} {!adding && !props.adjectives.length &&
-
setAdding(true)}>+ Adj.
+
setAdding(true)}>+ Adj.
}
; } diff --git a/src/components/np-picker/AdjectivePicker.tsx b/src/components/np-picker/AdjectivePicker.tsx index 50f9496..8b7b65c 100644 --- a/src/components/np-picker/AdjectivePicker.tsx +++ b/src/components/np-picker/AdjectivePicker.tsx @@ -46,9 +46,11 @@ function AdjectivePicker(props: { {!props.noTitle &&
Adjective
} - {(!addingSandwich && props.adjective && !props.adjective?.sandwich) + {/* not ready for sandwiches on adjectives */} + {/* {(!addingSandwich && props.adjective && !props.adjective?.sandwich) ?
setAddingSandwich(true)}>+ Sandwich
- :
} + :
} */} +
{ + try { + return getEnglishVerb(e.entry); + } catch(e) { + console.error("no english conjugations for verb"); + } + })(); const eng = engV || truncateEnglish(e.entry.e); const ps = plainTextPsAdjustment( { p: e.entry.p, f: removeFVarients(e.entry.f) }, diff --git a/src/components/vp-explorer/VPDisplay.tsx b/src/components/vp-explorer/VPDisplay.tsx index 1d8b6f5..141b96b 100644 --- a/src/components/vp-explorer/VPDisplay.tsx +++ b/src/components/vp-explorer/VPDisplay.tsx @@ -1,37 +1,28 @@ import { compileVP } from "../../lib/phrase-building/compile"; import * as T from "../../types"; import AbbreviationFormSelector from "./AbbreviationFormSelector"; -import useStickyState from "../../lib/useStickyState"; import Examples from "../Examples"; +import { getObjectSelection, getSubjectSelection } from "../../lib/phrase-building/blocks-utils"; function VPDisplay({ VP, opts, setForm }: { VP: T.VPSelectionState | T.VPRendered, opts: T.TextOptions, setForm: (form: T.FormVersion) => void, }) { - const [OSV, setOSV] = useStickyState(false, "includeOSV"); if (!("type" in VP)) { return
{(() => { - const twoNPs = (VP.subject === undefined) && (VP.object === undefined); - return `Choose NP${twoNPs ? "s " : ""} to make a phrase`; + const subject = getSubjectSelection(VP.blocks).selection; + const object = getObjectSelection(VP.blocks).selection; + if (subject === undefined || object || undefined) { + return `Choose NP${((subject === undefined) && (object === undefined)) ? "s " : ""} to make a phrase`; + } + return `Choose/remove AP to complete the phrase`; })()}
; } - const result = compileVP(VP, { ...VP.form, OSV }); + const result = compileVP(VP, { ...VP.form }); return
- {VP.verb.transitivity === "transitive" &&
- setOSV(e.target.checked)} - /> - -
} makeVPSelectionState(props.verb, savedVps), - "vpsState9", + "vpsState12", flashMessage, ); const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">( @@ -55,6 +58,10 @@ function VPExplorer(props: { const [showShareClipped, setShowShareClipped] = useState(false); const [alert, setAlert] = useState(undefined); const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false); + const parent = useRef(null); + useEffect(() => { + parent.current && autoAnimate(parent.current); + }, [parent]); const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense); const roles = getKingAndServant( isPast, @@ -75,7 +82,6 @@ function VPExplorer(props: { }, [props.verb]); useEffect(() => { const VPSFromUrl = getVPSFromUrl(); - console.log({ VPSFromUrl }); if (VPSFromUrl) { setMode("phrases"); adjustVps({ @@ -124,6 +130,8 @@ function VPExplorer(props: { setShowShareClipped(false); }, 1250); } + const object = getObjectSelection(vps.blocks).selection; + const subject = getSubjectSelection(vps.blocks).selection; const VPS = completeVPSelection(vps); const phraseIsComplete = !!VPS; const rendered = VPS ? renderVP(VPS) : undefined; @@ -160,54 +168,57 @@ function VPExplorer(props: { {mode === "phrases" ? : ""}
- {(vps.verb && (typeof vps.object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) && + {(vps.verb && (typeof object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
} - {mode !== "quiz" &&
+ {mode === "phrases" &&
adjustVps({ type: "insert new AP" })}>+ AP
} + {mode !== "quiz" &&
{mode === "phrases" && <> -
- setShowingExplanation({ role: "king", item: "subject" })}>Subject {roleIcon.king}
- :
- Subject - {` `} - setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant} - {` `} - {(rendered && rendered.whatsAdjustable !== "king") && - - {!servantIsShrunk ? "🪄" : "👶"} - - } -
} - entryFeeder={props.entryFeeder} - role={(isPast && vps.verb.transitivity !== "intransitive") - ? "ergative" - : "subject" - } - is2ndPersonPicker={vps.verb.tenseCategory === "imperative"} - np={vps.subject} - counterPart={vps.verb ? vps.object : undefined} - onChange={handleSubjectChange} - opts={props.opts} - isShrunk={(servantIsShrunk && roles.servant === "subject")} - /> -
- {vps.verb && (vps.object !== "none") &&
- {(typeof vps.object === "number") - ?
Unspoken 3rd Pers. Masc. Plur.
- : setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}
+ {vps.blocks.map(({ block, key }, i, blocks) => { + if (isNoObject(block)) return null; + return
+
+ {(i > 0 && !isNoObject(blocks[i - 1].block)) ?
adjustVps({ type: "shift block", payload: { index: i, direction: "back" }})} + > + +
:
} + {(i < vps.blocks.length - 1 && !isNoObject(blocks[i + 1].block)) ?
adjustVps({ type: "shift block", payload: { index: i, direction: "forward" }})} + > + +
:
} +
+ {(!block || block.type === "adverb" || block.type === "sandwich") + ? adjustVps({ type: "set AP", payload: { index: i, AP } })} + onRemove={() => adjustVps({ type: "remove AP", payload: i })} + /> + : (block?.type === "subjectSelection") + ? setShowingExplanation({ role: "king", item: "subject" })}>Subject {roleIcon.king}
:
- Object + Subject {` `} - setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant} + setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant} {` `} {(rendered && rendered.whatsAdjustable !== "king") && @@ -215,15 +226,48 @@ function VPExplorer(props: { }
} - entryFeeder={props.entryFeeder} - role="object" - np={vps.object} - counterPart={vps.subject} - onChange={handleObjectChange} - opts={props.opts} - isShrunk={(servantIsShrunk && roles.servant === "object")} - />} -
} + entryFeeder={props.entryFeeder} + np={block.selection} + counterPart={vps.verb ? object : undefined} + role={(isPast && vps.verb.transitivity !== "intransitive") + ? "ergative" + : "subject" + } + onChange={handleSubjectChange} + opts={props.opts} + isShrunk={(servantIsShrunk && roles.servant === "subject")} + /> + : (vps.verb && block?.type === "objectSelection" && block.selection !== "none") + ?
+ {(typeof block.selection === "number") + ?
Unspoken 3rd Pers. Masc. Plur.
+ : setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}
+ :
+ Object + {` `} + setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant} + {` `} + {(rendered && rendered.whatsAdjustable !== "king") && + + {!servantIsShrunk ? "🪄" : "👶"} + + } +
} + entryFeeder={props.entryFeeder} + role="object" + np={block.selection} + counterPart={subject} + onChange={handleObjectChange} + opts={props.opts} + isShrunk={(servantIsShrunk && roles.servant === "object")} + />} +
+ : null} +
; + })} }
setWithBa(e.target.checked)} + id="addBa" /> -