From f3b8a9d8c286f01a5fadf97919677bcafe67ec6f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 2 Nov 2023 22:56:04 -0600 Subject: [PATCH] WIP --- Cargo.lock | 2 +- crates/editor2/src/display_map.rs | 6 +- crates/editor2/src/editor.rs | 1536 +++++++++-------- crates/editor2/src/element.rs | 27 +- .../editor2/src/highlight_matching_bracket.rs | 43 +- crates/editor2/src/hover_popover.rs | 221 +-- crates/editor2/src/inlay_hint_cache.rs | 566 +++--- crates/editor2/src/items.rs | 143 +- crates/editor2/src/link_go_to_definition.rs | 380 ++-- crates/editor2/src/mouse_context_menu.rs | 37 +- crates/editor2/src/persistence.rs | 3 +- crates/editor2/src/scroll.rs | 303 ++-- crates/editor2/src/scroll/autoscroll.rs | 34 +- crates/editor2/src/scroll/scroll_amount.rs | 27 +- crates/editor2/src/selections_collection.rs | 62 +- crates/gpui2/src/executor.rs | 1 + crates/gpui2/src/geometry.rs | 12 + crates/gpui2/src/platform/mac/text_system.rs | 1 + crates/gpui2/src/style.rs | 9 + crates/gpui2/src/text_system.rs | 2 +- crates/gpui2/src/text_system/line.rs | 4 + crates/gpui2/src/text_system/line_layout.rs | 1 + crates/gpui2/src/window.rs | 1 + crates/text/Cargo.toml | 2 +- crates/text2/src/selection.rs | 6 +- crates/workspace2/src/item.rs | 18 +- 26 files changed, 1782 insertions(+), 1665 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd4fca5fa5..46d481c2ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/crates/editor2/src/display_map.rs b/crates/editor2/src/display_map.rs index 0635154910..3cf4d7340f 100644 --- a/crates/editor2/src/display_map.rs +++ b/crates/editor2/src/display_map.rs @@ -60,7 +60,7 @@ impl DisplayMap { buffer: Model, font: Font, font_size: Pixels, - wrap_width: Option, + wrap_width: Option, buffer_header_height: u8, excerpt_header_height: u8, cx: &mut ModelContext, @@ -241,7 +241,7 @@ impl DisplayMap { pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut ModelContext) -> 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); diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index ee552d3dbd..11ad04a659 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -1,3 +1,4 @@ +#![allow(unused)] mod blink_manager; pub mod display_map; mod editor_settings; @@ -20,8 +21,9 @@ mod editor_tests; #[cfg(any(test, feature = "test-support"))] pub mod test; use aho_corasick::AhoCorasick; +use anyhow::Result; use blink_manager::BlinkManager; -use client::{Collaborator, ParticipantIndex}; +use client::{Client, Collaborator, ParticipantIndex}; use clock::ReplicaId; use collections::{HashMap, HashSet, VecDeque}; pub use display_map::DisplayPoint; @@ -33,8 +35,8 @@ pub use element::{ use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - AnyElement, AppContext, Element, EventEmitter, Model, Pixels, Render, Subscription, Task, View, - ViewContext, WeakView, + AnyElement, AppContext, BackgroundExecutor, Element, EventEmitter, Model, Pixels, Render, + Subscription, Task, TextStyle, View, ViewContext, WeakView, WindowContext, }; use hover_popover::HoverState; pub use items::MAX_TAB_TITLE_LEN; @@ -42,27 +44,30 @@ pub use language::{char_kind, CharKind}; use language::{ language_settings::{self, all_language_settings, InlayHintSettings}, AutoindentMode, BracketPair, Buffer, CodeAction, Completion, CursorShape, Diagnostic, Language, - OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId, + LanguageRegistry, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId, }; use link_go_to_definition::LinkGoToDefinitionState; +use lsp::{Documentation, LanguageServerId}; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, }; +use ordered_float::OrderedFloat; use parking_lot::RwLock; -use project::Project; +use project::{FormatTrigger, Project}; use rpc::proto::*; use scroll::{autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager}; use selections_collection::SelectionsCollection; use serde::{Deserialize, Serialize}; use settings::Settings; use std::{ + cmp::Reverse, ops::{Deref, DerefMut, Range}, sync::Arc, time::Duration, }; pub use sum_tree::Bias; -use util::TryFutureExt; +use util::{ResultExt, TryFutureExt}; use workspace::{ItemNavHistory, ViewId, Workspace}; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); @@ -569,7 +574,7 @@ pub enum SoftWrap { #[derive(Clone)] pub struct EditorStyle { - // pub text: TextStyle, + pub text: TextStyle, pub line_height_scalar: f32, // pub placeholder_text: Option, // pub theme: theme::Editor, @@ -887,10 +892,11 @@ impl ContextMenu { workspace: Option>, cx: &mut ViewContext, ) -> (DisplayPoint, AnyElement) { - match self { - ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)), - ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx), - } + todo!() + // match self { + // ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)), + // ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx), + // } } } @@ -903,688 +909,715 @@ struct CompletionsMenu { match_candidates: Arc<[StringMatchCandidate]>, matches: Arc<[StringMatch]>, selected_item: usize, - // list: UniformListState, + list: UniformListState, } -// impl CompletionsMenu { -// fn select_first(&mut self, project: Option<&Model>, cx: &mut ViewContext) { -// self.selected_item = 0; -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// self.attempt_resolve_selected_completion_documentation(project, cx); -// cx.notify(); -// } +// todo!(this is fake) +#[derive(Clone)] +struct UniformListState; -// fn select_prev(&mut self, project: Option<&Model>, cx: &mut ViewContext) { -// if self.selected_item > 0 { -// self.selected_item -= 1; -// } else { -// self.selected_item = self.matches.len() - 1; -// } -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// self.attempt_resolve_selected_completion_documentation(project, cx); -// cx.notify(); -// } +// todo!(this is fake) +impl UniformListState { + pub fn scroll_to(&mut self, target: ScrollTarget) {} +} -// fn select_next(&mut self, project: Option<&Model>, cx: &mut ViewContext) { -// if self.selected_item + 1 < self.matches.len() { -// self.selected_item += 1; -// } else { -// self.selected_item = 0; -// } -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// self.attempt_resolve_selected_completion_documentation(project, cx); -// cx.notify(); -// } +// todo!(this is somewhat fake) +#[derive(Debug)] +pub enum ScrollTarget { + Show(usize), + Center(usize), +} -// fn select_last(&mut self, project: Option<&Model>, cx: &mut ViewContext) { -// self.selected_item = self.matches.len() - 1; -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// self.attempt_resolve_selected_completion_documentation(project, cx); -// cx.notify(); -// } +impl CompletionsMenu { + fn select_first(&mut self, project: Option<&Model>, cx: &mut ViewContext) { + self.selected_item = 0; + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + self.attempt_resolve_selected_completion_documentation(project, cx); + cx.notify(); + } -// fn pre_resolve_completion_documentation( -// &self, -// project: Option>, -// cx: &mut ViewContext, -// ) { -// let settings = settings::get::(cx); -// if !settings.show_completion_documentation { -// return; -// } + fn select_prev(&mut self, project: Option<&Model>, cx: &mut ViewContext) { + if self.selected_item > 0 { + self.selected_item -= 1; + } else { + self.selected_item = self.matches.len() - 1; + } + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + self.attempt_resolve_selected_completion_documentation(project, cx); + cx.notify(); + } -// let Some(project) = project else { -// return; -// }; -// let client = project.read(cx).client(); -// let language_registry = project.read(cx).languages().clone(); + fn select_next(&mut self, project: Option<&Model>, cx: &mut ViewContext) { + if self.selected_item + 1 < self.matches.len() { + self.selected_item += 1; + } else { + self.selected_item = 0; + } + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + self.attempt_resolve_selected_completion_documentation(project, cx); + cx.notify(); + } -// let is_remote = project.read(cx).is_remote(); -// let project_id = project.read(cx).remote_id(); + fn select_last(&mut self, project: Option<&Model>, cx: &mut ViewContext) { + self.selected_item = self.matches.len() - 1; + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + self.attempt_resolve_selected_completion_documentation(project, cx); + cx.notify(); + } -// let completions = self.completions.clone(); -// let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect(); + fn pre_resolve_completion_documentation( + &self, + project: Option>, + cx: &mut ViewContext, + ) { + todo!("implementation below "); + } + // ) { + // let settings = EditorSettings::get_global(cx); + // if !settings.show_completion_documentation { + // return; + // } -// cx.spawn(move |this, mut cx| async move { -// if is_remote { -// let Some(project_id) = project_id else { -// log::error!("Remote project without remote_id"); -// return; -// }; + // let Some(project) = project else { + // return; + // }; + // let client = project.read(cx).client(); + // let language_registry = project.read(cx).languages().clone(); -// for completion_index in completion_indices { -// let completions_guard = completions.read(); -// let completion = &completions_guard[completion_index]; -// if completion.documentation.is_some() { -// continue; -// } + // let is_remote = project.read(cx).is_remote(); + // let project_id = project.read(cx).remote_id(); -// let server_id = completion.server_id; -// let completion = completion.lsp_completion.clone(); -// drop(completions_guard); + // let completions = self.completions.clone(); + // let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect(); -// Self::resolve_completion_documentation_remote( -// project_id, -// server_id, -// completions.clone(), -// completion_index, -// completion, -// client.clone(), -// language_registry.clone(), -// ) -// .await; + // cx.spawn(move |this, mut cx| async move { + // if is_remote { + // let Some(project_id) = project_id else { + // log::error!("Remote project without remote_id"); + // return; + // }; -// _ = this.update(&mut cx, |_, cx| cx.notify()); -// } -// } else { -// for completion_index in completion_indices { -// let completions_guard = completions.read(); -// let completion = &completions_guard[completion_index]; -// if completion.documentation.is_some() { -// continue; -// } + // for completion_index in completion_indices { + // let completions_guard = completions.read(); + // let completion = &completions_guard[completion_index]; + // if completion.documentation.is_some() { + // continue; + // } -// let server_id = completion.server_id; -// let completion = completion.lsp_completion.clone(); -// drop(completions_guard); + // let server_id = completion.server_id; + // let completion = completion.lsp_completion.clone(); + // drop(completions_guard); -// let server = project.read_with(&mut cx, |project, _| { -// project.language_server_for_id(server_id) -// }); -// let Some(server) = server else { -// return; -// }; + // Self::resolve_completion_documentation_remote( + // project_id, + // server_id, + // completions.clone(), + // completion_index, + // completion, + // client.clone(), + // language_registry.clone(), + // ) + // .await; -// Self::resolve_completion_documentation_local( -// server, -// completions.clone(), -// completion_index, -// completion, -// language_registry.clone(), -// ) -// .await; + // _ = this.update(&mut cx, |_, cx| cx.notify()); + // } + // } else { + // for completion_index in completion_indices { + // let completions_guard = completions.read(); + // let completion = &completions_guard[completion_index]; + // if completion.documentation.is_some() { + // continue; + // } -// _ = this.update(&mut cx, |_, cx| cx.notify()); -// } -// } -// }) -// .detach(); -// } + // let server_id = completion.server_id; + // let completion = completion.lsp_completion.clone(); + // drop(completions_guard); -// fn attempt_resolve_selected_completion_documentation( -// &mut self, -// project: Option<&Model>, -// cx: &mut ViewContext, -// ) { -// let settings = settings::get::(cx); -// if !settings.show_completion_documentation { -// return; -// } + // let server = project.read_with(&mut cx, |project, _| { + // project.language_server_for_id(server_id) + // }); + // let Some(server) = server else { + // return; + // }; -// let completion_index = self.matches[self.selected_item].candidate_id; -// let Some(project) = project else { -// return; -// }; -// let language_registry = project.read(cx).languages().clone(); + // Self::resolve_completion_documentation_local( + // server, + // completions.clone(), + // completion_index, + // completion, + // language_registry.clone(), + // ) + // .await; -// let completions = self.completions.clone(); -// let completions_guard = completions.read(); -// let completion = &completions_guard[completion_index]; -// if completion.documentation.is_some() { -// return; -// } + // _ = this.update(&mut cx, |_, cx| cx.notify()); + // } + // } + // }) + // .detach(); + // } -// let server_id = completion.server_id; -// let completion = completion.lsp_completion.clone(); -// drop(completions_guard); + fn attempt_resolve_selected_completion_documentation( + &mut self, + project: Option<&Model>, + cx: &mut ViewContext, + ) { + let settings = EditorSettings::get_global(cx); + if !settings.show_completion_documentation { + return; + } -// if project.read(cx).is_remote() { -// let Some(project_id) = project.read(cx).remote_id() else { -// log::error!("Remote project without remote_id"); -// return; -// }; + let completion_index = self.matches[self.selected_item].candidate_id; + let Some(project) = project else { + return; + }; + let language_registry = project.read(cx).languages().clone(); -// let client = project.read(cx).client(); + let completions = self.completions.clone(); + let completions_guard = completions.read(); + let completion = &completions_guard[completion_index]; + // todo!() + // if completion.documentation.is_some() { + // return; + // } -// cx.spawn(move |this, mut cx| async move { -// Self::resolve_completion_documentation_remote( -// project_id, -// server_id, -// completions.clone(), -// completion_index, -// completion, -// client, -// language_registry.clone(), -// ) -// .await; + let server_id = completion.server_id; + let completion = completion.lsp_completion.clone(); + drop(completions_guard); -// _ = this.update(&mut cx, |_, cx| cx.notify()); -// }) -// .detach(); -// } else { -// let Some(server) = project.read(cx).language_server_for_id(server_id) else { -// return; -// }; + if project.read(cx).is_remote() { + let Some(project_id) = project.read(cx).remote_id() else { + log::error!("Remote project without remote_id"); + return; + }; -// cx.spawn(move |this, mut cx| async move { -// Self::resolve_completion_documentation_local( -// server, -// completions, -// completion_index, -// completion, -// language_registry, -// ) -// .await; + let client = project.read(cx).client(); -// _ = this.update(&mut cx, |_, cx| cx.notify()); -// }) -// .detach(); -// } -// } + cx.spawn(move |this, mut cx| async move { + Self::resolve_completion_documentation_remote( + project_id, + server_id, + completions.clone(), + completion_index, + completion, + client, + language_registry.clone(), + ) + .await; -// async fn resolve_completion_documentation_remote( -// project_id: u64, -// server_id: LanguageServerId, -// completions: Arc>>, -// completion_index: usize, -// completion: lsp::CompletionItem, -// client: Arc, -// language_registry: Arc, -// ) { -// let request = proto::ResolveCompletionDocumentation { -// project_id, -// language_server_id: server_id.0 as u64, -// lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(), -// }; + _ = this.update(&mut cx, |_, cx| cx.notify()); + }) + .detach(); + } else { + let Some(server) = project.read(cx).language_server_for_id(server_id) else { + return; + }; -// let Some(response) = client -// .request(request) -// .await -// .context("completion documentation resolve proto request") -// .log_err() -// else { -// return; -// }; + cx.spawn(move |this, mut cx| async move { + Self::resolve_completion_documentation_local( + server, + completions, + completion_index, + completion, + language_registry, + ) + .await; -// if response.text.is_empty() { -// let mut completions = completions.write(); -// let completion = &mut completions[completion_index]; -// completion.documentation = Some(Documentation::Undocumented); -// } + _ = this.update(&mut cx, |_, cx| cx.notify()); + }) + .detach(); + } + } -// let documentation = if response.is_markdown { -// Documentation::MultiLineMarkdown( -// markdown::parse_markdown(&response.text, &language_registry, None).await, -// ) -// } else if response.text.lines().count() <= 1 { -// Documentation::SingleLine(response.text) -// } else { -// Documentation::MultiLinePlainText(response.text) -// }; + async fn resolve_completion_documentation_remote( + project_id: u64, + server_id: LanguageServerId, + completions: Arc>>, + completion_index: usize, + completion: lsp::CompletionItem, + client: Arc, + language_registry: Arc, + ) { + todo!() + // let request = proto::ResolveCompletionDocumentation { + // project_id, + // language_server_id: server_id.0 as u64, + // lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(), + // }; -// let mut completions = completions.write(); -// let completion = &mut completions[completion_index]; -// completion.documentation = Some(documentation); -// } + // let Some(response) = client + // .request(request) + // .await + // .context("completion documentation resolve proto request") + // .log_err() + // else { + // return; + // }; -// async fn resolve_completion_documentation_local( -// server: Arc, -// completions: Arc>>, -// completion_index: usize, -// completion: lsp::CompletionItem, -// language_registry: Arc, -// ) { -// let can_resolve = server -// .capabilities() -// .completion_provider -// .as_ref() -// .and_then(|options| options.resolve_provider) -// .unwrap_or(false); -// if !can_resolve { -// return; -// } + // if response.text.is_empty() { + // let mut completions = completions.write(); + // let completion = &mut completions[completion_index]; + // completion.documentation = Some(Documentation::Undocumented); + // } -// let request = server.request::(completion); -// let Some(completion_item) = request.await.log_err() else { -// return; -// }; + // let documentation = if response.is_markdown { + // Documentation::MultiLineMarkdown( + // markdown::parse_markdown(&response.text, &language_registry, None).await, + // ) + // } else if response.text.lines().count() <= 1 { + // Documentation::SingleLine(response.text) + // } else { + // Documentation::MultiLinePlainText(response.text) + // }; -// if let Some(lsp_documentation) = completion_item.documentation { -// let documentation = language::prepare_completion_documentation( -// &lsp_documentation, -// &language_registry, -// None, // TODO: Try to reasonably work out which language the completion is for -// ) -// .await; + // let mut completions = completions.write(); + // let completion = &mut completions[completion_index]; + // completion.documentation = Some(documentation); + } -// let mut completions = completions.write(); -// let completion = &mut completions[completion_index]; -// completion.documentation = Some(documentation); -// } else { -// let mut completions = completions.write(); -// let completion = &mut completions[completion_index]; -// completion.documentation = Some(Documentation::Undocumented); -// } -// } + async fn resolve_completion_documentation_local( + server: Arc, + completions: Arc>>, + completion_index: usize, + completion: lsp::CompletionItem, + language_registry: Arc, + ) { + todo!() + // let can_resolve = server + // .capabilities() + // .completion_provider + // .as_ref() + // .and_then(|options| options.resolve_provider) + // .unwrap_or(false); + // if !can_resolve { + // return; + // } -// fn visible(&self) -> bool { -// !self.matches.is_empty() -// } + // let request = server.request::(completion); + // let Some(completion_item) = request.await.log_err() else { + // return; + // }; -// fn render( -// &self, -// style: EditorStyle, -// workspace: Option>, -// cx: &mut ViewContext, -// ) -> AnyElement { -// enum CompletionTag {} + // if let Some(lsp_documentation) = completion_item.documentation { + // let documentation = language::prepare_completion_documentation( + // &lsp_documentation, + // &language_registry, + // None, // TODO: Try to reasonably work out which language the completion is for + // ) + // .await; -// let settings = settings::get::(cx); -// let show_completion_documentation = settings.show_completion_documentation; + // let mut completions = completions.write(); + // let completion = &mut completions[completion_index]; + // completion.documentation = Some(documentation); + // } else { + // let mut completions = completions.write(); + // let completion = &mut completions[completion_index]; + // completion.documentation = Some(Documentation::Undocumented); + // } + } -// let widest_completion_ix = self -// .matches -// .iter() -// .enumerate() -// .max_by_key(|(_, mat)| { -// let completions = self.completions.read(); -// let completion = &completions[mat.candidate_id]; -// let documentation = &completion.documentation; + fn visible(&self) -> bool { + !self.matches.is_empty() + } -// let mut len = completion.label.text.chars().count(); -// if let Some(Documentation::SingleLine(text)) = documentation { -// if show_completion_documentation { -// len += text.chars().count(); -// } -// } + fn render( + &self, + style: EditorStyle, + workspace: Option>, + cx: &mut ViewContext, + ) { + todo!("old implementation below") + } + // ) -> AnyElement { + // enum CompletionTag {} -// len -// }) -// .map(|(ix, _)| ix); + // let settings = EditorSettings>(cx); + // let show_completion_documentation = settings.show_completion_documentation; -// let completions = self.completions.clone(); -// let matches = self.matches.clone(); -// let selected_item = self.selected_item; + // let widest_completion_ix = self + // .matches + // .iter() + // .enumerate() + // .max_by_key(|(_, mat)| { + // let completions = self.completions.read(); + // let completion = &completions[mat.candidate_id]; + // let documentation = &completion.documentation; -// let list = UniformList::new(self.list.clone(), matches.len(), cx, { -// let style = style.clone(); -// move |_, range, items, cx| { -// let start_ix = range.start; -// let completions_guard = completions.read(); + // let mut len = completion.label.text.chars().count(); + // if let Some(Documentation::SingleLine(text)) = documentation { + // if show_completion_documentation { + // len += text.chars().count(); + // } + // } -// for (ix, mat) in matches[range].iter().enumerate() { -// let item_ix = start_ix + ix; -// let candidate_id = mat.candidate_id; -// let completion = &completions_guard[candidate_id]; + // len + // }) + // .map(|(ix, _)| ix); -// let documentation = if show_completion_documentation { -// &completion.documentation -// } else { -// &None -// }; + // let completions = self.completions.clone(); + // let matches = self.matches.clone(); + // let selected_item = self.selected_item; -// items.push( -// MouseEventHandler::new::( -// mat.candidate_id, -// cx, -// |state, _| { -// let item_style = if item_ix == selected_item { -// style.autocomplete.selected_item -// } else if state.hovered() { -// style.autocomplete.hovered_item -// } else { -// style.autocomplete.item -// }; + // let list = UniformList::new(self.list.clone(), matches.len(), cx, { + // let style = style.clone(); + // move |_, range, items, cx| { + // let start_ix = range.start; + // let completions_guard = completions.read(); -// let completion_label = -// Text::new(completion.label.text.clone(), style.text.clone()) -// .with_soft_wrap(false) -// .with_highlights( -// combine_syntax_and_fuzzy_match_highlights( -// &completion.label.text, -// style.text.color.into(), -// styled_runs_for_code_label( -// &completion.label, -// &style.syntax, -// ), -// &mat.positions, -// ), -// ); + // for (ix, mat) in matches[range].iter().enumerate() { + // let item_ix = start_ix + ix; + // let candidate_id = mat.candidate_id; + // let completion = &completions_guard[candidate_id]; -// if let Some(Documentation::SingleLine(text)) = documentation { -// Flex::row() -// .with_child(completion_label) -// .with_children((|| { -// let text_style = TextStyle { -// color: style.autocomplete.inline_docs_color, -// font_size: style.text.font_size -// * style.autocomplete.inline_docs_size_percent, -// ..style.text.clone() -// }; + // let documentation = if show_completion_documentation { + // &completion.documentation + // } else { + // &None + // }; -// let label = Text::new(text.clone(), text_style) -// .aligned() -// .constrained() -// .dynamically(move |constraint, _, _| { -// gpui::SizeConstraint { -// min: constraint.min, -// max: vec2f( -// constraint.max.x(), -// constraint.min.y(), -// ), -// } -// }); + // items.push( + // MouseEventHandler::new::( + // mat.candidate_id, + // cx, + // |state, _| { + // let item_style = if item_ix == selected_item { + // style.autocomplete.selected_item + // } else if state.hovered() { + // style.autocomplete.hovered_item + // } else { + // style.autocomplete.item + // }; -// if Some(item_ix) == widest_completion_ix { -// Some( -// label -// .contained() -// .with_style( -// style -// .autocomplete -// .inline_docs_container, -// ) -// .into_any(), -// ) -// } else { -// Some(label.flex_float().into_any()) -// } -// })()) -// .into_any() -// } else { -// completion_label.into_any() -// } -// .contained() -// .with_style(item_style) -// .constrained() -// .dynamically( -// move |constraint, _, _| { -// if Some(item_ix) == widest_completion_ix { -// constraint -// } else { -// gpui::SizeConstraint { -// min: constraint.min, -// max: constraint.min, -// } -// } -// }, -// ) -// }, -// ) -// .with_cursor_style(CursorStyle::PointingHand) -// .on_down(MouseButton::Left, move |_, this, cx| { -// this.confirm_completion( -// &ConfirmCompletion { -// item_ix: Some(item_ix), -// }, -// cx, -// ) -// .map(|task| task.detach()); -// }) -// .constrained() -// .with_min_width(style.autocomplete.completion_min_width) -// .with_max_width(style.autocomplete.completion_max_width) -// .into_any(), -// ); -// } -// } -// }) -// .with_width_from_item(widest_completion_ix); + // let completion_label = + // Text::new(completion.label.text.clone(), style.text.clone()) + // .with_soft_wrap(false) + // .with_highlights( + // combine_syntax_and_fuzzy_match_highlights( + // &completion.label.text, + // style.text.color.into(), + // styled_runs_for_code_label( + // &completion.label, + // &style.syntax, + // ), + // &mat.positions, + // ), + // ); -// enum MultiLineDocumentation {} + // if let Some(Documentation::SingleLine(text)) = documentation { + // Flex::row() + // .with_child(completion_label) + // .with_children((|| { + // let text_style = TextStyle { + // color: style.autocomplete.inline_docs_color, + // font_size: style.text.font_size + // * style.autocomplete.inline_docs_size_percent, + // ..style.text.clone() + // }; -// Flex::row() -// .with_child(list.flex(1., false)) -// .with_children({ -// let mat = &self.matches[selected_item]; -// let completions = self.completions.read(); -// let completion = &completions[mat.candidate_id]; -// let documentation = &completion.documentation; + // let label = Text::new(text.clone(), text_style) + // .aligned() + // .constrained() + // .dynamically(move |constraint, _, _| { + // gpui::SizeConstraint { + // min: constraint.min, + // max: vec2f( + // constraint.max.x(), + // constraint.min.y(), + // ), + // } + // }); -// match documentation { -// Some(Documentation::MultiLinePlainText(text)) => Some( -// Flex::column() -// .scrollable::(0, None, cx) -// .with_child( -// Text::new(text.clone(), style.text.clone()).with_soft_wrap(true), -// ) -// .contained() -// .with_style(style.autocomplete.alongside_docs_container) -// .constrained() -// .with_max_width(style.autocomplete.alongside_docs_max_width) -// .flex(1., false), -// ), + // if Some(item_ix) == widest_completion_ix { + // Some( + // label + // .contained() + // .with_style( + // style + // .autocomplete + // .inline_docs_container, + // ) + // .into_any(), + // ) + // } else { + // Some(label.flex_float().into_any()) + // } + // })()) + // .into_any() + // } else { + // completion_label.into_any() + // } + // .contained() + // .with_style(item_style) + // .constrained() + // .dynamically( + // move |constraint, _, _| { + // if Some(item_ix) == widest_completion_ix { + // constraint + // } else { + // gpui::SizeConstraint { + // min: constraint.min, + // max: constraint.min, + // } + // } + // }, + // ) + // }, + // ) + // .with_cursor_style(CursorStyle::PointingHand) + // .on_down(MouseButton::Left, move |_, this, cx| { + // this.confirm_completion( + // &ConfirmCompletion { + // item_ix: Some(item_ix), + // }, + // cx, + // ) + // .map(|task| task.detach()); + // }) + // .constrained() + // .with_min_width(style.autocomplete.completion_min_width) + // .with_max_width(style.autocomplete.completion_max_width) + // .into_any(), + // ); + // } + // } + // }) + // .with_width_from_item(widest_completion_ix); -// Some(Documentation::MultiLineMarkdown(parsed)) => Some( -// Flex::column() -// .scrollable::(0, None, cx) -// .with_child(render_parsed_markdown::( -// parsed, &style, workspace, cx, -// )) -// .contained() -// .with_style(style.autocomplete.alongside_docs_container) -// .constrained() -// .with_max_width(style.autocomplete.alongside_docs_max_width) -// .flex(1., false), -// ), + // enum MultiLineDocumentation {} -// _ => None, -// } -// }) -// .contained() -// .with_style(style.autocomplete.container) -// .into_any() -// } + // Flex::row() + // .with_child(list.flex(1., false)) + // .with_children({ + // let mat = &self.matches[selected_item]; + // let completions = self.completions.read(); + // let completion = &completions[mat.candidate_id]; + // let documentation = &completion.documentation; -// pub async fn filter(&mut self, query: Option<&str>, executor: Arc) { -// let mut matches = if let Some(query) = query { -// fuzzy::match_strings( -// &self.match_candidates, -// query, -// query.chars().any(|c| c.is_uppercase()), -// 100, -// &Default::default(), -// executor, -// ) -// .await -// } else { -// self.match_candidates -// .iter() -// .enumerate() -// .map(|(candidate_id, candidate)| StringMatch { -// candidate_id, -// score: Default::default(), -// positions: Default::default(), -// string: candidate.string.clone(), -// }) -// .collect() -// }; + // match documentation { + // Some(Documentation::MultiLinePlainText(text)) => Some( + // Flex::column() + // .scrollable::(0, None, cx) + // .with_child( + // Text::new(text.clone(), style.text.clone()).with_soft_wrap(true), + // ) + // .contained() + // .with_style(style.autocomplete.alongside_docs_container) + // .constrained() + // .with_max_width(style.autocomplete.alongside_docs_max_width) + // .flex(1., false), + // ), -// // Remove all candidates where the query's start does not match the start of any word in the candidate -// if let Some(query) = query { -// if let Some(query_start) = query.chars().next() { -// matches.retain(|string_match| { -// split_words(&string_match.string).any(|word| { -// // Check that the first codepoint of the word as lowercase matches the first -// // codepoint of the query as lowercase -// word.chars() -// .flat_map(|codepoint| codepoint.to_lowercase()) -// .zip(query_start.to_lowercase()) -// .all(|(word_cp, query_cp)| word_cp == query_cp) -// }) -// }); -// } -// } + // Some(Documentation::MultiLineMarkdown(parsed)) => Some( + // Flex::column() + // .scrollable::(0, None, cx) + // .with_child(render_parsed_markdown::( + // parsed, &style, workspace, cx, + // )) + // .contained() + // .with_style(style.autocomplete.alongside_docs_container) + // .constrained() + // .with_max_width(style.autocomplete.alongside_docs_max_width) + // .flex(1., false), + // ), -// let completions = self.completions.read(); -// matches.sort_unstable_by_key(|mat| { -// let completion = &completions[mat.candidate_id]; -// ( -// completion.lsp_completion.sort_text.as_ref(), -// Reverse(OrderedFloat(mat.score)), -// completion.sort_key(), -// ) -// }); -// drop(completions); + // _ => None, + // } + // }) + // .contained() + // .with_style(style.autocomplete.container) + // .into_any() + // } -// for mat in &mut matches { -// let completions = self.completions.read(); -// let filter_start = completions[mat.candidate_id].label.filter_range.start; -// for position in &mut mat.positions { -// *position += filter_start; -// } -// } + pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) { + let mut matches = if let Some(query) = query { + fuzzy::match_strings( + &self.match_candidates, + query, + query.chars().any(|c| c.is_uppercase()), + 100, + &Default::default(), + executor, + ) + .await + } else { + self.match_candidates + .iter() + .enumerate() + .map(|(candidate_id, candidate)| StringMatch { + candidate_id, + score: Default::default(), + positions: Default::default(), + string: candidate.string.clone(), + }) + .collect() + }; -// self.matches = matches.into(); -// self.selected_item = 0; -// } -// } + // Remove all candidates where the query's start does not match the start of any word in the candidate + if let Some(query) = query { + if let Some(query_start) = query.chars().next() { + matches.retain(|string_match| { + split_words(&string_match.string).any(|word| { + // Check that the first codepoint of the word as lowercase matches the first + // codepoint of the query as lowercase + word.chars() + .flat_map(|codepoint| codepoint.to_lowercase()) + .zip(query_start.to_lowercase()) + .all(|(word_cp, query_cp)| word_cp == query_cp) + }) + }); + } + } + + let completions = self.completions.read(); + matches.sort_unstable_by_key(|mat| { + let completion = &completions[mat.candidate_id]; + ( + completion.lsp_completion.sort_text.as_ref(), + Reverse(OrderedFloat(mat.score)), + completion.sort_key(), + ) + }); + drop(completions); + + for mat in &mut matches { + let completions = self.completions.read(); + let filter_start = completions[mat.candidate_id].label.filter_range.start; + for position in &mut mat.positions { + *position += filter_start; + } + } + + self.matches = matches.into(); + self.selected_item = 0; + } +} #[derive(Clone)] struct CodeActionsMenu { actions: Arc<[CodeAction]>, buffer: Model, selected_item: usize, - // list: UniformListState, + list: UniformListState, deployed_from_indicator: bool, } -// impl CodeActionsMenu { -// fn select_first(&mut self, cx: &mut ViewContext) { -// self.selected_item = 0; -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// cx.notify() -// } +impl CodeActionsMenu { + fn select_first(&mut self, cx: &mut ViewContext) { + self.selected_item = 0; + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + cx.notify() + } -// fn select_prev(&mut self, cx: &mut ViewContext) { -// if self.selected_item > 0 { -// self.selected_item -= 1; -// } else { -// self.selected_item = self.actions.len() - 1; -// } -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// cx.notify(); -// } + fn select_prev(&mut self, cx: &mut ViewContext) { + if self.selected_item > 0 { + self.selected_item -= 1; + } else { + self.selected_item = self.actions.len() - 1; + } + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + cx.notify(); + } -// fn select_next(&mut self, cx: &mut ViewContext) { -// if self.selected_item + 1 < self.actions.len() { -// self.selected_item += 1; -// } else { -// self.selected_item = 0; -// } -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// cx.notify(); -// } + fn select_next(&mut self, cx: &mut ViewContext) { + if self.selected_item + 1 < self.actions.len() { + self.selected_item += 1; + } else { + self.selected_item = 0; + } + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + cx.notify(); + } -// fn select_last(&mut self, cx: &mut ViewContext) { -// self.selected_item = self.actions.len() - 1; -// self.list.scroll_to(ScrollTarget::Show(self.selected_item)); -// cx.notify() -// } + fn select_last(&mut self, cx: &mut ViewContext) { + self.selected_item = self.actions.len() - 1; + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); + cx.notify() + } -// fn visible(&self) -> bool { -// !self.actions.is_empty() -// } + fn visible(&self) -> bool { + !self.actions.is_empty() + } -// fn render( -// &self, -// mut cursor_position: DisplayPoint, -// style: EditorStyle, -// cx: &mut ViewContext, -// ) -> (DisplayPoint, AnyElement) { -// enum ActionTag {} + fn render( + &self, + mut cursor_position: DisplayPoint, + style: EditorStyle, + cx: &mut ViewContext, + ) -> (DisplayPoint, AnyElement) { + todo!("old version below") + } + // enum ActionTag {} -// let container_style = style.autocomplete.container; -// let actions = self.actions.clone(); -// let selected_item = self.selected_item; -// let element = UniformList::new( -// self.list.clone(), -// actions.len(), -// cx, -// move |_, range, items, cx| { -// let start_ix = range.start; -// for (ix, action) in actions[range].iter().enumerate() { -// let item_ix = start_ix + ix; -// items.push( -// MouseEventHandler::new::(item_ix, cx, |state, _| { -// let item_style = if item_ix == selected_item { -// style.autocomplete.selected_item -// } else if state.hovered() { -// style.autocomplete.hovered_item -// } else { -// style.autocomplete.item -// }; + // let container_style = style.autocomplete.container; + // let actions = self.actions.clone(); + // let selected_item = self.selected_item; + // let element = UniformList::new( + // self.list.clone(), + // actions.len(), + // cx, + // move |_, range, items, cx| { + // let start_ix = range.start; + // for (ix, action) in actions[range].iter().enumerate() { + // let item_ix = start_ix + ix; + // items.push( + // MouseEventHandler::new::(item_ix, cx, |state, _| { + // let item_style = if item_ix == selected_item { + // style.autocomplete.selected_item + // } else if state.hovered() { + // style.autocomplete.hovered_item + // } else { + // style.autocomplete.item + // }; -// Text::new(action.lsp_action.title.clone(), style.text.clone()) -// .with_soft_wrap(false) -// .contained() -// .with_style(item_style) -// }) -// .with_cursor_style(CursorStyle::PointingHand) -// .on_down(MouseButton::Left, move |_, this, cx| { -// let workspace = this -// .workspace -// .as_ref() -// .and_then(|(workspace, _)| workspace.upgrade(cx)); -// cx.window_context().defer(move |cx| { -// if let Some(workspace) = workspace { -// workspace.update(cx, |workspace, cx| { -// if let Some(task) = Editor::confirm_code_action( -// workspace, -// &ConfirmCodeAction { -// item_ix: Some(item_ix), -// }, -// cx, -// ) { -// task.detach_and_log_err(cx); -// } -// }); -// } -// }); -// }) -// .into_any(), -// ); -// } -// }, -// ) -// .with_width_from_item( -// self.actions -// .iter() -// .enumerate() -// .max_by_key(|(_, action)| action.lsp_action.title.chars().count()) -// .map(|(ix, _)| ix), -// ) -// .contained() -// .with_style(container_style) -// .into_any(); + // Text::new(action.lsp_action.title.clone(), style.text.clone()) + // .with_soft_wrap(false) + // .contained() + // .with_style(item_style) + // }) + // .with_cursor_style(CursorStyle::PointingHand) + // .on_down(MouseButton::Left, move |_, this, cx| { + // let workspace = this + // .workspace + // .as_ref() + // .and_then(|(workspace, _)| workspace.upgrade(cx)); + // cx.window_context().defer(move |cx| { + // if let Some(workspace) = workspace { + // workspace.update(cx, |workspace, cx| { + // if let Some(task) = Editor::confirm_code_action( + // workspace, + // &ConfirmCodeAction { + // item_ix: Some(item_ix), + // }, + // cx, + // ) { + // task.detach_and_log_err(cx); + // } + // }); + // } + // }); + // }) + // .into_any(), + // ); + // } + // }, + // ) + // .with_width_from_item( + // self.actions + // .iter() + // .enumerate() + // .max_by_key(|(_, action)| action.lsp_action.title.chars().count()) + // .map(|(ix, _)| ix), + // ) + // .contained() + // .with_style(container_style) + // .into_any(); -// if self.deployed_from_indicator { -// *cursor_position.column_mut() = 0; -// } + // if self.deployed_from_indicator { + // *cursor_position.column_mut() = 0; + // } -// (cursor_position, element) -// } -// } + // (cursor_position, element) + // } +} pub struct CopilotState { excerpt_id: Option, @@ -2018,20 +2051,21 @@ impl Editor { // self.buffer().read(cx).title(cx) // } - // pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot { - // EditorSnapshot { - // mode: self.mode, - // show_gutter: self.show_gutter, - // display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)), - // scroll_anchor: self.scroll_manager.anchor(), - // ongoing_scroll: self.scroll_manager.ongoing_scroll(), - // placeholder_text: self.placeholder_text.clone(), - // is_focused: self - // .handle - // .upgrade(cx) - // .map_or(false, |handle| handle.is_focused(cx)), - // } - // } + pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot { + todo!() + // EditorSnapshot { + // mode: self.mode, + // show_gutter: self.show_gutter, + // display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)), + // scroll_anchor: self.scroll_manager.anchor(), + // ongoing_scroll: self.scroll_manager.ongoing_scroll(), + // placeholder_text: self.placeholder_text.clone(), + // is_focused: self + // .handle + // .upgrade(cx) + // .map_or(false, |handle| handle.is_focused(cx)), + // } + } // pub fn language_at<'a, T: ToOffset>( // &self, @@ -2854,7 +2888,7 @@ impl Editor { // let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx); // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); - // if !brace_inserted && settings::get::(cx).use_on_type_format { + // if !brace_inserted && EditorSettings>(cx).use_on_type_format { // if let Some(on_type_format_task) = // this.trigger_on_type_formatting(text.to_string(), cx) // { @@ -3173,7 +3207,7 @@ impl Editor { // } // fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext) { - // if !settings::get::(cx).show_completions_on_input { + // if !EditorSettings>(cx).show_completions_on_input { // return; // } @@ -3377,16 +3411,16 @@ impl Editor { // } // } - // fn visible_inlay_hints(&self, cx: &ViewContext<'_, '_, Editor>) -> Vec { - // self.display_map - // .read(cx) - // .current_inlays() - // .filter(move |inlay| { - // Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id) - // }) - // .cloned() - // .collect() - // } + fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec { + self.display_map + .read(cx) + .current_inlays() + .filter(move |inlay| { + Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id) + }) + .cloned() + .collect() + } // pub fn excerpt_visible_offsets( // &self, @@ -7856,40 +7890,40 @@ impl Editor { // Some(self.perform_format(project, FormatTrigger::Manual, cx)) // } - // fn perform_format( - // &mut self, - // project: Model, - // trigger: FormatTrigger, - // cx: &mut ViewContext, - // ) -> Task> { - // let buffer = self.buffer().clone(); - // let buffers = buffer.read(cx).all_buffers(); + fn perform_format( + &mut self, + project: Model, + trigger: FormatTrigger, + cx: &mut ViewContext, + ) -> Task> { + let buffer = self.buffer().clone(); + let buffers = buffer.read(cx).all_buffers(); - // let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse(); - // let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx)); + let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse(); + let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx)); - // cx.spawn(|_, mut cx| async move { - // let transaction = futures::select_biased! { - // _ = timeout => { - // log::warn!("timed out waiting for formatting"); - // None - // } - // transaction = format.log_err().fuse() => transaction, - // }; + cx.spawn(|_, mut cx| async move { + let transaction = futures::select_biased! { + _ = timeout => { + log::warn!("timed out waiting for formatting"); + None + } + transaction = format.log_err().fuse() => transaction, + }; - // buffer.update(&mut cx, |buffer, cx| { - // if let Some(transaction) = transaction { - // if !buffer.is_singleton() { - // buffer.push_transaction(&transaction.0, cx); - // } - // } + buffer.update(&mut cx, |buffer, cx| { + if let Some(transaction) = transaction { + if !buffer.is_singleton() { + buffer.push_transaction(&transaction.0, cx); + } + } - // cx.notify(); - // }); + cx.notify(); + }); - // Ok(()) - // }) - // } + Ok(()) + }) + } // fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext) { // if let Some(project) = self.project.clone() { @@ -8162,42 +8196,42 @@ impl Editor { // self.fold_ranges(ranges, true, cx); // } - // pub fn fold_ranges( - // &mut self, - // ranges: impl IntoIterator>, - // auto_scroll: bool, - // cx: &mut ViewContext, - // ) { - // let mut ranges = ranges.into_iter().peekable(); - // if ranges.peek().is_some() { - // self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); + pub fn fold_ranges( + &mut self, + ranges: impl IntoIterator>, + auto_scroll: bool, + cx: &mut ViewContext, + ) { + let mut ranges = ranges.into_iter().peekable(); + if ranges.peek().is_some() { + self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); - // if auto_scroll { - // self.request_autoscroll(Autoscroll::fit(), cx); - // } + if auto_scroll { + self.request_autoscroll(Autoscroll::fit(), cx); + } - // cx.notify(); - // } - // } + cx.notify(); + } + } - // pub fn unfold_ranges( - // &mut self, - // ranges: impl IntoIterator>, - // inclusive: bool, - // auto_scroll: bool, - // cx: &mut ViewContext, - // ) { - // let mut ranges = ranges.into_iter().peekable(); - // if ranges.peek().is_some() { - // self.display_map - // .update(cx, |map, cx| map.unfold(ranges, inclusive, cx)); - // if auto_scroll { - // self.request_autoscroll(Autoscroll::fit(), cx); - // } + pub fn unfold_ranges( + &mut self, + ranges: impl IntoIterator>, + inclusive: bool, + auto_scroll: bool, + cx: &mut ViewContext, + ) { + let mut ranges = ranges.into_iter().peekable(); + if ranges.peek().is_some() { + self.display_map + .update(cx, |map, cx| map.unfold(ranges, inclusive, cx)); + if auto_scroll { + self.request_autoscroll(Autoscroll::fit(), cx); + } - // cx.notify(); - // } - // } + cx.notify(); + } + } // pub fn gutter_hover( // &mut self, @@ -8900,59 +8934,61 @@ impl Editor { // telemetry.report_clickhouse_event(event, telemetry_settings); // } - // #[cfg(any(test, feature = "test-support"))] - // fn report_editor_event( - // &self, - // _operation: &'static str, - // _file_extension: Option, - // _cx: &AppContext, - // ) { - // } + #[cfg(any(test, feature = "test-support"))] + fn report_editor_event( + &self, + _operation: &'static str, + _file_extension: Option, + _cx: &AppContext, + ) { + } - // #[cfg(not(any(test, feature = "test-support")))] - // fn report_editor_event( - // &self, - // operation: &'static str, - // file_extension: Option, - // cx: &AppContext, - // ) { - // let Some(project) = &self.project else { return }; + #[cfg(not(any(test, feature = "test-support")))] + fn report_editor_event( + &self, + operation: &'static str, + file_extension: Option, + cx: &AppContext, + ) { + todo!("old version below"); + } + // let Some(project) = &self.project else { return }; - // // If None, we are in a file without an extension - // let file = self - // .buffer - // .read(cx) - // .as_singleton() - // .and_then(|b| b.read(cx).file()); - // let file_extension = file_extension.or(file - // .as_ref() - // .and_then(|file| Path::new(file.file_name(cx)).extension()) - // .and_then(|e| e.to_str()) - // .map(|a| a.to_string())); + // // If None, we are in a file without an extension + // let file = self + // .buffer + // .read(cx) + // .as_singleton() + // .and_then(|b| b.read(cx).file()); + // let file_extension = file_extension.or(file + // .as_ref() + // .and_then(|file| Path::new(file.file_name(cx)).extension()) + // .and_then(|e| e.to_str()) + // .map(|a| a.to_string())); - // let vim_mode = cx - // .global::() - // .raw_user_settings() - // .get("vim_mode") - // == Some(&serde_json::Value::Bool(true)); - // let telemetry_settings = *settings::get::(cx); - // let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None); - // let copilot_enabled_for_language = self - // .buffer - // .read(cx) - // .settings_at(0, cx) - // .show_copilot_suggestions; + // let vim_mode = cx + // .global::() + // .raw_user_settings() + // .get("vim_mode") + // == Some(&serde_json::Value::Bool(true)); + // let telemetry_settings = *settings::get::(cx); + // let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None); + // let copilot_enabled_for_language = self + // .buffer + // .read(cx) + // .settings_at(0, cx) + // .show_copilot_suggestions; - // let telemetry = project.read(cx).client().telemetry().clone(); - // let event = ClickhouseEvent::Editor { - // file_extension, - // vim_mode, - // operation, - // copilot_enabled, - // copilot_enabled_for_language, - // }; - // telemetry.report_clickhouse_event(event, telemetry_settings) - // } + // let telemetry = project.read(cx).client().telemetry().clone(); + // let event = ClickhouseEvent::Editor { + // file_extension, + // vim_mode, + // operation, + // copilot_enabled, + // copilot_enabled_for_language, + // }; + // telemetry.report_clickhouse_event(event, telemetry_settings) + // } // /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines, // /// with each line being an array of {text, highlight} objects. @@ -9190,7 +9226,7 @@ impl EditorSnapshot { self.placeholder_text.as_ref() } - pub fn scroll_position(&self) -> gpui::Point { + pub fn scroll_position(&self) -> gpui::Point { self.scroll_anchor.scroll_position(&self.display_snapshot) } } diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index dc0b9f6751..6f36cf8e06 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -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> { 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, ) } diff --git a/crates/editor2/src/highlight_matching_bracket.rs b/crates/editor2/src/highlight_matching_bracket.rs index e0fc2c0d00..5074ee4eda 100644 --- a/crates/editor2/src/highlight_matching_bracket.rs +++ b/crates/editor2/src/highlight_matching_bracket.rs @@ -5,29 +5,30 @@ use crate::{Editor, RangeToAnchorExt}; enum MatchingBracketHighlight {} pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewContext) { - editor.clear_background_highlights::(cx); + todo!() + // // editor.clear_background_highlights::(cx); - let newest_selection = editor.selections.newest::(cx); - // Don't highlight brackets if the selection isn't empty - if !newest_selection.is_empty() { - return; - } + // let newest_selection = editor.selections.newest::(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::( - 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::( + // 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)] diff --git a/crates/editor2/src/hover_popover.rs b/crates/editor2/src/hover_popover.rs index b17c5df28f..9eddd259af 100644 --- a/crates/editor2/src/hover_popover.rs +++ b/crates/editor2/src/hover_popover.rs @@ -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) { - 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::( - 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::( + // 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) -> bool { editor.hover_state.info_task = None; editor.hover_state.triggered_from = None; - editor.clear_background_highlights::(cx); + // todo!() + // editor.clear_background_highlights::(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::( - vec![symbol_range], - |theme| theme.editor.hover_popover.highlight, - cx, - ); - } else { - this.clear_background_highlights::(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::( + // vec![symbol_range], + // |theme| theme.editor.hover_popover.highlight, + // cx, + // ); + // } else { + // this.clear_background_highlights::(cx); + // } + // + // this.hover_state.info_popover = hover_popover; + // cx.notify(); })?; Ok::<_, anyhow::Error>(()) @@ -424,38 +425,40 @@ impl HoverState { workspace: Option>, cx: &mut ViewContext, ) -> Option<(DisplayPoint, Vec>)> { - // 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)] diff --git a/crates/editor2/src/inlay_hint_cache.rs b/crates/editor2/src/inlay_hint_cache.rs index 74d6092ffa..addd3bf3ac 100644 --- a/crates/editor2/src/inlay_hint_cache.rs +++ b/crates/editor2/src/inlay_hint_cache.rs @@ -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, 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, 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, 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 { diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index f01e6ab2b3..717cdc08a2 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -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, -// project: Model, -// message: proto::update_view::Editor, -// cx: &mut AsyncAppContext, -// ) -> Result<()> { +async fn update_editor_from_message( + this: WeakView, + project: Model, + 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, cx: &mut ViewContext) -> bool { - if let Ok(data) = data.downcast::() { - let newest_selection = self.selections.newest::(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::() { + // let newest_selection = self.selections.newest::(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 { @@ -563,8 +568,8 @@ impl Item for Editor { fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option { 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> { + fn breadcrumbs(&self, variant: &ThemeVariant, cx: &AppContext) -> Option> { 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.clear_background_highlights::(cx); + todo!() + // self.clear_background_highlights::(cx); } fn update_matches(&mut self, matches: Vec>, cx: &mut ViewContext) { - self.highlight_background::( - matches, - |theme| theme.search.match_background, - cx, - ); + todo!() + // self.highlight_background::( + // matches, + // |theme| theme.search.match_background, + // cx, + // ); } fn query_suggestion(&mut self, cx: &mut ViewContext) -> String { @@ -952,20 +967,22 @@ impl SearchableItem for Editor { matches: Vec>, cx: &mut ViewContext, ) { - 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, cx: &mut ViewContext) { - 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, ) -> Task>> { 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( diff --git a/crates/editor2/src/link_go_to_definition.rs b/crates/editor2/src/link_go_to_definition.rs index cdbab3b3fc..da2b49def6 100644 --- a/crates/editor2/src/link_go_to_definition.rs +++ b/crates/editor2/src/link_go_to_definition.rs @@ -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, ) { - 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)] diff --git a/crates/editor2/src/mouse_context_menu.rs b/crates/editor2/src/mouse_context_menu.rs index 84c670c79d..97787c3d39 100644 --- a/crates/editor2/src/mouse_context_menu.rs +++ b/crates/editor2/src/mouse_context_menu.rs @@ -8,27 +8,28 @@ pub fn deploy_context_menu( point: DisplayPoint, cx: &mut ViewContext, ) { - 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)] diff --git a/crates/editor2/src/persistence.rs b/crates/editor2/src/persistence.rs index 6e37735c13..c1c1455014 100644 --- a/crates/editor2/src/persistence.rs +++ b/crates/editor2/src/persistence.rs @@ -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, diff --git a/crates/editor2/src/scroll.rs b/crates/editor2/src/scroll.rs index 2abf80a747..3c2a25dd93 100644 --- a/crates/editor2/src/scroll.rs +++ b/crates/editor2/src/scroll.rs @@ -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 { + pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point { 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, f32, f32, AutoscrollStrategy)>, + last_autoscroll: Option<(gpui::Point, f32, f32, AutoscrollStrategy)>, show_scrollbars: bool, hide_scrollbar_task: Option>, visible_line_count: Option, @@ -171,7 +171,7 @@ impl ScrollManager { self.ongoing.axis = axis; } - pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point { + pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point { 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::().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.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.scroll_manager.vertical_scroll_margin = margin_rows as f32; + // cx.notify(); + // } -// pub fn visible_line_count(&self) -> Option { -// self.scroll_manager.visible_line_count -// } + // pub fn visible_line_count(&self) -> Option { + // self.scroll_manager.visible_line_count + // } -// pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext) { -// 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) { + // 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, -// cx: &mut ViewContext, -// ) { -// self.set_scroll_position_internal(scroll_position, true, false, cx); -// } + pub fn set_scroll_position( + &mut self, + scroll_position: gpui::Point, + cx: &mut ViewContext, + ) { + self.set_scroll_position_internal(scroll_position, true, false, cx); + } -// pub(crate) fn set_scroll_position_internal( -// &mut self, -// scroll_position: gpui::Point, -// local: bool, -// autoscroll: bool, -// cx: &mut ViewContext, -// ) { -// 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, + local: bool, + autoscroll: bool, + cx: &mut ViewContext, + ) { + 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) -> gpui::Point { -// 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) -> gpui::Point { + // 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) { -// 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) { + // 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, -// ) { -// 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, + // ) { + // 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) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } + // pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext) { + // 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, -// ) { -// 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, + // ) { + // 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); + // } + // } +} diff --git a/crates/editor2/src/scroll/autoscroll.rs b/crates/editor2/src/scroll/autoscroll.rs index 5816e5683b..a4c37a258e 100644 --- a/crates/editor2/src/scroll/autoscroll.rs +++ b/crates/editor2/src/scroll/autoscroll.rs @@ -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, ) -> 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 diff --git a/crates/editor2/src/scroll/scroll_amount.rs b/crates/editor2/src/scroll/scroll_amount.rs index 2cb22d1516..89d188e324 100644 --- a/crates/editor2/src/scroll/scroll_amount.rs +++ b/crates/editor2/src/scroll/scroll_amount.rs @@ -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.), + // } } } diff --git a/crates/editor2/src/selections_collection.rs b/crates/editor2/src/selections_collection.rs index 0d10db7af9..2762fd369e 100644 --- a/crates/editor2/src/selections_collection.rs +++ b/crates/editor2/src/selections_collection.rs @@ -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, - reversed: bool, - text_layout_details: &TextLayoutDetails, - ) -> Option> { - 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, + // reversed: bool, + // text_layout_details: &TextLayoutDetails, + // ) -> Option> { + // 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( &mut self, diff --git a/crates/gpui2/src/executor.rs b/crates/gpui2/src/executor.rs index 018f575d2d..b6fd5b2318 100644 --- a/crates/gpui2/src/executor.rs +++ b/crates/gpui2/src/executor.rs @@ -29,6 +29,7 @@ pub struct ForegroundExecutor { } #[must_use] +#[derive(Debug)] pub enum Task { Ready(Option), Spawned(async_task::Task), diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index 468bc1e5b7..b2fad4efda 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -819,6 +819,18 @@ impl From for f64 { } } +impl From for u32 { + fn from(pixels: Pixels) -> Self { + pixels.0 as u32 + } +} + +impl From 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, )] diff --git a/crates/gpui2/src/platform/mac/text_system.rs b/crates/gpui2/src/platform/mac/text_system.rs index a4c56c3523..b87db09dc0 100644 --- a/crates/gpui2/src/platform/mac/text_system.rs +++ b/crates/gpui2/src/platform/mac/text_system.rs @@ -411,6 +411,7 @@ impl MacTextSystemState { descent: typographic_bounds.descent.into(), runs, font_size, + len: text.len(), } } diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 2544989ebc..b30d4aa002 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -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, diff --git a/crates/gpui2/src/text_system.rs b/crates/gpui2/src/text_system.rs index ee8c653866..dd0689396e 100644 --- a/crates/gpui2/src/text_system.rs +++ b/crates/gpui2/src/text_system.rs @@ -151,7 +151,7 @@ impl TextSystem { pub fn layout_text( &self, - text: &SharedString, + text: &str, font_size: Pixels, runs: &[TextRun], wrap_width: Option, diff --git a/crates/gpui2/src/text_system/line.rs b/crates/gpui2/src/text_system/line.rs index ad70a79bb1..63aac96faf 100644 --- a/crates/gpui2/src/text_system/line.rs +++ b/crates/gpui2/src/text_system/line.rs @@ -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() } diff --git a/crates/gpui2/src/text_system/line_layout.rs b/crates/gpui2/src/text_system/line_layout.rs index 7682aaa1b8..a310c32cd1 100644 --- a/crates/gpui2/src/text_system/line_layout.rs +++ b/crates/gpui2/src/text_system/line_layout.rs @@ -16,6 +16,7 @@ pub struct LineLayout { pub ascent: Pixels, pub descent: Pixels, pub runs: Vec, + pub len: usize, } #[derive(Debug)] diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index cebf546217..8f9538001d 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1655,6 +1655,7 @@ impl<'a, V: 'static> ViewContext<'a, V> { } } + // todo!("change this to return a reference"); pub fn view(&self) -> View { self.view.clone() } diff --git a/crates/text/Cargo.toml b/crates/text/Cargo.toml index d1bc6cc8f8..5a21500b2f 100644 --- a/crates/text/Cargo.toml +++ b/crates/text/Cargo.toml @@ -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 diff --git a/crates/text2/src/selection.rs b/crates/text2/src/selection.rs index 480cb99d74..4bf205dd5d 100644 --- a/crates/text2/src/selection.rs +++ b/crates/text2/src/selection.rs @@ -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)), } diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index 309cf96615..90ebd16f2a 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -104,7 +104,11 @@ pub trait Item: Render + EventEmitter { } fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement; - 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, cx: &AppContext) -> AnyElement; fn project_path(&self, cx: &AppContext) -> Option; 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; fn clone_on_split( @@ -331,7 +339,7 @@ impl ItemHandle for View { 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 ItemHandle for View { 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) }