chore: Refactor code for Input. (#1046)

This commit is contained in:
Jason Lee 2025-07-05 14:37:12 +08:00 committed by GitHub
parent 89ee8c0630
commit 4156c831c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 97 additions and 92 deletions

View file

@ -202,11 +202,11 @@ impl SyntaxHighlighter {
pub fn update( pub fn update(
&mut self, &mut self,
selected_range: &Range<usize>, selected_range: &Range<usize>,
full_text: SharedString, full_text: &SharedString,
new_text: &str, new_text: &str,
cx: &mut App, cx: &mut App,
) { ) {
if self.text == full_text { if &self.text == full_text {
return; return;
} }
@ -244,7 +244,7 @@ impl SyntaxHighlighter {
// Update state // Update state
self.old_tree = Some(new_tree); self.old_tree = Some(new_tree);
self.text = full_text; self.text = full_text.clone();
// let measure = Measure::new("build_styles"); // let measure = Measure::new("build_styles");
self.build_styles(changed_ranges, changed_len, cx); self.build_styles(changed_ranges, changed_len, cx);

View file

@ -79,7 +79,7 @@ impl TextElement {
let mut cursor_bounds = None; let mut cursor_bounds = None;
// If the input has a fixed height (Otherwise is auto-grow), we need to add a bottom margin to the input. // If the input has a fixed height (Otherwise is auto-grow), we need to add a bottom margin to the input.
let bottom_margin = if state.is_auto_grow() { let bottom_margin = if state.mode.is_auto_grow() {
px(0.) + line_height px(0.) + line_height
} else { } else {
BOTTOM_MARGIN_ROWS * line_height + line_height BOTTOM_MARGIN_ROWS * line_height + line_height
@ -336,7 +336,7 @@ impl TextElement {
line_height: Pixels, line_height: Pixels,
input_height: Pixels, input_height: Pixels,
) -> Range<usize> { ) -> Range<usize> {
if state.is_single_line() { if state.mode.is_single_line() {
return 0..1; return 0..1;
} }
@ -510,7 +510,7 @@ impl Element for TextElement {
let mut style = Style::default(); let mut style = Style::default();
style.size.width = relative(1.).into(); style.size.width = relative(1.).into();
if state.is_multi_line() { if state.mode.is_multi_line() {
style.flex_grow = 1.0; style.flex_grow = 1.0;
if let Some(h) = state.mode.height() { if let Some(h) = state.mode.height() {
style.size.height = h.into(); style.size.height = h.into();
@ -543,7 +543,7 @@ impl Element for TextElement {
let highlight_styles = self.highlight_lines(&visible_range, cx); let highlight_styles = self.highlight_lines(&visible_range, cx);
let state = self.state.read(cx); let state = self.state.read(cx);
let multi_line = state.is_multi_line(); let multi_line = state.mode.is_multi_line();
let text = state.text.clone(); let text = state.text.clone();
let is_empty = text.is_empty(); let is_empty = text.is_empty();
let placeholder = self.placeholder.clone(); let placeholder = self.placeholder.clone();

View file

@ -99,7 +99,7 @@ impl Render for DiagnosticPopover {
deferred( deferred(
div() div()
.id("code-editor-diagnostic-popover") .id("diagnostic-popover")
.absolute() .absolute()
.left(x) .left(x)
.top(y) .top(y)

View file

@ -43,6 +43,11 @@ pub enum InputMode {
rows: usize, rows: usize,
height: Option<DefiniteLength>, height: Option<DefiniteLength>,
}, },
AutoGrow {
rows: usize,
min_rows: usize,
max_rows: usize,
},
CodeEditor { CodeEditor {
tab: TabSize, tab: TabSize,
rows: usize, rows: usize,
@ -53,18 +58,33 @@ pub enum InputMode {
highlighter: Rc<RefCell<Option<SyntaxHighlighter>>>, highlighter: Rc<RefCell<Option<SyntaxHighlighter>>>,
markers: Rc<Vec<Marker>>, markers: Rc<Vec<Marker>>,
}, },
AutoGrow {
rows: usize,
min_rows: usize,
max_rows: usize,
},
} }
#[allow(unused)]
impl InputMode { impl InputMode {
#[inline]
pub(super) fn is_single_line(&self) -> bool {
matches!(self, InputMode::SingleLine)
}
#[inline]
pub(super) fn is_code_editor(&self) -> bool { pub(super) fn is_code_editor(&self) -> bool {
matches!(self, InputMode::CodeEditor { .. }) matches!(self, InputMode::CodeEditor { .. })
} }
#[inline]
pub(super) fn is_auto_grow(&self) -> bool {
matches!(self, InputMode::AutoGrow { .. })
}
#[inline]
pub(super) fn is_multi_line(&self) -> bool {
matches!(
self,
InputMode::MultiLine { .. } | InputMode::AutoGrow { .. } | InputMode::CodeEditor { .. }
)
}
pub(super) fn set_rows(&mut self, new_rows: usize) { pub(super) fn set_rows(&mut self, new_rows: usize) {
match self { match self {
InputMode::MultiLine { rows, .. } => { InputMode::MultiLine { rows, .. } => {
@ -162,7 +182,7 @@ impl InputMode {
pub(super) fn update_highlighter( pub(super) fn update_highlighter(
&mut self, &mut self,
selected_range: &Range<usize>, selected_range: &Range<usize>,
full_text: SharedString, full_text: &SharedString,
new_text: &str, new_text: &str,
cx: &mut App, cx: &mut App,
) { ) {

View file

@ -1,7 +1,7 @@
use gpui::{ use gpui::{
actions, prelude::FluentBuilder as _, px, AnyElement, App, Context, ElementId, Entity, actions, prelude::FluentBuilder as _, px, AnyElement, App, Context, Entity, EventEmitter,
EventEmitter, FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, ParentElement, RenderOnce,
ParentElement, RenderOnce, SharedString, Styled, Window, SharedString, Styled, Window,
}; };
use crate::{ use crate::{
@ -24,7 +24,6 @@ pub fn init(cx: &mut App) {
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct NumberInput { pub struct NumberInput {
id: ElementId,
state: Entity<InputState>, state: Entity<InputState>,
placeholder: SharedString, placeholder: SharedString,
size: Size, size: Size,
@ -36,7 +35,6 @@ impl NumberInput {
/// Create a new [`NumberInput`] element bind to the [`InputState`]. /// Create a new [`NumberInput`] element bind to the [`InputState`].
pub fn new(state: &Entity<InputState>) -> Self { pub fn new(state: &Entity<InputState>) -> Self {
Self { Self {
id: ("number-input", state.entity_id()).into(),
state: state.clone(), state: state.clone(),
size: Size::default(), size: Size::default(),
placeholder: SharedString::default(), placeholder: SharedString::default(),
@ -123,7 +121,7 @@ impl RenderOnce for NumberInput {
let focused = self.state.focus_handle(cx).is_focused(window); let focused = self.state.focus_handle(cx).is_focused(window);
h_flex() h_flex()
.id(self.id) .id(("number-input", self.state.entity_id()))
.key_context(KEY_CONTENT) .key_context(KEY_CONTENT)
.on_action(window.listener_for(&self.state, InputState::on_action_increment)) .on_action(window.listener_for(&self.state, InputState::on_action_increment))
.on_action(window.listener_for(&self.state, InputState::on_action_decrement)) .on_action(window.listener_for(&self.state, InputState::on_action_decrement))

View file

@ -244,7 +244,7 @@ impl RenderOnce for OtpInput {
groups[group_ix].push( groups[group_ix].push(
h_flex() h_flex()
.id(("input-otp", ix)) .id(ix)
.border_1() .border_1()
.border_color(cx.theme().input) .border_color(cx.theme().input)
.bg(cx.theme().background) .bg(cx.theme().background)
@ -292,6 +292,7 @@ impl RenderOnce for OtpInput {
} }
v_flex() v_flex()
.id(("otp-input", self.state.entity_id()))
.track_focus(&self.state.read(cx).focus_handle) .track_focus(&self.state.read(cx).focus_handle)
.on_key_down(window.listener_for(&self.state, OtpState::on_key_down)) .on_key_down(window.listener_for(&self.state, OtpState::on_key_down))
.items_center() .items_center()

View file

@ -563,7 +563,7 @@ impl InputState {
/// ///
/// move_lines: Number of lines to move vertically (positive for down, negative for up). /// move_lines: Number of lines to move vertically (positive for down, negative for up).
fn move_vertical(&mut self, move_lines: isize, window: &mut Window, cx: &mut Context<Self>) { fn move_vertical(&mut self, move_lines: isize, window: &mut Window, cx: &mut Context<Self>) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
@ -654,24 +654,6 @@ impl InputState {
cx.notify(); cx.notify();
} }
#[inline]
pub(super) fn is_multi_line(&self) -> bool {
matches!(
self.mode,
InputMode::MultiLine { .. } | InputMode::AutoGrow { .. } | InputMode::CodeEditor { .. }
)
}
#[inline]
pub(super) fn is_single_line(&self) -> bool {
matches!(self.mode, InputMode::SingleLine)
}
#[inline]
pub(super) fn is_auto_grow(&self) -> bool {
matches!(self.mode, InputMode::AutoGrow { .. })
}
/// Set the text of the input field. /// Set the text of the input field.
/// ///
/// And the selection_range will be reset to 0..0. /// And the selection_range will be reset to 0..0.
@ -685,7 +667,7 @@ impl InputState {
self.replace_text(value, window, cx); self.replace_text(value, window, cx);
self.history.ignore = false; self.history.ignore = false;
// Ensure cursor to start when set text // Ensure cursor to start when set text
if self.is_single_line() { if self.mode.is_single_line() {
self.selected_range = self.selected_range =
(Cursor::new(self.text.len())..Cursor::new(self.text.len())).into(); (Cursor::new(self.text.len())..Cursor::new(self.text.len())).into();
} else { } else {
@ -859,7 +841,7 @@ impl InputState {
} }
pub(super) fn up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) { pub(super) fn up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
@ -875,7 +857,7 @@ impl InputState {
} }
pub(super) fn down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) { pub(super) fn down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
@ -892,7 +874,7 @@ impl InputState {
} }
pub(super) fn page_up(&mut self, _: &MovePageUp, window: &mut Window, cx: &mut Context<Self>) { pub(super) fn page_up(&mut self, _: &MovePageUp, window: &mut Window, cx: &mut Context<Self>) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
@ -910,7 +892,7 @@ impl InputState {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
@ -949,7 +931,7 @@ impl InputState {
} }
pub(super) fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) { pub(super) fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
let offset = self.start_of_line(window, cx).saturating_sub(1); let offset = self.start_of_line(window, cx).saturating_sub(1);
@ -962,7 +944,7 @@ impl InputState {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
if self.is_single_line() { if self.mode.is_single_line() {
return; return;
} }
let offset = (self.end_of_line(window, cx) + 1).min(self.text.len()); let offset = (self.end_of_line(window, cx) + 1).min(self.text.len());
@ -1112,7 +1094,7 @@ impl InputState {
/// Get start of line /// Get start of line
fn start_of_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize { fn start_of_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize {
if self.is_single_line() { if self.mode.is_single_line() {
return 0; return 0;
} }
@ -1130,7 +1112,7 @@ impl InputState {
/// ///
/// This is means is always get the first line of selection. /// This is means is always get the first line of selection.
fn start_of_line_of_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize { fn start_of_line_of_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize {
if self.is_single_line() { if self.mode.is_single_line() {
return 0; return 0;
} }
@ -1154,7 +1136,7 @@ impl InputState {
/// Get end of line /// Get end of line
fn end_of_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize { fn end_of_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize {
if self.is_single_line() { if self.mode.is_single_line() {
return self.text.len(); return self.text.len();
} }
@ -1195,7 +1177,7 @@ impl InputState {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> String { ) -> String {
if self.is_single_line() { if self.mode.is_single_line() {
return "".into(); return "".into();
} }
@ -1326,7 +1308,7 @@ impl InputState {
} }
pub(super) fn enter(&mut self, action: &Enter, window: &mut Window, cx: &mut Context<Self>) { pub(super) fn enter(&mut self, action: &Enter, window: &mut Window, cx: &mut Context<Self>) {
if self.is_multi_line() { if self.mode.is_multi_line() {
// Get current line indent // Get current line indent
let indent = if self.mode.is_code_editor() { let indent = if self.mode.is_code_editor() {
self.indent_of_next_line(window, cx) self.indent_of_next_line(window, cx)
@ -1568,25 +1550,28 @@ impl InputState {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
let offset = self.index_for_mouse_position(event.position, window, cx); if self.mode.is_code_editor() {
if let Some(marker) = self.mode.marker_for_offset(offset) { // Show diagnostic popover on mouse move
if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() { let offset = self.index_for_mouse_position(event.position, window, cx);
if diagnostic_popover.read(cx).marker.range == marker.range { if let Some(marker) = self.mode.marker_for_offset(offset) {
diagnostic_popover.update(cx, |this, cx| { if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
this.show(cx); if diagnostic_popover.read(cx).marker.range == marker.range {
}); diagnostic_popover.update(cx, |this, cx| {
this.show(cx);
});
return; return;
}
} }
}
self.diagnostic_popover = Some(DiagnosticPopover::new(marker, cx.entity(), cx)); self.diagnostic_popover = Some(DiagnosticPopover::new(marker, cx.entity(), cx));
cx.notify(); cx.notify();
} else { } else {
if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() { if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() {
diagnostic_popover.update(cx, |this, cx| { diagnostic_popover.update(cx, |this, cx| {
this.check_to_hide(event.position, cx); this.check_to_hide(event.position, cx);
}) })
}
} }
} }
} }
@ -1652,7 +1637,7 @@ impl InputState {
pub(super) fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) { pub(super) fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
if let Some(clipboard) = cx.read_from_clipboard() { if let Some(clipboard) = cx.read_from_clipboard() {
let mut new_text = clipboard.text().unwrap_or_default(); let mut new_text = clipboard.text().unwrap_or_default();
if !self.is_multi_line() { if !self.mode.is_multi_line() {
new_text = new_text.replace('\n', ""); new_text = new_text.replace('\n', "");
} }
@ -1770,7 +1755,7 @@ impl InputState {
let pos = inner_position - line_origin; let pos = inner_position - line_origin;
// Return offset by use closest_index_for_x if is single line mode. // Return offset by use closest_index_for_x if is single line mode.
if self.is_single_line() { if self.mode.is_single_line() {
return line.unwrapped_layout.closest_index_for_x(pos.x); return line.unwrapped_layout.closest_index_for_x(pos.x);
} }
@ -1820,7 +1805,7 @@ impl InputState {
// //
// If only 1 line, the value is 0 // If only 1 line, the value is 0
// If have 2 line, the value is 1 // If have 2 line, the value is 1
if self.is_multi_line() { if self.mode.is_multi_line() {
let p = point(px(0.), *y_offset); let p = point(px(0.), *y_offset);
let height = line_height + line.wrap_boundaries.len() as f32 * line_height; let height = line_height + line.wrap_boundaries.len() as f32 * line_height;
*y_offset = *y_offset + height; *y_offset = *y_offset + height;
@ -2181,9 +2166,9 @@ impl EntityInputHandler for InputState {
self.push_history(&range, &new_text, window, cx); self.push_history(&range, &new_text, window, cx);
self.text = mask_text.clone(); self.text = mask_text.clone();
self.mode self.mode
.update_highlighter(&range, self.text.clone(), &new_text, cx); .update_highlighter(&range, &self.text, &new_text, cx);
self.mode.clear_markers(); self.mode.clear_markers();
self.text_wrapper.update(self.text.clone(), false, cx); self.text_wrapper.update(&self.text, false, cx);
self.selected_range = (new_offset..new_offset).into(); self.selected_range = (new_offset..new_offset).into();
self.marked_range.take(); self.marked_range.take();
self.update_preferred_x_offset(cx); self.update_preferred_x_offset(cx);
@ -2222,9 +2207,9 @@ impl EntityInputHandler for InputState {
self.push_history(&range, new_text, window, cx); self.push_history(&range, new_text, window, cx);
self.text = pending_text; self.text = pending_text;
self.mode self.mode
.update_highlighter(&range, self.text.clone(), &new_text, cx); .update_highlighter(&range, &self.text, &new_text, cx);
self.mode.clear_markers(); self.mode.clear_markers();
self.text_wrapper.update(self.text.clone(), false, cx); self.text_wrapper.update(&self.text, false, cx);
if new_text.is_empty() { if new_text.is_empty() {
// Cancel selection, when cancel IME input. // Cancel selection, when cancel IME input.
self.selected_range = (range.start..range.start).into(); self.selected_range = (range.start..range.start).into();
@ -2327,14 +2312,13 @@ impl Focusable for InputState {
impl Render for InputState { impl Render for InputState {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
self.text_wrapper.update(self.text.clone(), false, cx); self.text_wrapper.update(&self.text, false, cx);
self.mode self.mode.update_highlighter(&(0..0), &self.text, "", cx);
.update_highlighter(&(0..0), self.text.clone(), "", cx);
div() div()
.id("text-element") .id("input-state")
.flex_1() .flex_1()
.when(self.is_multi_line(), |this| this.h_full()) .when(self.mode.is_multi_line(), |this| this.h_full())
.flex_grow() .flex_grow()
.overflow_x_hidden() .overflow_x_hidden()
.child(TextElement::new(cx.entity().clone()).placeholder(self.placeholder.clone())) .child(TextElement::new(cx.entity().clone()).placeholder(self.placeholder.clone()))

View file

@ -174,8 +174,10 @@ impl RenderOnce for TextInput {
let prefix = self.prefix; let prefix = self.prefix;
let suffix = self.suffix; let suffix = self.suffix;
let show_clear_button = let show_clear_button = self.cleanable
self.cleanable && !state.loading && !state.text.is_empty() && state.is_single_line(); && !state.loading
&& !state.text.is_empty()
&& state.mode.is_single_line();
let has_suffix = suffix.is_some() || state.loading || self.mask_toggle || show_clear_button; let has_suffix = suffix.is_some() || state.loading || self.mask_toggle || show_clear_button;
div() div()
@ -198,7 +200,7 @@ impl RenderOnce for TextInput {
.on_action(window.listener_for(&self.state, InputState::cut)) .on_action(window.listener_for(&self.state, InputState::cut))
.on_action(window.listener_for(&self.state, InputState::undo)) .on_action(window.listener_for(&self.state, InputState::undo))
.on_action(window.listener_for(&self.state, InputState::redo)) .on_action(window.listener_for(&self.state, InputState::redo))
.when(state.is_multi_line(), |this| { .when(state.mode.is_multi_line(), |this| {
this.on_action(window.listener_for(&self.state, InputState::indent_inline)) this.on_action(window.listener_for(&self.state, InputState::indent_inline))
.on_action(window.listener_for(&self.state, InputState::outdent_inline)) .on_action(window.listener_for(&self.state, InputState::outdent_inline))
.on_action(window.listener_for(&self.state, InputState::indent_block)) .on_action(window.listener_for(&self.state, InputState::indent_block))
@ -209,7 +211,7 @@ impl RenderOnce for TextInput {
.on_action(window.listener_for(&self.state, InputState::right)) .on_action(window.listener_for(&self.state, InputState::right))
.on_action(window.listener_for(&self.state, InputState::select_left)) .on_action(window.listener_for(&self.state, InputState::select_left))
.on_action(window.listener_for(&self.state, InputState::select_right)) .on_action(window.listener_for(&self.state, InputState::select_right))
.when(state.is_multi_line(), |this| { .when(state.mode.is_multi_line(), |this| {
this.on_action(window.listener_for(&self.state, InputState::up)) this.on_action(window.listener_for(&self.state, InputState::up))
.on_action(window.listener_for(&self.state, InputState::down)) .on_action(window.listener_for(&self.state, InputState::down))
.on_action(window.listener_for(&self.state, InputState::select_up)) .on_action(window.listener_for(&self.state, InputState::select_up))
@ -249,7 +251,7 @@ impl RenderOnce for TextInput {
.input_h(self.size) .input_h(self.size)
.cursor_text() .cursor_text()
.text_size(font_size) .text_size(font_size)
.when(state.is_multi_line(), |this| { .when(state.mode.is_multi_line(), |this| {
this.h_auto() this.h_auto()
.when_some(self.height, |this, height| this.h(height)) .when_some(self.height, |this, height| this.h(height))
}) })
@ -297,7 +299,7 @@ impl RenderOnce for TextInput {
) )
}) })
.refine_style(&self.style) .refine_style(&self.style)
.when(state.is_multi_line(), |this| { .when(state.mode.is_multi_line(), |this| {
if state.last_layout.is_some() { if state.last_layout.is_some() {
this.relative().child( this.relative().child(
div() div()

View file

@ -47,20 +47,20 @@ impl TextWrapper {
pub(super) fn set_wrap_width(&mut self, wrap_width: Option<Pixels>, cx: &mut App) { pub(super) fn set_wrap_width(&mut self, wrap_width: Option<Pixels>, cx: &mut App) {
self.wrap_width = wrap_width; self.wrap_width = wrap_width;
self.update(self.text.clone(), true, cx); self.update(&self.text.clone(), true, cx);
} }
pub(super) fn set_font(&mut self, font: Font, font_size: Pixels, cx: &mut App) { pub(super) fn set_font(&mut self, font: Font, font_size: Pixels, cx: &mut App) {
self.font = font; self.font = font;
self.font_size = font_size; self.font_size = font_size;
self.update(self.text.clone(), true, cx); self.update(&self.text.clone(), true, cx);
} }
/// Update the text wrapper and recalculate the wrapped lines. /// Update the text wrapper and recalculate the wrapped lines.
/// ///
/// If the `text` is the same as the current text, do nothing. /// If the `text` is the same as the current text, do nothing.
pub(super) fn update(&mut self, text: SharedString, force: bool, cx: &mut App) { pub(super) fn update(&mut self, text: &SharedString, force: bool, cx: &mut App) {
if self.text == text && !force { if &self.text == text && !force {
return; return;
} }
@ -96,7 +96,7 @@ impl TextWrapper {
prev_line_ix += line.len() + 1; prev_line_ix += line.len() + 1;
} }
self.text = text; self.text = text.clone();
self.wrapped_lines = wrapped_lines; self.wrapped_lines = wrapped_lines;
self.lines = lines; self.lines = lines;
} }

View file

@ -242,7 +242,7 @@ impl CodeBlock {
let mut styles = vec![]; let mut styles = vec![];
if let Some(lang) = &lang { if let Some(lang) = &lang {
let mut highlighter = SyntaxHighlighter::new(&lang, cx); let mut highlighter = SyntaxHighlighter::new(&lang, cx);
highlighter.update(&(0..0), code.clone(), "", cx); highlighter.update(&(0..0), &code, "", cx);
styles = highlighter.styles(&(0..code.len()), &theme); styles = highlighter.styles(&(0..code.len()), &theme);
}; };