Skip to content

new utility fn, deepCompareReturnPrev. use for settings prefix atom t… #1630

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { ContextMenuModel } from "@/store/contextmenu";
import {
atoms,
createBlock,
getSettingsPrefixAtom,
globalStore,
isDev,
PLATFORM,
removeFlashError,
useSettingsPrefixAtom,
} from "@/store/global";
import { appHandleKeyDown } from "@/store/keymodel";
import { getElemAsStr } from "@/util/focusutil";
Expand Down Expand Up @@ -123,7 +123,7 @@ async function handleContextMenu(e: React.MouseEvent<HTMLDivElement>) {
}

function AppSettingsUpdater() {
const windowSettingsAtom = useSettingsPrefixAtom("window");
const windowSettingsAtom = getSettingsPrefixAtom("window");
const windowSettings = useAtomValue(windowSettingsAtom);
useEffect(() => {
const isTransparentOrBlur =
Expand Down
17 changes: 8 additions & 9 deletions frontend/app/store/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { getLayoutModelForStaticTab } from "@/layout/lib/layoutModelHooks";
import { getWebServerEndpoint } from "@/util/endpoints";
import { fetch } from "@/util/fetchutil";
import { getPrefixedSettings, isBlank } from "@/util/util";
import { deepCompareReturnPrev, getPrefixedSettings, isBlank } from "@/util/util";
import { atom, Atom, PrimitiveAtom, useAtomValue } from "jotai";
import { globalStore } from "./jotaiStore";
import { modalsModel } from "./modalmodel";
Expand Down Expand Up @@ -314,16 +314,15 @@ function useSettingsKeyAtom<T extends keyof SettingsType>(key: T): SettingsType[
return useAtomValue(getSettingsKeyAtom(key));
}

function useSettingsPrefixAtom(prefix: string): Atom<SettingsType> {
// TODO: use a shallow equal here to make this more efficient
let settingsPrefixAtom = settingsAtomCache.get(prefix + ":") as Atom<SettingsType>;
function getSettingsPrefixAtom(prefix: string): Atom<SettingsType> {
let settingsPrefixAtom = settingsAtomCache.get(prefix + ":");
if (settingsPrefixAtom == null) {
// create a stable, closured reference to use as the deepCompareReturnPrev key
const cacheKey = {};
settingsPrefixAtom = atom((get) => {
const settings = get(atoms.settingsAtom);
if (settings == null) {
return {};
}
return getPrefixedSettings(settings, prefix);
const newValue = getPrefixedSettings(settings, prefix);
return deepCompareReturnPrev(cacheKey, newValue);
});
settingsAtomCache.set(prefix + ":", settingsPrefixAtom);
}
Expand Down Expand Up @@ -674,6 +673,7 @@ export {
getObjectId,
getOverrideConfigAtom,
getSettingsKeyAtom,
getSettingsPrefixAtom,
getUserName,
globalStore,
initGlobal,
Expand All @@ -700,6 +700,5 @@ export {
useBlockMetaKeyAtom,
useOverrideConfigAtom,
useSettingsKeyAtom,
useSettingsPrefixAtom,
WOS,
};
4 changes: 2 additions & 2 deletions frontend/app/view/term/term.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
getConnStatusAtom,
getOverrideConfigAtom,
getSettingsKeyAtom,
getSettingsPrefixAtom,
globalStore,
useBlockAtom,
useSettingsPrefixAtom,
WOS,
} from "@/store/global";
import * as services from "@/store/services";
Expand Down Expand Up @@ -773,7 +773,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
const viewRef = React.useRef<HTMLDivElement>(null);
const connectElemRef = React.useRef<HTMLDivElement>(null);
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
const termSettingsAtom = useSettingsPrefixAtom("term");
const termSettingsAtom = getSettingsPrefixAtom("term");
const termSettings = jotai.useAtomValue(termSettingsAtom);
let termMode = blockData?.meta?.["term:mode"] ?? "term";
if (termMode != "term" && termMode != "vdom") {
Expand Down
16 changes: 16 additions & 0 deletions frontend/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import base64 from "base64-js";
import clsx from "clsx";
import { Atom, atom, Getter, SetStateAction, Setter, useAtomValue } from "jotai";
import { debounce, throttle } from "throttle-debounce";
const prevValueCache = new WeakMap<any, any>(); // stores a previous value for a deep equal comparison (used with the deepCompareReturnPrev function)

function isBlank(str: string): boolean {
return str == null || str == "";
Expand Down Expand Up @@ -42,6 +43,20 @@ function boundNumber(num: number, min: number, max: number): number {
return Math.min(Math.max(num, min), max);
}

// key must be a suitable weakmap key. pass the new value
// it will return the prevValue (for object equality) if the new value is deep equal to the prev value
function deepCompareReturnPrev(key: any, newValue: any): any {
if (key == null) {
return newValue;
}
const previousValue = prevValueCache.get(key);
if (previousValue !== undefined && JSON.stringify(newValue) === JSON.stringify(previousValue)) {
return previousValue;
}
prevValueCache.set(key, newValue);
return newValue;
}

// works for json-like objects (arrays, objects, strings, numbers, booleans)
function jsonDeepEqual(v1: any, v2: any): boolean {
if (v1 === v2) {
Expand Down Expand Up @@ -294,6 +309,7 @@ export {
base64ToString,
boundNumber,
countGraphemes,
deepCompareReturnPrev,
fireAndForget,
getPrefixedSettings,
getPromiseState,
Expand Down
Loading