mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-18 18:08:07 +03:00
commit
c0f43d964c
@ -578,12 +578,7 @@ impl DisplaySnapshot {
|
||||
line.push_str(chunk.chunk);
|
||||
|
||||
let text_style = if let Some(style) = chunk.style {
|
||||
editor_style
|
||||
.text
|
||||
.clone()
|
||||
.highlight(style)
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or_else(|_| Cow::Borrowed(&editor_style.text))
|
||||
Cow::Owned(editor_style.text.clone().highlight(style))
|
||||
} else {
|
||||
Cow::Borrowed(&editor_style.text)
|
||||
};
|
||||
|
@ -2,7 +2,7 @@ use super::{
|
||||
wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use crate::{Anchor, Editor, ExcerptId, ExcerptRange, ToPoint as _};
|
||||
use crate::{Anchor, Editor, EditorStyle, ExcerptId, ExcerptRange, ToPoint as _};
|
||||
use collections::{Bound, HashMap, HashSet};
|
||||
use gpui::{AnyElement, Pixels, ViewContext};
|
||||
use language::{BufferSnapshot, Chunk, Patch, Point};
|
||||
@ -88,6 +88,7 @@ pub struct BlockContext<'a, 'b> {
|
||||
pub em_width: Pixels,
|
||||
pub line_height: Pixels,
|
||||
pub block_id: usize,
|
||||
pub editor_style: &'b EditorStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -39,12 +39,12 @@ use futures::FutureExt;
|
||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use git::diff_hunk_to_display;
|
||||
use gpui::{
|
||||
action, actions, div, point, prelude::*, px, relative, rems, size, uniform_list, AnyElement,
|
||||
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
|
||||
EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla,
|
||||
InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels, Render, Styled,
|
||||
Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext,
|
||||
WeakView, WindowContext,
|
||||
action, actions, div, point, prelude::*, px, relative, rems, render_view, size, uniform_list,
|
||||
AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem,
|
||||
Component, Context, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight,
|
||||
HighlightStyle, Hsla, InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels,
|
||||
Render, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext,
|
||||
VisualContext, WeakView, WindowContext,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
@ -100,7 +100,9 @@ use theme::{
|
||||
use ui::{v_stack, HighlightedLabel, IconButton, StyledExt, TextTooltip};
|
||||
use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
|
||||
use workspace::{
|
||||
item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace,
|
||||
item::{ItemEvent, ItemHandle},
|
||||
searchable::SearchEvent,
|
||||
ItemNavHistory, SplitDirection, ViewId, Workspace,
|
||||
};
|
||||
|
||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||
@ -1878,10 +1880,8 @@ impl Editor {
|
||||
);
|
||||
|
||||
let focus_handle = cx.focus_handle();
|
||||
cx.on_focus_in(&focus_handle, Self::handle_focus_in)
|
||||
.detach();
|
||||
cx.on_focus_out(&focus_handle, Self::handle_focus_out)
|
||||
.detach();
|
||||
cx.on_focus(&focus_handle, Self::handle_focus).detach();
|
||||
cx.on_blur(&focus_handle, Self::handle_blur).detach();
|
||||
|
||||
let mut this = Self {
|
||||
handle: cx.view().downgrade(),
|
||||
@ -7690,183 +7690,210 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
|
||||
// use language::ToOffset as _;
|
||||
pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
|
||||
use language::ToOffset as _;
|
||||
|
||||
// let project = self.project.clone()?;
|
||||
// let selection = self.selections.newest_anchor().clone();
|
||||
// let (cursor_buffer, cursor_buffer_position) = self
|
||||
// .buffer
|
||||
// .read(cx)
|
||||
// .text_anchor_for_position(selection.head(), cx)?;
|
||||
// let (tail_buffer, _) = self
|
||||
// .buffer
|
||||
// .read(cx)
|
||||
// .text_anchor_for_position(selection.tail(), cx)?;
|
||||
// if tail_buffer != cursor_buffer {
|
||||
// return None;
|
||||
// }
|
||||
let project = self.project.clone()?;
|
||||
let selection = self.selections.newest_anchor().clone();
|
||||
let (cursor_buffer, cursor_buffer_position) = self
|
||||
.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(selection.head(), cx)?;
|
||||
let (tail_buffer, _) = self
|
||||
.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(selection.tail(), cx)?;
|
||||
if tail_buffer != cursor_buffer {
|
||||
return None;
|
||||
}
|
||||
|
||||
// let snapshot = cursor_buffer.read(cx).snapshot();
|
||||
// let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
|
||||
// let prepare_rename = project.update(cx, |project, cx| {
|
||||
// project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
|
||||
// });
|
||||
let snapshot = cursor_buffer.read(cx).snapshot();
|
||||
let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
|
||||
let prepare_rename = project.update(cx, |project, cx| {
|
||||
project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
|
||||
});
|
||||
|
||||
// Some(cx.spawn(|this, mut cx| async move {
|
||||
// let rename_range = if let Some(range) = prepare_rename.await? {
|
||||
// Some(range)
|
||||
// } else {
|
||||
// this.update(&mut cx, |this, cx| {
|
||||
// let buffer = this.buffer.read(cx).snapshot(cx);
|
||||
// let mut buffer_highlights = this
|
||||
// .document_highlights_for_position(selection.head(), &buffer)
|
||||
// .filter(|highlight| {
|
||||
// highlight.start.excerpt_id == selection.head().excerpt_id
|
||||
// && highlight.end.excerpt_id == selection.head().excerpt_id
|
||||
// });
|
||||
// buffer_highlights
|
||||
// .next()
|
||||
// .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
|
||||
// })?
|
||||
// };
|
||||
// if let Some(rename_range) = rename_range {
|
||||
// let rename_buffer_range = rename_range.to_offset(&snapshot);
|
||||
// let cursor_offset_in_rename_range =
|
||||
// cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
|
||||
Some(cx.spawn(|this, mut cx| async move {
|
||||
let rename_range = if let Some(range) = prepare_rename.await? {
|
||||
Some(range)
|
||||
} else {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let buffer = this.buffer.read(cx).snapshot(cx);
|
||||
let mut buffer_highlights = this
|
||||
.document_highlights_for_position(selection.head(), &buffer)
|
||||
.filter(|highlight| {
|
||||
highlight.start.excerpt_id == selection.head().excerpt_id
|
||||
&& highlight.end.excerpt_id == selection.head().excerpt_id
|
||||
});
|
||||
buffer_highlights
|
||||
.next()
|
||||
.map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
|
||||
})?
|
||||
};
|
||||
if let Some(rename_range) = rename_range {
|
||||
let rename_buffer_range = rename_range.to_offset(&snapshot);
|
||||
let cursor_offset_in_rename_range =
|
||||
cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
|
||||
|
||||
// this.update(&mut cx, |this, cx| {
|
||||
// this.take_rename(false, cx);
|
||||
// let buffer = this.buffer.read(cx).read(cx);
|
||||
// let cursor_offset = selection.head().to_offset(&buffer);
|
||||
// let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
|
||||
// let rename_end = rename_start + rename_buffer_range.len();
|
||||
// let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
|
||||
// let mut old_highlight_id = None;
|
||||
// let old_name: Arc<str> = buffer
|
||||
// .chunks(rename_start..rename_end, true)
|
||||
// .map(|chunk| {
|
||||
// if old_highlight_id.is_none() {
|
||||
// old_highlight_id = chunk.syntax_highlight_id;
|
||||
// }
|
||||
// chunk.text
|
||||
// })
|
||||
// .collect::<String>()
|
||||
// .into();
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.take_rename(false, cx);
|
||||
let buffer = this.buffer.read(cx).read(cx);
|
||||
let cursor_offset = selection.head().to_offset(&buffer);
|
||||
let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
|
||||
let rename_end = rename_start + rename_buffer_range.len();
|
||||
let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
|
||||
let mut old_highlight_id = None;
|
||||
let old_name: Arc<str> = buffer
|
||||
.chunks(rename_start..rename_end, true)
|
||||
.map(|chunk| {
|
||||
if old_highlight_id.is_none() {
|
||||
old_highlight_id = chunk.syntax_highlight_id;
|
||||
}
|
||||
chunk.text
|
||||
})
|
||||
.collect::<String>()
|
||||
.into();
|
||||
|
||||
// drop(buffer);
|
||||
drop(buffer);
|
||||
|
||||
// // Position the selection in the rename editor so that it matches the current selection.
|
||||
// this.show_local_selections = false;
|
||||
// let rename_editor = cx.build_view(|cx| {
|
||||
// let mut editor = Editor::single_line(cx);
|
||||
// if let Some(old_highlight_id) = old_highlight_id {
|
||||
// editor.override_text_style =
|
||||
// Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
|
||||
// }
|
||||
// editor.buffer.update(cx, |buffer, cx| {
|
||||
// buffer.edit([(0..0, old_name.clone())], None, cx)
|
||||
// });
|
||||
// editor.select_all(&SelectAll, cx);
|
||||
// editor
|
||||
// });
|
||||
// Position the selection in the rename editor so that it matches the current selection.
|
||||
this.show_local_selections = false;
|
||||
let rename_editor = cx.build_view(|cx| {
|
||||
let mut editor = Editor::single_line(cx);
|
||||
editor.buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(0..0, old_name.clone())], None, cx)
|
||||
});
|
||||
editor.select_all(&SelectAll, cx);
|
||||
editor
|
||||
});
|
||||
|
||||
// let ranges = this
|
||||
// .clear_background_highlights::<DocumentHighlightWrite>(cx)
|
||||
// .into_iter()
|
||||
// .flat_map(|(_, ranges)| ranges.into_iter())
|
||||
// .chain(
|
||||
// this.clear_background_highlights::<DocumentHighlightRead>(cx)
|
||||
// .into_iter()
|
||||
// .flat_map(|(_, ranges)| ranges.into_iter()),
|
||||
// )
|
||||
// .collect();
|
||||
let ranges = this
|
||||
.clear_background_highlights::<DocumentHighlightWrite>(cx)
|
||||
.into_iter()
|
||||
.flat_map(|(_, ranges)| ranges.into_iter())
|
||||
.chain(
|
||||
this.clear_background_highlights::<DocumentHighlightRead>(cx)
|
||||
.into_iter()
|
||||
.flat_map(|(_, ranges)| ranges.into_iter()),
|
||||
)
|
||||
.collect();
|
||||
|
||||
// this.highlight_text::<Rename>(
|
||||
// ranges,
|
||||
// HighlightStyle {
|
||||
// fade_out: Some(style.rename_fade),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// cx.focus(&rename_editor);
|
||||
// let block_id = this.insert_blocks(
|
||||
// [BlockProperties {
|
||||
// style: BlockStyle::Flex,
|
||||
// position: range.start.clone(),
|
||||
// height: 1,
|
||||
// render: Arc::new({
|
||||
// let editor = rename_editor.clone();
|
||||
// move |cx: &mut BlockContext| {
|
||||
// ChildView::new(&editor, cx)
|
||||
// .contained()
|
||||
// .with_padding_left(cx.anchor_x)
|
||||
// .into_any()
|
||||
// }
|
||||
// }),
|
||||
// disposition: BlockDisposition::Below,
|
||||
// }],
|
||||
// Some(Autoscroll::fit()),
|
||||
// cx,
|
||||
// )[0];
|
||||
// this.pending_rename = Some(RenameState {
|
||||
// range,
|
||||
// old_name,
|
||||
// editor: rename_editor,
|
||||
// block_id,
|
||||
// });
|
||||
// })?;
|
||||
// }
|
||||
this.highlight_text::<Rename>(
|
||||
ranges,
|
||||
HighlightStyle {
|
||||
fade_out: Some(0.6),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
);
|
||||
let rename_focus_handle = rename_editor.focus_handle(cx);
|
||||
cx.focus(&rename_focus_handle);
|
||||
let block_id = this.insert_blocks(
|
||||
[BlockProperties {
|
||||
style: BlockStyle::Flex,
|
||||
position: range.start.clone(),
|
||||
height: 1,
|
||||
render: Arc::new({
|
||||
let rename_editor = rename_editor.clone();
|
||||
move |cx: &mut BlockContext| {
|
||||
let mut text_style = cx.editor_style.text.clone();
|
||||
if let Some(highlight_style) = old_highlight_id
|
||||
.and_then(|h| h.style(&cx.editor_style.syntax))
|
||||
{
|
||||
text_style = text_style.highlight(highlight_style);
|
||||
}
|
||||
div()
|
||||
.pl(cx.anchor_x)
|
||||
.child(render_view(
|
||||
&rename_editor,
|
||||
EditorElement::new(
|
||||
&rename_editor,
|
||||
EditorStyle {
|
||||
background: cx.theme().system().transparent,
|
||||
local_player: cx.editor_style.local_player,
|
||||
text: text_style,
|
||||
scrollbar_width: cx
|
||||
.editor_style
|
||||
.scrollbar_width,
|
||||
syntax: cx.editor_style.syntax.clone(),
|
||||
diagnostic_style: cx
|
||||
.editor_style
|
||||
.diagnostic_style
|
||||
.clone(),
|
||||
},
|
||||
),
|
||||
))
|
||||
.render()
|
||||
}
|
||||
}),
|
||||
disposition: BlockDisposition::Below,
|
||||
}],
|
||||
Some(Autoscroll::fit()),
|
||||
cx,
|
||||
)[0];
|
||||
this.pending_rename = Some(RenameState {
|
||||
range,
|
||||
old_name,
|
||||
editor: rename_editor,
|
||||
block_id,
|
||||
});
|
||||
})?;
|
||||
}
|
||||
|
||||
// Ok(())
|
||||
// }))
|
||||
// }
|
||||
Ok(())
|
||||
}))
|
||||
}
|
||||
|
||||
// pub fn confirm_rename(
|
||||
// workspace: &mut Workspace,
|
||||
// _: &ConfirmRename,
|
||||
// cx: &mut ViewContext<Workspace>,
|
||||
// ) -> Option<Task<Result<()>>> {
|
||||
// let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
|
||||
pub fn confirm_rename(
|
||||
&mut self,
|
||||
_: &ConfirmRename,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<Task<Result<()>>> {
|
||||
let rename = self.take_rename(false, cx)?;
|
||||
let workspace = self.workspace()?;
|
||||
let (start_buffer, start) = self
|
||||
.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(rename.range.start.clone(), cx)?;
|
||||
let (end_buffer, end) = self
|
||||
.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(rename.range.end.clone(), cx)?;
|
||||
if start_buffer != end_buffer {
|
||||
return None;
|
||||
}
|
||||
|
||||
// let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
|
||||
// let rename = editor.take_rename(false, cx)?;
|
||||
// let buffer = editor.buffer.read(cx);
|
||||
// let (start_buffer, start) =
|
||||
// buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
|
||||
// let (end_buffer, end) =
|
||||
// buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
|
||||
// if start_buffer == end_buffer {
|
||||
// let new_name = rename.editor.read(cx).text(cx);
|
||||
// Some((start_buffer, start..end, rename.old_name, new_name))
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// })?;
|
||||
let buffer = start_buffer;
|
||||
let range = start..end;
|
||||
let old_name = rename.old_name;
|
||||
let new_name = rename.editor.read(cx).text(cx);
|
||||
|
||||
// let rename = workspace.project().clone().update(cx, |project, cx| {
|
||||
// project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
|
||||
// });
|
||||
let rename = workspace
|
||||
.read(cx)
|
||||
.project()
|
||||
.clone()
|
||||
.update(cx, |project, cx| {
|
||||
project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
|
||||
});
|
||||
let workspace = workspace.downgrade();
|
||||
|
||||
// let editor = editor.downgrade();
|
||||
// Some(cx.spawn(|workspace, mut cx| async move {
|
||||
// let project_transaction = rename.await?;
|
||||
// Self::open_project_transaction(
|
||||
// &editor,
|
||||
// workspace,
|
||||
// project_transaction,
|
||||
// format!("Rename: {} → {}", old_name, new_name),
|
||||
// cx.clone(),
|
||||
// )
|
||||
// .await?;
|
||||
Some(cx.spawn(|editor, mut cx| async move {
|
||||
let project_transaction = rename.await?;
|
||||
Self::open_project_transaction(
|
||||
&editor,
|
||||
workspace,
|
||||
project_transaction,
|
||||
format!("Rename: {} → {}", old_name, new_name),
|
||||
cx.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// editor.update(&mut cx, |editor, cx| {
|
||||
// editor.refresh_document_highlights(cx);
|
||||
// })?;
|
||||
// Ok(())
|
||||
// }))
|
||||
// }
|
||||
editor.update(&mut cx, |editor, cx| {
|
||||
editor.refresh_document_highlights(cx);
|
||||
})?;
|
||||
Ok(())
|
||||
}))
|
||||
}
|
||||
|
||||
fn take_rename(
|
||||
&mut self,
|
||||
@ -7874,6 +7901,10 @@ impl Editor {
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<RenameState> {
|
||||
let rename = self.pending_rename.take()?;
|
||||
if rename.editor.focus_handle(cx).is_focused(cx) {
|
||||
cx.focus(&self.focus_handle);
|
||||
}
|
||||
|
||||
self.remove_blocks(
|
||||
[rename.block_id].into_iter().collect(),
|
||||
Some(Autoscroll::fit()),
|
||||
@ -9172,17 +9203,13 @@ impl Editor {
|
||||
self.focus_handle.is_focused(cx)
|
||||
}
|
||||
|
||||
fn handle_focus_in(&mut self, cx: &mut ViewContext<Self>) {
|
||||
if self.focus_handle.is_focused(cx) {
|
||||
// todo!()
|
||||
// let focused_event = EditorFocused(cx.handle());
|
||||
// cx.emit_global(focused_event);
|
||||
cx.emit(Event::Focused);
|
||||
}
|
||||
fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
|
||||
cx.emit(Event::Focused);
|
||||
|
||||
if let Some(rename) = self.pending_rename.as_ref() {
|
||||
let rename_editor_focus_handle = rename.editor.read(cx).focus_handle.clone();
|
||||
cx.focus(&rename_editor_focus_handle);
|
||||
} else if self.focus_handle.is_focused(cx) {
|
||||
} else {
|
||||
self.blink_manager.update(cx, BlinkManager::enable);
|
||||
self.buffer.update(cx, |buffer, cx| {
|
||||
buffer.finalize_last_transaction(cx);
|
||||
@ -9198,7 +9225,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_focus_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||
fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
|
||||
// todo!()
|
||||
// let blurred_event = EditorBlurred(cx.handle());
|
||||
// cx.emit_global(blurred_event);
|
||||
|
@ -2012,10 +2012,10 @@ impl EditorElement {
|
||||
anchor_x,
|
||||
gutter_padding,
|
||||
line_height,
|
||||
// scroll_x,
|
||||
gutter_width,
|
||||
em_width,
|
||||
block_id,
|
||||
editor_style: &self.style,
|
||||
})
|
||||
}
|
||||
TransformBlock::ExcerptHeader {
|
||||
@ -2258,11 +2258,7 @@ impl LineWithInvisibles {
|
||||
|
||||
if !line_chunk.is_empty() && !line_exceeded_max_len {
|
||||
let text_style = if let Some(style) = highlighted_chunk.style {
|
||||
text_style
|
||||
.clone()
|
||||
.highlight(style)
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or_else(|_| Cow::Borrowed(text_style))
|
||||
Cow::Owned(text_style.clone().highlight(style))
|
||||
} else {
|
||||
Cow::Borrowed(text_style)
|
||||
};
|
||||
@ -2460,168 +2456,7 @@ impl Element<Editor> for EditorElement {
|
||||
dispatch_context,
|
||||
Some(editor.focus_handle.clone()),
|
||||
|_, cx| {
|
||||
register_action(cx, Editor::move_left);
|
||||
register_action(cx, Editor::move_right);
|
||||
register_action(cx, Editor::move_down);
|
||||
register_action(cx, Editor::move_up);
|
||||
// on_action(cx, Editor::new_file); todo!()
|
||||
// on_action(cx, Editor::new_file_in_direction); todo!()
|
||||
register_action(cx, Editor::cancel);
|
||||
register_action(cx, Editor::newline);
|
||||
register_action(cx, Editor::newline_above);
|
||||
register_action(cx, Editor::newline_below);
|
||||
register_action(cx, Editor::backspace);
|
||||
register_action(cx, Editor::delete);
|
||||
register_action(cx, Editor::tab);
|
||||
register_action(cx, Editor::tab_prev);
|
||||
register_action(cx, Editor::indent);
|
||||
register_action(cx, Editor::outdent);
|
||||
register_action(cx, Editor::delete_line);
|
||||
register_action(cx, Editor::join_lines);
|
||||
register_action(cx, Editor::sort_lines_case_sensitive);
|
||||
register_action(cx, Editor::sort_lines_case_insensitive);
|
||||
register_action(cx, Editor::reverse_lines);
|
||||
register_action(cx, Editor::shuffle_lines);
|
||||
register_action(cx, Editor::convert_to_upper_case);
|
||||
register_action(cx, Editor::convert_to_lower_case);
|
||||
register_action(cx, Editor::convert_to_title_case);
|
||||
register_action(cx, Editor::convert_to_snake_case);
|
||||
register_action(cx, Editor::convert_to_kebab_case);
|
||||
register_action(cx, Editor::convert_to_upper_camel_case);
|
||||
register_action(cx, Editor::convert_to_lower_camel_case);
|
||||
register_action(cx, Editor::delete_to_previous_word_start);
|
||||
register_action(cx, Editor::delete_to_previous_subword_start);
|
||||
register_action(cx, Editor::delete_to_next_word_end);
|
||||
register_action(cx, Editor::delete_to_next_subword_end);
|
||||
register_action(cx, Editor::delete_to_beginning_of_line);
|
||||
register_action(cx, Editor::delete_to_end_of_line);
|
||||
register_action(cx, Editor::cut_to_end_of_line);
|
||||
register_action(cx, Editor::duplicate_line);
|
||||
register_action(cx, Editor::move_line_up);
|
||||
register_action(cx, Editor::move_line_down);
|
||||
register_action(cx, Editor::transpose);
|
||||
register_action(cx, Editor::cut);
|
||||
register_action(cx, Editor::copy);
|
||||
register_action(cx, Editor::paste);
|
||||
register_action(cx, Editor::undo);
|
||||
register_action(cx, Editor::redo);
|
||||
register_action(cx, Editor::move_page_up);
|
||||
register_action(cx, Editor::move_page_down);
|
||||
register_action(cx, Editor::next_screen);
|
||||
register_action(cx, Editor::scroll_cursor_top);
|
||||
register_action(cx, Editor::scroll_cursor_center);
|
||||
register_action(cx, Editor::scroll_cursor_bottom);
|
||||
register_action(cx, |editor, _: &LineDown, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Line(1.), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &LineUp, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &HalfPageDown, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &HalfPageUp, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &PageDown, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(1.), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &PageUp, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
|
||||
});
|
||||
register_action(cx, Editor::move_to_previous_word_start);
|
||||
register_action(cx, Editor::move_to_previous_subword_start);
|
||||
register_action(cx, Editor::move_to_next_word_end);
|
||||
register_action(cx, Editor::move_to_next_subword_end);
|
||||
register_action(cx, Editor::move_to_beginning_of_line);
|
||||
register_action(cx, Editor::move_to_end_of_line);
|
||||
register_action(cx, Editor::move_to_start_of_paragraph);
|
||||
register_action(cx, Editor::move_to_end_of_paragraph);
|
||||
register_action(cx, Editor::move_to_beginning);
|
||||
register_action(cx, Editor::move_to_end);
|
||||
register_action(cx, Editor::select_up);
|
||||
register_action(cx, Editor::select_down);
|
||||
register_action(cx, Editor::select_left);
|
||||
register_action(cx, Editor::select_right);
|
||||
register_action(cx, Editor::select_to_previous_word_start);
|
||||
register_action(cx, Editor::select_to_previous_subword_start);
|
||||
register_action(cx, Editor::select_to_next_word_end);
|
||||
register_action(cx, Editor::select_to_next_subword_end);
|
||||
register_action(cx, Editor::select_to_beginning_of_line);
|
||||
register_action(cx, Editor::select_to_end_of_line);
|
||||
register_action(cx, Editor::select_to_start_of_paragraph);
|
||||
register_action(cx, Editor::select_to_end_of_paragraph);
|
||||
register_action(cx, Editor::select_to_beginning);
|
||||
register_action(cx, Editor::select_to_end);
|
||||
register_action(cx, Editor::select_all);
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor.select_all_matches(action, cx).log_err();
|
||||
});
|
||||
register_action(cx, Editor::select_line);
|
||||
register_action(cx, Editor::split_selection_into_lines);
|
||||
register_action(cx, Editor::add_selection_above);
|
||||
register_action(cx, Editor::add_selection_below);
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor.select_next(action, cx).log_err();
|
||||
});
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor.select_previous(action, cx).log_err();
|
||||
});
|
||||
register_action(cx, Editor::toggle_comments);
|
||||
register_action(cx, Editor::select_larger_syntax_node);
|
||||
register_action(cx, Editor::select_smaller_syntax_node);
|
||||
register_action(cx, Editor::move_to_enclosing_bracket);
|
||||
register_action(cx, Editor::undo_selection);
|
||||
register_action(cx, Editor::redo_selection);
|
||||
register_action(cx, Editor::go_to_diagnostic);
|
||||
register_action(cx, Editor::go_to_prev_diagnostic);
|
||||
register_action(cx, Editor::go_to_hunk);
|
||||
register_action(cx, Editor::go_to_prev_hunk);
|
||||
register_action(cx, Editor::go_to_definition);
|
||||
register_action(cx, Editor::go_to_definition_split);
|
||||
register_action(cx, Editor::go_to_type_definition);
|
||||
register_action(cx, Editor::go_to_type_definition_split);
|
||||
register_action(cx, Editor::fold);
|
||||
register_action(cx, Editor::fold_at);
|
||||
register_action(cx, Editor::unfold_lines);
|
||||
register_action(cx, Editor::unfold_at);
|
||||
register_action(cx, Editor::fold_selected_ranges);
|
||||
register_action(cx, Editor::show_completions);
|
||||
register_action(cx, Editor::toggle_code_actions);
|
||||
// on_action(cx, Editor::open_excerpts); todo!()
|
||||
register_action(cx, Editor::toggle_soft_wrap);
|
||||
register_action(cx, Editor::toggle_inlay_hints);
|
||||
register_action(cx, Editor::reveal_in_finder);
|
||||
register_action(cx, Editor::copy_path);
|
||||
register_action(cx, Editor::copy_relative_path);
|
||||
register_action(cx, Editor::copy_highlight_json);
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.format(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, Editor::restart_language_server);
|
||||
register_action(cx, Editor::show_character_palette);
|
||||
// on_action(cx, Editor::confirm_completion); todo!()
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.confirm_code_action(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
// on_action(cx, Editor::rename); todo!()
|
||||
// on_action(cx, Editor::confirm_rename); todo!()
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.find_all_references(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, Editor::next_copilot_suggestion);
|
||||
register_action(cx, Editor::previous_copilot_suggestion);
|
||||
register_action(cx, Editor::copilot_suggest);
|
||||
register_action(cx, Editor::context_menu_first);
|
||||
register_action(cx, Editor::context_menu_prev);
|
||||
register_action(cx, Editor::context_menu_next);
|
||||
register_action(cx, Editor::context_menu_last);
|
||||
register_actions(cx);
|
||||
|
||||
// We call with_z_index to establish a new stacking context.
|
||||
cx.with_z_index(0, |cx| {
|
||||
@ -2652,6 +2487,12 @@ impl Element<Editor> for EditorElement {
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Editor> for EditorElement {
|
||||
fn render(self) -> AnyElement<Editor> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
// impl EditorElement {
|
||||
// type LayoutState = LayoutState;
|
||||
// type PaintState = ();
|
||||
@ -4128,6 +3969,179 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 {
|
||||
// }
|
||||
// }
|
||||
|
||||
fn register_actions(cx: &mut ViewContext<Editor>) {
|
||||
register_action(cx, Editor::move_left);
|
||||
register_action(cx, Editor::move_right);
|
||||
register_action(cx, Editor::move_down);
|
||||
register_action(cx, Editor::move_up);
|
||||
// on_action(cx, Editor::new_file); todo!()
|
||||
// on_action(cx, Editor::new_file_in_direction); todo!()
|
||||
register_action(cx, Editor::cancel);
|
||||
register_action(cx, Editor::newline);
|
||||
register_action(cx, Editor::newline_above);
|
||||
register_action(cx, Editor::newline_below);
|
||||
register_action(cx, Editor::backspace);
|
||||
register_action(cx, Editor::delete);
|
||||
register_action(cx, Editor::tab);
|
||||
register_action(cx, Editor::tab_prev);
|
||||
register_action(cx, Editor::indent);
|
||||
register_action(cx, Editor::outdent);
|
||||
register_action(cx, Editor::delete_line);
|
||||
register_action(cx, Editor::join_lines);
|
||||
register_action(cx, Editor::sort_lines_case_sensitive);
|
||||
register_action(cx, Editor::sort_lines_case_insensitive);
|
||||
register_action(cx, Editor::reverse_lines);
|
||||
register_action(cx, Editor::shuffle_lines);
|
||||
register_action(cx, Editor::convert_to_upper_case);
|
||||
register_action(cx, Editor::convert_to_lower_case);
|
||||
register_action(cx, Editor::convert_to_title_case);
|
||||
register_action(cx, Editor::convert_to_snake_case);
|
||||
register_action(cx, Editor::convert_to_kebab_case);
|
||||
register_action(cx, Editor::convert_to_upper_camel_case);
|
||||
register_action(cx, Editor::convert_to_lower_camel_case);
|
||||
register_action(cx, Editor::delete_to_previous_word_start);
|
||||
register_action(cx, Editor::delete_to_previous_subword_start);
|
||||
register_action(cx, Editor::delete_to_next_word_end);
|
||||
register_action(cx, Editor::delete_to_next_subword_end);
|
||||
register_action(cx, Editor::delete_to_beginning_of_line);
|
||||
register_action(cx, Editor::delete_to_end_of_line);
|
||||
register_action(cx, Editor::cut_to_end_of_line);
|
||||
register_action(cx, Editor::duplicate_line);
|
||||
register_action(cx, Editor::move_line_up);
|
||||
register_action(cx, Editor::move_line_down);
|
||||
register_action(cx, Editor::transpose);
|
||||
register_action(cx, Editor::cut);
|
||||
register_action(cx, Editor::copy);
|
||||
register_action(cx, Editor::paste);
|
||||
register_action(cx, Editor::undo);
|
||||
register_action(cx, Editor::redo);
|
||||
register_action(cx, Editor::move_page_up);
|
||||
register_action(cx, Editor::move_page_down);
|
||||
register_action(cx, Editor::next_screen);
|
||||
register_action(cx, Editor::scroll_cursor_top);
|
||||
register_action(cx, Editor::scroll_cursor_center);
|
||||
register_action(cx, Editor::scroll_cursor_bottom);
|
||||
register_action(cx, |editor, _: &LineDown, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Line(1.), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &LineUp, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &HalfPageDown, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &HalfPageUp, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &PageDown, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(1.), cx)
|
||||
});
|
||||
register_action(cx, |editor, _: &PageUp, cx| {
|
||||
editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
|
||||
});
|
||||
register_action(cx, Editor::move_to_previous_word_start);
|
||||
register_action(cx, Editor::move_to_previous_subword_start);
|
||||
register_action(cx, Editor::move_to_next_word_end);
|
||||
register_action(cx, Editor::move_to_next_subword_end);
|
||||
register_action(cx, Editor::move_to_beginning_of_line);
|
||||
register_action(cx, Editor::move_to_end_of_line);
|
||||
register_action(cx, Editor::move_to_start_of_paragraph);
|
||||
register_action(cx, Editor::move_to_end_of_paragraph);
|
||||
register_action(cx, Editor::move_to_beginning);
|
||||
register_action(cx, Editor::move_to_end);
|
||||
register_action(cx, Editor::select_up);
|
||||
register_action(cx, Editor::select_down);
|
||||
register_action(cx, Editor::select_left);
|
||||
register_action(cx, Editor::select_right);
|
||||
register_action(cx, Editor::select_to_previous_word_start);
|
||||
register_action(cx, Editor::select_to_previous_subword_start);
|
||||
register_action(cx, Editor::select_to_next_word_end);
|
||||
register_action(cx, Editor::select_to_next_subword_end);
|
||||
register_action(cx, Editor::select_to_beginning_of_line);
|
||||
register_action(cx, Editor::select_to_end_of_line);
|
||||
register_action(cx, Editor::select_to_start_of_paragraph);
|
||||
register_action(cx, Editor::select_to_end_of_paragraph);
|
||||
register_action(cx, Editor::select_to_beginning);
|
||||
register_action(cx, Editor::select_to_end);
|
||||
register_action(cx, Editor::select_all);
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor.select_all_matches(action, cx).log_err();
|
||||
});
|
||||
register_action(cx, Editor::select_line);
|
||||
register_action(cx, Editor::split_selection_into_lines);
|
||||
register_action(cx, Editor::add_selection_above);
|
||||
register_action(cx, Editor::add_selection_below);
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor.select_next(action, cx).log_err();
|
||||
});
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor.select_previous(action, cx).log_err();
|
||||
});
|
||||
register_action(cx, Editor::toggle_comments);
|
||||
register_action(cx, Editor::select_larger_syntax_node);
|
||||
register_action(cx, Editor::select_smaller_syntax_node);
|
||||
register_action(cx, Editor::move_to_enclosing_bracket);
|
||||
register_action(cx, Editor::undo_selection);
|
||||
register_action(cx, Editor::redo_selection);
|
||||
register_action(cx, Editor::go_to_diagnostic);
|
||||
register_action(cx, Editor::go_to_prev_diagnostic);
|
||||
register_action(cx, Editor::go_to_hunk);
|
||||
register_action(cx, Editor::go_to_prev_hunk);
|
||||
register_action(cx, Editor::go_to_definition);
|
||||
register_action(cx, Editor::go_to_definition_split);
|
||||
register_action(cx, Editor::go_to_type_definition);
|
||||
register_action(cx, Editor::go_to_type_definition_split);
|
||||
register_action(cx, Editor::fold);
|
||||
register_action(cx, Editor::fold_at);
|
||||
register_action(cx, Editor::unfold_lines);
|
||||
register_action(cx, Editor::unfold_at);
|
||||
register_action(cx, Editor::fold_selected_ranges);
|
||||
register_action(cx, Editor::show_completions);
|
||||
register_action(cx, Editor::toggle_code_actions);
|
||||
// on_action(cx, Editor::open_excerpts); todo!()
|
||||
register_action(cx, Editor::toggle_soft_wrap);
|
||||
register_action(cx, Editor::toggle_inlay_hints);
|
||||
register_action(cx, Editor::reveal_in_finder);
|
||||
register_action(cx, Editor::copy_path);
|
||||
register_action(cx, Editor::copy_relative_path);
|
||||
register_action(cx, Editor::copy_highlight_json);
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.format(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, Editor::restart_language_server);
|
||||
register_action(cx, Editor::show_character_palette);
|
||||
// on_action(cx, Editor::confirm_completion); todo!()
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.confirm_code_action(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.rename(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.confirm_rename(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, |editor, action, cx| {
|
||||
editor
|
||||
.find_all_references(action, cx)
|
||||
.map(|task| task.detach_and_log_err(cx));
|
||||
});
|
||||
register_action(cx, Editor::next_copilot_suggestion);
|
||||
register_action(cx, Editor::previous_copilot_suggestion);
|
||||
register_action(cx, Editor::copilot_suggest);
|
||||
register_action(cx, Editor::context_menu_first);
|
||||
register_action(cx, Editor::context_menu_prev);
|
||||
register_action(cx, Editor::context_menu_next);
|
||||
register_action(cx, Editor::context_menu_last);
|
||||
}
|
||||
|
||||
fn register_action<T: Action>(
|
||||
cx: &mut ViewContext<Editor>,
|
||||
listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static,
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
|
||||
Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
|
||||
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Result,
|
||||
Rgba, SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext,
|
||||
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
|
||||
SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext,
|
||||
};
|
||||
use refineable::{Cascade, Refineable};
|
||||
use smallvec::SmallVec;
|
||||
@ -157,7 +157,7 @@ impl Default for TextStyle {
|
||||
}
|
||||
|
||||
impl TextStyle {
|
||||
pub fn highlight(mut self, style: HighlightStyle) -> Result<Self> {
|
||||
pub fn highlight(mut self, style: HighlightStyle) -> Self {
|
||||
if let Some(weight) = style.font_weight {
|
||||
self.font_weight = weight;
|
||||
}
|
||||
@ -177,7 +177,7 @@ impl TextStyle {
|
||||
self.underline = Some(underline);
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
self
|
||||
}
|
||||
|
||||
pub fn font(&self) -> Font {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
|
||||
Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels,
|
||||
Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||
BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId,
|
||||
Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use std::{
|
||||
@ -281,6 +281,84 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RenderView<C, V> {
|
||||
view: View<V>,
|
||||
component: Option<C>,
|
||||
}
|
||||
|
||||
impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderView<C, ViewState>
|
||||
where
|
||||
C: 'static + Component<ViewState>,
|
||||
ParentViewState: 'static,
|
||||
ViewState: 'static,
|
||||
{
|
||||
fn render(self) -> AnyElement<ParentViewState> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderView<C, ViewState>
|
||||
where
|
||||
C: 'static + Component<ViewState>,
|
||||
ParentViewState: 'static,
|
||||
ViewState: 'static,
|
||||
{
|
||||
type ElementState = AnyElement<ViewState>;
|
||||
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
Some(self.view.entity_id().into())
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_: &mut ParentViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<ParentViewState>,
|
||||
) -> Self::ElementState {
|
||||
cx.with_element_id(Some(self.view.entity_id()), |cx| {
|
||||
self.view.update(cx, |view, cx| {
|
||||
let mut element = self.component.take().unwrap().render();
|
||||
element.initialize(view, cx);
|
||||
element
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_: &mut ParentViewState,
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<ParentViewState>,
|
||||
) -> LayoutId {
|
||||
cx.with_element_id(Some(self.view.entity_id()), |cx| {
|
||||
self.view.update(cx, |view, cx| element.layout(view, cx))
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_: Bounds<Pixels>,
|
||||
_: &mut ParentViewState,
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<ParentViewState>,
|
||||
) {
|
||||
cx.with_element_id(Some(self.view.entity_id()), |cx| {
|
||||
self.view.update(cx, |view, cx| element.paint(view, cx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_view<C, V>(view: &View<V>, component: C) -> RenderView<C, V>
|
||||
where
|
||||
C: 'static + Component<V>,
|
||||
V: 'static,
|
||||
{
|
||||
RenderView {
|
||||
view: view.clone(),
|
||||
component: Some(component),
|
||||
}
|
||||
}
|
||||
|
||||
mod any_view {
|
||||
use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
|
||||
use std::any::Any;
|
||||
|
Loading…
Reference in New Issue
Block a user