mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Clean up inline assist editor rendering (#15536)
Release Notes: - N/A --------- Co-authored-by: Nathan <nathan@zed.dev> Co-authored-by: Max <max@zed.dev>
This commit is contained in:
parent
73d8370177
commit
5b1ea7eda0
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -3391,13 +3391,11 @@ dependencies = [
|
|||||||
"ctor",
|
"ctor",
|
||||||
"editor",
|
"editor",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"feature_flags",
|
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
"language",
|
"language",
|
||||||
"log",
|
"log",
|
||||||
"lsp",
|
"lsp",
|
||||||
"multi_buffer",
|
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"project",
|
"project",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
@ -1917,18 +1917,20 @@ impl ContextEditor {
|
|||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
for suggestion in suggestion_group.suggestions {
|
for suggestion in suggestion_group.suggestions {
|
||||||
let description = suggestion.description.unwrap_or_else(|| "Delete".into());
|
let description = suggestion.description.unwrap_or_else(|| "Delete".into());
|
||||||
|
|
||||||
let range = {
|
let range = {
|
||||||
let buffer = editor.read(cx).buffer().read(cx).read(cx);
|
let multibuffer = editor.read(cx).buffer().read(cx).read(cx);
|
||||||
let (&excerpt_id, _, _) = buffer.as_singleton().unwrap();
|
let (&excerpt_id, _, _) = multibuffer.as_singleton().unwrap();
|
||||||
buffer
|
multibuffer
|
||||||
.anchor_in_excerpt(excerpt_id, suggestion.range.start)
|
.anchor_in_excerpt(excerpt_id, suggestion.range.start)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
..buffer
|
..multibuffer
|
||||||
.anchor_in_excerpt(excerpt_id, suggestion.range.end)
|
.anchor_in_excerpt(excerpt_id, suggestion.range.end)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
InlineAssistant::update_global(cx, |assistant, cx| {
|
InlineAssistant::update_global(cx, |assistant, cx| {
|
||||||
assist_ids.push(assistant.suggest_assist(
|
let suggestion_id = assistant.suggest_assist(
|
||||||
&editor,
|
&editor,
|
||||||
range,
|
range,
|
||||||
description,
|
description,
|
||||||
@ -1936,16 +1938,20 @@ impl ContextEditor {
|
|||||||
Some(workspace.clone()),
|
Some(workspace.clone()),
|
||||||
assistant_panel.upgrade().as_ref(),
|
assistant_panel.upgrade().as_ref(),
|
||||||
cx,
|
cx,
|
||||||
));
|
);
|
||||||
|
assist_ids.push(suggestion_id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll the editor to the suggested assist
|
// Scroll the editor to the suggested assist
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
let anchor = {
|
let multibuffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
let buffer = editor.buffer().read(cx).read(cx);
|
let (&excerpt_id, _, buffer) = multibuffer.as_singleton().unwrap();
|
||||||
let (&excerpt_id, _, _) = buffer.as_singleton().unwrap();
|
let anchor = if suggestion_group.context_range.start.to_offset(buffer) == 0
|
||||||
buffer
|
{
|
||||||
|
Anchor::min()
|
||||||
|
} else {
|
||||||
|
multibuffer
|
||||||
.anchor_in_excerpt(excerpt_id, suggestion_group.context_range.start)
|
.anchor_in_excerpt(excerpt_id, suggestion_group.context_range.start)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
@ -331,11 +331,16 @@ impl InlineAssistant {
|
|||||||
prompt_editor: &View<PromptEditor>,
|
prompt_editor: &View<PromptEditor>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> [CustomBlockId; 2] {
|
) -> [CustomBlockId; 2] {
|
||||||
|
let prompt_editor_height = prompt_editor.update(cx, |prompt_editor, cx| {
|
||||||
|
prompt_editor
|
||||||
|
.editor
|
||||||
|
.update(cx, |editor, cx| editor.max_point(cx).row().0 + 1 + 2)
|
||||||
|
});
|
||||||
let assist_blocks = vec![
|
let assist_blocks = vec![
|
||||||
BlockProperties {
|
BlockProperties {
|
||||||
style: BlockStyle::Sticky,
|
style: BlockStyle::Sticky,
|
||||||
position: range.start,
|
position: range.start,
|
||||||
height: prompt_editor.read(cx).height_in_lines,
|
height: prompt_editor_height,
|
||||||
render: build_assist_editor_renderer(prompt_editor),
|
render: build_assist_editor_renderer(prompt_editor),
|
||||||
disposition: BlockDisposition::Above,
|
disposition: BlockDisposition::Above,
|
||||||
},
|
},
|
||||||
@ -446,9 +451,6 @@ impl InlineAssistant {
|
|||||||
PromptEditorEvent::DismissRequested => {
|
PromptEditorEvent::DismissRequested => {
|
||||||
self.dismiss_assist(assist_id, cx);
|
self.dismiss_assist(assist_id, cx);
|
||||||
}
|
}
|
||||||
PromptEditorEvent::Resized { height_in_lines } => {
|
|
||||||
self.resize_assist(assist_id, *height_in_lines, cx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,33 +788,6 @@ impl InlineAssistant {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_assist(
|
|
||||||
&mut self,
|
|
||||||
assist_id: InlineAssistId,
|
|
||||||
height_in_lines: u8,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
) {
|
|
||||||
if let Some(assist) = self.assists.get_mut(&assist_id) {
|
|
||||||
if let Some(editor) = assist.editor.upgrade() {
|
|
||||||
if let Some(decorations) = assist.decorations.as_ref() {
|
|
||||||
let mut new_blocks = HashMap::default();
|
|
||||||
new_blocks.insert(
|
|
||||||
decorations.prompt_block_id,
|
|
||||||
(
|
|
||||||
Some(height_in_lines),
|
|
||||||
build_assist_editor_renderer(&decorations.prompt_editor),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
editor.update(cx, |editor, cx| {
|
|
||||||
editor
|
|
||||||
.display_map
|
|
||||||
.update(cx, |map, cx| map.replace_blocks(new_blocks, cx))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlink_assist_group(
|
fn unlink_assist_group(
|
||||||
&mut self,
|
&mut self,
|
||||||
assist_group_id: InlineAssistGroupId,
|
assist_group_id: InlineAssistGroupId,
|
||||||
@ -1029,8 +1004,8 @@ impl InlineAssistant {
|
|||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
|
|
||||||
let height = deleted_lines_editor
|
let height =
|
||||||
.update(cx, |editor, cx| editor.max_point(cx).row().0 as u8 + 1);
|
deleted_lines_editor.update(cx, |editor, cx| editor.max_point(cx).row().0 + 1);
|
||||||
new_blocks.push(BlockProperties {
|
new_blocks.push(BlockProperties {
|
||||||
position: new_row,
|
position: new_row,
|
||||||
height,
|
height,
|
||||||
@ -1194,13 +1169,11 @@ enum PromptEditorEvent {
|
|||||||
ConfirmRequested,
|
ConfirmRequested,
|
||||||
CancelRequested,
|
CancelRequested,
|
||||||
DismissRequested,
|
DismissRequested,
|
||||||
Resized { height_in_lines: u8 },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PromptEditor {
|
struct PromptEditor {
|
||||||
id: InlineAssistId,
|
id: InlineAssistId,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
height_in_lines: u8,
|
|
||||||
editor: View<Editor>,
|
editor: View<Editor>,
|
||||||
edited_since_done: bool,
|
edited_since_done: bool,
|
||||||
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
|
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
|
||||||
@ -1307,9 +1280,8 @@ impl Render for PromptEditor {
|
|||||||
.bg(cx.theme().colors().editor_background)
|
.bg(cx.theme().colors().editor_background)
|
||||||
.border_y_1()
|
.border_y_1()
|
||||||
.border_color(cx.theme().status().info_border)
|
.border_color(cx.theme().status().info_border)
|
||||||
.py_1p5()
|
.size_full()
|
||||||
.h_full()
|
.py(cx.line_height() / 2.)
|
||||||
.w_full()
|
|
||||||
.on_action(cx.listener(Self::confirm))
|
.on_action(cx.listener(Self::confirm))
|
||||||
.on_action(cx.listener(Self::cancel))
|
.on_action(cx.listener(Self::cancel))
|
||||||
.on_action(cx.listener(Self::move_up))
|
.on_action(cx.listener(Self::move_up))
|
||||||
@ -1427,7 +1399,6 @@ impl PromptEditor {
|
|||||||
|
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
id,
|
id,
|
||||||
height_in_lines: 1,
|
|
||||||
editor: prompt_editor,
|
editor: prompt_editor,
|
||||||
edited_since_done: false,
|
edited_since_done: false,
|
||||||
gutter_dimensions,
|
gutter_dimensions,
|
||||||
@ -1443,7 +1414,6 @@ impl PromptEditor {
|
|||||||
_token_count_subscriptions: token_count_subscriptions,
|
_token_count_subscriptions: token_count_subscriptions,
|
||||||
workspace,
|
workspace,
|
||||||
};
|
};
|
||||||
this.count_lines(cx);
|
|
||||||
this.count_tokens(cx);
|
this.count_tokens(cx);
|
||||||
this.subscribe_to_editor(cx);
|
this.subscribe_to_editor(cx);
|
||||||
this
|
this
|
||||||
@ -1451,8 +1421,6 @@ impl PromptEditor {
|
|||||||
|
|
||||||
fn subscribe_to_editor(&mut self, cx: &mut ViewContext<Self>) {
|
fn subscribe_to_editor(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.editor_subscriptions.clear();
|
self.editor_subscriptions.clear();
|
||||||
self.editor_subscriptions
|
|
||||||
.push(cx.observe(&self.editor, Self::handle_prompt_editor_changed));
|
|
||||||
self.editor_subscriptions
|
self.editor_subscriptions
|
||||||
.push(cx.subscribe(&self.editor, Self::handle_prompt_editor_events));
|
.push(cx.subscribe(&self.editor, Self::handle_prompt_editor_events));
|
||||||
}
|
}
|
||||||
@ -1487,22 +1455,6 @@ impl PromptEditor {
|
|||||||
self.editor.read(cx).text(cx)
|
self.editor.read(cx).text(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_lines(&mut self, cx: &mut ViewContext<Self>) {
|
|
||||||
let height_in_lines = cmp::max(
|
|
||||||
2, // Make the editor at least two lines tall, to account for padding and buttons.
|
|
||||||
cmp::min(
|
|
||||||
self.editor
|
|
||||||
.update(cx, |editor, cx| editor.max_point(cx).row().0 + 1),
|
|
||||||
Self::MAX_LINES as u32,
|
|
||||||
),
|
|
||||||
) as u8;
|
|
||||||
|
|
||||||
if height_in_lines != self.height_in_lines {
|
|
||||||
self.height_in_lines = height_in_lines;
|
|
||||||
cx.emit(PromptEditorEvent::Resized { height_in_lines });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_parent_editor_event(
|
fn handle_parent_editor_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: View<Editor>,
|
_: View<Editor>,
|
||||||
@ -1545,10 +1497,6 @@ impl PromptEditor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_prompt_editor_changed(&mut self, _: View<Editor>, cx: &mut ViewContext<Self>) {
|
|
||||||
self.count_lines(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_prompt_editor_events(
|
fn handle_prompt_editor_events(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: View<Editor>,
|
_: View<Editor>,
|
||||||
|
@ -18,13 +18,11 @@ collections.workspace = true
|
|||||||
ctor.workspace = true
|
ctor.workspace = true
|
||||||
editor.workspace = true
|
editor.workspace = true
|
||||||
env_logger.workspace = true
|
env_logger.workspace = true
|
||||||
feature_flags.workspace = true
|
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
lsp.workspace = true
|
lsp.workspace = true
|
||||||
multi_buffer.workspace = true
|
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
schemars.workspace = true
|
schemars.workspace = true
|
||||||
|
@ -4,7 +4,6 @@ mod toolbar_controls;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod diagnostics_tests;
|
mod diagnostics_tests;
|
||||||
pub(crate) mod grouped_diagnostics;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{BTreeSet, HashSet};
|
use collections::{BTreeSet, HashSet};
|
||||||
@ -15,7 +14,6 @@ use editor::{
|
|||||||
scroll::Autoscroll,
|
scroll::Autoscroll,
|
||||||
Editor, EditorEvent, ExcerptId, ExcerptRange, MultiBuffer, ToOffset,
|
Editor, EditorEvent, ExcerptId, ExcerptRange, MultiBuffer, ToOffset,
|
||||||
};
|
};
|
||||||
use feature_flags::FeatureFlagAppExt;
|
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::mpsc::{self, UnboundedSender},
|
channel::mpsc::{self, UnboundedSender},
|
||||||
StreamExt as _,
|
StreamExt as _,
|
||||||
@ -54,9 +52,6 @@ pub fn init(cx: &mut AppContext) {
|
|||||||
ProjectDiagnosticsSettings::register(cx);
|
ProjectDiagnosticsSettings::register(cx);
|
||||||
cx.observe_new_views(ProjectDiagnosticsEditor::register)
|
cx.observe_new_views(ProjectDiagnosticsEditor::register)
|
||||||
.detach();
|
.detach();
|
||||||
if !cx.has_flag::<feature_flags::GroupedDiagnostics>() {
|
|
||||||
grouped_diagnostics::init(cx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProjectDiagnosticsEditor {
|
struct ProjectDiagnosticsEditor {
|
||||||
@ -469,7 +464,7 @@ impl ProjectDiagnosticsEditor {
|
|||||||
group_state.block_count += 1;
|
group_state.block_count += 1;
|
||||||
blocks_to_add.push(BlockProperties {
|
blocks_to_add.push(BlockProperties {
|
||||||
position: (excerpt_id, entry.range.start),
|
position: (excerpt_id, entry.range.start),
|
||||||
height: diagnostic.message.matches('\n').count() as u8 + 1,
|
height: diagnostic.message.matches('\n').count() as u32 + 1,
|
||||||
style: BlockStyle::Fixed,
|
style: BlockStyle::Fixed,
|
||||||
render: diagnostic_block_renderer(
|
render: diagnostic_block_renderer(
|
||||||
diagnostic, None, true, true,
|
diagnostic, None, true, true,
|
||||||
@ -787,7 +782,7 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
|||||||
let highlight_style: HighlightStyle = cx.theme().colors().text_accent.into();
|
let highlight_style: HighlightStyle = cx.theme().colors().text_accent.into();
|
||||||
h_flex()
|
h_flex()
|
||||||
.id(DIAGNOSTIC_HEADER)
|
.id(DIAGNOSTIC_HEADER)
|
||||||
.py_2()
|
.h(2. * cx.line_height())
|
||||||
.pl_10()
|
.pl_10()
|
||||||
.pr_5()
|
.pr_5()
|
||||||
.w_full()
|
.w_full()
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,11 @@
|
|||||||
use crate::{grouped_diagnostics::GroupedDiagnosticsEditor, ProjectDiagnosticsEditor};
|
use crate::ProjectDiagnosticsEditor;
|
||||||
use futures::future::Either;
|
|
||||||
use gpui::{EventEmitter, ParentElement, Render, View, ViewContext, WeakView};
|
use gpui::{EventEmitter, ParentElement, Render, View, ViewContext, WeakView};
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use ui::{IconButton, IconName, Tooltip};
|
use ui::{IconButton, IconName, Tooltip};
|
||||||
use workspace::{item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
|
use workspace::{item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
|
||||||
|
|
||||||
pub struct ToolbarControls {
|
pub struct ToolbarControls {
|
||||||
editor: Option<Either<WeakView<ProjectDiagnosticsEditor>, WeakView<GroupedDiagnosticsEditor>>>,
|
editor: Option<WeakView<ProjectDiagnosticsEditor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for ToolbarControls {
|
impl Render for ToolbarControls {
|
||||||
@ -16,32 +15,16 @@ impl Render for ToolbarControls {
|
|||||||
let mut is_updating = false;
|
let mut is_updating = false;
|
||||||
|
|
||||||
if let Some(editor) = self.editor() {
|
if let Some(editor) = self.editor() {
|
||||||
match editor {
|
let editor = editor.read(cx);
|
||||||
Either::Left(editor) => {
|
include_warnings = editor.include_warnings;
|
||||||
let editor = editor.read(cx);
|
has_stale_excerpts = !editor.paths_to_update.is_empty();
|
||||||
include_warnings = editor.include_warnings;
|
is_updating = editor.update_paths_tx.len() > 0
|
||||||
has_stale_excerpts = !editor.paths_to_update.is_empty();
|
|| editor
|
||||||
is_updating = editor.update_paths_tx.len() > 0
|
.project
|
||||||
|| editor
|
.read(cx)
|
||||||
.project
|
.language_servers_running_disk_based_diagnostics()
|
||||||
.read(cx)
|
.next()
|
||||||
.language_servers_running_disk_based_diagnostics()
|
.is_some();
|
||||||
.next()
|
|
||||||
.is_some();
|
|
||||||
}
|
|
||||||
Either::Right(editor) => {
|
|
||||||
let editor = editor.read(cx);
|
|
||||||
include_warnings = editor.include_warnings;
|
|
||||||
has_stale_excerpts = !editor.paths_to_update.is_empty();
|
|
||||||
is_updating = editor.update_paths_tx.len() > 0
|
|
||||||
|| editor
|
|
||||||
.project
|
|
||||||
.read(cx)
|
|
||||||
.language_servers_running_disk_based_diagnostics()
|
|
||||||
.next()
|
|
||||||
.is_some();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tooltip = if include_warnings {
|
let tooltip = if include_warnings {
|
||||||
@ -59,18 +42,9 @@ impl Render for ToolbarControls {
|
|||||||
.tooltip(move |cx| Tooltip::text("Update excerpts", cx))
|
.tooltip(move |cx| Tooltip::text("Update excerpts", cx))
|
||||||
.on_click(cx.listener(|this, _, cx| {
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
if let Some(editor) = this.editor() {
|
if let Some(editor) = this.editor() {
|
||||||
match editor {
|
editor.update(cx, |editor, _| {
|
||||||
Either::Left(editor) => {
|
editor.enqueue_update_stale_excerpts(None);
|
||||||
editor.update(cx, |editor, _| {
|
});
|
||||||
editor.enqueue_update_stale_excerpts(None);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Either::Right(editor) => {
|
|
||||||
editor.update(cx, |editor, _| {
|
|
||||||
editor.enqueue_update_stale_excerpts(None);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
@ -80,18 +54,9 @@ impl Render for ToolbarControls {
|
|||||||
.tooltip(move |cx| Tooltip::text(tooltip, cx))
|
.tooltip(move |cx| Tooltip::text(tooltip, cx))
|
||||||
.on_click(cx.listener(|this, _, cx| {
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
if let Some(editor) = this.editor() {
|
if let Some(editor) = this.editor() {
|
||||||
match editor {
|
editor.update(cx, |editor, cx| {
|
||||||
Either::Left(editor) => {
|
editor.toggle_warnings(&Default::default(), cx);
|
||||||
editor.update(cx, |editor, cx| {
|
});
|
||||||
editor.toggle_warnings(&Default::default(), cx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Either::Right(editor) => {
|
|
||||||
editor.update(cx, |editor, cx| {
|
|
||||||
editor.toggle_warnings(&Default::default(), cx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
@ -108,10 +73,7 @@ impl ToolbarItemView for ToolbarControls {
|
|||||||
) -> ToolbarItemLocation {
|
) -> ToolbarItemLocation {
|
||||||
if let Some(pane_item) = active_pane_item.as_ref() {
|
if let Some(pane_item) = active_pane_item.as_ref() {
|
||||||
if let Some(editor) = pane_item.downcast::<ProjectDiagnosticsEditor>() {
|
if let Some(editor) = pane_item.downcast::<ProjectDiagnosticsEditor>() {
|
||||||
self.editor = Some(Either::Left(editor.downgrade()));
|
self.editor = Some(editor.downgrade());
|
||||||
ToolbarItemLocation::PrimaryRight
|
|
||||||
} else if let Some(editor) = pane_item.downcast::<GroupedDiagnosticsEditor>() {
|
|
||||||
self.editor = Some(Either::Right(editor.downgrade()));
|
|
||||||
ToolbarItemLocation::PrimaryRight
|
ToolbarItemLocation::PrimaryRight
|
||||||
} else {
|
} else {
|
||||||
ToolbarItemLocation::Hidden
|
ToolbarItemLocation::Hidden
|
||||||
@ -127,12 +89,7 @@ impl ToolbarControls {
|
|||||||
ToolbarControls { editor: None }
|
ToolbarControls { editor: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(
|
fn editor(&self) -> Option<View<ProjectDiagnosticsEditor>> {
|
||||||
&self,
|
self.editor.as_ref()?.upgrade()
|
||||||
) -> Option<Either<View<ProjectDiagnosticsEditor>, View<GroupedDiagnosticsEditor>>> {
|
|
||||||
Some(match self.editor.as_ref()? {
|
|
||||||
Either::Left(diagnostics) => Either::Left(diagnostics.upgrade()?),
|
|
||||||
Either::Right(grouped_diagnostics) => Either::Right(grouped_diagnostics.upgrade()?),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,9 +120,9 @@ impl DisplayMap {
|
|||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
wrap_width: Option<Pixels>,
|
wrap_width: Option<Pixels>,
|
||||||
show_excerpt_controls: bool,
|
show_excerpt_controls: bool,
|
||||||
buffer_header_height: u8,
|
buffer_header_height: u32,
|
||||||
excerpt_header_height: u8,
|
excerpt_header_height: u32,
|
||||||
excerpt_footer_height: u8,
|
excerpt_footer_height: u32,
|
||||||
fold_placeholder: FoldPlaceholder,
|
fold_placeholder: FoldPlaceholder,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -286,44 +286,11 @@ impl DisplayMap {
|
|||||||
block_map.insert(blocks)
|
block_map.insert(blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_blocks(
|
pub fn resize_blocks(
|
||||||
&mut self,
|
&mut self,
|
||||||
heights_and_renderers: HashMap<CustomBlockId, (Option<u8>, RenderBlock)>,
|
heights: HashMap<CustomBlockId, u32>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
//
|
|
||||||
// Note: previous implementation of `replace_blocks` simply called
|
|
||||||
// `self.block_map.replace(styles)` which just modified the render by replacing
|
|
||||||
// the `RenderBlock` with the new one.
|
|
||||||
//
|
|
||||||
// ```rust
|
|
||||||
// for block in &self.blocks {
|
|
||||||
// if let Some(render) = renderers.remove(&block.id) {
|
|
||||||
// *block.render.lock() = render;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// If height changes however, we need to update the tree. There's a performance
|
|
||||||
// cost to this, so we'll split the replace blocks into handling the old behavior
|
|
||||||
// directly and the new behavior separately.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
let mut only_renderers = HashMap::<CustomBlockId, RenderBlock>::default();
|
|
||||||
let mut full_replace = HashMap::<CustomBlockId, (u8, RenderBlock)>::default();
|
|
||||||
for (id, (height, render)) in heights_and_renderers {
|
|
||||||
if let Some(height) = height {
|
|
||||||
full_replace.insert(id, (height, render));
|
|
||||||
} else {
|
|
||||||
only_renderers.insert(id, render);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.block_map.replace_renderers(only_renderers);
|
|
||||||
|
|
||||||
if full_replace.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||||
let edits = self.buffer_subscription.consume().into_inner();
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||||
@ -334,7 +301,11 @@ impl DisplayMap {
|
|||||||
.wrap_map
|
.wrap_map
|
||||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
||||||
let mut block_map = self.block_map.write(snapshot, edits);
|
let mut block_map = self.block_map.write(snapshot, edits);
|
||||||
block_map.replace(full_replace);
|
block_map.resize(heights);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_blocks(&mut self, renderers: HashMap<CustomBlockId, RenderBlock>) {
|
||||||
|
self.block_map.replace_blocks(renderers);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_blocks(&mut self, ids: HashSet<CustomBlockId>, cx: &mut ModelContext<Self>) {
|
pub fn remove_blocks(&mut self, ids: HashSet<CustomBlockId>, cx: &mut ModelContext<Self>) {
|
||||||
@ -1051,6 +1022,18 @@ impl DisplaySnapshot {
|
|||||||
let type_id = TypeId::of::<Tag>();
|
let type_id = TypeId::of::<Tag>();
|
||||||
self.inlay_highlights.get(&type_id)
|
self.inlay_highlights.get(&type_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn buffer_header_height(&self) -> u32 {
|
||||||
|
self.block_snapshot.buffer_header_height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn excerpt_footer_height(&self) -> u32 {
|
||||||
|
self.block_snapshot.excerpt_footer_height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn excerpt_header_height(&self) -> u32 {
|
||||||
|
self.block_snapshot.excerpt_header_height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||||
|
@ -35,9 +35,9 @@ pub struct BlockMap {
|
|||||||
custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,
|
custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,
|
||||||
transforms: RefCell<SumTree<Transform>>,
|
transforms: RefCell<SumTree<Transform>>,
|
||||||
show_excerpt_controls: bool,
|
show_excerpt_controls: bool,
|
||||||
buffer_header_height: u8,
|
buffer_header_height: u32,
|
||||||
excerpt_header_height: u8,
|
excerpt_header_height: u32,
|
||||||
excerpt_footer_height: u8,
|
excerpt_footer_height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BlockMapReader<'a> {
|
pub struct BlockMapReader<'a> {
|
||||||
@ -52,6 +52,9 @@ pub struct BlockSnapshot {
|
|||||||
wrap_snapshot: WrapSnapshot,
|
wrap_snapshot: WrapSnapshot,
|
||||||
transforms: SumTree<Transform>,
|
transforms: SumTree<Transform>,
|
||||||
custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,
|
custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,
|
||||||
|
pub(super) buffer_header_height: u32,
|
||||||
|
pub(super) excerpt_header_height: u32,
|
||||||
|
pub(super) excerpt_footer_height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
@ -77,15 +80,15 @@ pub type RenderBlock = Box<dyn Send + FnMut(&mut BlockContext) -> AnyElement>;
|
|||||||
pub struct CustomBlock {
|
pub struct CustomBlock {
|
||||||
id: CustomBlockId,
|
id: CustomBlockId,
|
||||||
position: Anchor,
|
position: Anchor,
|
||||||
height: u8,
|
height: u32,
|
||||||
style: BlockStyle,
|
style: BlockStyle,
|
||||||
render: Mutex<RenderBlock>,
|
render: Arc<Mutex<RenderBlock>>,
|
||||||
disposition: BlockDisposition,
|
disposition: BlockDisposition,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BlockProperties<P> {
|
pub struct BlockProperties<P> {
|
||||||
pub position: P,
|
pub position: P,
|
||||||
pub height: u8,
|
pub height: u32,
|
||||||
pub style: BlockStyle,
|
pub style: BlockStyle,
|
||||||
pub render: RenderBlock,
|
pub render: RenderBlock,
|
||||||
pub disposition: BlockDisposition,
|
pub disposition: BlockDisposition,
|
||||||
@ -189,14 +192,14 @@ pub enum Block {
|
|||||||
id: ExcerptId,
|
id: ExcerptId,
|
||||||
buffer: BufferSnapshot,
|
buffer: BufferSnapshot,
|
||||||
range: ExcerptRange<text::Anchor>,
|
range: ExcerptRange<text::Anchor>,
|
||||||
height: u8,
|
height: u32,
|
||||||
starts_new_buffer: bool,
|
starts_new_buffer: bool,
|
||||||
show_excerpt_controls: bool,
|
show_excerpt_controls: bool,
|
||||||
},
|
},
|
||||||
ExcerptFooter {
|
ExcerptFooter {
|
||||||
id: ExcerptId,
|
id: ExcerptId,
|
||||||
disposition: BlockDisposition,
|
disposition: BlockDisposition,
|
||||||
height: u8,
|
height: u32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +234,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self) -> u8 {
|
pub fn height(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => block.height,
|
Block::Custom(block) => block.height,
|
||||||
Block::ExcerptHeader { height, .. } => *height,
|
Block::ExcerptHeader { height, .. } => *height,
|
||||||
@ -301,9 +304,9 @@ impl BlockMap {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
wrap_snapshot: WrapSnapshot,
|
wrap_snapshot: WrapSnapshot,
|
||||||
show_excerpt_controls: bool,
|
show_excerpt_controls: bool,
|
||||||
buffer_header_height: u8,
|
buffer_header_height: u32,
|
||||||
excerpt_header_height: u8,
|
excerpt_header_height: u32,
|
||||||
excerpt_footer_height: u8,
|
excerpt_footer_height: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let row_count = wrap_snapshot.max_point().row() + 1;
|
let row_count = wrap_snapshot.max_point().row() + 1;
|
||||||
let map = Self {
|
let map = Self {
|
||||||
@ -336,6 +339,9 @@ impl BlockMap {
|
|||||||
wrap_snapshot,
|
wrap_snapshot,
|
||||||
transforms: self.transforms.borrow().clone(),
|
transforms: self.transforms.borrow().clone(),
|
||||||
custom_blocks_by_id: self.custom_blocks_by_id.clone(),
|
custom_blocks_by_id: self.custom_blocks_by_id.clone(),
|
||||||
|
buffer_header_height: self.buffer_header_height,
|
||||||
|
excerpt_header_height: self.excerpt_header_height,
|
||||||
|
excerpt_footer_height: self.excerpt_footer_height,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -551,7 +557,7 @@ impl BlockMap {
|
|||||||
*transforms = new_transforms;
|
*transforms = new_transforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_renderers(&mut self, mut renderers: HashMap<CustomBlockId, RenderBlock>) {
|
pub fn replace_blocks(&mut self, mut renderers: HashMap<CustomBlockId, RenderBlock>) {
|
||||||
for block in &mut self.custom_blocks {
|
for block in &mut self.custom_blocks {
|
||||||
if let Some(render) = renderers.remove(&block.id) {
|
if let Some(render) = renderers.remove(&block.id) {
|
||||||
*block.render.lock() = render;
|
*block.render.lock() = render;
|
||||||
@ -565,9 +571,9 @@ impl BlockMap {
|
|||||||
|
|
||||||
pub fn header_and_footer_blocks<'a, 'b: 'a, 'c: 'a + 'b, R, T>(
|
pub fn header_and_footer_blocks<'a, 'b: 'a, 'c: 'a + 'b, R, T>(
|
||||||
show_excerpt_controls: bool,
|
show_excerpt_controls: bool,
|
||||||
excerpt_footer_height: u8,
|
excerpt_footer_height: u32,
|
||||||
buffer_header_height: u8,
|
buffer_header_height: u32,
|
||||||
excerpt_header_height: u8,
|
excerpt_header_height: u32,
|
||||||
buffer: &'b multi_buffer::MultiBufferSnapshot,
|
buffer: &'b multi_buffer::MultiBufferSnapshot,
|
||||||
range: R,
|
range: R,
|
||||||
wrap_snapshot: &'c WrapSnapshot,
|
wrap_snapshot: &'c WrapSnapshot,
|
||||||
@ -793,7 +799,7 @@ impl<'a> BlockMapWriter<'a> {
|
|||||||
id,
|
id,
|
||||||
position,
|
position,
|
||||||
height: block.height,
|
height: block.height,
|
||||||
render: Mutex::new(block.render),
|
render: Arc::new(Mutex::new(block.render)),
|
||||||
disposition: block.disposition,
|
disposition: block.disposition,
|
||||||
style: block.style,
|
style: block.style,
|
||||||
});
|
});
|
||||||
@ -810,24 +816,21 @@ impl<'a> BlockMapWriter<'a> {
|
|||||||
ids
|
ids
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace(
|
pub fn resize(&mut self, mut heights: HashMap<CustomBlockId, u32>) {
|
||||||
&mut self,
|
|
||||||
mut heights_and_renderers: HashMap<CustomBlockId, (u8, RenderBlock)>,
|
|
||||||
) {
|
|
||||||
let wrap_snapshot = &*self.0.wrap_snapshot.borrow();
|
let wrap_snapshot = &*self.0.wrap_snapshot.borrow();
|
||||||
let buffer = wrap_snapshot.buffer_snapshot();
|
let buffer = wrap_snapshot.buffer_snapshot();
|
||||||
let mut edits = Patch::default();
|
let mut edits = Patch::default();
|
||||||
let mut last_block_buffer_row = None;
|
let mut last_block_buffer_row = None;
|
||||||
|
|
||||||
for block in &mut self.0.custom_blocks {
|
for block in &mut self.0.custom_blocks {
|
||||||
if let Some((new_height, render)) = heights_and_renderers.remove(&block.id) {
|
if let Some(new_height) = heights.remove(&block.id) {
|
||||||
if block.height != new_height {
|
if block.height != new_height {
|
||||||
let new_block = CustomBlock {
|
let new_block = CustomBlock {
|
||||||
id: block.id,
|
id: block.id,
|
||||||
position: block.position,
|
position: block.position,
|
||||||
height: new_height,
|
height: new_height,
|
||||||
style: block.style,
|
style: block.style,
|
||||||
render: Mutex::new(render),
|
render: block.render.clone(),
|
||||||
disposition: block.disposition,
|
disposition: block.disposition,
|
||||||
};
|
};
|
||||||
let new_block = Arc::new(new_block);
|
let new_block = Arc::new(new_block);
|
||||||
@ -1174,7 +1177,7 @@ impl Transform {
|
|||||||
Self {
|
Self {
|
||||||
summary: TransformSummary {
|
summary: TransformSummary {
|
||||||
input_rows: 0,
|
input_rows: 0,
|
||||||
output_rows: block.height() as u32,
|
output_rows: block.height(),
|
||||||
},
|
},
|
||||||
block: Some(block),
|
block: Some(block),
|
||||||
}
|
}
|
||||||
@ -1445,7 +1448,7 @@ mod tests {
|
|||||||
.blocks_in_range(0..8)
|
.blocks_in_range(0..8)
|
||||||
.map(|(start_row, block)| {
|
.map(|(start_row, block)| {
|
||||||
let block = block.as_custom().unwrap();
|
let block = block.as_custom().unwrap();
|
||||||
(start_row..start_row + block.height as u32, block.id)
|
(start_row..start_row + block.height, block.id)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@ -1697,10 +1700,9 @@ mod tests {
|
|||||||
|
|
||||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||||
|
|
||||||
let mut hash_map = HashMap::default();
|
let mut new_heights = HashMap::default();
|
||||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
new_heights.insert(block_ids[0], 2);
|
||||||
hash_map.insert(block_ids[0], (2_u8, render));
|
block_map_writer.resize(new_heights);
|
||||||
block_map_writer.replace(hash_map);
|
|
||||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||||
assert_eq!(snapshot.text(), "aaa\n\n\n\n\nbbb\nccc\nddd\n\n\n");
|
assert_eq!(snapshot.text(), "aaa\n\n\n\n\nbbb\nccc\nddd\n\n\n");
|
||||||
}
|
}
|
||||||
@ -1708,10 +1710,9 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||||
|
|
||||||
let mut hash_map = HashMap::default();
|
let mut new_heights = HashMap::default();
|
||||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
new_heights.insert(block_ids[0], 1);
|
||||||
hash_map.insert(block_ids[0], (1_u8, render));
|
block_map_writer.resize(new_heights);
|
||||||
block_map_writer.replace(hash_map);
|
|
||||||
|
|
||||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||||
assert_eq!(snapshot.text(), "aaa\n\n\n\nbbb\nccc\nddd\n\n\n");
|
assert_eq!(snapshot.text(), "aaa\n\n\n\nbbb\nccc\nddd\n\n\n");
|
||||||
@ -1720,10 +1721,9 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||||
|
|
||||||
let mut hash_map = HashMap::default();
|
let mut new_heights = HashMap::default();
|
||||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
new_heights.insert(block_ids[0], 0);
|
||||||
hash_map.insert(block_ids[0], (0_u8, render));
|
block_map_writer.resize(new_heights);
|
||||||
block_map_writer.replace(hash_map);
|
|
||||||
|
|
||||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||||
assert_eq!(snapshot.text(), "aaa\n\n\nbbb\nccc\nddd\n\n\n");
|
assert_eq!(snapshot.text(), "aaa\n\n\nbbb\nccc\nddd\n\n\n");
|
||||||
@ -1732,10 +1732,9 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||||
|
|
||||||
let mut hash_map = HashMap::default();
|
let mut new_heights = HashMap::default();
|
||||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
new_heights.insert(block_ids[0], 3);
|
||||||
hash_map.insert(block_ids[0], (3_u8, render));
|
block_map_writer.resize(new_heights);
|
||||||
block_map_writer.replace(hash_map);
|
|
||||||
|
|
||||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||||
assert_eq!(snapshot.text(), "aaa\n\n\n\n\n\nbbb\nccc\nddd\n\n\n");
|
assert_eq!(snapshot.text(), "aaa\n\n\n\n\n\nbbb\nccc\nddd\n\n\n");
|
||||||
@ -1744,10 +1743,9 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||||
|
|
||||||
let mut hash_map = HashMap::default();
|
let mut new_heights = HashMap::default();
|
||||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
new_heights.insert(block_ids[0], 3);
|
||||||
hash_map.insert(block_ids[0], (3_u8, render));
|
block_map_writer.resize(new_heights);
|
||||||
block_map_writer.replace(hash_map);
|
|
||||||
|
|
||||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||||
// Same height as before, should remain the same
|
// Same height as before, should remain the same
|
||||||
@ -2185,17 +2183,17 @@ mod tests {
|
|||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
enum ExpectedBlock {
|
enum ExpectedBlock {
|
||||||
ExcerptHeader {
|
ExcerptHeader {
|
||||||
height: u8,
|
height: u32,
|
||||||
starts_new_buffer: bool,
|
starts_new_buffer: bool,
|
||||||
},
|
},
|
||||||
ExcerptFooter {
|
ExcerptFooter {
|
||||||
height: u8,
|
height: u32,
|
||||||
disposition: BlockDisposition,
|
disposition: BlockDisposition,
|
||||||
},
|
},
|
||||||
Custom {
|
Custom {
|
||||||
disposition: BlockDisposition,
|
disposition: BlockDisposition,
|
||||||
id: CustomBlockId,
|
id: CustomBlockId,
|
||||||
height: u8,
|
height: u32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2214,7 +2212,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExpectedBlock {
|
impl ExpectedBlock {
|
||||||
fn height(&self) -> u8 {
|
fn height(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
ExpectedBlock::ExcerptHeader { height, .. } => *height,
|
ExpectedBlock::ExcerptHeader { height, .. } => *height,
|
||||||
ExpectedBlock::Custom { height, .. } => *height,
|
ExpectedBlock::Custom { height, .. } => *height,
|
||||||
|
@ -160,9 +160,9 @@ use workspace::{OpenInTerminal, OpenTerminal, TabBarSettings, Toast};
|
|||||||
use crate::hover_links::find_url;
|
use crate::hover_links::find_url;
|
||||||
use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
|
use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
|
||||||
|
|
||||||
pub const FILE_HEADER_HEIGHT: u8 = 1;
|
pub const FILE_HEADER_HEIGHT: u32 = 1;
|
||||||
pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u8 = 1;
|
pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
|
||||||
pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u8 = 1;
|
pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
|
||||||
pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
|
pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
|
||||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
const MAX_LINE_LEN: usize = 1024;
|
const MAX_LINE_LEN: usize = 1024;
|
||||||
@ -558,7 +558,7 @@ pub struct Editor {
|
|||||||
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
||||||
tasks_update_task: Option<Task<()>>,
|
tasks_update_task: Option<Task<()>>,
|
||||||
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
|
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
|
||||||
file_header_size: u8,
|
file_header_size: u32,
|
||||||
breadcrumb_header: Option<String>,
|
breadcrumb_header: Option<String>,
|
||||||
focused_block: Option<FocusedBlock>,
|
focused_block: Option<FocusedBlock>,
|
||||||
}
|
}
|
||||||
@ -9805,14 +9805,11 @@ impl Editor {
|
|||||||
for (block_id, diagnostic) in &active_diagnostics.blocks {
|
for (block_id, diagnostic) in &active_diagnostics.blocks {
|
||||||
new_styles.insert(
|
new_styles.insert(
|
||||||
*block_id,
|
*block_id,
|
||||||
(
|
diagnostic_block_renderer(diagnostic.clone(), None, true, is_valid),
|
||||||
None,
|
|
||||||
diagnostic_block_renderer(diagnostic.clone(), None, true, is_valid),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.display_map.update(cx, |display_map, cx| {
|
self.display_map.update(cx, |display_map, _cx| {
|
||||||
display_map.replace_blocks(new_styles, cx)
|
display_map.replace_blocks(new_styles)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9855,7 +9852,7 @@ impl Editor {
|
|||||||
.insert_blocks(
|
.insert_blocks(
|
||||||
diagnostic_group.iter().map(|entry| {
|
diagnostic_group.iter().map(|entry| {
|
||||||
let diagnostic = entry.diagnostic.clone();
|
let diagnostic = entry.diagnostic.clone();
|
||||||
let message_height = diagnostic.message.matches('\n').count() as u8 + 1;
|
let message_height = diagnostic.message.matches('\n').count() as u32 + 1;
|
||||||
BlockProperties {
|
BlockProperties {
|
||||||
style: BlockStyle::Fixed,
|
style: BlockStyle::Fixed,
|
||||||
position: buffer.anchor_after(entry.range.start),
|
position: buffer.anchor_after(entry.range.start),
|
||||||
@ -10170,19 +10167,34 @@ impl Editor {
|
|||||||
blocks
|
blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_blocks(
|
pub(crate) fn resize_blocks(
|
||||||
&mut self,
|
&mut self,
|
||||||
blocks: HashMap<CustomBlockId, (Option<u8>, RenderBlock)>,
|
heights: HashMap<CustomBlockId, u32>,
|
||||||
autoscroll: Option<Autoscroll>,
|
autoscroll: Option<Autoscroll>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
self.display_map
|
self.display_map
|
||||||
.update(cx, |display_map, cx| display_map.replace_blocks(blocks, cx));
|
.update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
|
||||||
if let Some(autoscroll) = autoscroll {
|
if let Some(autoscroll) = autoscroll {
|
||||||
self.request_autoscroll(autoscroll, cx);
|
self.request_autoscroll(autoscroll, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn replace_blocks(
|
||||||
|
&mut self,
|
||||||
|
renderers: HashMap<CustomBlockId, RenderBlock>,
|
||||||
|
autoscroll: Option<Autoscroll>,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
self.display_map
|
||||||
|
.update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
|
||||||
|
if let Some(autoscroll) = autoscroll {
|
||||||
|
self.request_autoscroll(autoscroll, cx);
|
||||||
|
} else {
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_blocks(
|
pub fn remove_blocks(
|
||||||
&mut self,
|
&mut self,
|
||||||
block_ids: HashSet<CustomBlockId>,
|
block_ids: HashSet<CustomBlockId>,
|
||||||
@ -11755,7 +11767,7 @@ impl Editor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_header_size(&self) -> u8 {
|
pub fn file_header_size(&self) -> u32 {
|
||||||
self.file_header_size
|
self.file_header_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,14 +17,14 @@ use crate::{
|
|||||||
hunk_diff::ExpandedHunk,
|
hunk_diff::ExpandedHunk,
|
||||||
hunk_status,
|
hunk_status,
|
||||||
items::BufferSearchHighlights,
|
items::BufferSearchHighlights,
|
||||||
mouse_context_menu::MenuPosition,
|
mouse_context_menu::{self, MenuPosition, MouseContextMenu},
|
||||||
mouse_context_menu::{self, MouseContextMenu},
|
|
||||||
scroll::scroll_amount::ScrollAmount,
|
scroll::scroll_amount::ScrollAmount,
|
||||||
BlockId, CodeActionsMenu, CursorShape, DisplayPoint, DisplayRow, DocumentHighlightRead,
|
BlockId, CodeActionsMenu, CursorShape, CustomBlockId, DisplayPoint, DisplayRow,
|
||||||
DocumentHighlightWrite, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
|
DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode, EditorSettings,
|
||||||
ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown, HalfPageUp, HoveredCursor,
|
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
||||||
HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RangeToAnchorExt, RowExt,
|
HalfPageUp, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown, PageUp,
|
||||||
RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
Point, RangeToAnchorExt, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
|
||||||
|
CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
||||||
};
|
};
|
||||||
use client::ParticipantIndex;
|
use client::ParticipantIndex;
|
||||||
use collections::{BTreeMap, HashMap};
|
use collections::{BTreeMap, HashMap};
|
||||||
@ -1929,7 +1929,7 @@ impl EditorElement {
|
|||||||
fn render_block(
|
fn render_block(
|
||||||
&self,
|
&self,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
available_space: Size<AvailableSpace>,
|
available_width: AvailableSpace,
|
||||||
block_id: BlockId,
|
block_id: BlockId,
|
||||||
block_row_start: DisplayRow,
|
block_row_start: DisplayRow,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
@ -1941,6 +1941,7 @@ impl EditorElement {
|
|||||||
em_width: Pixels,
|
em_width: Pixels,
|
||||||
text_hitbox: &Hitbox,
|
text_hitbox: &Hitbox,
|
||||||
scroll_width: &mut Pixels,
|
scroll_width: &mut Pixels,
|
||||||
|
resized_blocks: &mut HashMap<CustomBlockId, u32>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (AnyElement, Size<Pixels>) {
|
) -> (AnyElement, Size<Pixels>) {
|
||||||
let mut element = match block {
|
let mut element = match block {
|
||||||
@ -2021,7 +2022,7 @@ impl EditorElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let line_offset_from_top =
|
let line_offset_from_top =
|
||||||
block_row_start.0 + *height as u32 + offset_from_excerpt_start
|
block_row_start.0 + *height + offset_from_excerpt_start
|
||||||
- snapshot
|
- snapshot
|
||||||
.scroll_anchor
|
.scroll_anchor
|
||||||
.scroll_position(&snapshot.display_snapshot)
|
.scroll_position(&snapshot.display_snapshot)
|
||||||
@ -2054,12 +2055,13 @@ impl EditorElement {
|
|||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.id(("path excerpt header", EntityId::from(block_id)))
|
.id(("path excerpt header", EntityId::from(block_id)))
|
||||||
.size_full()
|
.w_full()
|
||||||
.p(header_padding)
|
.px(header_padding)
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.667)))
|
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.667)))
|
||||||
.id("path header block")
|
.id("path header block")
|
||||||
|
.h(2. * cx.line_height())
|
||||||
.pl(gpui::px(12.))
|
.pl(gpui::px(12.))
|
||||||
.pr(gpui::px(8.))
|
.pr(gpui::px(8.))
|
||||||
.rounded_md()
|
.rounded_md()
|
||||||
@ -2112,6 +2114,7 @@ impl EditorElement {
|
|||||||
.children(show_excerpt_controls.then(|| {
|
.children(show_excerpt_controls.then(|| {
|
||||||
h_flex()
|
h_flex()
|
||||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.333)))
|
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.333)))
|
||||||
|
.h(1. * cx.line_height())
|
||||||
.pt_1()
|
.pt_1()
|
||||||
.justify_end()
|
.justify_end()
|
||||||
.flex_none()
|
.flex_none()
|
||||||
@ -2157,7 +2160,8 @@ impl EditorElement {
|
|||||||
} else {
|
} else {
|
||||||
v_flex()
|
v_flex()
|
||||||
.id(("excerpt header", EntityId::from(block_id)))
|
.id(("excerpt header", EntityId::from(block_id)))
|
||||||
.size_full()
|
.w_full()
|
||||||
|
.h(snapshot.excerpt_header_height() as f32 * cx.line_height())
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
@ -2309,7 +2313,8 @@ impl EditorElement {
|
|||||||
Block::ExcerptFooter { id, .. } => {
|
Block::ExcerptFooter { id, .. } => {
|
||||||
let element = v_flex()
|
let element = v_flex()
|
||||||
.id(("excerpt footer", EntityId::from(block_id)))
|
.id(("excerpt footer", EntityId::from(block_id)))
|
||||||
.size_full()
|
.w_full()
|
||||||
|
.h(snapshot.excerpt_footer_height() as f32 * cx.line_height())
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.justify_end()
|
.justify_end()
|
||||||
@ -2357,8 +2362,24 @@ impl EditorElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = element.layout_as_root(available_space, cx);
|
// Discover the element's content height, then round up to the nearest multiple of line height.
|
||||||
(element, size)
|
let preliminary_size =
|
||||||
|
element.layout_as_root(size(available_width, AvailableSpace::MinContent), cx);
|
||||||
|
let quantized_height = (preliminary_size.height / line_height).ceil() * line_height;
|
||||||
|
let final_size = if preliminary_size.height == quantized_height {
|
||||||
|
preliminary_size
|
||||||
|
} else {
|
||||||
|
element.layout_as_root(size(available_width, quantized_height.into()), cx)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let BlockId::Custom(custom_block_id) = block_id {
|
||||||
|
let element_height_in_lines = (final_size.height / line_height).ceil() as u32;
|
||||||
|
if element_height_in_lines != block.height() {
|
||||||
|
resized_blocks.insert(custom_block_id, element_height_in_lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(element, final_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@ -2375,7 +2396,7 @@ impl EditorElement {
|
|||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Vec<BlockLayout> {
|
) -> Result<Vec<BlockLayout>, HashMap<CustomBlockId, u32>> {
|
||||||
let (fixed_blocks, non_fixed_blocks) = snapshot
|
let (fixed_blocks, non_fixed_blocks) = snapshot
|
||||||
.blocks_in_range(rows.clone())
|
.blocks_in_range(rows.clone())
|
||||||
.partition::<Vec<_>, _>(|(_, block)| block.style() == BlockStyle::Fixed);
|
.partition::<Vec<_>, _>(|(_, block)| block.style() == BlockStyle::Fixed);
|
||||||
@ -2385,11 +2406,9 @@ impl EditorElement {
|
|||||||
.update(cx, |editor, _| editor.take_focused_block());
|
.update(cx, |editor, _| editor.take_focused_block());
|
||||||
let mut fixed_block_max_width = Pixels::ZERO;
|
let mut fixed_block_max_width = Pixels::ZERO;
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
|
let mut resized_blocks = HashMap::default();
|
||||||
|
|
||||||
for (row, block) in fixed_blocks {
|
for (row, block) in fixed_blocks {
|
||||||
let available_space = size(
|
|
||||||
AvailableSpace::MinContent,
|
|
||||||
AvailableSpace::Definite(block.height() as f32 * line_height),
|
|
||||||
);
|
|
||||||
let block_id = block.id();
|
let block_id = block.id();
|
||||||
|
|
||||||
if focused_block.as_ref().map_or(false, |b| b.id == block_id) {
|
if focused_block.as_ref().map_or(false, |b| b.id == block_id) {
|
||||||
@ -2398,7 +2417,7 @@ impl EditorElement {
|
|||||||
|
|
||||||
let (element, element_size) = self.render_block(
|
let (element, element_size) = self.render_block(
|
||||||
block,
|
block,
|
||||||
available_space,
|
AvailableSpace::MinContent,
|
||||||
block_id,
|
block_id,
|
||||||
row,
|
row,
|
||||||
snapshot,
|
snapshot,
|
||||||
@ -2410,6 +2429,7 @@ impl EditorElement {
|
|||||||
em_width,
|
em_width,
|
||||||
text_hitbox,
|
text_hitbox,
|
||||||
scroll_width,
|
scroll_width,
|
||||||
|
&mut resized_blocks,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
fixed_block_max_width = fixed_block_max_width.max(element_size.width + em_width);
|
fixed_block_max_width = fixed_block_max_width.max(element_size.width + em_width);
|
||||||
@ -2417,7 +2437,7 @@ impl EditorElement {
|
|||||||
id: block_id,
|
id: block_id,
|
||||||
row: Some(row),
|
row: Some(row),
|
||||||
element,
|
element,
|
||||||
available_space,
|
available_space: size(AvailableSpace::MinContent, element_size.height.into()),
|
||||||
style: BlockStyle::Fixed,
|
style: BlockStyle::Fixed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2432,19 +2452,15 @@ impl EditorElement {
|
|||||||
.max(gutter_dimensions.width + *scroll_width),
|
.max(gutter_dimensions.width + *scroll_width),
|
||||||
BlockStyle::Fixed => unreachable!(),
|
BlockStyle::Fixed => unreachable!(),
|
||||||
};
|
};
|
||||||
let available_space = size(
|
|
||||||
AvailableSpace::Definite(width),
|
|
||||||
AvailableSpace::Definite(block.height() as f32 * line_height),
|
|
||||||
);
|
|
||||||
let block_id = block.id();
|
let block_id = block.id();
|
||||||
|
|
||||||
if focused_block.as_ref().map_or(false, |b| b.id == block_id) {
|
if focused_block.as_ref().map_or(false, |b| b.id == block_id) {
|
||||||
focused_block = None;
|
focused_block = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (element, _) = self.render_block(
|
let (element, element_size) = self.render_block(
|
||||||
block,
|
block,
|
||||||
available_space,
|
width.into(),
|
||||||
block_id,
|
block_id,
|
||||||
row,
|
row,
|
||||||
snapshot,
|
snapshot,
|
||||||
@ -2456,13 +2472,15 @@ impl EditorElement {
|
|||||||
em_width,
|
em_width,
|
||||||
text_hitbox,
|
text_hitbox,
|
||||||
scroll_width,
|
scroll_width,
|
||||||
|
&mut resized_blocks,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
blocks.push(BlockLayout {
|
blocks.push(BlockLayout {
|
||||||
id: block_id,
|
id: block_id,
|
||||||
row: Some(row),
|
row: Some(row),
|
||||||
element,
|
element,
|
||||||
available_space,
|
available_space: size(width.into(), element_size.height.into()),
|
||||||
style,
|
style,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2483,14 +2501,10 @@ impl EditorElement {
|
|||||||
),
|
),
|
||||||
BlockStyle::Sticky => AvailableSpace::Definite(hitbox.size.width),
|
BlockStyle::Sticky => AvailableSpace::Definite(hitbox.size.width),
|
||||||
};
|
};
|
||||||
let available_space = size(
|
|
||||||
width,
|
|
||||||
AvailableSpace::Definite(block.height() as f32 * line_height),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (element, _) = self.render_block(
|
let (element, element_size) = self.render_block(
|
||||||
&block,
|
&block,
|
||||||
available_space,
|
width,
|
||||||
focused_block.id,
|
focused_block.id,
|
||||||
rows.end,
|
rows.end,
|
||||||
snapshot,
|
snapshot,
|
||||||
@ -2502,6 +2516,7 @@ impl EditorElement {
|
|||||||
em_width,
|
em_width,
|
||||||
text_hitbox,
|
text_hitbox,
|
||||||
scroll_width,
|
scroll_width,
|
||||||
|
&mut resized_blocks,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2509,7 +2524,7 @@ impl EditorElement {
|
|||||||
id: block.id(),
|
id: block.id(),
|
||||||
row: None,
|
row: None,
|
||||||
element,
|
element,
|
||||||
available_space,
|
available_space: size(width, element_size.height.into()),
|
||||||
style,
|
style,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2517,10 +2532,16 @@ impl EditorElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*scroll_width = (*scroll_width).max(fixed_block_max_width - gutter_dimensions.width);
|
if resized_blocks.is_empty() {
|
||||||
blocks
|
*scroll_width = (*scroll_width).max(fixed_block_max_width - gutter_dimensions.width);
|
||||||
|
Ok(blocks)
|
||||||
|
} else {
|
||||||
|
Err(resized_blocks)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if any of the blocks changed size since the previous frame. This will trigger
|
||||||
|
/// a restart of rendering for the editor based on the new sizes.
|
||||||
fn layout_blocks(
|
fn layout_blocks(
|
||||||
&self,
|
&self,
|
||||||
blocks: &mut Vec<BlockLayout>,
|
blocks: &mut Vec<BlockLayout>,
|
||||||
@ -4938,21 +4959,27 @@ impl Element for EditorElement {
|
|||||||
editor.gutter_dimensions = gutter_dimensions;
|
editor.gutter_dimensions = gutter_dimensions;
|
||||||
editor.set_visible_line_count(bounds.size.height / line_height, cx);
|
editor.set_visible_line_count(bounds.size.height / line_height, cx);
|
||||||
|
|
||||||
let editor_width =
|
if matches!(editor.mode, EditorMode::AutoHeight { .. }) {
|
||||||
text_width - gutter_dimensions.margin - overscroll.width - em_width;
|
|
||||||
let wrap_width = match editor.soft_wrap_mode(cx) {
|
|
||||||
SoftWrap::None => None,
|
|
||||||
SoftWrap::PreferLine => Some((MAX_LINE_LEN / 2) as f32 * em_advance),
|
|
||||||
SoftWrap::EditorWidth => Some(editor_width),
|
|
||||||
SoftWrap::Column(column) => {
|
|
||||||
Some(editor_width.min(column as f32 * em_advance))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if editor.set_wrap_width(wrap_width, cx) {
|
|
||||||
editor.snapshot(cx)
|
|
||||||
} else {
|
|
||||||
snapshot
|
snapshot
|
||||||
|
} else {
|
||||||
|
let editor_width =
|
||||||
|
text_width - gutter_dimensions.margin - overscroll.width - em_width;
|
||||||
|
let wrap_width = match editor.soft_wrap_mode(cx) {
|
||||||
|
SoftWrap::None => None,
|
||||||
|
SoftWrap::PreferLine => {
|
||||||
|
Some((MAX_LINE_LEN / 2) as f32 * em_advance)
|
||||||
|
}
|
||||||
|
SoftWrap::EditorWidth => Some(editor_width),
|
||||||
|
SoftWrap::Column(column) => {
|
||||||
|
Some(editor_width.min(column as f32 * em_advance))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if editor.set_wrap_width(wrap_width, cx) {
|
||||||
|
editor.snapshot(cx)
|
||||||
|
} else {
|
||||||
|
snapshot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -4995,11 +5022,13 @@ impl Element for EditorElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut autoscroll_request = None;
|
||||||
let mut autoscroll_containing_element = false;
|
let mut autoscroll_containing_element = false;
|
||||||
let mut autoscroll_horizontally = false;
|
let mut autoscroll_horizontally = false;
|
||||||
self.editor.update(cx, |editor, cx| {
|
self.editor.update(cx, |editor, cx| {
|
||||||
|
autoscroll_request = editor.autoscroll_request();
|
||||||
autoscroll_containing_element =
|
autoscroll_containing_element =
|
||||||
editor.autoscroll_requested() || editor.has_pending_selection();
|
autoscroll_request.is_some() || editor.has_pending_selection();
|
||||||
autoscroll_horizontally =
|
autoscroll_horizontally =
|
||||||
editor.autoscroll_vertically(bounds, line_height, max_scroll_top, cx);
|
editor.autoscroll_vertically(bounds, line_height, max_scroll_top, cx);
|
||||||
snapshot = editor.snapshot(cx);
|
snapshot = editor.snapshot(cx);
|
||||||
@ -5116,7 +5145,7 @@ impl Element for EditorElement {
|
|||||||
let mut scroll_width =
|
let mut scroll_width =
|
||||||
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
||||||
|
|
||||||
let mut blocks = cx.with_element_namespace("blocks", |cx| {
|
let blocks = cx.with_element_namespace("blocks", |cx| {
|
||||||
self.render_blocks(
|
self.render_blocks(
|
||||||
start_row..end_row,
|
start_row..end_row,
|
||||||
&snapshot,
|
&snapshot,
|
||||||
@ -5131,6 +5160,15 @@ impl Element for EditorElement {
|
|||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
let mut blocks = match blocks {
|
||||||
|
Ok(blocks) => blocks,
|
||||||
|
Err(resized_blocks) => {
|
||||||
|
self.editor.update(cx, |editor, cx| {
|
||||||
|
editor.resize_blocks(resized_blocks, autoscroll_request, cx)
|
||||||
|
});
|
||||||
|
return self.prepaint(None, bounds, &mut (), cx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let start_buffer_row =
|
let start_buffer_row =
|
||||||
MultiBufferRow(start_anchor.to_point(&snapshot.buffer_snapshot).row);
|
MultiBufferRow(start_anchor.to_point(&snapshot.buffer_snapshot).row);
|
||||||
@ -6430,7 +6468,7 @@ mod tests {
|
|||||||
disposition: BlockDisposition::Above,
|
disposition: BlockDisposition::Above,
|
||||||
height: 3,
|
height: 3,
|
||||||
position: Anchor::min(),
|
position: Anchor::min(),
|
||||||
render: Box::new(|_| div().into_any()),
|
render: Box::new(|cx| div().h(3. * cx.line_height()).into_any()),
|
||||||
}],
|
}],
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
|
@ -364,7 +364,7 @@ impl Editor {
|
|||||||
.row;
|
.row;
|
||||||
let diff_end_row = diff_base.offset_to_point(hunk.diff_base_byte_range.end).row;
|
let diff_end_row = diff_base.offset_to_point(hunk.diff_base_byte_range.end).row;
|
||||||
let line_count = diff_end_row - diff_start_row;
|
let line_count = diff_end_row - diff_start_row;
|
||||||
line_count as u8
|
line_count
|
||||||
})?;
|
})?;
|
||||||
Some((diff_base_buffer, deleted_text_lines))
|
Some((diff_base_buffer, deleted_text_lines))
|
||||||
} else {
|
} else {
|
||||||
@ -422,7 +422,7 @@ impl Editor {
|
|||||||
fn insert_deleted_text_block(
|
fn insert_deleted_text_block(
|
||||||
&mut self,
|
&mut self,
|
||||||
diff_base_buffer: Model<Buffer>,
|
diff_base_buffer: Model<Buffer>,
|
||||||
deleted_text_height: u8,
|
deleted_text_height: u32,
|
||||||
hunk: &HoveredHunk,
|
hunk: &HoveredHunk,
|
||||||
cx: &mut ViewContext<'_, Self>,
|
cx: &mut ViewContext<'_, Self>,
|
||||||
) -> Option<CustomBlockId> {
|
) -> Option<CustomBlockId> {
|
||||||
@ -431,10 +431,11 @@ impl Editor {
|
|||||||
editor_with_deleted_text(diff_base_buffer, deleted_hunk_color, hunk, cx);
|
editor_with_deleted_text(diff_base_buffer, deleted_hunk_color, hunk, cx);
|
||||||
let editor = cx.view().clone();
|
let editor = cx.view().clone();
|
||||||
let hunk = hunk.clone();
|
let hunk = hunk.clone();
|
||||||
|
let height = editor_height.max(deleted_text_height);
|
||||||
let mut new_block_ids = self.insert_blocks(
|
let mut new_block_ids = self.insert_blocks(
|
||||||
Some(BlockProperties {
|
Some(BlockProperties {
|
||||||
position: hunk.multi_buffer_range.start,
|
position: hunk.multi_buffer_range.start,
|
||||||
height: editor_height.max(deleted_text_height),
|
height,
|
||||||
style: BlockStyle::Flex,
|
style: BlockStyle::Flex,
|
||||||
disposition: BlockDisposition::Above,
|
disposition: BlockDisposition::Above,
|
||||||
render: Box::new(move |cx| {
|
render: Box::new(move |cx| {
|
||||||
@ -474,7 +475,8 @@ impl Editor {
|
|||||||
h_flex()
|
h_flex()
|
||||||
.id("gutter with editor")
|
.id("gutter with editor")
|
||||||
.bg(deleted_hunk_color)
|
.bg(deleted_hunk_color)
|
||||||
.size_full()
|
.h(height as f32 * cx.line_height())
|
||||||
|
.w_full()
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.id("gutter")
|
.id("gutter")
|
||||||
@ -783,7 +785,7 @@ fn editor_with_deleted_text(
|
|||||||
deleted_color: Hsla,
|
deleted_color: Hsla,
|
||||||
hunk: &HoveredHunk,
|
hunk: &HoveredHunk,
|
||||||
cx: &mut ViewContext<'_, Editor>,
|
cx: &mut ViewContext<'_, Editor>,
|
||||||
) -> (u8, View<Editor>) {
|
) -> (u32, View<Editor>) {
|
||||||
let parent_editor = cx.view().downgrade();
|
let parent_editor = cx.view().downgrade();
|
||||||
let editor = cx.new_view(|cx| {
|
let editor = cx.new_view(|cx| {
|
||||||
let multi_buffer =
|
let multi_buffer =
|
||||||
@ -885,7 +887,7 @@ fn editor_with_deleted_text(
|
|||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
|
|
||||||
let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row().0 as u8);
|
let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row().0);
|
||||||
(editor_height, editor)
|
(editor_height, editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,8 +307,8 @@ impl ScrollManager {
|
|||||||
self.show_scrollbars
|
self.show_scrollbars
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn autoscroll_requested(&self) -> bool {
|
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
|
||||||
self.autoscroll_request.is_some()
|
self.autoscroll_request.map(|(autoscroll, _)| autoscroll)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_dragging_scrollbar(&self) -> bool {
|
pub fn is_dragging_scrollbar(&self) -> bool {
|
||||||
|
@ -61,8 +61,8 @@ impl AutoscrollStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn autoscroll_requested(&self) -> bool {
|
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
|
||||||
self.scroll_manager.autoscroll_requested()
|
self.scroll_manager.autoscroll_request()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn autoscroll_vertically(
|
pub fn autoscroll_vertically(
|
||||||
|
@ -43,11 +43,6 @@ impl FeatureFlag for LanguageModels {
|
|||||||
const NAME: &'static str = "language-models";
|
const NAME: &'static str = "language-models";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GroupedDiagnostics {}
|
|
||||||
impl FeatureFlag for GroupedDiagnostics {
|
|
||||||
const NAME: &'static str = "grouped-diagnostics";
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ZedPro {}
|
pub struct ZedPro {}
|
||||||
impl FeatureFlag for ZedPro {
|
impl FeatureFlag for ZedPro {
|
||||||
const NAME: &'static str = "zed-pro";
|
const NAME: &'static str = "zed-pro";
|
||||||
|
@ -1366,11 +1366,7 @@ impl<'a> WindowContext<'a> {
|
|||||||
|
|
||||||
/// The line height associated with the current text style.
|
/// The line height associated with the current text style.
|
||||||
pub fn line_height(&self) -> Pixels {
|
pub fn line_height(&self) -> Pixels {
|
||||||
let rem_size = self.rem_size();
|
self.text_style().line_height_in_pixels(self.rem_size())
|
||||||
let text_style = self.text_style();
|
|
||||||
text_style
|
|
||||||
.line_height
|
|
||||||
.to_pixels(text_style.font_size, rem_size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call to prevent the default action of an event. Currently only used to prevent
|
/// Call to prevent the default action of an event. Currently only used to prevent
|
||||||
|
@ -19,7 +19,7 @@ use ui::{div, prelude::*, v_flex, IntoElement, Styled, ViewContext};
|
|||||||
/// Given these outputs are destined for the editor with the block decorations API, all of them must report
|
/// Given these outputs are destined for the editor with the block decorations API, all of them must report
|
||||||
/// how many lines they will take up in the editor.
|
/// how many lines they will take up in the editor.
|
||||||
pub trait LineHeight: Sized {
|
pub trait LineHeight: Sized {
|
||||||
fn num_lines(&self, cx: &mut WindowContext) -> u8;
|
fn num_lines(&self, cx: &mut WindowContext) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When deciding what to render from a collection of mediatypes, we need to rank them in order of importance
|
/// When deciding what to render from a collection of mediatypes, we need to rank them in order of importance
|
||||||
@ -88,15 +88,9 @@ impl ImageView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LineHeight for ImageView {
|
impl LineHeight for ImageView {
|
||||||
fn num_lines(&self, cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, cx: &mut WindowContext) -> usize {
|
||||||
let line_height = cx.line_height();
|
let line_height = cx.line_height();
|
||||||
|
(self.height as f32 / line_height.0) as usize
|
||||||
let lines = self.height as f32 / line_height.0;
|
|
||||||
|
|
||||||
if lines > u8::MAX as f32 {
|
|
||||||
return u8::MAX;
|
|
||||||
}
|
|
||||||
lines as u8
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +251,7 @@ impl TableView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LineHeight for TableView {
|
impl LineHeight for TableView {
|
||||||
fn num_lines(&self, _cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, _cx: &mut WindowContext) -> usize {
|
||||||
let num_rows = match &self.table.data {
|
let num_rows = match &self.table.data {
|
||||||
// Rows + header
|
// Rows + header
|
||||||
Some(data) => data.len() + 1,
|
Some(data) => data.len() + 1,
|
||||||
@ -267,7 +261,7 @@ impl LineHeight for TableView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let num_lines = num_rows as f32 * (1.0 + TABLE_Y_PADDING_MULTIPLE) + 1.0;
|
let num_lines = num_rows as f32 * (1.0 + TABLE_Y_PADDING_MULTIPLE) + 1.0;
|
||||||
num_lines.ceil() as u8
|
num_lines.ceil() as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,12 +297,9 @@ impl ErrorView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LineHeight for ErrorView {
|
impl LineHeight for ErrorView {
|
||||||
fn num_lines(&self, cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, cx: &mut WindowContext) -> usize {
|
||||||
let mut height: u8 = 1; // Start at 1 to account for the y padding
|
// Start at 1 to account for the y padding
|
||||||
height = height.saturating_add(self.ename.lines().count() as u8);
|
1 + self.ename.lines().count() + self.evalue.lines().count() + self.traceback.num_lines(cx)
|
||||||
height = height.saturating_add(self.evalue.lines().count() as u8);
|
|
||||||
height = height.saturating_add(self.traceback.num_lines(cx));
|
|
||||||
height
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,12 +348,12 @@ impl OutputType {
|
|||||||
|
|
||||||
impl LineHeight for OutputType {
|
impl LineHeight for OutputType {
|
||||||
/// Calculates the expected number of lines
|
/// Calculates the expected number of lines
|
||||||
fn num_lines(&self, cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, cx: &mut WindowContext) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Plain(stdio) => stdio.num_lines(cx),
|
Self::Plain(stdio) => stdio.num_lines(cx),
|
||||||
Self::Stream(stdio) => stdio.num_lines(cx),
|
Self::Stream(stdio) => stdio.num_lines(cx),
|
||||||
Self::Image(image) => image.num_lines(cx),
|
Self::Image(image) => image.num_lines(cx),
|
||||||
Self::Message(message) => message.lines().count() as u8,
|
Self::Message(message) => message.lines().count(),
|
||||||
Self::Table(table) => table.num_lines(cx),
|
Self::Table(table) => table.num_lines(cx),
|
||||||
Self::ErrorOutput(error_view) => error_view.num_lines(cx),
|
Self::ErrorOutput(error_view) => error_view.num_lines(cx),
|
||||||
Self::ClearOutputWaitMarker => 0,
|
Self::ClearOutputWaitMarker => 0,
|
||||||
@ -572,7 +563,7 @@ impl Render for ExecutionView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LineHeight for ExecutionView {
|
impl LineHeight for ExecutionView {
|
||||||
fn num_lines(&self, cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, cx: &mut WindowContext) -> usize {
|
||||||
if self.outputs.is_empty() {
|
if self.outputs.is_empty() {
|
||||||
return 1; // For the status message if outputs are not there
|
return 1; // For the status message if outputs are not there
|
||||||
}
|
}
|
||||||
@ -581,9 +572,7 @@ impl LineHeight for ExecutionView {
|
|||||||
.outputs
|
.outputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|output| output.num_lines(cx))
|
.map(|output| output.num_lines(cx))
|
||||||
.fold(0_u8, |acc, additional_height| {
|
.sum::<usize>()
|
||||||
acc.saturating_add(additional_height)
|
|
||||||
})
|
|
||||||
.max(1);
|
.max(1);
|
||||||
|
|
||||||
let num_lines = match self.status {
|
let num_lines = match self.status {
|
||||||
@ -597,7 +586,7 @@ impl LineHeight for ExecutionView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LineHeight for View<ExecutionView> {
|
impl LineHeight for View<ExecutionView> {
|
||||||
fn num_lines(&self, cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, cx: &mut WindowContext) -> usize {
|
||||||
self.update(cx, |execution_view, cx| execution_view.num_lines(cx))
|
self.update(cx, |execution_view, cx| execution_view.num_lines(cx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,10 @@ pub struct Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct EditorBlock {
|
struct EditorBlock {
|
||||||
editor: WeakView<Editor>,
|
|
||||||
code_range: Range<Anchor>,
|
code_range: Range<Anchor>,
|
||||||
invalidation_anchor: Anchor,
|
invalidation_anchor: Anchor,
|
||||||
block_id: CustomBlockId,
|
block_id: CustomBlockId,
|
||||||
execution_view: View<ExecutionView>,
|
execution_view: View<ExecutionView>,
|
||||||
on_close: CloseBlockFn,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CloseBlockFn =
|
type CloseBlockFn =
|
||||||
@ -84,7 +82,7 @@ impl EditorBlock {
|
|||||||
let invalidation_anchor = buffer.read(cx).read(cx).anchor_before(next_row_start);
|
let invalidation_anchor = buffer.read(cx).read(cx).anchor_before(next_row_start);
|
||||||
let block = BlockProperties {
|
let block = BlockProperties {
|
||||||
position: code_range.end,
|
position: code_range.end,
|
||||||
height: execution_view.num_lines(cx).saturating_add(1),
|
height: (execution_view.num_lines(cx) + 1) as u32,
|
||||||
style: BlockStyle::Sticky,
|
style: BlockStyle::Sticky,
|
||||||
render: Self::create_output_area_renderer(execution_view.clone(), on_close.clone()),
|
render: Self::create_output_area_renderer(execution_view.clone(), on_close.clone()),
|
||||||
disposition: BlockDisposition::Below,
|
disposition: BlockDisposition::Below,
|
||||||
@ -95,12 +93,10 @@ impl EditorBlock {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
anyhow::Ok(Self {
|
anyhow::Ok(Self {
|
||||||
editor,
|
|
||||||
code_range,
|
code_range,
|
||||||
invalidation_anchor,
|
invalidation_anchor,
|
||||||
block_id,
|
block_id,
|
||||||
execution_view,
|
execution_view,
|
||||||
on_close,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,24 +104,6 @@ impl EditorBlock {
|
|||||||
self.execution_view.update(cx, |execution_view, cx| {
|
self.execution_view.update(cx, |execution_view, cx| {
|
||||||
execution_view.push_message(&message.content, cx);
|
execution_view.push_message(&message.content, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.editor
|
|
||||||
.update(cx, |editor, cx| {
|
|
||||||
let mut replacements = HashMap::default();
|
|
||||||
|
|
||||||
replacements.insert(
|
|
||||||
self.block_id,
|
|
||||||
(
|
|
||||||
Some(self.execution_view.num_lines(cx).saturating_add(1)),
|
|
||||||
Self::create_output_area_renderer(
|
|
||||||
self.execution_view.clone(),
|
|
||||||
self.on_close.clone(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
editor.replace_blocks(replacements, None, cx);
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_output_area_renderer(
|
fn create_output_area_renderer(
|
||||||
|
@ -96,8 +96,8 @@ impl TerminalOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LineHeight for TerminalOutput {
|
impl LineHeight for TerminalOutput {
|
||||||
fn num_lines(&self, _cx: &mut WindowContext) -> u8 {
|
fn num_lines(&self, _cx: &mut WindowContext) -> usize {
|
||||||
self.handler.buffer.lines().count().max(1) as u8
|
self.handler.buffer.lines().count().max(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user