Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:34:48.021Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

persistence.rs

146 lines · 4.8 KB · rust
1use anyhow::{Context, anyhow};
2use db::kvp::KeyValueStore;
3use gpui::App;
4use ui::Window;
5
6use crate::preview;
7use crate::shape::{self, Centered, RelativeHeight, RelativeWidth, Shape, ViewportFraction};
8
9const PICKERS_NAMESPACE: &str = "pickers_v2";
10
11pub(crate) fn store_shape_for_this_layout(
12    picker_delegate: &'static str,
13    preview_layout: Option<preview::Layout>,
14    shape: shape::Centered,
15    window: &ui::Window,
16    cx: &App,
17) {
18    let shape = PickerConfig::from_centered(shape, window);
19
20    let kvp = KeyValueStore::global(cx);
21    db::write_and_log(cx, async move || {
22        kvp.scoped(PICKERS_NAMESPACE)
23            .write(
24                shape_key(picker_delegate, preview_layout),
25                serde_json::to_string(&shape).context("Could not serialize size of picker")?,
26            )
27            .await?;
28        // Must be written after the shape or loading can break
29        // if this future is ever cancelled.
30        kvp.scoped(PICKERS_NAMESPACE)
31            .write(
32                last_layout_key(picker_delegate),
33                layout_as_str(preview_layout).to_string(),
34            )
35            .await
36    });
37}
38
39/// Persist the last-used preview layout without touching the stored shape.
40///
41/// Changing the preview position (e.g. right/below/hidden) without resizing
42/// must still be remembered, so this is called whenever the layout changes.
43pub(crate) fn store_last_layout(
44    picker_delegate: &'static str,
45    preview_layout: Option<preview::Layout>,
46    cx: &App,
47) {
48    let kvp = KeyValueStore::global(cx);
49    db::write_and_log(cx, async move || {
50        kvp.scoped(PICKERS_NAMESPACE)
51            .write(
52                last_layout_key(picker_delegate),
53                layout_as_str(preview_layout).to_string(),
54            )
55            .await
56    });
57}
58
59pub(crate) fn try_load_shape(
60    picker_delegate: &'static str,
61    preview_layout: impl Into<Option<preview::Layout>>,
62    cx: &App,
63) -> anyhow::Result<Option<Shape>> {
64    let Some(shape) = KeyValueStore::global(cx)
65        .scoped(PICKERS_NAMESPACE)
66        .read(&shape_key(picker_delegate, preview_layout.into()))
67        .context("Could not read picker shape from KeyValueStore")?
68    else {
69        return Ok(None);
70    };
71
72    let shape = serde_json::from_str::<PickerConfig>(&shape)
73        .context("Could not deserialize loaded picker shape from persistence")?
74        .into_centered();
75    Ok(Some(Shape::HorizontallyCentered(shape)))
76}
77
78pub(crate) fn load_last_preview_layout(
79    picker_delegate: &'static str,
80    cx: &App,
81) -> anyhow::Result<Option<preview::Layout>> {
82    let Some(last_layout) = KeyValueStore::global(cx)
83        .scoped(PICKERS_NAMESPACE)
84        .read(&last_layout_key(picker_delegate))
85        .context("Could not read last picker layout from KeyValueStore")?
86    else {
87        return Ok(None);
88    };
89
90    parse_layout(&last_layout)
91}
92
93fn shape_key(picker_delegate: &'static str, preview_layout: Option<preview::Layout>) -> String {
94    format!("{picker_delegate}/{}", layout_as_str(preview_layout))
95}
96
97fn last_layout_key(picker_delegate: &'static str) -> String {
98    format!("{picker_delegate}/LAST_PREVIEW_LAYOUT")
99}
100
101fn layout_as_str(layout: Option<preview::Layout>) -> &'static str {
102    match layout {
103        Some(preview::Layout::Hidden) => "hidden",
104        Some(preview::Layout::Below) => "below",
105        Some(preview::Layout::Right) => "right",
106        None => "none",
107    }
108}
109
110fn parse_layout(s: &str) -> anyhow::Result<Option<preview::Layout>> {
111    Ok(Some(match s {
112        "hidden" => preview::Layout::Hidden,
113        "below" => preview::Layout::Below,
114        "right" => preview::Layout::Right,
115        "none" => return Ok(None),
116        _ => return Err(anyhow!("Unknown layout: `{}`", s)),
117    }))
118}
119
120/// A resized picker for persisting its size. All values are stored as fractions
121/// of the viewport so they remain meaningful across window sizes.
122#[derive(Clone, Copy, serde::Serialize, serde::Deserialize)]
123pub(crate) struct PickerConfig {
124    width: f32,        // relative fraction of viewport
125    height: f32,       // relative fraction of viewport
126    preview_size: f32, // relative fraction of viewport
127}
128
129impl PickerConfig {
130    pub(crate) fn from_centered(shape: Centered, window: &Window) -> Self {
131        PickerConfig {
132            width: shape.width.as_viewport_fraction(window).raw(),
133            height: shape.height.as_viewport_fraction(window).raw(),
134            preview_size: shape.preview_size.raw(),
135        }
136    }
137
138    pub(crate) fn into_centered(self) -> Centered {
139        Centered {
140            width: RelativeWidth::viewport(self.width.clamp(0.0, 1.0)),
141            height: RelativeHeight::viewport(self.height.clamp(0.0, 1.0)),
142            preview_size: ViewportFraction::fraction(self.preview_size.clamp(0.0, 1.0)),
143        }
144    }
145}
146
Served at tenant.openagents/omega Member data and write actions are omitted.