Skip to content
Snippets Groups Projects
Commit 5a7a218e authored by Maxime Jacquemin's avatar Maxime Jacquemin Committed by Maxime Jacquemin
Browse files

[ivette] New Eva component feels quite good

parent d503cbb0
No related branches found
No related tags found
No related merge requests found
......@@ -561,12 +561,13 @@ export function useUpdate(...events: Event<any>[]) {
/**
Hook to re-render when a Promise returns.
The promise will be typically created by using `React.useMemo()`.
The hook returns three informations:
- result: the promise result if it succeeds, undefined otherwise;
- error: the promise error if it fails, undefined otherwise;
- loading: the promise status, true if the promise is still running.
*/
export function usePromiseNoMemo<T> (job: Promise<T>) {
export function usePromise<T>(job: Promise<T>) {
const [result, setResult] = React.useState<T | undefined>();
const [error, setError] = React.useState<Error | undefined>();
const [loading, setLoading] = React.useState(true);
......@@ -581,24 +582,6 @@ export function usePromiseNoMemo<T> (job: Promise<T>) {
return { result, error, loading };
}
/* Internal type alias */
type Dependencies = React.DependencyList | undefined
/**
Hook to re-render when a Promise returns.
The promise construction is memoized.
The hook returns three informations:
- result: the promise result if it succeeds, undefined otherwise;
- error: the promise error if it fails, undefined otherwise;
- loading: the promise status, true if the promise is still running.
*/
export function usePromise<T> (job: () => Promise<T>, deps: Dependencies) {
const depsArray: any[] = [];
deps?.forEach(depsArray.push);
const memoized = React.useMemo<Promise<T>>(job, [job, ...depsArray]);
return usePromiseNoMemo(memoized);
}
/* Internal type alias */
type Serialize<A> = (a: A) => string;
......@@ -610,7 +593,7 @@ type Serialize<A> = (a: A) => string;
*/
export function useCache<K, V>(r: (k: K) => V, s?: Serialize<K>): (k: K) => V {
const [ cache ] = React.useState(new Map<string, V>());
const serialize = React.useCallback((k: K) => s ? s(k) : `${k}`, [s]);
const serialize = React.useMemo(() => s ? s : (k: K) => `${k}`, [s]);
const get = React.useCallback((k: K): V => {
const id = serialize(k);
if (cache.has(id))
......
......@@ -71,7 +71,7 @@ async function getNativeTheme(): Promise<ColorTheme> {
export function useColorTheme(): [ColorTheme, (upd: ColorSettings) => void] {
Dome.useUpdate(NativeThemeUpdated);
const { result: current } = Dome.usePromiseNoMemo(getNativeTheme());
const { result: current } = Dome.usePromise(getNativeTheme());
const [pref, setTheme] = Settings.useGlobalSettings(ColorThemeSettings);
return [current ?? jColorTheme(pref), setTheme];
}
......
......@@ -83,7 +83,7 @@ export default function SourceCode(): JSX.Element {
const [fontSize] = Settings.useGlobalSettings(Preferences.EditorFontSize);
// Updating the buffer content.
const { result } = Dome.usePromise(async () => {
const text = React.useMemo(async () => {
const onError = (): string => {
if (file)
D.error(`Fail to load source code file ${file}`);
......@@ -91,6 +91,7 @@ export default function SourceCode(): JSX.Element {
};
return System.readFile(file).catch(onError);
}, [file]);
const { result } = Dome.usePromise(text);
React.useEffect(() => buffer.setValue(result), [buffer, result]);
/* Last location selected by a click in the source code. */
......
......@@ -24,86 +24,16 @@
// --- Eva Values
// --------------------------------------------------------------------------
// React & Dome
import React from 'react';
import * as Dome from 'dome';
import * as Ivette from 'ivette';
import * as Server from 'frama-c/server';
import { GlobalState, useGlobalState } from 'dome/data/states';
import { Vfill } from 'dome/layout/boxes';
import { IconButton } from 'dome/controls/buttons';
import { AutoSizer } from 'react-virtualized';
import { Model } from './model';
// Locals
import { ProbeInfos } from './probeinfos';
import { Dimension, ValuesPanel } from './valuetable';
import { AlarmsInfos, StackInfos } from './valueinfos';
import { } from 'frama-c/plugins/eva/state';
import { } from './Summary';
import { } from './Coverage';
import './style.css';
import { EvaTable } from 'frama-c/plugins/eva/state';
// --------------------------------------------------------------------------
// --- Values Component
// --------------------------------------------------------------------------
const globalModelState = new GlobalState(new Model());
function ValuesComponent(): JSX.Element {
const [model] = useGlobalState(globalModelState);
model.mount();
Dome.useUpdate(model.changed, model.laidout);
Server.onShutdown(() => model.unmount());
const [zoom, setZoom] = Dome.useNumberSettings('eva-zoom-factor', 0);
return (
<>
<Ivette.TitleBar>
<IconButton
enabled={zoom > 0}
icon="ZOOM.OUT"
onClick={() => setZoom(zoom - 1)}
/>
<IconButton
enabled={zoom < 20}
icon="ZOOM.IN"
onClick={() => setZoom(zoom + 1)}
/>
</Ivette.TitleBar>
<Vfill>
<ProbeInfos model={model} />
<Vfill>
<AutoSizer>
{(dim: Dimension) => (
<ValuesPanel
zoom={zoom}
model={model}
{...dim}
/>
)}
</AutoSizer>
</Vfill>
<AlarmsInfos model={model} />
<StackInfos model={model} />
</Vfill>
</>
);
}
// --------------------------------------------------------------------------
// --- Export Component
// --------------------------------------------------------------------------
Ivette.registerComponent({
id: 'frama-c.plugins.values',
group: 'frama-c.plugins',
rank: 1,
label: 'Eva Values',
title: 'Values inferred by the Eva analysis',
children: <ValuesComponent />,
});
Ivette.registerView({
id: 'summary',
rank: 1,
......@@ -124,13 +54,4 @@ Ivette.registerView({
],
});
Ivette.registerComponent({
id: 'frama-c.plugins.values.test',
group: 'frama-c.plugins',
rank: 1,
label: 'Test Eva Values',
title: 'Values inferred by the Eva analysis',
children: <EvaTable />,
});
// --------------------------------------------------------------------------
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment