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
@@ -0,0 +1,58 @@
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use warp_util::path::ShellFamily;
use warpui::platform::OperatingSystem;
#[derive(
Debug,
Default,
Clone,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
schemars::JsonSchema,
settings_value::SettingsValue,
)]
#[schemars(
description = "Shell to use when opening new sessions.",
rename_all = "snake_case"
)]
pub enum NewSessionShell {
#[default]
#[schemars(description = "Use the operating system's default shell.")]
SystemDefault,
#[schemars(description = "A shell executable path.")]
Executable(String),
#[schemars(description = "An MSYS2 shell environment.")]
MSYS2(String),
#[schemars(description = "A Windows Subsystem for Linux distribution.")]
WSL(String),
#[schemars(description = "A custom shell command.")]
Custom(String),
}
impl NewSessionShell {
pub fn shell_family(&self) -> ShellFamily {
let shell = match self {
NewSessionShell::SystemDefault => return OperatingSystem::get().default_shell_family(),
NewSessionShell::WSL(_) => return ShellFamily::Posix,
NewSessionShell::Executable(shell) => shell,
NewSessionShell::MSYS2(shell) => shell,
NewSessionShell::Custom(shell) => shell,
};
let path = PathBuf::from(shell);
if let Some(file_stem) = path
.file_stem()
.and_then(|s| s.to_str().map(|s| s.to_lowercase()))
{
if file_stem.contains("powershell") || file_stem.contains("pwsh") {
return ShellFamily::PowerShell;
}
}
ShellFamily::Posix
}
}
@@ -0,0 +1,69 @@
use serde::{Deserialize, Deserializer, Serialize};
/// A user setting for the shell to start new terminal sessions with.
///
/// Users choose between their login shell, the default versions of zsh/bash/fish
/// (if installed, the first matching executable on their `$PATH`), and a
/// custom path or command.
#[derive(Debug, Clone, Default, PartialEq, Eq, schemars::JsonSchema)]
#[schemars(
with = "Option<String>",
description = "Shell to start terminal sessions with. Use null for the system default, or one of \"bash\", \"zsh\", \"fish\", \"pwsh\", or a custom shell command/path."
)]
pub enum StartupShell {
#[default]
Default,
Bash,
Fish,
Zsh,
PowerShell,
Custom(String),
}
impl StartupShell {
/// Returns the command for this startup shell.
pub fn shell_command(&self) -> Option<&str> {
match self {
StartupShell::Default => None,
StartupShell::Bash => Some("bash"),
StartupShell::Fish => Some("fish"),
StartupShell::Zsh => Some("zsh"),
StartupShell::PowerShell => Some("pwsh"),
StartupShell::Custom(shell) => Some(shell),
}
}
}
impl Serialize for StartupShell {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.shell_command().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for StartupShell {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value: Option<String> = Option::deserialize(deserializer)?;
Ok(value.into())
}
}
impl settings_value::SettingsValue for StartupShell {}
impl From<Option<String>> for StartupShell {
fn from(value: Option<String>) -> Self {
match value {
None => StartupShell::Default,
Some(shell) if shell == "bash" => StartupShell::Bash,
Some(shell) if shell == "zsh" => StartupShell::Zsh,
Some(shell) if shell == "fish" => StartupShell::Fish,
Some(shell) if shell == "pwsh" => StartupShell::PowerShell,
Some(shell) => StartupShell::Custom(shell),
}
}
}
@@ -0,0 +1,168 @@
use std::{path::PathBuf, str::FromStr};
use serde::{Deserialize, Serialize};
use settings::Setting;
/// The source for a newly-created session.
#[derive(Debug, Copy, Clone)]
pub enum NewSessionSource {
/// The user split a pane to create a new session.
SplitPane,
/// The user created a new tab, and this is its initial session.
Tab,
/// The user created a new window, and this is its initial session.
Window,
}
#[derive(
Debug,
Copy,
Clone,
Default,
Serialize,
Deserialize,
PartialEq,
Eq,
schemars::JsonSchema,
settings_value::SettingsValue,
)]
#[schemars(description = "Where new sessions start.", rename_all = "snake_case")]
pub enum WorkingDirectoryMode {
/// Start a new session in the user's home directory.
HomeDir,
/// Start a new session in the same directory as the previous session.
#[default]
PreviousDir,
/// Start a new session in a specific directory.
CustomDir,
}
impl WorkingDirectoryMode {
/// Returns the label that should be used for this mode when configuring
/// values in the settings view.
pub fn dropdown_item_label(&self) -> &'static str {
match self {
WorkingDirectoryMode::HomeDir => "Home directory",
WorkingDirectoryMode::PreviousDir => "Previous session's directory",
WorkingDirectoryMode::CustomDir => "Custom directory",
}
}
}
#[derive(
Debug,
Clone,
Default,
Serialize,
Deserialize,
PartialEq,
Eq,
schemars::JsonSchema,
settings_value::SettingsValue,
)]
#[schemars(description = "Working directory settings for a specific session source.")]
pub struct WorkingDirectoryPerSourceConfig {
#[schemars(description = "How the working directory is determined.")]
pub mode: WorkingDirectoryMode,
#[schemars(description = "Custom directory path, used when mode is CustomDir.")]
pub custom_dir: String,
}
impl WorkingDirectoryPerSourceConfig {
/// Returns the initial session path that should be used for this source.
fn initial_directory_for_new_session(
&self,
initial_directory_from_current_session: Option<PathBuf>,
ignore_custom_directory: bool,
) -> Option<PathBuf> {
match self.mode {
WorkingDirectoryMode::HomeDir => None,
WorkingDirectoryMode::PreviousDir => initial_directory_from_current_session,
WorkingDirectoryMode::CustomDir => {
if self.custom_dir.is_empty() || ignore_custom_directory {
None
} else {
Some(
// Perform tilde expansion on the provided directory
// before converting it into a path.
PathBuf::from_str(&shellexpand::tilde(self.custom_dir.as_str()))
// This will never actually return the default value, as
// the error type here is Infallible.
.unwrap_or_default(),
)
}
}
}
}
}
#[derive(
Debug,
Clone,
Default,
Serialize,
Deserialize,
PartialEq,
Eq,
schemars::JsonSchema,
settings_value::SettingsValue,
)]
#[schemars(description = "Configuration for the initial working directory of new sessions.")]
pub struct WorkingDirectoryConfig {
#[schemars(description = "Whether to use separate settings per session source.")]
pub advanced_mode: bool,
#[schemars(description = "Default working directory settings used when advanced mode is off.")]
pub global: WorkingDirectoryPerSourceConfig,
#[schemars(description = "Working directory settings for split pane sessions.")]
pub split_pane: WorkingDirectoryPerSourceConfig,
#[schemars(description = "Working directory settings for new tab sessions.")]
pub new_tab: WorkingDirectoryPerSourceConfig,
#[schemars(description = "Working directory settings for new window sessions.")]
pub new_window: WorkingDirectoryPerSourceConfig,
}
impl WorkingDirectoryConfig {
/// Returns the per-source config for the given session source,
/// taking into account whether advanced mode is enabled.
pub fn config_for_source(&self, source: NewSessionSource) -> &WorkingDirectoryPerSourceConfig {
if self.advanced_mode {
match source {
NewSessionSource::SplitPane => &self.split_pane,
NewSessionSource::Tab => &self.new_tab,
NewSessionSource::Window => &self.new_window,
}
} else {
&self.global
}
}
/// Returns the initial session path that should be used for the given
/// new session source.
pub fn initial_directory_for_new_session(
&self,
source: NewSessionSource,
initial_directory_from_current_session: Option<PathBuf>,
ignore_custom_directory: bool,
) -> Option<PathBuf> {
self.config_for_source(source)
.initial_directory_for_new_session(
initial_directory_from_current_session,
ignore_custom_directory,
)
}
/// Invokes the provided function with a mutable reference to the setting's
/// internal value then persists it to storage.
pub fn update_and_save_value<F>(
&mut self,
update_fn: F,
ctx: &mut warpui::ModelContext<<Self as Setting>::Group>,
) -> anyhow::Result<()>
where
F: FnOnce(&mut <Self as Setting>::Value),
{
update_fn(self);
self.set_value(self.value().clone(), ctx)
}
}