Files
ELYTerminal/src/app.rs
T
2026-10-16 00:10:37 -04:00

116 lines
4.0 KiB
Rust

use std::borrow::Cow;
use anyhow::Context as _;
use ely_gpui_component::theme::ActiveTheme;
use gpui::{
App, AppContext, Bounds, TitlebarOptions, WindowBounds, WindowDecorations, WindowHandle,
WindowOptions, px, size,
};
#[cfg(target_os = "macos")]
use crate::term::mac;
use crate::{
blur, menus,
settings::{self, SettingsStore},
term::{ICONS, Launch, MONO, config, input, shell::ShellIntegration, spawn},
themes,
workspace::{self, TITLE, Workspace},
};
/// The id the macOS bundle and Linux desktop entry share.
pub const APP_ID: &str = "com.zacharyzhang.elyterminal";
/// Fonts, settings, integration scripts and the chosen font, each checked before a window opens.
pub fn start(cx: &mut App) -> anyhow::Result<()> {
cx.text_system()
.add_fonts(vec![
Cow::Borrowed(include_bytes!("../assets/fonts/JetBrainsMono-Bold.ttf")),
Cow::Borrowed(include_bytes!("../assets/fonts/JetBrainsMono-Italic.ttf")),
Cow::Borrowed(include_bytes!(
"../assets/fonts/JetBrainsMono-BoldItalic.ttf"
)),
Cow::Borrowed(include_bytes!(
"../assets/fonts/JetBrainsMonoNerdFontMono-Regular.ttf"
)),
])
.context("app: the bundled fonts failed to register")?;
let names = cx.text_system().all_font_names();
for family in [MONO, ICONS] {
anyhow::ensure!(
names.iter().any(|name| name == family),
"app: {family} is not among the registered fonts"
);
}
SettingsStore::init(cx)?;
ShellIntegration::init(cx)?;
input::bind_keys(cx);
workspace::bind_keys(cx);
settings::window::bind_keys(cx);
menus::init(cx);
// Settings alone hold no terminal, so they go with the last one.
cx.on_window_closed(|cx, _| {
let windows = cx.windows();
if !windows
.iter()
.any(|window| window.downcast::<Workspace>().is_some())
{
log::info!("app: no terminal window left; quitting");
cx.quit();
}
})
.detach();
#[cfg(target_os = "macos")]
{
mac::repeat_held_keys();
mac::deliver_command_key_ups()?;
}
#[cfg(target_os = "linux")]
themes::omarchy::start(cx)?;
themes::apply(cx);
let chosen = |settings: &settings::Settings| {
let theme = (settings.theme.clone(), settings.dark_theme.clone());
(theme, settings.background_opacity)
};
let mut worn = chosen(SettingsStore::get(cx));
cx.observe_global::<SettingsStore>(move |cx| {
let now = chosen(SettingsStore::get(cx));
if now != worn {
worn = now;
themes::apply(cx);
}
})
.detach();
Ok(())
}
/// Opens the main window running `launch`.
pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspace>> {
let bounds = Bounds::centered(None, size(px(1200.0), px(760.0)), cx);
let background = blur::appearance(SettingsStore::get(cx));
let options = WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
titlebar: Some(TitlebarOptions {
title: Some(TITLE.into()),
appears_transparent: true,
traffic_light_position: Some(cx.theme().traffic_light_origin()),
}),
// Ely's columns draw the controls; only Linux reads this, and must not draw its own.
window_decorations: Some(WindowDecorations::Client),
window_background: background,
..Default::default()
};
let (pty, events) = spawn(&launch, (80, 24), (8, 16), config(SettingsStore::get(cx)))?;
let window = cx.open_window(options, |window, cx| {
window.set_app_id(APP_ID);
window
.observe_window_appearance(|_, cx| themes::apply(cx))
.detach();
cx.new(|cx| Workspace::new(pty, events, launch, window, cx))
})?;
log::info!(
"app: main window open, blur: {background:?} on {}",
std::env::consts::OS
);
Ok(window)
}