Initial public release of Warp.
Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
pub fn create_message(id: &str, task_id: &str) -> api::Message {
|
||||
api::Message {
|
||||
id: id.to_string(),
|
||||
task_id: task_id.to_string(),
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
message: Some(api::message::Message::AgentOutput(
|
||||
api::message::AgentOutput {
|
||||
text: format!("Message content for {id}"),
|
||||
},
|
||||
)),
|
||||
request_id: String::new(),
|
||||
timestamp: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_subagent_tool_call_message(
|
||||
id: &str,
|
||||
task_id: &str,
|
||||
subtask_id: &str,
|
||||
metadata: Option<api::message::tool_call::subagent::Metadata>,
|
||||
) -> api::Message {
|
||||
api::Message {
|
||||
id: id.to_string(),
|
||||
task_id: task_id.to_string(),
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
message: Some(api::message::Message::ToolCall(api::message::ToolCall {
|
||||
tool_call_id: format!("{id}_tool_call"),
|
||||
tool: Some(api::message::tool_call::Tool::Subagent(
|
||||
api::message::tool_call::Subagent {
|
||||
task_id: subtask_id.to_string(),
|
||||
payload: String::new(),
|
||||
metadata,
|
||||
},
|
||||
)),
|
||||
})),
|
||||
request_id: String::new(),
|
||||
timestamp: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_api_task(id: &str, messages: Vec<api::Message>) -> api::Task {
|
||||
api::Task {
|
||||
id: id.to_string(),
|
||||
messages,
|
||||
dependencies: None,
|
||||
description: String::new(),
|
||||
summary: String::new(),
|
||||
server_data: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_api_subtask(
|
||||
id: &str,
|
||||
parent_task_id: &str,
|
||||
messages: Vec<api::Message>,
|
||||
) -> api::Task {
|
||||
api::Task {
|
||||
id: id.to_string(),
|
||||
messages,
|
||||
dependencies: Some(api::task::Dependencies {
|
||||
parent_task_id: parent_task_id.to_string(),
|
||||
}),
|
||||
description: String::new(),
|
||||
summary: String::new(),
|
||||
server_data: String::new(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
use itertools::Itertools;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use crate::terminal::event_listener::ChannelEventListener;
|
||||
use crate::terminal::model::ansi::{self, Handler};
|
||||
use crate::terminal::model::blockgrid::BlockGrid;
|
||||
use crate::terminal::model::cell::Flags;
|
||||
use crate::terminal::model::grid::grid_handler::PerformResetGridChecks;
|
||||
use crate::terminal::model::grid::Dimensions as _;
|
||||
use crate::terminal::model::index::{VisiblePoint, VisibleRow};
|
||||
use crate::terminal::model::ObfuscateSecrets;
|
||||
use crate::terminal::SizeInfo;
|
||||
|
||||
const MAX_SCROLL_LIMIT: usize = 1000;
|
||||
|
||||
/// Constructs a blockgrid from its contents as a string.
|
||||
///
|
||||
/// A `\n` will break line and `\r\n` will break line without wrapping.
|
||||
///
|
||||
/// This function will set `max_cursor` in the grid based on the position of
|
||||
/// the last character. Some features rely on the max cursor appearing at the
|
||||
/// end of a grid on a newline (e.g. block filtering), so when writing tests
|
||||
/// you may need to end the string with `\r\n`, even if there's no content
|
||||
/// after it.
|
||||
///
|
||||
/// # Example
|
||||
/// The line `mock_blockgrid("hello\n:)\r\nearth!")` will create a blockgrid with the following cells:
|
||||
/// ```
|
||||
/// // [h][e][l][l][o][ ] <- WRAPLINE flag set
|
||||
/// // [:][)][ ][ ][ ][ ]
|
||||
/// // [e][a][r][t][h][!]
|
||||
/// ```
|
||||
///
|
||||
pub fn mock_blockgrid(content: &str) -> BlockGrid {
|
||||
let rows: Vec<&str> = content.split('\n').collect();
|
||||
let num_cols = rows
|
||||
.iter()
|
||||
.map(|row| {
|
||||
let sum: usize = row
|
||||
.chars()
|
||||
.filter(|c| *c != '\r')
|
||||
// All characters in our mock blockgrid should have a minimum character width of one
|
||||
// because any character that is rendered in the blockgrid will occupy at least one
|
||||
// grapheme. This is true for the null-character '\0' as well.
|
||||
.map(|c| usize::max(c.width().unwrap_or(1), 1))
|
||||
.sum();
|
||||
sum
|
||||
})
|
||||
.collect_vec();
|
||||
let max_num_cols = num_cols.iter().cloned().max().unwrap_or(0);
|
||||
|
||||
// Create terminal with the appropriate dimensions.
|
||||
let size = SizeInfo::new_without_font_metrics(rows.len(), max_num_cols);
|
||||
|
||||
let mut blockgrid = BlockGrid::new(
|
||||
size,
|
||||
MAX_SCROLL_LIMIT,
|
||||
ChannelEventListener::new_for_test(),
|
||||
ObfuscateSecrets::No,
|
||||
PerformResetGridChecks::default(),
|
||||
);
|
||||
|
||||
blockgrid.start();
|
||||
|
||||
// Fill blockgrid with content.
|
||||
for (row, text) in rows.iter().enumerate() {
|
||||
if !text.ends_with('\r') && row + 1 != rows.len() {
|
||||
blockgrid.grid_storage_mut()[row][max_num_cols - 1]
|
||||
.flags_mut()
|
||||
.insert(Flags::WRAPLINE);
|
||||
}
|
||||
|
||||
let mut index = 0;
|
||||
for c in text.chars().take_while(|c| *c != '\r') {
|
||||
blockgrid.grid_storage_mut()[row][index].c = c;
|
||||
|
||||
// All characters in our mock blockgrid should have a minimum character width of one
|
||||
// because any character that is rendered in the blockgrid will occupy at least one
|
||||
// grapheme. This is true for the null-character '\0' as well.
|
||||
let width = usize::max(c.width().unwrap_or(1), 1);
|
||||
if width == 2 {
|
||||
blockgrid.grid_storage_mut()[row][index]
|
||||
.flags_mut()
|
||||
.insert(Flags::WIDE_CHAR);
|
||||
blockgrid.grid_storage_mut()[row][index + 1]
|
||||
.flags_mut()
|
||||
.insert(Flags::WIDE_CHAR_SPACER);
|
||||
}
|
||||
|
||||
index += width;
|
||||
}
|
||||
}
|
||||
if !rows.is_empty() {
|
||||
let total_cols = blockgrid.grid_handler().columns();
|
||||
blockgrid.grid_handler_mut().update_cursor(|cursor| {
|
||||
cursor.point = VisiblePoint {
|
||||
row: VisibleRow(rows.len() - 1),
|
||||
col: num_cols[rows.len() - 1].saturating_sub(1),
|
||||
};
|
||||
// If we are at the end of the line, we need to wrap the input on the next
|
||||
// usage of the cursor for writing!
|
||||
if num_cols[rows.len() - 1].saturating_sub(1) == total_cols - 1 {
|
||||
cursor.input_needs_wrap = true;
|
||||
}
|
||||
});
|
||||
blockgrid.grid_storage_mut().update_max_cursor();
|
||||
}
|
||||
|
||||
blockgrid.on_finish_byte_processing(&ansi::ProcessorInput::new(&[]));
|
||||
|
||||
blockgrid
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
pub mod ai_agent_tasks;
|
||||
pub mod blockgrid;
|
||||
pub mod settings;
|
||||
pub mod terminal;
|
||||
mod virtual_fs;
|
||||
|
||||
pub use blockgrid::mock_blockgrid;
|
||||
pub use terminal::add_window_with_terminal;
|
||||
pub use virtual_fs::{Stub, VirtualFS};
|
||||
|
||||
macro_rules! assert_eventually {
|
||||
($cond:expr, $($arg:tt)+) => {
|
||||
$crate::test_util::assert_eventually!(20 => $cond, $($arg)+);
|
||||
};
|
||||
// Run the condition up to ticks times, yielding to the executor in between. If it does
|
||||
// not become true, this panics with the provided format string + args.
|
||||
($ticks:literal => $cond:expr, $($arg:tt)+) => {{
|
||||
let mut pass = false;
|
||||
for _ in 0..$ticks {
|
||||
if $cond {
|
||||
pass = true;
|
||||
break;
|
||||
}
|
||||
warpui::r#async::Timer::after(std::time::Duration::from_millis(5)).await;
|
||||
}
|
||||
if !pass {
|
||||
panic!("{}", format_args!($($arg)+));
|
||||
}
|
||||
}};
|
||||
}
|
||||
pub(crate) use assert_eventually;
|
||||
@@ -0,0 +1,110 @@
|
||||
#[cfg(test)]
|
||||
use warpui::App;
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn initialize_settings_for_tests(app: &mut App) {
|
||||
use warp_core::execution_mode::ExecutionMode;
|
||||
initialize_settings_for_tests_with_mode(app, ExecutionMode::App, false);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn initialize_settings_for_tests_with_mode(
|
||||
app: &mut App,
|
||||
mode: warp_core::execution_mode::ExecutionMode,
|
||||
is_sandboxed: bool,
|
||||
) {
|
||||
use crate::{
|
||||
ai::cloud_agent_settings::CloudAgentSettings,
|
||||
drive::settings::WarpDriveSettings,
|
||||
search::command_search::settings::CommandSearchSettings,
|
||||
settings::{
|
||||
app_icon::AppIconSettings, init_and_register_user_preferences,
|
||||
manager::SettingsManager, AISettings, AccessibilitySettings, AliasExpansionSettings,
|
||||
AppEditorSettings, BlockVisibilitySettings, ChangelogSettings,
|
||||
CloudPreferencesSettings, CodeSettings, DebugSettings, EmacsBindingsSettings,
|
||||
FontSettings, GPUSettings, InputModeSettings, InputSettings, NativePreferenceSettings,
|
||||
PaneSettings, SameLinePromptBlockSettings, ScrollSettings, SelectionSettings,
|
||||
SshSettings, ThemeSettings, VimBannerSettings,
|
||||
},
|
||||
terminal::{
|
||||
general_settings::GeneralSettings, keys_settings::KeysSettings,
|
||||
ligature_settings::LigatureSettings, safe_mode_settings::SafeModeSettings,
|
||||
session_settings::SessionSettings, settings::TerminalSettings,
|
||||
shared_session::settings::SharedSessionSettings, warpify::settings::WarpifySettings,
|
||||
BlockListSettings,
|
||||
},
|
||||
undo_close::UndoCloseSettings,
|
||||
user_config::WarpConfig,
|
||||
window_settings::WindowSettings,
|
||||
workspace::tab_settings::TabSettings,
|
||||
};
|
||||
use warp_core::{execution_mode::AppExecutionMode, semantic_selection::SemanticSelection};
|
||||
app.add_singleton_model(|ctx| AppExecutionMode::new(mode, is_sandboxed, ctx));
|
||||
|
||||
app.update(init_and_register_user_preferences);
|
||||
app.add_singleton_model(|_ctx| SettingsManager::default());
|
||||
app.add_singleton_model(WarpConfig::mock);
|
||||
|
||||
AccessibilitySettings::register(app);
|
||||
app.update(AISettings::register_and_subscribe_to_events);
|
||||
AliasExpansionSettings::register(app);
|
||||
CloudAgentSettings::register(app);
|
||||
AppEditorSettings::register(app);
|
||||
BlockVisibilitySettings::register(app);
|
||||
BlockListSettings::register(app);
|
||||
ChangelogSettings::register(app);
|
||||
CloudPreferencesSettings::register(app);
|
||||
CommandSearchSettings::register(app);
|
||||
DebugSettings::register(app);
|
||||
AppIconSettings::register(app);
|
||||
EmacsBindingsSettings::register(app);
|
||||
|
||||
#[cfg(feature = "local_fs")]
|
||||
{
|
||||
crate::util::file::external_editor::EditorSettings::register(app);
|
||||
}
|
||||
|
||||
FontSettings::register(app);
|
||||
GeneralSettings::register(app);
|
||||
GPUSettings::register(app);
|
||||
InputModeSettings::register(app);
|
||||
InputSettings::register(app);
|
||||
KeysSettings::register(app);
|
||||
LigatureSettings::register(app);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use crate::settings::LinuxAppConfiguration;
|
||||
LinuxAppConfiguration::register(app);
|
||||
}
|
||||
|
||||
NativePreferenceSettings::register(app);
|
||||
SafeModeSettings::register(app);
|
||||
SameLinePromptBlockSettings::register(app);
|
||||
ScrollSettings::register(app);
|
||||
SelectionSettings::register(app);
|
||||
app.update(|ctx| {
|
||||
WarpifySettings::register(ctx);
|
||||
});
|
||||
SessionSettings::register(app);
|
||||
SshSettings::register(app);
|
||||
TabSettings::register(app);
|
||||
TerminalSettings::register(app);
|
||||
PaneSettings::register(app);
|
||||
ThemeSettings::register(app);
|
||||
UndoCloseSettings::register(app);
|
||||
VimBannerSettings::register(app);
|
||||
WarpDriveSettings::register(app);
|
||||
WindowSettings::register(app);
|
||||
SharedSessionSettings::register(app);
|
||||
CodeSettings::register(app);
|
||||
SemanticSelection::register(app);
|
||||
|
||||
app.update(|ctx| {
|
||||
// Register a no-op secure storage provider for testing.
|
||||
warpui_extras::secure_storage::register_noop("test", ctx);
|
||||
|
||||
// Add settings models that are backed by secure storage, not user preferences.
|
||||
ctx.add_singleton_model(ai::api_keys::ApiKeyManager::new);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
|
||||
use repo_metadata::repositories::DetectedRepositories;
|
||||
#[cfg(feature = "local_fs")]
|
||||
use repo_metadata::RepoMetadataModel;
|
||||
use warp_core::ui::appearance::Appearance;
|
||||
|
||||
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
|
||||
use crate::ai::agent_conversations_model::AgentConversationsModel;
|
||||
use crate::ai::ambient_agents::github_auth_notifier::GitHubAuthNotifier;
|
||||
use crate::ai::document::ai_document_model::AIDocumentModel;
|
||||
use crate::ai::mcp::{
|
||||
gallery::MCPGalleryManager, templatable_manager::TemplatableMCPServerManager,
|
||||
};
|
||||
use crate::ai::persisted_workspace::PersistedWorkspace;
|
||||
use crate::ai::skills::SkillManager;
|
||||
use crate::code_review::git_status_update::GitStatusUpdateModel;
|
||||
use crate::terminal::cli_agent_sessions::CLIAgentSessionsModel;
|
||||
use crate::warp_managed_paths_watcher::WarpManagedPathsWatcher;
|
||||
use warpui::SingletonEntity;
|
||||
use warpui::{platform::WindowStyle, App, ViewHandle, WindowId};
|
||||
use watcher::HomeDirectoryWatcher;
|
||||
|
||||
use super::settings::initialize_settings_for_tests;
|
||||
use crate::ai::blocklist::BlocklistAIPermissions;
|
||||
use crate::ai::blocklist::SerializedBlockListItem;
|
||||
use crate::ai::execution_profiles::profiles::AIExecutionProfilesModel;
|
||||
use crate::ai::llms::LLMPreferences;
|
||||
use crate::ai::outline::RepoOutlines;
|
||||
use crate::ai::restored_conversations::RestoredAgentConversations;
|
||||
use crate::auth::auth_manager::AuthManager;
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::changelog_model::ChangelogModel;
|
||||
use crate::pricing::PricingInfoModel;
|
||||
use crate::server::telemetry::context_provider::AppTelemetryContextProvider;
|
||||
use crate::suggestions::ignored_suggestions_model::IgnoredSuggestionsModel;
|
||||
use crate::terminal::shared_session::permissions_manager::SessionPermissionsManager;
|
||||
use crate::terminal::view::inline_banner::ByoLlmAuthBannerSessionState;
|
||||
use crate::undo_close::UndoCloseStack;
|
||||
use crate::workspace::{OneTimeModalModel, WorkspaceRegistry};
|
||||
use crate::AgentNotificationsModel;
|
||||
use crate::{
|
||||
ai::{blocklist::BlocklistAIHistoryModel, AIRequestUsageModel},
|
||||
cloud_object::model::persistence::CloudModel,
|
||||
context_chips::prompt::Prompt,
|
||||
experiments,
|
||||
network::NetworkStatus,
|
||||
search::files::model::FileSearchModel,
|
||||
server::{
|
||||
cloud_objects::{listener::Listener, update_manager::UpdateManager},
|
||||
server_api::ServerApiProvider,
|
||||
sync_queue::SyncQueue,
|
||||
},
|
||||
settings::PrivacySettings,
|
||||
settings_view::keybindings::KeybindingChangedNotifier,
|
||||
system::SystemInfo,
|
||||
system::SystemStats,
|
||||
terminal::{
|
||||
alt_screen_reporting::AltScreenReporting, keys::TerminalKeybindings,
|
||||
resizable_data::ResizableData, History, TerminalView,
|
||||
},
|
||||
workflows::local_workflows::LocalWorkflows,
|
||||
workspace::{sync_inputs::SyncedInputState, ActiveSession},
|
||||
workspaces::{
|
||||
team_tester::TeamTesterStatus, update_manager::TeamUpdateManager,
|
||||
user_workspaces::UserWorkspaces,
|
||||
},
|
||||
};
|
||||
use repo_metadata::watcher::DirectoryWatcher;
|
||||
|
||||
/// Initializes all of the necessary models to use a terminal view.
|
||||
pub fn initialize_app_for_terminal_view(app: &mut App) {
|
||||
initialize_settings_for_tests(app);
|
||||
|
||||
app.add_singleton_model(|_| ServerApiProvider::new_for_test());
|
||||
app.add_singleton_model(|ctx| ChangelogModel::new(ServerApiProvider::as_ref(ctx).get()));
|
||||
app.add_singleton_model(|_| NetworkStatus::new());
|
||||
app.add_singleton_model(|_| SystemStats::new());
|
||||
app.add_singleton_model(|_| Prompt::mock());
|
||||
app.add_singleton_model(SyncQueue::mock);
|
||||
app.add_singleton_model(CloudModel::mock);
|
||||
app.add_singleton_model(UserWorkspaces::default_mock);
|
||||
app.add_singleton_model(TeamTesterStatus::mock);
|
||||
app.add_singleton_model(TeamUpdateManager::mock);
|
||||
app.add_singleton_model(UpdateManager::mock);
|
||||
app.add_singleton_model(MCPGalleryManager::new);
|
||||
app.add_singleton_model(Listener::mock);
|
||||
app.add_singleton_model(|_| Appearance::mock());
|
||||
app.add_singleton_model(PrivacySettings::mock);
|
||||
app.add_singleton_model(|_ctx| SyncedInputState::mock());
|
||||
app.add_singleton_model(|_| ResizableData::default());
|
||||
app.add_singleton_model(LocalWorkflows::new);
|
||||
app.add_singleton_model(|_| History::default());
|
||||
app.add_singleton_model(|_| BlocklistAIHistoryModel::new_for_test());
|
||||
app.add_singleton_model(|_| CLIAgentSessionsModel::new());
|
||||
app.add_singleton_model(|_| ActiveAgentViewsModel::new());
|
||||
app.add_singleton_model(BlocklistAIPermissions::new);
|
||||
app.add_singleton_model(AgentNotificationsModel::new);
|
||||
app.add_singleton_model(UndoCloseStack::new);
|
||||
|
||||
app.add_singleton_model(|ctx| {
|
||||
AIRequestUsageModel::new_for_test(ServerApiProvider::as_ref(ctx).get_ai_client(), ctx)
|
||||
});
|
||||
app.add_singleton_model(|_| KeybindingChangedNotifier::new());
|
||||
app.add_singleton_model(TerminalKeybindings::new);
|
||||
app.add_singleton_model(|_| ActiveSession::default());
|
||||
app.add_singleton_model(|_| AuthStateProvider::new_for_test());
|
||||
app.add_singleton_model(AppTelemetryContextProvider::new_context_provider);
|
||||
app.add_singleton_model(AuthManager::new_for_test);
|
||||
app.add_singleton_model(LLMPreferences::new);
|
||||
app.add_singleton_model(SessionPermissionsManager::new);
|
||||
app.add_singleton_model(DirectoryWatcher::new);
|
||||
app.add_singleton_model(|_| DetectedRepositories::default());
|
||||
#[cfg(feature = "local_fs")]
|
||||
app.add_singleton_model(RepoMetadataModel::new);
|
||||
app.add_singleton_model(FileSearchModel::new);
|
||||
app.add_singleton_model(|_| GitStatusUpdateModel::new());
|
||||
app.add_singleton_model(RepoOutlines::new_for_test);
|
||||
app.add_singleton_model(HomeDirectoryWatcher::new_for_test);
|
||||
app.add_singleton_model(WarpManagedPathsWatcher::new_for_testing);
|
||||
app.add_singleton_model(SkillManager::new);
|
||||
app.add_singleton_model(|ctx| {
|
||||
CodebaseIndexManager::new_for_test(ServerApiProvider::as_ref(ctx).get(), ctx)
|
||||
});
|
||||
app.add_singleton_model(|_| TemplatableMCPServerManager::default());
|
||||
app.add_singleton_model(|ctx| {
|
||||
AIExecutionProfilesModel::new(&crate::LaunchMode::new_for_unit_test(), ctx)
|
||||
});
|
||||
#[cfg(feature = "voice_input")]
|
||||
app.add_singleton_model(voice_input::VoiceInput::new);
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
app.add_singleton_model(SystemInfo::new);
|
||||
|
||||
app.add_singleton_model(|_| RestoredAgentConversations::new(vec![]));
|
||||
app.add_singleton_model(OneTimeModalModel::new);
|
||||
app.add_singleton_model(|_| WorkspaceRegistry::new());
|
||||
app.add_singleton_model(|_| IgnoredSuggestionsModel::new(vec![]));
|
||||
app.add_singleton_model(|_| PricingInfoModel::new());
|
||||
app.add_singleton_model(AIDocumentModel::new);
|
||||
app.add_singleton_model(ByoLlmAuthBannerSessionState::new);
|
||||
app.add_singleton_model(|_| GitHubAuthNotifier::new());
|
||||
app.add_singleton_model(AgentConversationsModel::new);
|
||||
app.add_singleton_model(PersistedWorkspace::new_for_test);
|
||||
|
||||
app.update(experiments::init);
|
||||
AltScreenReporting::register(app);
|
||||
}
|
||||
|
||||
/// Creates a window in `app` with a [`TerminalView`] as the root view.
|
||||
/// Returns the handle to that terminal view.
|
||||
pub fn add_window_with_terminal(
|
||||
app: &mut App,
|
||||
restored_blocks: Option<&[SerializedBlockListItem]>,
|
||||
) -> ViewHandle<TerminalView> {
|
||||
add_window_with_id_and_terminal(app, restored_blocks).1
|
||||
}
|
||||
|
||||
/// Creates a window in `app` with a [`TerminalView`] as the root view.
|
||||
/// Returns the WindowID and the handle to that terminal view.
|
||||
pub fn add_window_with_id_and_terminal(
|
||||
app: &mut App,
|
||||
restored_blocks: Option<&[SerializedBlockListItem]>,
|
||||
) -> (WindowId, ViewHandle<TerminalView>) {
|
||||
let tips_model = app.add_model(|_| Default::default());
|
||||
app.add_window(WindowStyle::NotStealFocus, |ctx| {
|
||||
TerminalView::new_for_test(tips_model, restored_blocks, ctx)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
use std::path::PathBuf;
|
||||
pub use virtual_fs::{Dirs, Stub, VirtualFS};
|
||||
|
||||
pub trait WarpDirs {
|
||||
#[allow(dead_code)]
|
||||
fn git_repository_fixture(&self) -> PathBuf {
|
||||
Warp::fixtures().join("git_repository")
|
||||
}
|
||||
}
|
||||
|
||||
impl WarpDirs for Dirs {}
|
||||
|
||||
pub struct Warp;
|
||||
|
||||
impl Warp {
|
||||
#[allow(dead_code)]
|
||||
pub fn executable() -> PathBuf {
|
||||
let mut path = {
|
||||
let mut build = "debug";
|
||||
|
||||
if !cfg!(debug_assertions) {
|
||||
build = "release";
|
||||
}
|
||||
|
||||
std::env::var("CARGO_TARGET_DIR")
|
||||
.ok()
|
||||
.map(|directory| PathBuf::from(directory).join(build))
|
||||
.unwrap_or_else(|| Self::root().join(format!("target/{}", &build)))
|
||||
};
|
||||
|
||||
path.push("warp");
|
||||
path
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn fixtures() -> PathBuf {
|
||||
Self::root().join("tests/fixtures")
|
||||
}
|
||||
|
||||
pub fn root() -> PathBuf {
|
||||
let manifest_dir = if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
|
||||
PathBuf::from(manifest_dir)
|
||||
} else {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
};
|
||||
|
||||
if manifest_dir.join("Cargo.lock").exists() {
|
||||
manifest_dir
|
||||
} else {
|
||||
manifest_dir
|
||||
.parent()
|
||||
.expect("Could not find the debug binaries directory")
|
||||
.parent()
|
||||
.expect("Could not find the debug binaries directory")
|
||||
.to_path_buf()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user