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:
parent
83e2889d63
commit
c8003c0697
17 changed files with 288 additions and 257 deletions
|
@ -1677,8 +1677,10 @@ impl ContextEditor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursors(&self, cx: &AppContext) -> Vec<usize> {
|
fn cursors(&self, cx: &mut WindowContext) -> Vec<usize> {
|
||||||
let selections = self.editor.read(cx).selections.all::<usize>(cx);
|
let selections = self
|
||||||
|
.editor
|
||||||
|
.update(cx, |editor, cx| editor.selections.all::<usize>(cx));
|
||||||
selections
|
selections
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|selection| selection.head())
|
.map(|selection| selection.head())
|
||||||
|
@ -2385,7 +2387,9 @@ impl ContextEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_active_patch(&mut self, cx: &mut ViewContext<Self>) {
|
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 context = self.context.read(cx);
|
||||||
|
|
||||||
let new_patch = context.patch_containing(newest_cursor, cx).cloned();
|
let new_patch = context.patch_containing(newest_cursor, cx).cloned();
|
||||||
|
@ -2792,39 +2796,40 @@ impl ContextEditor {
|
||||||
) -> Option<(String, bool)> {
|
) -> Option<(String, bool)> {
|
||||||
const CODE_FENCE_DELIMITER: &'static str = "```";
|
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 head = context_editor.selections.newest::<Point>(cx).head();
|
||||||
let snapshot = context_editor.buffer().read(cx).snapshot(cx);
|
let offset = snapshot.point_to_offset(head);
|
||||||
let (_, _, snapshot) = snapshot.as_singleton()?;
|
|
||||||
|
|
||||||
let head = context_editor.selections.newest::<Point>(cx).head();
|
let surrounding_code_block_range = find_surrounding_code_block(snapshot, offset)?;
|
||||||
let offset = snapshot.point_to_offset(head);
|
let mut text = snapshot
|
||||||
|
.text_for_range(surrounding_code_block_range)
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
let surrounding_code_block_range = find_surrounding_code_block(snapshot, offset)?;
|
// If there is no newline trailing the closing three-backticks, then
|
||||||
let mut text = snapshot
|
// tree-sitter-md extends the range of the content node to include
|
||||||
.text_for_range(surrounding_code_block_range)
|
// the backticks.
|
||||||
.collect::<String>();
|
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
|
(!text.is_empty()).then_some((text, true))
|
||||||
// tree-sitter-md extends the range of the content node to include
|
} else {
|
||||||
// the backticks.
|
let anchor = context_editor.selections.newest_anchor();
|
||||||
if text.ends_with(CODE_FENCE_DELIMITER) {
|
let text = context_editor
|
||||||
text.drain((text.len() - CODE_FENCE_DELIMITER.len())..);
|
.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(
|
fn insert_selection(
|
||||||
|
|
|
@ -189,11 +189,16 @@ impl InlineAssistant {
|
||||||
initial_prompt: Option<String>,
|
initial_prompt: Option<String>,
|
||||||
cx: &mut WindowContext,
|
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 selections = Vec::<Selection<Point>>::new();
|
||||||
let mut newest_selection = None;
|
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 {
|
if selection.end > selection.start {
|
||||||
selection.start.column = 0;
|
selection.start.column = 0;
|
||||||
// If the selection ends at the start of the line, we don't want to include it.
|
// If the selection ends at the start of the line, we don't want to include it.
|
||||||
|
@ -566,10 +571,13 @@ impl InlineAssistant {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let editor = editor.read(cx);
|
if editor.read(cx).selections.count() == 1 {
|
||||||
if editor.selections.count() == 1 {
|
let (selection, buffer) = editor.update(cx, |editor, cx| {
|
||||||
let selection = editor.selections.newest::<usize>(cx);
|
(
|
||||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
editor.selections.newest::<usize>(cx),
|
||||||
|
editor.buffer().read(cx).snapshot(cx),
|
||||||
|
)
|
||||||
|
});
|
||||||
for assist_id in &editor_assists.assist_ids {
|
for assist_id in &editor_assists.assist_ids {
|
||||||
let assist = &self.assists[assist_id];
|
let assist = &self.assists[assist_id];
|
||||||
let assist_range = assist.range.to_offset(&buffer);
|
let assist_range = assist.range.to_offset(&buffer);
|
||||||
|
@ -594,10 +602,13 @@ impl InlineAssistant {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let editor = editor.read(cx);
|
if editor.read(cx).selections.count() == 1 {
|
||||||
if editor.selections.count() == 1 {
|
let (selection, buffer) = editor.update(cx, |editor, cx| {
|
||||||
let selection = editor.selections.newest::<usize>(cx);
|
(
|
||||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
editor.selections.newest::<usize>(cx),
|
||||||
|
editor.buffer().read(cx).snapshot(cx),
|
||||||
|
)
|
||||||
|
});
|
||||||
let mut closest_assist_fallback = None;
|
let mut closest_assist_fallback = None;
|
||||||
for assist_id in &editor_assists.assist_ids {
|
for assist_id in &editor_assists.assist_ids {
|
||||||
let assist = &self.assists[assist_id];
|
let assist = &self.assists[assist_id];
|
||||||
|
|
|
@ -1957,9 +1957,10 @@ async fn test_following_to_channel_notes_without_a_shared_project(
|
||||||
});
|
});
|
||||||
channel_notes_1_b.update(cx_b, |notes, cx| {
|
channel_notes_1_b.update(cx_b, |notes, cx| {
|
||||||
assert_eq!(notes.channel(cx).unwrap().name, "channel-1");
|
assert_eq!(notes.channel(cx).unwrap().name, "channel-1");
|
||||||
let editor = notes.editor.read(cx);
|
notes.editor.update(cx, |editor, cx| {
|
||||||
assert_eq!(editor.text(cx), "Hello from A.");
|
assert_eq!(editor.text(cx), "Hello from A.");
|
||||||
assert_eq!(editor.selections.ranges::<usize>(cx), &[3..4]);
|
assert_eq!(editor.selections.ranges::<usize>(cx), &[3..4]);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// Client A opens the notes for channel 2.
|
// Client A opens the notes for channel 2.
|
||||||
|
|
|
@ -136,11 +136,12 @@ impl DiagnosticIndicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
fn update(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
||||||
let editor = editor.read(cx);
|
let (buffer, cursor_position) = editor.update(cx, |editor, cx| {
|
||||||
let buffer = editor.buffer().read(cx);
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
let cursor_position = editor.selections.newest::<usize>(cx).head();
|
let cursor_position = editor.selections.newest::<usize>(cx).head();
|
||||||
|
(buffer, cursor_position)
|
||||||
|
});
|
||||||
let new_diagnostic = buffer
|
let new_diagnostic = buffer
|
||||||
.snapshot(cx)
|
|
||||||
.diagnostics_in_range::<_, usize>(cursor_position..cursor_position, false)
|
.diagnostics_in_range::<_, usize>(cursor_position..cursor_position, false)
|
||||||
.filter(|entry| !entry.range.is_empty())
|
.filter(|entry| !entry.range.is_empty())
|
||||||
.min_by_key(|entry| (entry.diagnostic.severity, entry.range.len()))
|
.min_by_key(|entry| (entry.diagnostic.severity, entry.range.len()))
|
||||||
|
|
|
@ -9629,8 +9629,8 @@ impl Editor {
|
||||||
let Some(provider) = self.semantics_provider.clone() else {
|
let Some(provider) = self.semantics_provider.clone() else {
|
||||||
return Task::ready(Ok(Navigated::No));
|
return Task::ready(Ok(Navigated::No));
|
||||||
};
|
};
|
||||||
let buffer = self.buffer.read(cx);
|
|
||||||
let head = self.selections.newest::<usize>(cx).head();
|
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) {
|
let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
|
||||||
text_anchor
|
text_anchor
|
||||||
} else {
|
} else {
|
||||||
|
@ -9937,8 +9937,8 @@ impl Editor {
|
||||||
_: &FindAllReferences,
|
_: &FindAllReferences,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<Task<Result<Navigated>>> {
|
) -> Option<Task<Result<Navigated>>> {
|
||||||
let multi_buffer = self.buffer.read(cx);
|
|
||||||
let selection = self.selections.newest::<usize>(cx);
|
let selection = self.selections.newest::<usize>(cx);
|
||||||
|
let multi_buffer = self.buffer.read(cx);
|
||||||
let head = selection.head();
|
let head = selection.head();
|
||||||
|
|
||||||
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
|
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
|
||||||
|
@ -10345,8 +10345,9 @@ impl Editor {
|
||||||
self.show_local_selections = true;
|
self.show_local_selections = true;
|
||||||
|
|
||||||
if moving_cursor {
|
if moving_cursor {
|
||||||
let rename_editor = rename.editor.read(cx);
|
let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
|
||||||
let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
|
editor.selections.newest::<usize>(cx).head()
|
||||||
|
});
|
||||||
|
|
||||||
// Update the selection to match the position of the selection inside
|
// Update the selection to match the position of the selection inside
|
||||||
// the rename editor.
|
// the rename editor.
|
||||||
|
@ -11592,9 +11593,9 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_file_location(&mut self, _: &CopyFileLocation, cx: &mut ViewContext<Self>) {
|
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(file) = self.target_file(cx) {
|
||||||
if let Some(path) = file.path().to_str() {
|
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}")));
|
cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12370,9 +12371,10 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let selections = self.selections.all::<usize>(cx);
|
||||||
let buffer = self.buffer.read(cx);
|
let buffer = self.buffer.read(cx);
|
||||||
let mut new_selections_by_buffer = HashMap::default();
|
let mut new_selections_by_buffer = HashMap::default();
|
||||||
for selection in self.selections.all::<usize>(cx) {
|
for selection in selections {
|
||||||
for (buffer, range, _) in
|
for (buffer, range, _) in
|
||||||
buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
|
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>) {
|
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);
|
let buffer = self.buffer.read(cx);
|
||||||
if buffer.is_singleton() {
|
if buffer.is_singleton() {
|
||||||
cx.propagate();
|
cx.propagate();
|
||||||
|
@ -12429,7 +12432,7 @@ impl Editor {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_selections_by_buffer = HashMap::default();
|
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
|
for (mut buffer_handle, mut range, _) in
|
||||||
buffer.range_to_buffer_ranges(selection.range(), cx)
|
buffer.range_to_buffer_ranges(selection.range(), cx)
|
||||||
{
|
{
|
||||||
|
@ -12545,7 +12548,7 @@ impl Editor {
|
||||||
fn selection_replacement_ranges(
|
fn selection_replacement_ranges(
|
||||||
&self,
|
&self,
|
||||||
range: Range<OffsetUtf16>,
|
range: Range<OffsetUtf16>,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Vec<Range<OffsetUtf16>> {
|
) -> Vec<Range<OffsetUtf16>> {
|
||||||
let selections = self.selections.all::<OffsetUtf16>(cx);
|
let selections = self.selections.all::<OffsetUtf16>(cx);
|
||||||
let newest_selection = selections
|
let newest_selection = selections
|
||||||
|
|
|
@ -824,129 +824,131 @@ impl EditorElement {
|
||||||
let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
|
let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
|
||||||
let mut active_rows = BTreeMap::new();
|
let mut active_rows = BTreeMap::new();
|
||||||
let mut newest_selection_head = None;
|
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 layout = SelectionLayout::new(
|
||||||
let mut local_selections: Vec<Selection<Point>> = editor
|
selection,
|
||||||
.selections
|
editor.selections.line_mode,
|
||||||
.disjoint_in_range(start_anchor..end_anchor, cx);
|
editor.cursor_shape,
|
||||||
local_selections.extend(editor.selections.pending(cx));
|
&snapshot.display_snapshot,
|
||||||
let mut layouts = Vec::new();
|
is_newest,
|
||||||
let newest = editor.selections.newest(cx);
|
editor.leader_peer_id.is_none(),
|
||||||
for selection in local_selections.drain(..) {
|
None,
|
||||||
let is_empty = selection.start == selection.end;
|
);
|
||||||
let is_newest = selection == newest;
|
if is_newest {
|
||||||
|
newest_selection_head = Some(layout.head);
|
||||||
|
}
|
||||||
|
|
||||||
let layout = SelectionLayout::new(
|
for row in cmp::max(layout.active_rows.start.0, start_row.0)
|
||||||
selection,
|
..=cmp::min(layout.active_rows.end.0, end_row.0)
|
||||||
editor.selections.line_mode,
|
{
|
||||||
editor.cursor_shape,
|
let contains_non_empty_selection =
|
||||||
&snapshot.display_snapshot,
|
active_rows.entry(DisplayRow(row)).or_insert(!is_empty);
|
||||||
is_newest,
|
*contains_non_empty_selection |= !is_empty;
|
||||||
editor.leader_peer_id.is_none(),
|
}
|
||||||
None,
|
layouts.push(layout);
|
||||||
);
|
|
||||||
if is_newest {
|
|
||||||
newest_selection_head = Some(layout.head);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for row in cmp::max(layout.active_rows.start.0, start_row.0)
|
let player = if editor.read_only(cx) {
|
||||||
..=cmp::min(layout.active_rows.end.0, end_row.0)
|
cx.theme().players().read_only()
|
||||||
{
|
} else {
|
||||||
let contains_non_empty_selection =
|
self.style.local_player
|
||||||
active_rows.entry(DisplayRow(row)).or_insert(!is_empty);
|
};
|
||||||
*contains_non_empty_selection |= !is_empty;
|
|
||||||
}
|
selections.push((player, layouts));
|
||||||
layouts.push(layout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let player = if editor.read_only(cx) {
|
if let Some(collaboration_hub) = &editor.collaboration_hub {
|
||||||
cx.theme().players().read_only()
|
// When following someone, render the local selections in their color.
|
||||||
} else {
|
if let Some(leader_id) = editor.leader_peer_id {
|
||||||
self.style.local_player
|
if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id)
|
||||||
};
|
|
||||||
|
|
||||||
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((local_selection_style, _)) = selections.first_mut() {
|
if let Some(participant_index) = collaboration_hub
|
||||||
*local_selection_style = cx
|
.user_participant_indices(cx)
|
||||||
.theme()
|
.get(&collaborator.user_id)
|
||||||
.players()
|
{
|
||||||
.color_for_participant(participant_index.0);
|
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();
|
let mut remote_selections = HashMap::default();
|
||||||
for selection in snapshot.remote_selections_in_range(
|
for selection in snapshot.remote_selections_in_range(
|
||||||
&(start_anchor..end_anchor),
|
&(start_anchor..end_anchor),
|
||||||
collaboration_hub.as_ref(),
|
collaboration_hub.as_ref(),
|
||||||
cx,
|
cx,
|
||||||
) {
|
) {
|
||||||
let selection_style = Self::get_participant_color(selection.participant_index, cx);
|
let selection_style =
|
||||||
|
Self::get_participant_color(selection.participant_index, cx);
|
||||||
|
|
||||||
// Don't re-render the leader's selections, since the local selections
|
// Don't re-render the leader's selections, since the local selections
|
||||||
// match theirs.
|
// match theirs.
|
||||||
if Some(selection.peer_id) == editor.leader_peer_id {
|
if Some(selection.peer_id) == editor.leader_peer_id {
|
||||||
continue;
|
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,
|
selections.extend(remote_selections.into_values());
|
||||||
selection_id: selection.selection.id,
|
} 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
|
||||||
let is_shown =
|
.buffer_snapshot
|
||||||
editor.show_cursor_names || editor.hovered_cursors.contains_key(&key);
|
.selections_in_range(&(start_anchor..end_anchor), true)
|
||||||
|
.map(move |(_, line_mode, cursor_shape, selection)| {
|
||||||
remote_selections
|
SelectionLayout::new(
|
||||||
.entry(selection.replica_id)
|
selection,
|
||||||
.or_insert((selection_style, Vec::new()))
|
line_mode,
|
||||||
.1
|
cursor_shape,
|
||||||
.push(SelectionLayout::new(
|
&snapshot.display_snapshot,
|
||||||
selection.selection,
|
false,
|
||||||
selection.line_mode,
|
false,
|
||||||
selection.cursor_shape,
|
None,
|
||||||
&snapshot.display_snapshot,
|
)
|
||||||
false,
|
})
|
||||||
false,
|
.collect::<Vec<_>>();
|
||||||
if is_shown { selection.user_name } else { None },
|
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)
|
(selections, active_rows, newest_selection_head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1848,23 +1850,25 @@ impl EditorElement {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let editor = self.editor.read(cx);
|
let (newest_selection_head, is_relative) = self.editor.update(cx, |editor, cx| {
|
||||||
let newest_selection_head = newest_selection_head.unwrap_or_else(|| {
|
let newest_selection_head = newest_selection_head.unwrap_or_else(|| {
|
||||||
let newest = editor.selections.newest::<Point>(cx);
|
let newest = editor.selections.newest::<Point>(cx);
|
||||||
SelectionLayout::new(
|
SelectionLayout::new(
|
||||||
newest,
|
newest,
|
||||||
editor.selections.line_mode,
|
editor.selections.line_mode,
|
||||||
editor.cursor_shape,
|
editor.cursor_shape,
|
||||||
&snapshot.display_snapshot,
|
&snapshot.display_snapshot,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.head
|
.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 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 {
|
let relative_to = if is_relative {
|
||||||
Some(newest_selection_head.row())
|
Some(newest_selection_head.row())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -41,9 +41,9 @@ pub(super) fn refresh_linked_ranges(this: &mut Editor, cx: &mut ViewContext<Edit
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let project = this.project.clone()?;
|
let project = this.project.clone()?;
|
||||||
|
let selections = this.selections.all::<usize>(cx);
|
||||||
let buffer = this.buffer.read(cx);
|
let buffer = this.buffer.read(cx);
|
||||||
let mut applicable_selections = vec![];
|
let mut applicable_selections = vec![];
|
||||||
let selections = this.selections.all::<usize>(cx);
|
|
||||||
let snapshot = buffer.snapshot(cx);
|
let snapshot = buffer.snapshot(cx);
|
||||||
for selection in selections {
|
for selection in selections {
|
||||||
let cursor_position = selection.head();
|
let cursor_position = selection.head();
|
||||||
|
|
|
@ -8,14 +8,14 @@ use std::{
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{AppContext, Model, Pixels};
|
use gpui::{AppContext, Model, Pixels};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::{Bias, Point, Selection, SelectionGoal, TextDimension, ToPoint};
|
use language::{Bias, Point, Selection, SelectionGoal, TextDimension};
|
||||||
use util::post_inc;
|
use util::post_inc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||||
movement::TextLayoutDetails,
|
movement::TextLayoutDetails,
|
||||||
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode,
|
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode,
|
||||||
ToOffset,
|
ToOffset, ToPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -96,7 +96,7 @@ impl SelectionsCollection {
|
||||||
|
|
||||||
pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
|
pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Option<Selection<D>> {
|
) -> Option<Selection<D>> {
|
||||||
self.pending_anchor()
|
self.pending_anchor()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -107,7 +107,7 @@ impl SelectionsCollection {
|
||||||
self.pending.as_ref().map(|pending| pending.mode.clone())
|
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
|
where
|
||||||
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
|
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
|
||||||
{
|
{
|
||||||
|
@ -194,7 +194,7 @@ impl SelectionsCollection {
|
||||||
pub fn disjoint_in_range<'a, D>(
|
pub fn disjoint_in_range<'a, D>(
|
||||||
&self,
|
&self,
|
||||||
range: Range<Anchor>,
|
range: Range<Anchor>,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Vec<Selection<D>>
|
) -> Vec<Selection<D>>
|
||||||
where
|
where
|
||||||
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
|
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>>(
|
pub fn newest<D: TextDimension + Ord + Sub<D, Output = D>>(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Selection<D> {
|
) -> 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> {
|
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>>(
|
pub fn oldest<D: TextDimension + Ord + Sub<D, Output = D>>(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Selection<D> {
|
) -> 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> {
|
pub fn first_anchor(&self) -> Selection<Anchor> {
|
||||||
|
@ -276,14 +278,14 @@ impl SelectionsCollection {
|
||||||
|
|
||||||
pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
|
pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Selection<D> {
|
) -> Selection<D> {
|
||||||
self.all(cx).first().unwrap().clone()
|
self.all(cx).first().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
|
pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Selection<D> {
|
) -> Selection<D> {
|
||||||
self.all(cx).last().unwrap().clone()
|
self.all(cx).last().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
@ -298,7 +300,7 @@ impl SelectionsCollection {
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub fn ranges<D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug>(
|
pub fn ranges<D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug>(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Vec<Range<D>> {
|
) -> Vec<Range<D>> {
|
||||||
self.all::<D>(cx)
|
self.all::<D>(cx)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -475,7 +477,7 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||||
where
|
where
|
||||||
T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
|
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 start = range.start.to_offset(&self.buffer());
|
||||||
let mut end = range.end.to_offset(&self.buffer());
|
let mut end = range.end.to_offset(&self.buffer());
|
||||||
let reversed = if start > end {
|
let reversed = if start > end {
|
||||||
|
@ -649,6 +651,7 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let display_map = self.display_map();
|
let display_map = self.display_map();
|
||||||
let selections = self
|
let selections = self
|
||||||
|
.collection
|
||||||
.all::<Point>(self.cx)
|
.all::<Point>(self.cx)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|selection| {
|
.map(|selection| {
|
||||||
|
@ -676,6 +679,7 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let snapshot = self.buffer().clone();
|
let snapshot = self.buffer().clone();
|
||||||
let selections = self
|
let selections = self
|
||||||
|
.collection
|
||||||
.all::<usize>(self.cx)
|
.all::<usize>(self.cx)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|selection| {
|
.map(|selection| {
|
||||||
|
@ -869,10 +873,3 @@ where
|
||||||
goal: s.goal,
|
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))
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,34 +37,34 @@ impl CursorPosition {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
||||||
let editor = editor.read(cx);
|
editor.update(cx, |editor, cx| {
|
||||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
|
|
||||||
self.selected_count = Default::default();
|
self.selected_count = Default::default();
|
||||||
self.selected_count.selections = editor.selections.count();
|
self.selected_count.selections = editor.selections.count();
|
||||||
let mut last_selection: Option<Selection<usize>> = None;
|
let mut last_selection: Option<Selection<usize>> = None;
|
||||||
for selection in editor.selections.all::<usize>(cx) {
|
for selection in editor.selections.all::<usize>(cx) {
|
||||||
self.selected_count.characters += buffer
|
self.selected_count.characters += buffer
|
||||||
.text_for_range(selection.start..selection.end)
|
.text_for_range(selection.start..selection.end)
|
||||||
.map(|t| t.chars().count())
|
.map(|t| t.chars().count())
|
||||||
.sum::<usize>();
|
.sum::<usize>();
|
||||||
if last_selection
|
if last_selection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(true, |last_selection| selection.id > last_selection.id)
|
.map_or(true, |last_selection| selection.id > last_selection.id)
|
||||||
{
|
{
|
||||||
last_selection = Some(selection);
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for selection in editor.selections.all::<Point>(cx) {
|
||||||
self.position = last_selection.map(|s| s.head().to_point(&buffer));
|
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();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,8 @@ impl GoToLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
|
pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
|
||||||
let editor = active_editor.read(cx);
|
let cursor =
|
||||||
let cursor = editor.selections.last::<Point>(cx).head();
|
active_editor.update(cx, |editor, cx| editor.selections.last::<Point>(cx).head());
|
||||||
|
|
||||||
let line = cursor.row + 1;
|
let line = cursor.row + 1;
|
||||||
let column = cursor.column + 1;
|
let column = cursor.column + 1;
|
||||||
|
|
|
@ -128,12 +128,14 @@ impl SyntaxTreeView {
|
||||||
fn editor_updated(&mut self, did_reparse: bool, cx: &mut ViewContext<Self>) -> Option<()> {
|
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.
|
// Find which excerpt the cursor is in, and the position within that excerpted buffer.
|
||||||
let editor_state = self.editor.as_mut()?;
|
let editor_state = self.editor.as_mut()?;
|
||||||
let editor = &editor_state.editor.read(cx);
|
let (buffer, range, excerpt_id) = editor_state.editor.update(cx, |editor, cx| {
|
||||||
let selection_range = editor.selections.last::<usize>(cx).range();
|
let selection_range = editor.selections.last::<usize>(cx).range();
|
||||||
let multibuffer = editor.buffer().read(cx);
|
editor
|
||||||
let (buffer, range, excerpt_id) = multibuffer
|
.buffer()
|
||||||
.range_to_buffer_ranges(selection_range, cx)
|
.read(cx)
|
||||||
.pop()?;
|
.range_to_buffer_ranges(selection_range, cx)
|
||||||
|
.pop()
|
||||||
|
})?;
|
||||||
|
|
||||||
// If the cursor has moved into a different excerpt, retrieve a new syntax layer
|
// If the cursor has moved into a different excerpt, retrieve a new syntax layer
|
||||||
// from that buffer.
|
// from that buffer.
|
||||||
|
|
|
@ -301,8 +301,8 @@ impl MarkdownPreviewView {
|
||||||
this.parse_markdown_from_active_editor(true, cx);
|
this.parse_markdown_from_active_editor(true, cx);
|
||||||
}
|
}
|
||||||
EditorEvent::SelectionsChanged { .. } => {
|
EditorEvent::SelectionsChanged { .. } => {
|
||||||
let editor = editor.read(cx);
|
let selection_range =
|
||||||
let selection_range = editor.selections.last::<usize>(cx).range();
|
editor.update(cx, |editor, cx| editor.selections.last::<usize>(cx).range());
|
||||||
this.selected_block = this.get_block_index_under_cursor(selection_range);
|
this.selected_block = this.get_block_index_under_cursor(selection_range);
|
||||||
this.list_state.scroll_to_reveal_item(this.selected_block);
|
this.list_state.scroll_to_reveal_item(this.selected_block);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
|
@ -194,9 +194,11 @@ impl PickerDelegate for OutlineViewDelegate {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let editor = self.active_editor.read(cx);
|
let (buffer, cursor_offset) = self.active_editor.update(cx, |editor, cx| {
|
||||||
let cursor_offset = editor.selections.newest::<usize>(cx).head();
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
let cursor_offset = editor.selections.newest::<usize>(cx).head();
|
||||||
|
(buffer, cursor_offset)
|
||||||
|
});
|
||||||
selected_index = self
|
selected_index = self
|
||||||
.outline
|
.outline
|
||||||
.items
|
.items
|
||||||
|
|
|
@ -2410,11 +2410,9 @@ impl OutlinePanel {
|
||||||
editor: &View<Editor>,
|
editor: &View<Editor>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<PanelEntry> {
|
) -> Option<PanelEntry> {
|
||||||
let selection = editor
|
let selection = editor.update(cx, |editor, cx| {
|
||||||
.read(cx)
|
editor.selections.newest::<language::Point>(cx).head()
|
||||||
.selections
|
});
|
||||||
.newest::<language::Point>(cx)
|
|
||||||
.head();
|
|
||||||
let editor_snapshot = editor.update(cx, |editor, cx| editor.snapshot(cx));
|
let editor_snapshot = editor.update(cx, |editor, cx| editor.snapshot(cx));
|
||||||
let multi_buffer = editor.read(cx).buffer();
|
let multi_buffer = editor.read(cx).buffer();
|
||||||
let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
|
let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use editor::Editor;
|
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 language::{BufferSnapshot, Language, LanguageName, Point};
|
||||||
|
|
||||||
use crate::repl_store::ReplStore;
|
use crate::repl_store::ReplStore;
|
||||||
|
@ -103,7 +103,7 @@ pub enum SessionSupport {
|
||||||
Unsupported,
|
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 store = ReplStore::global(cx);
|
||||||
let entity_id = editor.entity_id();
|
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>> {
|
fn get_language(editor: WeakView<Editor>, cx: &mut WindowContext) -> Option<Arc<Language>> {
|
||||||
let editor = editor.upgrade()?;
|
editor
|
||||||
let selection = editor.read(cx).selections.newest::<usize>(cx);
|
.update(cx, |editor, cx| {
|
||||||
let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
|
let selection = editor.selections.newest::<usize>(cx);
|
||||||
buffer.language_at(selection.head()).cloned()
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
|
buffer.language_at(selection.head()).cloned()
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use gpui::Context;
|
use gpui::{AppContext, Context};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use language::{Buffer, Language, LanguageConfig, LanguageRegistry};
|
use language::{Buffer, Language, LanguageConfig, LanguageRegistry};
|
||||||
|
|
||||||
|
|
|
@ -281,7 +281,7 @@ impl VimGlobals {
|
||||||
&mut self,
|
&mut self,
|
||||||
register: Option<char>,
|
register: Option<char>,
|
||||||
editor: Option<&mut Editor>,
|
editor: Option<&mut Editor>,
|
||||||
cx: &ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Option<Register> {
|
) -> Option<Register> {
|
||||||
let Some(register) = register.filter(|reg| *reg != '"') else {
|
let Some(register) = register.filter(|reg| *reg != '"') else {
|
||||||
let setting = VimSettings::get_global(cx).use_system_clipboard;
|
let setting = VimSettings::get_global(cx).use_system_clipboard;
|
||||||
|
|
|
@ -620,9 +620,11 @@ impl Vim {
|
||||||
let Some(editor) = self.editor() else {
|
let Some(editor) = self.editor() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let newest_selection_empty = editor.update(cx, |editor, cx| {
|
||||||
|
editor.selections.newest::<usize>(cx).is_empty()
|
||||||
|
});
|
||||||
let editor = editor.read(cx);
|
let editor = editor.read(cx);
|
||||||
let editor_mode = editor.mode();
|
let editor_mode = editor.mode();
|
||||||
let newest_selection_empty = editor.selections.newest::<usize>(cx).is_empty();
|
|
||||||
|
|
||||||
if editor_mode == EditorMode::Full
|
if editor_mode == EditorMode::Full
|
||||||
&& !newest_selection_empty
|
&& !newest_selection_empty
|
||||||
|
@ -717,11 +719,12 @@ impl Vim {
|
||||||
globals.recorded_count = None;
|
globals.recorded_count = None;
|
||||||
|
|
||||||
let selections = self.editor().map(|editor| {
|
let selections = self.editor().map(|editor| {
|
||||||
let editor = editor.read(cx);
|
editor.update(cx, |editor, cx| {
|
||||||
(
|
(
|
||||||
editor.selections.oldest::<Point>(cx),
|
editor.selections.oldest::<Point>(cx),
|
||||||
editor.selections.newest::<Point>(cx),
|
editor.selections.newest::<Point>(cx),
|
||||||
)
|
)
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some((oldest, newest)) = selections {
|
if let Some((oldest, newest)) = selections {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue