mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-29 04:20:46 +00:00
WIP
This commit is contained in:
parent
a731f8fb1e
commit
f3b8a9d8c2
26 changed files with 1782 additions and 1665 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -8884,7 +8884,7 @@ dependencies = [
|
|||
"ctor",
|
||||
"digest 0.9.0",
|
||||
"env_logger 0.9.3",
|
||||
"gpui",
|
||||
"gpui2",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"parking_lot 0.11.2",
|
||||
|
|
|
@ -60,7 +60,7 @@ impl DisplayMap {
|
|||
buffer: Model<MultiBuffer>,
|
||||
font: Font,
|
||||
font_size: Pixels,
|
||||
wrap_width: Option<f32>,
|
||||
wrap_width: Option<Pixels>,
|
||||
buffer_header_height: u8,
|
||||
excerpt_header_height: u8,
|
||||
cx: &mut ModelContext<Self>,
|
||||
|
@ -241,7 +241,7 @@ impl DisplayMap {
|
|||
|
||||
pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut ModelContext<Self>) -> bool {
|
||||
self.wrap_map
|
||||
.update(cx, |map, cx| map.set_font(font_id, font_size, cx))
|
||||
.update(cx, |map, cx| map.set_font(font, font_size, cx))
|
||||
}
|
||||
|
||||
pub fn set_fold_ellipses_color(&mut self, color: Hsla) -> bool {
|
||||
|
@ -621,7 +621,7 @@ impl DisplaySnapshot {
|
|||
pub fn column_for_x(
|
||||
&self,
|
||||
display_row: u32,
|
||||
x_coordinate: f32,
|
||||
x_coordinate: Pixels,
|
||||
text_layout_details: &TextLayoutDetails,
|
||||
) -> u32 {
|
||||
let layout_line = self.lay_out_line_for_row(display_row, text_layout_details);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,10 +5,13 @@ use crate::{
|
|||
display_map::{BlockStyle, DisplaySnapshot},
|
||||
EditorStyle,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use gpui::{
|
||||
px, relative, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun, TextSystem,
|
||||
black, px, relative, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun,
|
||||
TextSystem,
|
||||
};
|
||||
use language::{CursorShape, Selection};
|
||||
use smallvec::SmallVec;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
use sum_tree::Bias;
|
||||
|
||||
|
@ -2700,16 +2703,16 @@ impl PositionMap {
|
|||
let position = position - text_bounds.origin;
|
||||
let y = position.y.max(px(0.)).min(self.size.width);
|
||||
let x = position.x + (scroll_position.x * self.em_width);
|
||||
let row = (y / self.line_height + scroll_position.y).into();
|
||||
let row = (f32::from(y / self.line_height) + scroll_position.y) as u32;
|
||||
let (column, x_overshoot_after_line_end) = if let Some(line) = self
|
||||
.line_layouts
|
||||
.get(row as usize - scroll_position.y.into())
|
||||
.map(|line_with_spaces| &line_with_spaces.line)
|
||||
.map(|LineWithInvisibles { line, .. }| line)
|
||||
{
|
||||
if let Some(ix) = line.index_for_x(x) {
|
||||
(ix as u32, 0.0)
|
||||
(ix as u32, px(0.))
|
||||
} else {
|
||||
(line.len() as u32, px(0.).max(x - line.width()))
|
||||
(line.len as u32, px(0.).max(x - line.width()))
|
||||
}
|
||||
} else {
|
||||
(0, x)
|
||||
|
@ -2719,7 +2722,7 @@ impl PositionMap {
|
|||
let previous_valid = self.snapshot.clip_point(exact_unclipped, Bias::Left);
|
||||
let next_valid = self.snapshot.clip_point(exact_unclipped, Bias::Right);
|
||||
|
||||
let column_overshoot_after_line_end = (x_overshoot_after_line_end / self.em_advance) as u32;
|
||||
let column_overshoot_after_line_end = (x_overshoot_after_line_end / self.em_advance).into();
|
||||
*exact_unclipped.column_mut() += column_overshoot_after_line_end;
|
||||
PointForPosition {
|
||||
previous_valid,
|
||||
|
@ -2740,8 +2743,9 @@ fn layout_line(
|
|||
row: u32,
|
||||
snapshot: &EditorSnapshot,
|
||||
style: &EditorStyle,
|
||||
rem_size: Pixels,
|
||||
text_system: &TextSystem,
|
||||
) -> Line {
|
||||
) -> Result<SmallVec<[Line; 1]>> {
|
||||
let mut line = snapshot.line(row);
|
||||
|
||||
if line.len() > MAX_LINE_LEN {
|
||||
|
@ -2753,15 +2757,16 @@ fn layout_line(
|
|||
line.truncate(len);
|
||||
}
|
||||
|
||||
text_system.layout_str(
|
||||
text_system.layout_text(
|
||||
&line,
|
||||
style.text.font_size,
|
||||
style.text.font_size * rem_size,
|
||||
&[TextRun {
|
||||
len: snapshot.line_len(row) as usize,
|
||||
font: style.text.font.clone(),
|
||||
color: Hsla::black(),
|
||||
font: style.text.font(),
|
||||
color: black(),
|
||||
underline: Default::default(),
|
||||
}],
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,29 +5,30 @@ use crate::{Editor, RangeToAnchorExt};
|
|||
enum MatchingBracketHighlight {}
|
||||
|
||||
pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
|
||||
editor.clear_background_highlights::<MatchingBracketHighlight>(cx);
|
||||
todo!()
|
||||
// // editor.clear_background_highlights::<MatchingBracketHighlight>(cx);
|
||||
|
||||
let newest_selection = editor.selections.newest::<usize>(cx);
|
||||
// Don't highlight brackets if the selection isn't empty
|
||||
if !newest_selection.is_empty() {
|
||||
return;
|
||||
}
|
||||
// let newest_selection = editor.selections.newest::<usize>(cx);
|
||||
// // Don't highlight brackets if the selection isn't empty
|
||||
// if !newest_selection.is_empty() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let head = newest_selection.head();
|
||||
let snapshot = editor.snapshot(cx);
|
||||
if let Some((opening_range, closing_range)) = snapshot
|
||||
.buffer_snapshot
|
||||
.innermost_enclosing_bracket_ranges(head..head)
|
||||
{
|
||||
editor.highlight_background::<MatchingBracketHighlight>(
|
||||
vec![
|
||||
opening_range.to_anchors(&snapshot.buffer_snapshot),
|
||||
closing_range.to_anchors(&snapshot.buffer_snapshot),
|
||||
],
|
||||
|theme| theme.editor.document_highlight_read_background,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
// let head = newest_selection.head();
|
||||
// let snapshot = editor.snapshot(cx);
|
||||
// if let Some((opening_range, closing_range)) = snapshot
|
||||
// .buffer_snapshot
|
||||
// .innermost_enclosing_bracket_ranges(head..head)
|
||||
// {
|
||||
// editor.highlight_background::<MatchingBracketHighlight>(
|
||||
// vec![
|
||||
// opening_range.to_anchors(&snapshot.buffer_snapshot),
|
||||
// closing_range.to_anchors(&snapshot.buffer_snapshot),
|
||||
// ],
|
||||
// |theme| theme.editor.document_highlight_read_background,
|
||||
// cx,
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
use crate::{
|
||||
display_map::{InlayOffset, ToDisplayPoint},
|
||||
display_map::InlayOffset,
|
||||
link_go_to_definition::{InlayHighlight, RangeInEditor},
|
||||
Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSettings, EditorSnapshot, EditorStyle,
|
||||
ExcerptId, RangeToAnchorExt,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use gpui::{
|
||||
AnyElement, AppContext, CursorStyle, Element, Model, MouseButton, Task, ViewContext, WeakView,
|
||||
};
|
||||
use language::{
|
||||
markdown, Bias, DiagnosticEntry, DiagnosticSeverity, Language, LanguageRegistry, ParsedMarkdown,
|
||||
};
|
||||
use gpui::{AnyElement, AppContext, Model, Task, ViewContext, WeakView};
|
||||
use language::{markdown, Bias, DiagnosticEntry, Language, LanguageRegistry, ParsedMarkdown};
|
||||
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart, Project};
|
||||
use settings::Settings;
|
||||
use std::{ops::Range, sync::Arc, time::Duration};
|
||||
use util::TryFutureExt;
|
||||
use workspace::Workspace;
|
||||
|
@ -77,63 +74,64 @@ pub fn find_hovered_hint_part(
|
|||
}
|
||||
|
||||
pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut ViewContext<Editor>) {
|
||||
if EditorSettings::get_global(cx).hover_popover_enabled {
|
||||
if editor.pending_rename.is_some() {
|
||||
return;
|
||||
}
|
||||
todo!()
|
||||
// if EditorSettings::get_global(cx).hover_popover_enabled {
|
||||
// if editor.pending_rename.is_some() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let Some(project) = editor.project.clone() else {
|
||||
return;
|
||||
};
|
||||
// let Some(project) = editor.project.clone() else {
|
||||
// return;
|
||||
// };
|
||||
|
||||
if let Some(InfoPopover { symbol_range, .. }) = &editor.hover_state.info_popover {
|
||||
if let RangeInEditor::Inlay(range) = symbol_range {
|
||||
if range == &inlay_hover.range {
|
||||
// Hover triggered from same location as last time. Don't show again.
|
||||
return;
|
||||
}
|
||||
}
|
||||
hide_hover(editor, cx);
|
||||
}
|
||||
// if let Some(InfoPopover { symbol_range, .. }) = &editor.hover_state.info_popover {
|
||||
// if let RangeInEditor::Inlay(range) = symbol_range {
|
||||
// if range == &inlay_hover.range {
|
||||
// // Hover triggered from same location as last time. Don't show again.
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// hide_hover(editor, cx);
|
||||
// }
|
||||
|
||||
let task = cx.spawn(|this, mut cx| {
|
||||
async move {
|
||||
cx.background()
|
||||
.timer(Duration::from_millis(HOVER_DELAY_MILLIS))
|
||||
.await;
|
||||
this.update(&mut cx, |this, _| {
|
||||
this.hover_state.diagnostic_popover = None;
|
||||
})?;
|
||||
// let task = cx.spawn(|this, mut cx| {
|
||||
// async move {
|
||||
// cx.background_executor()
|
||||
// .timer(Duration::from_millis(HOVER_DELAY_MILLIS))
|
||||
// .await;
|
||||
// this.update(&mut cx, |this, _| {
|
||||
// this.hover_state.diagnostic_popover = None;
|
||||
// })?;
|
||||
|
||||
let language_registry = project.update(&mut cx, |p, _| p.languages().clone());
|
||||
let blocks = vec![inlay_hover.tooltip];
|
||||
let parsed_content = parse_blocks(&blocks, &language_registry, None).await;
|
||||
// let language_registry = project.update(&mut cx, |p, _| p.languages().clone())?;
|
||||
// let blocks = vec![inlay_hover.tooltip];
|
||||
// let parsed_content = parse_blocks(&blocks, &language_registry, None).await;
|
||||
|
||||
let hover_popover = InfoPopover {
|
||||
project: project.clone(),
|
||||
symbol_range: RangeInEditor::Inlay(inlay_hover.range.clone()),
|
||||
blocks,
|
||||
parsed_content,
|
||||
};
|
||||
// let hover_popover = InfoPopover {
|
||||
// project: project.clone(),
|
||||
// symbol_range: RangeInEditor::Inlay(inlay_hover.range.clone()),
|
||||
// blocks,
|
||||
// parsed_content,
|
||||
// };
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
// Highlight the selected symbol using a background highlight
|
||||
this.highlight_inlay_background::<HoverState>(
|
||||
vec![inlay_hover.range],
|
||||
|theme| theme.editor.hover_popover.highlight,
|
||||
cx,
|
||||
);
|
||||
this.hover_state.info_popover = Some(hover_popover);
|
||||
cx.notify();
|
||||
})?;
|
||||
// this.update(&mut cx, |this, cx| {
|
||||
// // Highlight the selected symbol using a background highlight
|
||||
// this.highlight_inlay_background::<HoverState>(
|
||||
// vec![inlay_hover.range],
|
||||
// |theme| theme.editor.hover_popover.highlight,
|
||||
// cx,
|
||||
// );
|
||||
// this.hover_state.info_popover = Some(hover_popover);
|
||||
// cx.notify();
|
||||
// })?;
|
||||
|
||||
anyhow::Ok(())
|
||||
}
|
||||
.log_err()
|
||||
});
|
||||
// anyhow::Ok(())
|
||||
// }
|
||||
// .log_err()
|
||||
// });
|
||||
|
||||
editor.hover_state.info_task = Some(task);
|
||||
}
|
||||
// editor.hover_state.info_task = Some(task);
|
||||
// }
|
||||
}
|
||||
|
||||
/// Hides the type information popup.
|
||||
|
@ -146,7 +144,8 @@ pub fn hide_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) -> bool {
|
|||
editor.hover_state.info_task = None;
|
||||
editor.hover_state.triggered_from = None;
|
||||
|
||||
editor.clear_background_highlights::<HoverState>(cx);
|
||||
// todo!()
|
||||
// editor.clear_background_highlights::<HoverState>(cx);
|
||||
|
||||
if did_hide {
|
||||
cx.notify();
|
||||
|
@ -237,11 +236,11 @@ fn show_hover(
|
|||
let delay = if !ignore_timeout {
|
||||
// Construct delay task to wait for later
|
||||
let total_delay = Some(
|
||||
cx.background()
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(HOVER_DELAY_MILLIS)),
|
||||
);
|
||||
|
||||
cx.background()
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(HOVER_REQUEST_DELAY_MILLIS))
|
||||
.await;
|
||||
total_delay
|
||||
|
@ -250,11 +249,11 @@ fn show_hover(
|
|||
};
|
||||
|
||||
// query the LSP for hover info
|
||||
let hover_request = cx.update(|cx| {
|
||||
let hover_request = cx.update(|_, cx| {
|
||||
project.update(cx, |project, cx| {
|
||||
project.hover(&buffer, buffer_position, cx)
|
||||
})
|
||||
});
|
||||
})?;
|
||||
|
||||
if let Some(delay) = delay {
|
||||
delay.await;
|
||||
|
@ -308,7 +307,8 @@ fn show_hover(
|
|||
anchor..anchor
|
||||
};
|
||||
|
||||
let language_registry = project.update(&mut cx, |p, _| p.languages().clone());
|
||||
let language_registry =
|
||||
project.update(&mut cx, |p, _| p.languages().clone())?;
|
||||
let blocks = hover_result.contents;
|
||||
let language = hover_result.language;
|
||||
let parsed_content = parse_blocks(&blocks, &language_registry, language).await;
|
||||
|
@ -325,22 +325,23 @@ fn show_hover(
|
|||
};
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
if let Some(symbol_range) = hover_popover
|
||||
.as_ref()
|
||||
.and_then(|hover_popover| hover_popover.symbol_range.as_text_range())
|
||||
{
|
||||
// Highlight the selected symbol using a background highlight
|
||||
this.highlight_background::<HoverState>(
|
||||
vec![symbol_range],
|
||||
|theme| theme.editor.hover_popover.highlight,
|
||||
cx,
|
||||
);
|
||||
} else {
|
||||
this.clear_background_highlights::<HoverState>(cx);
|
||||
}
|
||||
|
||||
this.hover_state.info_popover = hover_popover;
|
||||
cx.notify();
|
||||
todo!();
|
||||
// if let Some(symbol_range) = hover_popover
|
||||
// .as_ref()
|
||||
// .and_then(|hover_popover| hover_popover.symbol_range.as_text_range())
|
||||
// {
|
||||
// // Highlight the selected symbol using a background highlight
|
||||
// this.highlight_background::<HoverState>(
|
||||
// vec![symbol_range],
|
||||
// |theme| theme.editor.hover_popover.highlight,
|
||||
// cx,
|
||||
// );
|
||||
// } else {
|
||||
// this.clear_background_highlights::<HoverState>(cx);
|
||||
// }
|
||||
//
|
||||
// this.hover_state.info_popover = hover_popover;
|
||||
// cx.notify();
|
||||
})?;
|
||||
|
||||
Ok::<_, anyhow::Error>(())
|
||||
|
@ -424,38 +425,40 @@ impl HoverState {
|
|||
workspace: Option<WeakView<Workspace>>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<(DisplayPoint, Vec<AnyElement<Editor>>)> {
|
||||
// If there is a diagnostic, position the popovers based on that.
|
||||
// Otherwise use the start of the hover range
|
||||
let anchor = self
|
||||
.diagnostic_popover
|
||||
.as_ref()
|
||||
.map(|diagnostic_popover| &diagnostic_popover.local_diagnostic.range.start)
|
||||
.or_else(|| {
|
||||
self.info_popover
|
||||
.as_ref()
|
||||
.map(|info_popover| match &info_popover.symbol_range {
|
||||
RangeInEditor::Text(range) => &range.start,
|
||||
RangeInEditor::Inlay(range) => &range.inlay_position,
|
||||
})
|
||||
})?;
|
||||
let point = anchor.to_display_point(&snapshot.display_snapshot);
|
||||
|
||||
// Don't render if the relevant point isn't on screen
|
||||
if !self.visible() || !visible_rows.contains(&point.row()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut elements = Vec::new();
|
||||
|
||||
if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
|
||||
elements.push(diagnostic_popover.render(style, cx));
|
||||
}
|
||||
if let Some(info_popover) = self.info_popover.as_mut() {
|
||||
elements.push(info_popover.render(style, workspace, cx));
|
||||
}
|
||||
|
||||
Some((point, elements))
|
||||
todo!("old version below")
|
||||
}
|
||||
// // If there is a diagnostic, position the popovers based on that.
|
||||
// // Otherwise use the start of the hover range
|
||||
// let anchor = self
|
||||
// .diagnostic_popover
|
||||
// .as_ref()
|
||||
// .map(|diagnostic_popover| &diagnostic_popover.local_diagnostic.range.start)
|
||||
// .or_else(|| {
|
||||
// self.info_popover
|
||||
// .as_ref()
|
||||
// .map(|info_popover| match &info_popover.symbol_range {
|
||||
// RangeInEditor::Text(range) => &range.start,
|
||||
// RangeInEditor::Inlay(range) => &range.inlay_position,
|
||||
// })
|
||||
// })?;
|
||||
// let point = anchor.to_display_point(&snapshot.display_snapshot);
|
||||
|
||||
// // Don't render if the relevant point isn't on screen
|
||||
// if !self.visible() || !visible_rows.contains(&point.row()) {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// let mut elements = Vec::new();
|
||||
|
||||
// if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
|
||||
// elements.push(diagnostic_popover.render(style, cx));
|
||||
// }
|
||||
// if let Some(info_popover) = self.info_popover.as_mut() {
|
||||
// elements.push(info_popover.render(style, workspace, cx));
|
||||
// }
|
||||
|
||||
// Some((point, elements))
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -553,17 +553,18 @@ impl InlayHintCache {
|
|||
let mut resolved_hint =
|
||||
resolved_hint_task.await.context("hint resolve task")?;
|
||||
editor.update(&mut cx, |editor, _| {
|
||||
if let Some(excerpt_hints) =
|
||||
editor.inlay_hint_cache.hints.get(&excerpt_id)
|
||||
{
|
||||
let mut guard = excerpt_hints.write();
|
||||
if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
|
||||
if cached_hint.resolve_state == ResolveState::Resolving {
|
||||
resolved_hint.resolve_state = ResolveState::Resolved;
|
||||
*cached_hint = resolved_hint;
|
||||
}
|
||||
}
|
||||
}
|
||||
todo!()
|
||||
// if let Some(excerpt_hints) =
|
||||
// editor.inlay_hint_cache.hints.get(&excerpt_id)
|
||||
// {
|
||||
// let mut guard = excerpt_hints.write();
|
||||
// if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
|
||||
// if cached_hint.resolve_state == ResolveState::Resolving {
|
||||
// resolved_hint.resolve_state = ResolveState::Resolved;
|
||||
// *cached_hint = resolved_hint;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
})?;
|
||||
}
|
||||
|
||||
|
@ -584,89 +585,91 @@ fn spawn_new_update_tasks(
|
|||
update_cache_version: usize,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
|
||||
for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
|
||||
excerpts_to_query
|
||||
{
|
||||
if excerpt_visible_range.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let buffer = excerpt_buffer.read(cx);
|
||||
let buffer_id = buffer.remote_id();
|
||||
let buffer_snapshot = buffer.snapshot();
|
||||
if buffer_snapshot
|
||||
.version()
|
||||
.changed_since(&new_task_buffer_version)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
|
||||
if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
|
||||
let cached_excerpt_hints = cached_excerpt_hints.read();
|
||||
let cached_buffer_version = &cached_excerpt_hints.buffer_version;
|
||||
if cached_excerpt_hints.version > update_cache_version
|
||||
|| cached_buffer_version.changed_since(&new_task_buffer_version)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let (multi_buffer_snapshot, Some(query_ranges)) =
|
||||
editor.buffer.update(cx, |multi_buffer, cx| {
|
||||
(
|
||||
multi_buffer.snapshot(cx),
|
||||
determine_query_ranges(
|
||||
multi_buffer,
|
||||
excerpt_id,
|
||||
&excerpt_buffer,
|
||||
excerpt_visible_range,
|
||||
cx,
|
||||
),
|
||||
)
|
||||
})
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let query = ExcerptQuery {
|
||||
buffer_id,
|
||||
excerpt_id,
|
||||
cache_version: update_cache_version,
|
||||
invalidate,
|
||||
reason,
|
||||
};
|
||||
|
||||
let new_update_task = |query_ranges| {
|
||||
new_update_task(
|
||||
query,
|
||||
query_ranges,
|
||||
multi_buffer_snapshot,
|
||||
buffer_snapshot.clone(),
|
||||
Arc::clone(&visible_hints),
|
||||
cached_excerpt_hints,
|
||||
Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
|
||||
cx,
|
||||
)
|
||||
};
|
||||
|
||||
match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
|
||||
hash_map::Entry::Occupied(mut o) => {
|
||||
o.get_mut().update_cached_tasks(
|
||||
&buffer_snapshot,
|
||||
query_ranges,
|
||||
invalidate,
|
||||
new_update_task,
|
||||
);
|
||||
}
|
||||
hash_map::Entry::Vacant(v) => {
|
||||
v.insert(TasksForRanges::new(
|
||||
query_ranges.clone(),
|
||||
new_update_task(query_ranges),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
todo!("old version below");
|
||||
}
|
||||
// let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
|
||||
// for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
|
||||
// excerpts_to_query
|
||||
// {
|
||||
// if excerpt_visible_range.is_empty() {
|
||||
// continue;
|
||||
// }
|
||||
// let buffer = excerpt_buffer.read(cx);
|
||||
// let buffer_id = buffer.remote_id();
|
||||
// let buffer_snapshot = buffer.snapshot();
|
||||
// if buffer_snapshot
|
||||
// .version()
|
||||
// .changed_since(&new_task_buffer_version)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
|
||||
// if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
|
||||
// let cached_excerpt_hints = cached_excerpt_hints.read();
|
||||
// let cached_buffer_version = &cached_excerpt_hints.buffer_version;
|
||||
// if cached_excerpt_hints.version > update_cache_version
|
||||
// || cached_buffer_version.changed_since(&new_task_buffer_version)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// };
|
||||
|
||||
// let (multi_buffer_snapshot, Some(query_ranges)) =
|
||||
// editor.buffer.update(cx, |multi_buffer, cx| {
|
||||
// (
|
||||
// multi_buffer.snapshot(cx),
|
||||
// determine_query_ranges(
|
||||
// multi_buffer,
|
||||
// excerpt_id,
|
||||
// &excerpt_buffer,
|
||||
// excerpt_visible_range,
|
||||
// cx,
|
||||
// ),
|
||||
// )
|
||||
// })
|
||||
// else {
|
||||
// return;
|
||||
// };
|
||||
// let query = ExcerptQuery {
|
||||
// buffer_id,
|
||||
// excerpt_id,
|
||||
// cache_version: update_cache_version,
|
||||
// invalidate,
|
||||
// reason,
|
||||
// };
|
||||
|
||||
// let new_update_task = |query_ranges| {
|
||||
// new_update_task(
|
||||
// query,
|
||||
// query_ranges,
|
||||
// multi_buffer_snapshot,
|
||||
// buffer_snapshot.clone(),
|
||||
// Arc::clone(&visible_hints),
|
||||
// cached_excerpt_hints,
|
||||
// Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
|
||||
// cx,
|
||||
// )
|
||||
// };
|
||||
|
||||
// match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
|
||||
// hash_map::Entry::Occupied(mut o) => {
|
||||
// o.get_mut().update_cached_tasks(
|
||||
// &buffer_snapshot,
|
||||
// query_ranges,
|
||||
// invalidate,
|
||||
// new_update_task,
|
||||
// );
|
||||
// }
|
||||
// hash_map::Entry::Vacant(v) => {
|
||||
// v.insert(TasksForRanges::new(
|
||||
// query_ranges.clone(),
|
||||
// new_update_task(query_ranges),
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct QueryRanges {
|
||||
|
@ -762,78 +765,79 @@ fn new_update_task(
|
|||
lsp_request_limiter: Arc<Semaphore>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) -> Task<()> {
|
||||
cx.spawn(|editor, mut cx| async move {
|
||||
let closure_cx = cx.clone();
|
||||
let fetch_and_update_hints = |invalidate, range| {
|
||||
fetch_and_update_hints(
|
||||
editor.clone(),
|
||||
multi_buffer_snapshot.clone(),
|
||||
buffer_snapshot.clone(),
|
||||
Arc::clone(&visible_hints),
|
||||
cached_excerpt_hints.as_ref().map(Arc::clone),
|
||||
query,
|
||||
invalidate,
|
||||
range,
|
||||
Arc::clone(&lsp_request_limiter),
|
||||
closure_cx.clone(),
|
||||
)
|
||||
};
|
||||
let visible_range_update_results = future::join_all(query_ranges.visible.into_iter().map(
|
||||
|visible_range| async move {
|
||||
(
|
||||
visible_range.clone(),
|
||||
fetch_and_update_hints(query.invalidate.should_invalidate(), visible_range)
|
||||
.await,
|
||||
)
|
||||
},
|
||||
))
|
||||
.await;
|
||||
todo!()
|
||||
// cx.spawn(|editor, mut cx| async move {
|
||||
// let closure_cx = cx.clone();
|
||||
// let fetch_and_update_hints = |invalidate, range| {
|
||||
// fetch_and_update_hints(
|
||||
// editor.clone(),
|
||||
// multi_buffer_snapshot.clone(),
|
||||
// buffer_snapshot.clone(),
|
||||
// Arc::clone(&visible_hints),
|
||||
// cached_excerpt_hints.as_ref().map(Arc::clone),
|
||||
// query,
|
||||
// invalidate,
|
||||
// range,
|
||||
// Arc::clone(&lsp_request_limiter),
|
||||
// closure_cx.clone(),
|
||||
// )
|
||||
// };
|
||||
// let visible_range_update_results = future::join_all(query_ranges.visible.into_iter().map(
|
||||
// |visible_range| async move {
|
||||
// (
|
||||
// visible_range.clone(),
|
||||
// fetch_and_update_hints(query.invalidate.should_invalidate(), visible_range)
|
||||
// .await,
|
||||
// )
|
||||
// },
|
||||
// ))
|
||||
// .await;
|
||||
|
||||
let hint_delay = cx.background().timer(Duration::from_millis(
|
||||
INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS,
|
||||
));
|
||||
// let hint_delay = cx.background().timer(Duration::from_millis(
|
||||
// INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS,
|
||||
// ));
|
||||
|
||||
let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| {
|
||||
log::error!("inlay hint update task for range {range:?} failed: {e:#}");
|
||||
editor
|
||||
.update(&mut cx, |editor, _| {
|
||||
if let Some(task_ranges) = editor
|
||||
.inlay_hint_cache
|
||||
.update_tasks
|
||||
.get_mut(&query.excerpt_id)
|
||||
{
|
||||
task_ranges.invalidate_range(&buffer_snapshot, &range);
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
};
|
||||
// let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| {
|
||||
// log::error!("inlay hint update task for range {range:?} failed: {e:#}");
|
||||
// editor
|
||||
// .update(&mut cx, |editor, _| {
|
||||
// if let Some(task_ranges) = editor
|
||||
// .inlay_hint_cache
|
||||
// .update_tasks
|
||||
// .get_mut(&query.excerpt_id)
|
||||
// {
|
||||
// task_ranges.invalidate_range(&buffer_snapshot, &range);
|
||||
// }
|
||||
// })
|
||||
// .ok()
|
||||
// };
|
||||
|
||||
for (range, result) in visible_range_update_results {
|
||||
if let Err(e) = result {
|
||||
query_range_failed(&range, e);
|
||||
}
|
||||
}
|
||||
// for (range, result) in visible_range_update_results {
|
||||
// if let Err(e) = result {
|
||||
// query_range_failed(&range, e);
|
||||
// }
|
||||
// }
|
||||
|
||||
hint_delay.await;
|
||||
let invisible_range_update_results = future::join_all(
|
||||
query_ranges
|
||||
.before_visible
|
||||
.into_iter()
|
||||
.chain(query_ranges.after_visible.into_iter())
|
||||
.map(|invisible_range| async move {
|
||||
(
|
||||
invisible_range.clone(),
|
||||
fetch_and_update_hints(false, invisible_range).await,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
for (range, result) in invisible_range_update_results {
|
||||
if let Err(e) = result {
|
||||
query_range_failed(&range, e);
|
||||
}
|
||||
}
|
||||
})
|
||||
// hint_delay.await;
|
||||
// let invisible_range_update_results = future::join_all(
|
||||
// query_ranges
|
||||
// .before_visible
|
||||
// .into_iter()
|
||||
// .chain(query_ranges.after_visible.into_iter())
|
||||
// .map(|invisible_range| async move {
|
||||
// (
|
||||
// invisible_range.clone(),
|
||||
// fetch_and_update_hints(false, invisible_range).await,
|
||||
// )
|
||||
// }),
|
||||
// )
|
||||
// .await;
|
||||
// for (range, result) in invisible_range_update_results {
|
||||
// if let Err(e) = result {
|
||||
// query_range_failed(&range, e);
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
// async fn fetch_and_update_hints(
|
||||
|
@ -1073,126 +1077,128 @@ fn apply_hint_update(
|
|||
multi_buffer_snapshot: MultiBufferSnapshot,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
let cached_excerpt_hints = editor
|
||||
.inlay_hint_cache
|
||||
.hints
|
||||
.entry(new_update.excerpt_id)
|
||||
.or_insert_with(|| {
|
||||
Arc::new(RwLock::new(CachedExcerptHints {
|
||||
version: query.cache_version,
|
||||
buffer_version: buffer_snapshot.version().clone(),
|
||||
buffer_id: query.buffer_id,
|
||||
ordered_hints: Vec::new(),
|
||||
hints_by_id: HashMap::default(),
|
||||
}))
|
||||
});
|
||||
let mut cached_excerpt_hints = cached_excerpt_hints.write();
|
||||
match query.cache_version.cmp(&cached_excerpt_hints.version) {
|
||||
cmp::Ordering::Less => return,
|
||||
cmp::Ordering::Greater | cmp::Ordering::Equal => {
|
||||
cached_excerpt_hints.version = query.cache_version;
|
||||
}
|
||||
}
|
||||
|
||||
let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty();
|
||||
cached_excerpt_hints
|
||||
.ordered_hints
|
||||
.retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
|
||||
cached_excerpt_hints
|
||||
.hints_by_id
|
||||
.retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
|
||||
let mut splice = InlaySplice {
|
||||
to_remove: new_update.remove_from_visible,
|
||||
to_insert: Vec::new(),
|
||||
};
|
||||
for new_hint in new_update.add_to_cache {
|
||||
let insert_position = match cached_excerpt_hints
|
||||
.ordered_hints
|
||||
.binary_search_by(|probe| {
|
||||
cached_excerpt_hints.hints_by_id[probe]
|
||||
.position
|
||||
.cmp(&new_hint.position, &buffer_snapshot)
|
||||
}) {
|
||||
Ok(i) => {
|
||||
let mut insert_position = Some(i);
|
||||
for id in &cached_excerpt_hints.ordered_hints[i..] {
|
||||
let cached_hint = &cached_excerpt_hints.hints_by_id[id];
|
||||
if new_hint
|
||||
.position
|
||||
.cmp(&cached_hint.position, &buffer_snapshot)
|
||||
.is_gt()
|
||||
{
|
||||
break;
|
||||
}
|
||||
if cached_hint.text() == new_hint.text() {
|
||||
insert_position = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
insert_position
|
||||
}
|
||||
Err(i) => Some(i),
|
||||
};
|
||||
|
||||
if let Some(insert_position) = insert_position {
|
||||
let new_inlay_id = post_inc(&mut editor.next_inlay_id);
|
||||
if editor
|
||||
.inlay_hint_cache
|
||||
.allowed_hint_kinds
|
||||
.contains(&new_hint.kind)
|
||||
{
|
||||
let new_hint_position =
|
||||
multi_buffer_snapshot.anchor_in_excerpt(query.excerpt_id, new_hint.position);
|
||||
splice
|
||||
.to_insert
|
||||
.push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint));
|
||||
}
|
||||
let new_id = InlayId::Hint(new_inlay_id);
|
||||
cached_excerpt_hints.hints_by_id.insert(new_id, new_hint);
|
||||
cached_excerpt_hints
|
||||
.ordered_hints
|
||||
.insert(insert_position, new_id);
|
||||
cached_inlays_changed = true;
|
||||
}
|
||||
}
|
||||
cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
|
||||
drop(cached_excerpt_hints);
|
||||
|
||||
if invalidate {
|
||||
let mut outdated_excerpt_caches = HashSet::default();
|
||||
for (excerpt_id, excerpt_hints) in &editor.inlay_hint_cache().hints {
|
||||
let excerpt_hints = excerpt_hints.read();
|
||||
if excerpt_hints.buffer_id == query.buffer_id
|
||||
&& excerpt_id != &query.excerpt_id
|
||||
&& buffer_snapshot
|
||||
.version()
|
||||
.changed_since(&excerpt_hints.buffer_version)
|
||||
{
|
||||
outdated_excerpt_caches.insert(*excerpt_id);
|
||||
splice
|
||||
.to_remove
|
||||
.extend(excerpt_hints.ordered_hints.iter().copied());
|
||||
}
|
||||
}
|
||||
cached_inlays_changed |= !outdated_excerpt_caches.is_empty();
|
||||
editor
|
||||
.inlay_hint_cache
|
||||
.hints
|
||||
.retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
|
||||
}
|
||||
|
||||
let InlaySplice {
|
||||
to_remove,
|
||||
to_insert,
|
||||
} = splice;
|
||||
let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty();
|
||||
if cached_inlays_changed || displayed_inlays_changed {
|
||||
editor.inlay_hint_cache.version += 1;
|
||||
}
|
||||
if displayed_inlays_changed {
|
||||
editor.splice_inlay_hints(to_remove, to_insert, cx)
|
||||
}
|
||||
todo!("old implementation commented below")
|
||||
}
|
||||
// let cached_excerpt_hints = editor
|
||||
// .inlay_hint_cache
|
||||
// .hints
|
||||
// .entry(new_update.excerpt_id)
|
||||
// .or_insert_with(|| {
|
||||
// Arc::new(RwLock::new(CachedExcerptHints {
|
||||
// version: query.cache_version,
|
||||
// buffer_version: buffer_snapshot.version().clone(),
|
||||
// buffer_id: query.buffer_id,
|
||||
// ordered_hints: Vec::new(),
|
||||
// hints_by_id: HashMap::default(),
|
||||
// }))
|
||||
// });
|
||||
// let mut cached_excerpt_hints = cached_excerpt_hints.write();
|
||||
// match query.cache_version.cmp(&cached_excerpt_hints.version) {
|
||||
// cmp::Ordering::Less => return,
|
||||
// cmp::Ordering::Greater | cmp::Ordering::Equal => {
|
||||
// cached_excerpt_hints.version = query.cache_version;
|
||||
// }
|
||||
// }
|
||||
|
||||
// let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty();
|
||||
// cached_excerpt_hints
|
||||
// .ordered_hints
|
||||
// .retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
|
||||
// cached_excerpt_hints
|
||||
// .hints_by_id
|
||||
// .retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
|
||||
// let mut splice = InlaySplice {
|
||||
// to_remove: new_update.remove_from_visible,
|
||||
// to_insert: Vec::new(),
|
||||
// };
|
||||
// for new_hint in new_update.add_to_cache {
|
||||
// let insert_position = match cached_excerpt_hints
|
||||
// .ordered_hints
|
||||
// .binary_search_by(|probe| {
|
||||
// cached_excerpt_hints.hints_by_id[probe]
|
||||
// .position
|
||||
// .cmp(&new_hint.position, &buffer_snapshot)
|
||||
// }) {
|
||||
// Ok(i) => {
|
||||
// let mut insert_position = Some(i);
|
||||
// for id in &cached_excerpt_hints.ordered_hints[i..] {
|
||||
// let cached_hint = &cached_excerpt_hints.hints_by_id[id];
|
||||
// if new_hint
|
||||
// .position
|
||||
// .cmp(&cached_hint.position, &buffer_snapshot)
|
||||
// .is_gt()
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// if cached_hint.text() == new_hint.text() {
|
||||
// insert_position = None;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// insert_position
|
||||
// }
|
||||
// Err(i) => Some(i),
|
||||
// };
|
||||
|
||||
// if let Some(insert_position) = insert_position {
|
||||
// let new_inlay_id = post_inc(&mut editor.next_inlay_id);
|
||||
// if editor
|
||||
// .inlay_hint_cache
|
||||
// .allowed_hint_kinds
|
||||
// .contains(&new_hint.kind)
|
||||
// {
|
||||
// let new_hint_position =
|
||||
// multi_buffer_snapshot.anchor_in_excerpt(query.excerpt_id, new_hint.position);
|
||||
// splice
|
||||
// .to_insert
|
||||
// .push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint));
|
||||
// }
|
||||
// let new_id = InlayId::Hint(new_inlay_id);
|
||||
// cached_excerpt_hints.hints_by_id.insert(new_id, new_hint);
|
||||
// cached_excerpt_hints
|
||||
// .ordered_hints
|
||||
// .insert(insert_position, new_id);
|
||||
// cached_inlays_changed = true;
|
||||
// }
|
||||
// }
|
||||
// cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
|
||||
// drop(cached_excerpt_hints);
|
||||
|
||||
// if invalidate {
|
||||
// let mut outdated_excerpt_caches = HashSet::default();
|
||||
// for (excerpt_id, excerpt_hints) in &editor.inlay_hint_cache().hints {
|
||||
// let excerpt_hints = excerpt_hints.read();
|
||||
// if excerpt_hints.buffer_id == query.buffer_id
|
||||
// && excerpt_id != &query.excerpt_id
|
||||
// && buffer_snapshot
|
||||
// .version()
|
||||
// .changed_since(&excerpt_hints.buffer_version)
|
||||
// {
|
||||
// outdated_excerpt_caches.insert(*excerpt_id);
|
||||
// splice
|
||||
// .to_remove
|
||||
// .extend(excerpt_hints.ordered_hints.iter().copied());
|
||||
// }
|
||||
// }
|
||||
// cached_inlays_changed |= !outdated_excerpt_caches.is_empty();
|
||||
// editor
|
||||
// .inlay_hint_cache
|
||||
// .hints
|
||||
// .retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
|
||||
// }
|
||||
|
||||
// let InlaySplice {
|
||||
// to_remove,
|
||||
// to_insert,
|
||||
// } = splice;
|
||||
// let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty();
|
||||
// if cached_inlays_changed || displayed_inlays_changed {
|
||||
// editor.inlay_hint_cache.version += 1;
|
||||
// }
|
||||
// if displayed_inlays_changed {
|
||||
// editor.splice_inlay_hints(to_remove, to_insert, cx)
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[cfg(test)]
|
||||
// pub mod tests {
|
||||
|
|
|
@ -7,7 +7,7 @@ use anyhow::{Context, Result};
|
|||
use collections::HashSet;
|
||||
use futures::future::try_join_all;
|
||||
use gpui::{
|
||||
point, AnyElement, AppContext, AsyncAppContext, Entity, Model, Pixels, SharedString,
|
||||
point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, Model, Pixels, SharedString,
|
||||
Subscription, Task, View, ViewContext, WeakView,
|
||||
};
|
||||
use language::{
|
||||
|
@ -26,6 +26,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use text::Selection;
|
||||
use theme::ThemeVariant;
|
||||
use util::{paths::PathExt, ResultExt, TryFutureExt};
|
||||
use workspace::item::{BreadcrumbText, FollowableItemHandle};
|
||||
use workspace::{
|
||||
|
@ -306,12 +307,15 @@ impl FollowableItem for Editor {
|
|||
}
|
||||
}
|
||||
|
||||
// async fn update_editor_from_message(
|
||||
// this: WeakView<Editor>,
|
||||
// project: Model<Project>,
|
||||
// message: proto::update_view::Editor,
|
||||
// cx: &mut AsyncAppContext,
|
||||
// ) -> Result<()> {
|
||||
async fn update_editor_from_message(
|
||||
this: WeakView<Editor>,
|
||||
project: Model<Project>,
|
||||
message: proto::update_view::Editor,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
// Previous implementation of the above
|
||||
// // Open all of the buffers of which excerpts were added to the editor.
|
||||
// let inserted_excerpt_buffer_ids = message
|
||||
// .inserted_excerpts
|
||||
|
@ -512,38 +516,39 @@ fn deserialize_anchor(buffer: &MultiBufferSnapshot, anchor: proto::EditorAnchor)
|
|||
|
||||
impl Item for Editor {
|
||||
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
|
||||
if let Ok(data) = data.downcast::<NavigationData>() {
|
||||
let newest_selection = self.selections.newest::<Point>(cx);
|
||||
let buffer = self.buffer.read(cx).read(cx);
|
||||
let offset = if buffer.can_resolve(&data.cursor_anchor) {
|
||||
data.cursor_anchor.to_point(&buffer)
|
||||
} else {
|
||||
buffer.clip_point(data.cursor_position, Bias::Left)
|
||||
};
|
||||
todo!();
|
||||
// if let Ok(data) = data.downcast::<NavigationData>() {
|
||||
// let newest_selection = self.selections.newest::<Point>(cx);
|
||||
// let buffer = self.buffer.read(cx).read(cx);
|
||||
// let offset = if buffer.can_resolve(&data.cursor_anchor) {
|
||||
// data.cursor_anchor.to_point(&buffer)
|
||||
// } else {
|
||||
// buffer.clip_point(data.cursor_position, Bias::Left)
|
||||
// };
|
||||
|
||||
let mut scroll_anchor = data.scroll_anchor;
|
||||
if !buffer.can_resolve(&scroll_anchor.anchor) {
|
||||
scroll_anchor.anchor = buffer.anchor_before(
|
||||
buffer.clip_point(Point::new(data.scroll_top_row, 0), Bias::Left),
|
||||
);
|
||||
}
|
||||
// let mut scroll_anchor = data.scroll_anchor;
|
||||
// if !buffer.can_resolve(&scroll_anchor.anchor) {
|
||||
// scroll_anchor.anchor = buffer.anchor_before(
|
||||
// buffer.clip_point(Point::new(data.scroll_top_row, 0), Bias::Left),
|
||||
// );
|
||||
// }
|
||||
|
||||
drop(buffer);
|
||||
// drop(buffer);
|
||||
|
||||
if newest_selection.head() == offset {
|
||||
false
|
||||
} else {
|
||||
let nav_history = self.nav_history.take();
|
||||
self.set_scroll_anchor(scroll_anchor, cx);
|
||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.select_ranges([offset..offset])
|
||||
});
|
||||
self.nav_history = nav_history;
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
// if newest_selection.head() == offset {
|
||||
// false
|
||||
// } else {
|
||||
// let nav_history = self.nav_history.take();
|
||||
// self.set_scroll_anchor(scroll_anchor, cx);
|
||||
// self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
// s.select_ranges([offset..offset])
|
||||
// });
|
||||
// self.nav_history = nav_history;
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
}
|
||||
|
||||
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString> {
|
||||
|
@ -563,8 +568,8 @@ impl Item for Editor {
|
|||
|
||||
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<SharedString> {
|
||||
match path_for_buffer(&self.buffer, detail, true, cx)? {
|
||||
Cow::Borrowed(path) => Some(path.to_string_lossy),
|
||||
Cow::Owned(path) => Some(path.to_string_lossy.to_string().into()),
|
||||
Cow::Borrowed(path) => Some(path.to_string_lossy().into()),
|
||||
Cow::Owned(path) => Some(path.to_string_lossy().to_string().into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,10 +595,14 @@ impl Item for Editor {
|
|||
// .into_any()
|
||||
}
|
||||
|
||||
fn for_each_project_item(&self, cx: &AppContext, f: &mut dyn FnMut(usize, &dyn project::Item)) {
|
||||
fn for_each_project_item(
|
||||
&self,
|
||||
cx: &AppContext,
|
||||
f: &mut dyn FnMut(EntityId, &dyn project::Item),
|
||||
) {
|
||||
self.buffer
|
||||
.read(cx)
|
||||
.for_each_buffer(|buffer| f(buffer.id(), buffer.read(cx)));
|
||||
.for_each_buffer(|buffer| f(buffer.entity_id(), buffer.read(cx)));
|
||||
}
|
||||
|
||||
fn is_singleton(&self, cx: &AppContext) -> bool {
|
||||
|
@ -652,20 +661,24 @@ impl Item for Editor {
|
|||
|
||||
if buffers.len() == 1 {
|
||||
project
|
||||
.update(&mut cx, |project, cx| project.save_buffers(buffers, cx))
|
||||
.update(&mut cx, |project, cx| project.save_buffers(buffers, cx))?
|
||||
.await?;
|
||||
} else {
|
||||
// For multi-buffers, only save those ones that contain changes. For clean buffers
|
||||
// we simulate saving by calling `Buffer::did_save`, so that language servers or
|
||||
// other downstream listeners of save events get notified.
|
||||
let (dirty_buffers, clean_buffers) = buffers.into_iter().partition(|buffer| {
|
||||
buffer.read_with(&cx, |buffer, _| buffer.is_dirty || buffer.has_conflict())
|
||||
buffer
|
||||
.update(&mut cx, |buffer, _| {
|
||||
buffer.is_dirty() || buffer.has_conflict()
|
||||
})
|
||||
.unwrap_or(false)
|
||||
});
|
||||
|
||||
project
|
||||
.update(&mut cx, |project, cx| {
|
||||
project.save_buffers(dirty_buffers, cx)
|
||||
})
|
||||
})?
|
||||
.await?;
|
||||
for buffer in clean_buffers {
|
||||
buffer.update(&mut cx, |buffer, cx| {
|
||||
|
@ -760,7 +773,7 @@ impl Item for Editor {
|
|||
ToolbarItemLocation::PrimaryLeft { flex: None }
|
||||
}
|
||||
|
||||
fn breadcrumbs(&self, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
|
||||
fn breadcrumbs(&self, variant: &ThemeVariant, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
|
||||
todo!();
|
||||
// let cursor = self.selections.newest_anchor().head();
|
||||
// let multibuffer = &self.buffer().read(cx);
|
||||
|
@ -806,7 +819,7 @@ impl Item for Editor {
|
|||
if let Some(file) = buffer.read(cx).file().and_then(|file| file.as_local()) {
|
||||
let path = file.abs_path(cx);
|
||||
|
||||
cx.background()
|
||||
cx.background_executor()
|
||||
.spawn(async move {
|
||||
DB.save_path(item_id, workspace_id, path.clone())
|
||||
.await
|
||||
|
@ -913,15 +926,17 @@ impl SearchableItem for Editor {
|
|||
}
|
||||
|
||||
fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self.clear_background_highlights::<BufferSearchHighlights>(cx);
|
||||
todo!()
|
||||
// self.clear_background_highlights::<BufferSearchHighlights>(cx);
|
||||
}
|
||||
|
||||
fn update_matches(&mut self, matches: Vec<Range<Anchor>>, cx: &mut ViewContext<Self>) {
|
||||
self.highlight_background::<BufferSearchHighlights>(
|
||||
matches,
|
||||
|theme| theme.search.match_background,
|
||||
cx,
|
||||
);
|
||||
todo!()
|
||||
// self.highlight_background::<BufferSearchHighlights>(
|
||||
// matches,
|
||||
// |theme| theme.search.match_background,
|
||||
// cx,
|
||||
// );
|
||||
}
|
||||
|
||||
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
|
||||
|
@ -952,20 +967,22 @@ impl SearchableItem for Editor {
|
|||
matches: Vec<Range<Anchor>>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.unfold_ranges([matches[index].clone()], false, true, cx);
|
||||
let range = self.range_for_match(&matches[index]);
|
||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.select_ranges([range]);
|
||||
})
|
||||
todo!()
|
||||
// self.unfold_ranges([matches[index].clone()], false, true, cx);
|
||||
// let range = self.range_for_match(&matches[index]);
|
||||
// self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
// s.select_ranges([range]);
|
||||
// })
|
||||
}
|
||||
|
||||
fn select_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||
self.unfold_ranges(matches.clone(), false, false, cx);
|
||||
let mut ranges = Vec::new();
|
||||
for m in &matches {
|
||||
ranges.push(self.range_for_match(&m))
|
||||
}
|
||||
self.change_selections(None, cx, |s| s.select_ranges(ranges));
|
||||
todo!()
|
||||
// self.unfold_ranges(matches.clone(), false, false, cx);
|
||||
// let mut ranges = Vec::new();
|
||||
// for m in &matches {
|
||||
// ranges.push(self.range_for_match(&m))
|
||||
// }
|
||||
// self.change_selections(None, cx, |s| s.select_ranges(ranges));
|
||||
}
|
||||
fn replace(
|
||||
&mut self,
|
||||
|
@ -1044,7 +1061,7 @@ impl SearchableItem for Editor {
|
|||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Vec<Range<Anchor>>> {
|
||||
let buffer = self.buffer().read(cx).snapshot(cx);
|
||||
cx.background().spawn(async move {
|
||||
cx.background_executor().spawn(async move {
|
||||
let mut ranges = Vec::new();
|
||||
if let Some((_, _, excerpt_buffer)) = buffer.as_singleton() {
|
||||
ranges.extend(
|
||||
|
|
|
@ -170,170 +170,173 @@ pub fn update_inlay_link_and_hover_points(
|
|||
shift_held: bool,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||
Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut go_to_definition_updated = false;
|
||||
let mut hover_updated = false;
|
||||
if let Some(hovered_offset) = hovered_offset {
|
||||
let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
let previous_valid_anchor = buffer_snapshot.anchor_at(
|
||||
point_for_position.previous_valid.to_point(snapshot),
|
||||
Bias::Left,
|
||||
);
|
||||
let next_valid_anchor = buffer_snapshot.anchor_at(
|
||||
point_for_position.next_valid.to_point(snapshot),
|
||||
Bias::Right,
|
||||
);
|
||||
if let Some(hovered_hint) = editor
|
||||
.visible_inlay_hints(cx)
|
||||
.into_iter()
|
||||
.skip_while(|hint| {
|
||||
hint.position
|
||||
.cmp(&previous_valid_anchor, &buffer_snapshot)
|
||||
.is_lt()
|
||||
})
|
||||
.take_while(|hint| {
|
||||
hint.position
|
||||
.cmp(&next_valid_anchor, &buffer_snapshot)
|
||||
.is_le()
|
||||
})
|
||||
.max_by_key(|hint| hint.id)
|
||||
{
|
||||
let inlay_hint_cache = editor.inlay_hint_cache();
|
||||
let excerpt_id = previous_valid_anchor.excerpt_id;
|
||||
if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
||||
match cached_hint.resolve_state {
|
||||
ResolveState::CanResolve(_, _) => {
|
||||
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||
inlay_hint_cache.spawn_hint_resolve(
|
||||
buffer_id,
|
||||
excerpt_id,
|
||||
hovered_hint.id,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
ResolveState::Resolved => {
|
||||
let mut extra_shift_left = 0;
|
||||
let mut extra_shift_right = 0;
|
||||
if cached_hint.padding_left {
|
||||
extra_shift_left += 1;
|
||||
extra_shift_right += 1;
|
||||
}
|
||||
if cached_hint.padding_right {
|
||||
extra_shift_right += 1;
|
||||
}
|
||||
match cached_hint.label {
|
||||
project::InlayHintLabel::String(_) => {
|
||||
if let Some(tooltip) = cached_hint.tooltip {
|
||||
hover_popover::hover_at_inlay(
|
||||
editor,
|
||||
InlayHover {
|
||||
excerpt: excerpt_id,
|
||||
tooltip: match tooltip {
|
||||
InlayHintTooltip::String(text) => HoverBlock {
|
||||
text,
|
||||
kind: HoverBlockKind::PlainText,
|
||||
},
|
||||
InlayHintTooltip::MarkupContent(content) => {
|
||||
HoverBlock {
|
||||
text: content.value,
|
||||
kind: content.kind,
|
||||
}
|
||||
}
|
||||
},
|
||||
range: InlayHighlight {
|
||||
inlay: hovered_hint.id,
|
||||
inlay_position: hovered_hint.position,
|
||||
range: extra_shift_left
|
||||
..hovered_hint.text.len() + extra_shift_right,
|
||||
},
|
||||
},
|
||||
cx,
|
||||
);
|
||||
hover_updated = true;
|
||||
}
|
||||
}
|
||||
project::InlayHintLabel::LabelParts(label_parts) => {
|
||||
let hint_start =
|
||||
snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
||||
if let Some((hovered_hint_part, part_range)) =
|
||||
hover_popover::find_hovered_hint_part(
|
||||
label_parts,
|
||||
hint_start,
|
||||
hovered_offset,
|
||||
)
|
||||
{
|
||||
let highlight_start =
|
||||
(part_range.start - hint_start).0 + extra_shift_left;
|
||||
let highlight_end =
|
||||
(part_range.end - hint_start).0 + extra_shift_right;
|
||||
let highlight = InlayHighlight {
|
||||
inlay: hovered_hint.id,
|
||||
inlay_position: hovered_hint.position,
|
||||
range: highlight_start..highlight_end,
|
||||
};
|
||||
if let Some(tooltip) = hovered_hint_part.tooltip {
|
||||
hover_popover::hover_at_inlay(
|
||||
editor,
|
||||
InlayHover {
|
||||
excerpt: excerpt_id,
|
||||
tooltip: match tooltip {
|
||||
InlayHintLabelPartTooltip::String(text) => {
|
||||
HoverBlock {
|
||||
text,
|
||||
kind: HoverBlockKind::PlainText,
|
||||
}
|
||||
}
|
||||
InlayHintLabelPartTooltip::MarkupContent(
|
||||
content,
|
||||
) => HoverBlock {
|
||||
text: content.value,
|
||||
kind: content.kind,
|
||||
},
|
||||
},
|
||||
range: highlight.clone(),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
hover_updated = true;
|
||||
}
|
||||
if let Some((language_server_id, location)) =
|
||||
hovered_hint_part.location
|
||||
{
|
||||
go_to_definition_updated = true;
|
||||
update_go_to_definition_link(
|
||||
editor,
|
||||
Some(GoToDefinitionTrigger::InlayHint(
|
||||
highlight,
|
||||
location,
|
||||
language_server_id,
|
||||
)),
|
||||
cmd_held,
|
||||
shift_held,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
ResolveState::Resolving => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !go_to_definition_updated {
|
||||
update_go_to_definition_link(editor, None, cmd_held, shift_held, cx);
|
||||
}
|
||||
if !hover_updated {
|
||||
hover_popover::hover_at(editor, None, cx);
|
||||
}
|
||||
todo!("old implementation below")
|
||||
}
|
||||
// ) {
|
||||
// let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||
// Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||
// } else {
|
||||
// None
|
||||
// };
|
||||
// let mut go_to_definition_updated = false;
|
||||
// let mut hover_updated = false;
|
||||
// if let Some(hovered_offset) = hovered_offset {
|
||||
// let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
// let previous_valid_anchor = buffer_snapshot.anchor_at(
|
||||
// point_for_position.previous_valid.to_point(snapshot),
|
||||
// Bias::Left,
|
||||
// );
|
||||
// let next_valid_anchor = buffer_snapshot.anchor_at(
|
||||
// point_for_position.next_valid.to_point(snapshot),
|
||||
// Bias::Right,
|
||||
// );
|
||||
// if let Some(hovered_hint) = editor
|
||||
// .visible_inlay_hints(cx)
|
||||
// .into_iter()
|
||||
// .skip_while(|hint| {
|
||||
// hint.position
|
||||
// .cmp(&previous_valid_anchor, &buffer_snapshot)
|
||||
// .is_lt()
|
||||
// })
|
||||
// .take_while(|hint| {
|
||||
// hint.position
|
||||
// .cmp(&next_valid_anchor, &buffer_snapshot)
|
||||
// .is_le()
|
||||
// })
|
||||
// .max_by_key(|hint| hint.id)
|
||||
// {
|
||||
// let inlay_hint_cache = editor.inlay_hint_cache();
|
||||
// let excerpt_id = previous_valid_anchor.excerpt_id;
|
||||
// if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
||||
// match cached_hint.resolve_state {
|
||||
// ResolveState::CanResolve(_, _) => {
|
||||
// if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||
// inlay_hint_cache.spawn_hint_resolve(
|
||||
// buffer_id,
|
||||
// excerpt_id,
|
||||
// hovered_hint.id,
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// ResolveState::Resolved => {
|
||||
// let mut extra_shift_left = 0;
|
||||
// let mut extra_shift_right = 0;
|
||||
// if cached_hint.padding_left {
|
||||
// extra_shift_left += 1;
|
||||
// extra_shift_right += 1;
|
||||
// }
|
||||
// if cached_hint.padding_right {
|
||||
// extra_shift_right += 1;
|
||||
// }
|
||||
// match cached_hint.label {
|
||||
// project::InlayHintLabel::String(_) => {
|
||||
// if let Some(tooltip) = cached_hint.tooltip {
|
||||
// hover_popover::hover_at_inlay(
|
||||
// editor,
|
||||
// InlayHover {
|
||||
// excerpt: excerpt_id,
|
||||
// tooltip: match tooltip {
|
||||
// InlayHintTooltip::String(text) => HoverBlock {
|
||||
// text,
|
||||
// kind: HoverBlockKind::PlainText,
|
||||
// },
|
||||
// InlayHintTooltip::MarkupContent(content) => {
|
||||
// HoverBlock {
|
||||
// text: content.value,
|
||||
// kind: content.kind,
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// range: InlayHighlight {
|
||||
// inlay: hovered_hint.id,
|
||||
// inlay_position: hovered_hint.position,
|
||||
// range: extra_shift_left
|
||||
// ..hovered_hint.text.len() + extra_shift_right,
|
||||
// },
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// hover_updated = true;
|
||||
// }
|
||||
// }
|
||||
// project::InlayHintLabel::LabelParts(label_parts) => {
|
||||
// let hint_start =
|
||||
// snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
||||
// if let Some((hovered_hint_part, part_range)) =
|
||||
// hover_popover::find_hovered_hint_part(
|
||||
// label_parts,
|
||||
// hint_start,
|
||||
// hovered_offset,
|
||||
// )
|
||||
// {
|
||||
// let highlight_start =
|
||||
// (part_range.start - hint_start).0 + extra_shift_left;
|
||||
// let highlight_end =
|
||||
// (part_range.end - hint_start).0 + extra_shift_right;
|
||||
// let highlight = InlayHighlight {
|
||||
// inlay: hovered_hint.id,
|
||||
// inlay_position: hovered_hint.position,
|
||||
// range: highlight_start..highlight_end,
|
||||
// };
|
||||
// if let Some(tooltip) = hovered_hint_part.tooltip {
|
||||
// hover_popover::hover_at_inlay(
|
||||
// editor,
|
||||
// InlayHover {
|
||||
// excerpt: excerpt_id,
|
||||
// tooltip: match tooltip {
|
||||
// InlayHintLabelPartTooltip::String(text) => {
|
||||
// HoverBlock {
|
||||
// text,
|
||||
// kind: HoverBlockKind::PlainText,
|
||||
// }
|
||||
// }
|
||||
// InlayHintLabelPartTooltip::MarkupContent(
|
||||
// content,
|
||||
// ) => HoverBlock {
|
||||
// text: content.value,
|
||||
// kind: content.kind,
|
||||
// },
|
||||
// },
|
||||
// range: highlight.clone(),
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// hover_updated = true;
|
||||
// }
|
||||
// if let Some((language_server_id, location)) =
|
||||
// hovered_hint_part.location
|
||||
// {
|
||||
// go_to_definition_updated = true;
|
||||
// update_go_to_definition_link(
|
||||
// editor,
|
||||
// Some(GoToDefinitionTrigger::InlayHint(
|
||||
// highlight,
|
||||
// location,
|
||||
// language_server_id,
|
||||
// )),
|
||||
// cmd_held,
|
||||
// shift_held,
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// ResolveState::Resolving => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if !go_to_definition_updated {
|
||||
// update_go_to_definition_link(editor, None, cmd_held, shift_held, cx);
|
||||
// }
|
||||
// if !hover_updated {
|
||||
// hover_popover::hover_at(editor, None, cx);
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum LinkDefinitionKind {
|
||||
|
@ -570,34 +573,35 @@ fn go_to_fetched_definition_of_kind(
|
|||
split: bool,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let cached_definitions = editor.link_go_to_definition_state.definitions.clone();
|
||||
hide_link_definition(editor, cx);
|
||||
let cached_definitions_kind = editor.link_go_to_definition_state.kind;
|
||||
todo!();
|
||||
// let cached_definitions = editor.link_go_to_definition_state.definitions.clone();
|
||||
// hide_link_definition(editor, cx);
|
||||
// let cached_definitions_kind = editor.link_go_to_definition_state.kind;
|
||||
|
||||
let is_correct_kind = cached_definitions_kind == Some(kind);
|
||||
if !cached_definitions.is_empty() && is_correct_kind {
|
||||
if !editor.focused {
|
||||
cx.focus_self();
|
||||
}
|
||||
// let is_correct_kind = cached_definitions_kind == Some(kind);
|
||||
// if !cached_definitions.is_empty() && is_correct_kind {
|
||||
// if !editor.focused {
|
||||
// cx.focus_self();
|
||||
// }
|
||||
|
||||
editor.navigate_to_definitions(cached_definitions, split, cx);
|
||||
} else {
|
||||
editor.select(
|
||||
SelectPhase::Begin {
|
||||
position: point.next_valid,
|
||||
add: false,
|
||||
click_count: 1,
|
||||
},
|
||||
cx,
|
||||
);
|
||||
// editor.navigate_to_definitions(cached_definitions, split, cx);
|
||||
// } else {
|
||||
// editor.select(
|
||||
// SelectPhase::Begin {
|
||||
// position: point.next_valid,
|
||||
// add: false,
|
||||
// click_count: 1,
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
|
||||
if point.as_valid().is_some() {
|
||||
match kind {
|
||||
LinkDefinitionKind::Symbol => editor.go_to_definition(&Default::default(), cx),
|
||||
LinkDefinitionKind::Type => editor.go_to_type_definition(&Default::default(), cx),
|
||||
}
|
||||
}
|
||||
}
|
||||
// if point.as_valid().is_some() {
|
||||
// match kind {
|
||||
// LinkDefinitionKind::Symbol => editor.go_to_definition(&Default::default(), cx),
|
||||
// LinkDefinitionKind::Type => editor.go_to_type_definition(&Default::default(), cx),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
|
|
|
@ -8,27 +8,28 @@ pub fn deploy_context_menu(
|
|||
point: DisplayPoint,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
if !editor.focused {
|
||||
cx.focus_self();
|
||||
}
|
||||
todo!();
|
||||
|
||||
// Don't show context menu for inline editors
|
||||
if editor.mode() != EditorMode::Full {
|
||||
return;
|
||||
}
|
||||
// if !editor.focused {
|
||||
// cx.focus_self();
|
||||
// }
|
||||
|
||||
// Don't show the context menu if there isn't a project associated with this editor
|
||||
if editor.project.is_none() {
|
||||
return;
|
||||
}
|
||||
// // Don't show context menu for inline editors
|
||||
// if editor.mode() != EditorMode::Full {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Move the cursor to the clicked location so that dispatched actions make sense
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.clear_disjoint();
|
||||
s.set_pending_display_range(point..point, SelectMode::Character);
|
||||
});
|
||||
// // Don't show the context menu if there isn't a project associated with this editor
|
||||
// if editor.project.is_none() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Move the cursor to the clicked location so that dispatched actions make sense
|
||||
// editor.change_selections(None, cx, |s| {
|
||||
// s.clear_disjoint();
|
||||
// s.set_pending_display_range(point..point, SelectMode::Character);
|
||||
// });
|
||||
|
||||
// todo!()
|
||||
// editor.mouse_context_menu.update(cx, |menu, cx| {
|
||||
// menu.show(
|
||||
// position,
|
||||
|
@ -50,7 +51,7 @@ pub fn deploy_context_menu(
|
|||
// cx,
|
||||
// );
|
||||
// });
|
||||
cx.notify();
|
||||
// cx.notify();
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::path::PathBuf;
|
|||
use db::sqlez_macros::sql;
|
||||
use db::{define_connection, query};
|
||||
|
||||
use gpui::EntityId;
|
||||
use workspace::{ItemId, WorkspaceDb, WorkspaceId};
|
||||
|
||||
define_connection!(
|
||||
|
@ -66,7 +67,7 @@ impl EditorDb {
|
|||
|
||||
query! {
|
||||
pub async fn save_scroll_position(
|
||||
item_id: ItemId,
|
||||
item_id: EntityId,
|
||||
workspace_id: WorkspaceId,
|
||||
top_row: u32,
|
||||
vertical_offset: f32,
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
Anchor, DisplayPoint, Editor, EditorMode, Event, InlayHintRefreshReason, MultiBufferSnapshot,
|
||||
ToPoint,
|
||||
};
|
||||
use gpui::{point, px, AppContext, Pixels, Styled, Task, ViewContext};
|
||||
use gpui::{point, px, AppContext, Entity, Pixels, Styled, Task, ViewContext};
|
||||
use language::{Bias, Point};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
|
@ -39,18 +39,18 @@ pub struct ScrollAnchor {
|
|||
impl ScrollAnchor {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
offset: gpui::Point::zero(),
|
||||
offset: gpui::Point::default(),
|
||||
anchor: Anchor::min(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<Pixels> {
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<f32> {
|
||||
let mut scroll_position = self.offset;
|
||||
if self.anchor != Anchor::min() {
|
||||
let scroll_top = self.anchor.to_display_point(snapshot).row() as f32;
|
||||
scroll_position.set_y(scroll_top + scroll_position.y);
|
||||
scroll_position.y = scroll_top + scroll_position.y;
|
||||
} else {
|
||||
scroll_position.set_y(0.);
|
||||
scroll_position.y = 0.;
|
||||
}
|
||||
scroll_position
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ pub struct ScrollManager {
|
|||
anchor: ScrollAnchor,
|
||||
ongoing: OngoingScroll,
|
||||
autoscroll_request: Option<(Autoscroll, bool)>,
|
||||
last_autoscroll: Option<(gpui::Point<Pixels>, f32, f32, AutoscrollStrategy)>,
|
||||
last_autoscroll: Option<(gpui::Point<f32>, f32, f32, AutoscrollStrategy)>,
|
||||
show_scrollbars: bool,
|
||||
hide_scrollbar_task: Option<Task<()>>,
|
||||
visible_line_count: Option<f32>,
|
||||
|
@ -171,7 +171,7 @@ impl ScrollManager {
|
|||
self.ongoing.axis = axis;
|
||||
}
|
||||
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<Pixels> {
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<f32> {
|
||||
self.anchor.scroll_position(snapshot)
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ impl ScrollManager {
|
|||
(
|
||||
ScrollAnchor {
|
||||
anchor: Anchor::min(),
|
||||
offset: scroll_position.max(Point::zero()),
|
||||
offset: scroll_position.max(&gpui::Point::default()),
|
||||
},
|
||||
0,
|
||||
)
|
||||
|
@ -228,9 +228,9 @@ impl ScrollManager {
|
|||
self.show_scrollbar(cx);
|
||||
self.autoscroll_request.take();
|
||||
if let Some(workspace_id) = workspace_id {
|
||||
let item_id = cx.view_id();
|
||||
let item_id = cx.view().entity_id();
|
||||
|
||||
cx.background()
|
||||
cx.foreground_executor()
|
||||
.spawn(async move {
|
||||
DB.save_scroll_position(
|
||||
item_id,
|
||||
|
@ -255,7 +255,9 @@ impl ScrollManager {
|
|||
|
||||
if cx.default_global::<ScrollbarAutoHide>().0 {
|
||||
self.hide_scrollbar_task = Some(cx.spawn(|editor, mut cx| async move {
|
||||
cx.background().timer(SCROLLBAR_SHOW_INTERVAL).await;
|
||||
cx.background_executor()
|
||||
.timer(SCROLLBAR_SHOW_INTERVAL)
|
||||
.await;
|
||||
editor
|
||||
.update(&mut cx, |editor, cx| {
|
||||
editor.scroll_manager.show_scrollbars = false;
|
||||
|
@ -287,160 +289,161 @@ impl ScrollManager {
|
|||
}
|
||||
|
||||
// todo!()
|
||||
// impl Editor {
|
||||
// pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||
// self.scroll_manager.vertical_scroll_margin as usize
|
||||
// }
|
||||
impl Editor {
|
||||
// pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||
// self.scroll_manager.vertical_scroll_margin as usize
|
||||
// }
|
||||
|
||||
// pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||
// self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||
// cx.notify();
|
||||
// }
|
||||
// pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||
// self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||
// cx.notify();
|
||||
// }
|
||||
|
||||
// pub fn visible_line_count(&self) -> Option<f32> {
|
||||
// self.scroll_manager.visible_line_count
|
||||
// }
|
||||
// pub fn visible_line_count(&self) -> Option<f32> {
|
||||
// self.scroll_manager.visible_line_count
|
||||
// }
|
||||
|
||||
// pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
|
||||
// let opened_first_time = self.scroll_manager.visible_line_count.is_none();
|
||||
// self.scroll_manager.visible_line_count = Some(lines);
|
||||
// if opened_first_time {
|
||||
// cx.spawn(|editor, mut cx| async move {
|
||||
// editor
|
||||
// .update(&mut cx, |editor, cx| {
|
||||
// editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
|
||||
// })
|
||||
// .ok()
|
||||
// })
|
||||
// .detach()
|
||||
// }
|
||||
// }
|
||||
// pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
|
||||
// let opened_first_time = self.scroll_manager.visible_line_count.is_none();
|
||||
// self.scroll_manager.visible_line_count = Some(lines);
|
||||
// if opened_first_time {
|
||||
// cx.spawn(|editor, mut cx| async move {
|
||||
// editor
|
||||
// .update(&mut cx, |editor, cx| {
|
||||
// editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
|
||||
// })
|
||||
// .ok()
|
||||
// })
|
||||
// .detach()
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn set_scroll_position(
|
||||
// &mut self,
|
||||
// scroll_position: gpui::Point<Pixels>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// self.set_scroll_position_internal(scroll_position, true, false, cx);
|
||||
// }
|
||||
pub fn set_scroll_position(
|
||||
&mut self,
|
||||
scroll_position: gpui::Point<f32>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.set_scroll_position_internal(scroll_position, true, false, cx);
|
||||
}
|
||||
|
||||
// pub(crate) fn set_scroll_position_internal(
|
||||
// &mut self,
|
||||
// scroll_position: gpui::Point<Pixels>,
|
||||
// local: bool,
|
||||
// autoscroll: bool,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
pub(crate) fn set_scroll_position_internal(
|
||||
&mut self,
|
||||
scroll_position: gpui::Point<f32>,
|
||||
local: bool,
|
||||
autoscroll: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// self.scroll_manager.set_scroll_position(
|
||||
// scroll_position,
|
||||
// &map,
|
||||
// local,
|
||||
// autoscroll,
|
||||
// workspace_id,
|
||||
// cx,
|
||||
// );
|
||||
hide_hover(self, cx);
|
||||
let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
self.scroll_manager.set_scroll_position(
|
||||
scroll_position,
|
||||
&map,
|
||||
local,
|
||||
autoscroll,
|
||||
workspace_id,
|
||||
cx,
|
||||
);
|
||||
|
||||
// self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
// }
|
||||
// todo!()
|
||||
// self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
}
|
||||
|
||||
// pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
|
||||
// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// self.scroll_manager.anchor.scroll_position(&display_map)
|
||||
// }
|
||||
// pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
|
||||
// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// self.scroll_manager.anchor.scroll_position(&display_map)
|
||||
// }
|
||||
|
||||
// pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// let top_row = scroll_anchor
|
||||
// .anchor
|
||||
// .to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
// .row;
|
||||
// self.scroll_manager
|
||||
// .set_anchor(scroll_anchor, top_row, true, false, workspace_id, cx);
|
||||
// }
|
||||
// pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// let top_row = scroll_anchor
|
||||
// .anchor
|
||||
// .to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
// .row;
|
||||
// self.scroll_manager
|
||||
// .set_anchor(scroll_anchor, top_row, true, false, workspace_id, cx);
|
||||
// }
|
||||
|
||||
// pub(crate) fn set_scroll_anchor_remote(
|
||||
// &mut self,
|
||||
// scroll_anchor: ScrollAnchor,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// let top_row = scroll_anchor
|
||||
// .anchor
|
||||
// .to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
// .row;
|
||||
// self.scroll_manager
|
||||
// .set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
||||
// }
|
||||
// pub(crate) fn set_scroll_anchor_remote(
|
||||
// &mut self,
|
||||
// scroll_anchor: ScrollAnchor,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// let top_row = scroll_anchor
|
||||
// .anchor
|
||||
// .to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
// .row;
|
||||
// self.scroll_manager
|
||||
// .set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
||||
// }
|
||||
|
||||
// pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
||||
// cx.propagate_action();
|
||||
// return;
|
||||
// }
|
||||
// pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
||||
// cx.propagate_action();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if self.take_rename(true, cx).is_some() {
|
||||
// return;
|
||||
// }
|
||||
// if self.take_rename(true, cx).is_some() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let cur_position = self.scroll_position(cx);
|
||||
// let new_pos = cur_position + point(0., amount.lines(self));
|
||||
// self.set_scroll_position(new_pos, cx);
|
||||
// }
|
||||
// let cur_position = self.scroll_position(cx);
|
||||
// let new_pos = cur_position + point(0., amount.lines(self));
|
||||
// self.set_scroll_position(new_pos, cx);
|
||||
// }
|
||||
|
||||
// /// Returns an ordering. The newest selection is:
|
||||
// /// Ordering::Equal => on screen
|
||||
// /// Ordering::Less => above the screen
|
||||
// /// Ordering::Greater => below the screen
|
||||
// pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||
// let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// let newest_head = self
|
||||
// .selections
|
||||
// .newest_anchor()
|
||||
// .head()
|
||||
// .to_display_point(&snapshot);
|
||||
// let screen_top = self
|
||||
// .scroll_manager
|
||||
// .anchor
|
||||
// .anchor
|
||||
// .to_display_point(&snapshot);
|
||||
// /// Returns an ordering. The newest selection is:
|
||||
// /// Ordering::Equal => on screen
|
||||
// /// Ordering::Less => above the screen
|
||||
// /// Ordering::Greater => below the screen
|
||||
// pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||
// let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// let newest_head = self
|
||||
// .selections
|
||||
// .newest_anchor()
|
||||
// .head()
|
||||
// .to_display_point(&snapshot);
|
||||
// let screen_top = self
|
||||
// .scroll_manager
|
||||
// .anchor
|
||||
// .anchor
|
||||
// .to_display_point(&snapshot);
|
||||
|
||||
// if screen_top > newest_head {
|
||||
// return Ordering::Less;
|
||||
// }
|
||||
// if screen_top > newest_head {
|
||||
// return Ordering::Less;
|
||||
// }
|
||||
|
||||
// if let Some(visible_lines) = self.visible_line_count() {
|
||||
// if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||
// return Ordering::Equal;
|
||||
// }
|
||||
// }
|
||||
// if let Some(visible_lines) = self.visible_line_count() {
|
||||
// if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||
// return Ordering::Equal;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ordering::Greater
|
||||
// }
|
||||
// Ordering::Greater
|
||||
// }
|
||||
|
||||
// pub fn read_scroll_position_from_db(
|
||||
// &mut self,
|
||||
// item_id: usize,
|
||||
// workspace_id: WorkspaceId,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) {
|
||||
// let scroll_position = DB.get_scroll_position(item_id, workspace_id);
|
||||
// if let Ok(Some((top_row, x, y))) = scroll_position {
|
||||
// let top_anchor = self
|
||||
// .buffer()
|
||||
// .read(cx)
|
||||
// .snapshot(cx)
|
||||
// .anchor_at(Point::new(top_row as u32, 0), Bias::Left);
|
||||
// let scroll_anchor = ScrollAnchor {
|
||||
// offset: Point::new(x, y),
|
||||
// anchor: top_anchor,
|
||||
// };
|
||||
// self.set_scroll_anchor(scroll_anchor, cx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// pub fn read_scroll_position_from_db(
|
||||
// &mut self,
|
||||
// item_id: usize,
|
||||
// workspace_id: WorkspaceId,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) {
|
||||
// let scroll_position = DB.get_scroll_position(item_id, workspace_id);
|
||||
// if let Ok(Some((top_row, x, y))) = scroll_position {
|
||||
// let top_anchor = self
|
||||
// .buffer()
|
||||
// .read(cx)
|
||||
// .snapshot(cx)
|
||||
// .anchor_at(Point::new(top_row as u32, 0), Bias::Left);
|
||||
// let scroll_anchor = ScrollAnchor {
|
||||
// offset: Point::new(x, y),
|
||||
// anchor: top_anchor,
|
||||
// };
|
||||
// self.set_scroll_anchor(scroll_anchor, cx);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp;
|
||||
use std::{cmp, f32};
|
||||
|
||||
use gpui::ViewContext;
|
||||
use gpui::{px, Pixels, ViewContext};
|
||||
use language::Point;
|
||||
|
||||
use crate::{display_map::ToDisplayPoint, Editor, EditorMode, LineWithInvisibles};
|
||||
|
@ -61,7 +61,7 @@ impl Editor {
|
|||
display_map.max_point().row() as f32
|
||||
};
|
||||
if scroll_position.y > max_scroll_top {
|
||||
scroll_position.set_y(max_scroll_top);
|
||||
scroll_position.y = (max_scroll_top);
|
||||
self.set_scroll_position(scroll_position, cx);
|
||||
}
|
||||
|
||||
|
@ -143,24 +143,24 @@ impl Editor {
|
|||
let needs_scroll_down = target_bottom >= end_row;
|
||||
|
||||
if needs_scroll_up && !needs_scroll_down {
|
||||
scroll_position.set_y(target_top);
|
||||
scroll_position.y = (target_top);
|
||||
self.set_scroll_position_internal(scroll_position, local, true, cx);
|
||||
}
|
||||
if !needs_scroll_up && needs_scroll_down {
|
||||
scroll_position.set_y(target_bottom - visible_lines);
|
||||
scroll_position.y = (target_bottom - visible_lines);
|
||||
self.set_scroll_position_internal(scroll_position, local, true, cx);
|
||||
}
|
||||
}
|
||||
AutoscrollStrategy::Center => {
|
||||
scroll_position.set_y((target_top - margin).max(0.0));
|
||||
scroll_position.y = ((target_top - margin).max(0.0));
|
||||
self.set_scroll_position_internal(scroll_position, local, true, cx);
|
||||
}
|
||||
AutoscrollStrategy::Top => {
|
||||
scroll_position.set_y((target_top).max(0.0));
|
||||
scroll_position.y = ((target_top).max(0.0));
|
||||
self.set_scroll_position_internal(scroll_position, local, true, cx);
|
||||
}
|
||||
AutoscrollStrategy::Bottom => {
|
||||
scroll_position.set_y((target_bottom - visible_lines).max(0.0));
|
||||
scroll_position.y = ((target_bottom - visible_lines).max(0.0));
|
||||
self.set_scroll_position_internal(scroll_position, local, true, cx);
|
||||
}
|
||||
}
|
||||
|
@ -178,9 +178,9 @@ impl Editor {
|
|||
pub fn autoscroll_horizontally(
|
||||
&mut self,
|
||||
start_row: u32,
|
||||
viewport_width: f32,
|
||||
scroll_width: f32,
|
||||
max_glyph_width: f32,
|
||||
viewport_width: Pixels,
|
||||
scroll_width: Pixels,
|
||||
max_glyph_width: Pixels,
|
||||
layouts: &[LineWithInvisibles],
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> bool {
|
||||
|
@ -191,11 +191,11 @@ impl Editor {
|
|||
let mut target_right;
|
||||
|
||||
if self.highlighted_rows.is_some() {
|
||||
target_left = 0.0_f32;
|
||||
target_right = 0.0_f32;
|
||||
target_left = px(0.);
|
||||
target_right = px(0.);
|
||||
} else {
|
||||
target_left = std::f32::INFINITY;
|
||||
target_right = 0.0_f32;
|
||||
target_left = px(f32::INFINITY);
|
||||
target_right = px(0.);
|
||||
for selection in selections {
|
||||
let head = selection.head().to_display_point(&display_map);
|
||||
if head.row() >= start_row && head.row() < start_row + layouts.len() as u32 {
|
||||
|
@ -226,11 +226,11 @@ impl Editor {
|
|||
let scroll_right = scroll_left + viewport_width;
|
||||
|
||||
if target_left < scroll_left {
|
||||
self.scroll_manager.anchor.offset.x = (target_left / max_glyph_width);
|
||||
self.scroll_manager.anchor.offset.x = (target_left / max_glyph_width).into();
|
||||
true
|
||||
} else if target_right > scroll_right {
|
||||
self.scroll_manager.anchor.offset.x =
|
||||
((target_right - viewport_width) / max_glyph_width);
|
||||
((target_right - viewport_width) / max_glyph_width).into();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
|
@ -11,18 +11,19 @@ pub enum ScrollAmount {
|
|||
|
||||
impl ScrollAmount {
|
||||
pub fn lines(&self, editor: &mut Editor) -> f32 {
|
||||
match self {
|
||||
Self::Line(count) => *count,
|
||||
Self::Page(count) => editor
|
||||
.visible_line_count()
|
||||
.map(|mut l| {
|
||||
// for full pages subtract one to leave an anchor line
|
||||
if count.abs() == 1.0 {
|
||||
l -= 1.0
|
||||
}
|
||||
(l * count).trunc()
|
||||
})
|
||||
.unwrap_or(0.),
|
||||
}
|
||||
todo!()
|
||||
// match self {
|
||||
// Self::Line(count) => *count,
|
||||
// Self::Page(count) => editor
|
||||
// .visible_line_count()
|
||||
// .map(|mut l| {
|
||||
// // for full pages subtract one to leave an anchor line
|
||||
// if count.abs() == 1.0 {
|
||||
// l -= 1.0
|
||||
// }
|
||||
// (l * count).trunc()
|
||||
// })
|
||||
// .unwrap_or(0.),
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use collections::HashMap;
|
||||
use gpui::{AppContext, Model};
|
||||
use gpui::{AppContext, Model, Pixels};
|
||||
use itertools::Itertools;
|
||||
use language::{Bias, Point, Selection, SelectionGoal, TextDimension, ToPoint};
|
||||
use util::post_inc;
|
||||
|
@ -302,39 +302,39 @@ impl SelectionsCollection {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn build_columnar_selection(
|
||||
&mut self,
|
||||
display_map: &DisplaySnapshot,
|
||||
row: u32,
|
||||
positions: &Range<f32>,
|
||||
reversed: bool,
|
||||
text_layout_details: &TextLayoutDetails,
|
||||
) -> Option<Selection<Point>> {
|
||||
let is_empty = positions.start == positions.end;
|
||||
let line_len = display_map.line_len(row);
|
||||
// pub fn build_columnar_selection(
|
||||
// &mut self,
|
||||
// display_map: &DisplaySnapshot,
|
||||
// row: u32,
|
||||
// positions: &Range<Pixels>,
|
||||
// reversed: bool,
|
||||
// text_layout_details: &TextLayoutDetails,
|
||||
// ) -> Option<Selection<Point>> {
|
||||
// let is_empty = positions.start == positions.end;
|
||||
// let line_len = display_map.line_len(row);
|
||||
|
||||
let layed_out_line = display_map.lay_out_line_for_row(row, &text_layout_details);
|
||||
// let layed_out_line = display_map.lay_out_line_for_row(row, &text_layout_details);
|
||||
|
||||
let start_col = layed_out_line.closest_index_for_x(positions.start) as u32;
|
||||
if start_col < line_len || (is_empty && positions.start == layed_out_line.width()) {
|
||||
let start = DisplayPoint::new(row, start_col);
|
||||
let end_col = layed_out_line.closest_index_for_x(positions.end) as u32;
|
||||
let end = DisplayPoint::new(row, end_col);
|
||||
// let start_col = layed_out_line.closest_index_for_x(positions.start) as u32;
|
||||
// if start_col < line_len || (is_empty && positions.start == layed_out_line.width()) {
|
||||
// let start = DisplayPoint::new(row, start_col);
|
||||
// let end_col = layed_out_line.closest_index_for_x(positions.end) as u32;
|
||||
// let end = DisplayPoint::new(row, end_col);
|
||||
|
||||
Some(Selection {
|
||||
id: post_inc(&mut self.next_selection_id),
|
||||
start: start.to_point(display_map),
|
||||
end: end.to_point(display_map),
|
||||
reversed,
|
||||
goal: SelectionGoal::HorizontalRange {
|
||||
start: positions.start,
|
||||
end: positions.end,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
// Some(Selection {
|
||||
// id: post_inc(&mut self.next_selection_id),
|
||||
// start: start.to_point(display_map),
|
||||
// end: end.to_point(display_map),
|
||||
// reversed,
|
||||
// goal: SelectionGoal::HorizontalRange {
|
||||
// start: positions.start,
|
||||
// end: positions.end,
|
||||
// },
|
||||
// })
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
|
||||
pub(crate) fn change_with<R>(
|
||||
&mut self,
|
||||
|
|
|
@ -29,6 +29,7 @@ pub struct ForegroundExecutor {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
#[derive(Debug)]
|
||||
pub enum Task<T> {
|
||||
Ready(Option<T>),
|
||||
Spawned(async_task::Task<T>),
|
||||
|
|
|
@ -819,6 +819,18 @@ impl From<Pixels> for f64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Pixels> for u32 {
|
||||
fn from(pixels: Pixels) -> Self {
|
||||
pixels.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Pixels> for usize {
|
||||
fn from(pixels: Pixels) -> Self {
|
||||
pixels.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Add, AddAssign, Clone, Copy, Default, Div, Eq, Hash, Ord, PartialEq, PartialOrd, Sub, SubAssign,
|
||||
)]
|
||||
|
|
|
@ -411,6 +411,7 @@ impl MacTextSystemState {
|
|||
descent: typographic_bounds.descent.into(),
|
||||
runs,
|
||||
font_size,
|
||||
len: text.len(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -167,6 +167,15 @@ impl TextStyle {
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn font(&self) -> Font {
|
||||
Font {
|
||||
family: self.font_family.clone(),
|
||||
features: self.font_features.clone(),
|
||||
weight: self.font_weight,
|
||||
style: self.font_style,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_run(&self, len: usize) -> TextRun {
|
||||
TextRun {
|
||||
len,
|
||||
|
|
|
@ -151,7 +151,7 @@ impl TextSystem {
|
|||
|
||||
pub fn layout_text(
|
||||
&self,
|
||||
text: &SharedString,
|
||||
text: &str,
|
||||
font_size: Pixels,
|
||||
runs: &[TextRun],
|
||||
wrap_width: Option<Pixels>,
|
||||
|
|
|
@ -29,6 +29,10 @@ impl Line {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn width(&self) -> Pixels {
|
||||
self.layout.width
|
||||
}
|
||||
|
||||
pub fn wrap_count(&self) -> usize {
|
||||
self.layout.wrap_boundaries.len()
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ pub struct LineLayout {
|
|||
pub ascent: Pixels,
|
||||
pub descent: Pixels,
|
||||
pub runs: Vec<ShapedRun>,
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1655,6 +1655,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
|||
}
|
||||
}
|
||||
|
||||
// todo!("change this to return a reference");
|
||||
pub fn view(&self) -> View<V> {
|
||||
self.view.clone()
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ regex.workspace = true
|
|||
|
||||
[dev-dependencies]
|
||||
collections = { path = "../collections", features = ["test-support"] }
|
||||
gpui = { path = "../gpui", features = ["test-support"] }
|
||||
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
|
||||
util = { path = "../util", features = ["test-support"] }
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use gpui::Pixels;
|
||||
|
||||
use crate::{Anchor, BufferSnapshot, TextDimension};
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Range;
|
||||
|
@ -5,8 +7,8 @@ use std::ops::Range;
|
|||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum SelectionGoal {
|
||||
None,
|
||||
HorizontalPosition(f32),
|
||||
HorizontalRange { start: f32, end: f32 },
|
||||
HorizontalPosition(Pixels),
|
||||
HorizontalRange { start: Pixels, end: Pixels },
|
||||
WrappedHorizontalPosition((u32, f32)),
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,11 @@ pub trait Item: Render + EventEmitter {
|
|||
}
|
||||
fn tab_content<V: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<V>;
|
||||
|
||||
fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project2::Item)) {
|
||||
fn for_each_project_item(
|
||||
&self,
|
||||
_: &AppContext,
|
||||
_: &mut dyn FnMut(EntityId, &dyn project2::Item),
|
||||
) {
|
||||
} // (model id, Item)
|
||||
fn is_singleton(&self, _cx: &AppContext) -> bool {
|
||||
false
|
||||
|
@ -219,8 +223,12 @@ pub trait ItemHandle: 'static + Send {
|
|||
fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace>;
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
|
||||
fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>;
|
||||
fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]>;
|
||||
fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project2::Item));
|
||||
fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[EntityId; 3]>;
|
||||
fn for_each_project_item(
|
||||
&self,
|
||||
_: &AppContext,
|
||||
_: &mut dyn FnMut(EntityId, &dyn project2::Item),
|
||||
);
|
||||
fn is_singleton(&self, cx: &AppContext) -> bool;
|
||||
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
|
||||
fn clone_on_split(
|
||||
|
@ -331,7 +339,7 @@ impl<T: Item> ItemHandle for View<T> {
|
|||
result
|
||||
}
|
||||
|
||||
fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]> {
|
||||
fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[EntityId; 3]> {
|
||||
let mut result = SmallVec::new();
|
||||
self.read(cx).for_each_project_item(cx, &mut |id, _| {
|
||||
result.push(id);
|
||||
|
@ -342,7 +350,7 @@ impl<T: Item> ItemHandle for View<T> {
|
|||
fn for_each_project_item(
|
||||
&self,
|
||||
cx: &AppContext,
|
||||
f: &mut dyn FnMut(usize, &dyn project2::Item),
|
||||
f: &mut dyn FnMut(EntityId, &dyn project2::Item),
|
||||
) {
|
||||
self.read(cx).for_each_project_item(cx, f)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue