From fe1ae1860e5dbc6d779e6e00da7c446fffe5b671 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Mon, 7 Apr 2025 17:42:11 -0400 Subject: [PATCH] agent: Copy text as Markdown (#28272) Release Notes: - agent: Copying text in the Agent Panel will now copy it as Markdown. Co-authored-by: Antonio Scandurra --- assets/keymaps/default-linux.json | 7 +++++++ assets/keymaps/default-macos.json | 7 +++++++ crates/markdown/src/markdown.rs | 20 ++++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index fac89607d1..0e1163b53e 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -634,6 +634,13 @@ "ctrl-alt-e": "agent::RemoveAllContext" } }, + { + "context": "AgentPanel > Markdown", + "bindings": { + "copy": "markdown::CopyAsMarkdown", + "ctrl-c": "markdown::CopyAsMarkdown" + } + }, { "context": "AgentPanel && prompt_editor", "use_key_equivalents": true, diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 60735166e2..49c0b65b53 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -291,6 +291,13 @@ "cmd-alt-e": "agent::RemoveAllContext" } }, + { + "context": "AgentPanel > Markdown", + "use_key_equivalents": true, + "bindings": { + "cmd-c": "markdown::CopyAsMarkdown" + } + }, { "context": "AgentPanel && prompt_editor", "use_key_equivalents": true, diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs index 081ccea9fb..5aa70c0cba 100644 --- a/crates/markdown/src/markdown.rs +++ b/crates/markdown/src/markdown.rs @@ -90,7 +90,7 @@ struct Options { copy_code_block_buttons: bool, } -actions!(markdown, [Copy]); +actions!(markdown, [Copy, CopyAsMarkdown]); impl Markdown { pub fn new( @@ -178,6 +178,14 @@ impl Markdown { cx.write_to_clipboard(ClipboardItem::new_string(text)); } + fn copy_as_markdown(&self, _: &mut Window, cx: &mut Context) { + if self.selection.end <= self.selection.start { + return; + } + let text = self.source[self.selection.start..self.selection.end].to_string(); + cx.write_to_clipboard(ClipboardItem::new_string(text)); + } + fn parse(&mut self, cx: &mut Context) { if self.source.is_empty() { return; @@ -1040,8 +1048,8 @@ impl Element for MarkdownElement { let mut context = KeyContext::default(); context.add("Markdown"); window.set_key_context(context); - let entity = self.markdown.clone(); window.on_action(std::any::TypeId::of::(), { + let entity = self.markdown.clone(); let text = rendered_markdown.text.clone(); move |_, phase, window, cx| { let text = text.clone(); @@ -1050,6 +1058,14 @@ impl Element for MarkdownElement { } } }); + window.on_action(std::any::TypeId::of::(), { + let entity = self.markdown.clone(); + move |_, phase, window, cx| { + if phase == DispatchPhase::Bubble { + entity.update(cx, move |this, cx| this.copy_as_markdown(window, cx)) + } + } + }); self.paint_mouse_listeners(hitbox, &rendered_markdown.text, window, cx); rendered_markdown.element.paint(window, cx);