Vectrum
Sign In
116 lines · 3.6 KB · Rust
//! Vectrum Code: a minimal T3 Code-style desktop client for Claude Code.

// GPUI's derive macros expand to `gpui::` paths; route them through the Kit.
extern crate gpui_kit as gpui;

mod claude;
mod clock;
mod git;
mod http;
mod models;
mod remote;
mod session;
mod settings;
mod store;
mod textgen;
mod ui;
mod usage;
mod worktree;

use std::{
    path::PathBuf,
    sync::Mutex,
    time::{Duration, Instant},
};

use gpui_kit::component::{WindowExt as _, notification::Notification};
use gpui_kit::*;

use crate::ui::{icons::AppAssets, metal, workspace::Workspace};

gpui_kit::actions!(
    vectrum_code,
    [
        NewThread,
        OpenProject,
        Interrupt,
        ToggleSidebar,
        ToggleProjectPanel,
        FocusSearch,
        OpenSettings,
        CloseSettings,
        Quit
    ]
);

/// With the Hold quit shortcut, a second Ctrl+Q (or the key repeat of a
/// held one) within this long quits.
const QUIT_WINDOW: Duration = Duration::from_millis(1200);

fn main() {
    let project = std::env::args_os()
        .nth(1)
        .map(PathBuf::from)
        .map(|project| project.canonicalize().unwrap_or(project));

    gpui_kit::application()
        .with_assets(AppAssets)
        .run(move |cx| {
            gpui_kit::init(cx);
            metal::load_fonts(cx);
            models::Catalog::init(cx);

            cx.bind_keys([
                KeyBinding::new("ctrl-n", NewThread, None),
                KeyBinding::new("ctrl-o", OpenProject, None),
                KeyBinding::new("ctrl-b", ToggleSidebar, None),
                KeyBinding::new("ctrl-shift-b", ToggleProjectPanel, None),
                KeyBinding::new("ctrl-k", FocusSearch, None),
                KeyBinding::new("ctrl-,", OpenSettings, None),
                KeyBinding::new("ctrl-q", Quit, None),
                KeyBinding::new("escape", Interrupt, Some("ChatView")),
                KeyBinding::new("escape", CloseSettings, Some("SettingsView")),
            ]);
            cx.on_action(quit);
            cx.on_window_closed(|cx, _| cx.quit()).detach();

            let bounds = Bounds::centered(None, size(px(1280.), px(840.)), cx);
            let options = WindowOptions {
                window_bounds: Some(WindowBounds::Windowed(bounds)),
                titlebar: Some(TitlebarOptions {
                    title: Some("Vectrum Code".into()),
                    ..Default::default()
                }),
                app_id: Some("vectrum-code".into()),
                window_min_size: Some(size(px(820.), px(520.))),
                ..Default::default()
            };
            gpui_kit::open_window(options, cx, |window, cx| {
                metal::sync_appearance(window, cx);
                cx.new(|cx| Workspace::new(project, window, cx))
            })
            .expect("failed to open the main window");
            cx.activate(true);
        });
}

/// Quits, or with the Hold shortcut, asks for the keys to be held or pressed
/// again.
fn quit(_: &Quit, cx: &mut App) {
    static FIRST_PRESS: Mutex<Option<Instant>> = Mutex::new(None);
    if settings::get(|settings| settings.quit_shortcut) == settings::QuitShortcut::Press {
        cx.quit();
        return;
    }
    let mut first = FIRST_PRESS.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
    if first.is_some_and(|at| at.elapsed() < QUIT_WINDOW) {
        cx.quit();
        return;
    }
    *first = Some(Instant::now());
    if let Some(window) = cx.active_window() {
        let _ = window.update(cx, |_, window, cx| {
            window.push_notification(Notification::info("Hold Ctrl+Q, or press it again, to quit."), cx);
        });
    }
}