chore: Refactor code for Input. (#1046)
This commit is contained in:
parent
89ee8c0630
commit
4156c831c6
10 changed files with 97 additions and 92 deletions
|
|
@ -202,11 +202,11 @@ impl SyntaxHighlighter {
|
|||
pub fn update(
|
||||
&mut self,
|
||||
selected_range: &Range<usize>,
|
||||
full_text: SharedString,
|
||||
full_text: &SharedString,
|
||||
new_text: &str,
|
||||
cx: &mut App,
|
||||
) {
|
||||
if self.text == full_text {
|
||||
if &self.text == full_text {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ impl SyntaxHighlighter {
|
|||
|
||||
// Update state
|
||||
self.old_tree = Some(new_tree);
|
||||
self.text = full_text;
|
||||
self.text = full_text.clone();
|
||||
|
||||
// let measure = Measure::new("build_styles");
|
||||
self.build_styles(changed_ranges, changed_len, cx);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl TextElement {
|
|||
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.
|
||||
let bottom_margin = if state.is_auto_grow() {
|
||||
let bottom_margin = if state.mode.is_auto_grow() {
|
||||
px(0.) + line_height
|
||||
} else {
|
||||
BOTTOM_MARGIN_ROWS * line_height + line_height
|
||||
|
|
@ -336,7 +336,7 @@ impl TextElement {
|
|||
line_height: Pixels,
|
||||
input_height: Pixels,
|
||||
) -> Range<usize> {
|
||||
if state.is_single_line() {
|
||||
if state.mode.is_single_line() {
|
||||
return 0..1;
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +510,7 @@ impl Element for TextElement {
|
|||
|
||||
let mut style = Style::default();
|
||||
style.size.width = relative(1.).into();
|
||||
if state.is_multi_line() {
|
||||
if state.mode.is_multi_line() {
|
||||
style.flex_grow = 1.0;
|
||||
if let Some(h) = state.mode.height() {
|
||||
style.size.height = h.into();
|
||||
|
|
@ -543,7 +543,7 @@ impl Element for TextElement {
|
|||
let highlight_styles = self.highlight_lines(&visible_range, 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 is_empty = text.is_empty();
|
||||
let placeholder = self.placeholder.clone();
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl Render for DiagnosticPopover {
|
|||
|
||||
deferred(
|
||||
div()
|
||||
.id("code-editor-diagnostic-popover")
|
||||
.id("diagnostic-popover")
|
||||
.absolute()
|
||||
.left(x)
|
||||
.top(y)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ pub enum InputMode {
|
|||
rows: usize,
|
||||
height: Option<DefiniteLength>,
|
||||
},
|
||||
AutoGrow {
|
||||
rows: usize,
|
||||
min_rows: usize,
|
||||
max_rows: usize,
|
||||
},
|
||||
CodeEditor {
|
||||
tab: TabSize,
|
||||
rows: usize,
|
||||
|
|
@ -53,18 +58,33 @@ pub enum InputMode {
|
|||
highlighter: Rc<RefCell<Option<SyntaxHighlighter>>>,
|
||||
markers: Rc<Vec<Marker>>,
|
||||
},
|
||||
AutoGrow {
|
||||
rows: usize,
|
||||
min_rows: usize,
|
||||
max_rows: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl InputMode {
|
||||
#[inline]
|
||||
pub(super) fn is_single_line(&self) -> bool {
|
||||
matches!(self, InputMode::SingleLine)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn is_code_editor(&self) -> bool {
|
||||
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) {
|
||||
match self {
|
||||
InputMode::MultiLine { rows, .. } => {
|
||||
|
|
@ -162,7 +182,7 @@ impl InputMode {
|
|||
pub(super) fn update_highlighter(
|
||||
&mut self,
|
||||
selected_range: &Range<usize>,
|
||||
full_text: SharedString,
|
||||
full_text: &SharedString,
|
||||
new_text: &str,
|
||||
cx: &mut App,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use gpui::{
|
||||
actions, prelude::FluentBuilder as _, px, AnyElement, App, Context, ElementId, Entity,
|
||||
EventEmitter, FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding,
|
||||
ParentElement, RenderOnce, SharedString, Styled, Window,
|
||||
actions, prelude::FluentBuilder as _, px, AnyElement, App, Context, Entity, EventEmitter,
|
||||
FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, ParentElement, RenderOnce,
|
||||
SharedString, Styled, Window,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -24,7 +24,6 @@ pub fn init(cx: &mut App) {
|
|||
|
||||
#[derive(IntoElement)]
|
||||
pub struct NumberInput {
|
||||
id: ElementId,
|
||||
state: Entity<InputState>,
|
||||
placeholder: SharedString,
|
||||
size: Size,
|
||||
|
|
@ -36,7 +35,6 @@ impl NumberInput {
|
|||
/// Create a new [`NumberInput`] element bind to the [`InputState`].
|
||||
pub fn new(state: &Entity<InputState>) -> Self {
|
||||
Self {
|
||||
id: ("number-input", state.entity_id()).into(),
|
||||
state: state.clone(),
|
||||
size: Size::default(),
|
||||
placeholder: SharedString::default(),
|
||||
|
|
@ -123,7 +121,7 @@ impl RenderOnce for NumberInput {
|
|||
let focused = self.state.focus_handle(cx).is_focused(window);
|
||||
|
||||
h_flex()
|
||||
.id(self.id)
|
||||
.id(("number-input", self.state.entity_id()))
|
||||
.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_decrement))
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ impl RenderOnce for OtpInput {
|
|||
|
||||
groups[group_ix].push(
|
||||
h_flex()
|
||||
.id(("input-otp", ix))
|
||||
.id(ix)
|
||||
.border_1()
|
||||
.border_color(cx.theme().input)
|
||||
.bg(cx.theme().background)
|
||||
|
|
@ -292,6 +292,7 @@ impl RenderOnce for OtpInput {
|
|||
}
|
||||
|
||||
v_flex()
|
||||
.id(("otp-input", self.state.entity_id()))
|
||||
.track_focus(&self.state.read(cx).focus_handle)
|
||||
.on_key_down(window.listener_for(&self.state, OtpState::on_key_down))
|
||||
.items_center()
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ impl InputState {
|
|||
///
|
||||
/// 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>) {
|
||||
if self.is_single_line() {
|
||||
if self.mode.is_single_line() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -654,24 +654,6 @@ impl InputState {
|
|||
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.
|
||||
///
|
||||
/// And the selection_range will be reset to 0..0.
|
||||
|
|
@ -685,7 +667,7 @@ impl InputState {
|
|||
self.replace_text(value, window, cx);
|
||||
self.history.ignore = false;
|
||||
// Ensure cursor to start when set text
|
||||
if self.is_single_line() {
|
||||
if self.mode.is_single_line() {
|
||||
self.selected_range =
|
||||
(Cursor::new(self.text.len())..Cursor::new(self.text.len())).into();
|
||||
} else {
|
||||
|
|
@ -859,7 +841,7 @@ impl InputState {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -875,7 +857,7 @@ impl InputState {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -892,7 +874,7 @@ impl InputState {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -910,7 +892,7 @@ impl InputState {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.is_single_line() {
|
||||
if self.mode.is_single_line() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -949,7 +931,7 @@ impl InputState {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
let offset = self.start_of_line(window, cx).saturating_sub(1);
|
||||
|
|
@ -962,7 +944,7 @@ impl InputState {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.is_single_line() {
|
||||
if self.mode.is_single_line() {
|
||||
return;
|
||||
}
|
||||
let offset = (self.end_of_line(window, cx) + 1).min(self.text.len());
|
||||
|
|
@ -1112,7 +1094,7 @@ impl InputState {
|
|||
|
||||
/// Get start of line
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -1130,7 +1112,7 @@ impl InputState {
|
|||
///
|
||||
/// 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 {
|
||||
if self.is_single_line() {
|
||||
if self.mode.is_single_line() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1154,7 +1136,7 @@ impl InputState {
|
|||
|
||||
/// Get end of line
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -1195,7 +1177,7 @@ impl InputState {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> String {
|
||||
if self.is_single_line() {
|
||||
if self.mode.is_single_line() {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
|
|
@ -1326,7 +1308,7 @@ impl InputState {
|
|||
}
|
||||
|
||||
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
|
||||
let indent = if self.mode.is_code_editor() {
|
||||
self.indent_of_next_line(window, cx)
|
||||
|
|
@ -1568,25 +1550,28 @@ impl InputState {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let offset = self.index_for_mouse_position(event.position, window, cx);
|
||||
if let Some(marker) = self.mode.marker_for_offset(offset) {
|
||||
if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
|
||||
if diagnostic_popover.read(cx).marker.range == marker.range {
|
||||
diagnostic_popover.update(cx, |this, cx| {
|
||||
this.show(cx);
|
||||
});
|
||||
if self.mode.is_code_editor() {
|
||||
// Show diagnostic popover on mouse move
|
||||
let offset = self.index_for_mouse_position(event.position, window, cx);
|
||||
if let Some(marker) = self.mode.marker_for_offset(offset) {
|
||||
if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
|
||||
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));
|
||||
cx.notify();
|
||||
} else {
|
||||
if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() {
|
||||
diagnostic_popover.update(cx, |this, cx| {
|
||||
this.check_to_hide(event.position, cx);
|
||||
})
|
||||
self.diagnostic_popover = Some(DiagnosticPopover::new(marker, cx.entity(), cx));
|
||||
cx.notify();
|
||||
} else {
|
||||
if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() {
|
||||
diagnostic_popover.update(cx, |this, 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>) {
|
||||
if let Some(clipboard) = cx.read_from_clipboard() {
|
||||
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', "");
|
||||
}
|
||||
|
||||
|
|
@ -1770,7 +1755,7 @@ impl InputState {
|
|||
let pos = inner_position - line_origin;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
|
@ -1820,7 +1805,7 @@ impl InputState {
|
|||
//
|
||||
// If only 1 line, the value is 0
|
||||
// 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 height = line_height + line.wrap_boundaries.len() as f32 * line_height;
|
||||
*y_offset = *y_offset + height;
|
||||
|
|
@ -2181,9 +2166,9 @@ impl EntityInputHandler for InputState {
|
|||
self.push_history(&range, &new_text, window, cx);
|
||||
self.text = mask_text.clone();
|
||||
self.mode
|
||||
.update_highlighter(&range, self.text.clone(), &new_text, cx);
|
||||
.update_highlighter(&range, &self.text, &new_text, cx);
|
||||
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.marked_range.take();
|
||||
self.update_preferred_x_offset(cx);
|
||||
|
|
@ -2222,9 +2207,9 @@ impl EntityInputHandler for InputState {
|
|||
self.push_history(&range, new_text, window, cx);
|
||||
self.text = pending_text;
|
||||
self.mode
|
||||
.update_highlighter(&range, self.text.clone(), &new_text, cx);
|
||||
.update_highlighter(&range, &self.text, &new_text, cx);
|
||||
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() {
|
||||
// Cancel selection, when cancel IME input.
|
||||
self.selected_range = (range.start..range.start).into();
|
||||
|
|
@ -2327,14 +2312,13 @@ impl Focusable for InputState {
|
|||
|
||||
impl Render for InputState {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
self.text_wrapper.update(self.text.clone(), false, cx);
|
||||
self.mode
|
||||
.update_highlighter(&(0..0), self.text.clone(), "", cx);
|
||||
self.text_wrapper.update(&self.text, false, cx);
|
||||
self.mode.update_highlighter(&(0..0), &self.text, "", cx);
|
||||
|
||||
div()
|
||||
.id("text-element")
|
||||
.id("input-state")
|
||||
.flex_1()
|
||||
.when(self.is_multi_line(), |this| this.h_full())
|
||||
.when(self.mode.is_multi_line(), |this| this.h_full())
|
||||
.flex_grow()
|
||||
.overflow_x_hidden()
|
||||
.child(TextElement::new(cx.entity().clone()).placeholder(self.placeholder.clone()))
|
||||
|
|
|
|||
|
|
@ -174,8 +174,10 @@ impl RenderOnce for TextInput {
|
|||
|
||||
let prefix = self.prefix;
|
||||
let suffix = self.suffix;
|
||||
let show_clear_button =
|
||||
self.cleanable && !state.loading && !state.text.is_empty() && state.is_single_line();
|
||||
let show_clear_button = self.cleanable
|
||||
&& !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;
|
||||
|
||||
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::undo))
|
||||
.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))
|
||||
.on_action(window.listener_for(&self.state, InputState::outdent_inline))
|
||||
.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::select_left))
|
||||
.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))
|
||||
.on_action(window.listener_for(&self.state, InputState::down))
|
||||
.on_action(window.listener_for(&self.state, InputState::select_up))
|
||||
|
|
@ -249,7 +251,7 @@ impl RenderOnce for TextInput {
|
|||
.input_h(self.size)
|
||||
.cursor_text()
|
||||
.text_size(font_size)
|
||||
.when(state.is_multi_line(), |this| {
|
||||
.when(state.mode.is_multi_line(), |this| {
|
||||
this.h_auto()
|
||||
.when_some(self.height, |this, height| this.h(height))
|
||||
})
|
||||
|
|
@ -297,7 +299,7 @@ impl RenderOnce for TextInput {
|
|||
)
|
||||
})
|
||||
.refine_style(&self.style)
|
||||
.when(state.is_multi_line(), |this| {
|
||||
.when(state.mode.is_multi_line(), |this| {
|
||||
if state.last_layout.is_some() {
|
||||
this.relative().child(
|
||||
div()
|
||||
|
|
|
|||
|
|
@ -47,20 +47,20 @@ impl TextWrapper {
|
|||
|
||||
pub(super) fn set_wrap_width(&mut self, wrap_width: Option<Pixels>, cx: &mut App) {
|
||||
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) {
|
||||
self.font = font;
|
||||
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.
|
||||
///
|
||||
/// 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) {
|
||||
if self.text == text && !force {
|
||||
pub(super) fn update(&mut self, text: &SharedString, force: bool, cx: &mut App) {
|
||||
if &self.text == text && !force {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ impl TextWrapper {
|
|||
prev_line_ix += line.len() + 1;
|
||||
}
|
||||
|
||||
self.text = text;
|
||||
self.text = text.clone();
|
||||
self.wrapped_lines = wrapped_lines;
|
||||
self.lines = lines;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ impl CodeBlock {
|
|||
let mut styles = vec![];
|
||||
if let Some(lang) = &lang {
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue