This commit is contained in:
Nathan Sobo 2023-11-02 22:56:04 -06:00
parent a731f8fb1e
commit f3b8a9d8c2
26 changed files with 1782 additions and 1665 deletions

2
Cargo.lock generated
View file

@ -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",

View file

@ -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

View file

@ -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,
)
}

View file

@ -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)]

View file

@ -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)]

View file

@ -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 {

View file

@ -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(

View file

@ -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)]

View file

@ -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)]

View file

@ -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,

View file

@ -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);
// }
// }
}

View file

@ -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

View file

@ -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.),
// }
}
}

View file

@ -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,

View file

@ -29,6 +29,7 @@ pub struct ForegroundExecutor {
}
#[must_use]
#[derive(Debug)]
pub enum Task<T> {
Ready(Option<T>),
Spawned(async_task::Task<T>),

View file

@ -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,
)]

View file

@ -411,6 +411,7 @@ impl MacTextSystemState {
descent: typographic_bounds.descent.into(),
runs,
font_size,
len: text.len(),
}
}

View file

@ -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,

View file

@ -151,7 +151,7 @@ impl TextSystem {
pub fn layout_text(
&self,
text: &SharedString,
text: &str,
font_size: Pixels,
runs: &[TextRun],
wrap_width: Option<Pixels>,

View file

@ -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()
}

View file

@ -16,6 +16,7 @@ pub struct LineLayout {
pub ascent: Pixels,
pub descent: Pixels,
pub runs: Vec<ShapedRun>,
pub len: usize,
}
#[derive(Debug)]

View file

@ -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()
}

View file

@ -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

View file

@ -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)),
}

View file

@ -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)
}