Files
ELYTerminal/src/app.rs
T

124 lines
4.0 KiB
Rust

use std::borrow::Cow;
use anyhow::Context as _;
use ely_gpui_component::{primitives::FocusScope, theme::ActiveTheme};
use gpui::{
App, AppContext, Bounds, Context, Entity, FocusHandle, Focusable, IntoElement, ParentElement,
Render, Styled, Subscription, TitlebarOptions, Window, WindowBounds, WindowHandle,
WindowOptions, px, size,
};
#[cfg(target_os = "macos")]
use crate::term::mac;
use crate::{
settings::SettingsStore,
term::{
ICONS, Launch, MONO, TerminalEvent, TerminalView, config, input, shell::ShellIntegration,
spawn,
},
themes,
};
/// The window title while the program names none.
const TITLE: &str = "ELYTerminal";
/// The main window's content.
pub struct Workspace {
focus: FocusHandle,
terminal: Entity<TerminalView>,
_events: Subscription,
}
impl Workspace {
/// The window wears the terminal's title.
fn terminal_event(
&mut self,
_: &Entity<TerminalView>,
event: &TerminalEvent,
window: &mut Window,
_: &mut Context<Self>,
) {
if let TerminalEvent::Title(title) = event {
let title = if title.is_empty() { TITLE } else { title };
log::debug!("app: the window title is {title:?}");
window.set_window_title(title);
}
}
}
impl Render for Workspace {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
FocusScope::new(&self.focus)
.root()
.size_full()
.bg(cx.theme().colors.bg)
.child(self.terminal.clone())
}
}
/// 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);
#[cfg(target_os = "macos")]
{
mac::repeat_held_keys();
mac::deliver_command_key_ups()?;
}
let family = &SettingsStore::get(cx).font_family;
anyhow::ensure!(
cx.text_system().all_font_names().contains(family),
"settings: font_family is {family:?}, which is not installed"
);
themes::apply(cx);
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 options = WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
titlebar: Some(TitlebarOptions {
title: Some(TITLE.into()),
..Default::default()
}),
..Default::default()
};
let (pty, events) = spawn(&launch, (80, 24), (8, 16), config(SettingsStore::get(cx)))?;
let window = cx.open_window(options, |window, cx| {
window
.observe_window_appearance(|_, cx| themes::apply(cx))
.detach();
let terminal = cx.new(|cx| TerminalView::new(pty, events, window, cx));
window.focus(&terminal.focus_handle(cx), cx);
cx.new(|cx| Workspace {
focus: cx.focus_handle(),
_events: cx.subscribe_in(&terminal, window, Workspace::terminal_event),
terminal,
})
})?;
log::info!("app: main window open");
Ok(window)
}