text_view: Add to support custom code block style. (#1288)

And remove bg, padding for editor hover code blocks.

<img width="589" height="214" alt="image"
src="https://github.com/user-attachments/assets/55870f2f-e49e-4c2d-8899-9aa7edd17630"
/>
This commit is contained in:
Jason Lee 2025-09-25 17:11:14 +08:00 committed by GitHub
parent a6a14fd57b
commit 512f46aec8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 94 additions and 67 deletions

View file

@ -11,13 +11,13 @@ pub(crate) use diagnostic_popover::*;
pub(crate) use hover_popover::*;
use gpui::{
div, rems, App, Div, ElementId, Entity, InteractiveElement as _, IntoElement, SharedString,
Stateful, Styled as _, Window,
div, px, rems, App, Div, ElementId, Entity, InteractiveElement as _, IntoElement, SharedString,
Stateful, StyleRefinement, Styled as _, Window,
};
use crate::{
text::{TextView, TextViewStyle},
StyledExt as _,
ActiveTheme, StyledExt as _,
};
pub(crate) enum ContextMenu {
@ -58,7 +58,13 @@ pub(super) fn render_markdown(
1..=3 => rem_size * 1,
4 => rem_size * 0.9,
_ => rem_size * 0.8,
}),
})
.code_block(
StyleRefinement::default()
.bg(cx.theme().transparent)
.p_0()
.text_size(px(11.)),
),
)
.selectable()
}

View file

@ -1,10 +1,12 @@
mod format;
mod inline;
mod node;
mod style;
mod text_view;
mod utils;
use gpui::App;
pub use style::*;
pub use text_view::*;
pub(crate) fn init(cx: &mut App) {

View file

@ -3,7 +3,7 @@ use std::{collections::HashMap, ops::Range};
use gpui::{
div, img, prelude::FluentBuilder as _, px, relative, rems, AnyElement, App, DefiniteLength,
Div, ElementId, FontStyle, FontWeight, Half, HighlightStyle, InteractiveElement as _,
IntoElement, Length, ObjectFit, ParentElement, Rems, SharedString, SharedUri,
IntoElement, Length, ObjectFit, ParentElement, SharedString, SharedUri,
StatefulInteractiveElement, Styled, StyledImage as _, Window,
};
use markdown::mdast;
@ -14,7 +14,7 @@ use crate::{
highlighter::SyntaxHighlighter,
text::inline::{Inline, InlineState},
tooltip::Tooltip,
v_flex, ActiveTheme as _, Icon, IconName,
v_flex, ActiveTheme as _, Icon, IconName, StyledExt,
};
use super::{utils::list_item_prefix, TextViewStyle};
@ -318,16 +318,19 @@ impl CodeBlock {
text
}
fn render(&self, mb: Rems, _: &mut Window, cx: &mut App) -> AnyElement {
fn render(&self, node_cx: &NodeContext, _: &mut Window, cx: &mut App) -> AnyElement {
let style = &node_cx.style;
div()
.id("codeblock")
.mb(mb)
.mb(style.paragraph_gap)
.p_3()
.rounded(cx.theme().radius)
.bg(cx.theme().accent)
.font_family("Menlo, Monaco, Consolas, monospace")
.text_size(rems(0.875))
.relative()
.refine_style(&style.code_block)
.child(Inline::new(
"code",
self.state.clone(),
@ -927,7 +930,7 @@ impl Node {
items
})
.into_any_element(),
Node::CodeBlock(code_block) => code_block.render(mb, window, cx),
Node::CodeBlock(code_block) => code_block.render(node_cx, window, cx),
Node::Table { .. } => Self::render_table(&self, node_cx, window, cx).into_any_element(),
Node::Divider => div()
.id("divider")

View file

@ -0,0 +1,67 @@
use std::{rc::Rc, sync::Arc};
use gpui::{px, rems, Pixels, Rems, StyleRefinement};
use crate::highlighter::HighlightTheme;
/// TextViewStyle used to customize the style for [`TextView`].
#[derive(Clone)]
pub struct TextViewStyle {
/// Gap of each paragraphs, default is 1 rem.
pub paragraph_gap: Rems,
/// Base font size for headings, default is 14px.
pub heading_base_font_size: Pixels,
/// Function to calculate heading font size based on heading level (1-6).
///
/// The first parameter is the heading level (1-6), the second parameter is the base font size.
/// The second parameter is the base font size.
pub heading_font_size: Option<Rc<dyn Fn(u8, Pixels) -> Pixels + 'static>>,
/// Highlight theme for code blocks. Default: [`HighlightTheme::default_light()`]
pub highlight_theme: Arc<HighlightTheme>,
/// The style refinement for code blocks.
pub code_block: StyleRefinement,
pub is_dark: bool,
}
impl PartialEq for TextViewStyle {
fn eq(&self, other: &Self) -> bool {
self.paragraph_gap == other.paragraph_gap
&& self.heading_base_font_size == other.heading_base_font_size
&& self.highlight_theme == other.highlight_theme
}
}
impl Default for TextViewStyle {
fn default() -> Self {
Self {
paragraph_gap: rems(1.),
heading_base_font_size: px(14.),
heading_font_size: None,
highlight_theme: HighlightTheme::default_light().clone(),
code_block: StyleRefinement::default(),
is_dark: false,
}
}
}
impl TextViewStyle {
/// Set paragraph gap, default is 1 rem.
pub fn paragraph_gap(mut self, gap: Rems) -> Self {
self.paragraph_gap = gap;
self
}
pub fn heading_font_size<F>(mut self, f: F) -> Self
where
F: Fn(u8, Pixels) -> Pixels + 'static,
{
self.heading_font_size = Some(Rc::new(f));
self
}
/// Set style for code blocks.
pub fn code_block(mut self, style: StyleRefinement) -> Self {
self.code_block = style;
self
}
}

View file

@ -1,18 +1,20 @@
use std::{rc::Rc, sync::Arc, time::Instant};
use std::{rc::Rc, time::Instant};
use gpui::{
div, px, rems, AnyElement, App, Bounds, ClipboardItem, Element, ElementId, Entity, FocusHandle,
div, AnyElement, App, Bounds, ClipboardItem, Element, ElementId, Entity, FocusHandle,
GlobalElementId, InspectorElementId, InteractiveElement, IntoElement, KeyBinding, LayoutId,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Rems, RenderOnce,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, RenderOnce,
SharedString, Size, Window,
};
use super::format::{html::HtmlElement, markdown::MarkdownElement};
use crate::{
global_state::GlobalState,
highlighter::HighlightTheme,
input::{self},
text::node::{self, NodeContext},
text::{
node::{self, NodeContext},
TextViewStyle,
},
};
const CONTEXT: &'static str = "TextView";
@ -270,59 +272,6 @@ impl RenderOnce for Text {
}
}
/// TextViewStyle used to customize the style for [`TextView`].
#[derive(Clone)]
pub struct TextViewStyle {
/// Gap of each paragraphs, default is 1 rem.
pub paragraph_gap: Rems,
/// Base font size for headings, default is 14px.
pub heading_base_font_size: Pixels,
/// Function to calculate heading font size based on heading level (1-6).
///
/// The first parameter is the heading level (1-6), the second parameter is the base font size.
/// The second parameter is the base font size.
pub heading_font_size: Option<Rc<dyn Fn(u8, Pixels) -> Pixels + 'static>>,
/// Highlight theme for code blocks. Default: [`HighlightTheme::default_light()`]
pub highlight_theme: Arc<HighlightTheme>,
pub is_dark: bool,
}
impl PartialEq for TextViewStyle {
fn eq(&self, other: &Self) -> bool {
self.paragraph_gap == other.paragraph_gap
&& self.heading_base_font_size == other.heading_base_font_size
&& self.highlight_theme == other.highlight_theme
}
}
impl Default for TextViewStyle {
fn default() -> Self {
Self {
paragraph_gap: rems(1.),
heading_base_font_size: px(14.),
heading_font_size: None,
highlight_theme: HighlightTheme::default_light().clone(),
is_dark: false,
}
}
}
impl TextViewStyle {
/// Set paragraph gap, default is 1 rem.
pub fn paragraph_gap(mut self, gap: Rems) -> Self {
self.paragraph_gap = gap;
self
}
pub fn heading_font_size<F>(mut self, f: F) -> Self
where
F: Fn(u8, Pixels) -> Pixels + 'static,
{
self.heading_font_size = Some(Rc::new(f));
self
}
}
impl TextView {
/// Create a new markdown text view.
pub fn markdown(