first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+179 -72
View File
@@ -2,74 +2,63 @@
use std::path::PathBuf;
use std::sync::Arc;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::blocklist::agent_view::AgentViewEntryOrigin;
use crate::ai::document::ai_document_model::{AIDocumentSaveStatus, AIDocumentUserEditStatus};
use crate::appearance::Appearance;
use crate::drive::{items::WarpDriveItemId, sharing::ShareableObject, CloudObjectTypeAndId};
use crate::notebooks::editor::view::RichTextEditorConfig;
use crate::pane_group::focus_state::PaneFocusHandle;
use crate::pane_group::pane::view::header::components::{
render_pane_header_buttons, render_pane_header_title_text, render_three_column_header,
CenteredHeaderEdgeWidth,
};
use crate::pane_group::pane::view::header::toolbelt_button_position_id;
use crate::pane_group::pane::view::header::PaneHeaderAction;
use crate::send_telemetry_from_ctx;
use crate::settings::FontSettings;
use crate::terminal::input::MenuPositioning;
use crate::terminal::view::TerminalView;
use crate::util::bindings::keybinding_name_to_keystroke;
use crate::view_components::action_button::{
ButtonSize, NakedTheme, SecondaryTheme, TooltipAlignment,
};
use crate::view_components::DismissibleToast;
use crate::workspace::ToastStack;
use crate::BlocklistAIHistoryModel;
use crate::{
ai::document::ai_document_model::{
AIDocumentId, AIDocumentInstance, AIDocumentModel, AIDocumentModelEvent,
AIDocumentUpdateSource, AIDocumentVersion,
},
editor::InteractionState,
menu::{Menu, MenuItem, MenuItemFields},
notebooks::{
editor::{
model::NotebooksEditorModel,
rich_text_styles,
view::{EditorViewEvent, RichTextEditorView},
},
link::{NotebookLinks, SessionSource},
},
pane_group::{pane::view, BackingView, PaneConfiguration, PaneEvent},
server::telemetry::TelemetryEvent,
ui_components::buttons::icon_button,
ui_components::icons::Icon,
view_components::action_button::{ActionButton, PrimaryTheme},
};
use pathfinder_geometry::vector::vec2f;
use galaxy_core::ui::icons;
use galaxy_core::ui::icons::ICON_DIMENSIONS;
use galaxy_core::ui::theme::Fill as ThemeFill;
use galaxyui::clipboard::ClipboardContent;
use galaxyui::elements::CrossAxisAlignment;
use galaxyui::elements::MainAxisAlignment;
use galaxyui::elements::MainAxisSize;
use galaxyui::elements::{ChildAnchor, PositionedElementAnchor, PositionedElementOffsetBounds};
use galaxyui::keymap::EditableBinding;
use galaxyui::keymap::FixedBinding;
use galaxyui::elements::{
ChildAnchor, ChildView, ConstrainedBox, Container, CrossAxisAlignment, Flex, Hoverable,
MainAxisAlignment, MainAxisSize, MouseStateHandle, OffsetPositioning, ParentElement,
PositionedElementAnchor, PositionedElementOffsetBounds, SavePosition, Stack,
};
use galaxyui::keymap::{EditableBinding, FixedBinding};
use galaxyui::text_layout::ClipConfig;
use galaxyui::ui_components::button::ButtonTooltipPosition;
use galaxyui::ui_components::components::UiComponent;
use galaxyui::{
elements::{
ChildView, ConstrainedBox, Container, Flex, Hoverable, MouseStateHandle, OffsetPositioning,
ParentElement, SavePosition, Stack,
},
AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
ViewHandle,
id, AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
ViewContext, ViewHandle,
};
use galaxyui::{id, EntityId};
use pathfinder_geometry::vector::vec2f;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::blocklist::agent_view::AgentViewEntryOrigin;
use crate::ai::document::ai_document_model::{
AIDocumentId, AIDocumentInstance, AIDocumentModel, AIDocumentModelEvent, AIDocumentSaveStatus,
AIDocumentUpdateSource, AIDocumentUserEditStatus, AIDocumentVersion,
};
use crate::ai::document::orchestration_config_block::OrchestrationConfigBlockView;
use crate::appearance::Appearance;
use crate::drive::items::WarpDriveItemId;
use crate::drive::sharing::ShareableObject;
use crate::drive::CloudObjectTypeAndId;
use crate::editor::InteractionState;
use crate::menu::{Menu, MenuItem, MenuItemFields};
use crate::notebooks::editor::model::NotebooksEditorModel;
use crate::notebooks::editor::rich_text_styles;
use crate::notebooks::editor::view::{EditorViewEvent, RichTextEditorConfig, RichTextEditorView};
use crate::notebooks::link::{NotebookLinks, SessionSource};
use crate::pane_group::focus_state::PaneFocusHandle;
use crate::pane_group::pane::view;
use crate::pane_group::pane::view::header::components::{
render_pane_header_buttons, render_pane_header_title_text, render_three_column_header,
CenteredHeaderEdgeWidth,
};
use crate::pane_group::pane::view::header::{toolbelt_button_position_id, PaneHeaderAction};
use crate::pane_group::{BackingView, PaneConfiguration, PaneEvent};
use crate::server::telemetry::TelemetryEvent;
use crate::settings::FontSettings;
use crate::terminal::input::MenuPositioning;
use crate::terminal::view::TerminalView;
use crate::ui_components::buttons::icon_button;
use crate::ui_components::icons::Icon;
use crate::util::bindings::keybinding_name_to_keystroke;
use crate::view_components::action_button::{
ActionButton, ButtonSize, NakedTheme, PrimaryTheme, SecondaryTheme, TooltipAlignment,
};
use crate::view_components::DismissibleToast;
use crate::workspace::ToastStack;
use crate::{send_telemetry_from_ctx, BlocklistAIHistoryModel};
pub fn init(app: &mut AppContext) {
app.register_editable_bindings([EditableBinding::new(
@@ -90,23 +79,25 @@ pub fn init(app: &mut AppContext) {
)]);
}
#[cfg(feature = "local_fs")]
use warp_util::path::LineAndColumnArg;
#[cfg(feature = "local_fs")]
use crate::code::editor_management::CodeSource;
// Import keybinding constants from code view to ensure consistency
use crate::code::view::{SAVE_FILE_BINDING_DESCRIPTION, SAVE_FILE_BINDING_NAME};
use crate::notebooks::file::MarkdownDisplayMode;
#[cfg(feature = "local_fs")]
use crate::util::file::external_editor::settings::EditorLayout;
#[cfg(feature = "local_fs")]
use crate::util::openable_file_type::FileTarget;
#[cfg(feature = "local_fs")]
use galaxy_util::path::LineAndColumnArg;
// Import keybinding constants from code view to ensure consistency
use crate::code::view::{SAVE_FILE_BINDING_DESCRIPTION, SAVE_FILE_BINDING_NAME};
#[derive(Debug, Clone, PartialEq)]
pub enum AIDocumentAction {
Close,
SelectVersion(AIDocumentVersion),
Export,
CopyAsMarkdown,
OpenVersionMenu,
CreateWarpDriveNotebook,
RevertToDocumentVersion,
@@ -170,6 +161,7 @@ pub struct AIDocumentView {
synced_status_mouse_state: MouseStateHandle,
view_position_id: String,
version_button: ViewHandle<ActionButton>,
orchestration_config_block: Option<ViewHandle<OrchestrationConfigBlockView>>,
}
impl AIDocumentView {
@@ -271,21 +263,61 @@ impl AIDocumentView {
use crate::ai::blocklist::BlocklistAIHistoryEvent;
match event {
BlocklistAIHistoryEvent::UpdatedConversationStatus {
terminal_view_id, ..
terminal_surface_id,
..
} => {
// Check if this is our terminal view
if let Some(tv) = &me.original_terminal_view {
if tv.id() == *terminal_view_id {
if tv.id() == *terminal_surface_id {
me.update_header_buttons(ctx);
}
}
}
BlocklistAIHistoryEvent::RestoredConversations {
terminal_view_id,
terminal_surface_id,
conversation_ids,
} => {
// Try to populate terminal view if conversations were restored
me.maybe_populate_terminal_view(*terminal_view_id, conversation_ids, ctx);
me.maybe_populate_terminal_view(
*terminal_surface_id,
conversation_ids,
ctx,
);
}
BlocklistAIHistoryEvent::OrchestrationConfigUpdated {
conversation_id: cid,
from_restore,
} => {
let our_conv = AIDocumentModel::as_ref(ctx)
.get_conversation_id_for_document_id(&document_id);
if our_conv.as_ref() == Some(cid) {
// Lazily create the config block view if the
// plan sidebar opened before the orchestration
// config arrived.
let was_freshly_created = if me.orchestration_config_block.is_none() {
let conv_id = *cid;
// TODO: introduce DocumentId / PlanId newtypes to make this
// conversion type-safe.
let plan_id = document_id.to_string();
me.orchestration_config_block =
Some(ctx.add_typed_action_view(move |ctx| {
OrchestrationConfigBlockView::new(conv_id, plan_id, ctx)
}));
true
} else {
false
};
// Arm auto-pop for live agent dispatches but
// not for restore-hydrated events.
if was_freshly_created && !*from_restore {
if let Some(block) = &me.orchestration_config_block {
block.update(ctx, |block, ctx| {
block.arm_for_fresh_dispatch(ctx);
});
}
}
ctx.notify();
}
}
_ => {}
}
@@ -304,7 +336,9 @@ impl AIDocumentView {
let appearance = Appearance::as_ref(ctx);
let font_settings = FontSettings::as_ref(ctx);
let styles = rich_text_styles(appearance, font_settings);
NotebooksEditorModel::new_unbound(styles, ctx)
let mut model = NotebooksEditorModel::new_unbound(styles, ctx);
model.set_default_mermaid_display_mode(MarkdownDisplayMode::Rendered, ctx);
model
})
});
@@ -403,6 +437,27 @@ impl AIDocumentView {
})
});
// Create the orchestration config block if there's an active config
// for this document's conversation.
let doc_conversation_id =
AIDocumentModel::as_ref(ctx).get_conversation_id_for_document_id(&document_id);
let has_orchestration_config = doc_conversation_id.and_then(|cid| {
BlocklistAIHistoryModel::as_ref(ctx)
.conversation(&cid)
.and_then(|conv| {
let plan_id_str = document_id.to_string();
conv.orchestration_config_for_plan(&plan_id_str)
.map(|_| cid)
})
});
let doc_id_for_block = document_id;
let orchestration_config_block = has_orchestration_config.map(|conv_id| {
let plan_id = doc_id_for_block.to_string();
ctx.add_typed_action_view(move |ctx| {
OrchestrationConfigBlockView::new(conv_id, plan_id, ctx)
})
});
let mut me = Self {
document_id,
document_version,
@@ -420,6 +475,7 @@ impl AIDocumentView {
synced_status_mouse_state: MouseStateHandle::default(),
view_position_id,
version_button,
orchestration_config_block,
};
// Force update the editor view based on the initial document version
me.refresh(ctx);
@@ -958,8 +1014,9 @@ impl AIDocumentView {
/// Export the current content as a markdown file.
#[cfg(feature = "local_fs")]
fn export(&self, ctx: &mut ViewContext<Self>) {
use crate::drive::export::safe_filename;
use galaxyui::platform::SaveFilePickerConfiguration;
use crate::drive::export::safe_filename;
let markdown = self.editor.as_ref(ctx).markdown_unescaped(ctx);
// Get the document title from the model
@@ -1015,12 +1072,41 @@ impl View for AIDocumentView {
"AIDocumentView"
}
fn render(&self, _app: &AppContext) -> Box<dyn galaxyui::Element> {
fn render(&self, app: &AppContext) -> Box<dyn galaxyui::Element> {
let has_orchestration_config = AIDocumentModel::as_ref(app)
.get_conversation_id_for_document_id(&self.document_id)
.and_then(|cid| {
let plan_id_str = self.document_id.to_string();
BlocklistAIHistoryModel::as_ref(app)
.conversation(&cid)
.and_then(|conv| conv.orchestration_config_for_plan(&plan_id_str).map(|_| ()))
})
.is_some();
let mut content_column =
Flex::column().with_cross_axis_alignment(CrossAxisAlignment::Stretch);
// Orchestration config block — shown above the editor when the
// conversation has an active OrchestrationConfigSnapshot.
if has_orchestration_config {
if let Some(config_block) = &self.orchestration_config_block {
content_column.add_child(
Container::new(ChildView::new(config_block).finish())
.with_horizontal_padding(16.)
.with_padding_bottom(12.)
.with_padding_top(8.)
.finish(),
);
}
}
let editor = Container::new(ChildView::new(&self.editor).finish())
.with_padding_left(8.)
.with_padding_right(8.)
.finish();
let mut stack = Stack::new().with_child(editor);
content_column.add_child(warpui::elements::Expanded::new(1.0, editor).finish());
let mut stack = Stack::new().with_child(content_column.finish());
if self.is_version_menu_open {
stack.add_positioned_overlay_child(
@@ -1052,6 +1138,20 @@ impl TypedActionView for AIDocumentView {
self.refresh(ctx);
}
AIDocumentAction::Export => self.export(ctx),
AIDocumentAction::CopyAsMarkdown => {
let markdown = self.editor.as_ref(ctx).markdown_unescaped(ctx);
ctx.clipboard()
.write(ClipboardContent::plain_text(markdown));
let window_id = ctx.window_id();
ToastStack::handle(ctx).update(ctx, |toast_stack, ctx| {
toast_stack.add_ephemeral_toast(
DismissibleToast::success("Copied to clipboard as Markdown".to_string()),
window_id,
ctx,
);
});
}
AIDocumentAction::CreateWarpDriveNotebook => self.create_warp_drive_notebook(ctx),
AIDocumentAction::CopyLink(link) => {
send_telemetry_from_ctx!(
@@ -1240,6 +1340,13 @@ impl BackingView for AIDocumentView {
);
}
menu_items.push(
MenuItemFields::new("Copy as Markdown")
.with_on_select_action(AIDocumentAction::CopyAsMarkdown)
.with_icon(Icon::Copy)
.into_item(),
);
#[cfg(feature = "local_fs")]
{
menu_items.push(