Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
#![allow(deprecated)]
use std::ffi::CStr;
use cocoa::base::{id, nil};
use core_foundation::{
base::TCFType,
string::{CFString, CFStringRef},
};
use objc::{class, msg_send, sel, sel_impl};
use warp_core::channel::{Channel, ChannelState};
// Launch Services constants
type LSRolesMask = u32;
type OSStatus = i32;
// https://github.com/kornelski/core-services/blob/5572befea9fae3c31310d875240342229afa14ca/src/launch_services.rs#L33
const K_LS_ROLES_SHELL: LSRolesMask = 0x00000008;
extern "C" {
// Launch Services bindings
fn LSCopyDefaultRoleHandlerForContentType(
in_content_type: CFStringRef,
in_role: LSRolesMask,
) -> CFStringRef;
fn LSSetDefaultRoleHandlerForContentType(
in_content_type: CFStringRef,
in_role: LSRolesMask,
in_handler_bundle_id: CFStringRef,
) -> OSStatus;
}
pub fn can_become_default_terminal() -> bool {
unsafe {
let bundle_class = class!(NSBundle);
let main_bundle: id = msg_send![bundle_class, mainBundle];
let bundle_id: id = msg_send![main_bundle, bundleIdentifier];
bundle_id != nil && ChannelState::channel() != Channel::Local
}
}
pub fn is_warp_default_terminal() -> bool {
unsafe {
let unix_executable_content_type = CFString::new("public.unix-executable");
let handler = LSCopyDefaultRoleHandlerForContentType(
unix_executable_content_type.as_concrete_TypeRef(),
K_LS_ROLES_SHELL,
);
if handler.is_null() {
return false;
}
let Some(warp_bundle_id) = get_warp_bundle_id() else {
return false;
};
let handler_string = CFString::wrap_under_create_rule(handler);
let current_handler = handler_string.to_string();
current_handler == warp_bundle_id
}
}
pub fn set_warp_as_default_terminal() -> Result<(), String> {
log::debug!("Setting Warp as default terminal");
let bundle_id = get_warp_bundle_id().ok_or("No bundle ID".to_string())?;
set_default_terminal(&bundle_id)
}
fn set_default_terminal(bundle_id: &str) -> Result<(), String> {
log::debug!("Setting default terminal to bundle ID: {bundle_id}");
unsafe {
let unix_executable_content_type = CFString::new("public.unix-executable");
let bundle_id_cf = CFString::new(bundle_id);
let result = LSSetDefaultRoleHandlerForContentType(
unix_executable_content_type.as_concrete_TypeRef(),
K_LS_ROLES_SHELL,
bundle_id_cf.as_concrete_TypeRef(),
);
match result {
0 => Ok(()),
_ => Err(format!(
"LSSetDefaultRoleHandlerForContentType failed with stats: {result}"
)),
}
}
}
/// Gets Warp's bundle identifier. This may be `None` if not running as a bundle, i.e. through
/// `cargo run` without `cargo bundle`.
fn get_warp_bundle_id() -> Option<String> {
unsafe {
let bundle_class = class!(NSBundle);
let main_bundle: id = msg_send![bundle_class, mainBundle];
let bundle_id: id = msg_send![main_bundle, bundleIdentifier];
if bundle_id == nil {
return None;
}
let bundle_id_str: *const i8 = msg_send![bundle_id, UTF8String];
let bundle_id_cstr = CStr::from_ptr(bundle_id_str);
String::from_utf8(bundle_id_cstr.to_bytes().into())
.inspect_err(|err| log::error!("Error converting bundle ID to string: {err:#}"))
.ok()
}
}
+112
View File
@@ -0,0 +1,112 @@
use warpui::{
windowing::{StateEvent, WindowManager},
Entity, ModelContext, SingletonEntity,
};
#[cfg(target_os = "macos")]
mod mac;
#[cfg(target_os = "macos")]
use mac::*;
#[allow(dead_code)]
#[cfg(not(target_os = "macos"))]
mod non_mac {
pub fn can_become_default_terminal() -> bool {
false
}
pub fn is_warp_default_terminal() -> bool {
false
}
/// Sets Warp as the default terminal
pub fn set_warp_as_default_terminal() -> Result<(), String> {
Err("Not implemented".to_string())
}
}
#[allow(unused_imports)]
#[cfg(not(target_os = "macos"))]
use non_mac::*;
pub struct DefaultTerminal {
/// Whether the OS will treat Warp as the default app for scripts/executables.
is_warp_default: bool,
}
impl DefaultTerminal {
pub fn new(ctx: &mut ModelContext<Self>) -> Self {
ctx.subscribe_to_model(
&WindowManager::handle(ctx),
Self::handle_window_manager_event,
);
// This can be slow to compute due to calling into platform APIs, so in unit
// tests, where we shouldn't care, just pretend that we are not.
let is_warp_default = if cfg!(test) {
false
} else {
is_warp_default_terminal()
};
Self { is_warp_default }
}
/// This is an OS-level setting. Unlike most other settings, where Warp is the source-of-truth
/// for the value of the setting, it can be changed outside of Warp. We monitor if it gets
/// changed externally by checking when Warp is focused.
fn handle_window_manager_event(&mut self, event: &StateEvent, ctx: &mut ModelContext<Self>) {
match event {
StateEvent::ValueChanged { current, previous } => {
if current.active_window.is_some() && previous.active_window.is_none() {
let is_warp_default_now = is_warp_default_terminal();
if is_warp_default_now != self.is_warp_default {
self.set_is_warp_default(is_warp_default_now, ctx);
}
}
}
}
}
fn set_is_warp_default(&mut self, value: bool, ctx: &mut ModelContext<Self>) {
self.is_warp_default = value;
ctx.emit(DefaultTerminalEvent::ValueChanged);
ctx.notify();
}
pub fn can_warp_become_default() -> bool {
if cfg!(test) {
// Determining whether or not we can become the default terminal requires
// calling into platform APIs, which can be slow, and we can't actually
// set the default terminal in unit tests, so just say we can't.
false
} else {
can_become_default_terminal()
}
}
pub fn is_warp_default(&self) -> bool {
self.is_warp_default
}
/// This is a one-way operation. Once we set the default terminal to Warp, we can't really
/// "unset" it unless we pick a new default terminal. Picking a new default is complicated.
pub fn make_warp_default(&mut self, ctx: &mut ModelContext<Self>) {
if let Err(e) = set_warp_as_default_terminal() {
log::error!("Error setting Warp as default terminal: {e:#}");
} else {
self.set_is_warp_default(true, ctx);
}
}
}
pub enum DefaultTerminalEvent {
ValueChanged,
}
impl Entity for DefaultTerminal {
type Event = DefaultTerminalEvent;
}
impl SingletonEntity for DefaultTerminal {}