From fcd400331ddc29676a4358953111661f3bd7ee10 Mon Sep 17 00:00:00 2001 From: Grant G Date: Thu, 9 Jan 2025 12:47:10 -0800 Subject: [PATCH] chore: various cleanup in the codebase (#342) * random stuff * fix stuff --- Cargo.lock | 17 --- Cargo.toml | 1 - crates/dbus/Cargo.toml | 1 - crates/dbus/src/dbus/mod.rs | 7 +- crates/fig_api_client/Cargo.toml | 1 - crates/fig_auth/Cargo.toml | 1 - crates/fig_aws_common/src/lib.rs | 8 +- crates/fig_desktop/Cargo.toml | 1 - crates/fig_desktop/fuzz/Cargo.toml | 1 - .../fuzz/fuzz_targets/local_ipc.rs | 8 +- crates/fig_desktop/src/event.rs | 19 ++-- crates/fig_desktop/src/local_ipc/commands.rs | 9 +- crates/fig_desktop/src/main.rs | 6 +- crates/fig_desktop/src/notification_bus.rs | 33 +++--- .../fig_desktop/src/platform/linux/icons.rs | 8 +- .../src/platform/linux/integrations.rs | 6 +- crates/fig_desktop/src/platform/macos.rs | 34 +++--- crates/fig_desktop/src/platform/windows.rs | 8 +- crates/fig_desktop/src/protocol/api.rs | 103 +++++++++--------- crates/fig_desktop/src/protocol/icons.rs | 60 +++++----- crates/fig_desktop/src/protocol/resource.rs | 10 +- crates/fig_desktop/src/protocol/spec.rs | 13 ++- crates/fig_desktop/src/protocol/util.rs | 58 ++++++++-- crates/fig_desktop/src/remote_ipc/mod.rs | 29 ----- crates/fig_desktop/src/request/properties.rs | 4 +- crates/fig_desktop/src/request/window.rs | 3 +- crates/fig_desktop/src/utils.rs | 49 ++++----- .../fig_desktop/src/webview/autocomplete.rs | 5 +- crates/fig_desktop/src/webview/mod.rs | 14 +-- crates/fig_desktop/src/webview/window.rs | 34 ++---- crates/fig_desktop_api/Cargo.toml | 1 - crates/fig_desktop_api/src/requests/auth.rs | 8 +- crates/fig_install/src/index.rs | 33 +++--- crates/fig_log/Cargo.toml | 1 - crates/fig_log/src/lib.rs | 15 ++- crates/fig_proto/Cargo.toml | 1 - crates/fig_proto/src/lib.rs | 4 +- crates/fig_request/Cargo.toml | 1 - crates/fig_request/src/midway.rs | 10 +- crates/fig_request/src/reqwest_client.rs | 18 +-- crates/fig_settings/Cargo.toml | 1 - crates/fig_settings/src/sqlite/mod.rs | 4 +- crates/fig_telemetry/Cargo.toml | 1 - crates/fig_telemetry/src/install_method.rs | 4 +- crates/fig_telemetry/src/lib.rs | 4 +- crates/fig_util/src/terminal.rs | 49 ++++++++- crates/figterm/Cargo.toml | 1 - crates/figterm/src/event_handler.rs | 2 +- crates/figterm/src/inline/mod.rs | 7 +- crates/figterm/src/interceptor.rs | 7 +- crates/figterm/src/main.rs | 34 +++--- crates/figterm/src/message.rs | 12 +- crates/macos-utils/Cargo.toml | 1 - crates/q_cli/Cargo.toml | 1 - crates/q_cli/src/cli/chat/api.rs | 4 +- crates/q_cli/src/cli/init.rs | 4 +- crates/q_cli/src/cli/translate.rs | 4 +- packages/api-bindings/src/core.ts | 25 ++--- packages/api-bindings/src/global.d.ts | 10 -- packages/types/global.d.ts | 5 +- pnpm-lock.yaml | 5 +- tests/fig-api/package.json | 3 +- tests/fig-api/src/fs.test.ts | 2 +- tests/fig-api/src/setup.ts | 2 +- tests/fig-api/tsconfig.json | 7 +- 65 files changed, 421 insertions(+), 421 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cce7db4f4..e0158ed07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2231,7 +2231,6 @@ dependencies = [ "fig_os_shim", "fig_util", "futures-lite", - "once_cell", "serde", "serde_json", "thiserror 2.0.10", @@ -2693,7 +2692,6 @@ dependencies = [ "fig_settings", "fig_util", "http 1.2.0", - "once_cell", "regex", "serde", "serde_json", @@ -2729,7 +2727,6 @@ dependencies = [ "hyper 1.5.2", "hyper-util", "insta", - "once_cell", "percent-encoding", "rand 0.8.5", "reqwest", @@ -2807,7 +2804,6 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "once_cell", "parking_lot", "paste", "percent-encoding", @@ -2845,7 +2841,6 @@ dependencies = [ "fig_proto", "fig_util", "libfuzzer-sys", - "once_cell", "tempfile", "tokio", ] @@ -2873,7 +2868,6 @@ dependencies = [ "fig_util", "fnv", "macos-utils", - "once_cell", "reqwest", "serde", "serde_json", @@ -3022,7 +3016,6 @@ version = "1.6.0" dependencies = [ "console-subscriber", "fig_util", - "once_cell", "parking_lot", "tempfile", "thiserror 2.0.10", @@ -3053,7 +3046,6 @@ dependencies = [ "fig_util", "hex", "nix 0.29.0", - "once_cell", "prost", "prost-build", "prost-reflect", @@ -3093,7 +3085,6 @@ dependencies = [ "fig_settings", "fig_util", "mockito", - "once_cell", "reqwest", "reqwest_cookie_store", "rustls 0.23.20", @@ -3116,7 +3107,6 @@ dependencies = [ "fd-lock", "fig_test", "fig_util", - "once_cell", "parking_lot", "r2d2", "r2d2_sqlite", @@ -3156,7 +3146,6 @@ dependencies = [ "fig_telemetry_core", "fig_util", "macos-utils", - "once_cell", "serde", "serde_json", "thiserror 2.0.10", @@ -3273,7 +3262,6 @@ dependencies = [ "mimalloc", "nix 0.29.0", "num-traits", - "once_cell", "parking_lot", "pin-project", "portable-pty", @@ -5031,7 +5019,6 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "once_cell", "tokio", "tracing", ] @@ -5989,9 +5976,6 @@ name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -dependencies = [ - "parking_lot_core", -] [[package]] name = "oorandom" @@ -6771,7 +6755,6 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "once_cell", "owo-colors 4.1.0", "parking_lot", "paste", diff --git a/Cargo.toml b/Cargo.toml index da5185806..14408e0a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,7 +91,6 @@ objc2 = "0.5.2" objc2-app-kit = "0.2.2" objc2-foundation = "0.2.2" objc2-input-method-kit = "0.2.2" -once_cell = { version = "1.18.0", features = ["parking_lot"] } percent-encoding = "2.2.0" portable-pty = "0.8.1" rand = "0.8.5" diff --git a/crates/dbus/Cargo.toml b/crates/dbus/Cargo.toml index f9bde679b..643cd816d 100644 --- a/crates/dbus/Cargo.toml +++ b/crates/dbus/Cargo.toml @@ -14,7 +14,6 @@ async_zip = { version = "0.0.17", features = ["deflate"] } fig_os_shim.workspace = true fig_util.workspace = true futures-lite = "2.3.0" -once_cell.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/crates/dbus/src/dbus/mod.rs b/crates/dbus/src/dbus/mod.rs index 12b8e375d..336dee247 100644 --- a/crates/dbus/src/dbus/mod.rs +++ b/crates/dbus/src/dbus/mod.rs @@ -1,5 +1,6 @@ +use std::sync::OnceLock; + use fig_os_shim::Context; -use once_cell::sync::OnceCell; use thiserror::Error; use tokio::sync::Mutex; use zbus::Connection; @@ -26,7 +27,7 @@ pub enum CrateError { Fdo(#[from] zbus::fdo::Error), } -static SESSION_BUS: OnceCell = OnceCell::new(); +static SESSION_BUS: OnceLock = OnceLock::new(); static SESSION_BUS_INIT: Mutex<()> = Mutex::const_new(()); async fn session_bus() -> Result<&'static Connection, CrateError> { @@ -47,7 +48,7 @@ async fn session_bus() -> Result<&'static Connection, CrateError> { Ok(SESSION_BUS.get().unwrap()) } -static IBUS_BUS: OnceCell = OnceCell::new(); +static IBUS_BUS: OnceLock = OnceLock::new(); static IBUS_BUS_INIT: Mutex<()> = Mutex::const_new(()); pub async fn ibus_bus(ctx: &Context) -> Result<&'static Connection, CrateError> { diff --git a/crates/fig_api_client/Cargo.toml b/crates/fig_api_client/Cargo.toml index df3cc3c5d..972b889cf 100644 --- a/crates/fig_api_client/Cargo.toml +++ b/crates/fig_api_client/Cargo.toml @@ -32,7 +32,6 @@ fig_request.workspace = true fig_settings.workspace = true fig_util.workspace = true http = "1.1.0" -once_cell.workspace = true regex.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/fig_auth/Cargo.toml b/crates/fig_auth/Cargo.toml index 5e5c7b2e9..5bfd1a87a 100644 --- a/crates/fig_auth/Cargo.toml +++ b/crates/fig_auth/Cargo.toml @@ -27,7 +27,6 @@ fig_util.workspace = true http-body-util = "0.1.1" hyper = { version = "1.5.2", features = ["server"] } hyper-util = { version = "0.1.5", features = ["tokio"] } -once_cell.workspace = true percent-encoding.workspace = true rand.workspace = true serde.workspace = true diff --git a/crates/fig_aws_common/src/lib.rs b/crates/fig_aws_common/src/lib.rs index 9fff55788..3795f1cfc 100644 --- a/crates/fig_aws_common/src/lib.rs +++ b/crates/fig_aws_common/src/lib.rs @@ -1,7 +1,7 @@ mod sdk_error_display; mod user_agent_override_interceptor; -use std::sync::OnceLock; +use std::sync::LazyLock; use aws_smithy_runtime_api::client::behavior_version::BehaviorVersion; use aws_types::app_name::AppName; @@ -11,10 +11,8 @@ pub use user_agent_override_interceptor::UserAgentOverrideInterceptor; const APP_NAME_STR: &str = "AmazonQ-For-CLI"; pub fn app_name() -> AppName { - static APP_NAME: OnceLock = OnceLock::new(); - APP_NAME - .get_or_init(|| AppName::new(APP_NAME_STR).expect("invalid app name")) - .clone() + static APP_NAME: LazyLock = LazyLock::new(|| AppName::new(APP_NAME_STR).expect("invalid app name")); + APP_NAME.clone() } pub fn behavior_version() -> BehaviorVersion { diff --git a/crates/fig_desktop/Cargo.toml b/crates/fig_desktop/Cargo.toml index 9176ad131..4fbd09348 100644 --- a/crates/fig_desktop/Cargo.toml +++ b/crates/fig_desktop/Cargo.toml @@ -67,7 +67,6 @@ mime = "0.3.17" moka = { version = "0.12.1", features = ["future"] } muda = { version = "0.15.3", default-features = false } notify = "7.0.0" -once_cell.workspace = true parking_lot = { version = "0.12.1", features = ["serde"] } paste = "1.0.11" percent-encoding.workspace = true diff --git a/crates/fig_desktop/fuzz/Cargo.toml b/crates/fig_desktop/fuzz/Cargo.toml index be58be6f6..bdcb5d704 100644 --- a/crates/fig_desktop/fuzz/Cargo.toml +++ b/crates/fig_desktop/fuzz/Cargo.toml @@ -14,7 +14,6 @@ fig_util.workspace = true tempfile.workspace = true tokio.workspace = true fig_proto = { workspace = true, features = ["arbitrary"] } -once_cell.workspace = true [[bin]] name = "local_ipc" diff --git a/crates/fig_desktop/fuzz/fuzz_targets/local_ipc.rs b/crates/fig_desktop/fuzz/fuzz_targets/local_ipc.rs index f1ace476d..84d13d875 100644 --- a/crates/fig_desktop/fuzz/fuzz_targets/local_ipc.rs +++ b/crates/fig_desktop/fuzz/fuzz_targets/local_ipc.rs @@ -5,6 +5,7 @@ extern crate libfuzzer_sys; use std::ops::Deref; use std::path::PathBuf; +use std::sync::LazyLock; use fig_ipc::{ BufferedUnixStream, @@ -13,12 +14,11 @@ use fig_ipc::{ }; use fig_proto::local::LocalMessage; use libfuzzer_sys::fuzz_target; -use once_cell::sync::Lazy; use tokio::net::UnixListener; -static RUNTIME: Lazy = Lazy::new(|| tokio::runtime::Runtime::new().unwrap()); +static RUNTIME: LazyLock = LazyLock::new(|| tokio::runtime::Runtime::new().unwrap()); -static DIRSOCK: Lazy<(tempfile::TempDir, PathBuf)> = Lazy::new(|| { +static DIRSOCK: LazyLock<(tempfile::TempDir, PathBuf)> = LazyLock::new(|| { let temp_dir = tempfile::tempdir().unwrap(); let socket_path = temp_dir.path().join("test.sock"); #[cfg(unix)] @@ -31,7 +31,7 @@ static DIRSOCK: Lazy<(tempfile::TempDir, PathBuf)> = Lazy::new(|| { (temp_dir, socket_path) }); -static LISTENER: Lazy = Lazy::new(|| UnixListener::bind(&DIRSOCK.1).unwrap()); +static LISTENER: LazyLock = LazyLock::new(|| UnixListener::bind(&DIRSOCK.1).unwrap()); fuzz_target!(|input: LocalMessage| { RUNTIME.block_on(fuzz(input)); diff --git a/crates/fig_desktop/src/event.rs b/crates/fig_desktop/src/event.rs index 4e05d4960..9b27f417a 100644 --- a/crates/fig_desktop/src/event.rs +++ b/crates/fig_desktop/src/event.rs @@ -7,6 +7,7 @@ use tao::dpi::{ Size, }; use tao::event_loop::ControlFlow; +use tokio::sync::mpsc::UnboundedSender; use wry::Theme; use crate::platform::PlatformBoundEvent; @@ -73,6 +74,11 @@ pub enum WindowPosition { }, } +pub struct WindowGeometryResult { + pub is_above: bool, + pub is_clipped: bool, +} + #[derive(Debug, Clone)] pub enum WindowEvent { /// Sets the window to be enabled or disabled @@ -81,15 +87,13 @@ pub enum WindowEvent { /// [`WindowEvent::SetEnabled(true)`] SetEnabled(bool), /// Sets the theme of the window (light, dark, or system if None) - /// - /// This is currently unimplemented blocked on SetTheme(Option), UpdateWindowGeometry { position: Option, size: Option>, anchor: Option>, dry_run: bool, - tx: Option>, + tx: Option>, }, /// Hides the window Hide, @@ -114,20 +118,13 @@ pub enum WindowEvent { Reload, - /// Trigger a reload if the page is not already loaded - ReloadIfNotLoaded, - Api { /// A base64 encoded protobuf - payload: Cow<'static, str>, + payload: String, }, Devtools, DebugMode(bool), - SetHtml { - html: Cow<'static, str>, - }, - Drag, Batch(Vec), } diff --git a/crates/fig_desktop/src/local_ipc/commands.rs b/crates/fig_desktop/src/local_ipc/commands.rs index 6678a7ee3..f000b9e77 100644 --- a/crates/fig_desktop/src/local_ipc/commands.rs +++ b/crates/fig_desktop/src/local_ipc/commands.rs @@ -1,3 +1,5 @@ +use std::sync::Mutex; + use fig_os_shim::{ ContextArcProvider, ContextProvider, @@ -20,7 +22,6 @@ use fig_proto::local::{ use fig_remote_ipc::figterm::FigtermState; use fig_settings::StateProvider; use fig_settings::settings::SettingsProvider; -use parking_lot::Mutex; use tao::event_loop::ControlFlow; use tracing::error; @@ -47,16 +48,16 @@ pub async fn debug(command: DebugModeCommand, proxy: &EventLoopProxy) -> LocalRe let debug_mode = match command.set_debug_mode { Some(b) => { - *DEBUG_MODE.lock() = b; + *DEBUG_MODE.lock().unwrap() = b; b }, None => match command.toggle_debug_mode { Some(true) => { - let mut locked_debug = DEBUG_MODE.lock(); + let mut locked_debug = DEBUG_MODE.lock().unwrap(); *locked_debug = !*locked_debug; *locked_debug }, - _ => *DEBUG_MODE.lock(), + _ => *DEBUG_MODE.lock().unwrap(), }, }; diff --git a/crates/fig_desktop/src/main.rs b/crates/fig_desktop/src/main.rs index f05be6f4c..5ebaaf41b 100644 --- a/crates/fig_desktop/src/main.rs +++ b/crates/fig_desktop/src/main.rs @@ -17,7 +17,10 @@ mod webview; use std::path::Path; use std::process::exit; -use std::sync::Arc; +use std::sync::{ + Arc, + RwLock, +}; use clap::Parser; use event::Event; @@ -34,7 +37,6 @@ use fig_util::{ URL_SCHEMA, directories, }; -use parking_lot::RwLock; use platform::PlatformState; use sysinfo::{ ProcessRefreshKind, diff --git a/crates/fig_desktop/src/notification_bus.rs b/crates/fig_desktop/src/notification_bus.rs index beff784ca..6251dd660 100644 --- a/crates/fig_desktop/src/notification_bus.rs +++ b/crates/fig_desktop/src/notification_bus.rs @@ -1,6 +1,8 @@ +use std::sync::LazyLock; + use dashmap::DashMap; use fnv::FnvBuildHasher; -use once_cell::sync::Lazy; +use serde_json::Value; use tokio::sync::broadcast::{ self, Receiver, @@ -9,24 +11,17 @@ use tokio::sync::broadcast::{ const CHANNEL_SIZE: usize = 8; -pub static NOTIFICATION_BUS: Lazy = Lazy::new(NotificationBus::new); +pub static NOTIFICATION_BUS: LazyLock = LazyLock::new(NotificationBus::new); #[derive(Debug, Clone)] pub enum JsonNotification { - NewValue { - new: serde_json::Value, - }, - ChangedValue { - old: serde_json::Value, - new: serde_json::Value, - }, - RemoveValue { - old: serde_json::Value, - }, + NewValue { new: Value }, + ChangedValue { old: Value, new: Value }, + RemoveValue { old: Value }, } impl JsonNotification { - pub fn value(self) -> Option { + pub fn value(self) -> Option { match self { JsonNotification::NewValue { new } => Some(new), JsonNotification::ChangedValue { new, .. } => Some(new), @@ -105,19 +100,19 @@ impl NotificationBus { self.midway_channel.send(()).ok(); } - pub fn send_state_new(&self, key: impl AsRef, value: &serde_json::Value) { + pub fn send_state_new(&self, key: impl AsRef, value: &Value) { if let Some(tx) = self.state_channels.get(key.as_ref()) { tx.send(JsonNotification::NewValue { new: value.clone() }).ok(); } } - pub fn send_state_remove(&self, key: impl AsRef, value: &serde_json::Value) { + pub fn send_state_remove(&self, key: impl AsRef, value: &Value) { if let Some(tx) = self.state_channels.get(key.as_ref()) { tx.send(JsonNotification::RemoveValue { old: value.clone() }).ok(); } } - pub fn send_state_changed(&self, key: impl AsRef, old: &serde_json::Value, new: &serde_json::Value) { + pub fn send_state_changed(&self, key: impl AsRef, old: &Value, new: &Value) { if let Some(tx) = self.state_channels.get(key.as_ref()) { tx.send(JsonNotification::ChangedValue { old: old.clone(), @@ -127,19 +122,19 @@ impl NotificationBus { } } - pub fn send_settings_new(&self, key: impl AsRef, value: &serde_json::Value) { + pub fn send_settings_new(&self, key: impl AsRef, value: &Value) { if let Some(tx) = self.settings_channels.get(key.as_ref()) { tx.send(JsonNotification::NewValue { new: value.clone() }).ok(); } } - pub fn send_settings_remove(&self, key: impl AsRef, value: &serde_json::Value) { + pub fn send_settings_remove(&self, key: impl AsRef, value: &Value) { if let Some(tx) = self.settings_channels.get(key.as_ref()) { tx.send(JsonNotification::RemoveValue { old: value.clone() }).ok(); } } - pub fn send_settings_changed(&self, key: impl AsRef, old: &serde_json::Value, new: &serde_json::Value) { + pub fn send_settings_changed(&self, key: impl AsRef, old: &Value, new: &Value) { if let Some(tx) = self.settings_channels.get(key.as_ref()) { tx.send(JsonNotification::ChangedValue { old: old.clone(), diff --git a/crates/fig_desktop/src/platform/linux/icons.rs b/crates/fig_desktop/src/platform/linux/icons.rs index c05b93fef..fb43605ad 100644 --- a/crates/fig_desktop/src/platform/linux/icons.rs +++ b/crates/fig_desktop/src/platform/linux/icons.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; use std::process::Command; +use std::sync::Mutex; use anyhow::Result; use fig_settings::settings; -use parking_lot::Mutex; use tracing::{ error, info, @@ -15,7 +15,7 @@ use crate::protocol::icons::{ process_asset, }; -static SELECTED_THEME: Mutex> = parking_lot::const_mutex(Cow::Borrowed("hicolor")); +static SELECTED_THEME: Mutex> = Mutex::new(Cow::Borrowed("hicolor")); pub fn init() -> Result<()> { let mut use_local = true; @@ -50,7 +50,7 @@ pub fn init() -> Result<()> { fn set_theme(theme: String) -> Result<()> { if freedesktop_icons::list_themes().contains(&theme.as_str()) || theme == "hicolor" { - *SELECTED_THEME.lock() = Cow::Owned(theme); + *SELECTED_THEME.lock().unwrap() = Cow::Owned(theme); Ok(()) } else { warn!("invalid theme: {theme}"); @@ -59,7 +59,7 @@ fn set_theme(theme: String) -> Result<()> { } fn get_theme() -> String { - SELECTED_THEME.lock().to_string() + SELECTED_THEME.lock().unwrap().to_string() } pub(super) async fn lookup(name: &str) -> Option { diff --git a/crates/fig_desktop/src/platform/linux/integrations.rs b/crates/fig_desktop/src/platform/linux/integrations.rs index 6da4b3618..56ba3a0f9 100644 --- a/crates/fig_desktop/src/platform/linux/integrations.rs +++ b/crates/fig_desktop/src/platform/linux/integrations.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::sync::LazyLock; use std::sync::atomic::Ordering; use anyhow::{ @@ -7,7 +8,6 @@ use anyhow::{ }; use fig_proto::local::FocusedWindowDataHook; use fig_util::Terminal; -use once_cell::sync::Lazy; use tracing::debug; use super::WM_REVICED_DATA; @@ -24,7 +24,7 @@ use crate::{ EventLoopProxy, }; -pub static WM_CLASS_ALLOWLIST: Lazy> = Lazy::new(|| { +pub static WM_CLASS_ALLOWLIST: LazyLock> = LazyLock::new(|| { let mut allowlist = HashMap::new(); for terminal in fig_util::terminal::LINUX_TERMINALS { if let Some(wm_class) = terminal.wm_class() { @@ -34,7 +34,7 @@ pub static WM_CLASS_ALLOWLIST: Lazy> = Lazy::new allowlist }); -pub static GSE_ALLOWLIST: Lazy> = Lazy::new(|| { +pub static GSE_ALLOWLIST: LazyLock> = LazyLock::new(|| { let mut allowlist = HashMap::new(); for terminal in fig_util::terminal::LINUX_TERMINALS { // Using wm_class_instance here since on Wayland, (most?) terminals set the app_id equal to diff --git a/crates/fig_desktop/src/platform/macos.rs b/crates/fig_desktop/src/platform/macos.rs index ff9d4cc11..d7466d137 100644 --- a/crates/fig_desktop/src/platform/macos.rs +++ b/crates/fig_desktop/src/platform/macos.rs @@ -4,11 +4,16 @@ use std::ffi::CString; use std::path::Path; use std::slice; -use std::sync::Arc; use std::sync::atomic::{ AtomicBool, Ordering, }; +use std::sync::{ + Arc, + LazyLock, + Mutex, + RwLock, +}; use accessibility_sys::{ AXError, @@ -69,11 +74,6 @@ use objc2_foundation::{ NSOperationQueue, ns_string, }; -use once_cell::sync::Lazy; -use parking_lot::{ - Mutex, - RwLock, -}; use serde::Serialize; use tao::dpi::{ LogicalPosition, @@ -128,14 +128,14 @@ pub const DEFAULT_CARET_WIDTH: f64 = 10.0; #[allow(non_upper_case_globals)] const kCGFloatingWindowLevelKey: i32 = 5; -static UNMANAGED: Lazy = Lazy::new(|| Unmanaged { +static UNMANAGED: Unmanaged = Unmanaged { event_sender: RwLock::new(Option::::None), window_server: RwLock::new(Option::>>::None), -}); +}; -static ACCESSIBILITY_ENABLED: Lazy = Lazy::new(|| AtomicBool::new(accessibility_is_enabled())); +static ACCESSIBILITY_ENABLED: LazyLock = LazyLock::new(|| AtomicBool::new(accessibility_is_enabled())); -static MACOS_VERSION: Lazy = Lazy::new(|| { +static MACOS_VERSION: LazyLock = LazyLock::new(|| { let version = macos_utils::os::OperatingSystemVersion::get(); semver::Version::new(version.major() as u64, version.minor() as u64, version.patch() as u64) }); @@ -317,12 +317,13 @@ impl PlatformStateImpl { } } - UNMANAGED.event_sender.write().replace(self.proxy.clone()); + UNMANAGED.event_sender.write().unwrap().replace(self.proxy.clone()); let (tx, rx) = flume::unbounded::(); UNMANAGED .window_server .write() + .unwrap() .replace(Arc::new(Mutex::new(WindowServer::new(tx)))); let accessibility_proxy = self.proxy.clone(); @@ -522,7 +523,7 @@ impl PlatformStateImpl { .unwrap(); }); - let mut focused = self.focused_window.lock(); + let mut focused = self.focused_window.lock().unwrap(); focused.replace(window); } @@ -567,7 +568,7 @@ impl PlatformStateImpl { } }; - let mut policy_lock = ACTIVATION_POLICY.lock(); + let mut policy_lock = ACTIVATION_POLICY.lock().unwrap(); if *policy_lock != policy { debug!(?policy, "Setting application policy"); *policy_lock = policy; @@ -653,7 +654,7 @@ impl PlatformStateImpl { Ok(()) }, PlatformBoundEvent::WindowDestroyed { app } => { - let mut focused = self.focused_window.lock(); + let mut focused = self.focused_window.lock().unwrap(); if let Some(focused_window) = focused.as_ref() { if focused_window.bundle_id() == app.bundle_id { focused.take(); @@ -671,7 +672,7 @@ impl PlatformStateImpl { } fn refresh_window_position(&self) -> anyhow::Result<()> { - let mut guard = self.focused_window.lock(); + let mut guard = self.focused_window.lock().unwrap(); let active_window = guard.as_mut().context("No active window")?; let current_terminal = Terminal::from_bundle_id(active_window.bundle_id()); @@ -707,6 +708,7 @@ impl PlatformStateImpl { UNMANAGED .event_sender .read() + .unwrap() .clone() .unwrap() .send_event(Event::WindowEvent { @@ -756,7 +758,7 @@ impl PlatformStateImpl { /// Gets the currently active window on the platform pub(super) fn get_active_window(&self) -> Option { - let active_window = self.focused_window.lock().as_ref()?.clone(); + let active_window = self.focused_window.lock().unwrap().as_ref()?.clone(); Some(PlatformWindow { rect: active_window.get_bounds()?.into(), inner: active_window, diff --git a/crates/fig_desktop/src/platform/windows.rs b/crates/fig_desktop/src/platform/windows.rs index 361db54fe..3b7ab10f7 100644 --- a/crates/fig_desktop/src/platform/windows.rs +++ b/crates/fig_desktop/src/platform/windows.rs @@ -1,10 +1,12 @@ use std::borrow::Cow; use std::ffi::CStr; use std::mem::ManuallyDrop; -use std::sync::Arc; +use std::sync::{ + Arc, + LazyLock, +}; use anyhow::anyhow; -use once_cell::sync::Lazy; use parking_lot::Mutex; use tao::dpi::Position; use tracing::{ @@ -98,7 +100,7 @@ const VT_TRUE: VARIANT = VARIANT { }, }; -static UNMANAGED: Lazy> = Lazy::new(|| { +static UNMANAGED: LazyLock> = LazyLock::new(|| { Mutex::new(Unmanaged { event_sender: None, location_hook: None, diff --git a/crates/fig_desktop/src/protocol/api.rs b/crates/fig_desktop/src/protocol/api.rs index 25ae8b13d..02d976a06 100644 --- a/crates/fig_desktop/src/protocol/api.rs +++ b/crates/fig_desktop/src/protocol/api.rs @@ -39,15 +39,24 @@ pub async fn handle( window_id: WindowId, ) -> anyhow::Result>> { if request.method() != Method::POST { - anyhow::bail!("Unsupported method: {}", request.method()); + let body = format!("Unsupported method: {}", request.method()); + return Ok(Response::builder() + .status(StatusCode::METHOD_NOT_ALLOWED) + .body(Cow::Owned(body.into()))?); } - match request.headers().get(CONTENT_TYPE) { - Some(val) if val == APPLICATION_FIG_API => {}, - Some(val) => anyhow::bail!("Unsupported content type: {val:?}"), - None => anyhow::bail!("Missing content type"), + let unsupported_media_body = match request.headers().get(CONTENT_TYPE) { + Some(val) if val == APPLICATION_FIG_API => None, + Some(val) => Some(format!("Unsupported content type: {val:?}")), + None => Some("Missing content type".into()), }; + if let Some(body) = unsupported_media_body { + return Ok(Response::builder() + .status(StatusCode::UNSUPPORTED_MEDIA_TYPE) + .body(Cow::Owned(body.into()))?); + } + let client_message = ClientOriginatedMessage::decode(Bytes::from(request.into_body()))?; let server_message = fig_desktop_api::handler::api_request( EventHandler::default(), @@ -74,50 +83,40 @@ pub async fn handle( .body(body)?) } -// TODO: Add back -// -// #[cfg(test)] -// mod tests { -// use fig_desktop_api::handler::{ -// ClientOriginatedSubMessage, -// ServerOriginatedSubMessage, -// }; -// use fig_proto::fig::{ -// ClientOriginatedMessage, -// PingRequest, -// PingResponse, -// ServerOriginatedMessage, -// }; -// -// use super::*; -// use crate::AUTOCOMPLETE_ID; -// -// #[tokio::test] -// async fn test_handle() { -// let body = ClientOriginatedMessage { -// id: Some(0), -// submessage: Some(ClientOriginatedSubMessage::PingRequest(PingRequest {})), -// } -// .encode_to_vec(); -// -// let request = Request::builder() -// .method(Method::POST) -// .header(CONTENT_TYPE, APPLICATION_FIG_API.clone()) -// .body(body) -// .unwrap(); -// -// let response = handle(request, AUTOCOMPLETE_ID).await.unwrap(); -// -// println!("{:?}", response); -// -// assert_eq!(response.status(), StatusCode::OK); -// assert_eq!(response.headers().get(CONTENT_TYPE).unwrap(), APPLICATION_FIG_API); -// -// let decoded_response = -// ServerOriginatedMessage::decode(Bytes::from(response.into_body().to_vec())).unwrap(); -// assert_eq!( -// decoded_response.submessage.unwrap(), -// ServerOriginatedSubMessage::PingResponse(PingResponse {}) -// ); -// } -// } +#[cfg(test)] +mod tests { + use fig_desktop_api::handler::ClientOriginatedSubMessage; + use fig_proto::fig::{ + ClientOriginatedMessage, + PingRequest, + }; + + use super::*; + use crate::AUTOCOMPLETE_ID; + + // TODO: add success case, this fails currently due to the + // globals (FIGTERM_STATE, INTERCEPT_STATE, etc) not being set in tests + + #[tokio::test] + async fn test_handle_errors() { + let ctx = OsContext::new_fake(); + let id = AUTOCOMPLETE_ID; + let body = ClientOriginatedMessage { + id: Some(0), + submessage: Some(ClientOriginatedSubMessage::PingRequest(PingRequest {})), + } + .encode_to_vec(); + + let request = Request::builder().method(Method::GET).body(body.clone()).unwrap(); + let response = handle(ctx.clone(), request, id.clone()).await.unwrap(); + assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED); + + let request = Request::builder() + .method(Method::POST) + .header(CONTENT_TYPE, "text/plain") + .body(body) + .unwrap(); + let response = handle(ctx, request, id).await.unwrap(); + assert_eq!(response.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE); + } +} diff --git a/crates/fig_desktop/src/protocol/icons.rs b/crates/fig_desktop/src/protocol/icons.rs index 98869734b..d936e507b 100644 --- a/crates/fig_desktop/src/protocol/icons.rs +++ b/crates/fig_desktop/src/protocol/icons.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::collections::HashMap; -use std::collections::hash_map::RandomState; use std::ffi::OsStr; use std::hash::Hash; use std::io::Cursor; @@ -8,7 +7,10 @@ use std::path::{ Path, PathBuf, }; -use std::sync::Arc; +use std::sync::{ + Arc, + LazyLock, +}; use std::time::Duration; use anyhow::Result; @@ -21,7 +23,6 @@ use image::{ Rgba, }; use moka::future::Cache; -use once_cell::sync::Lazy; use percent_encoding::percent_decode_str; use tracing::{ debug, @@ -37,6 +38,10 @@ use wry::http::{ }; use crate::platform::PlatformState; +use crate::protocol::util::{ + parse_hex_rgb, + scale_u8, +}; use crate::webview::WindowId; const DEFAULT_ICON: &str = "template"; @@ -47,7 +52,7 @@ pub enum AssetSpecifier<'a> { PathBased(Cow<'a, Path>), } -static ASSETS: Lazy, Arc>>> = Lazy::new(|| { +static ASSETS: LazyLock, Arc>>> = LazyLock::new(|| { let mut map = HashMap::new(); macro_rules! load_assets { @@ -73,7 +78,7 @@ static ASSETS: Lazy, Arc>>> = pub type ProcessedAsset = (Arc>, AssetKind); #[cfg_attr(not(target_os = "linux"), allow(dead_code))] -static ASSET_CACHE: Lazy> = Lazy::new(|| { +static ASSET_CACHE: LazyLock> = LazyLock::new(|| { Cache::builder() .weigher(|k: &PathBuf, v: &(Arc>, AssetKind)| { (k.as_os_str().len() + v.0.len()).try_into().unwrap_or(u32::MAX) @@ -89,6 +94,15 @@ pub enum AssetKind { Svg, } +impl AssetKind { + pub fn mime(&self) -> mime::Mime { + match self { + AssetKind::Png => mime::IMAGE_PNG, + AssetKind::Svg => mime::IMAGE_SVG, + } + } +} + #[cfg_attr(not(target_os = "linux"), allow(dead_code))] pub async fn process_asset(path: PathBuf) -> Result { if let Some(asset) = ASSET_CACHE.get(&path).await { @@ -147,10 +161,7 @@ async fn resolve_asset(asset: &AssetSpecifier<'_>, fallback: Option<&str>) -> (A fn build_asset_response(data: Cow<'static, [u8]>, asset_kind: AssetKind) -> Response> { Response::builder() .status(StatusCode::OK) - .header(CONTENT_TYPE, match asset_kind { - AssetKind::Png => "image/png", - AssetKind::Svg => "image/svg+xml", - }) + .header(CONTENT_TYPE, asset_kind.mime().essence_str()) .body(data) .unwrap() } @@ -165,10 +176,6 @@ async fn build_default() -> Response> { cached_asset_response(&AssetSpecifier::Named(DEFAULT_ICON.into()), None).await } -fn scale(a: u8, b: u8) -> u8 { - (a as f32 * (b as f32 / 256.0)) as u8 -} - pub async fn handle( _ctx: Arc, request: Request>, @@ -177,8 +184,7 @@ pub async fn handle( debug!(uri =% request.uri(), "Fig protocol request"); let url = Url::parse(&request.uri().to_string())?; let domain = url.domain(); - // rust really doesn't like us not specifying RandomState here - let pairs: HashMap<_, _, RandomState> = url.query_pairs().collect(); + let pairs: HashMap<_, _> = url.query_pairs().collect(); let res = match domain { Some("template") => { @@ -188,21 +194,15 @@ pub async fn handle( let mut image = image::load_from_memory_with_format(asset, image::ImageFormat::Png).unwrap(); if let Some(color) = query_pairs.get("color") { - if color.len() == 6 { - if let (Ok(color_r), Ok(color_g), Ok(color_b)) = ( - u8::from_str_radix(&color[0..2], 16), - u8::from_str_radix(&color[2..4], 16), - u8::from_str_radix(&color[4..6], 16), - ) { - for y in 0..image.height() { - for x in 0..image.width() { - let Rgba([r, g, b, a]) = image.get_pixel(x, y); - image.put_pixel( - x, - y, - Rgba([scale(r, color_r), scale(g, color_g), scale(b, color_b), a]), - ); - } + if let Some(rgb) = parse_hex_rgb(color) { + for y in 0..image.height() { + for x in 0..image.width() { + let Rgba([r, g, b, a]) = image.get_pixel(x, y); + image.put_pixel( + x, + y, + Rgba([scale_u8(r, rgb[0]), scale_u8(g, rgb[1]), scale_u8(b, rgb[2]), a]), + ); } } } diff --git a/crates/fig_desktop/src/protocol/resource.rs b/crates/fig_desktop/src/protocol/resource.rs index 81833e4eb..87ffcf6fe 100644 --- a/crates/fig_desktop/src/protocol/resource.rs +++ b/crates/fig_desktop/src/protocol/resource.rs @@ -51,7 +51,7 @@ pub async fn handle( let resources_path = fig_util::directories::resources_path_ctx(&ctx)?.join(S::PATH); if request.uri().host() != Some("localhost") { - return Ok(res_400()); + return res_400(); } let uri_path = Path::new(request.uri().path()); @@ -63,7 +63,7 @@ pub async fn handle( if uri_path.extension().is_none() { resources_path.join("index.html") } else { - return Ok(res_404()); + return res_404(); } }, Err(err) => return res_500(err), @@ -71,7 +71,7 @@ pub async fn handle( // dont allow escaping the resources dir if !path.starts_with(&resources_path) { - return Ok(res_400()); + return res_400(); } match path.metadata() { @@ -84,7 +84,7 @@ pub async fn handle( if uri_path.extension().is_none() { path = resources_path.join("index.html"); } else { - return Ok(res_404()); + return res_404(); } }, Err(err) => return res_500(err), @@ -94,7 +94,7 @@ pub async fn handle( let content = match std::fs::read(&path) { Ok(content) => content, - Err(err) if err.kind() == ErrorKind::NotFound => return Ok(res_404()), + Err(err) if err.kind() == ErrorKind::NotFound => return res_404(), Err(err) => return res_500(err), }; diff --git a/crates/fig_desktop/src/protocol/spec.rs b/crates/fig_desktop/src/protocol/spec.rs index a2aac5934..dcdbf35c9 100644 --- a/crates/fig_desktop/src/protocol/spec.rs +++ b/crates/fig_desktop/src/protocol/spec.rs @@ -1,5 +1,8 @@ use std::borrow::Cow; -use std::sync::Arc; +use std::sync::{ + Arc, + LazyLock, +}; use anyhow::Result; use fig_auth::builder_id_token; @@ -7,7 +10,6 @@ use fig_os_shim::Context; use fig_request::reqwest::Client; use fnv::FnvHashSet; use futures::prelude::*; -use once_cell::sync::Lazy; use serde::{ Deserialize, Serialize, @@ -29,6 +31,8 @@ use wry::http::{ use crate::webview::WindowId; +const APPLICATION_JAVASCRIPT: HeaderValue = HeaderValue::from_static("application/javascript"); + #[non_exhaustive] #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum AuthType { @@ -51,7 +55,7 @@ struct CdnSource { auth_type: AuthType, } -static CDNS: Lazy> = Lazy::new(|| { +static CDNS: LazyLock> = LazyLock::new(|| { vec![ // Public cdn CdnSource { @@ -233,7 +237,8 @@ pub async fn handle( let content_type = response .headers() .get(http::header::CONTENT_TYPE) - .map_or_else(|| "application/javascript".try_into().unwrap(), |v| v.to_owned()); + .cloned() + .unwrap_or(APPLICATION_JAVASCRIPT); Ok(res_ok( response.bytes().await?.to_vec(), diff --git a/crates/fig_desktop/src/protocol/util.rs b/crates/fig_desktop/src/protocol/util.rs index d0b123e48..2c60de878 100644 --- a/crates/fig_desktop/src/protocol/util.rs +++ b/crates/fig_desktop/src/protocol/util.rs @@ -2,26 +2,25 @@ use std::borrow::Cow; use std::error::Error; use anyhow::Result; +use image::Rgb; use wry::http::header::CONTENT_TYPE; use wry::http::{ Response, StatusCode, }; -pub fn res_404() -> Response> { - Response::builder() +pub fn res_404() -> Result>> { + Ok(Response::builder() .status(StatusCode::NOT_FOUND) .header(CONTENT_TYPE, "text/plain") - .body(b"Not Found".as_ref().into()) - .unwrap() + .body(b"Not Found".as_ref().into())?) } -pub fn res_400() -> Response> { - Response::builder() +pub fn res_400() -> Result>> { + Ok(Response::builder() .status(StatusCode::BAD_REQUEST) .header(CONTENT_TYPE, "text/plain") - .body(b"Bad Request".as_ref().into()) - .unwrap() + .body(b"Bad Request".as_ref().into())?) } pub fn res_500(err: impl Error) -> Result>> { @@ -30,3 +29,46 @@ pub fn res_500(err: impl Error) -> Result>> { .header(CONTENT_TYPE, "text/plain") .body(err.to_string().into_bytes().into())?) } + +pub fn parse_hex_rgb(s: &str) -> Option> { + if s.len() != 6 { + return None; + } + let radix = 16; + Some(Rgb([ + u8::from_str_radix(&s[0..2], radix).ok()?, + u8::from_str_radix(&s[2..4], radix).ok()?, + u8::from_str_radix(&s[4..6], radix).ok()?, + ])) +} + +pub const fn scale_u8(a: u8, b: u8) -> u8 { + ((a as u16 * b as u16) / 256) as u8 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_hex_color() { + assert_eq!(parse_hex_rgb("000000"), Some(Rgb([0, 0, 0]))); + assert_eq!(parse_hex_rgb("ffffff"), Some(Rgb([255, 255, 255]))); + assert_eq!(parse_hex_rgb("ff0000"), Some(Rgb([255, 0, 0]))); + assert_eq!(parse_hex_rgb("00ff00"), Some(Rgb([0, 255, 0]))); + assert_eq!(parse_hex_rgb("0000ff"), Some(Rgb([0, 0, 255]))); + assert_eq!(parse_hex_rgb("00000f"), Some(Rgb([0, 0, 15]))); + assert_eq!(parse_hex_rgb("00000"), None); + assert_eq!(parse_hex_rgb("0000000"), None); + assert_eq!(parse_hex_rgb("00000g"), None); + } + + #[test] + fn test_scale() { + assert_eq!(scale_u8(0, 0), 0); + assert_eq!(scale_u8(128, 0), 0); + assert_eq!(scale_u8(255, 0), 0); + assert_eq!(scale_u8(128, 128), 64); + assert_eq!(scale_u8(255, 255), 254); + } +} diff --git a/crates/fig_desktop/src/remote_ipc/mod.rs b/crates/fig_desktop/src/remote_ipc/mod.rs index 2ee109b90..0dfdae58b 100644 --- a/crates/fig_desktop/src/remote_ipc/mod.rs +++ b/crates/fig_desktop/src/remote_ipc/mod.rs @@ -67,8 +67,6 @@ impl fig_remote_ipc::RemoteHookHandler for RemoteHook { hook: &EditBufferHook, session_id: &FigtermSessionId, figterm_state: &Arc, - // notifications_state: &WebviewNotificationsState, - // proxy: &EventLoopProxy, ) -> Result> { let _old_metrics = figterm_state.with_update(session_id.clone(), |session| { session.edit_buffer.text.clone_from(&hook.text); @@ -96,33 +94,6 @@ impl fig_remote_ipc::RemoteHookHandler for RemoteHook { } }); - // if let Some(metrics) = old_metrics.flatten() { - // if metrics.end_time > metrics.start_time { - // let properties: Vec<(&str, serde_json::Value)> = vec![ - // ("start_time", metrics.start_time.format(&Rfc3339)?.into()), - // ("end_time", metrics.end_time.format(&Rfc3339)?.into()), - // ( - // "duration", - // (metrics.end_time - metrics.start_time).whole_seconds().into(), - // ), - // ("num_insertions", metrics.num_insertions.into()), - // ("num_popups", metrics.num_popups.into()), - // ]; - // //tokio::spawn(async { - // if let Err(err) = fig_telemetry::emit_track(fig_telemetry::TrackEvent::new( - // fig_telemetry::TrackEventType::TerminalSessionMetricsRecorded, - // fig_telemetry::TrackSource::Desktop, - // env!("CARGO_PKG_VERSION").into(), - // properties, - // )) - // .await - // { - // warn!(%err, "Failed to record terminal session metrics"); - // } - // }); - // } - // } - let utf16_cursor_position = hook .text .get(..hook.cursor as usize) diff --git a/crates/fig_desktop/src/request/properties.rs b/crates/fig_desktop/src/request/properties.rs index 85f8ab8f5..c0625bb4f 100644 --- a/crates/fig_desktop/src/request/properties.rs +++ b/crates/fig_desktop/src/request/properties.rs @@ -23,11 +23,11 @@ pub fn update( intercept_state: &InterceptState, ) -> RequestResult { if let Some(intercept_bound_keystrokes) = request.intercept_bound_keystrokes { - *intercept_state.intercept_bound_keystrokes.write() = intercept_bound_keystrokes; + *intercept_state.intercept_bound_keystrokes.write().unwrap() = intercept_bound_keystrokes; } if let Some(intercept_global_keystrokes) = request.intercept_global_keystrokes { - *intercept_state.intercept_global_keystrokes.write() = intercept_global_keystrokes; + *intercept_state.intercept_global_keystrokes.write().unwrap() = intercept_global_keystrokes; } let key_bindings = KeyBindings::load_from_settings("autocomplete") diff --git a/crates/fig_desktop/src/request/window.rs b/crates/fig_desktop/src/request/window.rs index 97ee718fa..b48cc12df 100644 --- a/crates/fig_desktop/src/request/window.rs +++ b/crates/fig_desktop/src/request/window.rs @@ -17,6 +17,7 @@ use super::{ use crate::event::{ Event, WindowEvent, + WindowGeometryResult, }; use crate::webview::WindowId; use crate::{ @@ -80,7 +81,7 @@ pub async fn position_window( .unwrap(); match rx.recv().await { - Some((is_above, is_clipped)) => RequestResult::Ok(Box::new( + Some(WindowGeometryResult { is_above, is_clipped }) => RequestResult::Ok(Box::new( ServerOriginatedSubMessage::PositionWindowResponse(PositionWindowResponse { is_above: Some(is_above), is_clipped: Some(is_clipped), diff --git a/crates/fig_desktop/src/utils.rs b/crates/fig_desktop/src/utils.rs index 16b754716..261cf6f15 100644 --- a/crates/fig_desktop/src/utils.rs +++ b/crates/fig_desktop/src/utils.rs @@ -7,7 +7,6 @@ use std::sync::atomic::{ }; use fig_os_shim::Context; -use once_cell::sync::Lazy; use serde::{ Deserialize, Serialize, @@ -117,19 +116,19 @@ where } } -#[allow(clippy::needless_return)] -pub static ICON: Lazy = Lazy::new(|| { - cfg_if::cfg_if!( - if #[cfg(target_os = "linux")] { - return load_icon( - fig_util::search_xdg_data_dirs("icons/hicolor/512x512/apps/fig.png") - .unwrap_or_else(|| "/usr/share/icons/hicolor/512x512/apps/fig.png".into()), - ).unwrap_or_else(load_from_memory); - } else { - return load_from_memory(); - } - ); -}); +#[cfg(target_os = "linux")] +pub fn icon() -> Icon { + load_icon( + fig_util::search_xdg_data_dirs("icons/hicolor/512x512/apps/fig.png") + .unwrap_or_else(|| "/usr/share/icons/hicolor/512x512/apps/fig.png".into()), + ) + .unwrap_or_else(load_from_memory) +} + +#[cfg(not(target_os = "linux"))] +pub fn icon() -> Icon { + load_from_memory() +} #[cfg(target_os = "linux")] fn load_icon(path: impl AsRef) -> Option { @@ -152,17 +151,6 @@ fn load_from_memory() -> Icon { Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") } -#[cfg(test)] -mod tests { - use super::*; - - #[cfg_attr(target_os = "linux", ignore)] - #[test] - fn icon() { - let _icon = &*ICON; - } -} - /// A logical rect, where the origin point is the top left corner. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Rect { @@ -200,3 +188,14 @@ impl Rect { contains_x && contains_y } } + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg_attr(target_os = "linux", ignore)] + #[test] + fn test_icon() { + icon(); + } +} diff --git a/crates/fig_desktop/src/webview/autocomplete.rs b/crates/fig_desktop/src/webview/autocomplete.rs index cef19eb63..1b24f82d5 100644 --- a/crates/fig_desktop/src/webview/autocomplete.rs +++ b/crates/fig_desktop/src/webview/autocomplete.rs @@ -1,8 +1,9 @@ -use once_cell::sync::Lazy; +use std::sync::LazyLock; + use tracing::error; use url::Url; -pub static RESOURCE_URL: Lazy = Lazy::new(|| Url::parse("qcliresource://localhost").unwrap()); +pub static RESOURCE_URL: LazyLock = LazyLock::new(|| Url::parse("qcliresource://localhost").unwrap()); pub fn url() -> Url { if let Ok(autocomplete_url) = std::env::var("AUTOCOMPLETE_URL") { diff --git a/crates/fig_desktop/src/webview/mod.rs b/crates/fig_desktop/src/webview/mod.rs index f50b17f5d..1c678d869 100644 --- a/crates/fig_desktop/src/webview/mod.rs +++ b/crates/fig_desktop/src/webview/mod.rs @@ -10,6 +10,7 @@ use std::collections::HashMap; use std::rc::Rc; use std::sync::{ Arc, + LazyLock, OnceLock, }; use std::time::Duration; @@ -28,7 +29,6 @@ use fig_util::{ }; use fnv::FnvBuildHasher; use muda::MenuEvent; -use once_cell::sync::Lazy; use regex::RegexSet; use tao::dpi::LogicalSize; use tao::event::{ @@ -132,7 +132,7 @@ fn to_tao_theme(theme: WryTheme) -> Option { } } -pub static THEME: Lazy> = Lazy::new(|| { +pub static THEME: LazyLock> = LazyLock::new(|| { fig_settings::settings::get_string("app.theme") .ok() .flatten() @@ -177,7 +177,7 @@ impl WebviewManager { use crate::platform::ACTIVATION_POLICY; - *ACTIVATION_POLICY.lock() = ActivationPolicy::Accessory; + *ACTIVATION_POLICY.lock().unwrap() = ActivationPolicy::Accessory; event_loop.set_activation_policy(ActivationPolicy::Accessory); } @@ -650,7 +650,7 @@ pub fn build_dashboard( .with_visible(visible) .with_focused(visible) .with_always_on_top(false) - .with_window_icon(Some(utils::ICON.clone())) + .with_window_icon(Some(utils::icon())) .with_theme(THEME.and_then(to_tao_theme)) .build(event_loop)?; @@ -684,7 +684,7 @@ pub fn build_dashboard( .send_event(Event::WindowEvent { window_id: DASHBOARD_ID.clone(), window_event: WindowEvent::Api { - payload: payload.into_body().into(), + payload: payload.into_body(), }, }) .unwrap(); @@ -736,7 +736,7 @@ pub fn build_autocomplete( .with_decorations(false) .with_always_on_top(true) .with_focused(false) - .with_window_icon(Some(utils::ICON.clone())) + .with_window_icon(Some(utils::icon())) .with_inner_size(LogicalSize::new(1.0, 1.0)) .with_theme(THEME.and_then(to_tao_theme)); @@ -783,7 +783,7 @@ pub fn build_autocomplete( .send_event(Event::WindowEvent { window_id: AUTOCOMPLETE_ID.clone(), window_event: WindowEvent::Api { - payload: payload.into_body().into(), + payload: payload.into_body(), }, }) .unwrap(); diff --git a/crates/fig_desktop/src/webview/window.rs b/crates/fig_desktop/src/webview/window.rs index 5a4f9bc26..84e9ed7bf 100644 --- a/crates/fig_desktop/src/webview/window.rs +++ b/crates/fig_desktop/src/webview/window.rs @@ -40,10 +40,12 @@ use wry::{ }; use super::notification::WebviewNotificationsState; +use super::to_tao_theme; use super::window_id::WindowId; use crate::event::{ EmitEventName, WindowEvent, + WindowGeometryResult, WindowPosition, }; use crate::platform::{ @@ -329,7 +331,7 @@ impl WindowState { let (is_above, is_clipped) = self.update_window_geometry(position, size, anchor, platform_state, dry_run); if let Some(tx) = tx { - if let Err(err) = tx.send((is_above, is_clipped)) { + if let Err(err) = tx.send(WindowGeometryResult { is_above, is_clipped }) { tracing::error!(%err, "failed to send window geometry update result"); } } @@ -362,7 +364,7 @@ impl WindowState { EventLoopWindowTargetExtMacOS, }; - let mut policy_lock = platform::ACTIVATION_POLICY.lock(); + let mut policy_lock = platform::ACTIVATION_POLICY.lock().unwrap(); if *policy_lock != ActivationPolicy::Accessory { *policy_lock = ActivationPolicy::Accessory; window_target.set_activation_policy_at_runtime(ActivationPolicy::Accessory); @@ -398,7 +400,7 @@ impl WindowState { EventLoopWindowTargetExtMacOS, }; - let mut policy_lock = platform::ACTIVATION_POLICY.lock(); + let mut policy_lock = platform::ACTIVATION_POLICY.lock().unwrap(); if *policy_lock != ActivationPolicy::Regular { *policy_lock = ActivationPolicy::Regular; window_target.set_activation_policy_at_runtime(ActivationPolicy::Regular); @@ -440,20 +442,6 @@ impl WindowState { })), }); }, - WindowEvent::ReloadIfNotLoaded => { - info!(%self.window_id, "Reloading window if not loaded"); - - let url = serde_json::json!(self.url.lock().clone()); - - self.webview - .evaluate_script(&format!( - "if (window.location.href === 'about:blank') {{\ - console.log('Reloading window to', {url});\ - window.location.href = {url};\ - }}" - )) - .unwrap(); - }, WindowEvent::Reload => { info!(%self.window_id, "Reloading window"); @@ -475,7 +463,7 @@ impl WindowState { self.emit(event_name, payload); }, WindowEvent::Api { payload } => { - api_tx.send((self.window_id.clone(), payload.into())).unwrap(); + api_tx.send((self.window_id.clone(), payload)).unwrap(); }, WindowEvent::Devtools => { if self.webview.is_devtools_open() { @@ -509,11 +497,6 @@ impl WindowState { }, WindowEvent::SetEnabled(enabled) => self.set_enabled(enabled), WindowEvent::SetTheme(theme) => self.set_theme(theme), - WindowEvent::SetHtml { html } => { - self.webview - .evaluate_script(&format!("document.documentElement.innerHTML = `{html}`;")) - .unwrap(); - }, WindowEvent::Drag => { if let Err(err) = self.window.drag_window() { error!(%err, "Failed to drag window"); @@ -585,8 +568,7 @@ impl WindowState { self.enabled.load(std::sync::atomic::Ordering::SeqCst) } - #[allow(clippy::unused_self)] - pub fn set_theme(&self, _theme: Option) { - // TODO: blocked on https://github.com/tauri-apps/tao/issues/582 + pub fn set_theme(&self, theme: Option) { + self.window.set_theme(theme.and_then(to_tao_theme)); } } diff --git a/crates/fig_desktop_api/Cargo.toml b/crates/fig_desktop_api/Cargo.toml index bfc45b64a..d414b0d3a 100644 --- a/crates/fig_desktop_api/Cargo.toml +++ b/crates/fig_desktop_api/Cargo.toml @@ -28,7 +28,6 @@ fig_settings.workspace = true fig_telemetry.workspace = true fig_util.workspace = true fnv = "1.0.7" -once_cell.workspace = true serde.workspace = true serde_json.workspace = true shellexpand = "3.0.0" diff --git a/crates/fig_desktop_api/src/requests/auth.rs b/crates/fig_desktop_api/src/requests/auth.rs index edaf03c9c..5e690d824 100644 --- a/crates/fig_desktop_api/src/requests/auth.rs +++ b/crates/fig_desktop_api/src/requests/auth.rs @@ -1,4 +1,7 @@ -use std::sync::Arc; +use std::sync::{ + Arc, + LazyLock, +}; use fig_auth::builder_id::{ PollCreateToken, @@ -28,7 +31,6 @@ use fig_proto::fig::{ AuthStatusRequest, AuthStatusResponse, }; -use once_cell::sync::Lazy; use tokio::sync::Mutex; use tokio::sync::mpsc::{ Receiver, @@ -43,7 +45,7 @@ use tracing::{ use super::RequestResult; use crate::kv::KVStore; -static PKCE_REGISTRATION: Lazy>> = Lazy::new(PkceState::new); +static PKCE_REGISTRATION: LazyLock>> = LazyLock::new(PkceState::new); const BUILDER_ID_DATA_KEY: &str = "builder-id-data"; diff --git a/crates/fig_install/src/index.rs b/crates/fig_install/src/index.rs index 0d7cc0576..451a77f6f 100644 --- a/crates/fig_install/src/index.rs +++ b/crates/fig_install/src/index.rs @@ -3,7 +3,7 @@ use std::hash::{ Hash, Hasher, }; -use std::sync::OnceLock; +use std::sync::LazyLock; use std::time::{ SystemTime, UNIX_EPOCH, @@ -43,19 +43,16 @@ const DEFAULT_RELEASE_URL: &str = "https://desktop-release.q.us-east-1.amazonaws /// - The env var `Q_DESKTOP_RELEASE_URL` /// - The setting `install.releaseUrl` /// - Falls back to the default or the build time env var `Q_BUILD_DESKTOP_RELEASE_URL` -fn release_url() -> &'static Url { - static RELEASE_URL: OnceLock = OnceLock::new(); - RELEASE_URL.get_or_init(|| { - match std::env::var("Q_DESKTOP_RELEASE_URL") { - Ok(s) => Url::parse(&s), - Err(_) => match fig_settings::settings::get_string("install.releaseUrl") { - Ok(Some(s)) => Url::parse(&s), - _ => Url::parse(option_env!("Q_BUILD_DESKTOP_RELEASE_URL").unwrap_or(DEFAULT_RELEASE_URL)), - }, - } - .unwrap() - }) -} +static RELEASE_URL: LazyLock = LazyLock::new(|| { + match std::env::var("Q_DESKTOP_RELEASE_URL") { + Ok(s) => Url::parse(&s), + Err(_) => match fig_settings::settings::get_string("install.releaseUrl") { + Ok(Some(s)) => Url::parse(&s), + _ => Url::parse(option_env!("Q_BUILD_DESKTOP_RELEASE_URL").unwrap_or(DEFAULT_RELEASE_URL)), + }, + } + .unwrap() +}); fn deser_enum_other<'de, D, T>(deserializer: D) -> Result where @@ -287,7 +284,7 @@ pub struct Package { impl Package { pub(crate) fn download_url(&self) -> Url { - let mut url = release_url().clone(); + let mut url = RELEASE_URL.clone(); url.set_path(&self.download); url } @@ -340,7 +337,7 @@ impl PackageArchitecture { } fn index_endpoint(_channel: &Channel) -> Url { - let mut url = release_url().clone(); + let mut url = RELEASE_URL.clone(); url.set_path("index.json"); url } @@ -447,8 +444,8 @@ mod tests { #[test] fn test_release_url() { - println!("{}", *release_url()); - println!("{:#?}", *release_url()); + println!("{}", *RELEASE_URL); + println!("{:#?}", *RELEASE_URL); } #[test] diff --git a/crates/fig_log/Cargo.toml b/crates/fig_log/Cargo.toml index ec7dcb695..4a502a498 100644 --- a/crates/fig_log/Cargo.toml +++ b/crates/fig_log/Cargo.toml @@ -20,7 +20,6 @@ console-subscriber = { version = "0.4.1", optional = true, features = [ "parking_lot", ] } fig_util.workspace = true -once_cell.workspace = true parking_lot = "0.12.1" thiserror.workspace = true tracing.workspace = true diff --git a/crates/fig_log/src/lib.rs b/crates/fig_log/src/lib.rs index 5e325a672..c00116e38 100644 --- a/crates/fig_log/src/lib.rs +++ b/crates/fig_log/src/lib.rs @@ -1,8 +1,8 @@ use std::fs::File; use std::path::Path; +use std::sync::Mutex; use fig_util::env_var::Q_LOG_LEVEL; -use parking_lot::Mutex; use thiserror::Error; use tracing::info; use tracing::level_filters::LevelFilter; @@ -64,7 +64,7 @@ pub struct LogGuard { pub fn initialize_logging>(args: LogArgs) -> Result { let filter_layer = create_filter_layer(); let (reloadable_filter_layer, reloadable_handle) = tracing_subscriber::reload::Layer::new(filter_layer); - ENV_FILTER_RELOADABLE_HANDLE.lock().replace(reloadable_handle); + ENV_FILTER_RELOADABLE_HANDLE.lock().unwrap().replace(reloadable_handle); // First we construct the file logging layer if a file name was provided. let (file_layer, _file_guard) = match args.log_file_path { @@ -145,6 +145,7 @@ pub fn initialize_logging>(args: LogArgs) -> Result String { Q_LOG_LEVEL_GLOBAL .lock() + .unwrap() .clone() .unwrap_or_else(|| std::env::var(Q_LOG_LEVEL).unwrap_or_else(|_| DEFAULT_FILTER.to_string())) } @@ -158,13 +159,14 @@ pub fn set_log_level(level: String) -> Result { info!("Setting log level to {level:?}"); let old_level = get_log_level(); - *Q_LOG_LEVEL_GLOBAL.lock() = Some(level); + *Q_LOG_LEVEL_GLOBAL.lock().unwrap() = Some(level); let filter_layer = create_filter_layer(); - *MAX_LEVEL.lock() = filter_layer.max_level_hint(); + *MAX_LEVEL.lock().unwrap() = filter_layer.max_level_hint(); ENV_FILTER_RELOADABLE_HANDLE .lock() + .unwrap() .as_ref() .expect("set_log_level must not be called before logging is initialized") .reload(filter_layer)?; @@ -178,12 +180,12 @@ pub fn set_log_level(level: String) -> Result { /// /// The max log level which is set every time the log level is set. pub fn get_log_level_max() -> LevelFilter { - let max_level = *MAX_LEVEL.lock(); + let max_level = *MAX_LEVEL.lock().unwrap(); match max_level { Some(level) => level, None => { let filter_layer = create_filter_layer(); - *MAX_LEVEL.lock() = filter_layer.max_level_hint(); + *MAX_LEVEL.lock().unwrap() = filter_layer.max_level_hint(); filter_layer.max_level_hint().unwrap_or(DEFAULT_FILTER) }, } @@ -194,6 +196,7 @@ fn create_filter_layer() -> EnvFilter { let log_level = Q_LOG_LEVEL_GLOBAL .lock() + .unwrap() .clone() .or_else(|| std::env::var(Q_LOG_LEVEL).ok()); diff --git a/crates/fig_proto/Cargo.toml b/crates/fig_proto/Cargo.toml index 52318bf95..b18d357f9 100644 --- a/crates/fig_proto/Cargo.toml +++ b/crates/fig_proto/Cargo.toml @@ -15,7 +15,6 @@ arbitrary = { version = "1.4.1", optional = true, features = ["derive"] } bytes.workspace = true fig_util.workspace = true hex.workspace = true -once_cell.workspace = true prost = "0.13.3" prost-reflect = { version = "0.14.2", features = ["serde", "derive"] } rmp-serde = "1.3.0" diff --git a/crates/fig_proto/src/lib.rs b/crates/fig_proto/src/lib.rs index eb9b7fd2c..410e4a0b4 100644 --- a/crates/fig_proto/src/lib.rs +++ b/crates/fig_proto/src/lib.rs @@ -10,13 +10,13 @@ pub mod remote_hooks; pub mod util; use std::fmt::Debug; use std::mem::size_of; +use std::sync::LazyLock; use bytes::{ Buf, Bytes, BytesMut, }; -use once_cell::sync::Lazy; pub use prost; use prost::{ DecodeError, @@ -36,7 +36,7 @@ pub mod remote { // This is not used explicitly, but it must be here for the derive // impls on the protos for dynamic message -static DESCRIPTOR_POOL: Lazy = Lazy::new(|| { +static DESCRIPTOR_POOL: LazyLock = LazyLock::new(|| { DescriptorPool::decode(include_bytes!(concat!(env!("OUT_DIR"), "/file_descriptor_set.bin")).as_ref()).unwrap() }); diff --git a/crates/fig_request/Cargo.toml b/crates/fig_request/Cargo.toml index 0fddbbfad..fcabcced9 100644 --- a/crates/fig_request/Cargo.toml +++ b/crates/fig_request/Cargo.toml @@ -20,7 +20,6 @@ cfg-if.workspace = true cookie = "0.18.0" fig_settings.workspace = true fig_util.workspace = true -once_cell.workspace = true reqwest.workspace = true reqwest_cookie_store = "0.8.0" rustls-pemfile = "2.1.0" diff --git a/crates/fig_request/src/midway.rs b/crates/fig_request/src/midway.rs index 77fe3c810..cf70a1843 100644 --- a/crates/fig_request/src/midway.rs +++ b/crates/fig_request/src/midway.rs @@ -3,11 +3,13 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fmt; -use std::sync::Arc; +use std::sync::{ + Arc, + LazyLock, +}; use cookie::CookieBuilder; use fig_util::directories::DirectoryError; -use once_cell::sync::Lazy; use reqwest::cookie::Jar; use reqwest::redirect::Policy; use reqwest::{ @@ -264,9 +266,9 @@ impl MidwayCookies { } } -static JAR: Lazy> = Lazy::new(|| Arc::new(Jar::default())); +static JAR: LazyLock> = LazyLock::new(|| Arc::new(Jar::default())); -static CLIENT: Lazy = Lazy::new(|| { +static CLIENT: LazyLock = LazyLock::new(|| { reqwest::ClientBuilder::new() .redirect(Policy::custom(|attempt| { if attempt.url().domain() == Some("midway-auth.amazon.com") diff --git a/crates/fig_request/src/reqwest_client.rs b/crates/fig_request/src/reqwest_client.rs index 9434beff6..5f06b5fe2 100644 --- a/crates/fig_request/src/reqwest_client.rs +++ b/crates/fig_request/src/reqwest_client.rs @@ -2,9 +2,11 @@ use std::env::current_exe; use std::fs::File; use std::io::BufReader; use std::path::Path; -use std::sync::Arc; +use std::sync::{ + Arc, + LazyLock, +}; -use once_cell::sync::Lazy; use reqwest::Client; use rustls::{ ClientConfig, @@ -64,8 +66,8 @@ fn client_config(native_certs: bool) -> ClientConfig { .with_no_client_auth() } -static CLIENT_CONFIG_NATIVE_CERTS: Lazy> = Lazy::new(|| Arc::new(client_config(true))); -static CLIENT_CONFIG_NO_NATIVE_CERTS: Lazy> = Lazy::new(|| Arc::new(client_config(false))); +static CLIENT_CONFIG_NATIVE_CERTS: LazyLock> = LazyLock::new(|| Arc::new(client_config(true))); +static CLIENT_CONFIG_NO_NATIVE_CERTS: LazyLock> = LazyLock::new(|| Arc::new(client_config(false))); pub fn client_config_cached(native_certs: bool) -> Arc { if native_certs { @@ -75,7 +77,7 @@ pub fn client_config_cached(native_certs: bool) -> Arc { } } -pub static USER_AGENT: Lazy = Lazy::new(|| { +static USER_AGENT: LazyLock = LazyLock::new(|| { let name = current_exe() .ok() .and_then(|exe| exe.file_stem().and_then(|name| name.to_str().map(String::from))) @@ -92,7 +94,7 @@ pub fn user_agent() -> &'static str { &USER_AGENT } -pub static CLIENT_NATIVE_CERTS: Lazy> = Lazy::new(|| { +pub static CLIENT_NATIVE_CERTS: LazyLock> = LazyLock::new(|| { Some( Client::builder() .use_preconfigured_tls((*client_config_cached(true)).clone()) @@ -103,7 +105,7 @@ pub static CLIENT_NATIVE_CERTS: Lazy> = Lazy::new(|| { ) }); -pub static CLIENT_NO_NATIVE_CERTS: Lazy> = Lazy::new(|| { +pub static CLIENT_NO_NATIVE_CERTS: LazyLock> = LazyLock::new(|| { Some( Client::builder() .use_preconfigured_tls((*client_config_cached(false)).clone()) @@ -122,7 +124,7 @@ pub fn reqwest_client(native_certs: bool) -> Option<&'static reqwest::Client> { } } -pub static CLIENT_NATIVE_CERT_NO_REDIRECT: Lazy> = Lazy::new(|| { +pub static CLIENT_NATIVE_CERT_NO_REDIRECT: LazyLock> = LazyLock::new(|| { Client::builder() .use_preconfigured_tls((*client_config_cached(true)).clone()) .user_agent(USER_AGENT.chars().filter(|c| c.is_ascii_graphic()).collect::()) diff --git a/crates/fig_settings/Cargo.toml b/crates/fig_settings/Cargo.toml index dc697f7b6..64d2b44ba 100644 --- a/crates/fig_settings/Cargo.toml +++ b/crates/fig_settings/Cargo.toml @@ -13,7 +13,6 @@ workspace = true [dependencies] fd-lock = "4.0.0" fig_util.workspace = true -once_cell.workspace = true parking_lot = "0.12.1" r2d2 = "0.8.10" r2d2_sqlite = "0.24.0" diff --git a/crates/fig_settings/src/sqlite/mod.rs b/crates/fig_settings/src/sqlite/mod.rs index 0da430777..0e89697f1 100644 --- a/crates/fig_settings/src/sqlite/mod.rs +++ b/crates/fig_settings/src/sqlite/mod.rs @@ -3,9 +3,9 @@ use std::path::{ Path, PathBuf, }; +use std::sync::LazyLock; use fig_util::directories::fig_data_dir; -use once_cell::sync::Lazy; use r2d2::Pool; use r2d2_sqlite::SqliteConnectionManager; use rusqlite::types::FromSql; @@ -27,7 +27,7 @@ use crate::error::DbOpenError; const STATE_TABLE_NAME: &str = "state"; const AUTH_TABLE_NAME: &str = "auth_kv"; -pub static DATABASE: Lazy> = Lazy::new(|| { +pub static DATABASE: LazyLock> = LazyLock::new(|| { let db = Db::new().map_err(|e| DbOpenError(e.to_string()))?; db.migrate().map_err(|e| DbOpenError(e.to_string()))?; Ok(db) diff --git a/crates/fig_telemetry/Cargo.toml b/crates/fig_telemetry/Cargo.toml index 515568598..735e35047 100644 --- a/crates/fig_telemetry/Cargo.toml +++ b/crates/fig_telemetry/Cargo.toml @@ -32,7 +32,6 @@ fig_settings.workspace = true fig_telemetry_core.workspace = true fig_util.workspace = true macos-utils = { path = "../macos-utils" } -once_cell.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/crates/fig_telemetry/src/install_method.rs b/crates/fig_telemetry/src/install_method.rs index 3752cf3d8..2a541252a 100644 --- a/crates/fig_telemetry/src/install_method.rs +++ b/crates/fig_telemetry/src/install_method.rs @@ -1,12 +1,12 @@ use std::process::Command; +use std::sync::LazyLock; -use once_cell::sync::Lazy; use serde::{ Deserialize, Serialize, }; -static INSTALL_METHOD: Lazy = Lazy::new(|| { +static INSTALL_METHOD: LazyLock = LazyLock::new(|| { if let Ok(output) = Command::new("brew").args(["list", "amazon-q", "-1"]).output() { if output.status.success() { return InstallMethod::Brew; diff --git a/crates/fig_telemetry/src/lib.rs b/crates/fig_telemetry/src/lib.rs index 1c8f77f6f..5e39e93a6 100644 --- a/crates/fig_telemetry/src/lib.rs +++ b/crates/fig_telemetry/src/lib.rs @@ -6,6 +6,7 @@ mod install_method; mod util; use std::any::Any; +use std::sync::LazyLock; use std::time::{ Duration, SystemTime, @@ -69,7 +70,6 @@ pub use install_method::{ InstallMethod, get_install_method, }; -use once_cell::sync::Lazy; use tokio::sync::{ Mutex, OnceCell, @@ -164,7 +164,7 @@ impl TelemetryStage { } } -static JOIN_SET: Lazy>> = Lazy::new(|| Mutex::new(JoinSet::new())); +static JOIN_SET: LazyLock>> = LazyLock::new(|| Mutex::new(JoinSet::new())); /// Joins all current telemetry events pub async fn finish_telemetry() { diff --git a/crates/fig_util/src/terminal.rs b/crates/fig_util/src/terminal.rs index b02c64996..100562b95 100644 --- a/crates/fig_util/src/terminal.rs +++ b/crates/fig_util/src/terminal.rs @@ -73,6 +73,26 @@ pub fn in_special_terminal(ctx: &Context) -> Option { Terminal::from_process_info(ctx, &SPECIAL_TERMINALS.to_vec()) } +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct CustomTerminalMacos { + /// The macOS bundle ID + pub bundle_id: Option, + + #[serde(default)] + pub input_method: bool, + #[serde(default)] + pub accessibility: bool, + #[serde(default)] + pub xterm: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct CustomTerminal { + pub id: String, + pub name: String, + pub macos: CustomTerminalMacos, +} + /// All supported terminals #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] @@ -141,6 +161,9 @@ pub enum Terminal { Windsurf, /// Ghostty Ghostty, + + /// Custom terminal to support user/custom entries + Custom(CustomTerminal), } impl fmt::Display for Terminal { @@ -178,6 +201,7 @@ impl fmt::Display for Terminal { Terminal::Windsurf => write!(f, "Windsurf"), Terminal::Guake => write!(f, "Guake"), Terminal::Ghostty => write!(f, "Ghostty"), + Terminal::Custom(custom_terminal) => write!(f, "{}", custom_terminal.name), } } } @@ -210,6 +234,7 @@ impl Terminal { Some("Nova") => return Some(Terminal::Nova), Some("WezTerm") => return Some(Terminal::WezTerm), Some("guake") => return Some(Terminal::Guake), + Some("ghostty") => return Some(Terminal::Ghostty), _ => (), }; @@ -295,8 +320,10 @@ impl Terminal { } pub fn version() -> Option { + static RE: OnceLock> = OnceLock::new(); + let re = RE.get_or_init(|| regex::Regex::new("[0-9\\-\\._]+").ok()).as_ref()?; let version = std::env::var("TERM_PROGRAM_VERSION").ok()?; - match regex::Regex::new("[0-9\\-\\._]+").ok()?.captures(&version).is_some() { + match re.captures(&version).is_some() { true => Some(version), false => None, } @@ -338,6 +365,7 @@ impl Terminal { Terminal::Windsurf => "windsurf".into(), Terminal::Guake => "guake".into(), Terminal::Ghostty => "ghostty".into(), + Terminal::Custom(custom_terminal) => custom_terminal.id.clone().into(), } } @@ -364,6 +392,7 @@ impl Terminal { Terminal::Rio => Some("com.raphaelamorim.rio".into()), Terminal::Windsurf => Some("com.exafunction.windsurf".into()), Terminal::Ghostty => Some("com.mitchellh.ghostty".into()), + Terminal::Custom(custom_terminal) => custom_terminal.macos.bundle_id.clone().map(Cow::Owned), _ => None, } } @@ -409,7 +438,7 @@ impl Terminal { | Terminal::Zed | Terminal::Rio | Terminal::Ghostty - ) + ) || self.as_custom().map_or(false, |c| c.macos.input_method) } pub fn supports_macos_accessibility(&self) -> bool { @@ -422,7 +451,7 @@ impl Terminal { | Terminal::VSCodium | Terminal::Hyper | Terminal::Tabby - ) + ) || self.as_custom().map_or(false, |c| c.macos.accessibility) } pub fn is_xterm(&self) -> bool { @@ -436,7 +465,7 @@ impl Terminal { | Terminal::Cursor | Terminal::CursorNightly | Terminal::Windsurf - ) + ) || self.as_custom().map_or(false, |c| c.macos.xterm) } pub fn executable_names(&self) -> &'static [&'static str] { @@ -513,7 +542,10 @@ impl Terminal { pub fn is_jetbrains_terminal() -> bool { // Handles all official JetBrain IDEs + Android Studio - matches!(std::env::var("TERMINAL_EMULATOR").ok(), Some(v) if v == "JetBrains-JediTerm") + match std::env::var("TERMINAL_EMULATOR") { + Ok(v) => v == "JetBrains-JediTerm", + Err(_) => false, + } } pub fn supports_fancy_boxes(&self) -> bool { @@ -542,6 +574,13 @@ impl Terminal { Terminal::Ssh | Terminal::Tmux | Terminal::Vim | Terminal::Nvim | Terminal::Zellij ) } + + pub fn as_custom(&self) -> Option<&CustomTerminal> { + match self { + Terminal::Custom(custom) => Some(custom), + _ => None, + } + } } #[derive(Debug)] diff --git a/crates/figterm/Cargo.toml b/crates/figterm/Cargo.toml index 826e40a88..8df869ea4 100644 --- a/crates/figterm/Cargo.toml +++ b/crates/figterm/Cargo.toml @@ -46,7 +46,6 @@ indoc.workspace = true memmem = "0.1.1" mimalloc.workspace = true num-traits = "0.2" -once_cell.workspace = true parking_lot = "0.12.1" pin-project = "1.0.12" portable-pty.workspace = true diff --git a/crates/figterm/src/event_handler.rs b/crates/figterm/src/event_handler.rs index cf956356c..b989372a2 100644 --- a/crates/figterm/src/event_handler.rs +++ b/crates/figterm/src/event_handler.rs @@ -60,7 +60,7 @@ impl EventListener for EventHandler { let hook = new_prompt_hook(Some(context)); let message = hook_to_message(hook); - let insert_on_new_cmd = INSERT_ON_NEW_CMD.lock().take(); + let insert_on_new_cmd = INSERT_ON_NEW_CMD.lock().unwrap().take(); if let Some(cwd) = &shell_state.local_context.current_working_directory { if cwd.exists() { diff --git a/crates/figterm/src/inline/mod.rs b/crates/figterm/src/inline/mod.rs index 47f522e93..efc3ab60c 100644 --- a/crates/figterm/src/inline/mod.rs +++ b/crates/figterm/src/inline/mod.rs @@ -2,6 +2,7 @@ mod completion_cache; mod validate; use std::fmt::Write; +use std::sync::LazyLock; use std::time::{ Duration, Instant, @@ -34,7 +35,6 @@ use fig_util::terminal::{ current_terminal_version, }; use flume::Sender; -use once_cell::sync::Lazy; use tokio::sync::Mutex; use tracing::{ error, @@ -54,8 +54,9 @@ static INLINE_ENABLED: Mutex = Mutex::const_new(true); static LAST_RECEIVED: Mutex> = Mutex::const_new(None); -static CACHE_ENABLED: Lazy = Lazy::new(|| std::env::var_os("Q_INLINE_SHELL_COMPLETION_CACHE_DISABLE").is_none()); -static COMPLETION_CACHE: Lazy> = Lazy::new(|| Mutex::new(CompletionCache::new())); +static CACHE_ENABLED: LazyLock = + LazyLock::new(|| std::env::var_os("Q_INLINE_SHELL_COMPLETION_CACHE_DISABLE").is_none()); +static COMPLETION_CACHE: LazyLock> = LazyLock::new(|| Mutex::new(CompletionCache::new())); static TELEMETRY_QUEUE: Mutex = Mutex::const_new(TelemetryQueue::new()); diff --git a/crates/figterm/src/interceptor.rs b/crates/figterm/src/interceptor.rs index 1aadb1123..05b040b9f 100644 --- a/crates/figterm/src/interceptor.rs +++ b/crates/figterm/src/interceptor.rs @@ -1,3 +1,5 @@ +use std::sync::LazyLock; + use anyhow::Result; use dashmap::DashMap; use fig_proto::figterm::Action; @@ -5,7 +7,6 @@ use fig_settings::keybindings::{ KeyBinding, KeyBindings, }; -use once_cell::sync::Lazy; use tracing::trace; use crate::input::{ @@ -19,8 +20,8 @@ const GLOBAL_ACTIONS: &[&str] = &["toggleAutocomplete", "showAutocomplete"]; const IGNORE_ACTION: &str = "ignore"; -static ONLY_SHOW_ON_TAB: Lazy = - Lazy::new(|| fig_settings::settings::get_bool_or("autocomplete.onlyShowOnTab", false)); +static ONLY_SHOW_ON_TAB: LazyLock = + LazyLock::new(|| fig_settings::settings::get_bool_or("autocomplete.onlyShowOnTab", false)); pub fn key_from_text(text: impl AsRef) -> Option { let text = text.as_ref(); diff --git a/crates/figterm/src/main.rs b/crates/figterm/src/main.rs index 013c9a41f..dad61f11a 100644 --- a/crates/figterm/src/main.rs +++ b/crates/figterm/src/main.rs @@ -20,6 +20,11 @@ use std::ffi::{ OsStr, }; use std::iter::repeat; +use std::sync::{ + LazyLock, + Mutex, + RwLock, +}; use std::time::{ Duration, SystemTime, @@ -83,11 +88,6 @@ use flume::{ }; #[cfg(unix)] use nix::unistd::execvp; -use once_cell::sync::Lazy; -use parking_lot::{ - Mutex, - RwLock, -}; use portable_pty::PtySize; use tokio::io::{ self, @@ -143,19 +143,19 @@ const BUFFER_SIZE: usize = 16384; static INSERT_ON_NEW_CMD: Mutex> = Mutex::new(None); static INSERTION_LOCKED_AT: RwLock> = RwLock::new(None); -static EXPECTED_BUFFER: Lazy> = Lazy::new(|| Mutex::new("".to_string())); +static EXPECTED_BUFFER: Mutex = Mutex::new(String::new()); -static SHELL_ENVIRONMENT_VARIABLES: Lazy>> = Lazy::new(|| Mutex::new(vec![])); -static SHELL_ALIAS: Lazy>> = Lazy::new(|| Mutex::new(None)); +static SHELL_ENVIRONMENT_VARIABLES: Mutex> = Mutex::new(Vec::new()); +static SHELL_ALIAS: Mutex> = Mutex::new(None); -static USER_ENABLED_SHELLS: Lazy> = Lazy::new(|| { +static USER_ENABLED_SHELLS: LazyLock> = LazyLock::new(|| { fig_settings::state::get("user.enabled-shells") .ok() .flatten() .unwrap_or_default() }); -static HOSTNAME: Lazy> = Lazy::new(sysinfo::System::host_name); +static HOSTNAME: LazyLock> = LazyLock::new(sysinfo::System::host_name); pub enum MainLoopEvent { Insert { @@ -199,11 +199,11 @@ fn shell_state_to_context(shell_state: &ShellState) -> local::ShellContext { .username .as_deref() .and_then(|username| HOSTNAME.as_deref().map(|hostname| format!("{username}@{hostname}"))), - environment_variables: SHELL_ENVIRONMENT_VARIABLES.lock().clone(), + environment_variables: SHELL_ENVIRONMENT_VARIABLES.lock().unwrap().clone(), qterm_version: Some(env!("CARGO_PKG_VERSION").into()), preexec: Some(shell_state.preexec), osc_lock: Some(shell_state.osc_lock), - alias: SHELL_ALIAS.lock().clone(), + alias: SHELL_ALIAS.lock().unwrap().clone(), } } @@ -315,14 +315,14 @@ where }); let preexec = term.shell_state().preexec; - let mut handle = INSERTION_LOCKED_AT.write(); + let mut handle = INSERTION_LOCKED_AT.write().unwrap(); let insertion_locked = match handle.as_ref() { Some(at) => { let lock_expired = at.elapsed().unwrap_or(Duration::ZERO) > Duration::from_millis(16); let should_unlock = lock_expired - || term - .get_current_buffer() - .map_or(true, |buff| &buff.buffer == (&EXPECTED_BUFFER.lock() as &String)); + || term.get_current_buffer().map_or(true, |buff| { + &buff.buffer == (&EXPECTED_BUFFER.lock().unwrap() as &String) + }); if should_unlock { handle.take(); if lock_expired { @@ -916,7 +916,7 @@ fn figterm_main(command: Option<&[String]>) -> Result<()> { } // Check if to send the edit buffer because of timeout _ = edit_buffer_interval.tick() => { - let send_eb = INSERTION_LOCKED_AT.read().is_some(); + let send_eb = INSERTION_LOCKED_AT.read().unwrap().is_some(); if send_eb && can_send_edit_buffer(&term) { let cursor_coordinates = get_cursor_coordinates(&terminal); if let Err(err) = send_edit_buffer(&term, &remote_sender, cursor_coordinates).await { diff --git a/crates/figterm/src/message.rs b/crates/figterm/src/message.rs index f009c4478..90f5dccec 100644 --- a/crates/figterm/src/message.rs +++ b/crates/figterm/src/message.rs @@ -91,7 +91,7 @@ fn working_directory(path: Option<&str>, shell_state: &ShellState) -> PathBuf { } fn create_command(executable: impl AsRef, working_directory: impl AsRef) -> Command { - let env = (*SHELL_ENVIRONMENT_VARIABLES.lock()) + let env = (*SHELL_ENVIRONMENT_VARIABLES.lock().unwrap()) .clone() .into_iter() .filter_map(|EnvironmentVariable { key, value }| value.map(|value| (key, value))) @@ -180,10 +180,10 @@ pub async fn process_figterm_request( // // split text by cursor // let (left, right) = buffer.split_at(position); - INSERTION_LOCKED_AT.write().replace(SystemTime::now()); + INSERTION_LOCKED_AT.write().unwrap().replace(SystemTime::now()); let expected = format!("{buffer}{text_to_insert}"); trace!(?expected, "lock set, expected buffer"); - *EXPECTED_BUFFER.lock() = expected; + *EXPECTED_BUFFER.lock().unwrap() = expected; } if let Some(ref insertion_buffer) = request.insertion_buffer { if buffer.ne(insertion_buffer) { @@ -259,16 +259,16 @@ pub async fn process_figterm_request( Ok(Some(response)) }, FigtermRequest::InsertOnNewCmd(command) => { - *INSERT_ON_NEW_CMD.lock() = Some((command.text, command.bracketed, command.execute)); + *INSERT_ON_NEW_CMD.lock().unwrap() = Some((command.text, command.bracketed, command.execute)); Ok(None) }, FigtermRequest::SetBuffer(_) => Err(anyhow::anyhow!("SetBuffer is not supported in figterm")), FigtermRequest::UpdateShellContext(request) => { if request.update_environment_variables { - *SHELL_ENVIRONMENT_VARIABLES.lock() = request.environment_variables; + *SHELL_ENVIRONMENT_VARIABLES.lock().unwrap() = request.environment_variables; } if request.update_alias { - *SHELL_ALIAS.lock() = request.alias; + *SHELL_ALIAS.lock().unwrap() = request.alias; } Ok(None) }, diff --git a/crates/macos-utils/Cargo.toml b/crates/macos-utils/Cargo.toml index 8e2109387..1a4d4deb0 100644 --- a/crates/macos-utils/Cargo.toml +++ b/crates/macos-utils/Cargo.toml @@ -36,7 +36,6 @@ dashmap.workspace = true flume = "0.11.0" fnv = "1.0.7" accessibility-sys = { path = "./accessibility-master/accessibility-sys" } -once_cell.workspace = true accessibility = { path = "./accessibility-master/accessibility" } appkit-nsworkspace-bindings.workspace = true tracing.workspace = true diff --git a/crates/q_cli/Cargo.toml b/crates/q_cli/Cargo.toml index 2dde2537d..4c84f039a 100644 --- a/crates/q_cli/Cargo.toml +++ b/crates/q_cli/Cargo.toml @@ -59,7 +59,6 @@ globset = "0.4.10" indicatif = "0.17.3" indoc.workspace = true mimalloc.workspace = true -once_cell.workspace = true owo-colors = "4.0.0" parking_lot = "0.12.1" rand.workspace = true diff --git a/crates/q_cli/src/cli/chat/api.rs b/crates/q_cli/src/cli/chat/api.rs index 8adbf4b46..28a0927ad 100644 --- a/crates/q_cli/src/cli/chat/api.rs +++ b/crates/q_cli/src/cli/chat/api.rs @@ -1,5 +1,6 @@ use std::env; use std::path::Path; +use std::sync::LazyLock; use amzn_codewhisperer_streaming_client::operation::RequestId; use aws_smithy_types::error::display::DisplayErrorContext; @@ -25,7 +26,6 @@ use fig_settings::history::{ OrderBy, }; use fig_util::Shell; -use once_cell::sync::Lazy; use regex::Regex; use tokio::sync::mpsc::{ UnboundedReceiver, @@ -52,7 +52,7 @@ const MAX_SHELL_HISTORY_COMMAND_LEN: usize = 1024; const MAX_SHELL_HISTORY_DIRECTORY_LEN: usize = 256; /// Regex for the context modifiers `@git`, `@env`, and `@history` -static CONTEXT_MODIFIER_REGEX: Lazy = Lazy::new(|| Regex::new(r"@(git|env|history) ?").unwrap()); +static CONTEXT_MODIFIER_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"@(git|env|history) ?").unwrap()); fn truncate_safe(s: &str, max_bytes: usize) -> &str { if s.len() <= max_bytes { diff --git a/crates/q_cli/src/cli/init.rs b/crates/q_cli/src/cli/init.rs index 77efcc923..16ebeef32 100644 --- a/crates/q_cli/src/cli/init.rs +++ b/crates/q_cli/src/cli/init.rs @@ -6,6 +6,7 @@ use std::io::{ }; use std::path::Path; use std::process::ExitCode; +use std::sync::LazyLock; use std::time::SystemTime; use clap::Args; @@ -25,7 +26,6 @@ use fig_util::{ get_parent_process_exe, }; use indoc::formatdoc; -use once_cell::sync::Lazy; use super::internal::should_figterm_launch::should_figterm_launch_exit_status; use crate::util::app_path_from_bundle_id; @@ -33,7 +33,7 @@ use crate::util::app_path_from_bundle_id; const INLINE_ENABLED_SETTINGS_KEY: &str = "inline.enabled"; const SHELL_INTEGRATIONS_ENABLED_STATE_KEY: &str = "shell-integrations.enabled"; -static IS_SNAPSHOT_TEST: Lazy = Lazy::new(|| std::env::var_os("Q_INIT_SNAPSHOT_TEST").is_some()); +static IS_SNAPSHOT_TEST: LazyLock = LazyLock::new(|| std::env::var_os("Q_INIT_SNAPSHOT_TEST").is_some()); #[derive(Debug, Args, PartialEq, Eq)] pub struct InitArgs { diff --git a/crates/q_cli/src/cli/translate.rs b/crates/q_cli/src/cli/translate.rs index f86670762..45f595256 100644 --- a/crates/q_cli/src/cli/translate.rs +++ b/crates/q_cli/src/cli/translate.rs @@ -4,6 +4,7 @@ use std::io::{ stdout, }; use std::process::ExitCode; +use std::sync::LazyLock; use std::time::Instant; use anstream::{ @@ -33,7 +34,6 @@ use fig_ipc::{ use fig_telemetry::SuggestionState; use fig_util::CLI_BINARY_NAME; use fig_util::env_var::QTERM_SESSION_ID; -use once_cell::sync::Lazy; use regex::{ Captures, Regex, @@ -267,7 +267,7 @@ fn warning_message(content: &str) { } } -static PARAM_REGEX: Lazy = Lazy::new(|| Regex::new(r"(\$[A-Za-z][A-Za-z0-9\_\-]*)").unwrap()); +static PARAM_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"(\$[A-Za-z][A-Za-z0-9\_\-]*)").unwrap()); fn highlighter(s: &str) -> String { PARAM_REGEX diff --git a/packages/api-bindings/src/core.ts b/packages/api-bindings/src/core.ts index a05991609..03662ec8f 100644 --- a/packages/api-bindings/src/core.ts +++ b/packages/api-bindings/src/core.ts @@ -91,23 +91,16 @@ export function sendMessage( return; } - const b64 = bytesToBase64(buffer); - - if (window.ipc && window.ipc.postMessage) { - window.ipc.postMessage(b64); - } else if (window.webkit) { - if (!window.webkit?.messageHandlers?.proto) { - console.error( - "This version of Amazon Q does not support using protocol buffers. Please update.", - ); - return; - } - window.webkit.messageHandlers.proto.postMessage(b64); - } else { - console.error( - "Cannot send request. Fig.js is not supported in this browser.", - ); + const postMessage = window?.ipc?.postMessage; + if (postMessage && typeof postMessage === "function") { + const b64 = bytesToBase64(buffer); + postMessage(b64); + return; } + + console.error( + "Cannot send request. Fig.js is not supported in this browser.", + ); } const setupEventListeners = (): void => { diff --git a/packages/api-bindings/src/global.d.ts b/packages/api-bindings/src/global.d.ts index c635bbc52..07167f25d 100644 --- a/packages/api-bindings/src/global.d.ts +++ b/packages/api-bindings/src/global.d.ts @@ -15,16 +15,6 @@ declare global { } | undefined; - var webkit: - | { - messageHandlers?: Record & { - proto?: { - postMessage: (message: string) => void; - }; - }; - } - | undefined; - var ipc: | { postMessage?: (message: string) => void; diff --git a/packages/types/global.d.ts b/packages/types/global.d.ts index 10a59f668..a4416992c 100644 --- a/packages/types/global.d.ts +++ b/packages/types/global.d.ts @@ -51,13 +51,16 @@ declare global { } interface Window { // TODO: remove this from window when refactoring - webkit?: { messageHandlers?: Record }; globalTerminalSessionId: string | undefined; globalCWD: string; globalSSHString: string | undefined; logger: unknown; resetCaches?: () => void; listCache?: () => void; + + ipc?: { + postMessage?: (message: string) => void; + }; } const __APP_VERSION__: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6909a29d8..391e87156 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -627,8 +627,11 @@ importers: tests/fig-api: devDependencies: + '@amzn/tsconfig': + specifier: workspace:^ + version: link:../../packages/tsconfig '@amzn/types': - specifier: link:../../packages/types + specifier: workspace:^ version: link:../../packages/types '@aws/amazon-q-developer-cli-api-bindings': specifier: workspace:^ diff --git a/tests/fig-api/package.json b/tests/fig-api/package.json index 739bca19f..ced4f5936 100644 --- a/tests/fig-api/package.json +++ b/tests/fig-api/package.json @@ -10,8 +10,9 @@ "precommit": "exit 0" }, "devDependencies": { + "@amzn/tsconfig": "workspace:^", + "@amzn/types": "workspace:^", "@aws/amazon-q-developer-cli-api-bindings": "workspace:^", - "@amzn/types": "link:../../packages/types", "@types/node": "^22.10.1", "typescript": "^5.7.2", "vitest": "^2.1.8" diff --git a/tests/fig-api/src/fs.test.ts b/tests/fig-api/src/fs.test.ts index ea7734df0..0187163c4 100644 --- a/tests/fig-api/src/fs.test.ts +++ b/tests/fig-api/src/fs.test.ts @@ -1,6 +1,6 @@ import { fs as figFs } from "@aws/amazon-q-developer-cli-api-bindings"; import nodeFs from "node:fs"; -import { tempDir } from "./util"; +import { tempDir } from "./util.js"; import { describe, it, expect } from "vitest"; describe("fs api tests", () => { diff --git a/tests/fig-api/src/setup.ts b/tests/fig-api/src/setup.ts index 77f560331..212f12291 100644 --- a/tests/fig-api/src/setup.ts +++ b/tests/fig-api/src/setup.ts @@ -1,5 +1,5 @@ import childProcess from "node:child_process"; -import { tempDir } from "./util"; +import { tempDir } from "./util.js"; // Set Fig JS bindings to log less window.fig = { constants: undefined, quiet: true }; diff --git a/tests/fig-api/tsconfig.json b/tests/fig-api/tsconfig.json index 69f08c955..c8ef9f62b 100644 --- a/tests/fig-api/tsconfig.json +++ b/tests/fig-api/tsconfig.json @@ -1,12 +1,9 @@ { + "extends": ["@amzn/tsconfig/base.json"], "compilerOptions": { - "moduleResolution": "node", - "strict": true, - "sourceMap": true, - "esModuleInterop": true, + "noEmit": true, "lib": ["ESNext", "DOM", "DOM.Iterable"], "types": ["@amzn/types", "node"], - "outDir": "dist" }, "include": ["src/**/*.ts"], "exclude": ["node_modules"]