diff --git a/ivette/src/dome/renderer/data/settings.ts b/ivette/src/dome/renderer/data/settings.ts index 7dfa0c6bd8dfcef5767337d14d249f235b7f80d2..62abf2d59881643b1fcd2ccd35124c6713a5393c 100644 --- a/ivette/src/dome/renderer/data/settings.ts +++ b/ivette/src/dome/renderer/data/settings.ts @@ -112,8 +112,7 @@ export class GString extends GlobalSettings<string> { /** Smart constructor for optional (JSON serializable) data. */ export class GOption<A extends JSON.json> - extends GlobalSettings<A | undefined> -{ + extends GlobalSettings<A | undefined> { constructor(name: string, encoder: JSON.Decoder<A>, defaultValue?: A) { super(name, encoder, JSON.identity, defaultValue); } @@ -442,6 +441,14 @@ const GlobalSettingsDriver = new Driver({ defaults: true, }); +/** + Returns the current value of the global settings. + */ +export function getGlobalSettings<A>(S: GlobalSettings<A>): A { + const data = GlobalSettingsDriver.load(S.name); + return JSON.jCatch(S.decoder, S.defaultValue)(data); +} + /** Returns a global state, which is synchronized among all windows, and saved back in the global user settings. The global user settings file is located in diff --git a/ivette/src/ivette/laboratory.tsx b/ivette/src/ivette/laboratory.tsx index a7abef16b41726ada8df603edd9db51d8d00fe48..d174f5c7c4f15d5d5e3c19865dbdc86d7201150a 100644 --- a/ivette/src/ivette/laboratory.tsx +++ b/ivette/src/ivette/laboratory.tsx @@ -37,6 +37,7 @@ import { Catch } from 'dome/errors'; import { classes } from 'dome/misc/utils'; import * as Ivette from 'ivette'; import { compId, LayoutPosition, VIEW, COMPONENT, GROUP } from 'ivette'; +import { NotificationTimer } from 'ivette/prefs'; import * as State from 'ivette/state'; /* -------------------------------------------------------------------------- */ @@ -858,7 +859,7 @@ const NOTIFICATIONS = new States.GlobalState<NotificationState>({ function clearMessage(id: string): void { let { kid, index } = NOTIFICATIONS.getValue(); - if (index.has(id)) return; + if (!index.has(id)) return; index = copyMap(index); index.delete(id); NOTIFICATIONS.setValue({ kid, index }); @@ -901,7 +902,9 @@ export function showMessage(msg: Notification): void { const id = `W${++kid}`; index = copyMap(index).set(id, { ...msg, id }); NOTIFICATIONS.setValue({ kid, index }); - if (msg.kind !== 'error') setTimeout(() => clearMessage(id), 3000); + const timer = Settings.getGlobalSettings(NotificationTimer); + if (timer > 0 && timer < 60) + setTimeout(() => clearMessage(id), timer * 1000); } /* -------------------------------------------------------------------------- */ diff --git a/ivette/src/ivette/prefs.tsx b/ivette/src/ivette/prefs.tsx index 4bb16c1276941ae45edf8abe956b20899de332d4..5b5f3ae2229043fdfbce53a9031eabf72428f137 100644 --- a/ivette/src/ivette/prefs.tsx +++ b/ivette/src/ivette/prefs.tsx @@ -98,8 +98,12 @@ export const EditorCommand = export const ConsoleScrollback = new Settings.GNumber('Console.Scrollback', 2000); -export interface ConsoleScrollbackProps { - scrollback: Settings.GlobalSettings<number>; -} +// -------------------------------------------------------------------------- +// --- Notification Stack +// -------------------------------------------------------------------------- + +// in seconds; 0 means no timeout +export const NotificationTimer = + new Settings.GNumber('Laboratory.Notifications', 5); // -------------------------------------------------------------------------- diff --git a/ivette/src/renderer/Controller.tsx b/ivette/src/renderer/Controller.tsx index 87f25fcd8c0d1eb78184f62d5aa55dcb0ccb79ad..27a1688bb04ebca4c1c034c654523cc32c8e33b4 100644 --- a/ivette/src/renderer/Controller.tsx +++ b/ivette/src/renderer/Controller.tsx @@ -410,6 +410,8 @@ export function RenderConsole(): JSX.Element { Server.onStatus((s: Server.Status) => { switch (s) { case Server.Status.OFF: + case Server.Status.STARTING: + case Server.Status.RESTARTING: Display.clearMessages(); return; case Server.Status.FAILURE: diff --git a/ivette/src/renderer/Messages.tsx b/ivette/src/renderer/Messages.tsx index a8c779133dfc23ac877a7c51aa97cbd0f42e81d7..bb7ccfb467d4892493236569dc04d93b03cd6e57 100644 --- a/ivette/src/renderer/Messages.tsx +++ b/ivette/src/renderer/Messages.tsx @@ -533,10 +533,10 @@ let CURSOR = 0; States.onSyncArray(Kernel.message, () => { const data = States.getSyncArrayData(Kernel.message); - const k = data.length < CURSOR ? 0 : CURSOR; + const curr = data.length < CURSOR ? 0 : CURSOR; let errors = 0; const plugins = new Set<string>(); - while (k < data.length) { + for (let k = curr; k < data.length; k++) { const m = data[k]; switch (m.kind) { case Kernel.logkind.ERROR: diff --git a/ivette/src/renderer/Preferences.tsx b/ivette/src/renderer/Preferences.tsx index 5eb5c83ecfe0eb7eede68ce287f7677dae7e2ad4..f524262984eefe9f21981a3d7f71725b14351bd5 100644 --- a/ivette/src/renderer/Preferences.tsx +++ b/ivette/src/renderer/Preferences.tsx @@ -101,14 +101,34 @@ function EditorFields(): JSX.Element { // --- Console Scrollback Forms // -------------------------------------------------------------------------- -function ConsoleScrollbackFields( - props: IvettePrefs.ConsoleScrollbackProps -): JSX.Element { +function ConsoleFields(): JSX.Element { const scrollback = Forms.useDefined(Forms.useValid( - Settings.useGlobalSettings(props.scrollback), + Settings.useGlobalSettings(IvettePrefs.ConsoleScrollback), )); - const title = 'Maximum number of lines in the console window'; - return (<Forms.NumberField state={scrollback} label="Lines" title={title} />); + return ( + <Forms.SpinnerField + state={scrollback} + label="Console History" + title="Number of lines kept from Frama-C output" + units="l" + min={0} step={500} max={20_000} + /> + ); +} + +function NotificationFields(): JSX.Element { + const timer = Forms.useDefined(Forms.useValid( + Settings.useGlobalSettings(IvettePrefs.NotificationTimer), + )); + return ( + <Forms.SpinnerField + state={timer} + label="Notification Timer" + title="Time before notifications vanish (in seconds, 0 means no timer)" + units="s" + min={0} step={1} max={60} + /> + ); } // -------------------------------------------------------------------------- @@ -124,8 +144,9 @@ export default function Preferences(): JSX.Element { <Forms.Section label="Editors" unfold> <EditorFields /> </Forms.Section> - <Forms.Section label="Console Scrollback" unfold> - <ConsoleScrollbackFields scrollback={IvettePrefs.ConsoleScrollback} /> + <Forms.Section label="Console" unfold> + <ConsoleFields /> + <NotificationFields /> </Forms.Section> </Forms.Page> );