T56: Settings › Terminal checks for updates, which the owner asked for after 0.1.5: under Ely, a switch, on by default, checks at start and once a day through curl and Gitea's API, and Check now checks at once; the row says what the check found, a newer release brings Download, which opens its page, and one an automatic check finds posts a notification whose press opens it
CI / macos (push) Canceled after 0s
CI / platforms (windows-latest) (push) Canceled after 1m24s
CI / platforms (ubuntu-24.04) (push) Canceled after 1m32s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-19 10:39:13 -04:00
1 parent 17e91aafef
commit 55250f49f5
13 files changed
+296 -11

No files matched your search

+2 -1
View File
@@ -33,7 +33,7 @@ ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does;
## Layout
- `build.rs`: on Windows, the icon into the executable as resource 1, through `assets/icons/elyterminal.rc`. `.cargo/config.toml`: Windows builds carry the C runtime. `rust-toolchain.toml`: the toolchain rustup installs.
- `src/main.rs`: start. `src/lib.rs`: the modules, public so tests and examples reach them. `src/app.rs`: fonts, settings, integration, then the main window, at the size the settings keep, which it keeps as it settles. `src/menus.rs`: the menu bar, the keys of Quit, the font's size and Minimize, and what they do. `src/blur.rs`: what the window shows of the desktop, from the opacity and blur settings, set as they change; `blur/macos` gives gpui's NSVisualEffectView a material that blurs; `blur/wayland` asks a Wayland compositor for blur behind the window's surface through `ext_background_effect_v1`; `blur/x11` names the window's pane in `_KDE_NET_WM_BLUR_BEHIND_REGION`. `src/workspace.rs`: the window's content, Ely's `ColumnShell` with the sessions, terminal and right columns, their toggles, the right column's Git and Files switch, the title, and the sessions' lifecycle. `src/workspace/widths.rs`: the side columns' widths, which a drag on their border sets and the settings keep once it rests. `src/workspace/events.rs`: what a session's terminal reports: title, folder, bell, the state its row shows, the program's exit; and a press on a notification a session posted. `src/sessions.rs`: a session and its row, with the mark of its status and what hover shows of it; `sessions/orb` draws the mark, 3 by 3 dots on one clock. `src/files.rs`: the Files panel, the shown session's folder as Ely's `Tree` with Git's marks. `src/git.rs`: git through its command line: Files' marks, and the Git panel's status, stage, unstage, discard, commit and log; `src/git/diff.rs` reads git's diff into Ely's stretches. `src/git/panel.rs`: the Git panel's state and actions; `src/git/panel/view.rs`: how it draws.
- `src/main.rs`: start. `src/lib.rs`: the modules, public so tests and examples reach them. `src/app.rs`: fonts, settings, integration, then the main window, at the size the settings keep, which it keeps as it settles. `src/menus.rs`: the menu bar, the keys of Quit, the font's size and Minimize, and what they do. `src/blur.rs`: what the window shows of the desktop, from the opacity and blur settings, set as they change; `blur/macos` gives gpui's NSVisualEffectView a material that blurs; `blur/wayland` asks a Wayland compositor for blur behind the window's surface through `ext_background_effect_v1`; `blur/x11` names the window's pane in `_KDE_NET_WM_BLUR_BEHIND_REGION`. `src/workspace.rs`: the window's content, Ely's `ColumnShell` with the sessions, terminal and right columns, their toggles, the right column's Git and Files switch, the title, and the sessions' lifecycle. `src/workspace/widths.rs`: the side columns' widths, which a drag on their border sets and the settings keep once it rests. `src/workspace/events.rs`: what a session's terminal reports: title, folder, bell, the state its row shows, the program's exit; and a press on a notification a session posted. `src/sessions.rs`: a session and its row, with the mark of its status and what hover shows of it; `sessions/orb` draws the mark, 3 by 3 dots on one clock. `src/files.rs`: the Files panel, the shown session's folder as Ely's `Tree` with Git's marks. `src/git.rs`: git through its command line: Files' marks, and the Git panel's status, stage, unstage, discard, commit and log; `src/git/diff.rs` reads git's diff into Ely's stretches. `src/git/panel.rs`: the Git panel's state and actions; `src/git/panel/view.rs`: how it draws. `src/updates.rs`: checks for a newer release through `curl` and Gitea's API, at start and once a day while the settings ask, and when Settings › Terminal asks.
- `src/pet.rs`: Ely, peeking over the main window's top edge from a window of her own while the settings want her, or up from its bottom edge where no room lies above it; she draws at every frame the display gives her window; `pet/rig` draws her from the icon's paths in layers of one color, each moved by a matrix of its own, as the films rig her; `pet/look` reads her mood from the sessions' marks and her pose at each moment of it, `look/curves` the timings of her moves; and `pet/macos`, `pet/windows` and `pet/x11` keep her window on the main window's edge where the platform does not.
- `src/settings`: the model, its ranges, and `SettingsStore`, the global that loads, checks and saves `settings.json`; `window` is the settings window, `window/appearance` its Appearance page, `window/terminal` its Terminal page. `tests/fonts.rs` brings its own main: gpui builds its Mac platform only on the main thread.
- `src/themes`: built-in terminal themes, the chrome palette each maps to, and `apply`, which dresses the app for the system's appearance; `omarchy`, on Linux, wears Omarchy 4's current theme and follows its switches.
@@ -112,3 +112,4 @@ ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does;
- 2026-10-19: Ely stands inside the main window, her bottom on its pane's bottom edge, as far in from the left, while her box would not fit above it, which the owner asked for after 0.1.4: on a window at the screen's top or full screen her titled macOS panel, which AppKit keeps under the menu bar, stuck between the menu bar and the terminal, and on Windows and X11 she stood off the screen. The rule lives in `pet.rs`: she stands on the top edge while the room above the pane, up to the top of the work area of the main window's display, holds her box, 123.4 points; each platform measures the room and places her: macOS from the main window's `frame` and its `screen`'s `visibleFrame`, which leaves out the menu bar, both in AppKit's points; Windows from the client rect and the work area (`rcWork`) of the monitor `MonitorFromWindow` names, at the main window's scale, since above it or inside it she stands on that monitor; X11 from the pane's place on the root, up to the top of the RandR monitor holding most of it, as Windows and macOS pick a window's display, or of `_NET_WORKAREA`, its first desktop's, where that lies lower: the work area spans every monitor, so on a lower monitor its top is another's. A Wayland client knows no place of its own, so there she stands on the bottom edge while the window is full screen, maximized or tiled at its top, which gpui reports only for a window it draws itself: under server decorations, as Sway's tiling draws them, she stays on top. gpui moves a popup's anchor never, hears a change of state alone as no change of bounds, and gives an unseen popup no frames, so twice a second she checks where the window's size and state put her anchor, counted from the pane as gpui counts it, and opens there again when it moved. Each place logs the edge she moves to. On WSLg, X11 and Weston's Wayland both put her inside a window as tall as the screen or maximized, and over one with room; headless Sway and a two-monitor Xorg did too.
- 2026-10-19: Ely's window shows nothing but her, which the owner asked for after a user's 0.1.4 drew a hairline along the top of her box on macOS. gpui opens a popup as a titled panel, style mask 0x8081, titled, full-size content and nonactivating, and macOS draws a titled window's frame, there as a light edge over the clear room above her head. As it is glued her panel turns borderless, nonactivating alone, 0x80, and the log names both masks; a mask that does not take fails the glue, which closes her window, as any failed glue now does, where her window stayed open, unplaced, while the log said she did not show. macOS 27.2 draws nothing of that frame, so the line never showed here, the app active or not; there a real click on her borderless panel still winks her, the front app stays in front, and keys typed after it reach the terminal. On Windows her bare popup, and on Linux X11's override-redirect window and Wayland's xdg_popup, draw no frame, border or shadow.
- 2026-10-19: a drag moves Ely along the edge she stands on, which the owner asked for after 0.1.5. On macOS, Windows and X11 her glue moves her window after the pointer's place on the screen, `NSEvent`'s `mouseLocation`, `GetCursorPos` and `query_pointer`, since her window moves under the pointer, so a place in it would lag; her window keeps the pointer while the button is held, inside it or not, as AppKit, gpui's `SetCapture` and X's implicit grab give it. A Wayland popup cannot move, so there she moves once let go: the settings keep the place, and the twice-a-second check opens her popup there. She moves by whole points inside the pane, and `ely_left` keeps where she stands, 140 by default, where she stood before; a narrower pane holds her at its right end, and the log names where she is let go. Under Xorg's dummy screen xdotool dragged her 200 pixels and her window followed them; under Sway nested in Xorg, whose X input gives its seat a pointer, xdotool's drag reopened her popup 200 points on. Sway's own `seat cursor` commands send no motion while their press is held, and Sway draws no popup opened before its window settled, so a probe there reopens her before it drags.
- 2026-10-19: Settings › Terminal checks for updates, which the owner asked for after 0.1.5: under Ely, a switch, on by default, checks at start and once a day, and Check now checks at once. The check runs `curl`, as git runs through its command line, so no HTTP or TLS crate joins the build; macOS and Windows 10 ship it, and a missing curl shows as a failed check. It asks Gitea's API for the latest published release, compares its tag's three numbers with the running version, and the row says what it found; a newer one brings Download, which opens the release's page in the browser, since replacing a running, signed app is a job of its own. An automatic check that finds one posts a system notification, at most once a day, whose press opens the page. Checks run off the main thread, one at a time, each start and finding logged; a failure shows its error in the row. Under Xorg's dummy screen the start's check found 0.1.5 the latest, Check now and the switch checked again, and a build named 0.1.4 showed 0.1.5 out with Download, which opened its page.
+2
View File
@@ -118,6 +118,8 @@ Cmd-, opens it; on Windows and Linux, which have no menu bar, so does a gear in
- Option as Alt: off, left, right, both (macOS only).
- Copy on select.
- Ely: a switch.
- Check for updates automatically: a switch, on by default, which checks at start and once a day.
- Updates: what the last check found, and Check now; a newer release brings Download, which opens its page, and one an automatic check finds posts a notification.
- Shortcuts: every shortcut, as this platform's keys, with a search.
## 11. Background blur
+2
View File
@@ -84,6 +84,8 @@ The settings window saves each change at once to `settings.json` in the platform
A file that does not parse, or holds a value out of range, stops the start with an error naming the file and the field. The app never overwrites it.
Settings › Terminal checks for a newer release at start and once a day, or at once with Check now; a newer one shows a Download button that opens its page. The check runs `curl`, which macOS and Windows ship.
## Development
`scripts/check.sh` runs fmt, clippy, the tests and the 500-line rule. `AGENTS.md` lists the rest: the layout, the decisions and the tools.
+1 -1
View File
@@ -143,7 +143,7 @@ Progress truth. Top to bottom, one at a time. A task is ticked only after its co
## 30. Ely's drag and updates
- [x] T55 A drag moves Ely along the edge she stands on, which the owner asked for after 0.1.5: she follows the pointer sideways inside the pane, on macOS, Windows and X11 as it moves, on Wayland, whose popup keeps its place, once it lets go; where she stands, in points from the pane's left edge, the settings keep as `ely_left`.
- [ ] T56 Settings › Terminal checks for updates, which the owner asked for after 0.1.5: under Ely, a switch checks ELYTerminal's latest release at start and once a day, on by default, and a button checks at once; the row says what the check found, and a newer release brings a button that opens its page; a newer release an automatic check finds posts a system notification, whose press opens that page.
- [x] T56 Settings › Terminal checks for updates, which the owner asked for after 0.1.5: under Ely, a switch checks ELYTerminal's latest release at start and once a day, on by default, and a button checks at once; the row says what the check found, and a newer release brings a button that opens its page; a newer release an automatic check finds posts a system notification, whose press opens that page.
## 31. Release
+6 -2
View File
@@ -13,7 +13,7 @@ use crate::{
blur, menus,
settings::{self, SettingsStore},
term::{ICONS, Launch, MONO, config, input, shell::ShellIntegration, spawn},
themes,
themes, updates,
workspace::{self, TITLE, Workspace},
};
@@ -45,15 +45,19 @@ pub fn start(cx: &mut App) -> anyhow::Result<()> {
);
}
SettingsStore::init(cx)?;
updates::start(cx);
ShellIntegration::init(cx)?;
input::bind_keys(cx);
workspace::bind_keys(cx);
settings::window::bind_keys(cx);
menus::init(cx);
cx.set_app_identity(APP_ID, TITLE);
// A press on a notification goes to the window whose session posted it.
// A press on a notification goes to the window whose session posted it, or to a newer release's page.
cx.on_system_notification_response(|response, cx| {
let tag = response.tag;
if updates::pressed(&tag, cx) {
return;
}
let pressed = cx
.windows()
.into_iter()
+2 -2
View File
@@ -25,9 +25,9 @@ fn line<A: AsRef<OsStr>>(args: &[A]) -> String {
args.join(" ")
}
/// Keeps Windows from opening a console window for git.
/// Keeps Windows from opening a console window for git and curl.
#[cfg(windows)]
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
pub(crate) const CREATE_NO_WINDOW: u32 = 0x0800_0000;
/// Runs git in `folder`: English messages, literal paths, no lock the user's own git could meet; `input` feeds stdin.
fn git<A: AsRef<OsStr>>(folder: &Path, args: &[A], input: &[u8]) -> anyhow::Result<Output> {
+1
View File
@@ -12,4 +12,5 @@ mod testlog;
#[cfg(all(test, target_os = "linux"))]
mod testx11;
pub mod themes;
pub mod updates;
pub mod workspace;
+3
View File
@@ -76,6 +76,8 @@ pub struct Settings {
pub ely: bool,
/// How far in from the pane's left edge she stands, in points, as a drag left her.
pub ely_left: f32,
/// A check for a newer release at start and once a day.
pub check_updates: bool,
pub show_sessions: bool,
pub show_panel: bool,
pub panel: PanelTab,
@@ -109,6 +111,7 @@ impl Default for Settings {
copy_on_select: false,
ely: true,
ely_left: 140.0,
check_updates: true,
show_sessions: true,
show_panel: true,
panel: PanelTab::Git,
+3 -1
View File
@@ -17,7 +17,7 @@ use gpui::{
};
use super::{Settings, SettingsStore};
use crate::{app::APP_ID, menus, term::BLINK};
use crate::{app::APP_ID, menus, term::BLINK, updates::Updates};
mod appearance;
mod terminal;
@@ -100,6 +100,7 @@ pub struct SettingsWindow {
lit: bool,
_typed: Subscription,
_settings: Subscription,
_updates: Subscription,
_blink: Task<()>,
}
@@ -133,6 +134,7 @@ impl SettingsWindow {
lit: true,
_typed: typed,
_settings: cx.observe_global::<SettingsStore>(|_, cx| cx.notify()),
_updates: cx.observe_global::<Updates>(|_, cx| cx.notify()),
_blink: Self::blink(cx),
}
}
+62 -4
View File
@@ -1,7 +1,7 @@
use ely_gpui_component::{
buttons::SegmentedControl,
buttons::{Button, SegmentedControl},
feedback::InlineMessage,
forms::{Copy, NumberInput, Paste, PathInput, SelectAll},
forms::{Copy, NumberInput, Paste, PathInput, SelectAll, Switch},
primitives::Severity,
settings::{KeyboardShortcutsList, SettingsRow, SettingsSection, Shortcut},
theme::{ActiveTheme, ControlSize},
@@ -15,6 +15,7 @@ use crate::{
menus::{Bigger, Minimize, Quit, ResetSize, Smaller},
settings::{OptionAsAlt, SCROLLBACK, SettingsStore, StartIn},
term::input::{self, Find, NextPrompt, PreviousPrompt},
updates::{self, Updates, VERSION},
workspace::{
self, CloseSession, LastSession, NewSession, NextSession, PreviousSession, SelectSession,
TogglePanel, ToggleSessions,
@@ -42,7 +43,7 @@ const PLACES: [&str; 8] = [
];
impl SettingsWindow {
/// Shell, start in, scrollback, Option as Alt on macOS and copy on select, then the shortcuts.
/// Shell, start in, scrollback, Option as Alt on macOS, copy on select, Ely and updates, then the shortcuts.
pub(super) fn terminal(&self, cx: &Context<Self>) -> Div {
let settings = SettingsStore::get(cx);
let this = cx.entity();
@@ -106,13 +107,70 @@ impl SettingsWindow {
SettingsRow::new("Ely")
.description("Peeks over the window, her face as your sessions are")
.control(ely),
);
)
.row(
SettingsRow::new("Check for updates automatically")
.description("At start and once a day")
.control(auto_check(&this, settings.check_updates)),
)
.row(updates_row(cx));
let keys = SettingsSection::new("Shortcuts")
.row(KeyboardShortcutsList::new(shortcuts(cx), &self.search));
div().flex().flex_col().gap_6().child(section).child(keys)
}
}
/// The switch for automatic checks; turning it on checks at once.
fn auto_check(this: &Entity<SettingsWindow>, on: bool) -> Switch {
let this = this.clone();
Switch::new("check_updates", on).on_change(move |on, _, cx| {
let change = format!("check_updates is {on}");
if set(&this, change, cx, |settings| settings.check_updates = on) && on {
updates::check(false, cx);
}
})
}
/// What the last check found, a button that checks now, and one that opens a newer release's page.
fn updates_row(cx: &App) -> SettingsRow {
let found = cx.global::<Updates>();
let status: SharedString = match found {
Updates::Unchecked => format!("ELYTerminal {VERSION}").into(),
Updates::Checking => "Checking for a newer release…".into(),
Updates::Latest => format!("ELYTerminal {VERSION} is the latest").into(),
Updates::Newer { version, .. } => {
format!("ELYTerminal {version} is out; this is {VERSION}").into()
}
Updates::Failed(why) => format!("The check failed: {why}").into(),
};
let page = match found {
Updates::Newer { page, .. } => Some(page.clone()),
_ => None,
};
let check = Button::new("check-updates", "Check now")
.size(ControlSize::Sm)
.loading(*found == Updates::Checking)
.on_click(|_, _, cx| updates::check(false, cx));
let open = page.map(|page| {
Button::new("open-update", "Download")
.primary()
.size(ControlSize::Sm)
.on_click(move |_, _, cx| {
log::info!("updates: Settings opens {page}");
cx.open_url(&page);
})
});
let control = div()
.flex()
.items_center()
.gap_2()
.children(open)
.child(check);
SettingsRow::new("Updates")
.description(status)
.control(control)
}
/// Where new sessions start, as the settings keep it.
fn start_in(this: &Entity<SettingsWindow>, value: &SharedString, cx: &mut App) {
let start = match value.as_ref() {
+207
View File
@@ -0,0 +1,207 @@
//! Checks for a newer release through curl and Gitea's API: at start and once a day while the settings ask, and whenever Settings asks at once.
use std::{
process::{Command, Stdio},
time::Duration,
};
use anyhow::Context as _;
use gpui::{App, Global, SystemNotification};
use serde::Deserialize;
use crate::{settings::SettingsStore, workspace::TITLE};
/// The latest published release.
const LATEST: &str =
"https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/ELYTerminal/releases/latest";
/// How long an automatic check waits for the next.
const DAY: Duration = Duration::from_secs(24 * 60 * 60);
/// The tag a newer release's notification carries.
const TAG: &str = "elyterminal-update";
/// The running version.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// What the last check found.
#[derive(Clone, Debug, PartialEq)]
pub enum Updates {
Unchecked,
Checking,
Latest,
Newer { version: String, page: String },
Failed(String),
}
impl Global for Updates {}
/// The fields of a release the check reads.
#[derive(Debug, Deserialize)]
struct Release {
tag_name: String,
html_url: String,
}
/// Checks at once and then once a day, each time the settings ask for it.
pub fn start(cx: &mut App) {
cx.set_global(Updates::Unchecked);
cx.spawn(async move |cx| {
loop {
cx.update(|cx| {
if SettingsStore::get(cx).check_updates {
check(true, cx);
}
});
cx.background_executor().timer(DAY).await;
}
})
.detach();
}
/// Asks for the latest release off the main thread; when `auto`, a newer one posts a notification.
pub fn check(auto: bool, cx: &mut App) {
if *cx.global::<Updates>() == Updates::Checking {
return;
}
log::info!("updates: checking for a release newer than {VERSION}");
cx.set_global(Updates::Checking);
let fetched = cx.background_executor().spawn(async { latest() });
cx.spawn(async move |cx| {
let found = fetched.await.and_then(newer);
cx.update(|cx| finish(found, auto, cx));
})
.detach();
}
/// Keeps what the check found, and tells of a newer release it found by itself.
fn finish(found: anyhow::Result<Option<(String, String)>>, auto: bool, cx: &mut App) {
let found = match found {
Ok(Some((version, page))) => {
log::info!("updates: {version} is out, newer than {VERSION}, at {page}");
if auto {
cx.show_system_notification(SystemNotification {
tag: TAG.into(),
title: TITLE.into(),
body: format!("ELYTerminal {version} is out. Press to open its page.").into(),
actions: Vec::new(),
});
}
Updates::Newer { version, page }
}
Ok(None) => {
log::info!("updates: {VERSION} is the latest");
Updates::Latest
}
Err(error) => {
log::error!("{error:#}");
Updates::Failed(format!("{error:#}"))
}
};
cx.set_global(found);
}
/// Opens the newer release's page when its notification is pressed; tells whether `tag` was that notification's.
pub fn pressed(tag: &str, cx: &mut App) -> bool {
if tag != TAG {
return false;
}
match cx.global::<Updates>().clone() {
Updates::Newer { page, .. } => {
log::info!("updates: the notification opens {page}");
cx.open_url(&page);
}
found => {
log::info!("updates: the notification was pressed, the last check finding {found:?}")
}
}
true
}
/// The latest release, which curl fetches from Gitea's API.
fn latest() -> anyhow::Result<Release> {
let mut command = Command::new("curl");
#[cfg(windows)]
std::os::windows::process::CommandExt::creation_flags(
&mut command,
crate::git::CREATE_NO_WINDOW,
);
let output = command
.args(["--fail", "--silent", "--show-error", "--location"])
.args(["--max-time", "30", LATEST])
.stdin(Stdio::null())
.output()
.context("updates: curl did not start")?;
anyhow::ensure!(
output.status.success(),
"updates: curl failed: {}",
String::from_utf8_lossy(&output.stderr).trim()
);
serde_json::from_slice(&output.stdout).context("updates: the latest release does not read")
}
/// The release's version and page when it is newer than this one.
fn newer(release: Release) -> anyhow::Result<Option<(String, String)>> {
let latest = version(&release.tag_name)?;
let shown = release.tag_name.trim_start_matches('v').to_string();
Ok((latest > version(VERSION)?).then_some((shown, release.html_url)))
}
/// `tag`'s three numbers, from `v0.1.6` or `0.1.6`.
fn version(tag: &str) -> anyhow::Result<[u64; 3]> {
let numbers: Vec<u64> = (tag.trim_start_matches('v').split('.'))
.map(str::parse)
.collect::<Result<_, _>>()
.with_context(|| format!("updates: {tag:?} is no version"))?;
numbers
.try_into()
.map_err(|_| anyhow::anyhow!("updates: {tag:?} is no version of three numbers"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_tag_reads_as_three_numbers() {
assert_eq!(version("v0.1.6").expect("a tag"), [0, 1, 6]);
assert_eq!(version("1.10.0").expect("no v"), [1, 10, 0]);
assert!(version("v0.1").is_err(), "two numbers");
assert!(version("v0.1.6-beta").is_err(), "a suffix");
}
#[test]
fn only_a_later_release_is_newer() {
let release = |tag: &str| Release {
tag_name: tag.into(),
html_url: format!("https://example.org/{tag}"),
};
let [major, minor, patch] = version(VERSION).expect("this version");
let later = format!("v{major}.{minor}.{}", patch + 1);
let found = newer(release(&later)).expect("reads");
let shown = later.trim_start_matches('v').to_string();
assert_eq!(found, Some((shown, format!("https://example.org/{later}"))));
assert_eq!(
newer(release(&format!("v{VERSION}"))).expect("reads"),
None,
"this one"
);
assert_eq!(
newer(release("v0.0.1")).expect("reads"),
None,
"an older one"
);
assert_eq!(
newer(release(&format!("v{}.0.0", major + 1)))
.expect("reads")
.map(|(v, _)| v),
Some(format!("{}.0.0", major + 1)),
"by its numbers, not as text"
);
}
#[test]
fn gitea_s_release_reads() {
let body = r#"{"id":213,"tag_name":"v0.1.5","name":"ELYTerminal 0.1.5","html_url":"https://git.zacharyzhang.com/ZacharyZhang-NY/ELYTerminal/releases/tag/v0.1.5","draft":false,"assets":[]}"#;
let release: Release = serde_json::from_str(body).expect("a release");
assert_eq!(release.tag_name, "v0.1.5");
assert!(release.html_url.ends_with("/releases/tag/v0.1.5"));
}
}
+1
View File
@@ -126,6 +126,7 @@ What no check reached: no real KWin drew the blur; of Wayland desktops, only Hyp
| On Omarchy, the Omarchy theme first in the grid | T27 | on X11 with Omarchy's theme folder, the Omarchy card leads the grid, chosen, over a preview in its colors | Pass |
| Terminal: scrollback, Option as Alt (macOS), copy on select | T18 | T18 review | Pass |
| Terminal: Ely, a switch | T46 | on macOS the switch closed her window and saved `"ely": false`, a start with it showed no Ely, and the switch brought her back | Pass |
| Terminal: check for updates automatically, a switch on by default, at start and once a day; Updates says what the check found, with Check now, and Download for a newer release; an automatic check that finds one posts a notification that opens its page | T56 | `updates` tests: a tag reads as three numbers, only a later release is newer, by its numbers, and Gitea's release body reads; under Xorg's dummy screen the app's start checked through curl and logged `0.1.5 is the latest`, the two rows stood under Ely, before Shortcuts, Check now checked again, the switch saved `check_updates` off and on, and turning it on checked at once; a build named 0.1.4 logged `0.1.5 is out`, its row read `ELYTerminal 0.1.5 is out; this is 0.1.4` beside Download and Check now, and Download logged that it opened the release's page; the notification's press went unexercised, since the container held no notification daemon | Pass |
| Terminal: every shortcut, with a search | T26 | read from the keymap, the bindings that apply in the main window's terminal; on X11 the list showed this platform's keys (Ctrl+Shift+T, Alt+1 and on), and typing "paste" left Edit's Paste, Ctrl+Shift+V | Pass |
## 11. Background blur
+4
View File
@@ -276,3 +276,7 @@ Each task gets at most three codex rounds. Each round: the commit, the verdict,
## T55
- No review: the owner asked for 0.1.6 without one. Checked by scripts/check.sh (240 tests), Linux tests (247) and clippy, Windows gnu clippy, an xdotool drag under Xorg, a drag under Sway nested in Xorg, and the owner's own drags on macOS.
## T56
- No review: the owner asked for 0.1.6 without one. Checked by scripts/check.sh (243 tests), Linux tests (250) and clippy, Windows gnu clippy, and under Xorg's dummy screen the start's check, Check now, the switch, and a build named 0.1.4 that found 0.1.5 out and opened its page.