crates/editor/src/hover_popover.rs 🔗
@@ -590,6 +590,7 @@ async fn parse_blocks(
fallback_language_name,
cx,
)
+ .copy_code_block_buttons(false)
})
.ok();
Kirill Bulatov created
Follow-up of https://github.com/zed-industries/zed/pull/22866
Added a config option to the markdown renderer to omit code copying
buttons, and used those for editor hover popovers.
Such popovers are quite frequent in language servers' hover responses,
e.g. rust-analyzer on `.clone()` hover may respond with
```
{"jsonrpc":"2.0","id":119,"result":{"contents":{"kind":"markdown","value":"\n```rust\nalloc::string::String\n```\n\n```rust\nfn clone(&self) -> Self\n```\n\n---\n\nReturns a copy of the value.\n\n# Examples\n\n```rust\nlet hello = \"Hello\"; // &str implements Clone\n\nassert_eq!(\"Hello\", hello.clone());\n```"},"range":{"start":{"line":518,"character":24},"end":{"line":518,"character":29}}}}
```
(note multiple code blocks sent)


Sounds that editor has either to use a different way to copy popover's
data (so the entire text gets copied, not just its code blocks), or at
least better handle hover popover's hovering to show the button.
Release Notes:
- N/A
crates/editor/src/hover_popover.rs | 1
crates/markdown/src/markdown.rs | 77 ++++++++++++++++++++-----------
2 files changed, 50 insertions(+), 28 deletions(-)
@@ -590,6 +590,7 @@ async fn parse_blocks(
fallback_language_name,
cx,
)
+ .copy_code_block_buttons(false)
})
.ok();
@@ -61,7 +61,13 @@ pub struct Markdown {
focus_handle: FocusHandle,
language_registry: Option<Arc<LanguageRegistry>>,
fallback_code_block_language: Option<String>,
+ options: Options,
+}
+
+#[derive(Debug)]
+struct Options {
parse_links_only: bool,
+ copy_code_block_buttons: bool,
}
actions!(markdown, [Copy]);
@@ -87,7 +93,10 @@ impl Markdown {
focus_handle,
language_registry,
fallback_code_block_language,
- parse_links_only: false,
+ options: Options {
+ parse_links_only: false,
+ copy_code_block_buttons: true,
+ },
};
this.parse(cx);
this
@@ -113,7 +122,10 @@ impl Markdown {
focus_handle,
language_registry,
fallback_code_block_language,
- parse_links_only: true,
+ options: Options {
+ parse_links_only: true,
+ copy_code_block_buttons: true,
+ },
};
this.parse(cx);
this
@@ -164,7 +176,7 @@ impl Markdown {
}
let text = self.source.clone();
- let parse_text_only = self.parse_links_only;
+ let parse_text_only = self.options.parse_links_only;
let parsed = cx.background_executor().spawn(async move {
let text = SharedString::from(text);
let events = match parse_text_only {
@@ -195,6 +207,11 @@ impl Markdown {
.log_err()
}));
}
+
+ pub fn copy_code_block_buttons(mut self, should_copy: bool) -> Self {
+ self.options.copy_code_block_buttons = should_copy;
+ self
+ }
}
impl Render for Markdown {
@@ -667,31 +684,35 @@ impl Element for MarkdownElement {
}
MarkdownTagEnd::CodeBlock => {
builder.trim_trailing_newline();
- builder.flush_text();
- builder.modify_current_div(|el| {
- let id =
- ElementId::NamedInteger("copy-markdown-code".into(), range.end);
- let copy_button = div().absolute().top_1().right_1().w_5().child(
- IconButton::new(id, IconName::Copy)
- .icon_color(Color::Muted)
- .shape(ui::IconButtonShape::Square)
- .tooltip(|cx| Tooltip::text("Copy Code Block", cx))
- .on_click({
- let code = without_fences(
- parsed_markdown.source()[range.clone()].trim(),
- )
- .to_string();
-
- move |_, cx| {
- cx.write_to_clipboard(ClipboardItem::new_string(
- code.clone(),
- ))
- }
- }),
- );
- el.child(copy_button)
- });
+ if self.markdown.read(cx).options.copy_code_block_buttons {
+ builder.flush_text();
+ builder.modify_current_div(|el| {
+ let id =
+ ElementId::NamedInteger("copy-markdown-code".into(), range.end);
+ let copy_button = div().absolute().top_1().right_1().w_5().child(
+ IconButton::new(id, IconName::Copy)
+ .icon_color(Color::Muted)
+ .shape(ui::IconButtonShape::Square)
+ .tooltip(|cx| Tooltip::text("Copy Code Block", cx))
+ .on_click({
+ let code = without_fences(
+ parsed_markdown.source()[range.clone()].trim(),
+ )
+ .to_string();
+
+ move |_, cx| {
+ cx.write_to_clipboard(ClipboardItem::new_string(
+ code.clone(),
+ ))
+ }
+ }),
+ );
+
+ el.child(copy_button)
+ });
+ }
+
builder.pop_div();
builder.pop_code_block();
if self.style.code_block.text.is_some() {
@@ -1033,7 +1054,7 @@ impl MarkdownElementBuilder {
}
}
- pub fn flush_text(&mut self) {
+ fn flush_text(&mut self) {
let line = mem::take(&mut self.pending_line);
if line.text.is_empty() {
return;