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,5 @@
pub mod repo_data_source;
pub mod repo_search_item;
pub use repo_data_source::*;
pub use repo_search_item::*;
@@ -0,0 +1,72 @@
use ai::workspace::WorkspaceMetadata;
use fuzzy_match::{match_indices_case_insensitive, FuzzyMatchResult};
use itertools::Itertools;
use warpui::{AppContext, Entity, SingletonEntity};
use super::RepoSearchItem;
use crate::ai::persisted_workspace::PersistedWorkspace;
use crate::search::command_palette::mixer::CommandPaletteItemAction;
use crate::search::data_source::{Query, QueryResult};
use crate::search::mixer::{DataSourceRunErrorWrapper, SyncDataSource};
const MAX_REPOS_CONSIDERED: usize = 50;
pub struct RepoDataSource {}
impl Default for RepoDataSource {
fn default() -> Self {
Self::new()
}
}
impl RepoDataSource {
pub fn new() -> Self {
Self {}
}
pub fn top_n(&self, limit: usize, app: &AppContext) -> impl Iterator<Item = RepoSearchItem> {
PersistedWorkspace::as_ref(app)
.workspaces()
.filter(|cbm| cbm.path.is_dir())
.sorted_by(WorkspaceMetadata::most_recently_navigated)
.take(limit)
.map(RepoSearchItem::new)
}
}
impl Entity for RepoDataSource {
type Event = ();
}
impl SyncDataSource for RepoDataSource {
type Action = CommandPaletteItemAction;
fn run_query(
&self,
query: &Query,
app: &AppContext,
) -> Result<Vec<QueryResult<Self::Action>>, DataSourceRunErrorWrapper> {
let query_str = query.text.as_str();
let repos = self.top_n(MAX_REPOS_CONSIDERED, app);
let results = repos
.filter_map(|mut repo| {
let match_result = if query_str.is_empty() {
Some(FuzzyMatchResult::no_match())
} else {
match_indices_case_insensitive(repo.display_name.as_str(), query_str)
};
// Boost repo results so they compete fairly with other sources
match_result.map(|mut match_result| {
match_result.score *= 4;
repo.match_result = match_result;
repo.into()
})
})
.collect_vec();
Ok(results)
}
}
@@ -0,0 +1,141 @@
use ai::workspace::WorkspaceMetadata;
use fuzzy_match::FuzzyMatchResult;
use ordered_float::OrderedFloat;
use std::path::Path;
use warp_core::ui::theme::Fill;
use warpui::{
elements::{Align, ConstrainedBox, Flex, Highlight, ParentElement, Shrinkable, Text},
fonts::{Properties, Weight},
AppContext, Element, SingletonEntity,
};
use crate::appearance::Appearance;
use crate::search::action::search_item::styles;
use crate::search::command_palette::mixer::CommandPaletteItemAction;
use crate::search::command_palette::render_util;
use crate::search::item::SearchItem;
use crate::search::result_renderer::ItemHighlightState;
use crate::ui_components::icons::Icon as UiIcon;
#[derive(Debug)]
pub struct RepoSearchItem {
pub display_name: String,
pub metadata: WorkspaceMetadata,
pub match_result: FuzzyMatchResult,
}
fn repo_display_name(repo_path: &Path) -> String {
// Try to create a relative path from the user's home directory
dirs::home_dir()
.and_then(|home| repo_path.strip_prefix(&home).ok())
.map(|relative_path| format!("~/{}", relative_path.display()))
.unwrap_or_else(|| repo_path.display().to_string())
}
impl RepoSearchItem {
pub fn new(metadata: WorkspaceMetadata) -> Self {
RepoSearchItem {
display_name: repo_display_name(&metadata.path),
metadata,
match_result: FuzzyMatchResult::no_match(),
}
}
fn render(
&self,
item_highlight_state: ItemHighlightState,
appearance: &Appearance,
) -> Box<dyn Element> {
let label = self.render_label(item_highlight_state, appearance);
let mut binding = Flex::row();
binding.add_child(Shrinkable::new(1., Align::new(label).left().finish()).finish());
ConstrainedBox::new(binding.finish())
.with_height(styles::SEARCH_ITEM_HEIGHT)
.finish()
}
fn render_label(
&self,
item_highlight_state: ItemHighlightState,
appearance: &Appearance,
) -> Box<dyn Element> {
Text::new_inline(
repo_display_name(&self.metadata.path),
appearance.ui_font_family(),
appearance.monospace_font_size(),
)
.with_color(item_highlight_state.sub_text_fill(appearance).into_solid())
.with_style(Properties::default().weight(Weight::Bold))
.with_single_highlight(
Highlight::new()
.with_properties(Properties::default().weight(Weight::Bold))
.with_foreground_color(
item_highlight_state.main_text_fill(appearance).into_solid(),
),
self.match_result.matched_indices.clone(),
)
.finish()
}
}
impl SearchItem for RepoSearchItem {
type Action = CommandPaletteItemAction;
fn render_icon(
&self,
highlight_state: ItemHighlightState,
appearance: &Appearance,
) -> Box<dyn Element> {
let icon_color: Fill = appearance.theme().terminal_colors().normal.cyan.into();
render_util::render_search_item_icon(
appearance,
UiIcon::Folder,
icon_color.into_solid(),
highlight_state,
)
}
fn render_item(
&self,
highlight_state: ItemHighlightState,
app: &AppContext,
) -> Box<dyn Element> {
let appearance = Appearance::as_ref(app);
self.render(highlight_state, appearance)
}
fn render_details(&self, _ctx: &AppContext) -> Option<Box<dyn Element>> {
None
}
fn score(&self) -> OrderedFloat<f64> {
OrderedFloat(self.match_result.score as f64)
}
fn accept_result(&self) -> CommandPaletteItemAction {
// Convert the absolute repo path into parent + basename for OpenDirectory
let repo_path: &Path = &self.metadata.path;
let parent = repo_path.parent().unwrap_or(Path::new("/"));
let basename = repo_path
.file_name()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| repo_path.to_string_lossy().to_string());
CommandPaletteItemAction::OpenDirectory {
path: basename,
project_directory: parent.to_string_lossy().to_string(),
}
}
fn execute_result(&self) -> CommandPaletteItemAction {
// For projects, execute and accept have the same behavior
self.accept_result()
}
fn accessibility_label(&self) -> String {
format!("Repo: {}", self.metadata.path.display())
}
}