refactor/better naming for inflection search types

This commit is contained in:
adueck 2022-10-04 14:45:37 +05:00
parent ced17170a7
commit 0ad08abb88
7 changed files with 71 additions and 72 deletions

View File

@ -134,7 +134,7 @@ class App extends Component<RouteComponentProps, State> {
wordlist: [],
reviewTasks: [],
user: readUser(),
powerResults: undefined,
inflectionSearchResults: undefined,
};
this.handleOptionsUpdate = this.handleOptionsUpdate.bind(this);
this.handleTextOptionsUpdate = this.handleTextOptionsUpdate.bind(this);
@ -146,7 +146,7 @@ class App extends Component<RouteComponentProps, State> {
this.handleRefreshWordlist = this.handleRefreshWordlist.bind(this);
this.handleRefreshReviewTasks = this.handleRefreshReviewTasks.bind(this);
this.handleDictionaryUpdate = this.handleDictionaryUpdate.bind(this);
this.handlePowerSearch = this.handlePowerSearch.bind(this);
this.handleInflectionSearch = this.handleInflectionSearch.bind(this);
}
public componentDidMount() {
@ -245,7 +245,7 @@ class App extends Component<RouteComponentProps, State> {
e.preventDefault();
if (e.repeat) return;
if (!this.state.searchValue) return;
this.handlePowerSearch();
this.handleInflectionSearch();
});
Mousetrap.bind(["ctrl+s", "command+s"], (e) => {
if (this.state.user?.level === "basic") return;
@ -406,7 +406,7 @@ class App extends Component<RouteComponentProps, State> {
searchValue: "",
results: [],
page: 1,
powerResults: undefined,
inflectionSearchResults: undefined,
});
if (this.props.location.pathname !== "/") {
this.props.history.replace("/");
@ -417,7 +417,7 @@ class App extends Component<RouteComponentProps, State> {
searchValue,
results: dictionary.search({ ...prevState, searchValue }),
page: 1,
powerResults: undefined,
inflectionSearchResults: undefined,
}));
if (this.props.history.location.pathname !== "/search") {
this.props.history.push("/search");
@ -459,19 +459,19 @@ class App extends Component<RouteComponentProps, State> {
}
}
private handlePowerSearch() {
private handleInflectionSearch() {
function prepValueForSearch(searchValue: string, textOptions: T.TextOptions): string {
const s = revertSpelling(searchValue, textOptions.spelling);
return standardizePashto(s.trim());
}
this.setState({ powerResults: "searching" });
this.setState({ inflectionSearchResults: "searching" });
// need timeout to make sure the "searching" notice gets rendered before things lock up for the big search
setTimeout(() => {
const powerResults = searchAllInflections(
const inflectionSearchResults = searchAllInflections(
allEntries(),
prepValueForSearch(this.state.searchValue, this.state.options.textOptionsRecord.textOptions),
);
this.setState({ powerResults });
this.setState({ inflectionSearchResults });
}, 20);
}
@ -563,7 +563,7 @@ class App extends Component<RouteComponentProps, State> {
<Results
state={this.state}
isolateEntry={this.handleIsolateEntry}
handlePowerSearch={this.handlePowerSearch}
handleInflectionSearch={this.handleInflectionSearch}
/>
</Route>
<Route path="/new-entries">
@ -572,7 +572,7 @@ class App extends Component<RouteComponentProps, State> {
<Results
state={this.state}
isolateEntry={this.handleIsolateEntry}
handlePowerSearch={this.handlePowerSearch}
handleInflectionSearch={this.handleInflectionSearch}
/>
:
<div>No new words added this month 😓</div>

View File

@ -15,19 +15,19 @@ import {
displayPositionResult,
} from "../lib/inflection-search-helpers";
import {
InflectionSearchResult,
InflectionName,
InflectionFormMatch,
} from "../types/dictionary-types";
function InflectionSearchResultDisplay(
{ result, textOptions, entry }:
{ result: InflectionSearchResult, textOptions: T.TextOptions, entry: T.DictionaryEntry }
function InflectionFormMatchDisplay(
{ form, textOptions, entry }:
{ form: InflectionFormMatch, textOptions: T.TextOptions, entry: T.DictionaryEntry }
) {
function getTransitivity(): "transitive" | "intransitive" | "grammatically transitive" {
if (result.form.includes("grammaticallyTransitive")) {
if (form.path.includes("grammaticallyTransitive")) {
return "grammatically transitive";
}
if (result.form.includes("transitive")) {
if (form.path.includes("transitive")) {
return "transitive";
}
if (entry.c?.includes("intrans.")) {
@ -36,15 +36,15 @@ function InflectionSearchResultDisplay(
return "transitive";
}
const transitivity = getTransitivity();
const isPast = (result.form.includes("past") || result.form.includes("perfect"));
const isPast = (form.path.includes("past") || form.path.includes("perfect"));
const isErgative = (transitivity !== "intransitive") && isPast;
const isVerbPos = (x: InflectionName[] | T.Person[] | null) => {
if (x === null) return false;
return (typeof x[0] !== "string");
};
return <div className="mb-4">
<div className="mb-2"><strong>{displayFormResult(result.form)}</strong></div>
{result.matches.map((match, i) => <div className="ml-2" key={i}>
<div className="mb-2"><strong>{displayFormResult(form.path)}</strong></div>
{form.matches.map((match, i) => <div className="ml-2" key={i}>
<InlinePs opts={textOptions}>{match.ps}</InlinePs>
<div className="ml-3 my-2">
<em>
@ -57,4 +57,4 @@ function InflectionSearchResultDisplay(
</div>;
}
export default InflectionSearchResultDisplay;
export default InflectionFormMatchDisplay;

View File

@ -11,7 +11,7 @@ import {
} from "@lingdocs/pashto-inflector";
import { isPashtoScript } from "./is-pashto";
import {
InflectionSearchResult, PowerResult,
InflectionSearchResult, InflectionFormMatch,
} from "../types/dictionary-types";
import { makeAWeeBitFuzzy } from "./wee-bit-fuzzy";
// @ts-ignore
@ -26,19 +26,19 @@ const relevancySorter = new relevancy.Sorter();
// That's so much better I'm removing the option of skipping compounds
// ~4th iteration:~ ignore perfective or imperfective if wasn't present in verb info (not worth it - scrapped)
export function searchAllInflections(allDocs: T.DictionaryEntry[], searchValue: string): { entry: T.DictionaryEntry, results: InflectionSearchResult[] }[] {
export function searchAllInflections(allDocs: T.DictionaryEntry[], searchValue: string): InflectionSearchResult[] {
const index = isPashtoScript(searchValue) ? "p" : "f"
function sortResultsByRelevancy(arr: PowerResult[]): PowerResult[] {
return relevancySorter.sort(arr, searchValue, (obj: PowerResult, calc: any) => (
calc(removeAccents(obj.results[0].matches[0].ps[index]))
function sortResultsByRelevancy(arr: InflectionSearchResult[]): InflectionSearchResult[] {
return relevancySorter.sort(arr, searchValue, (obj: InflectionSearchResult, calc: any) => (
calc(removeAccents(obj.forms[0].matches[0].ps[index]))
));
}
// TODO: could be better to remove the accents on the searchValue as well beforehand
function sortMatchesByRelevancy(r: PowerResult): PowerResult {
function sortMatchesByRelevancy(r: InflectionSearchResult): InflectionSearchResult {
// first sort all the matches of each form by relevance
const rStage2 = {
...r,
results: r.results.map(x => ({
forms: r.forms.map(x => ({
...x,
matches: relevancySorter.sort(x.matches, searchValue, (obj: {
ps: T.PsString;
@ -48,12 +48,12 @@ export function searchAllInflections(allDocs: T.DictionaryEntry[], searchValue:
}))
};
// then sort the forms by relevance
const results = relevancySorter.sort(rStage2.results, searchValue, (obj: InflectionSearchResult, calc: any) => (
const forms = relevancySorter.sort(rStage2.forms, searchValue, (obj: InflectionFormMatch, calc: any) => (
calc(removeAccents(obj.matches[0].ps[index]))
));
return {
...r,
results,
forms,
};
}
@ -72,7 +72,7 @@ export function searchAllInflections(allDocs: T.DictionaryEntry[], searchValue:
// also do version without directional pronoun on front
const searchFun = (ps: T.PsString) => !!ps[script].match(searchRegex)
// console.time(timerLabel);
const results = allDocs.reduce((all: PowerResult[], entry) => {
const results = allDocs.reduce((all: InflectionSearchResult[], entry) => {
const type = isNounAdjOrVerb(entry);
if (entry.c && type === "verb") {
try {
@ -84,12 +84,12 @@ export function searchAllInflections(allDocs: T.DictionaryEntry[], searchValue:
entry,
complement,
);
const results = searchPile(
const forms = searchPile(
conjugation as any,
searchFun,
);
if (results.length) {
return [...all, { entry, results }];
if (forms.length) {
return [...all, { entry, forms }];
}
return all;
} catch (e) {
@ -101,9 +101,9 @@ export function searchAllInflections(allDocs: T.DictionaryEntry[], searchValue:
if (entry.c && type === "nounAdj") {
const inflections = inflectWord(entry);
if (!inflections) return all;
const results = searchPile(inflections as any, searchFun);
if (results.length) {
return [...all, { entry, results }];
const forms = searchPile(inflections as any, searchFun);
if (forms.length) {
return [...all, { entry, forms }];
}
}
return all;

View File

@ -17,7 +17,7 @@ import { personFromVerbBlockPos } from "@lingdocs/pashto-inflector";
import {
InflectionName,
PluralInflectionName,
InflectionSearchResult,
InflectionFormMatch,
} from "../types/dictionary-types";
const inflectionNames: { inflections: InflectionName[], plural: PluralInflectionName[] } = {
@ -42,17 +42,17 @@ function isPsString(x: T.PsString | ObPile): x is T.PsString {
);
}
function isBlockResult(x: InflectionSearchResult[] | BlockResult): x is BlockResult {
function isBlockResult(x: InflectionFormMatch[] | BlockResult): x is BlockResult {
return "ps" in x[0];
}
// NOTE: perfectiveSplit needs to be ignored because the [PsString, PsString] structure breaks the search!
const defaultFieldsToIgnore = ["info", "type", "perfectiveSplit"];
export function searchPile(pile: ObPile, searchFun: (s: T.PsString) => boolean, toIgnore: string[] = []): InflectionSearchResult[] {
export function searchPile(pile: ObPile, searchFun: (s: T.PsString) => boolean, toIgnore: string[] = []): InflectionFormMatch[] {
const fieldsToIgnore = [...defaultFieldsToIgnore, toIgnore];
function searchObRecord(record: ObRec): null | BlockResult | SinglePsResult | InflectionSearchResult[] {
function searchObRecord(record: ObRec): null | BlockResult | SinglePsResult | InflectionFormMatch[] {
// hit a bottom part a tree, see if what we're looking for is there
if (Array.isArray(record)) {
// @ts-ignore
@ -68,7 +68,7 @@ export function searchPile(pile: ObPile, searchFun: (s: T.PsString) => boolean,
return searchPile(record, searchFun);
}
return Object.entries(pile).reduce((res: InflectionSearchResult[], entry): InflectionSearchResult[] => {
return Object.entries(pile).reduce((res: InflectionFormMatch[], entry): InflectionFormMatch[] => {
const [name, value] = entry;
if (fieldsToIgnore.includes(name)) {
return res;
@ -83,7 +83,7 @@ export function searchPile(pile: ObPile, searchFun: (s: T.PsString) => boolean,
return [
...res,
{
form: [name],
path: [name],
matches: [{ ps: result, pos: null }],
},
];
@ -96,18 +96,18 @@ export function searchPile(pile: ObPile, searchFun: (s: T.PsString) => boolean,
return [
...res,
{
form: [name],
path: [name],
matches: result,
}
];
}
// Result: Have to keep looking down recursively
// add in the current path to all the results
const rb: InflectionSearchResult[] = [
const rb: InflectionFormMatch[] = [
...res,
...result.map((r) => ({
...r,
form: [name, ...r.form]
path: [name, ...r.path]
})),
]
return rb;

View File

@ -257,7 +257,7 @@ function IsolatedEntry({ state, dictionary, isolateEntry }: {
<Results
state={{ ...state, results: relatedEntries }}
isolateEntry={isolateEntry}
handlePowerSearch={() => null}
handleInflectionSearch={() => null}
/>
</> : <div style={{ height: "500px" }} />}
<Modal

View File

@ -15,20 +15,19 @@ import {
import { isPashtoScript } from "../lib/is-pashto";
import Entry from "../components/Entry";
import { Helmet } from "react-helmet";
import InflectionSearchResultDisplay from "../components/InflectionSearchResultDisplay";
import InflectionFormMatchDisplay from "../components/InflectionFormMatchDisplay";
import { getTextOptions } from "../lib/get-text-options";
import {
State,
InflectionSearchResult,
} from "../types/dictionary-types";
export const inflectionSearchIcon = "fas fa-search-plus";
// TODO: put power results in a prop so we can do it from outside with the keyboard shortcut
function Results({ state, isolateEntry, handlePowerSearch }: {
function Results({ state, isolateEntry, handleInflectionSearch }: {
state: State,
isolateEntry: (ts: number) => void,
handlePowerSearch: () => void,
handleInflectionSearch: () => void,
}) {
const [suggestionState, setSuggestionState] = useState<"none" | "editing" | "received">("none");
const [comment, setComment] = useState<string>("");
@ -67,34 +66,34 @@ function Results({ state, isolateEntry, handlePowerSearch }: {
addSubmission(newEntry, state.user);
setSuggestionState("received");
}
const powerResults = state.powerResults;
const inflectionResults = state.inflectionSearchResults;
return <div className="width-limiter">
<Helmet>
<title>LingDocs Pashto Dictionary</title>
</Helmet>
{(state.user && (window.location.pathname !== "/word") && suggestionState === "none" && powerResults === undefined) && <button
{(state.user && (window.location.pathname !== "/word") && suggestionState === "none" && inflectionResults === undefined) && <button
type="button"
className={`btn btn-outline-secondary bg-white entry-suggestion-button${state.options.searchBarPosition === "bottom" ? " entry-suggestion-button-with-bottom-searchbar" : ""}`}
onClick={startSuggestion}
>
<i className="fas fa-plus" style={{ padding: "3px" }} />
</button>}
{(powerResults === undefined && suggestionState === "none" && window.location.pathname === "/search") && <button
{(inflectionResults === undefined && suggestionState === "none" && window.location.pathname === "/search") && <button
type="button"
className={`btn btn-outline-secondary bg-white conjugation-search-button${state.options.searchBarPosition === "bottom" ? " conjugation-search-button-with-bottom-searchbar" : ""}`}
onClick={handlePowerSearch}
onClick={handleInflectionSearch}
>
<i className={inflectionSearchIcon} style={{ padding: "3px" }} />
</button>}
{powerResults === "searching" && <div>
{inflectionResults === "searching" && <div>
<p className="lead mt-1">Searching conjugations/inflections... <i className="fas fa-hourglass-half" /></p>
</div>}
{Array.isArray(powerResults) && <div>
{Array.isArray(inflectionResults) && <div>
<h4 className="mt-1 mb-3">Conjugation/Inflection Results</h4>
{powerResults.length === 0 && <div className="mt-4">
{inflectionResults.length === 0 && <div className="mt-4">
<div>No conjugation/inflection matches found for <strong>{state.searchValue}</strong></div>
</div>}
{powerResults.map((p) => (
{inflectionResults.map((p) => (
<div key={p.entry.ts}>
<Entry
key={p.entry.i}
@ -103,11 +102,11 @@ function Results({ state, isolateEntry, handlePowerSearch }: {
isolateEntry={isolateEntry}
/>
<div className="mb-3 ml-2">
{p.results.map((result: InflectionSearchResult, i) => (
<InflectionSearchResultDisplay
key={"inf-result" + i}
{p.forms.map((form, i) => (
<InflectionFormMatchDisplay
key={"inf-form" + i}
textOptions={textOptions}
result={result}
form={form}
entry={p.entry}
/>
))}
@ -115,7 +114,7 @@ function Results({ state, isolateEntry, handlePowerSearch }: {
</div>
))}
</div>}
{powerResults === undefined && suggestionState === "none" && state.results.map((entry) => (
{inflectionResults === undefined && suggestionState === "none" && state.results.map((entry) => (
<Entry
key={entry.i}
entry={entry}
@ -199,7 +198,7 @@ function Results({ state, isolateEntry, handlePowerSearch }: {
Thanks for the help!
</div>
}
{(((powerResults === undefined) && suggestionState === "none" && state.searchValue && (!state.results.length))) && <div>
{(((inflectionResults === undefined) && suggestionState === "none" && state.searchValue && (!state.results.length))) && <div>
<h5 className="mt-2">No Results Found in {state.options.language}</h5>
{state.options.language === "Pashto" && isPashtoScript(state.searchValue) && <p className="mt-3">
Click on the <i className={inflectionSearchIcon} /> to search inflections and conjugations

View File

@ -11,7 +11,7 @@ export type State = {
reviewTasks: import("./functions-types").ReviewTask[],
dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo | undefined,
user: undefined | import("./account-types").LingdocsUser,
powerResults: undefined | "searching" | PowerResult[],
inflectionSearchResults: undefined | "searching" | InflectionSearchResult[],
}
export type DictionaryAPI = {
@ -160,13 +160,13 @@ export type PluralInflectionName = "plural" | "2nd";
// for each form
// the possible matches, and their person/inflection number
export type PowerResult = {
entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry,
results: InflectionSearchResult[],
};
export type InflectionSearchResult = {
form: string[],
entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry,
forms: InflectionFormMatch[],
}
export type InflectionFormMatch = {
path: string[],
matches: {
ps: import("@lingdocs/pashto-inflector").Types.PsString,
pos: InflectionName[] | import("@lingdocs/pashto-inflector").Types.Person[] | null,