Take a mutable context when resolving selections (#19948)

This is a behavior-preserving change, but lays the groundwork for
expanding selections when the cursor lands inside of a "replace" block.

Release Notes:

- N/A
This commit is contained in:
Antonio Scandurra 2024-10-30 15:21:51 +01:00 committed by GitHub
parent 83e2889d63
commit c8003c0697
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 288 additions and 257 deletions

View file

@ -1677,8 +1677,10 @@ impl ContextEditor {
});
}
fn cursors(&self, cx: &AppContext) -> Vec<usize> {
let selections = self.editor.read(cx).selections.all::<usize>(cx);
fn cursors(&self, cx: &mut WindowContext) -> Vec<usize> {
let selections = self
.editor
.update(cx, |editor, cx| editor.selections.all::<usize>(cx));
selections
.into_iter()
.map(|selection| selection.head())
@ -2385,7 +2387,9 @@ impl ContextEditor {
}
fn update_active_patch(&mut self, cx: &mut ViewContext<Self>) {
let newest_cursor = self.editor.read(cx).selections.newest::<Point>(cx).head();
let newest_cursor = self.editor.update(cx, |editor, cx| {
editor.selections.newest::<Point>(cx).head()
});
let context = self.context.read(cx);
let new_patch = context.patch_containing(newest_cursor, cx).cloned();
@ -2792,39 +2796,40 @@ impl ContextEditor {
) -> Option<(String, bool)> {
const CODE_FENCE_DELIMITER: &'static str = "```";
let context_editor = context_editor_view.read(cx).editor.read(cx);
let context_editor = context_editor_view.read(cx).editor.clone();
context_editor.update(cx, |context_editor, cx| {
if context_editor.selections.newest::<Point>(cx).is_empty() {
let snapshot = context_editor.buffer().read(cx).snapshot(cx);
let (_, _, snapshot) = snapshot.as_singleton()?;
if context_editor.selections.newest::<Point>(cx).is_empty() {
let snapshot = context_editor.buffer().read(cx).snapshot(cx);
let (_, _, snapshot) = snapshot.as_singleton()?;
let head = context_editor.selections.newest::<Point>(cx).head();
let offset = snapshot.point_to_offset(head);
let head = context_editor.selections.newest::<Point>(cx).head();
let offset = snapshot.point_to_offset(head);
let surrounding_code_block_range = find_surrounding_code_block(snapshot, offset)?;
let mut text = snapshot
.text_for_range(surrounding_code_block_range)
.collect::<String>();
let surrounding_code_block_range = find_surrounding_code_block(snapshot, offset)?;
let mut text = snapshot
.text_for_range(surrounding_code_block_range)
.collect::<String>();
// If there is no newline trailing the closing three-backticks, then
// tree-sitter-md extends the range of the content node to include
// the backticks.
if text.ends_with(CODE_FENCE_DELIMITER) {
text.drain((text.len() - CODE_FENCE_DELIMITER.len())..);
}
// If there is no newline trailing the closing three-backticks, then
// tree-sitter-md extends the range of the content node to include
// the backticks.
if text.ends_with(CODE_FENCE_DELIMITER) {
text.drain((text.len() - CODE_FENCE_DELIMITER.len())..);
(!text.is_empty()).then_some((text, true))
} else {
let anchor = context_editor.selections.newest_anchor();
let text = context_editor
.buffer()
.read(cx)
.read(cx)
.text_for_range(anchor.range())
.collect::<String>();
(!text.is_empty()).then_some((text, false))
}
(!text.is_empty()).then_some((text, true))
} else {
let anchor = context_editor.selections.newest_anchor();
let text = context_editor
.buffer()
.read(cx)
.read(cx)
.text_for_range(anchor.range())
.collect::<String>();
(!text.is_empty()).then_some((text, false))
}
})
}
fn insert_selection(

View file

@ -189,11 +189,16 @@ impl InlineAssistant {
initial_prompt: Option<String>,
cx: &mut WindowContext,
) {
let snapshot = editor.read(cx).buffer().read(cx).snapshot(cx);
let (snapshot, initial_selections) = editor.update(cx, |editor, cx| {
(
editor.buffer().read(cx).snapshot(cx),
editor.selections.all::<Point>(cx),
)
});
let mut selections = Vec::<Selection<Point>>::new();
let mut newest_selection = None;
for mut selection in editor.read(cx).selections.all::<Point>(cx) {
for mut selection in initial_selections {
if selection.end > selection.start {
selection.start.column = 0;
// If the selection ends at the start of the line, we don't want to include it.
@ -566,10 +571,13 @@ impl InlineAssistant {
return;
};
let editor = editor.read(cx);
if editor.selections.count() == 1 {
let selection = editor.selections.newest::<usize>(cx);
let buffer = editor.buffer().read(cx).snapshot(cx);
if editor.read(cx).selections.count() == 1 {
let (selection, buffer) = editor.update(cx, |editor, cx| {
(
editor.selections.newest::<usize>(cx),
editor.buffer().read(cx).snapshot(cx),
)
});
for assist_id in &editor_assists.assist_ids {
let assist = &self.assists[assist_id];
let assist_range = assist.range.to_offset(&buffer);
@ -594,10 +602,13 @@ impl InlineAssistant {
return;
};
let editor = editor.read(cx);
if editor.selections.count() == 1 {
let selection = editor.selections.newest::<usize>(cx);
let buffer = editor.buffer().read(cx).snapshot(cx);
if editor.read(cx).selections.count() == 1 {
let (selection, buffer) = editor.update(cx, |editor, cx| {
(
editor.selections.newest::<usize>(cx),
editor.buffer().read(cx).snapshot(cx),
)
});
let mut closest_assist_fallback = None;
for assist_id in &editor_assists.assist_ids {
let assist = &self.assists[assist_id];

View file

@ -1957,9 +1957,10 @@ async fn test_following_to_channel_notes_without_a_shared_project(
});
channel_notes_1_b.update(cx_b, |notes, cx| {
assert_eq!(notes.channel(cx).unwrap().name, "channel-1");
let editor = notes.editor.read(cx);
assert_eq!(editor.text(cx), "Hello from A.");
assert_eq!(editor.selections.ranges::<usize>(cx), &[3..4]);
notes.editor.update(cx, |editor, cx| {
assert_eq!(editor.text(cx), "Hello from A.");
assert_eq!(editor.selections.ranges::<usize>(cx), &[3..4]);
})
});
// Client A opens the notes for channel 2.

View file

@ -136,11 +136,12 @@ impl DiagnosticIndicator {
}
fn update(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
let editor = editor.read(cx);
let buffer = editor.buffer().read(cx);
let cursor_position = editor.selections.newest::<usize>(cx).head();
let (buffer, cursor_position) = editor.update(cx, |editor, cx| {
let buffer = editor.buffer().read(cx).snapshot(cx);
let cursor_position = editor.selections.newest::<usize>(cx).head();
(buffer, cursor_position)
});
let new_diagnostic = buffer
.snapshot(cx)
.diagnostics_in_range::<_, usize>(cursor_position..cursor_position, false)
.filter(|entry| !entry.range.is_empty())
.min_by_key(|entry| (entry.diagnostic.severity, entry.range.len()))

View file

@ -9629,8 +9629,8 @@ impl Editor {
let Some(provider) = self.semantics_provider.clone() else {
return Task::ready(Ok(Navigated::No));
};
let buffer = self.buffer.read(cx);
let head = self.selections.newest::<usize>(cx).head();
let buffer = self.buffer.read(cx);
let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
text_anchor
} else {
@ -9937,8 +9937,8 @@ impl Editor {
_: &FindAllReferences,
cx: &mut ViewContext<Self>,
) -> Option<Task<Result<Navigated>>> {
let multi_buffer = self.buffer.read(cx);
let selection = self.selections.newest::<usize>(cx);
let multi_buffer = self.buffer.read(cx);
let head = selection.head();
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
@ -10345,8 +10345,9 @@ impl Editor {
self.show_local_selections = true;
if moving_cursor {
let rename_editor = rename.editor.read(cx);
let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
editor.selections.newest::<usize>(cx).head()
});
// Update the selection to match the position of the selection inside
// the rename editor.
@ -11592,9 +11593,9 @@ impl Editor {
}
pub fn copy_file_location(&mut self, _: &CopyFileLocation, cx: &mut ViewContext<Self>) {
let selection = self.selections.newest::<Point>(cx).start.row + 1;
if let Some(file) = self.target_file(cx) {
if let Some(path) = file.path().to_str() {
let selection = self.selections.newest::<Point>(cx).start.row + 1;
cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
}
}
@ -12370,9 +12371,10 @@ impl Editor {
return;
};
let selections = self.selections.all::<usize>(cx);
let buffer = self.buffer.read(cx);
let mut new_selections_by_buffer = HashMap::default();
for selection in self.selections.all::<usize>(cx) {
for selection in selections {
for (buffer, range, _) in
buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
{
@ -12417,6 +12419,7 @@ impl Editor {
}
fn open_excerpts_common(&mut self, split: bool, cx: &mut ViewContext<Self>) {
let selections = self.selections.all::<usize>(cx);
let buffer = self.buffer.read(cx);
if buffer.is_singleton() {
cx.propagate();
@ -12429,7 +12432,7 @@ impl Editor {
};
let mut new_selections_by_buffer = HashMap::default();
for selection in self.selections.all::<usize>(cx) {
for selection in selections {
for (mut buffer_handle, mut range, _) in
buffer.range_to_buffer_ranges(selection.range(), cx)
{
@ -12545,7 +12548,7 @@ impl Editor {
fn selection_replacement_ranges(
&self,
range: Range<OffsetUtf16>,
cx: &AppContext,
cx: &mut AppContext,
) -> Vec<Range<OffsetUtf16>> {
let selections = self.selections.all::<OffsetUtf16>(cx);
let newest_selection = selections

View file

@ -824,129 +824,131 @@ impl EditorElement {
let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
let mut active_rows = BTreeMap::new();
let mut newest_selection_head = None;
let editor = self.editor.read(cx);
self.editor.update(cx, |editor, cx| {
if editor.show_local_selections {
let mut local_selections: Vec<Selection<Point>> = editor
.selections
.disjoint_in_range(start_anchor..end_anchor, cx);
local_selections.extend(editor.selections.pending(cx));
let mut layouts = Vec::new();
let newest = editor.selections.newest(cx);
for selection in local_selections.drain(..) {
let is_empty = selection.start == selection.end;
let is_newest = selection == newest;
if editor.show_local_selections {
let mut local_selections: Vec<Selection<Point>> = editor
.selections
.disjoint_in_range(start_anchor..end_anchor, cx);
local_selections.extend(editor.selections.pending(cx));
let mut layouts = Vec::new();
let newest = editor.selections.newest(cx);
for selection in local_selections.drain(..) {
let is_empty = selection.start == selection.end;
let is_newest = selection == newest;
let layout = SelectionLayout::new(
selection,
editor.selections.line_mode,
editor.cursor_shape,
&snapshot.display_snapshot,
is_newest,
editor.leader_peer_id.is_none(),
None,
);
if is_newest {
newest_selection_head = Some(layout.head);
}
let layout = SelectionLayout::new(
selection,
editor.selections.line_mode,
editor.cursor_shape,
&snapshot.display_snapshot,
is_newest,
editor.leader_peer_id.is_none(),
None,
);
if is_newest {
newest_selection_head = Some(layout.head);
for row in cmp::max(layout.active_rows.start.0, start_row.0)
..=cmp::min(layout.active_rows.end.0, end_row.0)
{
let contains_non_empty_selection =
active_rows.entry(DisplayRow(row)).or_insert(!is_empty);
*contains_non_empty_selection |= !is_empty;
}
layouts.push(layout);
}
for row in cmp::max(layout.active_rows.start.0, start_row.0)
..=cmp::min(layout.active_rows.end.0, end_row.0)
{
let contains_non_empty_selection =
active_rows.entry(DisplayRow(row)).or_insert(!is_empty);
*contains_non_empty_selection |= !is_empty;
}
layouts.push(layout);
let player = if editor.read_only(cx) {
cx.theme().players().read_only()
} else {
self.style.local_player
};
selections.push((player, layouts));
}
let player = if editor.read_only(cx) {
cx.theme().players().read_only()
} else {
self.style.local_player
};
selections.push((player, layouts));
}
if let Some(collaboration_hub) = &editor.collaboration_hub {
// When following someone, render the local selections in their color.
if let Some(leader_id) = editor.leader_peer_id {
if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id) {
if let Some(participant_index) = collaboration_hub
.user_participant_indices(cx)
.get(&collaborator.user_id)
if let Some(collaboration_hub) = &editor.collaboration_hub {
// When following someone, render the local selections in their color.
if let Some(leader_id) = editor.leader_peer_id {
if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id)
{
if let Some((local_selection_style, _)) = selections.first_mut() {
*local_selection_style = cx
.theme()
.players()
.color_for_participant(participant_index.0);
if let Some(participant_index) = collaboration_hub
.user_participant_indices(cx)
.get(&collaborator.user_id)
{
if let Some((local_selection_style, _)) = selections.first_mut() {
*local_selection_style = cx
.theme()
.players()
.color_for_participant(participant_index.0);
}
}
}
}
}
let mut remote_selections = HashMap::default();
for selection in snapshot.remote_selections_in_range(
&(start_anchor..end_anchor),
collaboration_hub.as_ref(),
cx,
) {
let selection_style = Self::get_participant_color(selection.participant_index, cx);
let mut remote_selections = HashMap::default();
for selection in snapshot.remote_selections_in_range(
&(start_anchor..end_anchor),
collaboration_hub.as_ref(),
cx,
) {
let selection_style =
Self::get_participant_color(selection.participant_index, cx);
// Don't re-render the leader's selections, since the local selections
// match theirs.
if Some(selection.peer_id) == editor.leader_peer_id {
continue;
// Don't re-render the leader's selections, since the local selections
// match theirs.
if Some(selection.peer_id) == editor.leader_peer_id {
continue;
}
let key = HoveredCursor {
replica_id: selection.replica_id,
selection_id: selection.selection.id,
};
let is_shown =
editor.show_cursor_names || editor.hovered_cursors.contains_key(&key);
remote_selections
.entry(selection.replica_id)
.or_insert((selection_style, Vec::new()))
.1
.push(SelectionLayout::new(
selection.selection,
selection.line_mode,
selection.cursor_shape,
&snapshot.display_snapshot,
false,
false,
if is_shown { selection.user_name } else { None },
));
}
let key = HoveredCursor {
replica_id: selection.replica_id,
selection_id: selection.selection.id,
selections.extend(remote_selections.into_values());
} else if !editor.is_focused(cx) && editor.show_cursor_when_unfocused {
let player = if editor.read_only(cx) {
cx.theme().players().read_only()
} else {
self.style.local_player
};
let is_shown =
editor.show_cursor_names || editor.hovered_cursors.contains_key(&key);
remote_selections
.entry(selection.replica_id)
.or_insert((selection_style, Vec::new()))
.1
.push(SelectionLayout::new(
selection.selection,
selection.line_mode,
selection.cursor_shape,
&snapshot.display_snapshot,
false,
false,
if is_shown { selection.user_name } else { None },
));
let layouts = snapshot
.buffer_snapshot
.selections_in_range(&(start_anchor..end_anchor), true)
.map(move |(_, line_mode, cursor_shape, selection)| {
SelectionLayout::new(
selection,
line_mode,
cursor_shape,
&snapshot.display_snapshot,
false,
false,
None,
)
})
.collect::<Vec<_>>();
selections.push((player, layouts));
}
selections.extend(remote_selections.into_values());
} else if !editor.is_focused(cx) && editor.show_cursor_when_unfocused {
let player = if editor.read_only(cx) {
cx.theme().players().read_only()
} else {
self.style.local_player
};
let layouts = snapshot
.buffer_snapshot
.selections_in_range(&(start_anchor..end_anchor), true)
.map(move |(_, line_mode, cursor_shape, selection)| {
SelectionLayout::new(
selection,
line_mode,
cursor_shape,
&snapshot.display_snapshot,
false,
false,
None,
)
})
.collect::<Vec<_>>();
selections.push((player, layouts));
}
});
(selections, active_rows, newest_selection_head)
}
@ -1848,23 +1850,25 @@ impl EditorElement {
return Vec::new();
}
let editor = self.editor.read(cx);
let newest_selection_head = newest_selection_head.unwrap_or_else(|| {
let newest = editor.selections.newest::<Point>(cx);
SelectionLayout::new(
newest,
editor.selections.line_mode,
editor.cursor_shape,
&snapshot.display_snapshot,
true,
true,
None,
)
.head
let (newest_selection_head, is_relative) = self.editor.update(cx, |editor, cx| {
let newest_selection_head = newest_selection_head.unwrap_or_else(|| {
let newest = editor.selections.newest::<Point>(cx);
SelectionLayout::new(
newest,
editor.selections.line_mode,
editor.cursor_shape,
&snapshot.display_snapshot,
true,
true,
None,
)
.head
});
let is_relative = editor.should_use_relative_line_numbers(cx);
(newest_selection_head, is_relative)
});
let font_size = self.style.text.font_size.to_pixels(cx.rem_size());
let is_relative = editor.should_use_relative_line_numbers(cx);
let relative_to = if is_relative {
Some(newest_selection_head.row())
} else {

View file

@ -41,9 +41,9 @@ pub(super) fn refresh_linked_ranges(this: &mut Editor, cx: &mut ViewContext<Edit
return None;
}
let project = this.project.clone()?;
let selections = this.selections.all::<usize>(cx);
let buffer = this.buffer.read(cx);
let mut applicable_selections = vec![];
let selections = this.selections.all::<usize>(cx);
let snapshot = buffer.snapshot(cx);
for selection in selections {
let cursor_position = selection.head();

View file

@ -8,14 +8,14 @@ use std::{
use collections::HashMap;
use gpui::{AppContext, Model, Pixels};
use itertools::Itertools;
use language::{Bias, Point, Selection, SelectionGoal, TextDimension, ToPoint};
use language::{Bias, Point, Selection, SelectionGoal, TextDimension};
use util::post_inc;
use crate::{
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
movement::TextLayoutDetails,
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode,
ToOffset,
ToOffset, ToPoint,
};
#[derive(Debug, Clone)]
@ -96,7 +96,7 @@ impl SelectionsCollection {
pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &AppContext,
cx: &mut AppContext,
) -> Option<Selection<D>> {
self.pending_anchor()
.as_ref()
@ -107,7 +107,7 @@ impl SelectionsCollection {
self.pending.as_ref().map(|pending| pending.mode.clone())
}
pub fn all<'a, D>(&self, cx: &AppContext) -> Vec<Selection<D>>
pub fn all<'a, D>(&self, cx: &mut AppContext) -> Vec<Selection<D>>
where
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
{
@ -194,7 +194,7 @@ impl SelectionsCollection {
pub fn disjoint_in_range<'a, D>(
&self,
range: Range<Anchor>,
cx: &AppContext,
cx: &mut AppContext,
) -> Vec<Selection<D>>
where
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
@ -239,9 +239,10 @@ impl SelectionsCollection {
pub fn newest<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &AppContext,
cx: &mut AppContext,
) -> Selection<D> {
resolve(self.newest_anchor(), &self.buffer(cx))
let buffer = self.buffer(cx);
self.newest_anchor().map(|p| p.summary::<D>(&buffer))
}
pub fn newest_display(&self, cx: &mut AppContext) -> Selection<DisplayPoint> {
@ -262,9 +263,10 @@ impl SelectionsCollection {
pub fn oldest<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &AppContext,
cx: &mut AppContext,
) -> Selection<D> {
resolve(self.oldest_anchor(), &self.buffer(cx))
let buffer = self.buffer(cx);
self.oldest_anchor().map(|p| p.summary::<D>(&buffer))
}
pub fn first_anchor(&self) -> Selection<Anchor> {
@ -276,14 +278,14 @@ impl SelectionsCollection {
pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &AppContext,
cx: &mut AppContext,
) -> Selection<D> {
self.all(cx).first().unwrap().clone()
}
pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
cx: &AppContext,
cx: &mut AppContext,
) -> Selection<D> {
self.all(cx).last().unwrap().clone()
}
@ -298,7 +300,7 @@ impl SelectionsCollection {
#[cfg(any(test, feature = "test-support"))]
pub fn ranges<D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug>(
&self,
cx: &AppContext,
cx: &mut AppContext,
) -> Vec<Range<D>> {
self.all::<D>(cx)
.iter()
@ -475,7 +477,7 @@ impl<'a> MutableSelectionsCollection<'a> {
where
T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
{
let mut selections = self.all(self.cx);
let mut selections = self.collection.all(self.cx);
let mut start = range.start.to_offset(&self.buffer());
let mut end = range.end.to_offset(&self.buffer());
let reversed = if start > end {
@ -649,6 +651,7 @@ impl<'a> MutableSelectionsCollection<'a> {
let mut changed = false;
let display_map = self.display_map();
let selections = self
.collection
.all::<Point>(self.cx)
.into_iter()
.map(|selection| {
@ -676,6 +679,7 @@ impl<'a> MutableSelectionsCollection<'a> {
let mut changed = false;
let snapshot = self.buffer().clone();
let selections = self
.collection
.all::<usize>(self.cx)
.into_iter()
.map(|selection| {
@ -869,10 +873,3 @@ where
goal: s.goal,
})
}
fn resolve<D: TextDimension + Ord + Sub<D, Output = D>>(
selection: &Selection<Anchor>,
buffer: &MultiBufferSnapshot,
) -> Selection<D> {
selection.map(|p| p.summary::<D>(buffer))
}

View file

@ -37,34 +37,34 @@ impl CursorPosition {
}
fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
let editor = editor.read(cx);
let buffer = editor.buffer().read(cx).snapshot(cx);
editor.update(cx, |editor, cx| {
let buffer = editor.buffer().read(cx).snapshot(cx);
self.selected_count = Default::default();
self.selected_count.selections = editor.selections.count();
let mut last_selection: Option<Selection<usize>> = None;
for selection in editor.selections.all::<usize>(cx) {
self.selected_count.characters += buffer
.text_for_range(selection.start..selection.end)
.map(|t| t.chars().count())
.sum::<usize>();
if last_selection
.as_ref()
.map_or(true, |last_selection| selection.id > last_selection.id)
{
last_selection = Some(selection);
}
}
for selection in editor.selections.all::<Point>(cx) {
if selection.end != selection.start {
self.selected_count.lines += (selection.end.row - selection.start.row) as usize;
if selection.end.column != 0 {
self.selected_count.lines += 1;
self.selected_count = Default::default();
self.selected_count.selections = editor.selections.count();
let mut last_selection: Option<Selection<usize>> = None;
for selection in editor.selections.all::<usize>(cx) {
self.selected_count.characters += buffer
.text_for_range(selection.start..selection.end)
.map(|t| t.chars().count())
.sum::<usize>();
if last_selection
.as_ref()
.map_or(true, |last_selection| selection.id > last_selection.id)
{
last_selection = Some(selection);
}
}
}
self.position = last_selection.map(|s| s.head().to_point(&buffer));
for selection in editor.selections.all::<Point>(cx) {
if selection.end != selection.start {
self.selected_count.lines += (selection.end.row - selection.start.row) as usize;
if selection.end.column != 0 {
self.selected_count.lines += 1;
}
}
}
self.position = last_selection.map(|s| s.head().to_point(&buffer));
});
cx.notify();
}

View file

@ -56,8 +56,8 @@ impl GoToLine {
}
pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
let editor = active_editor.read(cx);
let cursor = editor.selections.last::<Point>(cx).head();
let cursor =
active_editor.update(cx, |editor, cx| editor.selections.last::<Point>(cx).head());
let line = cursor.row + 1;
let column = cursor.column + 1;

View file

@ -128,12 +128,14 @@ impl SyntaxTreeView {
fn editor_updated(&mut self, did_reparse: bool, cx: &mut ViewContext<Self>) -> Option<()> {
// Find which excerpt the cursor is in, and the position within that excerpted buffer.
let editor_state = self.editor.as_mut()?;
let editor = &editor_state.editor.read(cx);
let selection_range = editor.selections.last::<usize>(cx).range();
let multibuffer = editor.buffer().read(cx);
let (buffer, range, excerpt_id) = multibuffer
.range_to_buffer_ranges(selection_range, cx)
.pop()?;
let (buffer, range, excerpt_id) = editor_state.editor.update(cx, |editor, cx| {
let selection_range = editor.selections.last::<usize>(cx).range();
editor
.buffer()
.read(cx)
.range_to_buffer_ranges(selection_range, cx)
.pop()
})?;
// If the cursor has moved into a different excerpt, retrieve a new syntax layer
// from that buffer.

View file

@ -301,8 +301,8 @@ impl MarkdownPreviewView {
this.parse_markdown_from_active_editor(true, cx);
}
EditorEvent::SelectionsChanged { .. } => {
let editor = editor.read(cx);
let selection_range = editor.selections.last::<usize>(cx).range();
let selection_range =
editor.update(cx, |editor, cx| editor.selections.last::<usize>(cx).range());
this.selected_block = this.get_block_index_under_cursor(selection_range);
this.list_state.scroll_to_reveal_item(this.selected_block);
cx.notify();

View file

@ -194,9 +194,11 @@ impl PickerDelegate for OutlineViewDelegate {
})
.collect();
let editor = self.active_editor.read(cx);
let cursor_offset = editor.selections.newest::<usize>(cx).head();
let buffer = editor.buffer().read(cx).snapshot(cx);
let (buffer, cursor_offset) = self.active_editor.update(cx, |editor, cx| {
let buffer = editor.buffer().read(cx).snapshot(cx);
let cursor_offset = editor.selections.newest::<usize>(cx).head();
(buffer, cursor_offset)
});
selected_index = self
.outline
.items

View file

@ -2410,11 +2410,9 @@ impl OutlinePanel {
editor: &View<Editor>,
cx: &mut ViewContext<Self>,
) -> Option<PanelEntry> {
let selection = editor
.read(cx)
.selections
.newest::<language::Point>(cx)
.head();
let selection = editor.update(cx, |editor, cx| {
editor.selections.newest::<language::Point>(cx).head()
});
let editor_snapshot = editor.update(cx, |editor, cx| editor.snapshot(cx));
let multi_buffer = editor.read(cx).buffer();
let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx);

View file

@ -5,7 +5,7 @@ use std::sync::Arc;
use anyhow::{Context, Result};
use editor::Editor;
use gpui::{prelude::*, AppContext, Entity, View, WeakView, WindowContext};
use gpui::{prelude::*, Entity, View, WeakView, WindowContext};
use language::{BufferSnapshot, Language, LanguageName, Point};
use crate::repl_store::ReplStore;
@ -103,7 +103,7 @@ pub enum SessionSupport {
Unsupported,
}
pub fn session(editor: WeakView<Editor>, cx: &mut AppContext) -> SessionSupport {
pub fn session(editor: WeakView<Editor>, cx: &mut WindowContext) -> SessionSupport {
let store = ReplStore::global(cx);
let entity_id = editor.entity_id();
@ -311,17 +311,21 @@ fn language_supported(language: &Arc<Language>) -> bool {
}
}
fn get_language(editor: WeakView<Editor>, cx: &mut AppContext) -> Option<Arc<Language>> {
let editor = editor.upgrade()?;
let selection = editor.read(cx).selections.newest::<usize>(cx);
let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
buffer.language_at(selection.head()).cloned()
fn get_language(editor: WeakView<Editor>, cx: &mut WindowContext) -> Option<Arc<Language>> {
editor
.update(cx, |editor, cx| {
let selection = editor.selections.newest::<usize>(cx);
let buffer = editor.buffer().read(cx).snapshot(cx);
buffer.language_at(selection.head()).cloned()
})
.ok()
.flatten()
}
#[cfg(test)]
mod tests {
use super::*;
use gpui::Context;
use gpui::{AppContext, Context};
use indoc::indoc;
use language::{Buffer, Language, LanguageConfig, LanguageRegistry};

View file

@ -281,7 +281,7 @@ impl VimGlobals {
&mut self,
register: Option<char>,
editor: Option<&mut Editor>,
cx: &ViewContext<Editor>,
cx: &mut ViewContext<Editor>,
) -> Option<Register> {
let Some(register) = register.filter(|reg| *reg != '"') else {
let setting = VimSettings::get_global(cx).use_system_clipboard;

View file

@ -620,9 +620,11 @@ impl Vim {
let Some(editor) = self.editor() else {
return;
};
let newest_selection_empty = editor.update(cx, |editor, cx| {
editor.selections.newest::<usize>(cx).is_empty()
});
let editor = editor.read(cx);
let editor_mode = editor.mode();
let newest_selection_empty = editor.selections.newest::<usize>(cx).is_empty();
if editor_mode == EditorMode::Full
&& !newest_selection_empty
@ -717,11 +719,12 @@ impl Vim {
globals.recorded_count = None;
let selections = self.editor().map(|editor| {
let editor = editor.read(cx);
(
editor.selections.oldest::<Point>(cx),
editor.selections.newest::<Point>(cx),
)
editor.update(cx, |editor, cx| {
(
editor.selections.oldest::<Point>(cx),
editor.selections.newest::<Point>(cx),
)
})
});
if let Some((oldest, newest)) = selections {