Eliminate GPUI View, ViewContext, and WindowContext types (#22632)

There's still a bit more work to do on this, but this PR is compiling
(with warnings) after eliminating the key types. When the tasks below
are complete, this will be the new narrative for GPUI:

- `Entity<T>` - This replaces `View<T>`/`Model<T>`. It represents a unit
of state, and if `T` implements `Render`, then `Entity<T>` implements
`Element`.
- `&mut App` This replaces `AppContext` and represents the app.
- `&mut Context<T>` This replaces `ModelContext` and derefs to `App`. It
is provided by the framework when updating an entity.
- `&mut Window` Broken out of `&mut WindowContext` which no longer
exists. Every method that once took `&mut WindowContext` now takes `&mut
Window, &mut App` and every method that took `&mut ViewContext<T>` now
takes `&mut Window, &mut Context<T>`

Not pictured here are the two other failed attempts. It's been quite a
month!

Tasks:

- [x] Remove `View`, `ViewContext`, `WindowContext` and thread through
`Window`
- [x] [@cole-miller @mikayla-maki] Redraw window when entities change
- [x] [@cole-miller @mikayla-maki] Get examples and Zed running
- [x] [@cole-miller @mikayla-maki] Fix Zed rendering
- [x] [@mikayla-maki] Fix todo! macros and comments
- [x] Fix a bug where the editor would not be redrawn because of view
caching
- [x] remove publicness window.notify() and replace with
`AppContext::notify`
- [x] remove `observe_new_window_models`, replace with
`observe_new_models` with an optional window
- [x] Fix a bug where the project panel would not be redrawn because of
the wrong refresh() call being used
- [x] Fix the tests
- [x] Fix warnings by eliminating `Window` params or using `_`
- [x] Fix conflicts
- [x] Simplify generic code where possible
- [x] Rename types
- [ ] Update docs

### issues post merge

- [x] Issues switching between normal and insert mode
- [x] Assistant re-rendering failure
- [x] Vim test failures
- [x] Mac build issue



Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Mikayla <mikayla@zed.dev>
Co-authored-by: Joseph <joseph@zed.dev>
Co-authored-by: max <max@zed.dev>
Co-authored-by: Michael Sloan <michael@zed.dev>
Co-authored-by: Mikayla Maki <mikaylamaki@Mikaylas-MacBook-Pro.local>
Co-authored-by: Mikayla <mikayla.c.maki@gmail.com>
Co-authored-by: joão <joao@zed.dev>
This commit is contained in:
Nathan Sobo 2025-01-25 20:02:45 -07:00 committed by GitHub
parent 21b4a0d50e
commit 6fca1d2b0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
648 changed files with 36248 additions and 28208 deletions

View file

@ -2,8 +2,8 @@ use futures::Future;
use git::blame::BlameEntry;
use git::Oid;
use gpui::{
AppContext, Asset, ClipboardItem, Element, ParentElement, Render, ScrollHandle,
StatefulInteractiveElement, WeakView,
App, Asset, ClipboardItem, Element, ParentElement, Render, ScrollHandle,
StatefulInteractiveElement, WeakEntity,
};
use settings::Settings;
use std::hash::Hash;
@ -27,7 +27,11 @@ impl<'a> CommitAvatar<'a> {
}
impl<'a> CommitAvatar<'a> {
fn render(&'a self, cx: &mut ViewContext<BlameEntryTooltip>) -> Option<impl IntoElement> {
fn render(
&'a self,
window: &mut Window,
cx: &mut Context<BlameEntryTooltip>,
) -> Option<impl IntoElement> {
let remote = self
.details
.and_then(|details| details.remote.as_ref())
@ -35,7 +39,7 @@ impl<'a> CommitAvatar<'a> {
let avatar_url = CommitAvatarAsset::new(remote.clone(), self.sha);
let element = match cx.use_asset::<CommitAvatarAsset>(&avatar_url) {
let element = match window.use_asset::<CommitAvatarAsset>(&avatar_url, cx) {
// Loading or no avatar found
None | Some(None) => Icon::new(IconName::Person)
.color(Color::Muted)
@ -73,7 +77,7 @@ impl Asset for CommitAvatarAsset {
fn load(
source: Self::Source,
cx: &mut AppContext,
cx: &mut App,
) -> impl Future<Output = Self::Output> + Send + 'static {
let client = cx.http_client();
@ -91,7 +95,7 @@ pub(crate) struct BlameEntryTooltip {
blame_entry: BlameEntry,
details: Option<CommitDetails>,
editor_style: EditorStyle,
workspace: Option<WeakView<Workspace>>,
workspace: Option<WeakEntity<Workspace>>,
scroll_handle: ScrollHandle,
}
@ -100,7 +104,7 @@ impl BlameEntryTooltip {
blame_entry: BlameEntry,
details: Option<CommitDetails>,
style: &EditorStyle,
workspace: Option<WeakView<Workspace>>,
workspace: Option<WeakEntity<Workspace>>,
) -> Self {
Self {
editor_style: style.clone(),
@ -113,8 +117,9 @@ impl BlameEntryTooltip {
}
impl Render for BlameEntryTooltip {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let avatar = CommitAvatar::new(self.details.as_ref(), self.blame_entry.sha).render(cx);
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let avatar =
CommitAvatar::new(self.details.as_ref(), self.blame_entry.sha).render(window, cx);
let author = self
.blame_entry
@ -149,11 +154,11 @@ impl Render for BlameEntryTooltip {
.and_then(|details| details.pull_request.clone());
let ui_font_size = ThemeSettings::get_global(cx).ui_font_size;
let message_max_height = cx.line_height() * 12 + (ui_font_size / 0.4);
let message_max_height = window.line_height() * 12 + (ui_font_size / 0.4);
tooltip_container(cx, move |this, cx| {
tooltip_container(window, cx, move |this, _, cx| {
this.occlude()
.on_mouse_move(|_, cx| cx.stop_propagation())
.on_mouse_move(|_, _, cx| cx.stop_propagation())
.child(
v_flex()
.w(gpui::rems(30.))
@ -208,7 +213,7 @@ impl Render for BlameEntryTooltip {
.icon_color(Color::Muted)
.icon_position(IconPosition::Start)
.style(ButtonStyle::Subtle)
.on_click(move |_, cx| {
.on_click(move |_, _, cx| {
cx.stop_propagation();
cx.open_url(pr.url.as_str())
}),
@ -235,7 +240,7 @@ impl Render for BlameEntryTooltip {
.as_ref()
.and_then(|details| details.permalink.clone()),
|this, url| {
this.on_click(move |_, cx| {
this.on_click(move |_, _, cx| {
cx.stop_propagation();
cx.open_url(url.as_str())
})
@ -247,7 +252,7 @@ impl Render for BlameEntryTooltip {
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
.on_click(move |_, cx| {
.on_click(move |_, _, cx| {
cx.stop_propagation();
cx.write_to_clipboard(
ClipboardItem::new_string(full_sha.clone()),

View file

@ -1,5 +1,5 @@
use crate::EditorSettings;
use gpui::ModelContext;
use gpui::Context;
use settings::Settings;
use settings::SettingsStore;
use smol::Timer;
@ -15,7 +15,7 @@ pub struct BlinkManager {
}
impl BlinkManager {
pub fn new(blink_interval: Duration, cx: &mut ModelContext<Self>) -> Self {
pub fn new(blink_interval: Duration, cx: &mut Context<Self>) -> Self {
// Make sure we blink the cursors if the setting is re-enabled
cx.observe_global::<SettingsStore>(move |this, cx| {
this.blink_cursors(this.blink_epoch, cx)
@ -37,7 +37,7 @@ impl BlinkManager {
self.blink_epoch
}
pub fn pause_blinking(&mut self, cx: &mut ModelContext<Self>) {
pub fn pause_blinking(&mut self, cx: &mut Context<Self>) {
self.show_cursor(cx);
let epoch = self.next_blink_epoch();
@ -49,14 +49,14 @@ impl BlinkManager {
.detach();
}
fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ModelContext<Self>) {
fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut Context<Self>) {
if epoch == self.blink_epoch {
self.blinking_paused = false;
self.blink_cursors(epoch, cx);
}
}
fn blink_cursors(&mut self, epoch: usize, cx: &mut ModelContext<Self>) {
fn blink_cursors(&mut self, epoch: usize, cx: &mut Context<Self>) {
if EditorSettings::get_global(cx).cursor_blink {
if epoch == self.blink_epoch && self.enabled && !self.blinking_paused {
self.visible = !self.visible;
@ -78,14 +78,14 @@ impl BlinkManager {
}
}
pub fn show_cursor(&mut self, cx: &mut ModelContext<'_, BlinkManager>) {
pub fn show_cursor(&mut self, cx: &mut Context<'_, BlinkManager>) {
if !self.visible {
self.visible = true;
cx.notify();
}
}
pub fn enable(&mut self, cx: &mut ModelContext<Self>) {
pub fn enable(&mut self, cx: &mut Context<Self>) {
if self.enabled {
return;
}
@ -97,7 +97,7 @@ impl BlinkManager {
self.blink_cursors(self.blink_epoch, cx);
}
pub fn disable(&mut self, _cx: &mut ModelContext<Self>) {
pub fn disable(&mut self, _cx: &mut Context<Self>) {
self.visible = false;
self.enabled = false;
}

View file

@ -1,5 +1,5 @@
use anyhow::Context as _;
use gpui::{View, ViewContext, WindowContext};
use gpui::{App, Context, Entity, Window};
use language::Language;
use url::Url;
@ -16,7 +16,8 @@ fn is_c_language(language: &Language) -> bool {
pub fn switch_source_header(
editor: &mut Editor,
_: &SwitchSourceHeader,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let Some(project) = &editor.project else {
return;
@ -49,7 +50,7 @@ pub fn switch_source_header(
cx,
)
});
cx.spawn(|_editor, mut cx| async move {
cx.spawn_in(window, |_editor, mut cx| async move {
let switch_source_header = switch_source_header_task
.await
.with_context(|| format!("Switch source/header LSP request for path \"{source_file}\" failed"))?;
@ -70,8 +71,8 @@ pub fn switch_source_header(
})?;
workspace
.update(&mut cx, |workspace, view_cx| {
workspace.open_abs_path(path, false, view_cx)
.update_in(&mut cx, |workspace, window, cx| {
workspace.open_abs_path(path, false, window, cx)
})
.with_context(|| {
format!(
@ -84,11 +85,11 @@ pub fn switch_source_header(
.detach_and_log_err(cx);
}
pub fn apply_related_actions(editor: &View<Editor>, cx: &mut WindowContext) {
pub fn apply_related_actions(editor: &Entity<Editor>, window: &mut Window, cx: &mut App) {
if editor.update(cx, |e, cx| {
find_specific_language_server_in_selection(e, cx, is_c_language, CLANGD_SERVER_NAME)
.is_some()
}) {
register_action(editor, cx, switch_source_header);
register_action(editor, window, switch_source_header);
}
}

View file

@ -1,8 +1,8 @@
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
div, pulsating_between, px, uniform_list, Animation, AnimationExt, AnyElement,
BackgroundExecutor, Div, FontWeight, ListSizingBehavior, Model, ScrollStrategy, SharedString,
Size, StrikethroughStyle, StyledText, UniformListScrollHandle, ViewContext, WeakView,
BackgroundExecutor, Div, Entity, FontWeight, ListSizingBehavior, ScrollStrategy, SharedString,
Size, StrikethroughStyle, StyledText, UniformListScrollHandle, WeakEntity,
};
use language::Buffer;
use language::{CodeLabel, Documentation};
@ -46,7 +46,7 @@ impl CodeContextMenu {
pub fn select_first(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> bool {
if self.visible() {
match self {
@ -62,7 +62,7 @@ impl CodeContextMenu {
pub fn select_prev(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> bool {
if self.visible() {
match self {
@ -78,7 +78,7 @@ impl CodeContextMenu {
pub fn select_next(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> bool {
if self.visible() {
match self {
@ -94,7 +94,7 @@ impl CodeContextMenu {
pub fn select_last(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> bool {
if self.visible() {
match self {
@ -126,14 +126,15 @@ impl CodeContextMenu {
style: &EditorStyle,
max_height_in_lines: u32,
y_flipped: bool,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> AnyElement {
match self {
CodeContextMenu::Completions(menu) => {
menu.render(style, max_height_in_lines, y_flipped, cx)
menu.render(style, max_height_in_lines, y_flipped, window, cx)
}
CodeContextMenu::CodeActions(menu) => {
menu.render(style, max_height_in_lines, y_flipped, cx)
menu.render(style, max_height_in_lines, y_flipped, window, cx)
}
}
}
@ -142,8 +143,8 @@ impl CodeContextMenu {
&self,
style: &EditorStyle,
max_size: Size<Pixels>,
workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>,
workspace: Option<WeakEntity<Workspace>>,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {
match self {
CodeContextMenu::Completions(menu) => menu.render_aside(style, max_size, workspace, cx),
@ -162,7 +163,7 @@ pub struct CompletionsMenu {
pub id: CompletionId,
sort_completions: bool,
pub initial_position: Anchor,
pub buffer: Model<Buffer>,
pub buffer: Entity<Buffer>,
pub completions: Rc<RefCell<Box<[Completion]>>>,
match_candidates: Rc<[StringMatchCandidate]>,
pub entries: Rc<RefCell<Vec<CompletionEntry>>>,
@ -185,7 +186,7 @@ impl CompletionsMenu {
sort_completions: bool,
show_completion_documentation: bool,
initial_position: Anchor,
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
completions: Box<[Completion]>,
) -> Self {
let match_candidates = completions
@ -215,7 +216,7 @@ impl CompletionsMenu {
sort_completions: bool,
choices: &Vec<String>,
selection: Range<Anchor>,
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
) -> Self {
let completions = choices
.iter()
@ -271,7 +272,7 @@ impl CompletionsMenu {
fn select_first(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
let index = if self.scroll_handle.y_flipped() {
self.entries.borrow().len() - 1
@ -281,11 +282,7 @@ impl CompletionsMenu {
self.update_selection_index(index, provider, cx);
}
fn select_last(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
) {
fn select_last(&mut self, provider: Option<&dyn CompletionProvider>, cx: &mut Context<Editor>) {
let index = if self.scroll_handle.y_flipped() {
0
} else {
@ -294,11 +291,7 @@ impl CompletionsMenu {
self.update_selection_index(index, provider, cx);
}
fn select_prev(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
) {
fn select_prev(&mut self, provider: Option<&dyn CompletionProvider>, cx: &mut Context<Editor>) {
let index = if self.scroll_handle.y_flipped() {
self.next_match_index()
} else {
@ -307,11 +300,7 @@ impl CompletionsMenu {
self.update_selection_index(index, provider, cx);
}
fn select_next(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
) {
fn select_next(&mut self, provider: Option<&dyn CompletionProvider>, cx: &mut Context<Editor>) {
let index = if self.scroll_handle.y_flipped() {
self.prev_match_index()
} else {
@ -324,7 +313,7 @@ impl CompletionsMenu {
&mut self,
match_index: usize,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
if self.selected_item != match_index {
self.selected_item = match_index;
@ -372,7 +361,7 @@ impl CompletionsMenu {
pub fn resolve_visible_completions(
&mut self,
provider: Option<&dyn CompletionProvider>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
if !self.resolve_completions {
return;
@ -469,7 +458,8 @@ impl CompletionsMenu {
style: &EditorStyle,
max_height_in_lines: u32,
y_flipped: bool,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> AnyElement {
let completions = self.completions.borrow_mut();
let show_completion_documentation = self.show_completion_documentation;
@ -505,10 +495,10 @@ impl CompletionsMenu {
let last_rendered_range = self.last_rendered_range.clone();
let style = style.clone();
let list = uniform_list(
cx.view().clone(),
cx.model().clone(),
"completions",
self.entries.borrow().len(),
move |_editor, range, cx| {
move |_editor, range, _window, cx| {
last_rendered_range.borrow_mut().replace(range.clone());
let start_ix = range.start;
let completions_guard = completions.borrow_mut();
@ -591,12 +581,13 @@ impl CompletionsMenu {
ListItem::new(mat.candidate_id)
.inset(true)
.toggle_state(item_ix == selected_item)
.on_click(cx.listener(move |editor, _event, cx| {
.on_click(cx.listener(move |editor, _event, window, cx| {
cx.stop_propagation();
if let Some(task) = editor.confirm_completion(
&ConfirmCompletion {
item_ix: Some(item_ix),
},
window,
cx,
) {
task.detach_and_log_err(cx)
@ -659,9 +650,9 @@ impl CompletionsMenu {
.with_highlights(&style.text, None),
),
)
.on_click(cx.listener(move |editor, _event, cx| {
.on_click(cx.listener(move |editor, _event, window, cx| {
cx.stop_propagation();
editor.toggle_zed_predict_tos(cx);
editor.toggle_zed_predict_tos(window, cx);
})),
),
@ -678,10 +669,11 @@ impl CompletionsMenu {
.with_highlights(&style.text, None),
),
)
.on_click(cx.listener(move |editor, _event, cx| {
.on_click(cx.listener(move |editor, _event, window, cx| {
cx.stop_propagation();
editor.accept_inline_completion(
&AcceptInlineCompletion {},
window,
cx,
);
})),
@ -692,7 +684,7 @@ impl CompletionsMenu {
},
)
.occlude()
.max_h(max_height_in_lines as f32 * cx.line_height())
.max_h(max_height_in_lines as f32 * window.line_height())
.track_scroll(self.scroll_handle.clone())
.y_flipped(y_flipped)
.with_width_from_item(widest_completion_ix)
@ -705,8 +697,8 @@ impl CompletionsMenu {
&self,
style: &EditorStyle,
max_size: Size<Pixels>,
workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>,
workspace: Option<WeakEntity<Workspace>>,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {
if !self.show_completion_documentation {
return None;
@ -1008,14 +1000,14 @@ impl CodeActionsItem {
pub struct CodeActionsMenu {
pub actions: CodeActionContents,
pub buffer: Model<Buffer>,
pub buffer: Entity<Buffer>,
pub selected_item: usize,
pub scroll_handle: UniformListScrollHandle,
pub deployed_from_indicator: Option<DisplayRow>,
}
impl CodeActionsMenu {
fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
fn select_first(&mut self, cx: &mut Context<Editor>) {
self.selected_item = if self.scroll_handle.y_flipped() {
self.actions.len() - 1
} else {
@ -1026,7 +1018,7 @@ impl CodeActionsMenu {
cx.notify()
}
fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
fn select_last(&mut self, cx: &mut Context<Editor>) {
self.selected_item = if self.scroll_handle.y_flipped() {
0
} else {
@ -1037,7 +1029,7 @@ impl CodeActionsMenu {
cx.notify()
}
fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
fn select_prev(&mut self, cx: &mut Context<Editor>) {
self.selected_item = if self.scroll_handle.y_flipped() {
self.next_match_index()
} else {
@ -1048,7 +1040,7 @@ impl CodeActionsMenu {
cx.notify();
}
fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
fn select_next(&mut self, cx: &mut Context<Editor>) {
self.selected_item = if self.scroll_handle.y_flipped() {
self.prev_match_index()
} else {
@ -1092,15 +1084,16 @@ impl CodeActionsMenu {
_style: &EditorStyle,
max_height_in_lines: u32,
y_flipped: bool,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> AnyElement {
let actions = self.actions.clone();
let selected_item = self.selected_item;
let list = uniform_list(
cx.view().clone(),
cx.model().clone(),
"code_actions_menu",
self.actions.len(),
move |_this, range, cx| {
move |_this, range, _, cx| {
actions
.iter()
.skip(range.start)
@ -1115,12 +1108,13 @@ impl CodeActionsMenu {
.inset(true)
.toggle_state(selected)
.when_some(action.as_code_action(), |this, action| {
this.on_click(cx.listener(move |editor, _, cx| {
this.on_click(cx.listener(move |editor, _, window, cx| {
cx.stop_propagation();
if let Some(task) = editor.confirm_code_action(
&ConfirmCodeAction {
item_ix: Some(item_ix),
},
window,
cx,
) {
task.detach_and_log_err(cx)
@ -1139,12 +1133,13 @@ impl CodeActionsMenu {
)
})
.when_some(action.as_task(), |this, task| {
this.on_click(cx.listener(move |editor, _, cx| {
this.on_click(cx.listener(move |editor, _, window, cx| {
cx.stop_propagation();
if let Some(task) = editor.confirm_code_action(
&ConfirmCodeAction {
item_ix: Some(item_ix),
},
window,
cx,
) {
task.detach_and_log_err(cx)
@ -1165,7 +1160,7 @@ impl CodeActionsMenu {
},
)
.occlude()
.max_h(max_height_in_lines as f32 * cx.line_height())
.max_h(max_height_in_lines as f32 * window.line_height())
.track_scroll(self.scroll_handle.clone())
.y_flipped(y_flipped)
.with_width_from_item(

View file

@ -39,10 +39,7 @@ use collections::{HashMap, HashSet};
pub use crease_map::*;
pub use fold_map::{Fold, FoldId, FoldPlaceholder, FoldPoint};
use fold_map::{FoldMap, FoldSnapshot};
use gpui::{
AnyElement, AppContext, Font, HighlightStyle, LineLayout, Model, ModelContext, Pixels,
UnderlineStyle,
};
use gpui::{App, Context, Entity, Font, HighlightStyle, LineLayout, Pixels, UnderlineStyle};
pub use inlay_map::Inlay;
use inlay_map::{InlayMap, InlaySnapshot};
pub use inlay_map::{InlayOffset, InlayPoint};
@ -69,7 +66,7 @@ use std::{
use sum_tree::{Bias, TreeMap};
use tab_map::{TabMap, TabSnapshot};
use text::{BufferId, LineIndent};
use ui::{px, SharedString, WindowContext};
use ui::{px, SharedString};
use unicode_segmentation::UnicodeSegmentation;
use wrap_map::{WrapMap, WrapSnapshot};
@ -79,8 +76,6 @@ pub enum FoldStatus {
Foldable,
}
pub type RenderFoldToggle = Arc<dyn Fn(FoldStatus, &mut WindowContext) -> AnyElement>;
pub trait ToDisplayPoint {
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint;
}
@ -94,7 +89,7 @@ type InlayHighlights = TreeMap<TypeId, TreeMap<InlayId, (HighlightStyle, InlayHi
/// See the [module level documentation](self) for more information.
pub struct DisplayMap {
/// The buffer that we are displaying.
buffer: Model<MultiBuffer>,
buffer: Entity<MultiBuffer>,
buffer_subscription: BufferSubscription,
/// Decides where the [`Inlay`]s should be displayed.
inlay_map: InlayMap,
@ -103,7 +98,7 @@ pub struct DisplayMap {
/// Keeps track of hard tabs in a buffer.
tab_map: TabMap,
/// Handles soft wrapping.
wrap_map: Model<WrapMap>,
wrap_map: Entity<WrapMap>,
/// Tracks custom blocks such as diagnostics that should be displayed within buffer.
block_map: BlockMap,
/// Regions of text that should be highlighted.
@ -120,7 +115,7 @@ pub struct DisplayMap {
impl DisplayMap {
#[allow(clippy::too_many_arguments)]
pub fn new(
buffer: Model<MultiBuffer>,
buffer: Entity<MultiBuffer>,
font: Font,
font_size: Pixels,
wrap_width: Option<Pixels>,
@ -129,7 +124,7 @@ impl DisplayMap {
excerpt_header_height: u32,
excerpt_footer_height: u32,
fold_placeholder: FoldPlaceholder,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> Self {
let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@ -167,7 +162,7 @@ impl DisplayMap {
}
}
pub fn snapshot(&mut self, cx: &mut ModelContext<Self>) -> DisplaySnapshot {
pub fn snapshot(&mut self, cx: &mut Context<Self>) -> DisplaySnapshot {
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
@ -195,7 +190,7 @@ impl DisplayMap {
}
}
pub fn set_state(&mut self, other: &DisplaySnapshot, cx: &mut ModelContext<Self>) {
pub fn set_state(&mut self, other: &DisplaySnapshot, cx: &mut Context<Self>) {
self.fold(
other
.folds_in_range(0..other.buffer_snapshot.len())
@ -211,11 +206,7 @@ impl DisplayMap {
}
/// Creates folds for the given creases.
pub fn fold<T: Clone + ToOffset>(
&mut self,
creases: Vec<Crease<T>>,
cx: &mut ModelContext<Self>,
) {
pub fn fold<T: Clone + ToOffset>(&mut self, creases: Vec<Crease<T>>, cx: &mut Context<Self>) {
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
@ -287,7 +278,7 @@ impl DisplayMap {
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
type_id: TypeId,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
@ -312,7 +303,7 @@ impl DisplayMap {
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
inclusive: bool,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let offset_ranges = ranges
@ -339,7 +330,7 @@ impl DisplayMap {
block_map.remove_intersecting_replace_blocks(offset_ranges, inclusive);
}
pub fn fold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut ModelContext<Self>) {
pub fn fold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut Context<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
@ -353,7 +344,7 @@ impl DisplayMap {
block_map.fold_buffer(buffer_id, self.buffer.read(cx), cx)
}
pub fn unfold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut ModelContext<Self>) {
pub fn unfold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut Context<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
@ -378,7 +369,7 @@ impl DisplayMap {
pub fn insert_creases(
&mut self,
creases: impl IntoIterator<Item = Crease<Anchor>>,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> Vec<CreaseId> {
let snapshot = self.buffer.read(cx).snapshot(cx);
self.crease_map.insert(creases, &snapshot)
@ -387,7 +378,7 @@ impl DisplayMap {
pub fn remove_creases(
&mut self,
crease_ids: impl IntoIterator<Item = CreaseId>,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) {
let snapshot = self.buffer.read(cx).snapshot(cx);
self.crease_map.remove(crease_ids, &snapshot)
@ -396,7 +387,7 @@ impl DisplayMap {
pub fn insert_blocks(
&mut self,
blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> Vec<CustomBlockId> {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
@ -411,11 +402,7 @@ impl DisplayMap {
block_map.insert(blocks)
}
pub fn resize_blocks(
&mut self,
heights: HashMap<CustomBlockId, u32>,
cx: &mut ModelContext<Self>,
) {
pub fn resize_blocks(&mut self, heights: HashMap<CustomBlockId, u32>, cx: &mut Context<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
@ -433,7 +420,7 @@ impl DisplayMap {
self.block_map.replace_blocks(renderers);
}
pub fn remove_blocks(&mut self, ids: HashSet<CustomBlockId>, cx: &mut ModelContext<Self>) {
pub fn remove_blocks(&mut self, ids: HashSet<CustomBlockId>, cx: &mut Context<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
@ -450,7 +437,7 @@ impl DisplayMap {
pub fn row_for_block(
&mut self,
block_id: CustomBlockId,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> Option<DisplayRow> {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
@ -505,12 +492,12 @@ impl DisplayMap {
cleared
}
pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut ModelContext<Self>) -> bool {
pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut Context<Self>) -> bool {
self.wrap_map
.update(cx, |map, cx| map.set_font_with_size(font, font_size, cx))
}
pub fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut ModelContext<Self>) -> bool {
pub fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut Context<Self>) -> bool {
self.wrap_map
.update(cx, |map, cx| map.set_wrap_width(width, cx))
}
@ -523,7 +510,7 @@ impl DisplayMap {
&mut self,
to_remove: Vec<InlayId>,
to_insert: Vec<Inlay>,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) {
if to_remove.is_empty() && to_insert.is_empty() {
return;
@ -548,7 +535,7 @@ impl DisplayMap {
self.block_map.read(snapshot, edits);
}
fn tab_size(buffer: &Model<MultiBuffer>, cx: &AppContext) -> NonZeroU32 {
fn tab_size(buffer: &Entity<MultiBuffer>, cx: &App) -> NonZeroU32 {
let buffer = buffer.read(cx).as_singleton().map(|buffer| buffer.read(cx));
let language = buffer
.and_then(|buffer| buffer.language())
@ -558,7 +545,7 @@ impl DisplayMap {
}
#[cfg(test)]
pub fn is_rewrapping(&self, cx: &gpui::AppContext) -> bool {
pub fn is_rewrapping(&self, cx: &gpui::App) -> bool {
self.wrap_map.read(cx).is_rewrapping()
}
@ -1452,7 +1439,7 @@ pub mod tests {
use crate::{movement, test::marked_display_snapshot};
use block_map::BlockPlacement;
use gpui::{
div, font, observe, px, AppContext, BorrowAppContext, Context, Element, Hsla, Rgba,
div, font, observe, px, App, AppContext as _, BorrowAppContext, Element, Hsla, Rgba,
};
use language::{
language_settings::{AllLanguageSettings, AllLanguageSettingsContent},
@ -1508,7 +1495,7 @@ pub mod tests {
}
});
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer.clone(),
font("Helvetica"),
@ -1749,16 +1736,16 @@ pub mod tests {
let editor = cx.editor.clone();
let window = cx.window;
_ = cx.update_window(window, |_, cx| {
_ = cx.update_window(window, |_, window, cx| {
let text_layout_details =
editor.update(cx, |editor, cx| editor.text_layout_details(cx));
editor.update(cx, |editor, _cx| editor.text_layout_details(window));
let font_size = px(12.0);
let wrap_width = Some(px(64.));
let text = "one two three four five\nsix seven eight";
let buffer = MultiBuffer::build_simple(text, cx);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer.clone(),
font("Helvetica"),
@ -1862,14 +1849,14 @@ pub mod tests {
}
#[gpui::test]
fn test_text_chunks(cx: &mut gpui::AppContext) {
fn test_text_chunks(cx: &mut gpui::App) {
init_test(cx, |_| {});
let text = sample_text(6, 6, 'a');
let buffer = MultiBuffer::build_simple(&text, cx);
let font_size = px(14.0);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer.clone(),
font("Helvetica"),
@ -1959,13 +1946,13 @@ pub mod tests {
cx.update(|cx| init_test(cx, |s| s.defaults.tab_size = Some(2.try_into().unwrap())));
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx));
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let font_size = px(14.0);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer,
font("Helvetica"),
@ -2062,12 +2049,12 @@ pub mod tests {
cx.update(|cx| init_test(cx, |_| {}));
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx));
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer,
font("Courier"),
@ -2136,7 +2123,7 @@ pub mod tests {
cx.update(|cx| init_test(cx, |_| {}));
let buffer = cx.new_model(|cx| Buffer::local(text, cx));
let buffer = cx.new(|cx| Buffer::local(text, cx));
buffer.update(cx, |buffer, cx| {
buffer.update_diagnostics(
@ -2157,10 +2144,10 @@ pub mod tests {
)
});
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer,
font("Courier"),
@ -2249,7 +2236,7 @@ pub mod tests {
let buffer = cx.update(|cx| MultiBuffer::build_simple("abcde\nfghij\nklmno\npqrst", cx));
let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer.clone(),
font("Courier"),
@ -2387,13 +2374,13 @@ pub mod tests {
cx.update(|cx| init_test(cx, |_| {}));
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx));
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let font_size = px(16.0);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer,
font("Courier"),
@ -2470,14 +2457,14 @@ pub mod tests {
let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false);
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx));
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
let font_size = px(16.0);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer,
font("Courier"),
@ -2528,10 +2515,10 @@ pub mod tests {
}
#[gpui::test]
fn test_clip_point(cx: &mut gpui::AppContext) {
fn test_clip_point(cx: &mut gpui::App) {
init_test(cx, |_| {});
fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::AppContext) {
fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::App) {
let (unmarked_snapshot, mut markers) = marked_display_snapshot(text, cx);
match bias {
@ -2578,10 +2565,10 @@ pub mod tests {
}
#[gpui::test]
fn test_clip_at_line_ends(cx: &mut gpui::AppContext) {
fn test_clip_at_line_ends(cx: &mut gpui::App) {
init_test(cx, |_| {});
fn assert(text: &str, cx: &mut gpui::AppContext) {
fn assert(text: &str, cx: &mut gpui::App) {
let (mut unmarked_snapshot, markers) = marked_display_snapshot(text, cx);
unmarked_snapshot.clip_at_line_ends = true;
assert_eq!(
@ -2597,13 +2584,13 @@ pub mod tests {
}
#[gpui::test]
fn test_creases(cx: &mut gpui::AppContext) {
fn test_creases(cx: &mut gpui::App) {
init_test(cx, |_| {});
let text = "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll";
let buffer = MultiBuffer::build_simple(text, cx);
let font_size = px(14.0);
cx.new_model(|cx| {
cx.new(|cx| {
let mut map = DisplayMap::new(
buffer.clone(),
font("Helvetica"),
@ -2624,8 +2611,8 @@ pub mod tests {
[Crease::inline(
range,
FoldPlaceholder::test(),
|_row, _status, _toggle, _cx| div(),
|_row, _status, _cx| div(),
|_row, _status, _toggle, _window, _cx| div(),
|_row, _status, _window, _cx| div(),
)],
&map.buffer.read(cx).snapshot(cx),
);
@ -2635,14 +2622,14 @@ pub mod tests {
}
#[gpui::test]
fn test_tabs_with_multibyte_chars(cx: &mut gpui::AppContext) {
fn test_tabs_with_multibyte_chars(cx: &mut gpui::App) {
init_test(cx, |_| {});
let text = "\t\tα\nβ\t\n🏀β\t\tγ";
let buffer = MultiBuffer::build_simple(text, cx);
let font_size = px(14.0);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer.clone(),
font("Helvetica"),
@ -2714,12 +2701,12 @@ pub mod tests {
}
#[gpui::test]
fn test_max_point(cx: &mut gpui::AppContext) {
fn test_max_point(cx: &mut gpui::App) {
init_test(cx, |_| {});
let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx);
let font_size = px(14.0);
let map = cx.new_model(|cx| {
let map = cx.new(|cx| {
DisplayMap::new(
buffer.clone(),
font("Helvetica"),
@ -2741,9 +2728,9 @@ pub mod tests {
fn syntax_chunks(
rows: Range<DisplayRow>,
map: &Model<DisplayMap>,
map: &Entity<DisplayMap>,
theme: &SyntaxTheme,
cx: &mut AppContext,
cx: &mut App,
) -> Vec<(String, Option<Hsla>)> {
chunks(rows, map, theme, cx)
.into_iter()
@ -2753,9 +2740,9 @@ pub mod tests {
fn chunks(
rows: Range<DisplayRow>,
map: &Model<DisplayMap>,
map: &Entity<DisplayMap>,
theme: &SyntaxTheme,
cx: &mut AppContext,
cx: &mut App,
) -> Vec<(String, Option<Hsla>, Option<Hsla>)> {
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
let mut chunks: Vec<(String, Option<Hsla>, Option<Hsla>)> = Vec::new();
@ -2775,7 +2762,7 @@ pub mod tests {
chunks
}
fn init_test(cx: &mut AppContext, f: impl Fn(&mut AllLanguageSettingsContent)) {
fn init_test(cx: &mut App, f: impl Fn(&mut AllLanguageSettingsContent)) {
let settings = SettingsStore::test(cx);
cx.set_global(settings);
language::init(cx);

View file

@ -4,7 +4,7 @@ use super::{
};
use crate::{EditorStyle, GutterDimensions};
use collections::{Bound, HashMap, HashSet};
use gpui::{AnyElement, AppContext, EntityId, Pixels, WindowContext};
use gpui::{AnyElement, App, EntityId, Pixels, Window};
use language::{Chunk, Patch, Point};
use multi_buffer::{
Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, RowInfo,
@ -226,7 +226,8 @@ pub enum BlockStyle {
}
pub struct BlockContext<'a, 'b> {
pub context: &'b mut WindowContext<'a>,
pub window: &'a mut Window,
pub app: &'b mut App,
pub anchor_x: Pixels,
pub max_width: Pixels,
pub gutter_dimensions: &'b GutterDimensions,
@ -1232,22 +1233,12 @@ impl<'a> BlockMapWriter<'a> {
self.remove(blocks_to_remove);
}
pub fn fold_buffer(
&mut self,
buffer_id: BufferId,
multi_buffer: &MultiBuffer,
cx: &AppContext,
) {
pub fn fold_buffer(&mut self, buffer_id: BufferId, multi_buffer: &MultiBuffer, cx: &App) {
self.0.folded_buffers.insert(buffer_id);
self.recompute_blocks_for_buffer(buffer_id, multi_buffer, cx);
}
pub fn unfold_buffer(
&mut self,
buffer_id: BufferId,
multi_buffer: &MultiBuffer,
cx: &AppContext,
) {
pub fn unfold_buffer(&mut self, buffer_id: BufferId, multi_buffer: &MultiBuffer, cx: &App) {
self.0.folded_buffers.remove(&buffer_id);
self.recompute_blocks_for_buffer(buffer_id, multi_buffer, cx);
}
@ -1256,7 +1247,7 @@ impl<'a> BlockMapWriter<'a> {
&mut self,
buffer_id: BufferId,
multi_buffer: &MultiBuffer,
cx: &AppContext,
cx: &App,
) {
let wrap_snapshot = self.0.wrap_snapshot.borrow().clone();
@ -1934,16 +1925,16 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for BlockRow {
}
impl<'a> Deref for BlockContext<'a, '_> {
type Target = WindowContext<'a>;
type Target = App;
fn deref(&self) -> &Self::Target {
self.context
self.app
}
}
impl DerefMut for BlockContext<'_, '_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.context
self.app
}
}
@ -2001,7 +1992,7 @@ mod tests {
use crate::display_map::{
fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap, wrap_map::WrapMap,
};
use gpui::{div, font, px, AppContext, Context as _, Element};
use gpui::{div, font, px, App, AppContext as _, Element};
use itertools::Itertools;
use language::{Buffer, Capability};
use multi_buffer::{ExcerptRange, MultiBuffer};
@ -2195,15 +2186,15 @@ mod tests {
}
#[gpui::test]
fn test_multibuffer_headers_and_footers(cx: &mut AppContext) {
fn test_multibuffer_headers_and_footers(cx: &mut App) {
init_test(cx);
let buffer1 = cx.new_model(|cx| Buffer::local("Buffer 1", cx));
let buffer2 = cx.new_model(|cx| Buffer::local("Buffer 2", cx));
let buffer3 = cx.new_model(|cx| Buffer::local("Buffer 3", cx));
let buffer1 = cx.new(|cx| Buffer::local("Buffer 1", cx));
let buffer2 = cx.new(|cx| Buffer::local("Buffer 2", cx));
let buffer3 = cx.new(|cx| Buffer::local("Buffer 3", cx));
let mut excerpt_ids = Vec::new();
let multi_buffer = cx.new_model(|cx| {
let multi_buffer = cx.new(|cx| {
let mut multi_buffer = MultiBuffer::new(Capability::ReadWrite);
excerpt_ids.extend(multi_buffer.push_excerpts(
buffer1.clone(),
@ -3652,7 +3643,7 @@ mod tests {
}
}
fn init_test(cx: &mut gpui::AppContext) {
fn init_test(cx: &mut gpui::App) {
let settings = SettingsStore::test(cx);
cx.set_global(settings);
theme::init(theme::LoadThemes::JustBase, cx);

View file

@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use std::{cmp::Ordering, fmt::Debug, ops::Range, sync::Arc};
use sum_tree::{Bias, SeekTarget, SumTree};
use text::Point;
use ui::{IconName, SharedString, WindowContext};
use ui::{App, IconName, SharedString, Window};
use crate::{BlockStyle, FoldPlaceholder, RenderBlock};
@ -117,12 +117,13 @@ type RenderToggleFn = Arc<
+ Fn(
MultiBufferRow,
bool,
Arc<dyn Send + Sync + Fn(bool, &mut WindowContext)>,
&mut WindowContext,
Arc<dyn Send + Sync + Fn(bool, &mut Window, &mut App)>,
&mut Window,
&mut App,
) -> AnyElement,
>;
type RenderTrailerFn =
Arc<dyn Send + Sync + Fn(MultiBufferRow, bool, &mut WindowContext) -> AnyElement>;
Arc<dyn Send + Sync + Fn(MultiBufferRow, bool, &mut Window, &mut App) -> AnyElement>;
#[derive(Clone)]
pub enum Crease<T> {
@ -185,26 +186,27 @@ impl<T> Crease<T> {
+ Fn(
MultiBufferRow,
bool,
Arc<dyn Send + Sync + Fn(bool, &mut WindowContext)>,
&mut WindowContext,
Arc<dyn Send + Sync + Fn(bool, &mut Window, &mut App)>,
&mut Window,
&mut App,
) -> ToggleElement
+ 'static,
ToggleElement: IntoElement,
RenderTrailer: 'static
+ Send
+ Sync
+ Fn(MultiBufferRow, bool, &mut WindowContext) -> TrailerElement
+ Fn(MultiBufferRow, bool, &mut Window, &mut App) -> TrailerElement
+ 'static,
TrailerElement: IntoElement,
{
Crease::Inline {
range,
placeholder,
render_toggle: Some(Arc::new(move |row, folded, toggle, cx| {
render_toggle(row, folded, toggle, cx).into_any_element()
render_toggle: Some(Arc::new(move |row, folded, toggle, window, cx| {
render_toggle(row, folded, toggle, window, cx).into_any_element()
})),
render_trailer: Some(Arc::new(move |row, folded, cx| {
render_trailer(row, folded, cx).into_any_element()
render_trailer: Some(Arc::new(move |row, folded, window, cx| {
render_trailer(row, folded, window, cx).into_any_element()
})),
metadata: None,
}
@ -387,11 +389,11 @@ impl SeekTarget<'_, ItemSummary, ItemSummary> for Anchor {
#[cfg(test)]
mod test {
use super::*;
use gpui::{div, AppContext};
use gpui::{div, App};
use multi_buffer::MultiBuffer;
#[gpui::test]
fn test_insert_and_remove_creases(cx: &mut AppContext) {
fn test_insert_and_remove_creases(cx: &mut App) {
let text = "line1\nline2\nline3\nline4\nline5";
let buffer = MultiBuffer::build_simple(text, cx);
let snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
@ -402,14 +404,14 @@ mod test {
Crease::inline(
snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 5)),
FoldPlaceholder::test(),
|_row, _folded, _toggle, _cx| div(),
|_row, _folded, _cx| div(),
|_row, _folded, _toggle, _window, _cx| div(),
|_row, _folded, _window, _cx| div(),
),
Crease::inline(
snapshot.anchor_before(Point::new(3, 0))..snapshot.anchor_after(Point::new(3, 5)),
FoldPlaceholder::test(),
|_row, _folded, _toggle, _cx| div(),
|_row, _folded, _cx| div(),
|_row, _folded, _toggle, _window, _cx| div(),
|_row, _folded, _window, _cx| div(),
),
];
let crease_ids = crease_map.insert(creases, &snapshot);
@ -438,7 +440,7 @@ mod test {
}
#[gpui::test]
fn test_creases_in_range(cx: &mut AppContext) {
fn test_creases_in_range(cx: &mut App) {
let text = "line1\nline2\nline3\nline4\nline5\nline6\nline7";
let buffer = MultiBuffer::build_simple(text, cx);
let snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
@ -448,20 +450,20 @@ mod test {
Crease::inline(
snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 5)),
FoldPlaceholder::test(),
|_row, _folded, _toggle, _cx| div(),
|_row, _folded, _cx| div(),
|_row, _folded, _toggle, _window, _cx| div(),
|_row, _folded, _window, _cx| div(),
),
Crease::inline(
snapshot.anchor_before(Point::new(3, 0))..snapshot.anchor_after(Point::new(3, 5)),
FoldPlaceholder::test(),
|_row, _folded, _toggle, _cx| div(),
|_row, _folded, _cx| div(),
|_row, _folded, _toggle, _window, _cx| div(),
|_row, _folded, _window, _cx| div(),
),
Crease::inline(
snapshot.anchor_before(Point::new(5, 0))..snapshot.anchor_after(Point::new(5, 5)),
FoldPlaceholder::test(),
|_row, _folded, _toggle, _cx| div(),
|_row, _folded, _cx| div(),
|_row, _folded, _toggle, _window, _cx| div(),
|_row, _folded, _window, _cx| div(),
),
];
crease_map.insert(creases, &snapshot);

View file

@ -2,7 +2,7 @@ use super::{
inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
Highlights,
};
use gpui::{AnyElement, ElementId, WindowContext};
use gpui::{AnyElement, App, ElementId, Window};
use language::{Chunk, ChunkRenderer, Edit, Point, TextSummary};
use multi_buffer::{
Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset,
@ -21,7 +21,8 @@ use util::post_inc;
#[derive(Clone)]
pub struct FoldPlaceholder {
/// Creates an element to represent this fold's placeholder.
pub render: Arc<dyn Send + Sync + Fn(FoldId, Range<Anchor>, &mut WindowContext) -> AnyElement>,
pub render:
Arc<dyn Send + Sync + Fn(FoldId, Range<Anchor>, &mut Window, &mut App) -> AnyElement>,
/// If true, the element is constrained to the shaped width of an ellipsis.
pub constrain_width: bool,
/// If true, merges the fold with an adjacent one.
@ -33,7 +34,7 @@ pub struct FoldPlaceholder {
impl Default for FoldPlaceholder {
fn default() -> Self {
Self {
render: Arc::new(|_, _, _| gpui::Empty.into_any_element()),
render: Arc::new(|_, _, _, _| gpui::Empty.into_any_element()),
constrain_width: true,
merge_adjacent: true,
type_tag: None,
@ -45,7 +46,7 @@ impl FoldPlaceholder {
#[cfg(any(test, feature = "test-support"))]
pub fn test() -> Self {
Self {
render: Arc::new(|_id, _range, _cx| gpui::Empty.into_any_element()),
render: Arc::new(|_id, _range, _window, _cx| gpui::Empty.into_any_element()),
constrain_width: true,
merge_adjacent: true,
type_tag: None,
@ -485,7 +486,8 @@ impl FoldMap {
(fold.placeholder.render)(
fold_id,
fold.range.0.clone(),
cx,
cx.window,
cx.context,
)
}),
constrain_width: fold.placeholder.constrain_width,
@ -1395,7 +1397,7 @@ mod tests {
use Bias::{Left, Right};
#[gpui::test]
fn test_basic_folds(cx: &mut gpui::AppContext) {
fn test_basic_folds(cx: &mut gpui::App) {
init_test(cx);
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@ -1474,7 +1476,7 @@ mod tests {
}
#[gpui::test]
fn test_adjacent_folds(cx: &mut gpui::AppContext) {
fn test_adjacent_folds(cx: &mut gpui::App) {
init_test(cx);
let buffer = MultiBuffer::build_simple("abcdefghijkl", cx);
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@ -1533,7 +1535,7 @@ mod tests {
}
#[gpui::test]
fn test_overlapping_folds(cx: &mut gpui::AppContext) {
fn test_overlapping_folds(cx: &mut gpui::App) {
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx);
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
@ -1550,7 +1552,7 @@ mod tests {
}
#[gpui::test]
fn test_merging_folds_via_edit(cx: &mut gpui::AppContext) {
fn test_merging_folds_via_edit(cx: &mut gpui::App) {
init_test(cx);
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@ -1577,7 +1579,7 @@ mod tests {
}
#[gpui::test]
fn test_folds_in_range(cx: &mut gpui::AppContext) {
fn test_folds_in_range(cx: &mut gpui::App) {
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx);
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
@ -1608,7 +1610,7 @@ mod tests {
}
#[gpui::test(iterations = 100)]
fn test_random_folds(cx: &mut gpui::AppContext, mut rng: StdRng) {
fn test_random_folds(cx: &mut gpui::App, mut rng: StdRng) {
init_test(cx);
let operations = env::var("OPERATIONS")
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
@ -1879,7 +1881,7 @@ mod tests {
}
#[gpui::test]
fn test_buffer_rows(cx: &mut gpui::AppContext) {
fn test_buffer_rows(cx: &mut gpui::App) {
let text = sample_text(6, 6, 'a') + "\n";
let buffer = MultiBuffer::build_simple(&text, cx);
@ -1911,7 +1913,7 @@ mod tests {
);
}
fn init_test(cx: &mut gpui::AppContext) {
fn init_test(cx: &mut gpui::App) {
let store = SettingsStore::test(cx);
cx.set_global(store);
}

View file

@ -1070,7 +1070,7 @@ mod tests {
hover_links::InlayHighlight,
InlayId, MultiBuffer,
};
use gpui::{AppContext, HighlightStyle};
use gpui::{App, HighlightStyle};
use project::{InlayHint, InlayHintLabel, ResolveState};
use rand::prelude::*;
use settings::SettingsStore;
@ -1163,7 +1163,7 @@ mod tests {
}
#[gpui::test]
fn test_basic_inlays(cx: &mut AppContext) {
fn test_basic_inlays(cx: &mut App) {
let buffer = MultiBuffer::build_simple("abcdefghi", cx);
let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
@ -1451,7 +1451,7 @@ mod tests {
}
#[gpui::test]
fn test_inlay_buffer_rows(cx: &mut AppContext) {
fn test_inlay_buffer_rows(cx: &mut App) {
let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx);
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi");
@ -1488,7 +1488,7 @@ mod tests {
}
#[gpui::test(iterations = 100)]
fn test_random_inlays(cx: &mut AppContext, mut rng: StdRng) {
fn test_random_inlays(cx: &mut App, mut rng: StdRng) {
init_test(cx);
let operations = env::var("OPERATIONS")
@ -1792,7 +1792,7 @@ mod tests {
}
}
fn init_test(cx: &mut AppContext) {
fn init_test(cx: &mut App) {
let store = SettingsStore::test(cx);
cx.set_global(store);
theme::init(theme::LoadThemes::JustBase, cx);

View file

@ -608,7 +608,7 @@ mod tests {
use rand::{prelude::StdRng, Rng};
#[gpui::test]
fn test_expand_tabs(cx: &mut gpui::AppContext) {
fn test_expand_tabs(cx: &mut gpui::App) {
let buffer = MultiBuffer::build_simple("", cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx);
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
@ -621,7 +621,7 @@ mod tests {
}
#[gpui::test]
fn test_long_lines(cx: &mut gpui::AppContext) {
fn test_long_lines(cx: &mut gpui::App) {
let max_expansion_column = 12;
let input = "A\tBC\tDEF\tG\tHI\tJ\tK\tL\tM";
let output = "A BC DEF G HI J K L M";
@ -669,7 +669,7 @@ mod tests {
}
#[gpui::test]
fn test_long_lines_with_character_spanning_max_expansion_column(cx: &mut gpui::AppContext) {
fn test_long_lines_with_character_spanning_max_expansion_column(cx: &mut gpui::App) {
let max_expansion_column = 8;
let input = "abcdefg⋯hij";
@ -684,7 +684,7 @@ mod tests {
}
#[gpui::test]
fn test_marking_tabs(cx: &mut gpui::AppContext) {
fn test_marking_tabs(cx: &mut gpui::App) {
let input = "\t \thello";
let buffer = MultiBuffer::build_simple(input, cx);
@ -735,7 +735,7 @@ mod tests {
}
#[gpui::test(iterations = 100)]
fn test_random_tabs(cx: &mut gpui::AppContext, mut rng: StdRng) {
fn test_random_tabs(cx: &mut gpui::App, mut rng: StdRng) {
let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
let len = rng.gen_range(0..30);
let buffer = if rng.gen() {

View file

@ -3,7 +3,7 @@ use super::{
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
Highlights,
};
use gpui::{AppContext, Context, Font, LineWrapper, Model, ModelContext, Pixels, Task};
use gpui::{App, AppContext as _, Context, Entity, Font, LineWrapper, Pixels, Task};
use language::{Chunk, Point};
use multi_buffer::{MultiBufferSnapshot, RowInfo};
use smol::future::yield_now;
@ -90,9 +90,9 @@ impl WrapMap {
font: Font,
font_size: Pixels,
wrap_width: Option<Pixels>,
cx: &mut AppContext,
) -> (Model<Self>, WrapSnapshot) {
let handle = cx.new_model(|cx| {
cx: &mut App,
) -> (Entity<Self>, WrapSnapshot) {
let handle = cx.new(|cx| {
let mut this = Self {
font_with_size: (font, font_size),
wrap_width: None,
@ -119,7 +119,7 @@ impl WrapMap {
&mut self,
tab_snapshot: TabSnapshot,
edits: Vec<TabEdit>,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> (WrapSnapshot, Patch<u32>) {
if self.wrap_width.is_some() {
self.pending_edits.push_back((tab_snapshot, edits));
@ -138,7 +138,7 @@ impl WrapMap {
&mut self,
font: Font,
font_size: Pixels,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> bool {
let font_with_size = (font, font_size);
@ -151,11 +151,7 @@ impl WrapMap {
}
}
pub fn set_wrap_width(
&mut self,
wrap_width: Option<Pixels>,
cx: &mut ModelContext<Self>,
) -> bool {
pub fn set_wrap_width(&mut self, wrap_width: Option<Pixels>, cx: &mut Context<Self>) -> bool {
if wrap_width == self.wrap_width {
return false;
}
@ -165,7 +161,7 @@ impl WrapMap {
true
}
fn rewrap(&mut self, cx: &mut ModelContext<Self>) {
fn rewrap(&mut self, cx: &mut Context<Self>) {
self.background_task.take();
self.interpolated_edits.clear();
self.pending_edits.clear();
@ -236,7 +232,7 @@ impl WrapMap {
}
}
fn flush_edits(&mut self, cx: &mut ModelContext<Self>) {
fn flush_edits(&mut self, cx: &mut Context<Self>) {
if !self.snapshot.interpolated {
let mut to_remove_len = 0;
for (tab_snapshot, _) in &self.pending_edits {

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
use gpui::AppContext;
use gpui::App;
use language::CursorShape;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@ -463,7 +463,7 @@ pub struct GutterContent {
}
impl EditorSettings {
pub fn jupyter_enabled(cx: &AppContext) -> bool {
pub fn jupyter_enabled(cx: &App) -> bool {
EditorSettings::get_global(cx).jupyter.enabled
}
}
@ -473,10 +473,7 @@ impl Settings for EditorSettings {
type FileContent = EditorSettingsContent;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut AppContext,
) -> anyhow::Result<Self> {
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
sources.json_merge()
}
}

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use gpui::{AppContext, FontFeatures, FontWeight};
use gpui::{App, FontFeatures, FontWeight};
use project::project_settings::{InlineBlameSettings, ProjectSettings};
use settings::{EditableSettingControl, Settings};
use theme::{FontFamilyCache, ThemeSettings};
@ -27,7 +27,7 @@ impl EditorSettingsControls {
}
impl RenderOnce for EditorSettingsControls {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
SettingsContainer::new()
.child(
SettingsGroup::new("Font")
@ -65,7 +65,7 @@ impl EditableSettingControl for BufferFontFamilyControl {
"Buffer Font Family".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.buffer_font.family.clone()
}
@ -73,14 +73,14 @@ impl EditableSettingControl for BufferFontFamilyControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
settings.buffer_font_family = Some(value.to_string());
}
}
impl RenderOnce for BufferFontFamilyControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
@ -89,18 +89,18 @@ impl RenderOnce for BufferFontFamilyControl {
.child(DropdownMenu::new(
"buffer-font-family",
value.clone(),
ContextMenu::build(cx, |mut menu, cx| {
ContextMenu::build(window, cx, |mut menu, _, cx| {
let font_family_cache = FontFamilyCache::global(cx);
for font_name in font_family_cache.list_font_families(cx) {
menu = menu.custom_entry(
{
let font_name = font_name.clone();
move |_cx| Label::new(font_name.clone()).into_any_element()
move |_window, _cx| Label::new(font_name.clone()).into_any_element()
},
{
let font_name = font_name.clone();
move |cx| {
move |_window, cx| {
Self::write(font_name.clone(), cx);
}
},
@ -124,7 +124,7 @@ impl EditableSettingControl for BufferFontSizeControl {
"Buffer Font Size".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.buffer_font_size
}
@ -132,14 +132,14 @@ impl EditableSettingControl for BufferFontSizeControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
settings.buffer_font_size = Some(value.into());
}
}
impl RenderOnce for BufferFontSizeControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
@ -148,10 +148,10 @@ impl RenderOnce for BufferFontSizeControl {
.child(NumericStepper::new(
"buffer-font-size",
value.to_string(),
move |_, cx| {
move |_, _, cx| {
Self::write(value - px(1.), cx);
},
move |_, cx| {
move |_, _, cx| {
Self::write(value + px(1.), cx);
},
))
@ -169,7 +169,7 @@ impl EditableSettingControl for BufferFontWeightControl {
"Buffer Font Weight".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.buffer_font.weight
}
@ -177,14 +177,14 @@ impl EditableSettingControl for BufferFontWeightControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
settings.buffer_font_weight = Some(value.0);
}
}
impl RenderOnce for BufferFontWeightControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
@ -193,12 +193,12 @@ impl RenderOnce for BufferFontWeightControl {
.child(DropdownMenu::new(
"buffer-font-weight",
value.0.to_string(),
ContextMenu::build(cx, |mut menu, _cx| {
ContextMenu::build(window, cx, |mut menu, _window, _cx| {
for weight in FontWeight::ALL {
menu = menu.custom_entry(
move |_cx| Label::new(weight.0.to_string()).into_any_element(),
move |_window, _cx| Label::new(weight.0.to_string()).into_any_element(),
{
move |cx| {
move |_, cx| {
Self::write(weight, cx);
}
},
@ -222,7 +222,7 @@ impl EditableSettingControl for BufferFontLigaturesControl {
"Buffer Font Ligatures".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings
.buffer_font
@ -234,7 +234,7 @@ impl EditableSettingControl for BufferFontLigaturesControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
let value = if value { 1 } else { 0 };
@ -255,14 +255,14 @@ impl EditableSettingControl for BufferFontLigaturesControl {
}
impl RenderOnce for BufferFontLigaturesControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
"buffer-font-ligatures",
Label::new(self.name()),
value.into(),
|selection, cx| {
|selection, _, cx| {
Self::write(
match selection {
ToggleState::Selected => true,
@ -286,7 +286,7 @@ impl EditableSettingControl for InlineGitBlameControl {
"Inline Git Blame".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = ProjectSettings::get_global(cx);
settings.git.inline_blame_enabled()
}
@ -294,7 +294,7 @@ impl EditableSettingControl for InlineGitBlameControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
if let Some(inline_blame) = settings.git.inline_blame.as_mut() {
inline_blame.enabled = value;
@ -308,14 +308,14 @@ impl EditableSettingControl for InlineGitBlameControl {
}
impl RenderOnce for InlineGitBlameControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
"inline-git-blame",
Label::new(self.name()),
value.into(),
|selection, cx| {
|selection, _, cx| {
Self::write(
match selection {
ToggleState::Selected => true,
@ -339,7 +339,7 @@ impl EditableSettingControl for LineNumbersControl {
"Line Numbers".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = EditorSettings::get_global(cx);
settings.gutter.line_numbers
}
@ -347,7 +347,7 @@ impl EditableSettingControl for LineNumbersControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
if let Some(gutter) = settings.gutter.as_mut() {
gutter.line_numbers = Some(value);
@ -361,14 +361,14 @@ impl EditableSettingControl for LineNumbersControl {
}
impl RenderOnce for LineNumbersControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
"line-numbers",
Label::new(self.name()),
value.into(),
|selection, cx| {
|selection, _, cx| {
Self::write(
match selection {
ToggleState::Selected => true,
@ -392,7 +392,7 @@ impl EditableSettingControl for RelativeLineNumbersControl {
"Relative Line Numbers".into()
}
fn read(cx: &AppContext) -> Self::Value {
fn read(cx: &App) -> Self::Value {
let settings = EditorSettings::get_global(cx);
settings.relative_line_numbers
}
@ -400,27 +400,27 @@ impl EditableSettingControl for RelativeLineNumbersControl {
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
_cx: &App,
) {
settings.relative_line_numbers = Some(value);
}
}
impl RenderOnce for RelativeLineNumbersControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let value = Self::read(cx);
DropdownMenu::new(
"relative-line-numbers",
if value { "Relative" } else { "Ascending" },
ContextMenu::build(cx, |menu, _cx| {
ContextMenu::build(window, cx, |menu, _window, _cx| {
menu.custom_entry(
|_cx| Label::new("Ascending").into_any_element(),
move |cx| Self::write(false, cx),
|_window, _cx| Label::new("Ascending").into_any_element(),
move |_, cx| Self::write(false, cx),
)
.custom_entry(
|_cx| Label::new("Relative").into_any_element(),
move |cx| Self::write(true, cx),
|_window, _cx| Label::new("Relative").into_any_element(),
move |_, cx| Self::write(true, cx),
)
}),
)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ use git::{
blame::{Blame, BlameEntry},
parse_git_remote_url, GitHostingProvider, GitHostingProviderRegistry, Oid, PullRequest,
};
use gpui::{AppContext, Model, ModelContext, Subscription, Task};
use gpui::{App, Context, Entity, Subscription, Task};
use http_client::HttpClient;
use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
use multi_buffer::RowInfo;
@ -96,8 +96,8 @@ pub struct CommitDetails {
}
pub struct GitBlame {
project: Model<Project>,
buffer: Model<Buffer>,
project: Entity<Project>,
buffer: Entity<Buffer>,
entries: SumTree<GitBlameEntry>,
commit_details: HashMap<Oid, CommitDetails>,
buffer_snapshot: BufferSnapshot,
@ -113,11 +113,11 @@ pub struct GitBlame {
impl GitBlame {
pub fn new(
buffer: Model<Buffer>,
project: Model<Project>,
buffer: Entity<Buffer>,
project: Entity<Project>,
user_triggered: bool,
focused: bool,
cx: &mut ModelContext<Self>,
cx: &mut Context<Self>,
) -> Self {
let entries = SumTree::from_item(
GitBlameEntry {
@ -194,7 +194,7 @@ impl GitBlame {
pub fn blame_for_rows<'a>(
&'a mut self,
rows: &'a [RowInfo],
cx: &AppContext,
cx: &App,
) -> impl 'a + Iterator<Item = Option<BlameEntry>> {
self.sync(cx);
@ -206,7 +206,7 @@ impl GitBlame {
})
}
pub fn max_author_length(&mut self, cx: &AppContext) -> usize {
pub fn max_author_length(&mut self, cx: &App) -> usize {
self.sync(cx);
let mut max_author_length = 0;
@ -227,11 +227,11 @@ impl GitBlame {
max_author_length
}
pub fn blur(&mut self, _: &mut ModelContext<Self>) {
pub fn blur(&mut self, _: &mut Context<Self>) {
self.focused = false;
}
pub fn focus(&mut self, cx: &mut ModelContext<Self>) {
pub fn focus(&mut self, cx: &mut Context<Self>) {
self.focused = true;
if self.changed_while_blurred {
self.changed_while_blurred = false;
@ -239,7 +239,7 @@ impl GitBlame {
}
}
fn sync(&mut self, cx: &AppContext) {
fn sync(&mut self, cx: &App) {
let edits = self.buffer_edits.consume();
let new_snapshot = self.buffer.read(cx).snapshot();
@ -342,7 +342,7 @@ impl GitBlame {
}
#[cfg(test)]
fn check_invariants(&mut self, cx: &mut ModelContext<Self>) {
fn check_invariants(&mut self, cx: &mut Context<Self>) {
self.sync(cx);
assert_eq!(
self.entries.summary().rows,
@ -350,7 +350,7 @@ impl GitBlame {
);
}
fn generate(&mut self, cx: &mut ModelContext<Self>) {
fn generate(&mut self, cx: &mut Context<Self>) {
if !self.focused {
self.changed_while_blurred = true;
return;
@ -422,7 +422,7 @@ impl GitBlame {
});
}
fn regenerate_on_edit(&mut self, cx: &mut ModelContext<Self>) {
fn regenerate_on_edit(&mut self, cx: &mut Context<Self>) {
self.regenerate_on_edit_task = cx.spawn(|this, mut cx| async move {
cx.background_executor()
.timer(REGENERATE_ON_EDIT_DEBOUNCE_INTERVAL)
@ -552,7 +552,7 @@ async fn parse_markdown(text: &str, language_registry: &Arc<LanguageRegistry>) -
#[cfg(test)]
mod tests {
use super::*;
use gpui::Context;
use gpui::{AppContext as _, Context};
use language::{Point, Rope};
use project::FakeFs;
use rand::prelude::*;
@ -578,7 +578,7 @@ mod tests {
blame: &mut GitBlame,
rows: Range<u32>,
expected: Vec<Option<BlameEntry>>,
cx: &mut ModelContext<GitBlame>,
cx: &mut Context<GitBlame>,
) {
assert_eq!(
blame
@ -640,8 +640,7 @@ mod tests {
.await
.unwrap();
let blame =
cx.new_model(|cx| GitBlame::new(buffer.clone(), project.clone(), true, true, cx));
let blame = cx.new(|cx| GitBlame::new(buffer.clone(), project.clone(), true, true, cx));
let event = project.next_event(cx).await;
assert_eq!(
@ -720,7 +719,7 @@ mod tests {
.await
.unwrap();
let git_blame = cx.new_model(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
let git_blame = cx.new(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
cx.executor().run_until_parked();
@ -826,7 +825,7 @@ mod tests {
.await
.unwrap();
let git_blame = cx.new_model(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
let git_blame = cx.new(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
cx.executor().run_until_parked();
@ -975,7 +974,7 @@ mod tests {
.await
.unwrap();
let git_blame = cx.new_model(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
let git_blame = cx.new(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
cx.executor().run_until_parked();
git_blame.update(cx, |blame, cx| blame.check_invariants(cx));

View file

@ -11,8 +11,8 @@ use collections::{BTreeMap, HashMap};
use feature_flags::FeatureFlagAppExt;
use git::diff::{BufferDiff, DiffHunk};
use gpui::{
actions, AnyElement, AnyView, AppContext, EventEmitter, FocusHandle, FocusableView,
InteractiveElement, Model, Render, Subscription, Task, View, WeakView,
actions, AnyElement, AnyView, App, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement, Render, Subscription, Task, WeakEntity,
};
use language::{Buffer, BufferRow};
use multi_buffer::{ExcerptId, ExcerptRange, ExpandExcerptDirection, MultiBuffer};
@ -30,8 +30,8 @@ use crate::{Editor, EditorEvent, DEFAULT_MULTIBUFFER_CONTEXT};
actions!(project_diff, [Deploy]);
pub fn init(cx: &mut AppContext) {
cx.observe_new_views(ProjectDiffEditor::register).detach();
pub fn init(cx: &mut App) {
cx.observe_new(ProjectDiffEditor::register).detach();
}
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
@ -39,11 +39,11 @@ const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
struct ProjectDiffEditor {
buffer_changes: BTreeMap<WorktreeId, HashMap<ProjectEntryId, Changes>>,
entry_order: HashMap<WorktreeId, Vec<(ProjectPath, ProjectEntryId)>>,
excerpts: Model<MultiBuffer>,
editor: View<Editor>,
excerpts: Entity<MultiBuffer>,
editor: Entity<Editor>,
project: Model<Project>,
workspace: WeakView<Workspace>,
project: Entity<Project>,
workspace: WeakEntity<Workspace>,
focus_handle: FocusHandle,
worktree_rescans: HashMap<WorktreeId, Task<()>>,
_subscriptions: Vec<Subscription>,
@ -51,40 +51,50 @@ struct ProjectDiffEditor {
#[derive(Debug)]
struct Changes {
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
hunks: Vec<DiffHunk>,
}
impl ProjectDiffEditor {
fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
fn register(
workspace: &mut Workspace,
_window: Option<&mut Window>,
_: &mut Context<Workspace>,
) {
workspace.register_action(Self::deploy);
}
fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext<Workspace>) {
fn deploy(
workspace: &mut Workspace,
_: &Deploy,
window: &mut Window,
cx: &mut Context<Workspace>,
) {
if !cx.is_staff() {
return;
}
if let Some(existing) = workspace.item_of_type::<Self>(cx) {
workspace.activate_item(&existing, true, true, cx);
workspace.activate_item(&existing, true, true, window, cx);
} else {
let workspace_handle = cx.view().downgrade();
let workspace_handle = cx.model().downgrade();
let project_diff =
cx.new_view(|cx| Self::new(workspace.project().clone(), workspace_handle, cx));
workspace.add_item_to_active_pane(Box::new(project_diff), None, true, cx);
cx.new(|cx| Self::new(workspace.project().clone(), workspace_handle, window, cx));
workspace.add_item_to_active_pane(Box::new(project_diff), None, true, window, cx);
}
}
fn new(
project: Model<Project>,
workspace: WeakView<Workspace>,
cx: &mut ViewContext<Self>,
project: Entity<Project>,
workspace: WeakEntity<Workspace>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
// TODO diff change subscriptions. For that, needed:
// * `-20/+50` stats retrieval: some background process that reacts on file changes
let focus_handle = cx.focus_handle();
let changed_entries_subscription =
cx.subscribe(&project, |project_diff_editor, _, e, cx| {
cx.subscribe_in(&project, window, |project_diff_editor, _, e, window, cx| {
let mut worktree_to_rescan = None;
match e {
project::Event::WorktreeAdded(id) => {
@ -137,15 +147,15 @@ impl ProjectDiffEditor {
}
if let Some(worktree_to_rescan) = worktree_to_rescan {
project_diff_editor.schedule_worktree_rescan(worktree_to_rescan, cx);
project_diff_editor.schedule_worktree_rescan(worktree_to_rescan, window, cx);
}
});
let excerpts = cx.new_model(|cx| MultiBuffer::new(project.read(cx).capability()));
let excerpts = cx.new(|cx| MultiBuffer::new(project.read(cx).capability()));
let editor = cx.new_view(|cx| {
let editor = cx.new(|cx| {
let mut diff_display_editor =
Editor::for_multibuffer(excerpts.clone(), Some(project.clone()), true, cx);
Editor::for_multibuffer(excerpts.clone(), Some(project.clone()), true, window, cx);
diff_display_editor.set_expand_all_diff_hunks(cx);
diff_display_editor
});
@ -161,16 +171,16 @@ impl ProjectDiffEditor {
excerpts,
_subscriptions: vec![changed_entries_subscription],
};
new_self.schedule_rescan_all(cx);
new_self.schedule_rescan_all(window, cx);
new_self
}
fn schedule_rescan_all(&mut self, cx: &mut ViewContext<Self>) {
fn schedule_rescan_all(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let mut current_worktrees = HashSet::<WorktreeId>::default();
for worktree in self.project.read(cx).worktrees(cx).collect::<Vec<_>>() {
let worktree_id = worktree.read(cx).id();
current_worktrees.insert(worktree_id);
self.schedule_worktree_rescan(worktree_id, cx);
self.schedule_worktree_rescan(worktree_id, window, cx);
}
self.worktree_rescans
@ -181,11 +191,16 @@ impl ProjectDiffEditor {
.retain(|worktree_id, _| current_worktrees.contains(worktree_id));
}
fn schedule_worktree_rescan(&mut self, id: WorktreeId, cx: &mut ViewContext<Self>) {
fn schedule_worktree_rescan(
&mut self,
id: WorktreeId,
window: &mut Window,
cx: &mut Context<Self>,
) {
let project = self.project.clone();
self.worktree_rescans.insert(
id,
cx.spawn(|project_diff_editor, mut cx| async move {
cx.spawn_in(window, |project_diff_editor, mut cx| async move {
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
let open_tasks = project
.update(&mut cx, |project, cx| {
@ -229,7 +244,7 @@ impl ProjectDiffEditor {
let mut new_entries = Vec::new();
let mut buffers = HashMap::<
ProjectEntryId,
(text::BufferSnapshot, Model<Buffer>, BufferDiff),
(text::BufferSnapshot, Entity<Buffer>, BufferDiff),
>::default();
let mut change_sets = Vec::new();
for (entry_id, entry_path, open_task) in open_tasks {
@ -258,7 +273,7 @@ impl ProjectDiffEditor {
continue;
};
cx.update(|cx| {
cx.update(|_, cx| {
buffers.insert(
entry_id,
(
@ -307,7 +322,7 @@ impl ProjectDiffEditor {
.await;
project_diff_editor
.update(&mut cx, |project_diff_editor, cx| {
.update_in(&mut cx, |project_diff_editor, _window, cx| {
project_diff_editor.update_excerpts(id, new_changes, new_entry_order, cx);
project_diff_editor.editor.update(cx, |editor, cx| {
editor.buffer.update(cx, |buffer, cx| {
@ -327,7 +342,8 @@ impl ProjectDiffEditor {
worktree_id: WorktreeId,
new_changes: HashMap<ProjectEntryId, Changes>,
new_entry_order: Vec<(ProjectPath, ProjectEntryId)>,
cx: &mut ViewContext<ProjectDiffEditor>,
cx: &mut Context<ProjectDiffEditor>,
) {
if let Some(current_order) = self.entry_order.get(&worktree_id) {
let current_entries = self.buffer_changes.entry(worktree_id).or_default();
@ -335,7 +351,7 @@ impl ProjectDiffEditor {
let mut excerpts_to_remove = Vec::new();
let mut new_excerpt_hunks = BTreeMap::<
ExcerptId,
Vec<(ProjectPath, Model<Buffer>, Vec<Range<text::Anchor>>)>,
Vec<(ProjectPath, Entity<Buffer>, Vec<Range<text::Anchor>>)>,
>::new();
let mut excerpt_to_expand =
HashMap::<(u32, ExpandExcerptDirection), Vec<ExcerptId>>::default();
@ -902,8 +918,8 @@ impl ProjectDiffEditor {
impl EventEmitter<EditorEvent> for ProjectDiffEditor {}
impl FocusableView for ProjectDiffEditor {
fn focus_handle(&self, _: &AppContext) -> FocusHandle {
impl Focusable for ProjectDiffEditor {
fn focus_handle(&self, _: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
@ -915,20 +931,26 @@ impl Item for ProjectDiffEditor {
Editor::to_item_events(event, f)
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
self.editor.update(cx, |editor, cx| editor.deactivated(cx));
}
fn navigate(&mut self, data: Box<dyn Any>, cx: &mut ViewContext<Self>) -> bool {
fn deactivated(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.editor
.update(cx, |editor, cx| editor.navigate(data, cx))
.update(cx, |editor, cx| editor.deactivated(window, cx));
}
fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
fn navigate(
&mut self,
data: Box<dyn Any>,
window: &mut Window,
cx: &mut Context<Self>,
) -> bool {
self.editor
.update(cx, |editor, cx| editor.navigate(data, window, cx))
}
fn tab_tooltip_text(&self, _: &App) -> Option<SharedString> {
Some("Project Diff".into())
}
fn tab_content(&self, params: TabContentParams, _: &WindowContext) -> AnyElement {
fn tab_content(&self, params: TabContentParams, _window: &Window, _: &App) -> AnyElement {
if self.buffer_changes.is_empty() {
Label::new("No changes")
.color(if params.selected {
@ -978,17 +1000,22 @@ impl Item for ProjectDiffEditor {
fn for_each_project_item(
&self,
cx: &AppContext,
cx: &App,
f: &mut dyn FnMut(gpui::EntityId, &dyn project::ProjectItem),
) {
self.editor.for_each_project_item(cx, f)
}
fn is_singleton(&self, _: &AppContext) -> bool {
fn is_singleton(&self, _: &App) -> bool {
false
}
fn set_nav_history(&mut self, nav_history: ItemNavHistory, cx: &mut ViewContext<Self>) {
fn set_nav_history(
&mut self,
nav_history: ItemNavHistory,
_: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, _| {
editor.set_nav_history(Some(nav_history));
});
@ -997,59 +1024,63 @@ impl Item for ProjectDiffEditor {
fn clone_on_split(
&self,
_workspace_id: Option<workspace::WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Entity<Self>>
where
Self: Sized,
{
Some(cx.new_view(|cx| {
ProjectDiffEditor::new(self.project.clone(), self.workspace.clone(), cx)
Some(cx.new(|cx| {
ProjectDiffEditor::new(self.project.clone(), self.workspace.clone(), window, cx)
}))
}
fn is_dirty(&self, cx: &AppContext) -> bool {
fn is_dirty(&self, cx: &App) -> bool {
self.excerpts.read(cx).is_dirty(cx)
}
fn has_conflict(&self, cx: &AppContext) -> bool {
fn has_conflict(&self, cx: &App) -> bool {
self.excerpts.read(cx).has_conflict(cx)
}
fn can_save(&self, _: &AppContext) -> bool {
fn can_save(&self, _: &App) -> bool {
true
}
fn save(
&mut self,
format: bool,
project: Model<Project>,
cx: &mut ViewContext<Self>,
project: Entity<Project>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<anyhow::Result<()>> {
self.editor.save(format, project, cx)
self.editor.save(format, project, window, cx)
}
fn save_as(
&mut self,
_: Model<Project>,
_: Entity<Project>,
_: ProjectPath,
_: &mut ViewContext<Self>,
_window: &mut Window,
_: &mut Context<Self>,
) -> Task<anyhow::Result<()>> {
unreachable!()
}
fn reload(
&mut self,
project: Model<Project>,
cx: &mut ViewContext<Self>,
project: Entity<Project>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<anyhow::Result<()>> {
self.editor.reload(project, cx)
self.editor.reload(project, window, cx)
}
fn act_as_type<'a>(
&'a self,
type_id: TypeId,
self_handle: &'a View<Self>,
_: &'a AppContext,
self_handle: &'a Entity<Self>,
_: &'a App,
) -> Option<AnyView> {
if type_id == TypeId::of::<Self>() {
Some(self_handle.to_any())
@ -1060,22 +1091,28 @@ impl Item for ProjectDiffEditor {
}
}
fn breadcrumb_location(&self, _: &AppContext) -> ToolbarItemLocation {
fn breadcrumb_location(&self, _: &App) -> ToolbarItemLocation {
ToolbarItemLocation::PrimaryLeft
}
fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
fn breadcrumbs(&self, theme: &theme::Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
self.editor.breadcrumbs(theme, cx)
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
self.editor
.update(cx, |editor, cx| editor.added_to_workspace(workspace, cx));
fn added_to_workspace(
&mut self,
workspace: &mut Workspace,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, cx| {
editor.added_to_workspace(workspace, window, cx)
});
}
}
impl Render for ProjectDiffEditor {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let child = if self.buffer_changes.is_empty() {
div()
.bg(cx.theme().colors().editor_background)
@ -1142,14 +1179,15 @@ mod tests {
.await;
let project = Project::test(fs.clone(), [Path::new("/root")], cx).await;
let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
let workspace =
cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
let file_a_editor = workspace
.update(cx, |workspace, cx| {
.update(cx, |workspace, window, cx| {
let file_a_editor =
workspace.open_abs_path(PathBuf::from("/root/file_a"), true, cx);
ProjectDiffEditor::deploy(workspace, &Deploy, cx);
workspace.open_abs_path(PathBuf::from("/root/file_a"), true, window, cx);
ProjectDiffEditor::deploy(workspace, &Deploy, window, cx);
file_a_editor
})
.unwrap()
@ -1158,7 +1196,7 @@ mod tests {
.downcast::<Editor>()
.expect("did not open an editor for file_a");
let project_diff_editor = workspace
.update(cx, |workspace, cx| {
.update(cx, |workspace, _, cx| {
workspace
.active_pane()
.read(cx)
@ -1177,14 +1215,14 @@ mod tests {
let old_text = file_a_editor.update(cx, |editor, cx| editor.text(cx));
let change = "an edit after git add";
file_a_editor
.update(cx, |file_a_editor, cx| {
file_a_editor.insert(change, cx);
file_a_editor.save(false, project.clone(), cx)
.update_in(cx, |file_a_editor, window, cx| {
file_a_editor.insert(change, window, cx);
file_a_editor.save(false, project.clone(), window, cx)
})
.await
.expect("failed to save a file");
file_a_editor.update(cx, |file_a_editor, cx| {
let change_set = cx.new_model(|cx| {
file_a_editor.update_in(cx, |file_a_editor, _window, cx| {
let change_set = cx.new(|cx| {
BufferChangeSet::new_with_base_text(
old_text.clone(),
&file_a_editor.buffer().read(cx).as_singleton().unwrap(),
@ -1223,7 +1261,7 @@ mod tests {
cx.executor()
.advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
cx.run_until_parked();
let editor = project_diff_editor.update(cx, |view, _| view.editor.clone());
let editor = project_diff_editor.update(cx, |diff_editor, _| diff_editor.editor.clone());
assert_state_with_diff(
&editor,

View file

@ -1,11 +1,14 @@
use gpui::ViewContext;
use language::CursorShape;
use crate::{Editor, RangeToAnchorExt};
use gpui::{Context, Window};
use language::CursorShape;
enum MatchingBracketHighlight {}
pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
pub fn refresh_matching_bracket_highlights(
editor: &mut Editor,
window: &mut Window,
cx: &mut Context<Editor>,
) {
editor.clear_background_highlights::<MatchingBracketHighlight>(cx);
let newest_selection = editor.selections.newest::<usize>(cx);
@ -14,7 +17,7 @@ pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewCon
return;
}
let snapshot = editor.snapshot(cx);
let snapshot = editor.snapshot(window, cx);
let head = newest_selection.head();
let mut tail = head;
if (editor.cursor_shape == CursorShape::Block || editor.cursor_shape == CursorShape::Hollow)

View file

@ -5,7 +5,7 @@ use crate::{
Anchor, Editor, EditorSettings, EditorSnapshot, FindAllReferences, GoToDefinition,
GoToTypeDefinition, GotoDefinitionKind, InlayId, Navigated, PointForPosition, SelectPhase,
};
use gpui::{px, AppContext, AsyncWindowContext, Model, Modifiers, Task, ViewContext};
use gpui::{px, App, AsyncWindowContext, Context, Entity, Modifiers, Task, Window};
use language::{Bias, ToOffset};
use linkify::{LinkFinder, LinkKind};
use lsp::LanguageServerId;
@ -93,10 +93,10 @@ impl TriggerPoint {
}
pub fn exclude_link_to_position(
buffer: &Model<language::Buffer>,
buffer: &Entity<language::Buffer>,
current_position: &text::Anchor,
location: &LocationLink,
cx: &AppContext,
cx: &App,
) -> bool {
// Exclude definition links that points back to cursor position.
// (i.e., currently cursor upon definition).
@ -117,7 +117,8 @@ impl Editor {
point_for_position: PointForPosition,
snapshot: &EditorSnapshot,
modifiers: Modifiers,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
let hovered_link_modifier = match multi_cursor_setting {
@ -137,7 +138,7 @@ impl Editor {
.anchor_before(point.to_offset(&snapshot.display_snapshot, Bias::Left)),
);
show_link_definition(modifiers.shift, self, trigger_point, snapshot, cx);
show_link_definition(modifiers.shift, self, trigger_point, snapshot, window, cx);
}
None => {
update_inlay_link_and_hover_points(
@ -146,13 +147,14 @@ impl Editor {
self,
hovered_link_modifier,
modifiers.shift,
window,
cx,
);
}
}
}
pub(crate) fn hide_hovered_link(&mut self, cx: &mut ViewContext<Self>) {
pub(crate) fn hide_hovered_link(&mut self, cx: &mut Context<Self>) {
self.hovered_link_state.take();
self.clear_highlights::<HoveredLinkState>(cx);
}
@ -161,17 +163,18 @@ impl Editor {
&mut self,
point: PointForPosition,
modifiers: Modifiers,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let reveal_task = self.cmd_click_reveal_task(point, modifiers, cx);
cx.spawn(|editor, mut cx| async move {
let reveal_task = self.cmd_click_reveal_task(point, modifiers, window, cx);
cx.spawn_in(window, |editor, mut cx| async move {
let definition_revealed = reveal_task.await.log_err().unwrap_or(Navigated::No);
let find_references = editor
.update(&mut cx, |editor, cx| {
.update_in(&mut cx, |editor, window, cx| {
if definition_revealed == Navigated::Yes {
return None;
}
editor.find_all_references(&FindAllReferences, cx)
editor.find_all_references(&FindAllReferences, window, cx)
})
.ok()
.flatten();
@ -182,9 +185,14 @@ impl Editor {
.detach();
}
pub fn scroll_hover(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) -> bool {
pub fn scroll_hover(
&mut self,
amount: &ScrollAmount,
window: &mut Window,
cx: &mut Context<Self>,
) -> bool {
let selection = self.selections.newest_anchor().head();
let snapshot = self.snapshot(cx);
let snapshot = self.snapshot(window, cx);
let Some(popover) = self.hover_state.info_popovers.iter().find(|popover| {
popover
@ -193,7 +201,7 @@ impl Editor {
}) else {
return false;
};
popover.scroll(amount, cx);
popover.scroll(amount, window, cx);
true
}
@ -201,19 +209,20 @@ impl Editor {
&mut self,
point: PointForPosition,
modifiers: Modifiers,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Task<anyhow::Result<Navigated>> {
if let Some(hovered_link_state) = self.hovered_link_state.take() {
self.hide_hovered_link(cx);
if !hovered_link_state.links.is_empty() {
if !self.focus_handle.is_focused(cx) {
cx.focus(&self.focus_handle);
if !self.focus_handle.is_focused(window) {
window.focus(&self.focus_handle);
}
// exclude links pointing back to the current anchor
let current_position = point
.next_valid
.to_point(&self.snapshot(cx).display_snapshot);
.to_point(&self.snapshot(window, cx).display_snapshot);
let Some((buffer, anchor)) = self
.buffer()
.read(cx)
@ -233,7 +242,7 @@ impl Editor {
})
.collect();
return self.navigate_to_hover_links(None, links, modifiers.alt, cx);
return self.navigate_to_hover_links(None, links, modifiers.alt, window, cx);
}
}
@ -245,14 +254,15 @@ impl Editor {
add: false,
click_count: 1,
},
window,
cx,
);
if point.as_valid().is_some() {
if modifiers.shift {
self.go_to_type_definition(&GoToTypeDefinition, cx)
self.go_to_type_definition(&GoToTypeDefinition, window, cx)
} else {
self.go_to_definition(&GoToDefinition, cx)
self.go_to_definition(&GoToDefinition, window, cx)
}
} else {
Task::ready(Ok(Navigated::No))
@ -266,7 +276,8 @@ pub fn update_inlay_link_and_hover_points(
editor: &mut Editor,
secondary_held: bool,
shift_held: bool,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<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))
@ -310,6 +321,7 @@ pub fn update_inlay_link_and_hover_points(
buffer_id,
excerpt_id,
hovered_hint.id,
window,
cx,
);
}
@ -349,6 +361,7 @@ pub fn update_inlay_link_and_hover_points(
..hovered_hint.text.len() + extra_shift_right,
},
},
window,
cx,
);
hover_updated = true;
@ -393,6 +406,7 @@ pub fn update_inlay_link_and_hover_points(
},
range: highlight.clone(),
},
window,
cx,
);
hover_updated = true;
@ -413,6 +427,7 @@ pub fn update_inlay_link_and_hover_points(
language_server_id,
),
snapshot,
window,
cx,
);
}
@ -431,7 +446,7 @@ pub fn update_inlay_link_and_hover_points(
editor.hide_hovered_link(cx)
}
if !hover_updated {
hover_popover::hover_at(editor, None, cx);
hover_popover::hover_at(editor, None, window, cx);
}
}
@ -440,7 +455,8 @@ pub fn show_link_definition(
editor: &mut Editor,
trigger_point: TriggerPoint,
snapshot: &EditorSnapshot,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let preferred_kind = match trigger_point {
TriggerPoint::Text(_) if !shift_held => GotoDefinitionKind::Symbol,
@ -509,7 +525,7 @@ pub fn show_link_definition(
let provider = editor.semantics_provider.clone();
let snapshot = snapshot.buffer_snapshot.clone();
hovered_link_state.task = Some(cx.spawn(|this, mut cx| {
hovered_link_state.task = Some(cx.spawn_in(window, |this, mut cx| {
async move {
let result = match &trigger_point {
TriggerPoint::Text(_) => {
@ -536,7 +552,7 @@ pub fn show_link_definition(
Some((range, vec![HoverLink::File(filename)]))
} else if let Some(provider) = provider {
let task = cx.update(|cx| {
let task = cx.update(|_, cx| {
provider.definitions(&buffer, buffer_position, preferred_kind, cx)
})?;
if let Some(task) = task {
@ -633,7 +649,7 @@ pub fn show_link_definition(
}
pub(crate) fn find_url(
buffer: &Model<language::Buffer>,
buffer: &Entity<language::Buffer>,
position: text::Anchor,
mut cx: AsyncWindowContext,
) -> Option<(Range<text::Anchor>, String)> {
@ -695,7 +711,7 @@ pub(crate) fn find_url(
}
pub(crate) fn find_url_from_range(
buffer: &Model<language::Buffer>,
buffer: &Entity<language::Buffer>,
range: Range<text::Anchor>,
mut cx: AsyncWindowContext,
) -> Option<String> {
@ -754,8 +770,8 @@ pub(crate) fn find_url_from_range(
}
pub(crate) async fn find_file(
buffer: &Model<language::Buffer>,
project: Option<Model<Project>>,
buffer: &Entity<language::Buffer>,
project: Option<Entity<Project>>,
position: text::Anchor,
cx: &mut AsyncWindowContext,
) -> Option<(Range<text::Anchor>, ResolvedPath)> {
@ -766,8 +782,8 @@ pub(crate) async fn find_file(
async fn check_path(
candidate_file_path: &str,
project: &Model<Project>,
buffer: &Model<language::Buffer>,
project: &Entity<Project>,
buffer: &Entity<language::Buffer>,
cx: &mut AsyncWindowContext,
) -> Option<ResolvedPath> {
project
@ -926,7 +942,7 @@ mod tests {
struct A;
let vˇariable = A;
"});
let screen_coord = cx.editor(|editor, cx| editor.pixel_position_of_cursor(cx));
let screen_coord = cx.editor(|editor, _, cx| editor.pixel_position_of_cursor(cx));
// Basic hold cmd+shift, expect highlight in region if response contains type definition
let symbol_range = cx.lsp_range(indoc! {"
@ -1226,11 +1242,11 @@ mod tests {
fn do_work() { test(); }
"})[0]
.clone();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, window, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let anchor_range = snapshot.anchor_before(selection_range.start)
..snapshot.anchor_after(selection_range.end);
editor.change_selections(Some(crate::Autoscroll::fit()), cx, |s| {
editor.change_selections(Some(crate::Autoscroll::fit()), window, cx, |s| {
s.set_pending_anchor_range(anchor_range, crate::SelectMode::Character)
});
});
@ -1319,7 +1335,7 @@ mod tests {
.next()
.await;
cx.background_executor.run_until_parked();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, _window, cx| {
let expected_layers = vec![hint_label.to_string()];
assert_eq!(expected_layers, cached_hint_labels(editor));
assert_eq!(expected_layers, visible_hint_labels(editor, cx));
@ -1336,8 +1352,8 @@ mod tests {
.first()
.cloned()
.unwrap();
let midpoint = cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
let midpoint = cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let previous_valid = inlay_range.start.to_display_point(&snapshot);
let next_valid = inlay_range.end.to_display_point(&snapshot);
assert_eq!(previous_valid.row(), next_valid.row());
@ -1351,8 +1367,8 @@ mod tests {
let hover_point = cx.pixel_position_for(midpoint);
cx.simulate_mouse_move(hover_point, None, Modifiers::secondary_key());
cx.background_executor.run_until_parked();
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let actual_highlights = snapshot
.inlay_highlights::<HoveredLinkState>()
.into_iter()
@ -1370,8 +1386,8 @@ mod tests {
cx.simulate_mouse_move(hover_point, None, Modifiers::none());
// Assert no link highlights
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let actual_ranges = snapshot
.text_highlight_ranges::<HoveredLinkState>()
.map(|ranges| ranges.as_ref().clone().1)
@ -1515,7 +1531,7 @@ mod tests {
for (input, expected) in test_cases {
cx.set_state(input);
let (position, snapshot) = cx.editor(|editor, cx| {
let (position, snapshot) = cx.editor(|editor, _, cx| {
let positions = editor.selections.newest_anchor().head().text_anchor;
let snapshot = editor
.buffer()
@ -1556,7 +1572,7 @@ mod tests {
.await;
// Insert a new file
let fs = cx.update_workspace(|workspace, cx| workspace.project().read(cx).fs().clone());
let fs = cx.update_workspace(|workspace, _, cx| workspace.project().read(cx).fs().clone());
fs.as_fake()
.insert_file("/root/dir/file2.rs", "This is file2.rs".as_bytes().to_vec())
.await;
@ -1579,9 +1595,9 @@ mod tests {
"});
cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
// No highlight
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, window, cx| {
assert!(editor
.snapshot(cx)
.snapshot(window, cx)
.text_highlight_ranges::<HoveredLinkState>()
.unwrap_or_default()
.1
@ -1662,8 +1678,8 @@ mod tests {
cx.simulate_click(screen_coord, Modifiers::secondary_key());
cx.update_workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2));
cx.update_workspace(|workspace, cx| {
cx.update_workspace(|workspace, _, cx| assert_eq!(workspace.items(cx).count(), 2));
cx.update_workspace(|workspace, _, cx| {
let active_editor = workspace.active_item_as::<Editor>(cx).unwrap();
let buffer = active_editor
@ -1692,7 +1708,7 @@ mod tests {
.await;
// Insert a new file
let fs = cx.update_workspace(|workspace, cx| workspace.project().read(cx).fs().clone());
let fs = cx.update_workspace(|workspace, _, cx| workspace.project().read(cx).fs().clone());
fs.as_fake()
.insert_file("/root/dir/file2.rs", "This is file2.rs".as_bytes().to_vec())
.await;
@ -1708,9 +1724,9 @@ mod tests {
cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
// No highlight
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, window, cx| {
assert!(editor
.snapshot(cx)
.snapshot(window, cx)
.text_highlight_ranges::<HoveredLinkState>()
.unwrap_or_default()
.1
@ -1719,6 +1735,6 @@ mod tests {
// Does not open the directory
cx.simulate_click(screen_coord, Modifiers::secondary_key());
cx.update_workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 1));
cx.update_workspace(|workspace, _, cx| assert_eq!(workspace.items(cx).count(), 1));
}
}

View file

@ -6,9 +6,10 @@ use crate::{
Hover,
};
use gpui::{
div, px, AnyElement, AsyncWindowContext, FontWeight, Hsla, InteractiveElement, IntoElement,
MouseButton, ParentElement, Pixels, ScrollHandle, Size, Stateful, StatefulInteractiveElement,
StyleRefinement, Styled, Task, TextStyleRefinement, View, ViewContext,
div, px, AnyElement, AsyncWindowContext, Context, Entity, Focusable as _, FontWeight, Hsla,
InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, ScrollHandle, Size,
Stateful, StatefulInteractiveElement, StyleRefinement, Styled, Task, TextStyleRefinement,
Window,
};
use itertools::Itertools;
use language::{DiagnosticEntry, Language, LanguageRegistry};
@ -21,7 +22,7 @@ use std::rc::Rc;
use std::{borrow::Cow, cell::RefCell};
use std::{ops::Range, sync::Arc, time::Duration};
use theme::ThemeSettings;
use ui::{prelude::*, window_is_transparent, Scrollbar, ScrollbarState};
use ui::{prelude::*, theme_is_transparent, Scrollbar, ScrollbarState};
use util::TryFutureExt;
pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
@ -30,33 +31,42 @@ pub const MIN_POPOVER_LINE_HEIGHT: Pixels = px(4.);
pub const HOVER_POPOVER_GAP: Pixels = px(10.);
/// Bindable action which uses the most recent selection head to trigger a hover
pub fn hover(editor: &mut Editor, _: &Hover, cx: &mut ViewContext<Editor>) {
pub fn hover(editor: &mut Editor, _: &Hover, window: &mut Window, cx: &mut Context<Editor>) {
let head = editor.selections.newest_anchor().head();
show_hover(editor, head, true, cx);
show_hover(editor, head, true, window, cx);
}
/// The internal hover action dispatches between `show_hover` or `hide_hover`
/// depending on whether a point to hover over is provided.
pub fn hover_at(editor: &mut Editor, anchor: Option<Anchor>, cx: &mut ViewContext<Editor>) {
pub fn hover_at(
editor: &mut Editor,
anchor: Option<Anchor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if EditorSettings::get_global(cx).hover_popover_enabled {
if show_keyboard_hover(editor, cx) {
if show_keyboard_hover(editor, window, cx) {
return;
}
if let Some(anchor) = anchor {
show_hover(editor, anchor, false, cx);
show_hover(editor, anchor, false, window, cx);
} else {
hide_hover(editor, cx);
}
}
}
pub fn show_keyboard_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) -> bool {
pub fn show_keyboard_hover(
editor: &mut Editor,
window: &mut Window,
cx: &mut Context<Editor>,
) -> bool {
let info_popovers = editor.hover_state.info_popovers.clone();
for p in info_popovers {
let keyboard_grace = p.keyboard_grace.borrow();
if *keyboard_grace {
if let Some(anchor) = p.anchor {
show_hover(editor, anchor, false, cx);
show_hover(editor, anchor, false, window, cx);
return true;
}
}
@ -67,7 +77,7 @@ pub fn show_keyboard_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) ->
let keyboard_grace = d.keyboard_grace.borrow();
if *keyboard_grace {
if let Some(anchor) = d.anchor {
show_hover(editor, anchor, false, cx);
show_hover(editor, anchor, false, window, cx);
return true;
}
}
@ -103,7 +113,12 @@ pub fn find_hovered_hint_part(
None
}
pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut ViewContext<Editor>) {
pub fn hover_at_inlay(
editor: &mut Editor,
inlay_hover: InlayHover,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if EditorSettings::get_global(cx).hover_popover_enabled {
if editor.pending_rename.is_some() {
return;
@ -132,7 +147,7 @@ pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut Vie
let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
let task = cx.spawn(|this, mut cx| {
let task = cx.spawn_in(window, |this, mut cx| {
async move {
cx.background_executor()
.timer(Duration::from_millis(hover_popover_delay))
@ -173,7 +188,7 @@ pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut Vie
/// Hides the type information popup.
/// Triggered by the `Hover` action when the cursor is not over a symbol or when the
/// selections changed.
pub fn hide_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) -> bool {
pub fn hide_hover(editor: &mut Editor, cx: &mut Context<Editor>) -> bool {
let info_popovers = editor.hover_state.info_popovers.drain(..);
let diagnostics_popover = editor.hover_state.diagnostic_popover.take();
let did_hide = info_popovers.count() > 0 || diagnostics_popover.is_some();
@ -197,13 +212,14 @@ fn show_hover(
editor: &mut Editor,
anchor: Anchor,
ignore_timeout: bool,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Option<()> {
if editor.pending_rename.is_some() {
return None;
}
let snapshot = editor.snapshot(cx);
let snapshot = editor.snapshot(window, cx);
let (buffer, buffer_position) = editor
.buffer
@ -239,7 +255,7 @@ fn show_hover(
let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
let task = cx.spawn(|this, mut cx| {
let task = cx.spawn_in(window, |this, mut cx| {
async move {
// If we need to delay, delay a set amount initially before making the lsp request
let delay = if ignore_timeout {
@ -257,7 +273,7 @@ fn show_hover(
total_delay
};
let hover_request = cx.update(|cx| provider.hover(&buffer, buffer_position, cx))?;
let hover_request = cx.update(|_, cx| provider.hover(&buffer, buffer_position, cx))?;
if let Some(delay) = delay {
delay.await;
@ -290,7 +306,7 @@ fn show_hover(
let mut background_color: Option<Hsla> = None;
let parsed_content = cx
.new_view(|cx| {
.new_window_model(|window, cx| {
let status_colors = cx.theme().status();
match local_diagnostic.diagnostic.severity {
@ -316,7 +332,7 @@ fn show_hover(
}
};
let settings = ThemeSettings::get_global(cx);
let mut base_text_style = cx.text_style();
let mut base_text_style = window.text_style();
base_text_style.refine(&TextStyleRefinement {
font_family: Some(settings.ui_font.family.clone()),
font_fallbacks: settings.ui_font.fallbacks.clone(),
@ -339,7 +355,7 @@ fn show_hover(
},
..Default::default()
};
Markdown::new_text(text, markdown_style.clone(), None, None, cx)
Markdown::new_text(text, markdown_style.clone(), None, None, window, cx)
})
.ok();
@ -389,7 +405,7 @@ fn show_hover(
} else {
Vec::new()
};
let snapshot = this.update(&mut cx, |this, cx| this.snapshot(cx))?;
let snapshot = this.update_in(&mut cx, |this, window, cx| this.snapshot(window, cx))?;
let mut hover_highlights = Vec::with_capacity(hovers_response.len());
let mut info_popovers = Vec::with_capacity(
hovers_response.len() + if invisible_char.is_some() { 1 } else { 0 },
@ -451,7 +467,7 @@ fn show_hover(
});
}
this.update(&mut cx, |editor, cx| {
this.update_in(&mut cx, |editor, window, cx| {
if hover_highlights.is_empty() {
editor.clear_background_highlights::<HoverState>(cx);
} else {
@ -465,7 +481,7 @@ fn show_hover(
editor.hover_state.info_popovers = info_popovers;
cx.notify();
cx.refresh();
window.refresh();
})?;
anyhow::Ok(())
@ -519,7 +535,7 @@ async fn parse_blocks(
language_registry: &Arc<LanguageRegistry>,
language: Option<Arc<Language>>,
cx: &mut AsyncWindowContext,
) -> Option<View<Markdown>> {
) -> Option<Entity<Markdown>> {
let fallback_language_name = if let Some(ref l) = language {
let l = Arc::clone(l);
Some(l.lsp_id().clone())
@ -540,14 +556,14 @@ async fn parse_blocks(
.join("\n\n");
let rendered_block = cx
.new_view(|cx| {
.new_window_model(|window, cx| {
let settings = ThemeSettings::get_global(cx);
let ui_font_family = settings.ui_font.family.clone();
let ui_font_fallbacks = settings.ui_font.fallbacks.clone();
let buffer_font_family = settings.buffer_font.family.clone();
let buffer_font_fallbacks = settings.buffer_font.fallbacks.clone();
let mut base_text_style = cx.text_style();
let mut base_text_style = window.text_style();
base_text_style.refine(&TextStyleRefinement {
font_family: Some(ui_font_family.clone()),
font_fallbacks: ui_font_fallbacks,
@ -594,6 +610,7 @@ async fn parse_blocks(
markdown_style.clone(),
Some(language_registry.clone()),
fallback_language_name,
window,
cx,
)
.copy_code_block_buttons(false)
@ -621,7 +638,7 @@ impl HoverState {
snapshot: &EditorSnapshot,
visible_rows: Range<DisplayRow>,
max_size: Size<Pixels>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> Option<(DisplayPoint, Vec<AnyElement>)> {
// If there is a diagnostic, position the popovers based on that.
// Otherwise use the start of the hover range
@ -664,18 +681,18 @@ impl HoverState {
Some((point, elements))
}
pub fn focused(&self, cx: &mut ViewContext<Editor>) -> bool {
pub fn focused(&self, window: &mut Window, cx: &mut Context<Editor>) -> bool {
let mut hover_popover_is_focused = false;
for info_popover in &self.info_popovers {
if let Some(markdown_view) = &info_popover.parsed_content {
if markdown_view.focus_handle(cx).is_focused(cx) {
if markdown_view.focus_handle(cx).is_focused(window) {
hover_popover_is_focused = true;
}
}
}
if let Some(diagnostic_popover) = &self.diagnostic_popover {
if let Some(markdown_view) = &diagnostic_popover.parsed_content {
if markdown_view.focus_handle(cx).is_focused(cx) {
if markdown_view.focus_handle(cx).is_focused(window) {
hover_popover_is_focused = true;
}
}
@ -687,7 +704,7 @@ impl HoverState {
#[derive(Debug, Clone)]
pub(crate) struct InfoPopover {
pub(crate) symbol_range: RangeInEditor,
pub(crate) parsed_content: Option<View<Markdown>>,
pub(crate) parsed_content: Option<Entity<Markdown>>,
pub(crate) scroll_handle: ScrollHandle,
pub(crate) scrollbar_state: ScrollbarState,
pub(crate) keyboard_grace: Rc<RefCell<bool>>,
@ -698,7 +715,7 @@ impl InfoPopover {
pub(crate) fn render(
&mut self,
max_size: Size<Pixels>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> AnyElement {
let keyboard_grace = Rc::clone(&self.keyboard_grace);
let mut d = div()
@ -706,8 +723,8 @@ impl InfoPopover {
.elevation_2(cx)
// Prevent a mouse down/move on the popover from being propagated to the editor,
// because that would dismiss the popover.
.on_mouse_move(|_, cx| cx.stop_propagation())
.on_mouse_down(MouseButton::Left, move |_, cx| {
.on_mouse_move(|_, _, cx| cx.stop_propagation())
.on_mouse_down(MouseButton::Left, move |_, _, cx| {
let mut keyboard_grace = keyboard_grace.borrow_mut();
*keyboard_grace = false;
cx.stop_propagation();
@ -730,37 +747,37 @@ impl InfoPopover {
d.into_any_element()
}
pub fn scroll(&self, amount: &ScrollAmount, cx: &mut ViewContext<Editor>) {
pub fn scroll(&self, amount: &ScrollAmount, window: &mut Window, cx: &mut Context<Editor>) {
let mut current = self.scroll_handle.offset();
current.y -= amount.pixels(
cx.line_height(),
window.line_height(),
self.scroll_handle.bounds().size.height - px(16.),
) / 2.0;
cx.notify();
self.scroll_handle.set_offset(current);
}
fn render_vertical_scrollbar(&self, cx: &mut ViewContext<Editor>) -> Stateful<Div> {
fn render_vertical_scrollbar(&self, cx: &mut Context<Editor>) -> Stateful<Div> {
div()
.occlude()
.id("info-popover-vertical-scroll")
.on_mouse_move(cx.listener(|_, _, cx| {
.on_mouse_move(cx.listener(|_, _, _, cx| {
cx.notify();
cx.stop_propagation()
}))
.on_hover(|_, cx| {
.on_hover(|_, _, cx| {
cx.stop_propagation();
})
.on_any_mouse_down(|_, cx| {
.on_any_mouse_down(|_, _, cx| {
cx.stop_propagation();
})
.on_mouse_up(
MouseButton::Left,
cx.listener(|_, _, cx| {
cx.listener(|_, _, _, cx| {
cx.stop_propagation();
}),
)
.on_scroll_wheel(cx.listener(|_, _, cx| {
.on_scroll_wheel(cx.listener(|_, _, _, cx| {
cx.notify();
}))
.h_full()
@ -777,7 +794,7 @@ impl InfoPopover {
#[derive(Debug, Clone)]
pub struct DiagnosticPopover {
pub(crate) local_diagnostic: DiagnosticEntry<Anchor>,
parsed_content: Option<View<Markdown>>,
parsed_content: Option<Entity<Markdown>>,
border_color: Option<Hsla>,
background_color: Option<Hsla>,
pub keyboard_grace: Rc<RefCell<bool>>,
@ -785,7 +802,7 @@ pub struct DiagnosticPopover {
}
impl DiagnosticPopover {
pub fn render(&self, max_size: Size<Pixels>, cx: &mut ViewContext<Editor>) -> AnyElement {
pub fn render(&self, max_size: Size<Pixels>, cx: &mut Context<Editor>) -> AnyElement {
let keyboard_grace = Rc::clone(&self.keyboard_grace);
let mut markdown_div = div().py_1().px_2();
if let Some(markdown) = &self.parsed_content {
@ -812,15 +829,15 @@ impl DiagnosticPopover {
.elevation_2_borderless(cx)
// Don't draw the background color if the theme
// allows transparent surfaces.
.when(window_is_transparent(cx), |this| {
.when(theme_is_transparent(cx), |this| {
this.bg(gpui::transparent_black())
})
// Prevent a mouse move on the popover from being propagated to the editor,
// because that would dismiss the popover.
.on_mouse_move(|_, cx| cx.stop_propagation())
.on_mouse_move(|_, _, cx| cx.stop_propagation())
// Prevent a mouse down on the popover from being propagated to the editor,
// because that would move the cursor.
.on_mouse_down(MouseButton::Left, move |_, cx| {
.on_mouse_down(MouseButton::Left, move |_, _, cx| {
let mut keyboard_grace = keyboard_grace.borrow_mut();
*keyboard_grace = false;
cx.stop_propagation();
@ -843,7 +860,7 @@ mod tests {
InlayId, PointForPosition,
};
use collections::BTreeSet;
use gpui::AppContext;
use gpui::App;
use indoc::indoc;
use language::{language_settings::InlayHintSettings, Diagnostic, DiagnosticSet};
use lsp::LanguageServerId;
@ -854,11 +871,11 @@ mod tests {
use text::Bias;
fn get_hover_popover_delay(cx: &gpui::TestAppContext) -> u64 {
cx.read(|cx: &AppContext| -> u64 { EditorSettings::get_global(cx).hover_popover_delay })
cx.read(|cx: &App| -> u64 { EditorSettings::get_global(cx).hover_popover_delay })
}
impl InfoPopover {
fn get_rendered_text(&self, cx: &gpui::AppContext) -> String {
fn get_rendered_text(&self, cx: &gpui::App) -> String {
let mut rendered_text = String::new();
if let Some(parsed_content) = self.parsed_content.clone() {
let markdown = parsed_content.read(cx);
@ -927,14 +944,14 @@ mod tests {
three
fn test() { printˇln!(); }
"});
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let anchor = snapshot
.buffer_snapshot
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
hover_at(editor, Some(anchor), cx)
hover_at(editor, Some(anchor), window, cx)
});
assert!(!cx.editor(|editor, _| editor.hover_state.visible()));
assert!(!cx.editor(|editor, _window, _cx| editor.hover_state.visible()));
// After delay, hover should be visible.
let symbol_range = cx.lsp_range(indoc! {"
@ -957,7 +974,7 @@ mod tests {
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
requests.next().await;
cx.editor(|editor, cx| {
cx.editor(|editor, _window, cx| {
assert!(editor.hover_state.visible());
assert_eq!(
editor.hover_state.info_popovers.len(),
@ -975,14 +992,14 @@ mod tests {
});
// check that the completion menu is still visible and that there still has only been 1 completion request
cx.editor(|editor, _| assert!(editor.context_menu_visible()));
cx.editor(|editor, _, _| assert!(editor.context_menu_visible()));
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
//apply a completion and check it was successfully applied
let _apply_additional_edits = cx.update_editor(|editor, cx| {
editor.context_menu_next(&Default::default(), cx);
let _apply_additional_edits = cx.update_editor(|editor, window, cx| {
editor.context_menu_next(&Default::default(), window, cx);
editor
.confirm_completion(&ConfirmCompletion::default(), cx)
.confirm_completion(&ConfirmCompletion::default(), window, cx)
.unwrap()
});
cx.assert_editor_state(indoc! {"
@ -993,11 +1010,11 @@ mod tests {
"});
// check that the completion menu is no longer visible and that there still has only been 1 completion request
cx.editor(|editor, _| assert!(!editor.context_menu_visible()));
cx.editor(|editor, _, _| assert!(!editor.context_menu_visible()));
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
//verify the information popover is still visible and unchanged
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
assert!(editor.hover_state.visible());
assert_eq!(
editor.hover_state.info_popovers.len(),
@ -1025,19 +1042,19 @@ mod tests {
let mut request = cx
.lsp
.handle_request::<lsp::request::HoverRequest, _, _>(|_, _| async move { Ok(None) });
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let anchor = snapshot
.buffer_snapshot
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
hover_at(editor, Some(anchor), cx)
hover_at(editor, Some(anchor), window, cx)
});
cx.background_executor
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
request.next().await;
// verify that the information popover is no longer visible
cx.editor(|editor, _| {
cx.editor(|editor, _, _| {
assert!(!editor.hover_state.visible());
});
}
@ -1063,14 +1080,14 @@ mod tests {
fn test() { printˇln!(); }
"});
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let anchor = snapshot
.buffer_snapshot
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
hover_at(editor, Some(anchor), cx)
hover_at(editor, Some(anchor), window, cx)
});
assert!(!cx.editor(|editor, _| editor.hover_state.visible()));
assert!(!cx.editor(|editor, _window, _cx| editor.hover_state.visible()));
// After delay, hover should be visible.
let symbol_range = cx.lsp_range(indoc! {"
@ -1090,7 +1107,7 @@ mod tests {
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
requests.next().await;
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
assert!(editor.hover_state.visible());
assert_eq!(
editor.hover_state.info_popovers.len(),
@ -1115,17 +1132,17 @@ mod tests {
let mut request = cx
.lsp
.handle_request::<lsp::request::HoverRequest, _, _>(|_, _| async move { Ok(None) });
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let anchor = snapshot
.buffer_snapshot
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
hover_at(editor, Some(anchor), cx)
hover_at(editor, Some(anchor), window, cx)
});
cx.background_executor
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
request.next().await;
cx.editor(|editor, _| {
cx.editor(|editor, _, _| {
assert!(!editor.hover_state.visible());
});
}
@ -1147,12 +1164,12 @@ mod tests {
cx.set_state(indoc! {"
fˇn test() { println!(); }
"});
cx.update_editor(|editor, cx| hover(editor, &Hover, cx));
cx.update_editor(|editor, window, cx| hover(editor, &Hover, window, cx));
let symbol_range = cx.lsp_range(indoc! {"
«fn» test() { println!(); }
"});
cx.editor(|editor, _cx| {
cx.editor(|editor, _window, _cx| {
assert!(!editor.hover_state.visible());
assert_eq!(
@ -1178,7 +1195,7 @@ mod tests {
cx.dispatch_action(Hover);
cx.condition(|editor, _| editor.hover_state.visible()).await;
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
assert_eq!(
editor.hover_state.info_popovers.len(),
1,
@ -1214,7 +1231,7 @@ mod tests {
cx.set_state(indoc! {"
fˇn test() { println!(); }
"});
cx.update_editor(|editor, cx| hover(editor, &Hover, cx));
cx.update_editor(|editor, window, cx| hover(editor, &Hover, window, cx));
let symbol_range = cx.lsp_range(indoc! {"
«fn» test() { println!(); }
"});
@ -1236,7 +1253,7 @@ mod tests {
cx.dispatch_action(Hover);
cx.condition(|editor, _| editor.hover_state.visible()).await;
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
assert_eq!(
editor.hover_state.info_popovers.len(),
1,
@ -1275,7 +1292,7 @@ mod tests {
cx.set_state(indoc! {"
fˇn test() { println!(); }
"});
cx.update_editor(|editor, cx| hover(editor, &Hover, cx));
cx.update_editor(|editor, window, cx| hover(editor, &Hover, window, cx));
let symbol_range = cx.lsp_range(indoc! {"
«fn» test() { println!(); }
"});
@ -1302,7 +1319,7 @@ mod tests {
cx.dispatch_action(Hover);
cx.condition(|editor, _| editor.hover_state.visible()).await;
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
assert_eq!(
editor.hover_state.info_popovers.len(),
1,
@ -1362,10 +1379,10 @@ mod tests {
});
// Hover pops diagnostic immediately
cx.update_editor(|editor, cx| hover(editor, &Hover, cx));
cx.update_editor(|editor, window, cx| hover(editor, &Hover, window, cx));
cx.background_executor.run_until_parked();
cx.editor(|Editor { hover_state, .. }, _| {
cx.editor(|Editor { hover_state, .. }, _, _| {
assert!(
hover_state.diagnostic_popover.is_some() && hover_state.info_popovers.is_empty()
)
@ -1388,7 +1405,7 @@ mod tests {
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
cx.background_executor.run_until_parked();
cx.editor(|Editor { hover_state, .. }, _| {
cx.editor(|Editor { hover_state, .. }, _, _| {
hover_state.diagnostic_popover.is_some() && hover_state.info_task.is_some()
});
}
@ -1437,10 +1454,10 @@ mod tests {
}))
}
});
cx.update_editor(|editor, cx| hover(editor, &Default::default(), cx));
cx.update_editor(|editor, window, cx| hover(editor, &Default::default(), window, cx));
cx.run_until_parked();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, _, cx| {
let popover = editor.hover_state.info_popovers.first().unwrap();
let content = popover.get_rendered_text(cx);
@ -1552,7 +1569,7 @@ mod tests {
.next()
.await;
cx.background_executor.run_until_parked();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, _, cx| {
let expected_layers = vec![entire_hint_label.to_string()];
assert_eq!(expected_layers, cached_hint_labels(editor));
assert_eq!(expected_layers, visible_hint_labels(editor, cx));
@ -1573,8 +1590,8 @@ mod tests {
.first()
.cloned()
.unwrap();
let new_type_hint_part_hover_position = cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
let new_type_hint_part_hover_position = cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let previous_valid = inlay_range.start.to_display_point(&snapshot);
let next_valid = inlay_range.end.to_display_point(&snapshot);
assert_eq!(previous_valid.row(), next_valid.row());
@ -1592,13 +1609,14 @@ mod tests {
column_overshoot_after_line_end: 0,
}
});
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, window, cx| {
update_inlay_link_and_hover_points(
&editor.snapshot(cx),
&editor.snapshot(window, cx),
new_type_hint_part_hover_position,
editor,
true,
false,
window,
cx,
);
});
@ -1662,20 +1680,21 @@ mod tests {
.await;
cx.background_executor.run_until_parked();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, window, cx| {
update_inlay_link_and_hover_points(
&editor.snapshot(cx),
&editor.snapshot(window, cx),
new_type_hint_part_hover_position,
editor,
true,
false,
window,
cx,
);
});
cx.background_executor
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
cx.background_executor.run_until_parked();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, _, cx| {
let hover_state = &editor.hover_state;
assert!(
hover_state.diagnostic_popover.is_none() && hover_state.info_popovers.len() == 1
@ -1697,8 +1716,8 @@ mod tests {
);
});
let struct_hint_part_hover_position = cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
let struct_hint_part_hover_position = cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
let previous_valid = inlay_range.start.to_display_point(&snapshot);
let next_valid = inlay_range.end.to_display_point(&snapshot);
assert_eq!(previous_valid.row(), next_valid.row());
@ -1716,20 +1735,21 @@ mod tests {
column_overshoot_after_line_end: 0,
}
});
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, window, cx| {
update_inlay_link_and_hover_points(
&editor.snapshot(cx),
&editor.snapshot(window, cx),
struct_hint_part_hover_position,
editor,
true,
false,
window,
cx,
);
});
cx.background_executor
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
cx.background_executor.run_until_parked();
cx.update_editor(|editor, cx| {
cx.update_editor(|editor, _, cx| {
let hover_state = &editor.hover_state;
assert!(
hover_state.diagnostic_popover.is_none() && hover_state.info_popovers.len() == 1

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,10 @@
use std::{ops::Range, time::Duration};
use collections::HashSet;
use gpui::{AppContext, Task};
use gpui::{App, Context, Task, Window};
use language::language_settings::language_settings;
use multi_buffer::{IndentGuide, MultiBufferRow};
use text::{LineIndent, Point};
use ui::ViewContext;
use util::ResultExt;
use crate::{DisplaySnapshot, Editor};
@ -34,7 +33,7 @@ impl Editor {
&self,
visible_buffer_range: Range<MultiBufferRow>,
snapshot: &DisplaySnapshot,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> Option<Vec<IndentGuide>> {
let show_indent_guides = self.should_show_indent_guides().unwrap_or_else(|| {
if let Some(buffer) = self.buffer().read(cx).as_singleton() {
@ -67,7 +66,8 @@ impl Editor {
&mut self,
indent_guides: &[IndentGuide],
snapshot: &DisplaySnapshot,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Option<HashSet<usize>> {
let selection = self.selections.newest::<Point>(cx);
let cursor_row = MultiBufferRow(selection.head().row);
@ -113,15 +113,16 @@ impl Editor {
{
Ok(result) => state.active_indent_range = result,
Err(future) => {
state.pending_refresh = Some(cx.spawn(|editor, mut cx| async move {
let result = cx.background_executor().spawn(future).await;
editor
.update(&mut cx, |editor, _| {
editor.active_indent_guides_state.active_indent_range = result;
editor.active_indent_guides_state.pending_refresh = None;
})
.log_err();
}));
state.pending_refresh =
Some(cx.spawn_in(window, |editor, mut cx| async move {
let result = cx.background_executor().spawn(future).await;
editor
.update(&mut cx, |editor, _| {
editor.active_indent_guides_state.active_indent_range = result;
editor.active_indent_guides_state.pending_refresh = None;
})
.log_err();
}));
return None;
}
}
@ -154,7 +155,7 @@ pub fn indent_guides_in_range(
visible_buffer_range: Range<MultiBufferRow>,
ignore_disabled_for_language: bool,
snapshot: &DisplaySnapshot,
cx: &AppContext,
cx: &App,
) -> Vec<IndentGuide> {
let start_anchor = snapshot
.buffer_snapshot

View file

@ -16,10 +16,10 @@ use std::{
use crate::{
display_map::Inlay, Anchor, Editor, ExcerptId, InlayId, MultiBuffer, MultiBufferSnapshot,
};
use anyhow::Context;
use anyhow::Context as _;
use clock::Global;
use futures::future;
use gpui::{AsyncWindowContext, Model, ModelContext, Task, ViewContext};
use gpui::{AsyncAppContext, Context, Entity, Task, Window};
use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot};
use parking_lot::RwLock;
use project::{InlayHint, ResolveState};
@ -281,10 +281,10 @@ impl InlayHintCache {
/// Does not update inlay hint cache state on disabling or inlay hint kinds change: only reenabling forces new LSP queries.
pub(super) fn update_settings(
&mut self,
multi_buffer: &Model<MultiBuffer>,
multi_buffer: &Entity<MultiBuffer>,
new_hint_settings: InlayHintSettings,
visible_hints: Vec<Inlay>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> ControlFlow<Option<InlaySplice>> {
let old_enabled = self.enabled;
// If the setting for inlay hints has changed, update `enabled`. This condition avoids inlay
@ -348,10 +348,10 @@ impl InlayHintCache {
pub(super) fn spawn_hint_refresh(
&mut self,
reason_description: &'static str,
excerpts_to_query: HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)>,
excerpts_to_query: HashMap<ExcerptId, (Entity<Buffer>, Global, Range<usize>)>,
invalidate: InvalidationStrategy,
ignore_debounce: bool,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> Option<InlaySplice> {
if !self.enabled {
return None;
@ -411,10 +411,10 @@ impl InlayHintCache {
fn new_allowed_hint_kinds_splice(
&self,
multi_buffer: &Model<MultiBuffer>,
multi_buffer: &Entity<MultiBuffer>,
visible_hints: &[Inlay],
new_kinds: &HashSet<Option<InlayHintKind>>,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> Option<InlaySplice> {
let old_kinds = &self.allowed_hint_kinds;
if new_kinds == old_kinds {
@ -582,7 +582,8 @@ impl InlayHintCache {
buffer_id: BufferId,
excerpt_id: ExcerptId,
id: InlayId,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if let Some(excerpt_hints) = self.hints.get(&excerpt_id) {
let mut guard = excerpt_hints.write();
@ -592,7 +593,7 @@ impl InlayHintCache {
let server_id = *server_id;
cached_hint.resolve_state = ResolveState::Resolving;
drop(guard);
cx.spawn(|editor, mut cx| async move {
cx.spawn_in(window, |editor, mut cx| async move {
let resolved_hint_task = editor.update(&mut cx, |editor, cx| {
let buffer = editor.buffer().read(cx).buffer(buffer_id)?;
editor.semantics_provider.as_ref()?.resolve_inlay_hint(
@ -640,10 +641,10 @@ fn debounce_value(debounce_ms: u64) -> Option<Duration> {
fn spawn_new_update_tasks(
editor: &mut Editor,
reason: &'static str,
excerpts_to_query: HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)>,
excerpts_to_query: HashMap<ExcerptId, (Entity<Buffer>, Global, Range<usize>)>,
invalidate: InvalidationStrategy,
update_cache_version: usize,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
excerpts_to_query
@ -738,9 +739,9 @@ impl QueryRanges {
fn determine_query_ranges(
multi_buffer: &mut MultiBuffer,
excerpt_id: ExcerptId,
excerpt_buffer: &Model<Buffer>,
excerpt_buffer: &Entity<Buffer>,
excerpt_visible_range: Range<usize>,
cx: &mut ModelContext<'_, MultiBuffer>,
cx: &mut Context<'_, MultiBuffer>,
) -> Option<QueryRanges> {
let full_excerpt_range = multi_buffer
.excerpts_for_buffer(excerpt_buffer, cx)
@ -809,8 +810,8 @@ const INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS: u64 = 400;
fn new_update_task(
query: ExcerptQuery,
query_ranges: QueryRanges,
excerpt_buffer: Model<Buffer>,
cx: &mut ViewContext<Editor>,
excerpt_buffer: Entity<Buffer>,
cx: &mut Context<Editor>,
) -> Task<()> {
cx.spawn(move |editor, mut cx| async move {
let visible_range_update_results = future::join_all(
@ -839,7 +840,7 @@ fn new_update_task(
));
let query_range_failed =
|range: &Range<language::Anchor>, e: anyhow::Error, cx: &mut AsyncWindowContext| {
|range: &Range<language::Anchor>, e: anyhow::Error, cx: &mut AsyncAppContext| {
log::error!("inlay hint update task for range failed: {e:#?}");
editor
.update(cx, |editor, cx| {
@ -892,11 +893,11 @@ fn new_update_task(
}
fn fetch_and_update_hints(
excerpt_buffer: Model<Buffer>,
excerpt_buffer: Entity<Buffer>,
query: ExcerptQuery,
fetch_range: Range<language::Anchor>,
invalidate: bool,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) -> Task<anyhow::Result<()>> {
cx.spawn(|editor, mut cx| async move {
let buffer_snapshot = excerpt_buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
@ -1018,7 +1019,7 @@ fn fetch_and_update_hints(
);
log::trace!("New update: {new_update:?}");
editor
.update(&mut cx, |editor, cx| {
.update(&mut cx, |editor, cx| {
apply_hint_update(
editor,
new_update,
@ -1142,7 +1143,7 @@ fn apply_hint_update(
invalidate: bool,
buffer_snapshot: BufferSnapshot,
multi_buffer_snapshot: MultiBufferSnapshot,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
let cached_excerpt_hints = editor
.inlay_hint_cache
@ -1262,7 +1263,7 @@ pub mod tests {
use crate::scroll::ScrollAmount;
use crate::{scroll::Autoscroll, test::editor_lsp_test_context::rust_lang, ExcerptRange};
use futures::StreamExt;
use gpui::{Context, SemanticVersion, TestAppContext, WindowHandle};
use gpui::{AppContext as _, Context, SemanticVersion, TestAppContext, WindowHandle};
use itertools::Itertools as _;
use language::{language_settings::AllLanguageSettingsContent, Capability, FakeLspAdapter};
use language::{Language, LanguageConfig, LanguageMatcher};
@ -1317,7 +1318,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(
expected_hints,
@ -1334,14 +1335,14 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input("some change", cx);
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| s.select_ranges([13..13]));
editor.handle_input("some change", window, cx);
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["2".to_string()];
assert_eq!(
expected_hints,
@ -1363,7 +1364,7 @@ pub mod tests {
.expect("inlay refresh request failed");
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["3".to_string()];
assert_eq!(
expected_hints,
@ -1422,7 +1423,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["0".to_string()];
assert_eq!(
expected_hints,
@ -1450,7 +1451,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["0".to_string()];
assert_eq!(
expected_hints,
@ -1470,7 +1471,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(
expected_hints,
@ -1588,14 +1589,15 @@ pub mod tests {
})
.await
.unwrap();
let rs_editor =
cx.add_window(|cx| Editor::for_buffer(rs_buffer, Some(project.clone()), cx));
let rs_editor = cx.add_window(|window, cx| {
Editor::for_buffer(rs_buffer, Some(project.clone()), window, cx)
});
cx.executor().run_until_parked();
let _rs_fake_server = rs_fake_servers.unwrap().next().await.unwrap();
cx.executor().run_until_parked();
rs_editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(
expected_hints,
@ -1613,13 +1615,14 @@ pub mod tests {
})
.await
.unwrap();
let md_editor = cx.add_window(|cx| Editor::for_buffer(md_buffer, Some(project), cx));
let md_editor =
cx.add_window(|window, cx| Editor::for_buffer(md_buffer, Some(project), window, cx));
cx.executor().run_until_parked();
let _md_fake_server = md_fake_servers.unwrap().next().await.unwrap();
cx.executor().run_until_parked();
md_editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(
expected_hints,
@ -1631,14 +1634,14 @@ pub mod tests {
.unwrap();
rs_editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input("some rs change", cx);
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| s.select_ranges([13..13]));
editor.handle_input("some rs change", window, cx);
})
.unwrap();
cx.executor().run_until_parked();
rs_editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
// TODO: Here, we do not get "2", because inserting another language server will trigger `RefreshInlayHints` event from the `LspStore`
// A project is listened in every editor, so each of them will react to this event.
//
@ -1654,7 +1657,7 @@ pub mod tests {
})
.unwrap();
md_editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(
expected_hints,
@ -1666,14 +1669,14 @@ pub mod tests {
.unwrap();
md_editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input("some md change", cx);
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| s.select_ranges([13..13]));
editor.handle_input("some md change", window, cx);
})
.unwrap();
cx.executor().run_until_parked();
md_editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["2".to_string()];
assert_eq!(
expected_hints,
@ -1684,7 +1687,7 @@ pub mod tests {
})
.unwrap();
rs_editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec!["3".to_string()];
assert_eq!(
expected_hints,
@ -1767,7 +1770,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
1,
@ -1800,7 +1803,7 @@ pub mod tests {
.expect("inlay refresh request failed");
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
2,
@ -1870,7 +1873,7 @@ pub mod tests {
})
});
cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
editor.update(cx, |editor, _, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
2,
@ -1913,7 +1916,7 @@ pub mod tests {
});
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
2,
@ -1941,7 +1944,7 @@ pub mod tests {
.expect("inlay refresh request failed");
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
2,
@ -1967,7 +1970,7 @@ pub mod tests {
});
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
3,
@ -2001,7 +2004,7 @@ pub mod tests {
.expect("inlay refresh request failed");
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
lsp_request_count.load(Ordering::Relaxed),
4,
@ -2075,9 +2078,9 @@ pub mod tests {
"initial change #3",
] {
editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input(change_after_opening, cx);
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| s.select_ranges([13..13]));
editor.handle_input(change_after_opening, window, cx);
})
.unwrap();
expected_changes.push(change_after_opening);
@ -2086,7 +2089,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let current_text = editor.text(cx);
for change in &expected_changes {
assert!(
@ -2119,9 +2122,9 @@ pub mod tests {
let task_editor = editor;
edits.push(cx.spawn(|mut cx| async move {
task_editor
.update(&mut cx, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input(async_later_change, cx);
.update(&mut cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| s.select_ranges([13..13]));
editor.handle_input(async_later_change, window, cx);
})
.unwrap();
}));
@ -2130,7 +2133,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let current_text = editor.text(cx);
for change in &expected_changes {
assert!(
@ -2238,7 +2241,8 @@ pub mod tests {
})
.await
.unwrap();
let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
let editor =
cx.add_window(|window, cx| Editor::for_buffer(buffer, Some(project), window, cx));
cx.executor().run_until_parked();
@ -2266,7 +2270,7 @@ pub mod tests {
lsp::Position::new(initial_visible_range.end.row * 2, 2);
let mut expected_invisible_query_start = lsp_initial_visible_range.end;
expected_invisible_query_start.character += 1;
editor.update(cx, |editor, cx| {
editor.update(cx, |editor, _window, cx| {
let ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
assert_eq!(ranges.len(), 2,
"When scroll is at the edge of a big document, its visible part and the same range further should be queried in order, but got: {ranges:?}");
@ -2290,14 +2294,14 @@ pub mod tests {
}).unwrap();
editor
.update(cx, |editor, cx| {
editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
.update(cx, |editor, window, cx| {
editor.scroll_screen(&ScrollAmount::Page(1.0), window, cx);
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
.update(cx, |editor, window, cx| {
editor.scroll_screen(&ScrollAmount::Page(1.0), window, cx);
})
.unwrap();
cx.executor().advance_clock(Duration::from_millis(
@ -2306,10 +2310,12 @@ pub mod tests {
cx.executor().run_until_parked();
let visible_range_after_scrolls = editor_visible_range(&editor, cx);
let visible_line_count = editor
.update(cx, |editor, _| editor.visible_line_count().unwrap())
.update(cx, |editor, _window, _| {
editor.visible_line_count().unwrap()
})
.unwrap();
let selection_in_cached_range = editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let ranges = lsp_request_ranges
.lock()
.drain(..)
@ -2362,8 +2368,8 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::center()), cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(Some(Autoscroll::center()), window, cx, |s| {
s.select_ranges([selection_in_cached_range..selection_in_cached_range])
});
})
@ -2372,7 +2378,7 @@ pub mod tests {
INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
));
cx.executor().run_until_parked();
editor.update(cx, |_, _| {
editor.update(cx, |_, _, _| {
let ranges = lsp_request_ranges
.lock()
.drain(..)
@ -2383,15 +2389,15 @@ pub mod tests {
}).unwrap();
editor
.update(cx, |editor, cx| {
editor.handle_input("++++more text++++", cx);
.update(cx, |editor, window, cx| {
editor.handle_input("++++more text++++", window, cx);
})
.unwrap();
cx.executor().advance_clock(Duration::from_millis(
INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
));
cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
editor.update(cx, |editor, _window, cx| {
let mut ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
ranges.sort_by_key(|r| r.start);
@ -2427,7 +2433,7 @@ pub mod tests {
cx: &mut gpui::TestAppContext,
) -> Range<Point> {
let ranges = editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
editor.excerpts_for_inlay_hints_query(None, cx)
})
.unwrap();
@ -2501,7 +2507,7 @@ pub mod tests {
})
.await
.unwrap();
let multibuffer = cx.new_model(|cx| {
let multibuffer = cx.new(|cx| {
let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
multibuffer.push_excerpts(
buffer_1.clone(),
@ -2567,8 +2573,9 @@ pub mod tests {
});
cx.executor().run_until_parked();
let editor = cx
.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), true, cx));
let editor = cx.add_window(|window, cx| {
Editor::for_multibuffer(multibuffer, Some(project.clone()), true, window, cx)
});
let editor_edited = Arc::new(AtomicBool::new(false));
let fake_server = fake_servers.next().await.unwrap();
@ -2641,7 +2648,7 @@ pub mod tests {
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
@ -2660,21 +2667,21 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(Some(Autoscroll::Next), window, cx, |s| {
s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
});
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
editor.change_selections(Some(Autoscroll::Next), window, cx, |s| {
s.select_ranges([Point::new(22, 0)..Point::new(22, 0)])
});
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
editor.change_selections(Some(Autoscroll::Next), window, cx, |s| {
s.select_ranges([Point::new(50, 0)..Point::new(50, 0)])
});
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
@ -2693,8 +2700,8 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(Some(Autoscroll::Next), window, cx, |s| {
s.select_ranges([Point::new(100, 0)..Point::new(100, 0)])
});
})
@ -2704,7 +2711,7 @@ pub mod tests {
));
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
@ -2726,8 +2733,8 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::Next), cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(Some(Autoscroll::Next), window, cx, |s| {
s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
});
})
@ -2737,7 +2744,7 @@ pub mod tests {
));
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
@ -2760,16 +2767,16 @@ pub mod tests {
editor_edited.store(true, Ordering::Release);
editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
s.select_ranges([Point::new(57, 0)..Point::new(57, 0)])
});
editor.handle_input("++++more text++++", cx);
editor.handle_input("++++more text++++", window, cx);
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec![
"main hint #0".to_string(),
"main hint #1".to_string(),
@ -2843,7 +2850,7 @@ pub mod tests {
})
.await
.unwrap();
let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
let (buffer_1_excerpts, buffer_2_excerpts) = multibuffer.update(cx, |multibuffer, cx| {
let buffer_1_excerpts = multibuffer.push_excerpts(
buffer_1.clone(),
@ -2868,8 +2875,9 @@ pub mod tests {
assert!(!buffer_2_excerpts.is_empty());
cx.executor().run_until_parked();
let editor = cx
.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), true, cx));
let editor = cx.add_window(|window, cx| {
Editor::for_multibuffer(multibuffer, Some(project.clone()), true, window, cx)
});
let editor_edited = Arc::new(AtomicBool::new(false));
let fake_server = fake_servers.next().await.unwrap();
let closure_editor_edited = Arc::clone(&editor_edited);
@ -2939,7 +2947,7 @@ pub mod tests {
.await;
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
vec!["main hint #0".to_string(), "other hint #0".to_string()],
sorted_cached_hint_labels(editor),
@ -2953,7 +2961,7 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
editor.buffer().update(cx, |multibuffer, cx| {
multibuffer.remove_excerpts(buffer_2_excerpts, cx)
})
@ -2961,7 +2969,7 @@ pub mod tests {
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert_eq!(
vec!["main hint #0".to_string()],
cached_hint_labels(editor),
@ -2987,7 +2995,7 @@ pub mod tests {
});
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["main hint #0".to_string()];
assert_eq!(
expected_hints,
@ -3073,19 +3081,20 @@ pub mod tests {
})
.await
.unwrap();
let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
let editor =
cx.add_window(|window, cx| Editor::for_buffer(buffer, Some(project), window, cx));
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
s.select_ranges([Point::new(10, 0)..Point::new(10, 0)])
})
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(expected_hints, cached_hint_labels(editor));
assert_eq!(expected_hints, visible_hint_labels(editor, cx));
@ -3134,14 +3143,14 @@ pub mod tests {
.await;
editor
.update(cx, |editor, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
.update(cx, |editor, window, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, window, cx)
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["1".to_string()];
assert_eq!(
expected_hints,
@ -3153,13 +3162,13 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
.update(cx, |editor, window, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, window, cx)
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert!(
cached_hint_labels(editor).is_empty(),
"Should clear hints after 2nd toggle"
@ -3181,7 +3190,7 @@ pub mod tests {
});
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
let expected_hints = vec!["2".to_string()];
assert_eq!(
expected_hints,
@ -3193,13 +3202,13 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
.update(cx, |editor, window, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, window, cx)
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert!(
cached_hint_labels(editor).is_empty(),
"Should clear hints after enabling in settings and a 3rd toggle"
@ -3209,12 +3218,12 @@ pub mod tests {
.unwrap();
editor
.update(cx, |editor, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
.update(cx, |editor, window, cx| {
editor.toggle_inlay_hints(&crate::ToggleInlayHints, window, cx)
})
.unwrap();
cx.executor().run_until_parked();
editor.update(cx, |editor, cx| {
editor.update(cx, |editor, _, cx| {
let expected_hints = vec!["3".to_string()];
assert_eq!(
expected_hints,
@ -3346,19 +3355,20 @@ pub mod tests {
})
.await
.unwrap();
let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
let editor =
cx.add_window(|window, cx| Editor::for_buffer(buffer, Some(project), window, cx));
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| {
.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
s.select_ranges([Point::new(10, 0)..Point::new(10, 0)])
})
})
.unwrap();
cx.executor().run_until_parked();
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _window, cx| {
let expected_hints = vec![
"move".to_string(),
"(".to_string(),
@ -3429,10 +3439,11 @@ pub mod tests {
})
.await
.unwrap();
let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
let editor =
cx.add_window(|window, cx| Editor::for_buffer(buffer, Some(project), window, cx));
editor
.update(cx, |editor, cx| {
.update(cx, |editor, _, cx| {
assert!(cached_hint_labels(editor).is_empty());
assert!(visible_hint_labels(editor, cx).is_empty());
})
@ -3471,7 +3482,7 @@ pub mod tests {
labels
}
pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<Editor>) -> Vec<String> {
pub fn visible_hint_labels(editor: &Editor, cx: &Context<Editor>) -> Vec<String> {
editor
.visible_inlay_hints(cx)
.into_iter()

View file

@ -1,4 +1,4 @@
use gpui::{prelude::*, Model};
use gpui::{prelude::*, Entity};
use indoc::indoc;
use inline_completion::InlineCompletionProvider;
use language::{Language, LanguageConfig};
@ -15,12 +15,12 @@ async fn test_inline_completion_insert(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
let provider = cx.new_model(|_| FakeInlineCompletionProvider::default());
let provider = cx.new(|_| FakeInlineCompletionProvider::default());
assign_editor_completion_provider(provider.clone(), &mut cx);
cx.set_state("let absolute_zero_celsius = ˇ;");
propose_edits(&provider, vec![(28..28, "-273.15")], &mut cx);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_edit_completion(&mut cx, |_, edits| {
assert_eq!(edits.len(), 1);
@ -37,12 +37,12 @@ async fn test_inline_completion_modification(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
let provider = cx.new_model(|_| FakeInlineCompletionProvider::default());
let provider = cx.new(|_| FakeInlineCompletionProvider::default());
assign_editor_completion_provider(provider.clone(), &mut cx);
cx.set_state("let pi = ˇ\"foo\";");
propose_edits(&provider, vec![(9..14, "3.14159")], &mut cx);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_edit_completion(&mut cx, |_, edits| {
assert_eq!(edits.len(), 1);
@ -59,7 +59,7 @@ async fn test_inline_completion_jump_button(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
let provider = cx.new_model(|_| FakeInlineCompletionProvider::default());
let provider = cx.new(|_| FakeInlineCompletionProvider::default());
assign_editor_completion_provider(provider.clone(), &mut cx);
// Cursor is 2+ lines above the proposed edit
@ -77,7 +77,7 @@ async fn test_inline_completion_jump_button(cx: &mut gpui::TestAppContext) {
&mut cx,
);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_move_completion(&mut cx, |snapshot, move_target| {
assert_eq!(move_target.to_point(&snapshot), Point::new(4, 3));
});
@ -107,7 +107,7 @@ async fn test_inline_completion_jump_button(cx: &mut gpui::TestAppContext) {
&mut cx,
);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_move_completion(&mut cx, |snapshot, move_target| {
assert_eq!(move_target.to_point(&snapshot), Point::new(1, 3));
});
@ -140,7 +140,7 @@ async fn test_indentation(cx: &mut gpui::TestAppContext) {
let mut cx = EditorTestContext::new(cx).await;
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
let provider = cx.new_model(|_| FakeInlineCompletionProvider::default());
let provider = cx.new(|_| FakeInlineCompletionProvider::default());
assign_editor_completion_provider(provider.clone(), &mut cx);
cx.set_state(indoc! {"
@ -154,7 +154,7 @@ async fn test_indentation(cx: &mut gpui::TestAppContext) {
vec![(Point::new(1, 0)..Point::new(1, 0), " const function()")],
&mut cx,
);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_edit_completion(&mut cx, |_, edits| {
assert_eq!(edits.len(), 1);
@ -176,7 +176,7 @@ async fn test_inline_completion_invalidation_range(cx: &mut gpui::TestAppContext
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
let provider = cx.new_model(|_| FakeInlineCompletionProvider::default());
let provider = cx.new(|_| FakeInlineCompletionProvider::default());
assign_editor_completion_provider(provider.clone(), &mut cx);
// Cursor is 3+ lines above the proposed edit
@ -196,7 +196,7 @@ async fn test_inline_completion_invalidation_range(cx: &mut gpui::TestAppContext
&mut cx,
);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_move_completion(&mut cx, |snapshot, move_target| {
assert_eq!(move_target.to_point(&snapshot), edit_location);
});
@ -223,7 +223,7 @@ async fn test_inline_completion_invalidation_range(cx: &mut gpui::TestAppContext
line 4
line
"});
cx.editor(|editor, _| {
cx.editor(|editor, _, _| {
assert!(editor.active_inline_completion.is_none());
});
@ -244,7 +244,7 @@ async fn test_inline_completion_invalidation_range(cx: &mut gpui::TestAppContext
&mut cx,
);
cx.update_editor(|editor, cx| editor.update_visible_inline_completion(cx));
cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
assert_editor_active_move_completion(&mut cx, |snapshot, move_target| {
assert_eq!(move_target.to_point(&snapshot), edit_location);
});
@ -271,7 +271,7 @@ async fn test_inline_completion_invalidation_range(cx: &mut gpui::TestAppContext
line 4
line ˇ5
"});
cx.editor(|editor, _| {
cx.editor(|editor, _, _| {
assert!(editor.active_inline_completion.is_none());
});
}
@ -280,7 +280,7 @@ fn assert_editor_active_edit_completion(
cx: &mut EditorTestContext,
assert: impl FnOnce(MultiBufferSnapshot, &Vec<(Range<Anchor>, String)>),
) {
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
let completion_state = editor
.active_inline_completion
.as_ref()
@ -298,7 +298,7 @@ fn assert_editor_active_move_completion(
cx: &mut EditorTestContext,
assert: impl FnOnce(MultiBufferSnapshot, Anchor),
) {
cx.editor(|editor, cx| {
cx.editor(|editor, _, cx| {
let completion_state = editor
.active_inline_completion
.as_ref()
@ -313,13 +313,13 @@ fn assert_editor_active_move_completion(
}
fn accept_completion(cx: &mut EditorTestContext) {
cx.update_editor(|editor, cx| {
editor.accept_inline_completion(&crate::AcceptInlineCompletion, cx)
cx.update_editor(|editor, window, cx| {
editor.accept_inline_completion(&crate::AcceptInlineCompletion, window, cx)
})
}
fn propose_edits<T: ToOffset>(
provider: &Model<FakeInlineCompletionProvider>,
provider: &Entity<FakeInlineCompletionProvider>,
edits: Vec<(Range<T>, &str)>,
cx: &mut EditorTestContext,
) {
@ -329,7 +329,7 @@ fn propose_edits<T: ToOffset>(
(range, text.into())
});
cx.update(|cx| {
cx.update(|_, cx| {
provider.update(cx, |provider, _| {
provider.set_inline_completion(Some(inline_completion::InlineCompletion {
edits: edits.collect(),
@ -340,11 +340,11 @@ fn propose_edits<T: ToOffset>(
}
fn assign_editor_completion_provider(
provider: Model<FakeInlineCompletionProvider>,
provider: Entity<FakeInlineCompletionProvider>,
cx: &mut EditorTestContext,
) {
cx.update_editor(|editor, cx| {
editor.set_inline_completion_provider(Some(provider), cx);
cx.update_editor(|editor, window, cx| {
editor.set_inline_completion_provider(Some(provider), window, cx);
})
}
@ -381,9 +381,9 @@ impl InlineCompletionProvider for FakeInlineCompletionProvider {
fn is_enabled(
&self,
_buffer: &gpui::Model<language::Buffer>,
_buffer: &gpui::Entity<language::Buffer>,
_cursor_position: language::Anchor,
_cx: &gpui::AppContext,
_cx: &gpui::App,
) -> bool {
true
}
@ -394,31 +394,31 @@ impl InlineCompletionProvider for FakeInlineCompletionProvider {
fn refresh(
&mut self,
_buffer: gpui::Model<language::Buffer>,
_buffer: gpui::Entity<language::Buffer>,
_cursor_position: language::Anchor,
_debounce: bool,
_cx: &mut gpui::ModelContext<Self>,
_cx: &mut gpui::Context<Self>,
) {
}
fn cycle(
&mut self,
_buffer: gpui::Model<language::Buffer>,
_buffer: gpui::Entity<language::Buffer>,
_cursor_position: language::Anchor,
_direction: inline_completion::Direction,
_cx: &mut gpui::ModelContext<Self>,
_cx: &mut gpui::Context<Self>,
) {
}
fn accept(&mut self, _cx: &mut gpui::ModelContext<Self>) {}
fn accept(&mut self, _cx: &mut gpui::Context<Self>) {}
fn discard(&mut self, _cx: &mut gpui::ModelContext<Self>) {}
fn discard(&mut self, _cx: &mut gpui::Context<Self>) {}
fn suggest<'a>(
&mut self,
_buffer: &gpui::Model<language::Buffer>,
_buffer: &gpui::Entity<language::Buffer>,
_cursor_position: language::Anchor,
_cx: &mut gpui::ModelContext<Self>,
_cx: &mut gpui::Context<Self>,
) -> Option<inline_completion::InlineCompletion> {
self.completion.clone()
}

View file

@ -11,9 +11,8 @@ use file_icons::FileIcons;
use futures::future::try_join_all;
use git::status::GitSummary;
use gpui::{
point, AnyElement, AppContext, AsyncWindowContext, Context, Entity, EntityId, EventEmitter,
IntoElement, Model, ParentElement, Pixels, SharedString, Styled, Task, View, ViewContext,
VisualContext, WeakView, WindowContext,
point, AnyElement, App, AsyncWindowContext, Context, Entity, EntityId, EventEmitter,
IntoElement, ParentElement, Pixels, SharedString, Styled, Task, WeakEntity, Window,
};
use language::{
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, DiskState, Point,
@ -55,11 +54,12 @@ impl FollowableItem for Editor {
}
fn from_state_proto(
workspace: View<Workspace>,
workspace: Entity<Workspace>,
remote_id: ViewId,
state: &mut Option<proto::view::Variant>,
cx: &mut WindowContext,
) -> Option<Task<Result<View<Self>>>> {
window: &mut Window,
cx: &mut App,
) -> Option<Task<Result<Entity<Self>>>> {
let project = workspace.read(cx).project().to_owned();
let Some(proto::view::Variant::Editor(_)) = state else {
return None;
@ -80,13 +80,13 @@ impl FollowableItem for Editor {
.collect::<Result<Vec<_>>>()
});
Some(cx.spawn(|mut cx| async move {
Some(window.spawn(cx, |mut cx| async move {
let mut buffers = futures::future::try_join_all(buffers?)
.await
.debug_assert_ok("leaders don't share views for unshared buffers")?;
let editor = cx.update(|cx| {
let multibuffer = cx.new_model(|cx| {
let editor = cx.update(|window, cx| {
let multibuffer = cx.new(|cx| {
let mut multibuffer;
if state.singleton && buffers.len() == 1 {
multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
@ -121,9 +121,14 @@ impl FollowableItem for Editor {
multibuffer
});
cx.new_view(|cx| {
let mut editor =
Editor::for_multibuffer(multibuffer, Some(project.clone()), true, cx);
cx.new(|cx| {
let mut editor = Editor::for_multibuffer(
multibuffer,
Some(project.clone()),
true,
window,
cx,
);
editor.remote_id = Some(remote_id);
editor
})
@ -148,13 +153,18 @@ impl FollowableItem for Editor {
}))
}
fn set_leader_peer_id(&mut self, leader_peer_id: Option<PeerId>, cx: &mut ViewContext<Self>) {
fn set_leader_peer_id(
&mut self,
leader_peer_id: Option<PeerId>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.leader_peer_id = leader_peer_id;
if self.leader_peer_id.is_some() {
self.buffer.update(cx, |buffer, cx| {
buffer.remove_active_selections(cx);
});
} else if self.focus_handle.is_focused(cx) {
} else if self.focus_handle.is_focused(window) {
self.buffer.update(cx, |buffer, cx| {
buffer.set_active_selections(
&self.selections.disjoint_anchors(),
@ -167,7 +177,7 @@ impl FollowableItem for Editor {
cx.notify();
}
fn to_state_proto(&self, cx: &WindowContext) -> Option<proto::view::Variant> {
fn to_state_proto(&self, _: &Window, cx: &App) -> Option<proto::view::Variant> {
let buffer = self.buffer.read(cx);
if buffer
.as_singleton()
@ -237,7 +247,8 @@ impl FollowableItem for Editor {
&self,
event: &EditorEvent,
update: &mut Option<proto::update_view::Variant>,
cx: &WindowContext,
_: &Window,
cx: &App,
) -> bool {
let update =
update.get_or_insert_with(|| proto::update_view::Variant::Editor(Default::default()));
@ -299,22 +310,23 @@ impl FollowableItem for Editor {
fn apply_update_proto(
&mut self,
project: &Model<Project>,
project: &Entity<Project>,
message: update_view::Variant,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
let update_view::Variant::Editor(message) = message;
let project = project.clone();
cx.spawn(|this, mut cx| async move {
cx.spawn_in(window, |this, mut cx| async move {
update_editor_from_message(this, project, message, &mut cx).await
})
}
fn is_project_item(&self, _cx: &WindowContext) -> bool {
fn is_project_item(&self, _window: &Window, _cx: &App) -> bool {
true
}
fn dedup(&self, existing: &Self, cx: &WindowContext) -> Option<Dedup> {
fn dedup(&self, existing: &Self, _: &Window, cx: &App) -> Option<Dedup> {
let self_singleton = self.buffer.read(cx).as_singleton()?;
let other_singleton = existing.buffer.read(cx).as_singleton()?;
if self_singleton == other_singleton {
@ -326,8 +338,8 @@ impl FollowableItem for Editor {
}
async fn update_editor_from_message(
this: WeakView<Editor>,
project: Model<Project>,
this: WeakEntity<Editor>,
project: Entity<Project>,
message: proto::update_view::Editor,
cx: &mut AsyncWindowContext,
) -> Result<()> {
@ -437,9 +449,9 @@ async fn update_editor_from_message(
.await?;
// Update the editor's state.
this.update(cx, |editor, cx| {
this.update_in(cx, |editor, window, cx| {
if !selections.is_empty() || pending_selection.is_some() {
editor.set_selections_from_remote(selections, pending_selection, cx);
editor.set_selections_from_remote(selections, pending_selection, window, cx);
editor.request_autoscroll_remotely(Autoscroll::newest(), cx);
} else if let Some(scroll_top_anchor) = scroll_top_anchor {
editor.set_scroll_anchor_remote(
@ -447,6 +459,7 @@ async fn update_editor_from_message(
anchor: scroll_top_anchor,
offset: point(message.scroll_x, message.scroll_y),
},
window,
cx,
);
}
@ -534,7 +547,12 @@ fn deserialize_anchor(buffer: &MultiBufferSnapshot, anchor: proto::EditorAnchor)
impl Item for Editor {
type Event = EditorEvent;
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
fn navigate(
&mut self,
data: Box<dyn std::any::Any>,
window: &mut Window,
cx: &mut Context<Self>,
) -> bool {
if let Ok(data) = data.downcast::<NavigationData>() {
let newest_selection = self.selections.newest::<Point>(cx);
let buffer = self.buffer.read(cx).read(cx);
@ -557,8 +575,8 @@ impl Item for Editor {
false
} else {
let nav_history = self.nav_history.take();
self.set_scroll_anchor(scroll_anchor, cx);
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
self.set_scroll_anchor(scroll_anchor, window, cx);
self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
s.select_ranges([offset..offset])
});
self.nav_history = nav_history;
@ -569,7 +587,7 @@ impl Item for Editor {
}
}
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString> {
fn tab_tooltip_text(&self, cx: &App) -> Option<SharedString> {
let file_path = self
.buffer()
.read(cx)
@ -588,12 +606,12 @@ impl Item for Editor {
None
}
fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString> {
fn tab_description(&self, detail: usize, cx: &App) -> Option<SharedString> {
let path = path_for_buffer(&self.buffer, detail, true, cx)?;
Some(path.to_string_lossy().to_string().into())
}
fn tab_icon(&self, cx: &WindowContext) -> Option<Icon> {
fn tab_icon(&self, _: &Window, cx: &App) -> Option<Icon> {
ItemSettings::get_global(cx)
.file_icons
.then(|| {
@ -607,7 +625,7 @@ impl Item for Editor {
.map(Icon::from_path)
}
fn tab_content(&self, params: TabContentParams, cx: &WindowContext) -> AnyElement {
fn tab_content(&self, params: TabContentParams, _: &Window, cx: &App) -> AnyElement {
let label_color = if ItemSettings::get_global(cx).git_status {
self.buffer()
.read(cx)
@ -673,7 +691,7 @@ impl Item for Editor {
fn for_each_project_item(
&self,
cx: &AppContext,
cx: &App,
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
) {
self.buffer
@ -681,53 +699,59 @@ impl Item for Editor {
.for_each_buffer(|buffer| f(buffer.entity_id(), buffer.read(cx)));
}
fn is_singleton(&self, cx: &AppContext) -> bool {
fn is_singleton(&self, cx: &App) -> bool {
self.buffer.read(cx).is_singleton()
}
fn clone_on_split(
&self,
_workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Editor>>
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Entity<Editor>>
where
Self: Sized,
{
Some(cx.new_view(|cx| self.clone(cx)))
Some(cx.new(|cx| self.clone(window, cx)))
}
fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
fn set_nav_history(
&mut self,
history: ItemNavHistory,
_window: &mut Window,
_: &mut Context<Self>,
) {
self.nav_history = Some(history);
}
fn discarded(&self, _project: Model<Project>, cx: &mut ViewContext<Self>) {
fn discarded(&self, _project: Entity<Project>, _: &mut Window, cx: &mut Context<Self>) {
for buffer in self.buffer().clone().read(cx).all_buffers() {
buffer.update(cx, |buffer, cx| buffer.discarded(cx))
}
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
fn deactivated(&mut self, _: &mut Window, cx: &mut Context<Self>) {
let selection = self.selections.newest_anchor();
self.push_to_nav_history(selection.head(), None, cx);
}
fn workspace_deactivated(&mut self, cx: &mut ViewContext<Self>) {
fn workspace_deactivated(&mut self, _: &mut Window, cx: &mut Context<Self>) {
self.hide_hovered_link(cx);
}
fn is_dirty(&self, cx: &AppContext) -> bool {
fn is_dirty(&self, cx: &App) -> bool {
self.buffer().read(cx).read(cx).is_dirty()
}
fn has_deleted_file(&self, cx: &AppContext) -> bool {
fn has_deleted_file(&self, cx: &App) -> bool {
self.buffer().read(cx).read(cx).has_deleted_file()
}
fn has_conflict(&self, cx: &AppContext) -> bool {
fn has_conflict(&self, cx: &App) -> bool {
self.buffer().read(cx).read(cx).has_conflict()
}
fn can_save(&self, cx: &AppContext) -> bool {
fn can_save(&self, cx: &App) -> bool {
let buffer = &self.buffer().read(cx);
if let Some(buffer) = buffer.as_singleton() {
buffer.read(cx).project_path(cx).is_some()
@ -739,8 +763,9 @@ impl Item for Editor {
fn save(
&mut self,
format: bool,
project: Model<Project>,
cx: &mut ViewContext<Self>,
project: Entity<Project>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
self.report_editor_event("Editor Saved", None, cx);
let buffers = self.buffer().clone().read(cx).all_buffers();
@ -748,13 +773,14 @@ impl Item for Editor {
.into_iter()
.map(|handle| handle.read(cx).base_buffer().unwrap_or(handle.clone()))
.collect::<HashSet<_>>();
cx.spawn(|this, mut cx| async move {
cx.spawn_in(window, |this, mut cx| async move {
if format {
this.update(&mut cx, |editor, cx| {
this.update_in(&mut cx, |editor, window, cx| {
editor.perform_format(
project.clone(),
FormatTrigger::Save,
FormatTarget::Buffers,
window,
cx,
)
})?
@ -800,9 +826,10 @@ impl Item for Editor {
fn save_as(
&mut self,
project: Model<Project>,
project: Entity<Project>,
path: ProjectPath,
cx: &mut ViewContext<Self>,
_: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
let buffer = self
.buffer()
@ -819,12 +846,17 @@ impl Item for Editor {
project.update(cx, |project, cx| project.save_buffer_as(buffer, path, cx))
}
fn reload(&mut self, project: Model<Project>, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
fn reload(
&mut self,
project: Entity<Project>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
let buffer = self.buffer().clone();
let buffers = self.buffer.read(cx).all_buffers();
let reload_buffers =
project.update(cx, |project, cx| project.reload_buffers(buffers, true, cx));
cx.spawn(|this, mut cx| async move {
cx.spawn_in(window, |this, mut cx| async move {
let transaction = reload_buffers.log_err().await;
this.update(&mut cx, |editor, cx| {
editor.request_autoscroll(Autoscroll::fit(), cx)
@ -842,15 +874,15 @@ impl Item for Editor {
})
}
fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
fn as_searchable(&self, handle: &Entity<Self>) -> Option<Box<dyn SearchableItemHandle>> {
Some(Box::new(handle.clone()))
}
fn pixel_position_of_cursor(&self, _: &AppContext) -> Option<gpui::Point<Pixels>> {
fn pixel_position_of_cursor(&self, _: &App) -> Option<gpui::Point<Pixels>> {
self.pixel_position_of_newest_cursor
}
fn breadcrumb_location(&self, _: &AppContext) -> ToolbarItemLocation {
fn breadcrumb_location(&self, _: &App) -> ToolbarItemLocation {
if self.show_breadcrumbs {
ToolbarItemLocation::PrimaryLeft
} else {
@ -858,7 +890,7 @@ impl Item for Editor {
}
}
fn breadcrumbs(&self, variant: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
fn breadcrumbs(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
let cursor = self.selections.newest_anchor().head();
let multibuffer = &self.buffer().read(cx);
let (buffer_id, symbols) =
@ -902,7 +934,12 @@ impl Item for Editor {
Some(breadcrumbs)
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, _: &mut ViewContext<Self>) {
fn added_to_workspace(
&mut self,
workspace: &mut Workspace,
_window: &mut Window,
_: &mut Context<Self>,
) {
self.workspace = Some((workspace.weak_handle(), workspace.database_id()));
}
@ -940,7 +977,7 @@ impl Item for Editor {
}
}
fn preserve_preview(&self, cx: &AppContext) -> bool {
fn preserve_preview(&self, cx: &App) -> bool {
self.buffer.read(cx).preserve_preview(cx)
}
}
@ -953,18 +990,20 @@ impl SerializableItem for Editor {
fn cleanup(
workspace_id: WorkspaceId,
alive_items: Vec<ItemId>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> Task<Result<()>> {
cx.spawn(|_| DB.delete_unloaded_items(workspace_id, alive_items))
window.spawn(cx, |_| DB.delete_unloaded_items(workspace_id, alive_items))
}
fn deserialize(
project: Model<Project>,
workspace: WeakView<Workspace>,
project: Entity<Project>,
workspace: WeakEntity<Workspace>,
workspace_id: workspace::WorkspaceId,
item_id: ItemId,
cx: &mut WindowContext,
) -> Task<Result<View<Self>>> {
window: &mut Window,
cx: &mut App,
) -> Task<Result<Entity<Self>>> {
let serialized_editor = match DB
.get_serialized_editor(item_id, workspace_id)
.context("Failed to query editor state")
@ -998,7 +1037,7 @@ impl SerializableItem for Editor {
contents: Some(contents),
language,
..
} => cx.spawn(|mut cx| {
} => window.spawn(cx, |mut cx| {
let project = project.clone();
async move {
let language = if let Some(language_name) = language {
@ -1028,11 +1067,11 @@ impl SerializableItem for Editor {
buffer.set_text(contents, cx);
})?;
cx.update(|cx| {
cx.new_view(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(project), cx);
cx.update(|window, cx| {
cx.new(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(project), window, cx);
editor.read_scroll_position_from_db(item_id, workspace_id, cx);
editor.read_scroll_position_from_db(item_id, workspace_id, window, cx);
editor
})
})
@ -1055,7 +1094,7 @@ impl SerializableItem for Editor {
match project_item {
Some(project_item) => {
cx.spawn(|mut cx| async move {
window.spawn(cx, |mut cx| async move {
let (_, project_item) = project_item.await?;
let buffer = project_item.downcast::<Buffer>().map_err(|_| {
anyhow!("Project item at stored path was not a buffer")
@ -1082,11 +1121,17 @@ impl SerializableItem for Editor {
})?;
}
cx.update(|cx| {
cx.new_view(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(project), cx);
cx.update(|window, cx| {
cx.new(|cx| {
let mut editor =
Editor::for_buffer(buffer, Some(project), window, cx);
editor.read_scroll_position_from_db(item_id, workspace_id, cx);
editor.read_scroll_position_from_db(
item_id,
workspace_id,
window,
cx,
);
editor
})
})
@ -1094,12 +1139,12 @@ impl SerializableItem for Editor {
}
None => {
let open_by_abs_path = workspace.update(cx, |workspace, cx| {
workspace.open_abs_path(abs_path.clone(), false, cx)
workspace.open_abs_path(abs_path.clone(), false, window, cx)
});
cx.spawn(|mut cx| async move {
window.spawn(cx, |mut cx| async move {
let editor = open_by_abs_path?.await?.downcast::<Editor>().with_context(|| format!("Failed to downcast to Editor after opening abs path {abs_path:?}"))?;
editor.update(&mut cx, |editor, cx| {
editor.read_scroll_position_from_db(item_id, workspace_id, cx);
editor.update_in(&mut cx, |editor, window, cx| {
editor.read_scroll_position_from_db(item_id, workspace_id, window, cx);
})?;
Ok(editor)
})
@ -1119,7 +1164,8 @@ impl SerializableItem for Editor {
workspace: &mut Workspace,
item_id: ItemId,
closing: bool,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Task<Result<()>>> {
let mut serialize_dirty_buffers = self.serialize_dirty_buffers;
@ -1156,7 +1202,7 @@ impl SerializableItem for Editor {
let snapshot = buffer.read(cx).snapshot();
Some(cx.spawn(|_this, cx| async move {
Some(cx.spawn_in(window, |_this, cx| async move {
cx.background_executor()
.spawn(async move {
let (contents, language) = if serialize_dirty_buffers && is_dirty {
@ -1173,7 +1219,6 @@ impl SerializableItem for Editor {
language,
mtime,
};
DB.save_serialized_editor(item_id, workspace_id, editor)
.await
.context("failed to save serialized editor")
@ -1197,11 +1242,12 @@ impl ProjectItem for Editor {
type Item = Buffer;
fn for_project_item(
project: Model<Project>,
buffer: Model<Buffer>,
cx: &mut ViewContext<Self>,
project: Entity<Project>,
buffer: Entity<Buffer>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
Self::for_buffer(buffer, Some(project), cx)
Self::for_buffer(buffer, Some(project), window, cx)
}
}
@ -1211,7 +1257,7 @@ pub(crate) enum BufferSearchHighlights {}
impl SearchableItem for Editor {
type Match = Range<Anchor>;
fn get_matches(&self, _: &mut WindowContext) -> Vec<Range<Anchor>> {
fn get_matches(&self, _window: &mut Window, _: &mut App) -> Vec<Range<Anchor>> {
self.background_highlights
.get(&TypeId::of::<BufferSearchHighlights>())
.map_or(Vec::new(), |(_color, ranges)| {
@ -1219,7 +1265,7 @@ impl SearchableItem for Editor {
})
}
fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
fn clear_matches(&mut self, _: &mut Window, cx: &mut Context<Self>) {
if self
.clear_background_highlights::<BufferSearchHighlights>(cx)
.is_some()
@ -1228,7 +1274,12 @@ impl SearchableItem for Editor {
}
}
fn update_matches(&mut self, matches: &[Range<Anchor>], cx: &mut ViewContext<Self>) {
fn update_matches(
&mut self,
matches: &[Range<Anchor>],
_: &mut Window,
cx: &mut Context<Self>,
) {
let existing_range = self
.background_highlights
.get(&TypeId::of::<BufferSearchHighlights>())
@ -1248,7 +1299,12 @@ impl SearchableItem for Editor {
self.has_background_highlights::<SearchWithinRange>()
}
fn toggle_filtered_search_ranges(&mut self, enabled: bool, cx: &mut ViewContext<Self>) {
fn toggle_filtered_search_ranges(
&mut self,
enabled: bool,
_: &mut Window,
cx: &mut Context<Self>,
) {
if self.has_filtered_search_ranges() {
self.previous_search_ranges = self
.clear_background_highlights::<SearchWithinRange>(cx)
@ -1267,9 +1323,9 @@ impl SearchableItem for Editor {
}
}
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
fn query_suggestion(&mut self, window: &mut Window, cx: &mut Context<Self>) -> String {
let setting = EditorSettings::get_global(cx).seed_search_query_from_cursor;
let snapshot = &self.snapshot(cx).buffer_snapshot;
let snapshot = &self.snapshot(window, cx).buffer_snapshot;
let selection = self.selections.newest::<usize>(cx);
match setting {
@ -1302,28 +1358,35 @@ impl SearchableItem for Editor {
&mut self,
index: usize,
matches: &[Range<Anchor>],
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.unfold_ranges(&[matches[index].clone()], false, true, cx);
let range = self.range_for_match(&matches[index]);
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
s.select_ranges([range]);
})
}
fn select_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext<Self>) {
fn select_matches(
&mut self,
matches: &[Self::Match],
window: &mut Window,
cx: &mut Context<Self>,
) {
self.unfold_ranges(matches, 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));
self.change_selections(None, window, cx, |s| s.select_ranges(ranges));
}
fn replace(
&mut self,
identifier: &Self::Match,
query: &SearchQuery,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
let text = self.buffer.read(cx);
let text = text.snapshot(cx);
@ -1336,7 +1399,7 @@ impl SearchableItem for Editor {
};
if let Some(replacement) = query.replacement_for(&text) {
self.transact(cx, |this, cx| {
self.transact(window, cx, |this, _, cx| {
this.edit([(identifier.clone(), Arc::from(&*replacement))], cx);
});
}
@ -1345,7 +1408,8 @@ impl SearchableItem for Editor {
&mut self,
matches: &mut dyn Iterator<Item = &Self::Match>,
query: &SearchQuery,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
let text = self.buffer.read(cx);
let text = text.snapshot(cx);
@ -1365,7 +1429,7 @@ impl SearchableItem for Editor {
}
if !edits.is_empty() {
self.transact(cx, |this, cx| {
self.transact(window, cx, |this, _, cx| {
this.edit(edits, cx);
});
}
@ -1376,7 +1440,8 @@ impl SearchableItem for Editor {
current_index: usize,
direction: Direction,
count: usize,
cx: &mut ViewContext<Self>,
_: &mut Window,
cx: &mut Context<Self>,
) -> usize {
let buffer = self.buffer().read(cx).snapshot(cx);
let current_index_position = if self.selections.disjoint_anchors().len() == 1 {
@ -1422,7 +1487,8 @@ impl SearchableItem for Editor {
fn find_matches(
&mut self,
query: Arc<project::search::SearchQuery>,
cx: &mut ViewContext<Self>,
_: &mut Window,
cx: &mut Context<Self>,
) -> Task<Vec<Range<Anchor>>> {
let buffer = self.buffer().read(cx).snapshot(cx);
let search_within_ranges = self
@ -1470,7 +1536,8 @@ impl SearchableItem for Editor {
fn active_match_index(
&mut self,
matches: &[Range<Anchor>],
cx: &mut ViewContext<Self>,
_: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
active_match_index(
matches,
@ -1479,7 +1546,7 @@ impl SearchableItem for Editor {
)
}
fn search_bar_visibility_changed(&mut self, _visible: bool, _cx: &mut ViewContext<Self>) {
fn search_bar_visibility_changed(&mut self, _: bool, _: &mut Window, _: &mut Context<Self>) {
self.expect_bounds_change = self.last_bounds;
}
}
@ -1550,10 +1617,10 @@ pub fn entry_git_aware_label_color(git_status: GitSummary, ignored: bool, select
}
fn path_for_buffer<'a>(
buffer: &Model<MultiBuffer>,
buffer: &Entity<MultiBuffer>,
height: usize,
include_filename: bool,
cx: &'a AppContext,
cx: &'a App,
) -> Option<Cow<'a, Path>> {
let file = buffer.read(cx).as_singleton()?.read(cx).file()?;
path_for_file(file.as_ref(), height, include_filename, cx)
@ -1563,7 +1630,7 @@ fn path_for_file<'a>(
file: &'a dyn language::File,
mut height: usize,
include_filename: bool,
cx: &'a AppContext,
cx: &'a App,
) -> Option<Cow<'a, Path>> {
// Ensure we always render at least the filename.
height += 1;
@ -1604,13 +1671,13 @@ mod tests {
use super::*;
use fs::MTime;
use gpui::{AppContext, VisualTestContext};
use gpui::{App, VisualTestContext};
use language::{LanguageMatcher, TestFile};
use project::FakeFs;
use std::path::{Path, PathBuf};
#[gpui::test]
fn test_path_for_file(cx: &mut AppContext) {
fn test_path_for_file(cx: &mut App) {
let file = TestFile {
path: Path::new("").into(),
root_name: String::new(),
@ -1621,12 +1688,12 @@ mod tests {
async fn deserialize_editor(
item_id: ItemId,
workspace_id: WorkspaceId,
workspace: View<Workspace>,
project: Model<Project>,
workspace: Entity<Workspace>,
project: Entity<Project>,
cx: &mut VisualTestContext,
) -> View<Editor> {
) -> Entity<Editor> {
workspace
.update(cx, |workspace, cx| {
.update_in(cx, |workspace, window, cx| {
let pane = workspace.active_pane();
pane.update(cx, |_, cx| {
Editor::deserialize(
@ -1634,6 +1701,7 @@ mod tests {
workspace.weak_handle(),
workspace_id,
item_id,
window,
cx,
)
})
@ -1666,7 +1734,8 @@ mod tests {
// Test case 1: Deserialize with path and contents
{
let project = Project::test(fs.clone(), ["/file.rs".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let workspace_id = workspace::WORKSPACE_DB.next_id().await.unwrap();
let item_id = 1234 as ItemId;
let mtime = fs
@ -1702,7 +1771,8 @@ mod tests {
// Test case 2: Deserialize with only path
{
let project = Project::test(fs.clone(), ["/file.rs".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let workspace_id = workspace::WORKSPACE_DB.next_id().await.unwrap();
@ -1737,7 +1807,8 @@ mod tests {
// Add Rust to the language, so that we can restore the language of the buffer
project.update(cx, |project, _| project.languages().add(rust_language()));
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let workspace_id = workspace::WORKSPACE_DB.next_id().await.unwrap();
@ -1772,7 +1843,8 @@ mod tests {
// Test case 4: Deserialize with path, content, and old mtime
{
let project = Project::test(fs.clone(), ["/file.rs".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let workspace_id = workspace::WORKSPACE_DB.next_id().await.unwrap();

View file

@ -1,9 +1,8 @@
use std::{ops::Range, time::Duration};
use collections::HashMap;
use gpui::{Context, Window};
use itertools::Itertools;
use std::{ops::Range, time::Duration};
use text::{AnchorRangeExt, BufferId, ToPoint};
use ui::ViewContext;
use util::ResultExt;
use crate::Editor;
@ -42,14 +41,15 @@ const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
// TODO do not refresh anything at all, if the settings/capabilities do not have it enabled.
pub(super) fn refresh_linked_ranges(
editor: &mut Editor,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Option<()> {
if editor.pending_rename.is_some() {
return None;
}
let project = editor.project.as_ref()?.downgrade();
editor.linked_editing_range_task = Some(cx.spawn(|editor, mut cx| async move {
editor.linked_editing_range_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
let mut applicable_selections = Vec::new();

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use crate::Editor;
use collections::HashMap;
use gpui::{Model, WindowContext};
use gpui::{App, Entity};
use language::Buffer;
use language::Language;
use lsp::LanguageServerId;
@ -11,10 +11,10 @@ use multi_buffer::Anchor;
pub(crate) fn find_specific_language_server_in_selection<F>(
editor: &Editor,
cx: &WindowContext,
cx: &mut App,
filter_language: F,
language_server_name: &str,
) -> Option<(Anchor, Arc<Language>, LanguageServerId, Model<Buffer>)>
) -> Option<(Anchor, Arc<Language>, LanguageServerId, Entity<Buffer>)>
where
F: Fn(&Language) -> bool,
{

View file

@ -6,7 +6,7 @@ use crate::{
SelectMode, ToDisplayPoint, ToggleCodeActions,
};
use gpui::prelude::FluentBuilder;
use gpui::{DismissEvent, Pixels, Point, Subscription, View, ViewContext};
use gpui::{Context, DismissEvent, Entity, Focusable as _, Pixels, Point, Subscription, Window};
use std::ops::Range;
use text::PointUtf16;
use workspace::OpenInTerminal;
@ -26,7 +26,7 @@ pub enum MenuPosition {
pub struct MouseContextMenu {
pub(crate) position: MenuPosition,
pub(crate) context_menu: View<ui::ContextMenu>,
pub(crate) context_menu: Entity<ui::ContextMenu>,
_subscription: Subscription,
}
@ -44,37 +44,45 @@ impl MouseContextMenu {
editor: &mut Editor,
source: multi_buffer::Anchor,
position: Point<Pixels>,
context_menu: View<ui::ContextMenu>,
cx: &mut ViewContext<Editor>,
context_menu: Entity<ui::ContextMenu>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Option<Self> {
let editor_snapshot = editor.snapshot(cx);
let editor_snapshot = editor.snapshot(window, cx);
let content_origin = editor.last_bounds?.origin
+ Point {
x: editor.gutter_dimensions.width,
y: Pixels(0.0),
};
let source_position = editor.to_pixel_point(source, &editor_snapshot, cx)?;
let source_position = editor.to_pixel_point(source, &editor_snapshot, window)?;
let menu_position = MenuPosition::PinnedToEditor {
source,
offset: position - (source_position + content_origin),
};
return Some(MouseContextMenu::new(menu_position, context_menu, cx));
return Some(MouseContextMenu::new(
menu_position,
context_menu,
window,
cx,
));
}
pub(crate) fn new(
position: MenuPosition,
context_menu: View<ui::ContextMenu>,
cx: &mut ViewContext<Editor>,
context_menu: Entity<ui::ContextMenu>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Self {
let context_menu_focus = context_menu.focus_handle(cx);
cx.focus(&context_menu_focus);
window.focus(&context_menu_focus);
let _subscription = cx.subscribe(
let _subscription = cx.subscribe_in(
&context_menu,
move |editor, _, _event: &DismissEvent, cx| {
window,
move |editor, _, _event: &DismissEvent, window, cx| {
editor.mouse_context_menu.take();
if context_menu_focus.contains_focused(cx) {
editor.focus(cx);
if context_menu_focus.contains_focused(window, cx) {
window.focus(&editor.focus_handle(cx));
}
},
);
@ -106,10 +114,11 @@ pub fn deploy_context_menu(
editor: &mut Editor,
position: Option<Point<Pixels>>,
point: DisplayPoint,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if !editor.is_focused(cx) {
editor.focus(cx);
if !editor.is_focused(window) {
window.focus(&editor.focus_handle(cx));
}
// Don't show context menu for inline editors
@ -120,7 +129,7 @@ pub fn deploy_context_menu(
let display_map = editor.selections.display_map(cx);
let source_anchor = display_map.display_point_to_anchor(point, text::Bias::Right);
let context_menu = if let Some(custom) = editor.custom_context_menu.take() {
let menu = custom(editor, point, cx);
let menu = custom(editor, point, window, cx);
editor.custom_context_menu = Some(custom);
let Some(menu) = menu else {
return;
@ -133,17 +142,17 @@ pub fn deploy_context_menu(
}
let display_map = editor.selections.display_map(cx);
let buffer = &editor.snapshot(cx).buffer_snapshot;
let buffer = &editor.snapshot(window, cx).buffer_snapshot;
let anchor = buffer.anchor_before(point.to_point(&display_map));
if !display_ranges(&display_map, &editor.selections).any(|r| r.contains(&point)) {
// Move the cursor to the clicked location so that dispatched actions make sense
editor.change_selections(None, cx, |s| {
editor.change_selections(None, window, cx, |s| {
s.clear_disjoint();
s.set_pending_anchor_range(anchor..anchor, SelectMode::Character);
});
}
let focus = cx.focused();
let focus = window.focused(cx);
let has_reveal_target = editor.target_file(cx).is_some();
let reveal_in_finder_label = if cfg!(target_os = "macos") {
"Reveal in Finder"
@ -161,7 +170,7 @@ pub fn deploy_context_menu(
})
});
ui::ContextMenu::build(cx, |menu, _cx| {
ui::ContextMenu::build(window, cx, |menu, _window, _cx| {
let builder = menu
.on_blur_subscription(Subscription::new(|| {}))
.action("Go to Definition", Box::new(GoToDefinition))
@ -211,15 +220,25 @@ pub fn deploy_context_menu(
};
editor.mouse_context_menu = match position {
Some(position) => {
MouseContextMenu::pinned_to_editor(editor, source_anchor, position, context_menu, cx)
}
Some(position) => MouseContextMenu::pinned_to_editor(
editor,
source_anchor,
position,
context_menu,
window,
cx,
),
None => {
let menu_position = MenuPosition::PinnedToEditor {
source: source_anchor,
offset: editor.character_size(cx),
offset: editor.character_size(window),
};
Some(MouseContextMenu::new(menu_position, context_menu, cx))
Some(MouseContextMenu::new(
menu_position,
context_menu,
window,
cx,
))
}
};
cx.notify();
@ -254,9 +273,9 @@ mod tests {
do_wˇork();
}
"});
cx.editor(|editor, _app| assert!(editor.mouse_context_menu.is_none()));
cx.update_editor(|editor, cx| {
deploy_context_menu(editor, Some(Default::default()), point, cx)
cx.editor(|editor, _window, _app| assert!(editor.mouse_context_menu.is_none()));
cx.update_editor(|editor, window, cx| {
deploy_context_menu(editor, Some(Default::default()), point, window, cx)
});
cx.assert_editor_state(indoc! {"
@ -264,6 +283,6 @@ mod tests {
do_wˇork();
}
"});
cx.editor(|editor, _app| assert!(editor.mouse_context_menu.is_some()));
cx.editor(|editor, _window, _app| assert!(editor.mouse_context_menu.is_some()));
}
}

View file

@ -703,17 +703,17 @@ mod tests {
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
Buffer, DisplayMap, DisplayRow, ExcerptRange, FoldPlaceholder, InlayId, MultiBuffer,
};
use gpui::{font, px, Context as _};
use gpui::{font, px, AppContext as _};
use language::Capability;
use project::Project;
use settings::SettingsStore;
use util::post_inc;
#[gpui::test]
fn test_previous_word_start(cx: &mut gpui::AppContext) {
fn test_previous_word_start(cx: &mut gpui::App) {
init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
fn assert(marked_text: &str, cx: &mut gpui::App) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
previous_word_start(&snapshot, display_points[1]),
@ -738,10 +738,10 @@ mod tests {
}
#[gpui::test]
fn test_previous_subword_start(cx: &mut gpui::AppContext) {
fn test_previous_subword_start(cx: &mut gpui::App) {
init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
fn assert(marked_text: &str, cx: &mut gpui::App) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
previous_subword_start(&snapshot, display_points[1]),
@ -773,12 +773,12 @@ mod tests {
}
#[gpui::test]
fn test_find_preceding_boundary(cx: &mut gpui::AppContext) {
fn test_find_preceding_boundary(cx: &mut gpui::App) {
init_test(cx);
fn assert(
marked_text: &str,
cx: &mut gpui::AppContext,
cx: &mut gpui::App,
is_boundary: impl FnMut(char, char) -> bool,
) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
@ -811,7 +811,7 @@ mod tests {
}
#[gpui::test]
fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) {
fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::App) {
init_test(cx);
let input_text = "abcdefghijklmnopqrstuvwxys";
@ -820,7 +820,7 @@ mod tests {
let buffer = MultiBuffer::build_simple(input_text, cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx);
let display_map = cx.new_model(|cx| {
let display_map = cx.new(|cx| {
DisplayMap::new(
buffer,
font,
@ -884,10 +884,10 @@ mod tests {
}
#[gpui::test]
fn test_next_word_end(cx: &mut gpui::AppContext) {
fn test_next_word_end(cx: &mut gpui::App) {
init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
fn assert(marked_text: &str, cx: &mut gpui::App) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
next_word_end(&snapshot, display_points[0]),
@ -909,10 +909,10 @@ mod tests {
}
#[gpui::test]
fn test_next_subword_end(cx: &mut gpui::AppContext) {
fn test_next_subword_end(cx: &mut gpui::App) {
init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
fn assert(marked_text: &str, cx: &mut gpui::App) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
next_subword_end(&snapshot, display_points[0]),
@ -943,12 +943,12 @@ mod tests {
}
#[gpui::test]
fn test_find_boundary(cx: &mut gpui::AppContext) {
fn test_find_boundary(cx: &mut gpui::App) {
init_test(cx);
fn assert(
marked_text: &str,
cx: &mut gpui::AppContext,
cx: &mut gpui::App,
is_boundary: impl FnMut(char, char) -> bool,
) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
@ -981,10 +981,10 @@ mod tests {
}
#[gpui::test]
fn test_surrounding_word(cx: &mut gpui::AppContext) {
fn test_surrounding_word(cx: &mut gpui::App) {
init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
fn assert(marked_text: &str, cx: &mut gpui::App) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
surrounding_word(&snapshot, display_points[1]),
@ -1013,14 +1013,13 @@ mod tests {
let mut cx = EditorTestContext::new(cx).await;
let editor = cx.editor.clone();
let window = cx.window;
_ = cx.update_window(window, |_, cx| {
let text_layout_details =
editor.update(cx, |editor, cx| editor.text_layout_details(cx));
_ = cx.update_window(window, |_, window, cx| {
let text_layout_details = editor.read(cx).text_layout_details(window);
let font = font("Helvetica");
let buffer = cx.new_model(|cx| Buffer::local("abc\ndefg\nhijkl\nmn", cx));
let multibuffer = cx.new_model(|cx| {
let buffer = cx.new(|cx| Buffer::local("abc\ndefg\nhijkl\nmn", cx));
let multibuffer = cx.new(|cx| {
let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
multibuffer.push_excerpts(
buffer.clone(),
@ -1038,7 +1037,7 @@ mod tests {
);
multibuffer
});
let display_map = cx.new_model(|cx| {
let display_map = cx.new(|cx| {
DisplayMap::new(
multibuffer,
font,
@ -1182,7 +1181,7 @@ mod tests {
});
}
fn init_test(cx: &mut gpui::AppContext) {
fn init_test(cx: &mut gpui::App) {
let settings_store = SettingsStore::test(cx);
cx.set_global(settings_store);
theme::init(theme::LoadThemes::JustBase, cx);

View file

@ -1,7 +1,7 @@
use crate::{ApplyAllDiffHunks, Editor, EditorEvent, SemanticsProvider};
use collections::HashSet;
use futures::{channel::mpsc, future::join_all};
use gpui::{AppContext, EventEmitter, FocusableView, Model, Render, Subscription, Task, View};
use gpui::{App, Entity, EventEmitter, Focusable, Render, Subscription, Task};
use language::{Buffer, BufferEvent, Capability};
use multi_buffer::{ExcerptRange, MultiBuffer};
use project::{buffer_store::BufferChangeSet, Project};
@ -15,8 +15,8 @@ use workspace::{
};
pub struct ProposedChangesEditor {
editor: View<Editor>,
multibuffer: Model<MultiBuffer>,
editor: Entity<Editor>,
multibuffer: Entity<MultiBuffer>,
title: SharedString,
buffer_entries: Vec<BufferEntry>,
_recalculate_diffs_task: Task<Option<()>>,
@ -24,22 +24,22 @@ pub struct ProposedChangesEditor {
}
pub struct ProposedChangeLocation<T> {
pub buffer: Model<Buffer>,
pub buffer: Entity<Buffer>,
pub ranges: Vec<Range<T>>,
}
struct BufferEntry {
base: Model<Buffer>,
branch: Model<Buffer>,
base: Entity<Buffer>,
branch: Entity<Buffer>,
_subscription: Subscription,
}
pub struct ProposedChangesEditorToolbar {
current_editor: Option<View<ProposedChangesEditor>>,
current_editor: Option<Entity<ProposedChangesEditor>>,
}
struct RecalculateDiff {
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
debounce: bool,
}
@ -53,14 +53,16 @@ impl ProposedChangesEditor {
pub fn new<T: ToOffset>(
title: impl Into<SharedString>,
locations: Vec<ProposedChangeLocation<T>>,
project: Option<Model<Project>>,
cx: &mut ViewContext<Self>,
project: Option<Entity<Project>>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
let (recalculate_diffs_tx, mut recalculate_diffs_rx) = mpsc::unbounded();
let mut this = Self {
editor: cx.new_view(|cx| {
let mut editor = Editor::for_multibuffer(multibuffer.clone(), project, true, cx);
editor: cx.new(|cx| {
let mut editor =
Editor::for_multibuffer(multibuffer.clone(), project, true, window, cx);
editor.set_expand_all_diff_hunks(cx);
editor.set_completion_provider(None);
editor.clear_code_action_providers();
@ -75,7 +77,7 @@ impl ProposedChangesEditor {
title: title.into(),
buffer_entries: Vec::new(),
recalculate_diffs_tx,
_recalculate_diffs_task: cx.spawn(|this, mut cx| async move {
_recalculate_diffs_task: cx.spawn_in(window, |this, mut cx| async move {
let mut buffers_to_diff = HashSet::default();
while let Some(mut recalculate_diff) = recalculate_diffs_rx.next().await {
buffers_to_diff.insert(recalculate_diff.buffer);
@ -125,11 +127,11 @@ impl ProposedChangesEditor {
None
}),
};
this.reset_locations(locations, cx);
this.reset_locations(locations, window, cx);
this
}
pub fn branch_buffer_for_base(&self, base_buffer: &Model<Buffer>) -> Option<Model<Buffer>> {
pub fn branch_buffer_for_base(&self, base_buffer: &Entity<Buffer>) -> Option<Entity<Buffer>> {
self.buffer_entries.iter().find_map(|entry| {
if &entry.base == base_buffer {
Some(entry.branch.clone())
@ -139,7 +141,7 @@ impl ProposedChangesEditor {
})
}
pub fn set_title(&mut self, title: SharedString, cx: &mut ViewContext<Self>) {
pub fn set_title(&mut self, title: SharedString, cx: &mut Context<Self>) {
self.title = title;
cx.notify();
}
@ -147,7 +149,8 @@ impl ProposedChangesEditor {
pub fn reset_locations<T: ToOffset>(
&mut self,
locations: Vec<ProposedChangeLocation<T>>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
// Undo all branch changes
for entry in &self.buffer_entries {
@ -186,7 +189,7 @@ impl ProposedChangesEditor {
buffer_entries.push(entry);
} else {
branch_buffer = location.buffer.update(cx, |buffer, cx| buffer.branch(cx));
new_change_sets.push(cx.new_model(|cx| {
new_change_sets.push(cx.new(|cx| {
let mut change_set = BufferChangeSet::new(&branch_buffer, cx);
let _ = change_set.set_base_text(
location.buffer.read(cx).text(),
@ -216,7 +219,7 @@ impl ProposedChangesEditor {
self.buffer_entries = buffer_entries;
self.editor.update(cx, |editor, cx| {
editor.change_selections(None, cx, |selections| selections.refresh());
editor.change_selections(None, window, cx, |selections| selections.refresh());
editor.buffer.update(cx, |buffer, cx| {
for change_set in new_change_sets {
buffer.add_change_set(change_set, cx)
@ -238,9 +241,9 @@ impl ProposedChangesEditor {
fn on_buffer_event(
&mut self,
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
event: &BufferEvent,
_cx: &mut ViewContext<Self>,
_cx: &mut Context<Self>,
) {
match event {
BufferEvent::Operation { .. } => {
@ -265,7 +268,7 @@ impl ProposedChangesEditor {
}
impl Render for ProposedChangesEditor {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.size_full()
.key_context("ProposedChangesEditor")
@ -273,8 +276,8 @@ impl Render for ProposedChangesEditor {
}
}
impl FocusableView for ProposedChangesEditor {
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
impl Focusable for ProposedChangesEditor {
fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
self.editor.focus_handle(cx)
}
}
@ -284,23 +287,23 @@ impl EventEmitter<EditorEvent> for ProposedChangesEditor {}
impl Item for ProposedChangesEditor {
type Event = EditorEvent;
fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {
fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
Some(Icon::new(IconName::Diff))
}
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
fn tab_content_text(&self, _window: &Window, _cx: &App) -> Option<SharedString> {
Some(self.title.clone())
}
fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
fn as_searchable(&self, _: &Entity<Self>) -> Option<Box<dyn SearchableItemHandle>> {
Some(Box::new(self.editor.clone()))
}
fn act_as_type<'a>(
&'a self,
type_id: TypeId,
self_handle: &'a View<Self>,
_: &'a AppContext,
self_handle: &'a Entity<Self>,
_: &'a App,
) -> Option<gpui::AnyView> {
if type_id == TypeId::of::<Self>() {
Some(self_handle.to_any())
@ -311,43 +314,57 @@ impl Item for ProposedChangesEditor {
}
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
fn added_to_workspace(
&mut self,
workspace: &mut Workspace,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, cx| {
Item::added_to_workspace(editor, workspace, cx)
Item::added_to_workspace(editor, workspace, window, cx)
});
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
self.editor.update(cx, Item::deactivated);
fn deactivated(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.editor
.update(cx, |editor, cx| editor.deactivated(window, cx));
}
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
fn navigate(
&mut self,
data: Box<dyn std::any::Any>,
window: &mut Window,
cx: &mut Context<Self>,
) -> bool {
self.editor
.update(cx, |editor, cx| Item::navigate(editor, data, cx))
.update(cx, |editor, cx| Item::navigate(editor, data, window, cx))
}
fn set_nav_history(
&mut self,
nav_history: workspace::ItemNavHistory,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, cx| {
Item::set_nav_history(editor, nav_history, cx)
Item::set_nav_history(editor, nav_history, window, cx)
});
}
fn can_save(&self, cx: &AppContext) -> bool {
fn can_save(&self, cx: &App) -> bool {
self.editor.read(cx).can_save(cx)
}
fn save(
&mut self,
format: bool,
project: Model<Project>,
cx: &mut ViewContext<Self>,
project: Entity<Project>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<gpui::Result<()>> {
self.editor
.update(cx, |editor, cx| Item::save(editor, format, project, cx))
self.editor.update(cx, |editor, cx| {
Item::save(editor, format, project, window, cx)
})
}
}
@ -368,17 +385,20 @@ impl ProposedChangesEditorToolbar {
}
impl Render for ProposedChangesEditorToolbar {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let button_like = ButtonLike::new("apply-changes").child(Label::new("Apply All"));
match &self.current_editor {
Some(editor) => {
let focus_handle = editor.focus_handle(cx);
let keybinding = KeyBinding::for_action_in(&ApplyAllDiffHunks, &focus_handle, cx)
.map(|binding| binding.into_any_element());
let keybinding =
KeyBinding::for_action_in(&ApplyAllDiffHunks, &focus_handle, window)
.map(|binding| binding.into_any_element());
button_like.children(keybinding).on_click({
move |_event, cx| focus_handle.dispatch_action(&ApplyAllDiffHunks, cx)
move |_event, window, cx| {
focus_handle.dispatch_action(&ApplyAllDiffHunks, window, cx)
}
})
}
None => button_like.disabled(true),
@ -392,7 +412,8 @@ impl ToolbarItemView for ProposedChangesEditorToolbar {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn workspace::ItemHandle>,
_cx: &mut ViewContext<Self>,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> workspace::ToolbarItemLocation {
self.current_editor =
active_pane_item.and_then(|item| item.downcast::<ProposedChangesEditor>());
@ -403,10 +424,10 @@ impl ToolbarItemView for ProposedChangesEditorToolbar {
impl BranchBufferSemanticsProvider {
fn to_base(
&self,
buffer: &Model<Buffer>,
buffer: &Entity<Buffer>,
positions: &[text::Anchor],
cx: &AppContext,
) -> Option<Model<Buffer>> {
cx: &App,
) -> Option<Entity<Buffer>> {
let base_buffer = buffer.read(cx).base_buffer()?;
let version = base_buffer.read(cx).version();
if positions
@ -422,9 +443,9 @@ impl BranchBufferSemanticsProvider {
impl SemanticsProvider for BranchBufferSemanticsProvider {
fn hover(
&self,
buffer: &Model<Buffer>,
buffer: &Entity<Buffer>,
position: text::Anchor,
cx: &mut AppContext,
cx: &mut App,
) -> Option<Task<Vec<project::Hover>>> {
let buffer = self.to_base(buffer, &[position], cx)?;
self.0.hover(&buffer, position, cx)
@ -432,9 +453,9 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
fn inlay_hints(
&self,
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
range: Range<text::Anchor>,
cx: &mut AppContext,
cx: &mut App,
) -> Option<Task<anyhow::Result<Vec<project::InlayHint>>>> {
let buffer = self.to_base(&buffer, &[range.start, range.end], cx)?;
self.0.inlay_hints(buffer, range, cx)
@ -443,15 +464,15 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
fn resolve_inlay_hint(
&self,
hint: project::InlayHint,
buffer: Model<Buffer>,
buffer: Entity<Buffer>,
server_id: lsp::LanguageServerId,
cx: &mut AppContext,
cx: &mut App,
) -> Option<Task<anyhow::Result<project::InlayHint>>> {
let buffer = self.to_base(&buffer, &[], cx)?;
self.0.resolve_inlay_hint(hint, buffer, server_id, cx)
}
fn supports_inlay_hints(&self, buffer: &Model<Buffer>, cx: &AppContext) -> bool {
fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &App) -> bool {
if let Some(buffer) = self.to_base(&buffer, &[], cx) {
self.0.supports_inlay_hints(&buffer, cx)
} else {
@ -461,9 +482,9 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
fn document_highlights(
&self,
buffer: &Model<Buffer>,
buffer: &Entity<Buffer>,
position: text::Anchor,
cx: &mut AppContext,
cx: &mut App,
) -> Option<Task<gpui::Result<Vec<project::DocumentHighlight>>>> {
let buffer = self.to_base(&buffer, &[position], cx)?;
self.0.document_highlights(&buffer, position, cx)
@ -471,10 +492,10 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
fn definitions(
&self,
buffer: &Model<Buffer>,
buffer: &Entity<Buffer>,
position: text::Anchor,
kind: crate::GotoDefinitionKind,
cx: &mut AppContext,
cx: &mut App,
) -> Option<Task<gpui::Result<Vec<project::LocationLink>>>> {
let buffer = self.to_base(&buffer, &[position], cx)?;
self.0.definitions(&buffer, position, kind, cx)
@ -482,19 +503,19 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
fn range_for_rename(
&self,
_: &Model<Buffer>,
_: &Entity<Buffer>,
_: text::Anchor,
_: &mut AppContext,
_: &mut App,
) -> Option<Task<gpui::Result<Option<Range<text::Anchor>>>>> {
None
}
fn perform_rename(
&self,
_: &Model<Buffer>,
_: &Entity<Buffer>,
_: text::Anchor,
_: String,
_: &mut AppContext,
_: &mut App,
) -> Option<Task<gpui::Result<project::ProjectTransaction>>> {
None
}

View file

@ -1,7 +1,7 @@
use std::{fs, path::Path};
use anyhow::Context as _;
use gpui::{Context, View, ViewContext, VisualContext, WindowContext};
use gpui::{App, AppContext as _, Context, Entity, Window};
use language::Language;
use multi_buffer::MultiBuffer;
use project::lsp_ext_command::ExpandMacro;
@ -18,22 +18,23 @@ fn is_rust_language(language: &Language) -> bool {
language.name() == "Rust".into()
}
pub fn apply_related_actions(editor: &View<Editor>, cx: &mut WindowContext) {
pub fn apply_related_actions(editor: &Entity<Editor>, window: &mut Window, cx: &mut App) {
if editor
.update(cx, |e, cx| {
find_specific_language_server_in_selection(e, cx, is_rust_language, RUST_ANALYZER_NAME)
})
.is_some()
{
register_action(editor, cx, expand_macro_recursively);
register_action(editor, cx, open_docs);
register_action(editor, window, expand_macro_recursively);
register_action(editor, window, open_docs);
}
}
pub fn expand_macro_recursively(
editor: &mut Editor,
_: &ExpandMacroRecursively,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if editor.selections.count() == 0 {
return;
@ -67,7 +68,7 @@ pub fn expand_macro_recursively(
cx,
)
});
cx.spawn(|_editor, mut cx| async move {
cx.spawn_in(window, |_editor, mut cx| async move {
let macro_expansion = expand_macro_task.await.context("expand macro")?;
if macro_expansion.is_empty() {
log::info!("Empty macro expansion for position {position:?}");
@ -77,20 +78,20 @@ pub fn expand_macro_recursively(
let buffer = project
.update(&mut cx, |project, cx| project.create_buffer(cx))?
.await?;
workspace.update(&mut cx, |workspace, cx| {
workspace.update_in(&mut cx, |workspace, window, cx| {
buffer.update(cx, |buffer, cx| {
buffer.edit([(0..0, macro_expansion.expansion)], None, cx);
buffer.set_language(Some(rust_language), cx)
});
let multibuffer = cx.new_model(|cx| {
MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name)
});
let multibuffer =
cx.new(|cx| MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name));
workspace.add_item_to_active_pane(
Box::new(
cx.new_view(|cx| Editor::for_multibuffer(multibuffer, Some(project), true, cx)),
),
Box::new(cx.new(|cx| {
Editor::for_multibuffer(multibuffer, Some(project), true, window, cx)
})),
None,
true,
window,
cx,
);
})
@ -98,7 +99,7 @@ pub fn expand_macro_recursively(
.detach_and_log_err(cx);
}
pub fn open_docs(editor: &mut Editor, _: &OpenDocs, cx: &mut ViewContext<Editor>) {
pub fn open_docs(editor: &mut Editor, _: &OpenDocs, window: &mut Window, cx: &mut Context<Editor>) {
if editor.selections.count() == 0 {
return;
}
@ -132,7 +133,7 @@ pub fn open_docs(editor: &mut Editor, _: &OpenDocs, cx: &mut ViewContext<Editor>
)
});
cx.spawn(|_editor, mut cx| async move {
cx.spawn_in(window, |_editor, mut cx| async move {
let docs_urls = open_docs_task.await.context("open docs")?;
if docs_urls.is_empty() {
log::debug!("Empty docs urls for position {position:?}");

View file

@ -12,9 +12,7 @@ use crate::{
};
pub use autoscroll::{Autoscroll, AutoscrollStrategy};
use core::fmt::Debug;
use gpui::{
point, px, Along, AppContext, Axis, Entity, Global, Pixels, Task, ViewContext, WindowContext,
};
use gpui::{point, px, Along, App, Axis, Context, Global, Pixels, Task, Window};
use language::{Bias, Point};
pub use scroll_amount::ScrollAmount;
use settings::Settings;
@ -188,7 +186,7 @@ pub struct ScrollManager {
}
impl ScrollManager {
pub fn new(cx: &mut WindowContext) -> Self {
pub fn new(cx: &mut App) -> Self {
ScrollManager {
vertical_scroll_margin: EditorSettings::get_global(cx).vertical_scroll_margin,
anchor: ScrollAnchor::new(),
@ -225,6 +223,7 @@ impl ScrollManager {
self.anchor.scroll_position(snapshot)
}
#[allow(clippy::too_many_arguments)]
fn set_scroll_position(
&mut self,
scroll_position: gpui::Point<f32>,
@ -232,7 +231,8 @@ impl ScrollManager {
local: bool,
autoscroll: bool,
workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if self.forbid_vertical_scroll {
return;
@ -287,9 +287,18 @@ impl ScrollManager {
)
};
self.set_anchor(new_anchor, top_row, local, autoscroll, workspace_id, cx);
self.set_anchor(
new_anchor,
top_row,
local,
autoscroll,
workspace_id,
window,
cx,
);
}
#[allow(clippy::too_many_arguments)]
fn set_anchor(
&mut self,
anchor: ScrollAnchor,
@ -297,17 +306,18 @@ impl ScrollManager {
local: bool,
autoscroll: bool,
workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if self.forbid_vertical_scroll {
return;
}
self.anchor = anchor;
cx.emit(EditorEvent::ScrollPositionChanged { local, autoscroll });
self.show_scrollbar(cx);
self.show_scrollbar(window, cx);
self.autoscroll_request.take();
if let Some(workspace_id) = workspace_id {
let item_id = cx.view().entity_id().as_u64() as ItemId;
let item_id = cx.model().entity_id().as_u64() as ItemId;
cx.foreground_executor()
.spawn(async move {
@ -326,14 +336,14 @@ impl ScrollManager {
cx.notify();
}
pub fn show_scrollbar(&mut self, cx: &mut ViewContext<Editor>) {
pub fn show_scrollbar(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
if !self.show_scrollbars {
self.show_scrollbars = true;
cx.notify();
}
if cx.default_global::<ScrollbarAutoHide>().0 {
self.hide_scrollbar_task = Some(cx.spawn(|editor, mut cx| async move {
self.hide_scrollbar_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
cx.background_executor()
.timer(SCROLLBAR_SHOW_INTERVAL)
.await;
@ -365,7 +375,7 @@ impl ScrollManager {
&mut self,
axis: Axis,
dragging: bool,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
self.dragging_scrollbar = self.dragging_scrollbar.apply_along(axis, |_| dragging);
cx.notify();
@ -394,7 +404,7 @@ impl Editor {
self.scroll_manager.vertical_scroll_margin as usize
}
pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut Context<Self>) {
self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
cx.notify();
}
@ -408,11 +418,16 @@ impl Editor {
.map(|line_count| line_count as u32 - 1)
}
pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
pub(crate) fn set_visible_line_count(
&mut self,
lines: f32,
window: &mut Window,
cx: &mut Context<Self>,
) {
let opened_first_time = self.scroll_manager.visible_line_count.is_none();
self.scroll_manager.visible_line_count = Some(lines);
if opened_first_time {
cx.spawn(|editor, mut cx| async move {
cx.spawn_in(window, |editor, mut cx| async move {
editor
.update(&mut cx, |editor, cx| {
editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
@ -426,25 +441,27 @@ impl Editor {
pub fn apply_scroll_delta(
&mut self,
scroll_delta: gpui::Point<f32>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
if self.scroll_manager.forbid_vertical_scroll {
return;
}
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let position = self.scroll_manager.anchor.scroll_position(&display_map) + scroll_delta;
self.set_scroll_position_taking_display_map(position, true, false, display_map, cx);
self.set_scroll_position_taking_display_map(position, true, false, display_map, window, cx);
}
pub fn set_scroll_position(
&mut self,
scroll_position: gpui::Point<f32>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
if self.scroll_manager.forbid_vertical_scroll {
return;
}
self.set_scroll_position_internal(scroll_position, true, false, cx);
self.set_scroll_position_internal(scroll_position, true, false, window, cx);
}
pub(crate) fn set_scroll_position_internal(
@ -452,10 +469,18 @@ impl Editor {
scroll_position: gpui::Point<f32>,
local: bool,
autoscroll: bool,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.set_scroll_position_taking_display_map(scroll_position, local, autoscroll, map, cx);
self.set_scroll_position_taking_display_map(
scroll_position,
local,
autoscroll,
map,
window,
cx,
);
}
fn set_scroll_position_taking_display_map(
@ -464,7 +489,8 @@ impl Editor {
local: bool,
autoscroll: bool,
display_map: DisplaySnapshot,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
hide_hover(self, cx);
let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
@ -475,32 +501,46 @@ impl Editor {
local,
autoscroll,
workspace_id,
window,
cx,
);
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
}
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<f32> {
pub fn scroll_position(&self, cx: &mut Context<Self>) -> gpui::Point<f32> {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.scroll_manager.anchor.scroll_position(&display_map)
}
pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
pub fn set_scroll_anchor(
&mut self,
scroll_anchor: ScrollAnchor,
window: &mut Window,
cx: &mut Context<Self>,
) {
hide_hover(self, cx);
let workspace_id = self.workspace.as_ref().and_then(|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);
self.scroll_manager.set_anchor(
scroll_anchor,
top_row,
true,
false,
workspace_id,
window,
cx,
);
}
pub(crate) fn set_scroll_anchor_remote(
&mut self,
scroll_anchor: ScrollAnchor,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
hide_hover(self, cx);
let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
@ -510,17 +550,29 @@ impl Editor {
return;
}
let top_row = scroll_anchor.anchor.to_point(snapshot).row;
self.scroll_manager
.set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
self.scroll_manager.set_anchor(
scroll_anchor,
top_row,
false,
false,
workspace_id,
window,
cx,
);
}
pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
pub fn scroll_screen(
&mut self,
amount: &ScrollAmount,
window: &mut Window,
cx: &mut Context<Self>,
) {
if matches!(self.mode, EditorMode::SingleLine { .. }) {
cx.propagate();
return;
}
if self.take_rename(true, cx).is_some() {
if self.take_rename(true, window, cx).is_some() {
return;
}
@ -529,14 +581,14 @@ impl Editor {
return;
};
let new_pos = cur_position + point(0., amount.lines(visible_line_count));
self.set_scroll_position(new_pos, cx);
self.set_scroll_position(new_pos, window, 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 {
pub fn newest_selection_on_screen(&self, cx: &mut App) -> Ordering {
let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let newest_head = self
.selections
@ -566,7 +618,8 @@ impl Editor {
&mut self,
item_id: u64,
workspace_id: WorkspaceId,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let scroll_position = DB.get_scroll_position(item_id, workspace_id);
if let Ok(Some((top_row, x, y))) = scroll_position {
@ -579,7 +632,7 @@ impl Editor {
offset: gpui::Point::new(x, y),
anchor: top_anchor,
};
self.set_scroll_anchor(scroll_anchor, cx);
self.set_scroll_anchor(scroll_anchor, window, cx);
}
}
}

View file

@ -4,11 +4,11 @@ use crate::{
ScrollAnchor, ScrollCursorBottom, ScrollCursorCenter, ScrollCursorCenterTopBottom,
ScrollCursorTop, SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT,
};
use gpui::{AsyncWindowContext, Point, ViewContext};
use gpui::{Context, Point, Window};
impl Editor {
pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) {
if self.take_rename(true, cx).is_some() {
pub fn next_screen(&mut self, _: &NextScreen, window: &mut Window, cx: &mut Context<Editor>) {
if self.take_rename(true, window, cx).is_some() {
return;
}
@ -27,18 +27,20 @@ impl Editor {
&mut self,
scroll_position: Point<f32>,
axis: Option<Axis>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.scroll_manager.update_ongoing_scroll(axis);
self.set_scroll_position(scroll_position, cx);
self.set_scroll_position(scroll_position, window, cx);
}
pub fn scroll_cursor_center_top_bottom(
&mut self,
_: &ScrollCursorCenterTopBottom,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
let snapshot = self.snapshot(cx).display_snapshot;
let snapshot = self.snapshot(window, cx).display_snapshot;
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
visible_rows as u32
} else {
@ -70,25 +72,30 @@ impl Editor {
.anchor_before(new_screen_top.to_offset(&snapshot, Bias::Left)),
offset: Default::default(),
},
window,
cx,
);
self.next_scroll_position = self.next_scroll_position.next();
self._scroll_cursor_center_top_bottom_task =
cx.spawn(|editor, mut cx: AsyncWindowContext| async move {
cx.background_executor()
.timer(SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT)
.await;
editor
.update(&mut cx, |editor, _| {
editor.next_scroll_position = NextScrollCursorCenterTopBottom::default();
})
.ok();
});
self._scroll_cursor_center_top_bottom_task = cx.spawn(|editor, mut cx| async move {
cx.background_executor()
.timer(SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT)
.await;
editor
.update(&mut cx, |editor, _| {
editor.next_scroll_position = NextScrollCursorCenterTopBottom::default();
})
.ok();
});
}
pub fn scroll_cursor_top(&mut self, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
let snapshot = self.snapshot(cx).display_snapshot;
pub fn scroll_cursor_top(
&mut self,
_: &ScrollCursorTop,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let snapshot = self.snapshot(window, cx).display_snapshot;
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
let mut new_screen_top = self.selections.newest_display(cx).head();
@ -102,12 +109,18 @@ impl Editor {
anchor: new_anchor,
offset: Default::default(),
},
window,
cx,
)
}
pub fn scroll_cursor_center(&mut self, _: &ScrollCursorCenter, cx: &mut ViewContext<Editor>) {
let snapshot = self.snapshot(cx).display_snapshot;
pub fn scroll_cursor_center(
&mut self,
_: &ScrollCursorCenter,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let snapshot = self.snapshot(window, cx).display_snapshot;
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
visible_rows as u32
} else {
@ -125,12 +138,18 @@ impl Editor {
anchor: new_anchor,
offset: Default::default(),
},
window,
cx,
)
}
pub fn scroll_cursor_bottom(&mut self, _: &ScrollCursorBottom, cx: &mut ViewContext<Editor>) {
let snapshot = self.snapshot(cx).display_snapshot;
pub fn scroll_cursor_bottom(
&mut self,
_: &ScrollCursorBottom,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let snapshot = self.snapshot(window, cx).display_snapshot;
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
visible_rows as u32
@ -152,6 +171,7 @@ impl Editor {
anchor: new_anchor,
offset: Default::default(),
},
window,
cx,
)
}

View file

@ -1,7 +1,7 @@
use crate::{
display_map::ToDisplayPoint, DisplayRow, Editor, EditorMode, LineWithInvisibles, RowExt,
};
use gpui::{px, Bounds, Pixels, ViewContext};
use gpui::{px, Bounds, Context, Pixels, Window};
use language::Point;
use std::{cmp, f32};
@ -76,7 +76,8 @@ impl Editor {
bounds: Bounds<Pixels>,
line_height: Pixels,
max_scroll_top: f32,
cx: &mut ViewContext<Editor>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> bool {
let viewport_height = bounds.size.height;
let visible_lines = viewport_height / line_height;
@ -96,7 +97,7 @@ impl Editor {
}
if original_y != scroll_position.y {
self.set_scroll_position(scroll_position, cx);
self.set_scroll_position(scroll_position, window, cx);
}
let Some((autoscroll, local)) = self.scroll_manager.autoscroll_request.take() else {
@ -183,33 +184,33 @@ impl Editor {
if needs_scroll_up && !needs_scroll_down {
scroll_position.y = target_top;
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
if !needs_scroll_up && needs_scroll_down {
scroll_position.y = target_bottom - visible_lines;
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
}
AutoscrollStrategy::Center => {
scroll_position.y = (target_top - margin).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::Focused => {
let margin = margin.min(self.scroll_manager.vertical_scroll_margin);
scroll_position.y = (target_top - margin).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::Top => {
scroll_position.y = (target_top).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::Bottom => {
scroll_position.y = (target_bottom - visible_lines).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::TopRelative(lines) => {
scroll_position.y = target_top - lines as f32;
self.set_scroll_position_internal(scroll_position, local, true, cx);
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
}
@ -230,7 +231,7 @@ impl Editor {
scroll_width: Pixels,
max_glyph_width: Pixels,
layouts: &[LineWithInvisibles],
cx: &mut ViewContext<Self>,
cx: &mut Context<Self>,
) -> bool {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all::<Point>(cx);
@ -287,7 +288,7 @@ impl Editor {
}
}
pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut Context<Self>) {
self.scroll_manager.autoscroll_request = Some((autoscroll, true));
cx.notify();
}
@ -295,7 +296,7 @@ impl Editor {
pub(crate) fn request_autoscroll_remotely(
&mut self,
autoscroll: Autoscroll,
cx: &mut ViewContext<Self>,
cx: &mut Context<Self>,
) {
self.scroll_manager.autoscroll_request = Some((autoscroll, false));
cx.notify();

View file

@ -6,7 +6,7 @@ use std::{
};
use collections::HashMap;
use gpui::{AppContext, Model, Pixels};
use gpui::{App, Entity, Pixels};
use itertools::Itertools;
use language::{Bias, Point, Selection, SelectionGoal, TextDimension};
use util::post_inc;
@ -26,8 +26,8 @@ pub struct PendingSelection {
#[derive(Debug, Clone)]
pub struct SelectionsCollection {
display_map: Model<DisplayMap>,
buffer: Model<MultiBuffer>,
display_map: Entity<DisplayMap>,
buffer: Entity<MultiBuffer>,
pub next_selection_id: usize,
pub line_mode: bool,
/// The non-pending, non-overlapping selections.
@ -38,7 +38,7 @@ pub struct SelectionsCollection {
}
impl SelectionsCollection {
pub fn new(display_map: Model<DisplayMap>, buffer: Model<MultiBuffer>) -> Self {
pub fn new(display_map: Entity<DisplayMap>, buffer: Entity<MultiBuffer>) -> Self {
Self {
display_map,
buffer,
@ -58,11 +58,11 @@ impl SelectionsCollection {
}
}
pub fn display_map(&self, cx: &mut AppContext) -> DisplaySnapshot {
pub fn display_map(&self, cx: &mut App) -> DisplaySnapshot {
self.display_map.update(cx, |map, cx| map.snapshot(cx))
}
fn buffer<'a>(&self, cx: &'a AppContext) -> Ref<'a, MultiBufferSnapshot> {
fn buffer<'a>(&self, cx: &'a App) -> Ref<'a, MultiBufferSnapshot> {
self.buffer.read(cx).read(cx)
}
@ -102,7 +102,7 @@ impl SelectionsCollection {
pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &mut AppContext,
cx: &mut App,
) -> Option<Selection<D>> {
let map = self.display_map(cx);
let selection = resolve_selections(self.pending_anchor().as_ref(), &map).next();
@ -113,7 +113,7 @@ impl SelectionsCollection {
self.pending.as_ref().map(|pending| pending.mode.clone())
}
pub fn all<'a, D>(&self, cx: &mut AppContext) -> Vec<Selection<D>>
pub fn all<'a, D>(&self, cx: &mut App) -> Vec<Selection<D>>
where
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
{
@ -148,7 +148,7 @@ impl SelectionsCollection {
}
/// Returns all of the selections, adjusted to take into account the selection line_mode
pub fn all_adjusted(&self, cx: &mut AppContext) -> Vec<Selection<Point>> {
pub fn all_adjusted(&self, cx: &mut App) -> Vec<Selection<Point>> {
let mut selections = self.all::<Point>(cx);
if self.line_mode {
let map = self.display_map(cx);
@ -162,7 +162,7 @@ impl SelectionsCollection {
}
/// Returns the newest selection, adjusted to take into account the selection line_mode
pub fn newest_adjusted(&self, cx: &mut AppContext) -> Selection<Point> {
pub fn newest_adjusted(&self, cx: &mut App) -> Selection<Point> {
let mut selection = self.newest::<Point>(cx);
if self.line_mode {
let map = self.display_map(cx);
@ -175,7 +175,7 @@ impl SelectionsCollection {
pub fn all_adjusted_display(
&self,
cx: &mut AppContext,
cx: &mut App,
) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
if self.line_mode {
let selections = self.all::<Point>(cx);
@ -195,11 +195,7 @@ impl SelectionsCollection {
}
}
pub fn disjoint_in_range<'a, D>(
&self,
range: Range<Anchor>,
cx: &mut AppContext,
) -> Vec<Selection<D>>
pub fn disjoint_in_range<'a, D>(&self, range: Range<Anchor>, cx: &mut App) -> Vec<Selection<D>>
where
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
{
@ -220,10 +216,7 @@ impl SelectionsCollection {
resolve_selections(&self.disjoint[start_ix..end_ix], &map).collect()
}
pub fn all_display(
&self,
cx: &mut AppContext,
) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
pub fn all_display(&self, cx: &mut App) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
let map = self.display_map(cx);
let disjoint_anchors = &self.disjoint;
let mut disjoint = resolve_selections_display(disjoint_anchors.iter(), &map).peekable();
@ -266,7 +259,7 @@ impl SelectionsCollection {
pub fn newest<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &mut AppContext,
cx: &mut App,
) -> Selection<D> {
let map = self.display_map(cx);
let selection = resolve_selections([self.newest_anchor()], &map)
@ -275,7 +268,7 @@ impl SelectionsCollection {
selection
}
pub fn newest_display(&self, cx: &mut AppContext) -> Selection<DisplayPoint> {
pub fn newest_display(&self, cx: &mut App) -> Selection<DisplayPoint> {
let map = self.display_map(cx);
let selection = resolve_selections_display([self.newest_anchor()], &map)
.next()
@ -293,7 +286,7 @@ impl SelectionsCollection {
pub fn oldest<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &mut AppContext,
cx: &mut App,
) -> Selection<D> {
let map = self.display_map(cx);
let selection = resolve_selections([self.oldest_anchor()], &map)
@ -309,23 +302,17 @@ impl SelectionsCollection {
.unwrap_or_else(|| self.disjoint.first().cloned().unwrap())
}
pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &mut AppContext,
) -> Selection<D> {
pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(&self, cx: &mut App) -> Selection<D> {
self.all(cx).first().unwrap().clone()
}
pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &mut AppContext,
) -> Selection<D> {
pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(&self, cx: &mut App) -> Selection<D> {
self.all(cx).last().unwrap().clone()
}
pub fn ranges<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &mut AppContext,
cx: &mut App,
) -> Vec<Range<D>> {
self.all::<D>(cx)
.iter()
@ -340,7 +327,7 @@ impl SelectionsCollection {
}
#[cfg(any(test, feature = "test-support"))]
pub fn display_ranges(&self, cx: &mut AppContext) -> Vec<Range<DisplayPoint>> {
pub fn display_ranges(&self, cx: &mut App) -> Vec<Range<DisplayPoint>> {
let display_map = self.display_map(cx);
self.disjoint_anchors()
.iter()
@ -391,7 +378,7 @@ impl SelectionsCollection {
pub fn change_with<R>(
&mut self,
cx: &mut AppContext,
cx: &mut App,
change: impl FnOnce(&mut MutableSelectionsCollection) -> R,
) -> (bool, R) {
let mut mutable_collection = MutableSelectionsCollection {
@ -412,7 +399,7 @@ impl SelectionsCollection {
pub struct MutableSelectionsCollection<'a> {
collection: &'a mut SelectionsCollection,
selections_changed: bool,
cx: &'a mut AppContext,
cx: &'a mut App,
}
impl<'a> MutableSelectionsCollection<'a> {

View file

@ -3,7 +3,7 @@ mod state;
use crate::actions::ShowSignatureHelp;
use crate::{Editor, EditorSettings, ToggleAutoSignatureHelp};
use gpui::{AppContext, ViewContext};
use gpui::{App, Context, Window};
use language::markdown::parse_markdown;
use language::BufferSnapshot;
use multi_buffer::{Anchor, ToOffset};
@ -27,7 +27,8 @@ impl Editor {
pub fn toggle_auto_signature_help_menu(
&mut self,
_: &ToggleAutoSignatureHelp,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.auto_signature_help = self
.auto_signature_help
@ -35,7 +36,7 @@ impl Editor {
.or_else(|| Some(!EditorSettings::get_global(cx).auto_signature_help));
match self.auto_signature_help {
Some(auto_signature_help) if auto_signature_help => {
self.show_signature_help(&ShowSignatureHelp, cx);
self.show_signature_help(&ShowSignatureHelp, window, cx);
}
Some(_) => {
self.hide_signature_help(cx, SignatureHelpHiddenBy::AutoClose);
@ -47,7 +48,7 @@ impl Editor {
pub(super) fn hide_signature_help(
&mut self,
cx: &mut ViewContext<Self>,
cx: &mut Context<Self>,
signature_help_hidden_by: SignatureHelpHiddenBy,
) -> bool {
if self.signature_help_state.is_shown() {
@ -60,7 +61,7 @@ impl Editor {
}
}
pub fn auto_signature_help_enabled(&self, cx: &AppContext) -> bool {
pub fn auto_signature_help_enabled(&self, cx: &App) -> bool {
if let Some(auto_signature_help) = self.auto_signature_help {
auto_signature_help
} else {
@ -72,7 +73,8 @@ impl Editor {
&mut self,
old_cursor_position: &Anchor,
backspace_pressed: bool,
cx: &mut ViewContext<Self>,
cx: &mut Context<Self>,
) -> bool {
if !(self.signature_help_state.is_shown() || self.auto_signature_help_enabled(cx)) {
return false;
@ -150,7 +152,12 @@ impl Editor {
}
}
pub fn show_signature_help(&mut self, _: &ShowSignatureHelp, cx: &mut ViewContext<Self>) {
pub fn show_signature_help(
&mut self,
_: &ShowSignatureHelp,
window: &mut Window,
cx: &mut Context<Self>,
) {
if self.pending_rename.is_some() || self.has_active_completions_menu() {
return;
}
@ -163,7 +170,7 @@ impl Editor {
};
self.signature_help_state
.set_task(cx.spawn(move |editor, mut cx| async move {
.set_task(cx.spawn_in(window, move |editor, mut cx| async move {
let signature_help = editor
.update(&mut cx, |editor, cx| {
let language = editor.language_at(position, cx);

View file

@ -1,7 +1,7 @@
use crate::{Editor, EditorStyle};
use gpui::{
div, AnyElement, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, Size,
StatefulInteractiveElement, Styled, ViewContext, WeakView,
div, AnyElement, Context, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels,
Size, StatefulInteractiveElement, Styled, WeakEntity,
};
use language::ParsedMarkdown;
use ui::StyledExt;
@ -25,8 +25,8 @@ impl SignatureHelpPopover {
&mut self,
style: &EditorStyle,
max_size: Size<Pixels>,
workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>,
workspace: Option<WeakEntity<Workspace>>,
cx: &mut Context<Editor>,
) -> AnyElement {
div()
.id("signature_help_popover")
@ -34,8 +34,8 @@ impl SignatureHelpPopover {
.overflow_y_scroll()
.max_w(max_size.width)
.max_h(max_size.height)
.on_mouse_move(|_, cx| cx.stop_propagation())
.on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
.on_mouse_move(|_, _, cx| cx.stop_propagation())
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
.child(div().p_2().child(crate::render_parsed_markdown(
"signature_help_popover_content",
&self.parsed_content,

View file

@ -1,6 +1,6 @@
use crate::Editor;
use gpui::{Task as AsyncTask, WindowContext};
use gpui::{App, Task as AsyncTask, Window};
use project::Location;
use task::{TaskContext, TaskVariables, VariableName};
use text::{ToOffset, ToPoint};
@ -8,7 +8,8 @@ use workspace::Workspace;
fn task_context_with_editor(
editor: &mut Editor,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> AsyncTask<Option<TaskContext>> {
let Some(project) = editor.project.clone() else {
return AsyncTask::ready(None);
@ -22,7 +23,7 @@ fn task_context_with_editor(
else {
return AsyncTask::ready(None);
};
let snapshot = editor.snapshot(cx);
let snapshot = editor.snapshot(window, cx);
(selection, buffer, snapshot)
};
let selection_range = selection.range();
@ -74,7 +75,11 @@ fn task_context_with_editor(
})
}
pub fn task_context(workspace: &Workspace, cx: &mut WindowContext) -> AsyncTask<TaskContext> {
pub fn task_context(
workspace: &Workspace,
window: &mut Window,
cx: &mut App,
) -> AsyncTask<TaskContext> {
let Some(editor) = workspace
.active_item(cx)
.and_then(|item| item.act_as::<Editor>(cx))
@ -82,7 +87,7 @@ pub fn task_context(workspace: &Workspace, cx: &mut WindowContext) -> AsyncTask<
return AsyncTask::ready(TaskContext::default());
};
editor.update(cx, |editor, cx| {
let context_task = task_context_with_editor(editor, cx);
let context_task = task_context_with_editor(editor, window, cx);
cx.background_executor()
.spawn(async move { context_task.await.unwrap_or_default() })
})

View file

@ -5,7 +5,9 @@ use crate::{
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
DisplayPoint, Editor, EditorMode, FoldPlaceholder, MultiBuffer,
};
use gpui::{Context, Font, FontFeatures, FontStyle, FontWeight, Model, Pixels, ViewContext};
use gpui::{
AppContext as _, Context, Entity, Font, FontFeatures, FontStyle, FontWeight, Pixels, Window,
};
use project::Project;
use util::test::{marked_text_offsets, marked_text_ranges};
@ -20,7 +22,7 @@ fn init_logger() {
// Returns a snapshot from text containing '|' character markers with the markers removed, and DisplayPoints for each one.
pub fn marked_display_snapshot(
text: &str,
cx: &mut gpui::AppContext,
cx: &mut gpui::App,
) -> (DisplaySnapshot, Vec<DisplayPoint>) {
let (unmarked_text, markers) = marked_text_offsets(text);
@ -34,7 +36,7 @@ pub fn marked_display_snapshot(
let font_size: Pixels = 14usize.into();
let buffer = MultiBuffer::build_simple(&unmarked_text, cx);
let display_map = cx.new_model(|cx| {
let display_map = cx.new(|cx| {
DisplayMap::new(
buffer,
font,
@ -57,17 +59,22 @@ pub fn marked_display_snapshot(
(snapshot, markers)
}
pub fn select_ranges(editor: &mut Editor, marked_text: &str, cx: &mut ViewContext<Editor>) {
pub fn select_ranges(
editor: &mut Editor,
marked_text: &str,
window: &mut Window,
cx: &mut Context<Editor>,
) {
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
assert_eq!(editor.text(cx), unmarked_text);
editor.change_selections(None, cx, |s| s.select_ranges(text_ranges));
editor.change_selections(None, window, cx, |s| s.select_ranges(text_ranges));
}
#[track_caller]
pub fn assert_text_with_selections(
editor: &mut Editor,
marked_text: &str,
cx: &mut ViewContext<Editor>,
cx: &mut Context<Editor>,
) {
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
assert_eq!(editor.text(cx), unmarked_text);
@ -77,14 +84,19 @@ pub fn assert_text_with_selections(
// RA thinks this is dead code even though it is used in a whole lot of tests
#[allow(dead_code)]
#[cfg(any(test, feature = "test-support"))]
pub(crate) fn build_editor(buffer: Model<MultiBuffer>, cx: &mut ViewContext<Editor>) -> Editor {
Editor::new(EditorMode::Full, buffer, None, true, cx)
pub(crate) fn build_editor(
buffer: Entity<MultiBuffer>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Editor {
Editor::new(EditorMode::Full, buffer, None, true, window, cx)
}
pub(crate) fn build_editor_with_project(
project: Model<Project>,
buffer: Model<MultiBuffer>,
cx: &mut ViewContext<Editor>,
project: Entity<Project>,
buffer: Entity<MultiBuffer>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Editor {
Editor::new(EditorMode::Full, buffer, Some(project), true, cx)
Editor::new(EditorMode::Full, buffer, Some(project), true, window, cx)
}

View file

@ -11,7 +11,7 @@ use serde_json::json;
use crate::{Editor, ToPoint};
use collections::HashSet;
use futures::Future;
use gpui::{View, ViewContext, VisualTestContext};
use gpui::{Context, Entity, Focusable as _, VisualTestContext, Window};
use indoc::indoc;
use language::{
point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageQueries,
@ -27,7 +27,7 @@ use super::editor_test_context::{AssertionContextManager, EditorTestContext};
pub struct EditorLspTestContext {
pub cx: EditorTestContext,
pub lsp: lsp::FakeLanguageServer,
pub workspace: View<Workspace>,
pub workspace: Entity<Workspace>,
pub buffer_lsp_url: lsp::Url,
}
@ -131,9 +131,9 @@ impl EditorLspTestContext {
)
.await;
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
let workspace = window.root_view(cx).unwrap();
let workspace = window.root_model(cx).unwrap();
let mut cx = VisualTestContext::from_window(*window.deref(), cx);
project
@ -146,16 +146,18 @@ impl EditorLspTestContext {
.await;
let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone());
let item = workspace
.update(&mut cx, |workspace, cx| {
workspace.open_path(file, None, true, cx)
.update_in(&mut cx, |workspace, window, cx| {
workspace.open_path(file, None, true, window, cx)
})
.await
.expect("Could not open test file");
let editor = cx.update(|cx| {
let editor = cx.update(|_, cx| {
item.act_as::<Editor>(cx)
.expect("Opened test file wasn't an editor")
});
editor.update(&mut cx, |editor, cx| editor.focus(cx));
editor.update_in(&mut cx, |editor, window, cx| {
window.focus(&editor.focus_handle(cx))
});
let lsp = fake_servers.next().await.unwrap();
Self {
@ -272,11 +274,11 @@ impl EditorLspTestContext {
}
pub fn to_lsp_range(&mut self, range: Range<usize>) -> lsp::Range {
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
let snapshot = self.update_editor(|editor, window, cx| editor.snapshot(window, cx));
let start_point = range.start.to_point(&snapshot.buffer_snapshot);
let end_point = range.end.to_point(&snapshot.buffer_snapshot);
self.editor(|editor, cx| {
self.editor(|editor, _, cx| {
let buffer = editor.buffer().read(cx);
let start = point_to_lsp(
buffer
@ -298,10 +300,10 @@ impl EditorLspTestContext {
}
pub fn to_lsp(&mut self, offset: usize) -> lsp::Position {
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
let snapshot = self.update_editor(|editor, window, cx| editor.snapshot(window, cx));
let point = offset.to_point(&snapshot.buffer_snapshot);
self.editor(|editor, cx| {
self.editor(|editor, _, cx| {
let buffer = editor.buffer().read(cx);
point_to_lsp(
buffer
@ -315,9 +317,9 @@ impl EditorLspTestContext {
pub fn update_workspace<F, T>(&mut self, update: F) -> T
where
F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
F: FnOnce(&mut Workspace, &mut Window, &mut Context<Workspace>) -> T,
{
self.workspace.update(&mut self.cx.cx, update)
self.workspace.update_in(&mut self.cx.cx, update)
}
pub fn handle_request<T, F, Fut>(

View file

@ -6,8 +6,8 @@ use collections::BTreeMap;
use futures::Future;
use git::diff::DiffHunkStatus;
use gpui::{
prelude::*, AnyWindowHandle, AppContext, Keystroke, ModelContext, Pixels, Point, View,
ViewContext, VisualTestContext, WindowHandle,
prelude::*, AnyWindowHandle, App, Context, Entity, Focusable as _, Keystroke, Pixels, Point,
VisualTestContext, Window, WindowHandle,
};
use itertools::Itertools;
use language::{Buffer, BufferSnapshot, LanguageRegistry};
@ -33,7 +33,7 @@ use super::{build_editor, build_editor_with_project};
pub struct EditorTestContext {
pub cx: gpui::VisualTestContext,
pub window: AnyWindowHandle,
pub editor: View<Editor>,
pub editor: Entity<Editor>,
pub assertion_cx: AssertionContextManager,
}
@ -56,13 +56,18 @@ impl EditorTestContext {
})
.await
.unwrap();
let editor = cx.add_window(|cx| {
let editor =
build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx);
editor.focus(cx);
let editor = cx.add_window(|window, cx| {
let editor = build_editor_with_project(
project,
MultiBuffer::build_from_buffer(buffer, cx),
window,
cx,
);
window.focus(&editor.focus_handle(cx));
editor
});
let editor_view = editor.root_view(cx).unwrap();
let editor_view = editor.root_model(cx).unwrap();
cx.run_until_parked();
Self {
@ -84,7 +89,7 @@ impl EditorTestContext {
}
pub async fn for_editor(editor: WindowHandle<Editor>, cx: &mut gpui::TestAppContext) -> Self {
let editor_view = editor.root_view(cx).unwrap();
let editor_view = editor.root_model(cx).unwrap();
Self {
cx: VisualTestContext::from_window(*editor.deref(), cx),
window: editor.into(),
@ -98,10 +103,10 @@ impl EditorTestContext {
excerpts: [&str; COUNT],
) -> EditorTestContext {
let mut multibuffer = MultiBuffer::new(language::Capability::ReadWrite);
let buffer = cx.new_model(|cx| {
let buffer = cx.new(|cx| {
for excerpt in excerpts.into_iter() {
let (text, ranges) = marked_text_ranges(excerpt, false);
let buffer = cx.new_model(|cx| Buffer::local(text, cx));
let buffer = cx.new(|cx| Buffer::local(text, cx));
multibuffer.push_excerpts(
buffer,
ranges.into_iter().map(|range| ExcerptRange {
@ -114,13 +119,14 @@ impl EditorTestContext {
multibuffer
});
let editor = cx.add_window(|cx| {
let editor = build_editor(buffer, cx);
editor.focus(cx);
let editor = cx.add_window(|window, cx| {
let editor = build_editor(buffer, window, cx);
window.focus(&editor.focus_handle(cx));
editor
});
let editor_view = editor.root_view(cx).unwrap();
let editor_view = editor.root_model(cx).unwrap();
Self {
cx: VisualTestContext::from_window(*editor.deref(), cx),
window: editor.into(),
@ -131,7 +137,7 @@ impl EditorTestContext {
pub fn condition(
&self,
predicate: impl FnMut(&Editor, &AppContext) -> bool,
predicate: impl FnMut(&Editor, &App) -> bool,
) -> impl Future<Output = ()> {
self.editor
.condition::<crate::EditorEvent>(&self.cx, predicate)
@ -140,31 +146,32 @@ impl EditorTestContext {
#[track_caller]
pub fn editor<F, T>(&mut self, read: F) -> T
where
F: FnOnce(&Editor, &ViewContext<Editor>) -> T,
F: FnOnce(&Editor, &Window, &mut Context<Editor>) -> T,
{
self.editor.update(&mut self.cx, |this, cx| read(this, cx))
self.editor
.update_in(&mut self.cx, |this, window, cx| read(this, window, cx))
}
#[track_caller]
pub fn update_editor<F, T>(&mut self, update: F) -> T
where
F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
F: FnOnce(&mut Editor, &mut Window, &mut Context<Editor>) -> T,
{
self.editor.update(&mut self.cx, update)
self.editor.update_in(&mut self.cx, update)
}
pub fn multibuffer<F, T>(&mut self, read: F) -> T
where
F: FnOnce(&MultiBuffer, &AppContext) -> T,
F: FnOnce(&MultiBuffer, &App) -> T,
{
self.editor(|editor, cx| read(editor.buffer().read(cx), cx))
self.editor(|editor, _, cx| read(editor.buffer().read(cx), cx))
}
pub fn update_multibuffer<F, T>(&mut self, update: F) -> T
where
F: FnOnce(&mut MultiBuffer, &mut ModelContext<MultiBuffer>) -> T,
F: FnOnce(&mut MultiBuffer, &mut Context<MultiBuffer>) -> T,
{
self.update_editor(|editor, cx| editor.buffer().update(cx, update))
self.update_editor(|editor, _, cx| editor.buffer().update(cx, update))
}
pub fn buffer_text(&mut self) -> String {
@ -172,12 +179,12 @@ impl EditorTestContext {
}
pub fn display_text(&mut self) -> String {
self.update_editor(|editor, cx| editor.display_text(cx))
self.update_editor(|editor, _, cx| editor.display_text(cx))
}
pub fn buffer<F, T>(&mut self, read: F) -> T
where
F: FnOnce(&Buffer, &AppContext) -> T,
F: FnOnce(&Buffer, &App) -> T,
{
self.multibuffer(|multibuffer, cx| {
let buffer = multibuffer.as_singleton().unwrap().read(cx);
@ -186,7 +193,7 @@ impl EditorTestContext {
}
pub fn language_registry(&mut self) -> Arc<LanguageRegistry> {
self.editor(|editor, cx| {
self.editor(|editor, _, cx| {
editor
.project
.as_ref()
@ -199,7 +206,7 @@ impl EditorTestContext {
pub fn update_buffer<F, T>(&mut self, update: F) -> T
where
F: FnOnce(&mut Buffer, &mut ModelContext<Buffer>) -> T,
F: FnOnce(&mut Buffer, &mut Context<Buffer>) -> T,
{
self.update_multibuffer(|multibuffer, cx| {
let buffer = multibuffer.as_singleton().unwrap();
@ -239,9 +246,9 @@ impl EditorTestContext {
pub fn display_point(&mut self, marked_text: &str) -> DisplayPoint {
let ranges = self.ranges(marked_text);
let snapshot = self
.editor
.update(&mut self.cx, |editor, cx| editor.snapshot(cx));
let snapshot = self.editor.update_in(&mut self.cx, |editor, window, cx| {
editor.snapshot(window, cx)
});
ranges[0].start.to_display_point(&snapshot)
}
@ -251,16 +258,16 @@ impl EditorTestContext {
}
pub fn pixel_position_for(&mut self, display_point: DisplayPoint) -> Point<Pixels> {
self.update_editor(|editor, cx| {
self.update_editor(|editor, window, cx| {
let newest_point = editor.selections.newest_display(cx).head();
let pixel_position = editor.pixel_position_of_newest_cursor.unwrap();
let line_height = editor
.style()
.unwrap()
.text
.line_height_in_pixels(cx.rem_size());
let snapshot = editor.snapshot(cx);
let details = editor.text_layout_details(cx);
.line_height_in_pixels(window.rem_size());
let snapshot = editor.snapshot(window, cx);
let details = editor.text_layout_details(window);
let y = pixel_position.y
+ line_height * (display_point.row().as_f32() - newest_point.row().as_f32());
@ -279,8 +286,9 @@ impl EditorTestContext {
pub fn set_diff_base(&mut self, diff_base: &str) {
self.cx.run_until_parked();
let fs = self
.update_editor(|editor, cx| editor.project.as_ref().unwrap().read(cx).fs().as_fake());
let fs = self.update_editor(|editor, _, cx| {
editor.project.as_ref().unwrap().read(cx).fs().as_fake()
});
let path = self.update_buffer(|buffer, _| buffer.file().unwrap().path().clone());
fs.set_index_for_repo(
&Self::root_path().join(".git"),
@ -303,9 +311,9 @@ impl EditorTestContext {
marked_text.escape_debug()
));
let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
self.editor.update(&mut self.cx, |editor, cx| {
editor.set_text(unmarked_text, cx);
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
self.editor.update_in(&mut self.cx, |editor, window, cx| {
editor.set_text(unmarked_text, window, cx);
editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
s.select_ranges(selection_ranges)
})
});
@ -319,9 +327,9 @@ impl EditorTestContext {
marked_text.escape_debug()
));
let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
self.editor.update(&mut self.cx, |editor, cx| {
self.editor.update_in(&mut self.cx, |editor, window, cx| {
assert_eq!(editor.text(cx), unmarked_text);
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
s.select_ranges(selection_ranges)
})
});
@ -355,8 +363,8 @@ impl EditorTestContext {
#[track_caller]
pub fn assert_editor_background_highlights<Tag: 'static>(&mut self, marked_text: &str) {
let expected_ranges = self.ranges(marked_text);
let actual_ranges: Vec<Range<usize>> = self.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
let actual_ranges: Vec<Range<usize>> = self.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx);
editor
.background_highlights
.get(&TypeId::of::<Tag>())
@ -372,7 +380,7 @@ impl EditorTestContext {
#[track_caller]
pub fn assert_editor_text_highlights<Tag: ?Sized + 'static>(&mut self, marked_text: &str) {
let expected_ranges = self.ranges(marked_text);
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
let snapshot = self.update_editor(|editor, window, cx| editor.snapshot(window, cx));
let actual_ranges: Vec<Range<usize>> = snapshot
.text_highlight_ranges::<Tag>()
.map(|ranges| ranges.as_ref().clone().1)
@ -429,13 +437,13 @@ impl EditorTestContext {
#[track_caller]
pub fn assert_state_with_diff(
editor: &View<Editor>,
editor: &Entity<Editor>,
cx: &mut VisualTestContext,
expected_diff_text: &str,
) {
let (snapshot, selections) = editor.update(cx, |editor, cx| {
let (snapshot, selections) = editor.update_in(cx, |editor, window, cx| {
(
editor.snapshot(cx).buffer_snapshot.clone(),
editor.snapshot(window, cx).buffer_snapshot.clone(),
editor.selections.ranges::<usize>(cx),
)
});