Detailed changes
@@ -13,7 +13,7 @@ use collections::{HashMap, HashSet};
use editor::{
Addon, Anchor, AnchorRangeExt, ContextMenuOptions, ContextMenuPlacement, Editor, EditorElement,
EditorEvent, EditorMode, EditorSnapshot, EditorStyle, ExcerptId, FoldPlaceholder, Inlay,
- MultiBuffer, ToOffset,
+ MultiBuffer, MultiBufferOffset, ToOffset,
actions::Paste,
code_context_menus::CodeContextMenu,
display_map::{Crease, CreaseId, FoldId},
@@ -209,7 +209,7 @@ impl MessageEditor {
let acp::AvailableCommandInput::Unstructured { mut hint } =
available_command.input.clone()?;
- let mut hint_pos = parsed_command.source_range.end + 1;
+ let mut hint_pos = MultiBufferOffset(parsed_command.source_range.end) + 1usize;
if hint_pos > snapshot.len() {
hint_pos = snapshot.len();
hint.insert(0, ' ');
@@ -307,9 +307,9 @@ impl MessageEditor {
return Task::ready(());
};
let excerpt_id = start_anchor.excerpt_id;
- let end_anchor = snapshot
- .buffer_snapshot()
- .anchor_before(start_anchor.to_offset(&snapshot.buffer_snapshot()) + content_len + 1);
+ let end_anchor = snapshot.buffer_snapshot().anchor_before(
+ start_anchor.to_offset(&snapshot.buffer_snapshot()) + content_len + 1usize,
+ );
let crease = if let MentionUri::File { abs_path } = &mention_uri
&& let Some(extension) = abs_path.extension()
@@ -739,8 +739,8 @@ impl MessageEditor {
};
let crease_range = crease.range().to_offset(&snapshot.buffer_snapshot());
- if crease_range.start > ix {
- let chunk = text[ix..crease_range.start].into();
+ if crease_range.start.0 > ix {
+ let chunk = text[ix..crease_range.start.0].into();
chunks.push(chunk);
}
let chunk = match mention {
@@ -808,7 +808,7 @@ impl MessageEditor {
}),
};
chunks.push(chunk);
- ix = crease_range.end;
+ ix = crease_range.end.0;
}
if ix < text.len() {
@@ -862,7 +862,7 @@ impl MessageEditor {
let snapshot = editor.display_snapshot(cx);
let cursor = editor.selections.newest::<text::Point>(&snapshot).head();
let offset = cursor.to_offset(&snapshot);
- if offset > 0 {
+ if offset.0 > 0 {
snapshot
.buffer_snapshot()
.reversed_chars_at(offset)
@@ -1132,7 +1132,7 @@ impl MessageEditor {
let cursor_anchor = editor.selections.newest_anchor().head();
let cursor_offset = cursor_anchor.to_offset(&editor_buffer.snapshot(cx));
let anchor = buffer.update(cx, |buffer, _cx| {
- buffer.anchor_before(cursor_offset.min(buffer.len()))
+ buffer.anchor_before(cursor_offset.0.min(buffer.len()))
});
let Some(workspace) = self.workspace.upgrade() else {
return;
@@ -1258,7 +1258,7 @@ impl MessageEditor {
});
for (range, mention_uri, mention) in mentions {
- let anchor = snapshot.anchor_before(range.start);
+ let anchor = snapshot.anchor_before(MultiBufferOffset(range.start));
let Some((crease_id, tx)) = insert_crease_for_mention(
anchor.excerpt_id,
anchor.text_anchor,
@@ -1713,7 +1713,7 @@ mod tests {
use agent::{HistoryStore, outline};
use agent_client_protocol as acp;
use assistant_text_thread::TextThreadStore;
- use editor::{AnchorRangeExt as _, Editor, EditorMode};
+ use editor::{AnchorRangeExt as _, Editor, EditorMode, MultiBufferOffset};
use fs::FakeFs;
use futures::StreamExt as _;
use gpui::{
@@ -2682,7 +2682,7 @@ mod tests {
editor.display_map.update(cx, |display_map, cx| {
display_map
.snapshot(cx)
- .folds_in_range(0..snapshot.len())
+ .folds_in_range(MultiBufferOffset(0)..snapshot.len())
.map(|fold| fold.range.to_point(&snapshot))
.collect()
})
@@ -6066,6 +6066,7 @@ pub(crate) mod tests {
use acp_thread::StubAgentConnection;
use agent_client_protocol::SessionId;
use assistant_text_thread::TextThreadStore;
+ use editor::MultiBufferOffset;
use fs::FakeFs;
use gpui::{EventEmitter, SemanticVersion, TestAppContext, VisualTestContext};
use project::Project;
@@ -7234,7 +7235,7 @@ pub(crate) mod tests {
Editor::for_buffer(buffer.clone(), Some(project.clone()), window, cx);
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges([8..15]);
+ selections.select_ranges([MultiBufferOffset(8)..MultiBufferOffset(15)]);
});
editor
@@ -7296,7 +7297,7 @@ pub(crate) mod tests {
Editor::for_buffer(buffer.clone(), Some(project.clone()), window, cx);
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges([8..15]);
+ selections.select_ranges([MultiBufferOffset(8)..MultiBufferOffset(15)]);
});
editor
@@ -12,7 +12,7 @@ use client::zed_urls;
use cloud_llm_client::{Plan, PlanV1, PlanV2};
use collections::HashMap;
use context_server::ContextServerId;
-use editor::{Editor, SelectionEffects, scroll::Autoscroll};
+use editor::{Editor, MultiBufferOffset, SelectionEffects, scroll::Autoscroll};
use extension::ExtensionManifest;
use extension_host::ExtensionStore;
use fs::Fs;
@@ -1362,7 +1362,15 @@ async fn open_new_agent_servers_entry_in_settings_editor(
.map(|(range, _)| range.clone())
.collect::<Vec<_>>();
- item.edit(edits, cx);
+ item.edit(
+ edits.into_iter().map(|(range, s)| {
+ (
+ MultiBufferOffset(range.start)..MultiBufferOffset(range.end),
+ s,
+ )
+ }),
+ cx,
+ );
if let Some((unique_server_name, buffer)) =
unique_server_name.zip(item.buffer().read(cx).as_singleton())
{
@@ -1375,7 +1383,9 @@ async fn open_new_agent_servers_entry_in_settings_editor(
window,
cx,
|selections| {
- selections.select_ranges(vec![range]);
+ selections.select_ranges(vec![
+ MultiBufferOffset(range.start)..MultiBufferOffset(range.end),
+ ]);
},
);
}
@@ -429,7 +429,12 @@ impl CodegenAlternative {
let prompt = self
.builder
- .generate_inline_transformation_prompt(user_prompt, language_name, buffer, range)
+ .generate_inline_transformation_prompt(
+ user_prompt,
+ language_name,
+ buffer,
+ range.start.0..range.end.0,
+ )
.context("generating content prompt")?;
let context_task = self.context_store.as_ref().and_then(|context_store| {
@@ -1082,7 +1082,7 @@ impl MentionCompletion {
#[cfg(test)]
mod tests {
use super::*;
- use editor::AnchorRangeExt;
+ use editor::{AnchorRangeExt, MultiBufferOffset};
use gpui::{EventEmitter, FocusHandle, Focusable, TestAppContext, VisualTestContext};
use project::{Project, ProjectPath};
use serde_json::json;
@@ -1677,7 +1677,7 @@ mod tests {
editor.display_map.update(cx, |display_map, cx| {
display_map
.snapshot(cx)
- .folds_in_range(0..snapshot.len())
+ .folds_in_range(MultiBufferOffset(0)..snapshot.len())
.map(|fold| fold.range.to_point(&snapshot))
.collect()
})
@@ -16,6 +16,7 @@ use agent_settings::AgentSettings;
use anyhow::{Context as _, Result};
use client::telemetry::Telemetry;
use collections::{HashMap, HashSet, VecDeque, hash_map};
+use editor::MultiBufferOffset;
use editor::RowExt;
use editor::SelectionEffects;
use editor::scroll::ScrollOffset;
@@ -803,7 +804,7 @@ impl InlineAssistant {
(
editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx)),
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx)),
editor.buffer().read(cx).snapshot(cx),
)
});
@@ -836,7 +837,7 @@ impl InlineAssistant {
(
editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx)),
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx)),
editor.buffer().read(cx).snapshot(cx),
)
});
@@ -853,12 +854,14 @@ impl InlineAssistant {
} else {
let distance_from_selection = assist_range
.start
- .abs_diff(selection.start)
- .min(assist_range.start.abs_diff(selection.end))
+ .0
+ .abs_diff(selection.start.0)
+ .min(assist_range.start.0.abs_diff(selection.end.0))
+ assist_range
.end
- .abs_diff(selection.start)
- .min(assist_range.end.abs_diff(selection.end));
+ .0
+ .abs_diff(selection.start.0)
+ .min(assist_range.end.0.abs_diff(selection.end.0));
match closest_assist_fallback {
Some((_, old_distance)) => {
if distance_from_selection < old_distance {
@@ -935,7 +938,7 @@ impl InlineAssistant {
EditorEvent::Edited { transaction_id } => {
let buffer = editor.read(cx).buffer().read(cx);
let edited_ranges =
- buffer.edited_ranges_for_transaction::<usize>(*transaction_id, cx);
+ buffer.edited_ranges_for_transaction::<MultiBufferOffset>(*transaction_id, cx);
let snapshot = buffer.snapshot(cx);
for assist_id in editor_assists.assist_ids.clone() {
@@ -2,7 +2,7 @@ use agent::HistoryStore;
use collections::{HashMap, VecDeque};
use editor::actions::Paste;
use editor::display_map::{CreaseId, EditorMargins};
-use editor::{Addon, AnchorRangeExt as _};
+use editor::{Addon, AnchorRangeExt as _, MultiBufferOffset};
use editor::{
ContextMenuOptions, Editor, EditorElement, EditorEvent, EditorMode, EditorStyle, MultiBuffer,
actions::{MoveDown, MoveUp},
@@ -1165,7 +1165,7 @@ impl GenerationMode {
/// Stored information that can be used to resurrect a context crease when creating an editor for a past message.
#[derive(Clone, Debug)]
pub struct MessageCrease {
- pub range: Range<usize>,
+ pub range: Range<MultiBufferOffset>,
pub icon_path: SharedString,
pub label: SharedString,
/// None for a deserialized message, Some otherwise.
@@ -9,8 +9,8 @@ use assistant_slash_commands::{DefaultSlashCommand, FileSlashCommand, selections
use client::{proto, zed_urls};
use collections::{BTreeSet, HashMap, HashSet, hash_map};
use editor::{
- Anchor, Editor, EditorEvent, MenuEditPredictionsPolicy, MultiBuffer, MultiBufferSnapshot,
- RowExt, ToOffset as _, ToPoint,
+ Anchor, Editor, EditorEvent, MenuEditPredictionsPolicy, MultiBuffer, MultiBufferOffset,
+ MultiBufferSnapshot, RowExt, ToOffset as _, ToPoint,
actions::{MoveToEndOfLine, Newline, ShowCompletions},
display_map::{
BlockPlacement, BlockProperties, BlockStyle, Crease, CreaseMetadata, CustomBlockId, FoldId,
@@ -390,7 +390,7 @@ impl TextThreadEditor {
let cursor = user_message
.start
.to_offset(self.text_thread.read(cx).buffer().read(cx));
- cursor..cursor
+ MultiBufferOffset(cursor)..MultiBufferOffset(cursor)
};
self.editor.update(cx, |editor, cx| {
editor.change_selections(Default::default(), window, cx, |selections| {
@@ -431,7 +431,7 @@ impl TextThreadEditor {
let cursors = self.cursors(cx);
self.text_thread.update(cx, |text_thread, cx| {
let messages = text_thread
- .messages_for_offsets(cursors, cx)
+ .messages_for_offsets(cursors.into_iter().map(|cursor| cursor.0), cx)
.into_iter()
.map(|message| message.id)
.collect();
@@ -439,9 +439,11 @@ impl TextThreadEditor {
});
}
- fn cursors(&self, cx: &mut App) -> Vec<usize> {
+ fn cursors(&self, cx: &mut App) -> Vec<MultiBufferOffset> {
let selections = self.editor.update(cx, |editor, cx| {
- editor.selections.all::<usize>(&editor.display_snapshot(cx))
+ editor
+ .selections
+ .all::<MultiBufferOffset>(&editor.display_snapshot(cx))
});
selections
.into_iter()
@@ -1580,7 +1582,11 @@ impl TextThreadEditor {
fn get_clipboard_contents(
&mut self,
cx: &mut Context<Self>,
- ) -> (String, CopyMetadata, Vec<text::Selection<usize>>) {
+ ) -> (
+ String,
+ CopyMetadata,
+ Vec<text::Selection<MultiBufferOffset>>,
+ ) {
let (mut selection, creases) = self.editor.update(cx, |editor, cx| {
let mut selection = editor
.selections
@@ -1638,30 +1644,26 @@ impl TextThreadEditor {
// If selection is empty, we want to copy the entire line
if selection.range().is_empty() {
- let snapshot = text_thread.buffer().read(cx).snapshot();
+ let snapshot = self.editor.read(cx).buffer().read(cx).snapshot(cx);
let point = snapshot.offset_to_point(selection.range().start);
selection.start = snapshot.point_to_offset(Point::new(point.row, 0));
selection.end = snapshot
.point_to_offset(cmp::min(Point::new(point.row + 1, 0), snapshot.max_point()));
- for chunk in text_thread
- .buffer()
- .read(cx)
- .text_for_range(selection.range())
- {
+ for chunk in snapshot.text_for_range(selection.range()) {
text.push_str(chunk);
}
} else {
for message in text_thread.messages(cx) {
- if message.offset_range.start >= selection.range().end {
+ if message.offset_range.start >= selection.range().end.0 {
break;
- } else if message.offset_range.end >= selection.range().start {
- let range = cmp::max(message.offset_range.start, selection.range().start)
- ..cmp::min(message.offset_range.end, selection.range().end);
+ } else if message.offset_range.end >= selection.range().start.0 {
+ let range = cmp::max(message.offset_range.start, selection.range().start.0)
+ ..cmp::min(message.offset_range.end, selection.range().end.0);
if !range.is_empty() {
for chunk in text_thread.buffer().read(cx).text_for_range(range) {
text.push_str(chunk);
}
- if message.offset_range.end < selection.range().end {
+ if message.offset_range.end < selection.range().end.0 {
text.push('\n');
}
}
@@ -1743,7 +1745,7 @@ impl TextThreadEditor {
self.editor.update(cx, |editor, cx| {
let paste_position = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
.head();
editor.paste(action, window, cx);
@@ -1791,13 +1793,16 @@ impl TextThreadEditor {
editor.transact(window, cx, |editor, _window, cx| {
let edits = editor
.selections
- .all::<usize>(&editor.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&editor.display_snapshot(cx))
.into_iter()
.map(|selection| (selection.start..selection.end, "\n"));
editor.edit(edits, cx);
let snapshot = editor.buffer().read(cx).snapshot(cx);
- for selection in editor.selections.all::<usize>(&editor.display_snapshot(cx)) {
+ for selection in editor
+ .selections
+ .all::<MultiBufferOffset>(&editor.display_snapshot(cx))
+ {
image_positions.push(snapshot.anchor_before(selection.end));
}
});
@@ -1889,7 +1894,7 @@ impl TextThreadEditor {
let range = selection
.map(|endpoint| endpoint.to_offset(&buffer))
.range();
- text_thread.split_message(range, cx);
+ text_thread.split_message(range.start.0..range.end.0, cx);
}
});
}
@@ -2963,7 +2968,7 @@ pub fn make_lsp_adapter_delegate(
#[cfg(test)]
mod tests {
use super::*;
- use editor::SelectionEffects;
+ use editor::{MultiBufferOffset, SelectionEffects};
use fs::FakeFs;
use gpui::{App, TestAppContext, VisualTestContext};
use indoc::indoc;
@@ -3169,15 +3174,16 @@ mod tests {
text_thread: &Entity<TextThread>,
message_ix: usize,
cx: &mut TestAppContext,
- ) -> Range<usize> {
- text_thread.update(cx, |text_thread, cx| {
+ ) -> Range<MultiBufferOffset> {
+ let range = text_thread.update(cx, |text_thread, cx| {
text_thread
.messages(cx)
.nth(message_ix)
.unwrap()
.anchor_range
.to_offset(&text_thread.buffer().read(cx).snapshot())
- })
+ });
+ MultiBufferOffset(range.start)..MultiBufferOffset(range.end)
}
fn assert_copy_paste_text_thread_editor<T: editor::ToOffset>(
@@ -667,7 +667,7 @@ pub struct TextThread {
buffer: Entity<Buffer>,
pub(crate) parsed_slash_commands: Vec<ParsedSlashCommand>,
invoked_slash_commands: HashMap<InvokedSlashCommandId, InvokedSlashCommand>,
- edits_since_last_parse: language::Subscription,
+ edits_since_last_parse: language::Subscription<usize>,
slash_commands: Arc<SlashCommandWorkingSet>,
pub(crate) slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>,
thought_process_output_sections: Vec<ThoughtProcessOutputSection<language::Anchor>>,
@@ -7,7 +7,7 @@ use channel::ACKNOWLEDGE_DEBOUNCE_INTERVAL;
use client::{Collaborator, ParticipantIndex, UserId};
use collab_ui::channel_view::ChannelView;
use collections::HashMap;
-use editor::{Anchor, Editor, ToOffset};
+use editor::{Anchor, Editor, MultiBufferOffset, ToOffset};
use futures::future;
use gpui::{BackgroundExecutor, Context, Entity, TestAppContext, Window};
use rpc::{RECEIVE_TIMEOUT, proto::PeerId};
@@ -180,7 +180,7 @@ async fn test_channel_notes_participant_indices(
notes.editor.update(cx, |editor, cx| {
editor.insert("a", window, cx);
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges(vec![0..1]);
+ selections.select_ranges(vec![MultiBufferOffset(0)..MultiBufferOffset(1)]);
});
});
});
@@ -190,7 +190,7 @@ async fn test_channel_notes_participant_indices(
editor.move_down(&Default::default(), window, cx);
editor.insert("b", window, cx);
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges(vec![1..2]);
+ selections.select_ranges(vec![MultiBufferOffset(1)..MultiBufferOffset(2)]);
});
});
});
@@ -200,7 +200,7 @@ async fn test_channel_notes_participant_indices(
editor.move_down(&Default::default(), window, cx);
editor.insert("c", window, cx);
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges(vec![2..3]);
+ selections.select_ranges(vec![MultiBufferOffset(2)..MultiBufferOffset(3)]);
});
});
});
@@ -287,12 +287,12 @@ async fn test_channel_notes_participant_indices(
editor_a.update_in(cx_a, |editor, window, cx| {
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges(vec![0..1]);
+ selections.select_ranges(vec![MultiBufferOffset(0)..MultiBufferOffset(1)]);
});
});
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(Default::default(), window, cx, |selections| {
- selections.select_ranges(vec![2..3]);
+ selections.select_ranges(vec![MultiBufferOffset(2)..MultiBufferOffset(3)]);
});
});
executor.run_until_parked();
@@ -327,7 +327,7 @@ fn assert_remote_selections(
let end = s.selection.end.to_offset(snapshot.buffer_snapshot());
let user_id = collaborators.get(&peer_id).unwrap().user_id;
let participant_index = hub.user_participant_indices(cx).get(&user_id).copied();
- (participant_index, start..end)
+ (participant_index, start.0..end.0)
})
.collect::<Vec<_>>();
assert_eq!(
@@ -4,7 +4,8 @@ use crate::{
};
use call::ActiveCall;
use editor::{
- DocumentColorsRenderMode, Editor, FETCH_COLORS_DEBOUNCE_TIMEOUT, RowInfo, SelectionEffects,
+ DocumentColorsRenderMode, Editor, FETCH_COLORS_DEBOUNCE_TIMEOUT, MultiBufferOffset, RowInfo,
+ SelectionEffects,
actions::{
ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst,
ExpandMacroRecursively, MoveToEnd, Redo, Rename, SelectAll, ToggleCodeActions, Undo,
@@ -381,7 +382,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
// Type a completion trigger character as the guest.
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input(".", window, cx);
});
@@ -503,7 +504,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
// resolved
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([46..46])
+ s.select_ranges([MultiBufferOffset(46)..MultiBufferOffset(46)])
});
editor.handle_input("; a", window, cx);
editor.handle_input(".", window, cx);
@@ -601,7 +602,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
// Add another completion trigger to test the second language server
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([68..68])
+ s.select_ranges([MultiBufferOffset(68)..MultiBufferOffset(68)])
});
editor.handle_input("; b", window, cx);
editor.handle_input(".", window, cx);
@@ -950,7 +951,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
// Move cursor to a location that can be renamed.
let prepare_rename = editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([7..7])
+ s.select_ranges([MultiBufferOffset(7)..MultiBufferOffset(7)])
});
editor.rename(&Rename, window, cx).unwrap()
});
@@ -977,17 +978,17 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
let buffer = editor.buffer().read(cx).snapshot(cx);
assert_eq!(
rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
- 6..9
+ MultiBufferOffset(6)..MultiBufferOffset(9)
);
rename.editor.update(cx, |rename_editor, cx| {
- let rename_selection = rename_editor.selections.newest::<usize>(&rename_editor.display_snapshot(cx));
+ let rename_selection = rename_editor.selections.newest::<MultiBufferOffset>(&rename_editor.display_snapshot(cx));
assert_eq!(
rename_selection.range(),
- 0..3,
+ MultiBufferOffset(0)..MultiBufferOffset(3),
"Rename that was triggered from zero selection caret, should propose the whole word."
);
rename_editor.buffer().update(cx, |rename_buffer, cx| {
- rename_buffer.edit([(0..3, "THREE")], None, cx);
+ rename_buffer.edit([(MultiBufferOffset(0)..MultiBufferOffset(3), "THREE")], None, cx);
});
});
});
@@ -998,7 +999,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
});
let prepare_rename = editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([7..8])
+ s.select_ranges([MultiBufferOffset(7)..MultiBufferOffset(8)])
});
editor.rename(&Rename, window, cx).unwrap()
});
@@ -1025,16 +1026,16 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
let buffer = editor.buffer().read(cx).snapshot(cx);
let lsp_rename_start = rename.range.start.to_offset(&buffer);
let lsp_rename_end = rename.range.end.to_offset(&buffer);
- assert_eq!(lsp_rename_start..lsp_rename_end, 6..9);
+ assert_eq!(lsp_rename_start..lsp_rename_end, MultiBufferOffset(6)..MultiBufferOffset(9));
rename.editor.update(cx, |rename_editor, cx| {
- let rename_selection = rename_editor.selections.newest::<usize>(&rename_editor.display_snapshot(cx));
+ let rename_selection = rename_editor.selections.newest::<MultiBufferOffset>(&rename_editor.display_snapshot(cx));
assert_eq!(
rename_selection.range(),
- 1..2,
+ MultiBufferOffset(1)..MultiBufferOffset(2),
"Rename that was triggered from a selection, should have the same selection range in the rename proposal"
);
rename_editor.buffer().update(cx, |rename_buffer, cx| {
- rename_buffer.edit([(0..lsp_rename_end - lsp_rename_start, "THREE")], None, cx);
+ rename_buffer.edit([(MultiBufferOffset(0)..MultiBufferOffset(lsp_rename_end - lsp_rename_start), "THREE")], None, cx);
});
});
});
@@ -1237,7 +1238,7 @@ async fn test_slow_lsp_server(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte
// Move cursor to a location, this should trigger the code lens call.
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([7..7])
+ s.select_ranges([MultiBufferOffset(7)..MultiBufferOffset(7)])
});
});
let () = request_started_rx.next().await.unwrap();
@@ -1259,7 +1260,7 @@ async fn test_slow_lsp_server(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1])
+ s.select_ranges([MultiBufferOffset(1)..MultiBufferOffset(1)])
});
});
let () = request_started_rx.next().await.unwrap();
@@ -1281,7 +1282,7 @@ async fn test_slow_lsp_server(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([2..2])
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(2)])
});
});
let () = request_started_rx.next().await.unwrap();
@@ -1719,7 +1720,7 @@ async fn test_on_input_format_from_host_to_guest(
cx_a.focus(&editor_a);
editor_a.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input(">", window, cx);
});
@@ -1828,7 +1829,7 @@ async fn test_on_input_format_from_guest_to_host(
cx_b.focus(&editor_b);
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input(":", window, cx);
});
@@ -2056,7 +2057,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
let after_client_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
editor_b.update_in(cx_b, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13].clone())
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)].clone())
});
editor.handle_input(":", window, cx);
});
@@ -2080,7 +2081,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
let after_host_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
editor_a.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input("a change to increment both buffers' versions", window, cx);
});
@@ -2520,7 +2521,7 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
editor_a.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13].clone())
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)].clone())
});
editor.handle_input(":", window, cx);
});
@@ -2957,7 +2958,7 @@ async fn test_lsp_pull_diagnostics(
editor_a_main.update(cx_a, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
assert_eq!(
all_diagnostics.len(),
@@ -3086,7 +3087,7 @@ async fn test_lsp_pull_diagnostics(
editor_a_main.update(cx_a, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
assert_eq!(
all_diagnostics.len(),
@@ -3133,7 +3134,7 @@ async fn test_lsp_pull_diagnostics(
editor_b_main.update(cx_b, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
assert_eq!(
all_diagnostics.len(),
@@ -3180,7 +3181,7 @@ async fn test_lsp_pull_diagnostics(
editor_b_lib.update(cx_b, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
let expected_messages = [
expected_pull_diagnostic_lib_message,
@@ -3247,7 +3248,7 @@ async fn test_lsp_pull_diagnostics(
editor_b_lib.update(cx_b, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
let expected_messages = [
expected_workspace_pull_diagnostics_lib_message,
@@ -3382,7 +3383,7 @@ async fn test_lsp_pull_diagnostics(
editor_b_lib.update(cx_b, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
let expected_messages = [
expected_workspace_pull_diagnostics_lib_message,
@@ -3400,7 +3401,7 @@ async fn test_lsp_pull_diagnostics(
editor_b_main.update(cx_b, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
assert_eq!(all_diagnostics.len(), 2);
@@ -3419,7 +3420,7 @@ async fn test_lsp_pull_diagnostics(
editor_a_main.update(cx_a, |editor, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let all_diagnostics = snapshot
- .diagnostics_in_range(0..snapshot.len())
+ .diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
.collect::<Vec<_>>();
assert_eq!(all_diagnostics.len(), 2);
let expected_messages = [
@@ -6,7 +6,7 @@ use collab_ui::{
channel_view::ChannelView,
notifications::project_shared_notification::ProjectSharedNotification,
};
-use editor::{Editor, MultiBuffer, PathKey, SelectionEffects};
+use editor::{Editor, MultiBuffer, MultiBufferOffset, PathKey, SelectionEffects};
use gpui::{
AppContext as _, BackgroundExecutor, BorrowAppContext, Entity, SharedString, TestAppContext,
VisualContext, VisualTestContext, point,
@@ -124,7 +124,7 @@ async fn test_basic_following(
editor.select_left(&Default::default(), window, cx);
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![3..2]
+ vec![MultiBufferOffset(3)..MultiBufferOffset(2)]
);
});
editor_a2.update_in(cx_a, |editor, window, cx| {
@@ -133,7 +133,7 @@ async fn test_basic_following(
editor.select_left(&Default::default(), window, cx);
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![2..1]
+ vec![MultiBufferOffset(2)..MultiBufferOffset(1)]
);
});
@@ -158,13 +158,13 @@ async fn test_basic_following(
editor_b2.update(cx_b, |editor, cx| editor
.selections
.ranges(&editor.display_snapshot(cx))),
- vec![2..1]
+ vec![MultiBufferOffset(2)..MultiBufferOffset(1)]
);
assert_eq!(
editor_b1.update(cx_b, |editor, cx| editor
.selections
.ranges(&editor.display_snapshot(cx))),
- vec![3..3]
+ vec![MultiBufferOffset(3)..MultiBufferOffset(3)]
);
executor.run_until_parked();
@@ -386,7 +386,10 @@ async fn test_basic_following(
// Changes to client A's editor are reflected on client B.
editor_a1.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1, 2..2])
+ s.select_ranges([
+ MultiBufferOffset(1)..MultiBufferOffset(1),
+ MultiBufferOffset(2)..MultiBufferOffset(2),
+ ])
});
});
executor.advance_clock(workspace::item::LEADER_UPDATE_THROTTLE);
@@ -396,7 +399,10 @@ async fn test_basic_following(
editor_b1.update(cx_b, |editor, cx| {
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- &[1..1, 2..2]
+ &[
+ MultiBufferOffset(1)..MultiBufferOffset(1),
+ MultiBufferOffset(2)..MultiBufferOffset(2)
+ ]
);
});
@@ -408,7 +414,7 @@ async fn test_basic_following(
editor_a1.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([3..3])
+ s.select_ranges([MultiBufferOffset(3)..MultiBufferOffset(3)])
});
editor.set_scroll_position(point(0., 100.), window, cx);
});
@@ -417,7 +423,7 @@ async fn test_basic_following(
editor_b1.update(cx_b, |editor, cx| {
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- &[3..3]
+ &[MultiBufferOffset(3)..MultiBufferOffset(3)]
);
});
@@ -1694,7 +1700,7 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T
// b should follow a to position 1
editor_a.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1])
+ s.select_ranges([MultiBufferOffset(1)..MultiBufferOffset(1)])
})
});
cx_a.executor()
@@ -1703,7 +1709,7 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T
editor_b.update(cx_b, |editor, cx| {
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![1..1]
+ vec![MultiBufferOffset(1)..MultiBufferOffset(1)]
)
});
@@ -1719,7 +1725,7 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T
// b should not follow a to position 2
editor_a.update_in(cx_a, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([2..2])
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(2)])
})
});
cx_a.executor()
@@ -1728,7 +1734,7 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T
editor_b.update(cx_b, |editor, cx| {
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![1..1]
+ vec![MultiBufferOffset(1)..MultiBufferOffset(1)]
)
});
cx_b.update(|_, cx| {
@@ -1829,7 +1835,7 @@ async fn test_following_into_excluded_file(
editor.select_left(&Default::default(), window, cx);
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![3..2]
+ vec![MultiBufferOffset(3)..MultiBufferOffset(2)]
);
});
editor_for_excluded_a.update_in(cx_a, |editor, window, cx| {
@@ -1838,7 +1844,7 @@ async fn test_following_into_excluded_file(
editor.select_left(&Default::default(), window, cx);
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![18..17]
+ vec![MultiBufferOffset(18)..MultiBufferOffset(17)]
);
});
@@ -1864,7 +1870,7 @@ async fn test_following_into_excluded_file(
editor_for_excluded_b.update(cx_b, |editor, cx| editor
.selections
.ranges(&editor.display_snapshot(cx))),
- vec![18..17]
+ vec![MultiBufferOffset(18)..MultiBufferOffset(17)]
);
editor_for_excluded_a.update_in(cx_a, |editor, window, cx| {
@@ -2040,7 +2046,7 @@ async fn test_following_to_channel_notes_without_a_shared_project(
notes.editor.update(cx, |editor, cx| {
editor.insert("Hello from A.", window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
- selections.select_ranges(vec![3..4]);
+ selections.select_ranges(vec![MultiBufferOffset(3)..MultiBufferOffset(4)]);
});
});
});
@@ -2076,8 +2082,8 @@ async fn test_following_to_channel_notes_without_a_shared_project(
assert_eq!(
editor
.selections
- .ranges::<usize>(&editor.display_snapshot(cx)),
- &[3..4]
+ .ranges::<MultiBufferOffset>(&editor.display_snapshot(cx)),
+ &[MultiBufferOffset(3)..MultiBufferOffset(4)]
);
})
});
@@ -1496,7 +1496,7 @@ impl CollabPanel {
fn reset_filter_editor_text(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
self.filter_editor.update(cx, |editor, cx| {
- if editor.buffer().read(cx).len(cx) > 0 {
+ if editor.buffer().read(cx).len(cx).0 > 0 {
editor.set_text("", window, cx);
true
} else {
@@ -270,7 +270,7 @@ fn common_prefix<T1: Iterator<Item = char>, T2: Iterator<Item = char>>(a: T1, b:
mod tests {
use super::*;
use editor::{
- Editor, ExcerptRange, MultiBuffer, SelectionEffects,
+ Editor, ExcerptRange, MultiBuffer, MultiBufferOffset, SelectionEffects,
test::editor_lsp_test_context::EditorLspTestContext,
};
use fs::FakeFs;
@@ -1081,8 +1081,9 @@ mod tests {
vec![complete_from_marker, replace_range_marker.clone()],
);
+ let range = marked_ranges.remove(&replace_range_marker).unwrap()[0].clone();
let replace_range =
- cx.to_lsp_range(marked_ranges.remove(&replace_range_marker).unwrap()[0].clone());
+ cx.to_lsp_range(MultiBufferOffset(range.start)..MultiBufferOffset(range.end));
let mut request =
cx.set_request_handler::<lsp::request::Completion, _, _>(move |url, params, _| {
@@ -14,13 +14,12 @@ use collections::IndexMap;
use dap::adapters::DebugAdapterName;
use dap::{DapRegistry, StartDebuggingRequestArguments};
use dap::{client::SessionId, debugger_settings::DebuggerSettings};
-use editor::Editor;
+use editor::{Editor, MultiBufferOffset, ToPoint};
use gpui::{
Action, App, AsyncWindowContext, ClipboardItem, Context, DismissEvent, Entity, EntityId,
EventEmitter, FocusHandle, Focusable, MouseButton, MouseDownEvent, Point, Subscription, Task,
WeakEntity, anchored, deferred,
};
-use text::ToPoint as _;
use itertools::Itertools as _;
use language::Buffer;
@@ -1216,11 +1215,11 @@ impl DebugPanel {
let mut last_offset = None;
while let Some(mat) = matches.next() {
if let Some(pos) = mat.captures.first().map(|m| m.node.byte_range().end) {
- last_offset = Some(pos)
+ last_offset = Some(MultiBufferOffset(pos))
}
}
let mut edits = Vec::new();
- let mut cursor_position = 0;
+ let mut cursor_position = MultiBufferOffset(0);
if let Some(pos) = last_offset {
edits.push((pos..pos, format!(",\n{new_scenario}")));
@@ -1234,24 +1233,25 @@ impl DebugPanel {
if let Some(mat) = matches.next() {
if let Some(pos) = mat.captures.first().map(|m| m.node.byte_range().end - 1) {
- edits.push((pos..pos, format!("\n{new_scenario}\n")));
- cursor_position = pos + "\n ".len();
+ edits.push((
+ MultiBufferOffset(pos)..MultiBufferOffset(pos),
+ format!("\n{new_scenario}\n"),
+ ));
+ cursor_position = MultiBufferOffset(pos) + "\n ".len();
}
} else {
- edits.push((0..0, format!("[\n{}\n]", new_scenario)));
- cursor_position = "[\n ".len();
+ edits.push((
+ MultiBufferOffset(0)..MultiBufferOffset(0),
+ format!("[\n{}\n]", new_scenario),
+ ));
+ cursor_position = MultiBufferOffset("[\n ".len());
}
}
editor.transact(window, cx, |editor, window, cx| {
editor.edit(edits, cx);
- let snapshot = editor
- .buffer()
- .read(cx)
- .as_singleton()
- .unwrap()
- .read(cx)
- .snapshot();
+ let snapshot = editor.buffer().read(cx).read(cx);
let point = cursor_position.to_point(&snapshot);
+ drop(snapshot);
editor.go_to_singleton_buffer_point(point, window, cx);
});
Ok(editor.save(SaveOptions::default(), project, window, cx))
@@ -1,7 +1,7 @@
use std::any::TypeId;
use debugger_panel::DebugPanel;
-use editor::Editor;
+use editor::{Editor, MultiBufferOffsetUtf16};
use gpui::{Action, App, DispatchPhase, EntityInputHandler, actions};
use new_process_modal::{NewProcessModal, NewProcessMode};
use onboarding_modal::DebuggerOnboardingModal;
@@ -390,11 +390,14 @@ pub fn init(cx: &mut App) {
maybe!({
let text = editor
.update(cx, |editor, cx| {
+ let range = editor
+ .selections
+ .newest::<MultiBufferOffsetUtf16>(
+ &editor.display_snapshot(cx),
+ )
+ .range();
editor.text_for_range(
- editor
- .selections
- .newest(&editor.display_snapshot(cx))
- .range(),
+ range.start.0.0..range.end.0.0,
&mut None,
window,
cx,
@@ -8,7 +8,7 @@ use collections::HashMap;
use dap::{CompletionItem, CompletionItemType, OutputEvent};
use editor::{
Bias, CompletionProvider, Editor, EditorElement, EditorMode, EditorStyle, ExcerptId,
- SizingBehavior,
+ MultiBufferOffset, SizingBehavior,
};
use fuzzy::StringMatchCandidate;
use gpui::{
@@ -161,7 +161,9 @@ impl Console {
) -> Task<Result<()>> {
self.console.update(cx, |_, cx| {
cx.spawn_in(window, async move |console, cx| {
- let mut len = console.update(cx, |this, cx| this.buffer().read(cx).len(cx))?;
+ let mut len = console
+ .update(cx, |this, cx| this.buffer().read(cx).len(cx))?
+ .0;
let (output, spans, background_spans) = cx
.background_spawn(async move {
let mut all_spans = Vec::new();
@@ -227,8 +229,8 @@ impl Console {
for (range, color) in spans {
let Some(color) = color else { continue };
let start_offset = range.start;
- let range =
- buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
+ let range = buffer.anchor_after(MultiBufferOffset(range.start))
+ ..buffer.anchor_before(MultiBufferOffset(range.end));
let style = HighlightStyle {
color: Some(terminal_view::terminal_element::convert_color(
&color,
@@ -247,8 +249,8 @@ impl Console {
for (range, color) in background_spans {
let Some(color) = color else { continue };
let start_offset = range.start;
- let range =
- buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
+ let range = buffer.anchor_after(MultiBufferOffset(range.start))
+ ..buffer.anchor_before(MultiBufferOffset(range.end));
console.highlight_background_key::<ConsoleAnsiHighlight>(
start_offset,
&[range],
@@ -961,7 +963,7 @@ fn color_fetcher(color: ansi::Color) -> fn(&Theme) -> Hsla {
mod tests {
use super::*;
use crate::tests::init_test;
- use editor::test::editor_test_context::EditorTestContext;
+ use editor::{MultiBufferOffset, test::editor_test_context::EditorTestContext};
use gpui::TestAppContext;
use language::Point;
@@ -993,8 +995,8 @@ mod tests {
cx.update_editor(|editor, _, cx| {
editor.edit(
vec![(
- snapshot.offset_for_anchor(&replace_range.start)
- ..snapshot.offset_for_anchor(&replace_range.end),
+ MultiBufferOffset(snapshot.offset_for_anchor(&replace_range.start))
+ ..MultiBufferOffset(snapshot.offset_for_anchor(&replace_range.end)),
replacement,
)],
cx,
@@ -1,7 +1,7 @@
use super::*;
use collections::{HashMap, HashSet};
use editor::{
- DisplayPoint, EditorSettings, Inlay,
+ DisplayPoint, EditorSettings, Inlay, MultiBufferOffset,
actions::{GoToDiagnostic, GoToPreviousDiagnostic, Hover, MoveToBeginning},
display_map::DisplayRow,
test::{
@@ -878,7 +878,8 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
diagnostics.editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(window, cx);
if !snapshot.buffer_snapshot().is_empty() {
- let position = rng.random_range(0..snapshot.buffer_snapshot().len());
+ let position = rng
+ .random_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len());
let position = snapshot.buffer_snapshot().clip_offset(position, Bias::Left);
log::info!(
"adding inlay at {position}/{}: {:?}",
@@ -1,6 +1,6 @@
use std::time::Duration;
-use editor::Editor;
+use editor::{Editor, MultiBufferOffset};
use gpui::{
Context, Entity, EventEmitter, IntoElement, ParentElement, Render, Styled, Subscription, Task,
WeakEntity, Window,
@@ -171,14 +171,19 @@ impl DiagnosticIndicator {
let buffer = editor.buffer().read(cx).snapshot(cx);
let cursor_position = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
.head();
(buffer, cursor_position)
});
let new_diagnostic = buffer
- .diagnostics_in_range::<usize>(cursor_position..cursor_position)
+ .diagnostics_in_range::<MultiBufferOffset>(cursor_position..cursor_position)
.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.end - entry.range.start,
+ )
+ })
.map(|entry| entry.diagnostic);
if new_diagnostic != self.current_diagnostic.as_ref() {
let new_diagnostic = new_diagnostic.cloned();
@@ -3,7 +3,9 @@ use client::{Client, UserStore, zed_urls};
use cloud_llm_client::UsageLimit;
use codestral::CodestralCompletionProvider;
use copilot::{Copilot, Status};
-use editor::{Editor, SelectionEffects, actions::ShowEditPrediction, scroll::Autoscroll};
+use editor::{
+ Editor, MultiBufferOffset, SelectionEffects, actions::ShowEditPrediction, scroll::Autoscroll,
+};
use feature_flags::{FeatureFlagAppExt, PredictEditsRateCompletionsFeatureFlag};
use fs::Fs;
use gpui::{
@@ -1107,7 +1109,12 @@ async fn open_disabled_globs_setting_in_editor(
});
if !edits.is_empty() {
- item.edit(edits, cx);
+ item.edit(
+ edits
+ .into_iter()
+ .map(|(r, s)| (MultiBufferOffset(r.start)..MultiBufferOffset(r.end), s)),
+ cx,
+ );
}
let text = item.buffer().read(cx).snapshot(cx).text();
@@ -1122,6 +1129,7 @@ async fn open_disabled_globs_setting_in_editor(
.map(|inner_match| inner_match.start()..inner_match.end())
});
if let Some(range) = range {
+ let range = MultiBufferOffset(range.start)..MultiBufferOffset(range.end);
item.change_selections(
SelectionEffects::scroll(Autoscroll::newest()),
window,
@@ -2,6 +2,7 @@ use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use editor::MultiBuffer;
use gpui::TestDispatcher;
use itertools::Itertools;
+use multi_buffer::MultiBufferOffset;
use rand::{Rng, SeedableRng, rngs::StdRng};
use std::num::NonZeroU32;
use text::Bias;
@@ -24,7 +25,9 @@ fn to_tab_point_benchmark(c: &mut Criterion) {
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
let fold_point = fold_snapshot.to_fold_point(
- inlay_snapshot.to_point(InlayOffset(rng.random_range(0..length))),
+ inlay_snapshot.to_point(InlayOffset(
+ rng.random_range(MultiBufferOffset(0)..MultiBufferOffset(length)),
+ )),
Bias::Left,
);
let (_, snapshot) = TabMap::new(fold_snapshot, NonZeroU32::new(4).unwrap());
@@ -69,7 +72,9 @@ fn to_fold_point_benchmark(c: &mut Criterion) {
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
let fold_point = fold_snapshot.to_fold_point(
- inlay_snapshot.to_point(InlayOffset(rng.random_range(0..length))),
+ inlay_snapshot.to_point(InlayOffset(
+ rng.random_range(MultiBufferOffset(0)..MultiBufferOffset(length)),
+ )),
Bias::Left,
);
@@ -44,12 +44,10 @@ pub use invisibles::{is_invisible, replacement};
use collections::{HashMap, HashSet};
use gpui::{App, Context, Entity, Font, HighlightStyle, LineLayout, Pixels, UnderlineStyle};
-use language::{
- OffsetUtf16, Point, Subscription as BufferSubscription, language_settings::language_settings,
-};
+use language::{Point, Subscription as BufferSubscription, language_settings::language_settings};
use multi_buffer::{
- Anchor, AnchorRangeExt, MultiBuffer, MultiBufferPoint, MultiBufferRow, MultiBufferSnapshot,
- RowInfo, ToOffset, ToPoint,
+ Anchor, AnchorRangeExt, MultiBuffer, MultiBufferOffset, MultiBufferOffsetUtf16,
+ MultiBufferPoint, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset, ToPoint,
};
use project::InlayId;
use project::project_settings::DiagnosticSeverity;
@@ -104,7 +102,7 @@ type InlayHighlights = TreeMap<TypeId, TreeMap<InlayId, (HighlightStyle, InlayHi
pub struct DisplayMap {
/// The buffer that we are displaying.
buffer: Entity<MultiBuffer>,
- buffer_subscription: BufferSubscription,
+ buffer_subscription: BufferSubscription<MultiBufferOffset>,
/// Decides where the [`Inlay`]s should be displayed.
inlay_map: InlayMap,
/// Decides where the fold indicators should be and tracks parts of a source file that are currently folded.
@@ -198,7 +196,7 @@ impl DisplayMap {
pub fn set_state(&mut self, other: &DisplaySnapshot, cx: &mut Context<Self>) {
self.fold(
other
- .folds_in_range(0..other.buffer_snapshot().len())
+ .folds_in_range(MultiBufferOffset(0)..other.buffer_snapshot().len())
.map(|fold| {
Crease::simple(
fold.range.to_offset(other.buffer_snapshot()),
@@ -794,7 +792,7 @@ impl DisplaySnapshot {
}
pub fn is_empty(&self) -> bool {
- self.buffer_snapshot().len() == 0
+ self.buffer_snapshot().len() == MultiBufferOffset(0)
}
pub fn row_infos(&self, start_row: DisplayRow) -> impl Iterator<Item = RowInfo> + '_ {
@@ -1133,7 +1131,10 @@ impl DisplaySnapshot {
})
}
- pub fn buffer_chars_at(&self, mut offset: usize) -> impl Iterator<Item = (char, usize)> + '_ {
+ pub fn buffer_chars_at(
+ &self,
+ mut offset: MultiBufferOffset,
+ ) -> impl Iterator<Item = (char, MultiBufferOffset)> + '_ {
self.buffer_snapshot().chars_at(offset).map(move |ch| {
let ret = (ch, offset);
offset += ch.len_utf8();
@@ -1143,8 +1144,8 @@ impl DisplaySnapshot {
pub fn reverse_buffer_chars_at(
&self,
- mut offset: usize,
- ) -> impl Iterator<Item = (char, usize)> + '_ {
+ mut offset: MultiBufferOffset,
+ ) -> impl Iterator<Item = (char, MultiBufferOffset)> + '_ {
self.buffer_snapshot()
.reversed_chars_at(offset)
.map(move |ch| {
@@ -1526,7 +1527,7 @@ impl DisplayPoint {
map.display_point_to_point(self, Bias::Left)
}
- pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
+ pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> MultiBufferOffset {
let wrap_point = map.block_snapshot.to_wrap_point(self.0, bias);
let tab_point = map.wrap_snapshot().to_tab_point(wrap_point);
let fold_point = map.tab_snapshot().to_fold_point(tab_point, bias).0;
@@ -1536,13 +1537,13 @@ impl DisplayPoint {
}
}
-impl ToDisplayPoint for usize {
+impl ToDisplayPoint for MultiBufferOffset {
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
map.point_to_display_point(self.to_point(map.buffer_snapshot()), Bias::Left)
}
}
-impl ToDisplayPoint for OffsetUtf16 {
+impl ToDisplayPoint for MultiBufferOffsetUtf16 {
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
self.to_offset(map.buffer_snapshot()).to_display_point(map)
}
@@ -1685,7 +1686,7 @@ pub mod tests {
let block_properties = (0..rng.random_range(1..=1))
.map(|_| {
let position = buffer.anchor_after(buffer.clip_offset(
- rng.random_range(0..=buffer.len()),
+ rng.random_range(MultiBufferOffset(0)..=buffer.len()),
Bias::Left,
));
@@ -1727,8 +1728,12 @@ pub mod tests {
for _ in 0..rng.random_range(1..=3) {
buffer.read_with(cx, |buffer, cx| {
let buffer = buffer.read(cx);
- let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
- let start = buffer.clip_offset(rng.random_range(0..=end), Left);
+ let end = buffer.clip_offset(
+ rng.random_range(MultiBufferOffset(0)..=buffer.len()),
+ Right,
+ );
+ let start = buffer
+ .clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
ranges.push(start..end);
});
}
@@ -1954,7 +1959,7 @@ pub mod tests {
)
);
- let ix = snapshot.buffer_snapshot().text().find("seven").unwrap();
+ let ix = MultiBufferOffset(snapshot.buffer_snapshot().text().find("seven").unwrap());
buffer.update(cx, |buffer, cx| {
buffer.edit([(ix..ix, "and ")], None, cx);
});
@@ -2083,7 +2088,7 @@ pub mod tests {
&[],
vec![Inlay::edit_prediction(
0,
- buffer_snapshot.anchor_after(0),
+ buffer_snapshot.anchor_after(MultiBufferOffset(0)),
"\n",
)],
cx,
@@ -2094,7 +2099,11 @@ pub mod tests {
// Regression test: updating the display map does not crash when a
// block is immediately followed by a multi-line inlay.
buffer.update(cx, |buffer, cx| {
- buffer.edit([(1..1, "b")], None, cx);
+ buffer.edit(
+ [(MultiBufferOffset(1)..MultiBufferOffset(1), "b")],
+ None,
+ cx,
+ );
});
map.update(cx, |m, cx| assert_eq!(m.snapshot(cx).text(), "\n\n\nab"));
}
@@ -2694,6 +2703,7 @@ pub mod tests {
HighlightKey::Type(TypeId::of::<MyType>()),
highlighted_ranges
.into_iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
.map(|range| {
buffer_snapshot.anchor_before(range.start)
..buffer_snapshot.anchor_before(range.end)
@@ -11,8 +11,8 @@ use collections::{Bound, HashMap, HashSet};
use gpui::{AnyElement, App, EntityId, Pixels, Window};
use language::{Patch, Point};
use multi_buffer::{
- Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, RowInfo,
- ToOffset, ToPoint as _,
+ Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferOffset, MultiBufferRow,
+ MultiBufferSnapshot, RowInfo, ToOffset, ToPoint as _,
};
use parking_lot::Mutex;
use std::{
@@ -1208,7 +1208,7 @@ impl BlockMapWriter<'_> {
pub fn remove_intersecting_replace_blocks(
&mut self,
- ranges: impl IntoIterator<Item = Range<usize>>,
+ ranges: impl IntoIterator<Item = Range<MultiBufferOffset>>,
inclusive: bool,
) {
let wrap_snapshot = self.0.wrap_snapshot.borrow();
@@ -1283,7 +1283,7 @@ impl BlockMapWriter<'_> {
fn blocks_intersecting_buffer_range(
&self,
- range: Range<usize>,
+ range: Range<MultiBufferOffset>,
inclusive: bool,
) -> &[Arc<CustomBlock>] {
if range.is_empty() && !inclusive {
@@ -3043,8 +3043,10 @@ mod tests {
let block_properties = (0..block_count)
.map(|_| {
let buffer = cx.update(|cx| buffer.read(cx).read(cx).clone());
- let offset =
- buffer.clip_offset(rng.random_range(0..=buffer.len()), Bias::Left);
+ let offset = buffer.clip_offset(
+ rng.random_range(MultiBufferOffset(0)..=buffer.len()),
+ Bias::Left,
+ );
let mut min_height = 0;
let placement = match rng.random_range(0..3) {
0 => {
@@ -3244,7 +3246,7 @@ mod tests {
// Note that this needs to be synced with the related section in BlockMap::sync
expected_blocks.extend(block_map.header_and_footer_blocks(
&buffer_snapshot,
- 0..,
+ MultiBufferOffset(0)..,
&wraps_snapshot,
));
@@ -1,7 +1,7 @@
use collections::BTreeMap;
use gpui::HighlightStyle;
use language::Chunk;
-use multi_buffer::{MultiBufferChunks, MultiBufferSnapshot, ToOffset as _};
+use multi_buffer::{MultiBufferChunks, MultiBufferOffset, MultiBufferSnapshot, ToOffset as _};
use std::{
cmp,
iter::{self, Peekable},
@@ -14,7 +14,7 @@ use crate::display_map::{HighlightKey, TextHighlights};
pub struct CustomHighlightsChunks<'a> {
buffer_chunks: MultiBufferChunks<'a>,
buffer_chunk: Option<Chunk<'a>>,
- offset: usize,
+ offset: MultiBufferOffset,
multibuffer_snapshot: &'a MultiBufferSnapshot,
highlight_endpoints: Peekable<vec::IntoIter<HighlightEndpoint>>,
@@ -24,14 +24,14 @@ pub struct CustomHighlightsChunks<'a> {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct HighlightEndpoint {
- offset: usize,
+ offset: MultiBufferOffset,
tag: HighlightKey,
style: Option<HighlightStyle>,
}
impl<'a> CustomHighlightsChunks<'a> {
pub fn new(
- range: Range<usize>,
+ range: Range<MultiBufferOffset>,
language_aware: bool,
text_highlights: Option<&'a TextHighlights>,
multibuffer_snapshot: &'a MultiBufferSnapshot,
@@ -52,7 +52,7 @@ impl<'a> CustomHighlightsChunks<'a> {
}
}
- pub fn seek(&mut self, new_range: Range<usize>) {
+ pub fn seek(&mut self, new_range: Range<MultiBufferOffset>) {
self.highlight_endpoints =
create_highlight_endpoints(&new_range, self.text_highlights, self.multibuffer_snapshot);
self.offset = new_range.start;
@@ -63,7 +63,7 @@ impl<'a> CustomHighlightsChunks<'a> {
}
fn create_highlight_endpoints(
- range: &Range<usize>,
+ range: &Range<MultiBufferOffset>,
text_highlights: Option<&TextHighlights>,
buffer: &MultiBufferSnapshot,
) -> iter::Peekable<vec::IntoIter<HighlightEndpoint>> {
@@ -117,7 +117,7 @@ impl<'a> Iterator for CustomHighlightsChunks<'a> {
type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> {
- let mut next_highlight_endpoint = usize::MAX;
+ let mut next_highlight_endpoint = MultiBufferOffset(usize::MAX);
while let Some(endpoint) = self.highlight_endpoints.peek().copied() {
if endpoint.offset <= self.offset {
if let Some(style) = endpoint.style {
@@ -224,20 +224,22 @@ mod tests {
let range_count = rng.random_range(1..10);
let text = buffer_snapshot.text();
for _ in 0..range_count {
- if buffer_snapshot.len() == 0 {
+ if buffer_snapshot.len() == MultiBufferOffset(0) {
continue;
}
- let mut start = rng.random_range(0..=buffer_snapshot.len().saturating_sub(10));
+ let mut start = rng.random_range(
+ MultiBufferOffset(0)..=buffer_snapshot.len().saturating_sub_usize(10),
+ );
- while !text.is_char_boundary(start) {
- start = start.saturating_sub(1);
+ while !text.is_char_boundary(start.0) {
+ start = start.saturating_sub_usize(1);
}
- let end_end = buffer_snapshot.len().min(start + 100);
+ let end_end = buffer_snapshot.len().min(start + 100usize);
let mut end = rng.random_range(start..=end_end);
- while !text.is_char_boundary(end) {
- end = end.saturating_sub(1);
+ while !text.is_char_boundary(end.0) {
+ end = end.saturating_sub_usize(1);
}
if start < end {
@@ -253,8 +255,12 @@ mod tests {
}
// Get all chunks and verify their bitmaps
- let chunks =
- CustomHighlightsChunks::new(0..buffer_snapshot.len(), false, None, &buffer_snapshot);
+ let chunks = CustomHighlightsChunks::new(
+ MultiBufferOffset(0)..buffer_snapshot.len(),
+ false,
+ None,
+ &buffer_snapshot,
+ );
for chunk in chunks {
let chunk_text = chunk.text;
@@ -5,16 +5,17 @@ use super::{
inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
};
use gpui::{AnyElement, App, ElementId, HighlightStyle, Pixels, Window};
-use language::{Edit, HighlightId, Point, TextSummary};
+use language::{Edit, HighlightId, Point};
use multi_buffer::{
- Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset,
+ Anchor, AnchorRangeExt, MBTextSummary, MultiBufferOffset, MultiBufferRow, MultiBufferSnapshot,
+ RowInfo, ToOffset,
};
use project::InlayId;
use std::{
any::TypeId,
cmp::{self, Ordering},
fmt, iter,
- ops::{Add, AddAssign, Deref, DerefMut, Range, Sub},
+ ops::{Add, AddAssign, Deref, DerefMut, Range, Sub, SubAssign},
sync::Arc,
usize,
};
@@ -261,7 +262,7 @@ impl FoldMapWriter<'_> {
fold_ixs_to_delete.dedup();
self.0.snapshot.folds = {
- let mut cursor = self.0.snapshot.folds.cursor::<usize>(buffer);
+ let mut cursor = self.0.snapshot.folds.cursor::<MultiBufferOffset>(buffer);
let mut folds = SumTree::new(buffer);
for fold_ix in fold_ixs_to_delete {
folds.append(cursor.slice(&fold_ix, Bias::Right), buffer);
@@ -413,7 +414,7 @@ impl FoldMap {
let mut new_transforms = SumTree::<Transform>::default();
let mut cursor = self.snapshot.transforms.cursor::<InlayOffset>(());
- cursor.seek(&InlayOffset(0), Bias::Right);
+ cursor.seek(&InlayOffset(MultiBufferOffset(0)), Bias::Right);
while let Some(mut edit) = inlay_edits_iter.next() {
if let Some(item) = cursor.item()
@@ -436,7 +437,7 @@ impl FoldMap {
cursor.seek(&edit.old.end, Bias::Right);
cursor.next();
- let mut delta = edit.new_len().0 as isize - edit.old_len().0 as isize;
+ let mut delta = edit.new_len() as isize - edit.old_len() as isize;
loop {
edit.old.end = *cursor.start();
@@ -446,7 +447,7 @@ impl FoldMap {
}
let next_edit = inlay_edits_iter.next().unwrap();
- delta += next_edit.new_len().0 as isize - next_edit.old_len().0 as isize;
+ delta += next_edit.new_len() as isize - next_edit.old_len() as isize;
if next_edit.old.end >= edit.old.end {
edit.old.end = next_edit.old.end;
@@ -458,8 +459,9 @@ impl FoldMap {
}
}
- edit.new.end =
- InlayOffset(((edit.new.start + edit.old_len()).0 as isize + delta) as usize);
+ edit.new.end = InlayOffset(MultiBufferOffset(
+ ((edit.new.start + edit.old_len()).0.0 as isize + delta) as usize,
+ ));
let anchor = inlay_snapshot
.buffer
@@ -522,7 +524,7 @@ impl FoldMap {
new_transforms.push(
Transform {
summary: TransformSummary {
- output: TextSummary::from(ELLIPSIS),
+ output: MBTextSummary::from(ELLIPSIS),
input: inlay_snapshot
.text_summary_for_range(fold_range.start..fold_range.end),
},
@@ -579,7 +581,7 @@ impl FoldMap {
edit.old.start = old_transforms.start().0;
}
let old_start =
- old_transforms.start().1.0 + (edit.old.start - old_transforms.start().0).0;
+ old_transforms.start().1.0 + (edit.old.start - old_transforms.start().0);
old_transforms.seek_forward(&edit.old.end, Bias::Right);
if old_transforms.item().is_some_and(|t| t.is_fold()) {
@@ -587,14 +589,14 @@ impl FoldMap {
edit.old.end = old_transforms.start().0;
}
let old_end =
- old_transforms.start().1.0 + (edit.old.end - old_transforms.start().0).0;
+ old_transforms.start().1.0 + (edit.old.end - old_transforms.start().0);
new_transforms.seek(&edit.new.start, Bias::Left);
if new_transforms.item().is_some_and(|t| t.is_fold()) {
edit.new.start = new_transforms.start().0;
}
let new_start =
- new_transforms.start().1.0 + (edit.new.start - new_transforms.start().0).0;
+ new_transforms.start().1.0 + (edit.new.start - new_transforms.start().0);
new_transforms.seek_forward(&edit.new.end, Bias::Right);
if new_transforms.item().is_some_and(|t| t.is_fold()) {
@@ -602,7 +604,7 @@ impl FoldMap {
edit.new.end = new_transforms.start().0;
}
let new_end =
- new_transforms.start().1.0 + (edit.new.end - new_transforms.start().0).0;
+ new_transforms.start().1.0 + (edit.new.end - new_transforms.start().0);
fold_edits.push(FoldEdit {
old: FoldOffset(old_start)..FoldOffset(old_end),
@@ -649,9 +651,13 @@ impl FoldSnapshot {
#[cfg(test)]
pub fn text(&self) -> String {
- self.chunks(FoldOffset(0)..self.len(), false, Highlights::default())
- .map(|c| c.text)
- .collect()
+ self.chunks(
+ FoldOffset(MultiBufferOffset(0))..self.len(),
+ false,
+ Highlights::default(),
+ )
+ .map(|c| c.text)
+ .collect()
}
#[cfg(test)]
@@ -659,8 +665,8 @@ impl FoldSnapshot {
self.folds.items(&self.inlay_snapshot.buffer).len()
}
- pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> TextSummary {
- let mut summary = TextSummary::default();
+ pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> MBTextSummary {
+ let mut summary = MBTextSummary::default();
let mut cursor = self
.transforms
@@ -670,7 +676,7 @@ impl FoldSnapshot {
let start_in_transform = range.start.0 - cursor.start().0.0;
let end_in_transform = cmp::min(range.end, cursor.end().0).0 - cursor.start().0.0;
if let Some(placeholder) = transform.placeholder.as_ref() {
- summary = TextSummary::from(
+ summary = MBTextSummary::from(
&placeholder.text
[start_in_transform.column as usize..end_in_transform.column as usize],
);
@@ -689,14 +695,14 @@ impl FoldSnapshot {
if range.end > cursor.end().0 {
cursor.next();
- summary += &cursor
+ summary += cursor
.summary::<_, TransformSummary>(&range.end, Bias::Right)
.output;
if let Some(transform) = cursor.item() {
let end_in_transform = range.end.0 - cursor.start().0.0;
if let Some(placeholder) = transform.placeholder.as_ref() {
summary +=
- TextSummary::from(&placeholder.text[..end_in_transform.column as usize]);
+ MBTextSummary::from(&placeholder.text[..end_in_transform.column as usize]);
} else {
let inlay_start = self.inlay_snapshot.to_offset(cursor.start().1);
let inlay_end = self
@@ -839,8 +845,8 @@ impl FoldSnapshot {
transform_cursor.seek(&range.start, Bias::Right);
let inlay_start = {
- let overshoot = range.start.0 - transform_cursor.start().0.0;
- transform_cursor.start().1 + InlayOffset(overshoot)
+ let overshoot = range.start - transform_cursor.start().0;
+ transform_cursor.start().1 + overshoot
};
let transform_end = transform_cursor.end();
@@ -851,8 +857,8 @@ impl FoldSnapshot {
{
inlay_start
} else if range.end < transform_end.0 {
- let overshoot = range.end.0 - transform_cursor.start().0.0;
- transform_cursor.start().1 + InlayOffset(overshoot)
+ let overshoot = range.end - transform_cursor.start().0;
+ transform_cursor.start().1 + overshoot
} else {
transform_end.1
};
@@ -921,7 +927,7 @@ impl FoldSnapshot {
}
}
-fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: TextSummary) {
+fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: MBTextSummary) {
let mut did_merge = false;
transforms.update_last(
|last| {
@@ -950,13 +956,13 @@ fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: TextSummary) {
fn intersecting_folds<'a>(
inlay_snapshot: &'a InlaySnapshot,
folds: &'a SumTree<Fold>,
- range: Range<usize>,
+ range: Range<MultiBufferOffset>,
inclusive: bool,
-) -> FilterCursor<'a, 'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize> {
+) -> FilterCursor<'a, 'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, MultiBufferOffset> {
let buffer = &inlay_snapshot.buffer;
let start = buffer.anchor_before(range.start.to_offset(buffer));
let end = buffer.anchor_after(range.end.to_offset(buffer));
- let mut cursor = folds.filter::<_, usize>(buffer, move |summary| {
+ let mut cursor = folds.filter::<_, MultiBufferOffset>(buffer, move |summary| {
let start_cmp = start.cmp(&summary.max_end, buffer);
let end_cmp = end.cmp(&summary.min_start, buffer);
@@ -1061,8 +1067,8 @@ impl Transform {
#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct TransformSummary {
- output: TextSummary,
- input: TextSummary,
+ output: MBTextSummary,
+ input: MBTextSummary,
}
impl sum_tree::Item for Transform {
@@ -1079,8 +1085,8 @@ impl sum_tree::ContextLessSummary for TransformSummary {
}
fn add_summary(&mut self, other: &Self) {
- self.input += &other.input;
- self.output += &other.output;
+ self.input += other.input;
+ self.output += other.output;
}
}
@@ -1211,7 +1217,7 @@ impl sum_tree::SeekTarget<'_, FoldSummary, FoldRange> for FoldRange {
}
}
-impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize {
+impl<'a> sum_tree::Dimension<'a, FoldSummary> for MultiBufferOffset {
fn zero(_cx: &MultiBufferSnapshot) -> Self {
Default::default()
}
@@ -1357,8 +1363,8 @@ impl FoldChunks<'_> {
self.transform_cursor.seek(&range.start, Bias::Right);
let inlay_start = {
- let overshoot = range.start.0 - self.transform_cursor.start().0.0;
- self.transform_cursor.start().1 + InlayOffset(overshoot)
+ let overshoot = range.start - self.transform_cursor.start().0;
+ self.transform_cursor.start().1 + overshoot
};
let transform_end = self.transform_cursor.end();
@@ -1370,8 +1376,8 @@ impl FoldChunks<'_> {
{
inlay_start
} else if range.end < transform_end.0 {
- let overshoot = range.end.0 - self.transform_cursor.start().0.0;
- self.transform_cursor.start().1 + InlayOffset(overshoot)
+ let overshoot = range.end - self.transform_cursor.start().0;
+ self.transform_cursor.start().1 + overshoot
} else {
transform_end.1
};
@@ -1423,8 +1429,8 @@ impl<'a> Iterator for FoldChunks<'a> {
let transform_start = self.transform_cursor.start();
let transform_end = self.transform_cursor.end();
let inlay_end = if self.max_output_offset < transform_end.0 {
- let overshoot = self.max_output_offset.0 - transform_start.0.0;
- transform_start.1 + InlayOffset(overshoot)
+ let overshoot = self.max_output_offset - transform_start.0;
+ transform_start.1 + overshoot
} else {
transform_end.1
};
@@ -1441,15 +1447,15 @@ impl<'a> Iterator for FoldChunks<'a> {
// Otherwise, take a chunk from the buffer's text.
if let Some((buffer_chunk_start, mut inlay_chunk)) = self.inlay_chunk.clone() {
let chunk = &mut inlay_chunk.chunk;
- let buffer_chunk_end = buffer_chunk_start + InlayOffset(chunk.text.len());
+ let buffer_chunk_end = buffer_chunk_start + chunk.text.len();
let transform_end = self.transform_cursor.end().1;
let chunk_end = buffer_chunk_end.min(transform_end);
- let bit_start = (self.inlay_offset - buffer_chunk_start).0;
- let bit_end = (chunk_end - buffer_chunk_start).0;
+ let bit_start = self.inlay_offset - buffer_chunk_start;
+ let bit_end = chunk_end - buffer_chunk_start;
chunk.text = &chunk.text[bit_start..bit_end];
- let bit_end = (chunk_end - buffer_chunk_start).0;
+ let bit_end = chunk_end - buffer_chunk_start;
let mask = 1u128.unbounded_shl(bit_end as u32).wrapping_sub(1);
chunk.tabs = (chunk.tabs >> bit_start) & mask;
@@ -1483,7 +1489,7 @@ impl<'a> Iterator for FoldChunks<'a> {
}
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
-pub struct FoldOffset(pub usize);
+pub struct FoldOffset(pub MultiBufferOffset);
impl FoldOffset {
pub fn to_point(self, snapshot: &FoldSnapshot) -> FoldPoint {
@@ -1493,7 +1499,7 @@ impl FoldOffset {
let overshoot = if item.is_none_or(|t| t.is_fold()) {
Point::new(0, (self.0 - start.0.0) as u32)
} else {
- let inlay_offset = start.1.input.len + self.0 - start.0.0;
+ let inlay_offset = start.1.input.len + (self - start.0);
let inlay_point = snapshot.inlay_snapshot.to_point(InlayOffset(inlay_offset));
inlay_point.0 - start.1.input.lines
};
@@ -1505,7 +1511,7 @@ impl FoldOffset {
let (start, _, _) = snapshot
.transforms
.find::<Dimensions<FoldOffset, InlayOffset>, _>((), &self, Bias::Right);
- let overshoot = self.0 - start.0.0;
+ let overshoot = self - start.0;
InlayOffset(start.1.0 + overshoot)
}
}
@@ -1518,17 +1524,46 @@ impl Add for FoldOffset {
}
}
+impl Sub for FoldOffset {
+ type Output = <MultiBufferOffset as Sub>::Output;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.0 - rhs.0
+ }
+}
+
+impl<T> SubAssign<T> for FoldOffset
+where
+ MultiBufferOffset: SubAssign<T>,
+{
+ fn sub_assign(&mut self, rhs: T) {
+ self.0 -= rhs;
+ }
+}
+
+impl<T> Add<T> for FoldOffset
+where
+ MultiBufferOffset: Add<T, Output = MultiBufferOffset>,
+{
+ type Output = Self;
+
+ fn add(self, rhs: T) -> Self::Output {
+ Self(self.0 + rhs)
+ }
+}
+
impl AddAssign for FoldOffset {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
-impl Sub for FoldOffset {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self::Output {
- Self(self.0 - rhs.0)
+impl<T> AddAssign<T> for FoldOffset
+where
+ MultiBufferOffset: AddAssign<T>,
+{
+ fn add_assign(&mut self, rhs: T) {
+ self.0 += rhs;
}
}
@@ -1538,7 +1573,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldOffset {
}
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
- self.0 += &summary.output.len;
+ self.0 += summary.output.len;
}
}
@@ -1558,7 +1593,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
}
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
- self.0 += &summary.input.len;
+ self.0 += summary.input.len;
}
}
@@ -1596,12 +1631,12 @@ mod tests {
edits,
&[
FoldEdit {
- old: FoldOffset(2)..FoldOffset(16),
- new: FoldOffset(2)..FoldOffset(5),
+ old: FoldOffset(MultiBufferOffset(2))..FoldOffset(MultiBufferOffset(16)),
+ new: FoldOffset(MultiBufferOffset(2))..FoldOffset(MultiBufferOffset(5)),
},
FoldEdit {
- old: FoldOffset(18)..FoldOffset(29),
- new: FoldOffset(7)..FoldOffset(10)
+ old: FoldOffset(MultiBufferOffset(18))..FoldOffset(MultiBufferOffset(29)),
+ new: FoldOffset(MultiBufferOffset(7))..FoldOffset(MultiBufferOffset(10)),
},
]
);
@@ -1626,12 +1661,12 @@ mod tests {
edits,
&[
FoldEdit {
- old: FoldOffset(0)..FoldOffset(1),
- new: FoldOffset(0)..FoldOffset(3),
+ old: FoldOffset(MultiBufferOffset(0))..FoldOffset(MultiBufferOffset(1)),
+ new: FoldOffset(MultiBufferOffset(0))..FoldOffset(MultiBufferOffset(3)),
},
FoldEdit {
- old: FoldOffset(6)..FoldOffset(6),
- new: FoldOffset(8)..FoldOffset(11),
+ old: FoldOffset(MultiBufferOffset(6))..FoldOffset(MultiBufferOffset(6)),
+ new: FoldOffset(MultiBufferOffset(8))..FoldOffset(MultiBufferOffset(11)),
},
]
);
@@ -1668,15 +1703,24 @@ mod tests {
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
- writer.fold(vec![(5..8, FoldPlaceholder::test())]);
+ writer.fold(vec![(
+ MultiBufferOffset(5)..MultiBufferOffset(8),
+ FoldPlaceholder::test(),
+ )]);
let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
assert_eq!(snapshot.text(), "abcde⋯ijkl");
// Create an fold adjacent to the start of the first fold.
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
writer.fold(vec![
- (0..1, FoldPlaceholder::test()),
- (2..5, FoldPlaceholder::test()),
+ (
+ MultiBufferOffset(0)..MultiBufferOffset(1),
+ FoldPlaceholder::test(),
+ ),
+ (
+ MultiBufferOffset(2)..MultiBufferOffset(5),
+ FoldPlaceholder::test(),
+ ),
]);
let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
assert_eq!(snapshot.text(), "⋯b⋯ijkl");
@@ -1684,8 +1728,14 @@ mod tests {
// Create an fold adjacent to the end of the first fold.
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
writer.fold(vec![
- (11..11, FoldPlaceholder::test()),
- (8..10, FoldPlaceholder::test()),
+ (
+ MultiBufferOffset(11)..MultiBufferOffset(11),
+ FoldPlaceholder::test(),
+ ),
+ (
+ MultiBufferOffset(8)..MultiBufferOffset(10),
+ FoldPlaceholder::test(),
+ ),
]);
let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
assert_eq!(snapshot.text(), "⋯b⋯kl");
@@ -1697,15 +1747,25 @@ mod tests {
// Create two adjacent folds.
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
writer.fold(vec![
- (0..2, FoldPlaceholder::test()),
- (2..5, FoldPlaceholder::test()),
+ (
+ MultiBufferOffset(0)..MultiBufferOffset(2),
+ FoldPlaceholder::test(),
+ ),
+ (
+ MultiBufferOffset(2)..MultiBufferOffset(5),
+ FoldPlaceholder::test(),
+ ),
]);
let (snapshot, _) = map.read(inlay_snapshot, vec![]);
assert_eq!(snapshot.text(), "⋯fghijkl");
// Edit within one of the folds.
let buffer_snapshot = buffer.update(cx, |buffer, cx| {
- buffer.edit([(0..1, "12345")], None, cx);
+ buffer.edit(
+ [(MultiBufferOffset(0)..MultiBufferOffset(1), "12345")],
+ None,
+ cx,
+ );
buffer.snapshot(cx)
});
let (inlay_snapshot, inlay_edits) =
@@ -1849,7 +1909,7 @@ mod tests {
for fold_range in map.merged_folds().into_iter().rev() {
let fold_inlay_start = inlay_snapshot.to_inlay_offset(fold_range.start);
let fold_inlay_end = inlay_snapshot.to_inlay_offset(fold_range.end);
- expected_text.replace_range(fold_inlay_start.0..fold_inlay_end.0, "⋯");
+ expected_text.replace_range(fold_inlay_start.0.0..fold_inlay_end.0.0, "⋯");
}
assert_eq!(snapshot.text(), expected_text);
@@ -1898,7 +1958,7 @@ mod tests {
.chars()
.count();
let mut fold_point = FoldPoint::new(0, 0);
- let mut fold_offset = FoldOffset(0);
+ let mut fold_offset = FoldOffset(MultiBufferOffset(0));
let mut char_column = 0;
for c in expected_text.chars() {
let inlay_point = fold_point.to_inlay_point(&snapshot);
@@ -1944,18 +2004,18 @@ mod tests {
for _ in 0..5 {
let mut start = snapshot.clip_offset(
- FoldOffset(rng.random_range(0..=snapshot.len().0)),
+ FoldOffset(rng.random_range(MultiBufferOffset(0)..=snapshot.len().0)),
Bias::Left,
);
let mut end = snapshot.clip_offset(
- FoldOffset(rng.random_range(0..=snapshot.len().0)),
+ FoldOffset(rng.random_range(MultiBufferOffset(0)..=snapshot.len().0)),
Bias::Right,
);
if start > end {
mem::swap(&mut start, &mut end);
}
- let text = &expected_text[start.0..end.0];
+ let text = &expected_text[start.0.0..end.0.0];
assert_eq!(
snapshot
.chunks(start..end, false, Highlights::default())
@@ -2004,9 +2064,12 @@ mod tests {
}
for _ in 0..5 {
- let end =
- buffer_snapshot.clip_offset(rng.random_range(0..=buffer_snapshot.len()), Right);
- let start = buffer_snapshot.clip_offset(rng.random_range(0..=end), Left);
+ let end = buffer_snapshot.clip_offset(
+ rng.random_range(MultiBufferOffset(0)..=buffer_snapshot.len()),
+ Right,
+ );
+ let start =
+ buffer_snapshot.clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
let expected_folds = map
.snapshot
.folds
@@ -2046,7 +2109,7 @@ mod tests {
let bytes = start.to_offset(&snapshot)..end.to_offset(&snapshot);
assert_eq!(
snapshot.text_summary_for_range(lines),
- TextSummary::from(&text[bytes.start.0..bytes.end.0])
+ MBTextSummary::from(&text[bytes.start.0.0..bytes.end.0.0])
)
}
@@ -2054,8 +2117,8 @@ mod tests {
for (snapshot, edits) in snapshot_edits.drain(..) {
let new_text = snapshot.text();
for edit in edits {
- let old_bytes = edit.new.start.0..edit.new.start.0 + edit.old_len().0;
- let new_bytes = edit.new.start.0..edit.new.end.0;
+ let old_bytes = edit.new.start.0.0..edit.new.start.0.0 + edit.old_len();
+ let new_bytes = edit.new.start.0.0..edit.new.end.0.0;
text.replace_range(old_bytes, &new_text[new_bytes]);
}
@@ -2126,7 +2189,7 @@ mod tests {
// Get all chunks and verify their bitmaps
let chunks = snapshot.chunks(
- FoldOffset(0)..FoldOffset(snapshot.len().0),
+ FoldOffset(MultiBufferOffset(0))..FoldOffset(snapshot.len().0),
false,
Highlights::default(),
);
@@ -2195,7 +2258,7 @@ mod tests {
}
impl FoldMap {
- fn merged_folds(&self) -> Vec<Range<usize>> {
+ fn merged_folds(&self) -> Vec<Range<MultiBufferOffset>> {
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
let buffer = &inlay_snapshot.buffer;
let mut folds = self.snapshot.folds.items(buffer);
@@ -2236,8 +2299,12 @@ mod tests {
let buffer = &inlay_snapshot.buffer;
let mut to_unfold = Vec::new();
for _ in 0..rng.random_range(1..=3) {
- let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
- let start = buffer.clip_offset(rng.random_range(0..=end), Left);
+ let end = buffer.clip_offset(
+ rng.random_range(MultiBufferOffset(0)..=buffer.len()),
+ Right,
+ );
+ let start =
+ buffer.clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
to_unfold.push(start..end);
}
let inclusive = rng.random();
@@ -2252,8 +2319,12 @@ mod tests {
let buffer = &inlay_snapshot.buffer;
let mut to_fold = Vec::new();
for _ in 0..rng.random_range(1..=2) {
- let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
- let start = buffer.clip_offset(rng.random_range(0..=end), Left);
+ let end = buffer.clip_offset(
+ rng.random_range(MultiBufferOffset(0)..=buffer.len()),
+ Right,
+ );
+ let start =
+ buffer.clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
to_fold.push((start..end, FoldPlaceholder::test()));
}
log::info!("folding {:?}", to_fold);
@@ -4,7 +4,10 @@ use crate::{
};
use collections::BTreeSet;
use language::{Chunk, Edit, Point, TextSummary};
-use multi_buffer::{MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, RowInfo, ToOffset};
+use multi_buffer::{
+ MBTextSummary, MultiBufferOffset, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot,
+ RowInfo, ToOffset,
+};
use project::InlayId;
use std::{
cmp,
@@ -42,7 +45,7 @@ impl std::ops::Deref for InlaySnapshot {
#[derive(Clone, Debug)]
enum Transform {
- Isomorphic(TextSummary),
+ Isomorphic(MBTextSummary),
Inlay(Inlay),
}
@@ -56,8 +59,8 @@ impl sum_tree::Item for Transform {
output: *summary,
},
Transform::Inlay(inlay) => TransformSummary {
- input: TextSummary::default(),
- output: inlay.text().summary(),
+ input: MBTextSummary::default(),
+ output: MBTextSummary::from(inlay.text().summary()),
},
}
}
@@ -65,8 +68,8 @@ impl sum_tree::Item for Transform {
#[derive(Clone, Debug, Default)]
struct TransformSummary {
- input: TextSummary,
- output: TextSummary,
+ input: MBTextSummary,
+ output: MBTextSummary,
}
impl sum_tree::ContextLessSummary for TransformSummary {
@@ -75,15 +78,15 @@ impl sum_tree::ContextLessSummary for TransformSummary {
}
fn add_summary(&mut self, other: &Self) {
- self.input += &other.input;
- self.output += &other.output;
+ self.input += other.input;
+ self.output += other.output;
}
}
pub type InlayEdit = Edit<InlayOffset>;
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
-pub struct InlayOffset(pub usize);
+pub struct InlayOffset(pub MultiBufferOffset);
impl Add for InlayOffset {
type Output = Self;
@@ -94,10 +97,30 @@ impl Add for InlayOffset {
}
impl Sub for InlayOffset {
- type Output = Self;
+ type Output = <MultiBufferOffset as Sub>::Output;
fn sub(self, rhs: Self) -> Self::Output {
- Self(self.0 - rhs.0)
+ self.0 - rhs.0
+ }
+}
+
+impl<T> SubAssign<T> for InlayOffset
+where
+ MultiBufferOffset: SubAssign<T>,
+{
+ fn sub_assign(&mut self, rhs: T) {
+ self.0 -= rhs;
+ }
+}
+
+impl<T> Add<T> for InlayOffset
+where
+ MultiBufferOffset: Add<T, Output = MultiBufferOffset>,
+{
+ type Output = Self;
+
+ fn add(self, rhs: T) -> Self::Output {
+ Self(self.0 + rhs)
}
}
@@ -107,9 +130,12 @@ impl AddAssign for InlayOffset {
}
}
-impl SubAssign for InlayOffset {
- fn sub_assign(&mut self, rhs: Self) {
- self.0 -= rhs.0;
+impl<T> AddAssign<T> for InlayOffset
+where
+ MultiBufferOffset: AddAssign<T>,
+{
+ fn add_assign(&mut self, rhs: T) {
+ self.0 += rhs;
}
}
@@ -119,7 +145,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
}
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
- self.0 += &summary.output.len;
+ self.0 += summary.output.len;
}
}
@@ -152,13 +178,13 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {
}
}
-impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for MultiBufferOffset {
fn zero(_cx: ()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
- *self += &summary.input.len;
+ *self += summary.input.len;
}
}
@@ -181,7 +207,7 @@ pub struct InlayBufferRows<'a> {
}
pub struct InlayChunks<'a> {
- transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, usize>>,
+ transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, MultiBufferOffset>>,
buffer_chunks: CustomHighlightsChunks<'a>,
buffer_chunk: Option<Chunk<'a>>,
inlay_chunks: Option<text::ChunkWithBitmaps<'a>>,
@@ -332,12 +358,12 @@ impl<'a> Iterator for InlayChunks<'a> {
let offset_in_inlay = self.output_offset - self.transforms.start().0;
if let Some((style, highlight)) = inlay_style_and_highlight {
let range = &highlight.range;
- if offset_in_inlay.0 < range.start {
- next_inlay_highlight_endpoint = range.start - offset_in_inlay.0;
- } else if offset_in_inlay.0 >= range.end {
+ if offset_in_inlay < range.start {
+ next_inlay_highlight_endpoint = range.start - offset_in_inlay;
+ } else if offset_in_inlay >= range.end {
next_inlay_highlight_endpoint = usize::MAX;
} else {
- next_inlay_highlight_endpoint = range.end - offset_in_inlay.0;
+ next_inlay_highlight_endpoint = range.end - offset_in_inlay;
highlight_style = highlight_style
.map(|highlight| highlight.highlight(*style))
.or_else(|| Some(*style));
@@ -350,7 +376,7 @@ impl<'a> Iterator for InlayChunks<'a> {
let start = offset_in_inlay;
let end = cmp::min(self.max_output_offset, self.transforms.end().0)
- self.transforms.start().0;
- let chunks = inlay.text().chunks_in_range(start.0..end.0);
+ let chunks = inlay.text().chunks_in_range(start..end);
text::ChunkWithBitmaps(chunks)
});
let ChunkBitmaps {
@@ -488,7 +514,7 @@ impl InlayMap {
pub fn sync(
&mut self,
buffer_snapshot: MultiBufferSnapshot,
- mut buffer_edits: Vec<text::Edit<usize>>,
+ mut buffer_edits: Vec<text::Edit<MultiBufferOffset>>,
) -> (InlaySnapshot, Vec<InlayEdit>) {
let snapshot = &mut self.snapshot;
@@ -519,7 +545,7 @@ impl InlayMap {
let mut new_transforms = SumTree::default();
let mut cursor = snapshot
.transforms
- .cursor::<Dimensions<usize, InlayOffset>>(());
+ .cursor::<Dimensions<MultiBufferOffset, InlayOffset>>(());
let mut buffer_edits_iter = buffer_edits.iter().peekable();
while let Some(buffer_edit) = buffer_edits_iter.next() {
new_transforms.append(cursor.slice(&buffer_edit.old.start, Bias::Left), ());
@@ -531,11 +557,9 @@ impl InlayMap {
}
// Remove all the inlays and transforms contained by the edit.
- let old_start =
- cursor.start().1 + InlayOffset(buffer_edit.old.start - cursor.start().0);
+ let old_start = cursor.start().1 + (buffer_edit.old.start - cursor.start().0);
cursor.seek(&buffer_edit.old.end, Bias::Right);
- let old_end =
- cursor.start().1 + InlayOffset(buffer_edit.old.end - cursor.start().0);
+ let old_end = cursor.start().1 + (buffer_edit.old.end - cursor.start().0);
// Push the unchanged prefix.
let prefix_start = new_transforms.summary().input.len;
@@ -687,7 +711,10 @@ impl InlayMap {
let snapshot = &mut self.snapshot;
for i in 0..rng.random_range(1..=5) {
if self.inlays.is_empty() || rng.random() {
- let position = snapshot.buffer.random_byte_range(0, rng).start;
+ let position = snapshot
+ .buffer
+ .random_byte_range(MultiBufferOffset(0), rng)
+ .start;
let bias = if rng.random() {
Bias::Left
} else {
@@ -740,9 +767,11 @@ impl InlayMap {
impl InlaySnapshot {
pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
- let (start, _, item) = self
- .transforms
- .find::<Dimensions<InlayOffset, InlayPoint, usize>, _>((), &offset, Bias::Right);
+ let (start, _, item) = self.transforms.find::<Dimensions<
+ InlayOffset,
+ InlayPoint,
+ MultiBufferOffset,
+ >, _>((), &offset, Bias::Right);
let overshoot = offset.0 - start.0.0;
match item {
Some(Transform::Isomorphic(_)) => {
@@ -801,22 +830,24 @@ impl InlaySnapshot {
None => self.buffer.max_point(),
}
}
- pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
- let (start, _, item) =
- self.transforms
- .find::<Dimensions<InlayOffset, usize>, _>((), &offset, Bias::Right);
+ pub fn to_buffer_offset(&self, offset: InlayOffset) -> MultiBufferOffset {
+ let (start, _, item) = self
+ .transforms
+ .find::<Dimensions<InlayOffset, MultiBufferOffset>, _>((), &offset, Bias::Right);
match item {
Some(Transform::Isomorphic(_)) => {
let overshoot = offset - start.0;
- start.1 + overshoot.0
+ start.1 + overshoot
}
Some(Transform::Inlay(_)) => start.1,
None => self.buffer.len(),
}
}
- pub fn to_inlay_offset(&self, offset: usize) -> InlayOffset {
- let mut cursor = self.transforms.cursor::<Dimensions<usize, InlayOffset>>(());
+ pub fn to_inlay_offset(&self, offset: MultiBufferOffset) -> InlayOffset {
+ let mut cursor = self
+ .transforms
+ .cursor::<Dimensions<MultiBufferOffset, InlayOffset>>(());
cursor.seek(&offset, Bias::Left);
loop {
match cursor.item() {
@@ -973,14 +1004,16 @@ impl InlaySnapshot {
}
}
- pub fn text_summary(&self) -> TextSummary {
+ pub fn text_summary(&self) -> MBTextSummary {
self.transforms.summary().output
}
- pub fn text_summary_for_range(&self, range: Range<InlayOffset>) -> TextSummary {
- let mut summary = TextSummary::default();
+ pub fn text_summary_for_range(&self, range: Range<InlayOffset>) -> MBTextSummary {
+ let mut summary = MBTextSummary::default();
- let mut cursor = self.transforms.cursor::<Dimensions<InlayOffset, usize>>(());
+ let mut cursor = self
+ .transforms
+ .cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
cursor.seek(&range.start, Bias::Right);
let overshoot = range.start.0 - cursor.start().0.0;
@@ -996,7 +1029,12 @@ impl InlaySnapshot {
Some(Transform::Inlay(inlay)) => {
let suffix_start = overshoot;
let suffix_end = cmp::min(cursor.end().0, range.end).0 - cursor.start().0.0;
- summary = inlay.text().cursor(suffix_start).summary(suffix_end);
+ summary = MBTextSummary::from(
+ inlay
+ .text()
+ .cursor(suffix_start)
+ .summary::<TextSummary>(suffix_end),
+ );
cursor.next();
}
None => {}
@@ -1014,7 +1052,7 @@ impl InlaySnapshot {
let prefix_end = prefix_start + overshoot;
summary += self
.buffer
- .text_summary_for_range::<TextSummary, _>(prefix_start..prefix_end);
+ .text_summary_for_range::<MBTextSummary, _>(prefix_start..prefix_end);
}
Some(Transform::Inlay(inlay)) => {
let prefix_end = overshoot;
@@ -1070,7 +1108,9 @@ impl InlaySnapshot {
language_aware: bool,
highlights: Highlights<'a>,
) -> InlayChunks<'a> {
- let mut cursor = self.transforms.cursor::<Dimensions<InlayOffset, usize>>(());
+ let mut cursor = self
+ .transforms
+ .cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
cursor.seek(&range.start, Bias::Right);
let buffer_range = self.to_buffer_offset(range.start)..self.to_buffer_offset(range.end);
@@ -1122,8 +1162,8 @@ impl InlaySnapshot {
}
}
-fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: TextSummary) {
- if summary.len == 0 {
+fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: MBTextSummary) {
+ if summary.len == MultiBufferOffset(0) {
return;
}
@@ -1279,7 +1319,10 @@ mod tests {
&[],
vec![Inlay::mock_hint(
post_inc(&mut next_inlay_id),
- buffer.read(cx).snapshot(cx).anchor_after(3),
+ buffer
+ .read(cx)
+ .snapshot(cx)
+ .anchor_after(MultiBufferOffset(3)),
"|123|",
)],
);
@@ -1335,7 +1378,15 @@ mod tests {
// Edits before or after the inlay should not affect it.
buffer.update(cx, |buffer, cx| {
- buffer.edit([(2..3, "x"), (3..3, "y"), (4..4, "z")], None, cx)
+ buffer.edit(
+ [
+ (MultiBufferOffset(2)..MultiBufferOffset(3), "x"),
+ (MultiBufferOffset(3)..MultiBufferOffset(3), "y"),
+ (MultiBufferOffset(4)..MultiBufferOffset(4), "z"),
+ ],
+ None,
+ cx,
+ )
});
let (inlay_snapshot, _) = inlay_map.sync(
buffer.read(cx).snapshot(cx),
@@ -1344,7 +1395,13 @@ mod tests {
assert_eq!(inlay_snapshot.text(), "abxy|123|dzefghi");
// An edit surrounding the inlay should invalidate it.
- buffer.update(cx, |buffer, cx| buffer.edit([(4..5, "D")], None, cx));
+ buffer.update(cx, |buffer, cx| {
+ buffer.edit(
+ [(MultiBufferOffset(4)..MultiBufferOffset(5), "D")],
+ None,
+ cx,
+ )
+ });
let (inlay_snapshot, _) = inlay_map.sync(
buffer.read(cx).snapshot(cx),
buffer_edits.consume().into_inner(),
@@ -1356,12 +1413,18 @@ mod tests {
vec![
Inlay::mock_hint(
post_inc(&mut next_inlay_id),
- buffer.read(cx).snapshot(cx).anchor_before(3),
+ buffer
+ .read(cx)
+ .snapshot(cx)
+ .anchor_before(MultiBufferOffset(3)),
"|123|",
),
Inlay::edit_prediction(
post_inc(&mut next_inlay_id),
- buffer.read(cx).snapshot(cx).anchor_after(3),
+ buffer
+ .read(cx)
+ .snapshot(cx)
+ .anchor_after(MultiBufferOffset(3)),
"|456|",
),
],
@@ -1369,7 +1432,13 @@ mod tests {
assert_eq!(inlay_snapshot.text(), "abx|123||456|yDzefghi");
// Edits ending where the inlay starts should not move it if it has a left bias.
- buffer.update(cx, |buffer, cx| buffer.edit([(3..3, "JKL")], None, cx));
+ buffer.update(cx, |buffer, cx| {
+ buffer.edit(
+ [(MultiBufferOffset(3)..MultiBufferOffset(3), "JKL")],
+ None,
+ cx,
+ )
+ });
let (inlay_snapshot, _) = inlay_map.sync(
buffer.read(cx).snapshot(cx),
buffer_edits.consume().into_inner(),
@@ -1571,17 +1640,26 @@ mod tests {
vec![
Inlay::mock_hint(
post_inc(&mut next_inlay_id),
- buffer.read(cx).snapshot(cx).anchor_before(0),
+ buffer
+ .read(cx)
+ .snapshot(cx)
+ .anchor_before(MultiBufferOffset(0)),
"|123|\n",
),
Inlay::mock_hint(
post_inc(&mut next_inlay_id),
- buffer.read(cx).snapshot(cx).anchor_before(4),
+ buffer
+ .read(cx)
+ .snapshot(cx)
+ .anchor_before(MultiBufferOffset(4)),
"|456|",
),
Inlay::edit_prediction(
post_inc(&mut next_inlay_id),
- buffer.read(cx).snapshot(cx).anchor_before(7),
+ buffer
+ .read(cx)
+ .snapshot(cx)
+ .anchor_before(MultiBufferOffset(7)),
"\n|567|\n",
),
],
@@ -1658,7 +1736,7 @@ mod tests {
.collect::<Vec<_>>();
let mut expected_text = Rope::from(&buffer_snapshot.text());
for (offset, inlay) in inlays.iter().rev() {
- expected_text.replace(*offset..*offset, &inlay.text().to_string());
+ expected_text.replace(offset.0..offset.0, &inlay.text().to_string());
}
assert_eq!(inlay_snapshot.text(), expected_text.to_string());
@@ -1681,7 +1759,7 @@ mod tests {
let mut text_highlights = TextHighlights::default();
let text_highlight_count = rng.random_range(0_usize..10);
let mut text_highlight_ranges = (0..text_highlight_count)
- .map(|_| buffer_snapshot.random_byte_range(0, &mut rng))
+ .map(|_| buffer_snapshot.random_byte_range(MultiBufferOffset(0), &mut rng))
.collect::<Vec<_>>();
text_highlight_ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
log::info!("highlighting text ranges {text_highlight_ranges:?}");
@@ -1744,12 +1822,13 @@ mod tests {
}
for _ in 0..5 {
- let mut end = rng.random_range(0..=inlay_snapshot.len().0);
+ let mut end = rng.random_range(0..=inlay_snapshot.len().0.0);
end = expected_text.clip_offset(end, Bias::Right);
let mut start = rng.random_range(0..=end);
start = expected_text.clip_offset(start, Bias::Right);
- let range = InlayOffset(start)..InlayOffset(end);
+ let range =
+ InlayOffset(MultiBufferOffset(start))..InlayOffset(MultiBufferOffset(end));
log::info!("calling inlay_snapshot.chunks({range:?})");
let actual_text = inlay_snapshot
.chunks(
@@ -1771,25 +1850,27 @@ mod tests {
);
assert_eq!(
- inlay_snapshot.text_summary_for_range(InlayOffset(start)..InlayOffset(end)),
- expected_text.slice(start..end).summary()
+ inlay_snapshot.text_summary_for_range(
+ InlayOffset(MultiBufferOffset(start))..InlayOffset(MultiBufferOffset(end))
+ ),
+ MBTextSummary::from(expected_text.slice(start..end).summary())
);
}
for edit in inlay_edits {
prev_inlay_text.replace_range(
- edit.new.start.0..edit.new.start.0 + edit.old_len().0,
- &inlay_snapshot.text()[edit.new.start.0..edit.new.end.0],
+ edit.new.start.0.0..edit.new.start.0.0 + edit.old_len(),
+ &inlay_snapshot.text()[edit.new.start.0.0..edit.new.end.0.0],
);
}
assert_eq!(prev_inlay_text, inlay_snapshot.text());
assert_eq!(expected_text.max_point(), inlay_snapshot.max_point().0);
- assert_eq!(expected_text.len(), inlay_snapshot.len().0);
+ assert_eq!(expected_text.len(), inlay_snapshot.len().0.0);
let mut buffer_point = Point::default();
let mut inlay_point = inlay_snapshot.to_inlay_point(buffer_point);
- let mut buffer_chars = buffer_snapshot.chars_at(0);
+ let mut buffer_chars = buffer_snapshot.chars_at(MultiBufferOffset(0));
loop {
// Ensure conversion from buffer coordinates to inlay coordinates
// is consistent.
@@ -1930,7 +2011,7 @@ mod tests {
// Get all chunks and verify their bitmaps
let chunks = snapshot.chunks(
- InlayOffset(0)..InlayOffset(snapshot.len().0),
+ InlayOffset(MultiBufferOffset(0))..snapshot.len(),
false,
Highlights::default(),
);
@@ -2064,7 +2145,7 @@ mod tests {
// Collect chunks - this previously would panic
let chunks: Vec<_> = inlay_snapshot
.chunks(
- InlayOffset(0)..InlayOffset(inlay_snapshot.len().0),
+ InlayOffset(MultiBufferOffset(0))..inlay_snapshot.len(),
false,
highlights,
)
@@ -2178,7 +2259,7 @@ mod tests {
let chunks: Vec<_> = inlay_snapshot
.chunks(
- InlayOffset(0)..InlayOffset(inlay_snapshot.len().0),
+ InlayOffset(MultiBufferOffset(0))..inlay_snapshot.len(),
false,
highlights,
)
@@ -648,6 +648,7 @@ mod tests {
inlay_map::InlayMap,
},
};
+ use multi_buffer::MultiBufferOffset;
use rand::{Rng, prelude::StdRng};
use util;
@@ -1156,7 +1157,7 @@ mod tests {
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
let chunks = fold_snapshot.chunks(
- FoldOffset(0)..fold_snapshot.len(),
+ FoldOffset(MultiBufferOffset(0))..fold_snapshot.len(),
false,
Default::default(),
);
@@ -1318,7 +1319,7 @@ mod tests {
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
let chunks = fold_snapshot.chunks(
- FoldOffset(0)..fold_snapshot.len(),
+ FoldOffset(MultiBufferOffset(0))..fold_snapshot.len(),
false,
Default::default(),
);
@@ -64,8 +64,9 @@ pub use items::MAX_TAB_TITLE_LEN;
pub use lsp::CompletionContext;
pub use lsp_ext::lsp_tasks;
pub use multi_buffer::{
- Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
- RowInfo, ToOffset, ToPoint,
+ Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
+ MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
+ ToPoint,
};
pub use text::Bias;
@@ -118,8 +119,7 @@ use language::{
BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
IndentSize, Language, LanguageRegistry, OffsetRangeExt, OutlineItem, Point, Runnable,
- RunnableRange, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
- WordsQuery,
+ Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
language_settings::{
self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
language_settings,
@@ -856,9 +856,6 @@ pub struct ResolvedTasks {
position: Anchor,
}
-#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
-struct BufferOffset(usize);
-
/// Addons allow storing per-editor state in other crates (e.g. Vim)
pub trait Addon: 'static {
fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
@@ -1575,7 +1572,7 @@ pub struct ClipboardSelection {
// selections, scroll behavior, was newest selection reversed
type SelectSyntaxNodeHistoryState = (
- Box<[Selection<usize>]>,
+ Box<[Selection<MultiBufferOffset>]>,
SelectSyntaxNodeScrollBehavior,
bool,
);
@@ -1930,16 +1927,18 @@ impl Editor {
}
}
project::Event::SnippetEdit(id, snippet_edits) => {
- if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
+ // todo(lw): Non singletons
+ if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
+ let snapshot = buffer.read(cx).snapshot();
let focus_handle = editor.focus_handle(cx);
- if focus_handle.is_focused(window) {
- let snapshot = buffer.read(cx).snapshot();
+ if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
for (range, snippet) in snippet_edits {
- let editor_range =
+ let buffer_range =
language::range_from_lsp(*range).to_offset(&snapshot);
editor
.insert_snippet(
- &[editor_range],
+ &[MultiBufferOffset(buffer_range.start)
+ ..MultiBufferOffset(buffer_range.end)],
snippet.clone(),
window,
cx,
@@ -2516,7 +2515,7 @@ impl Editor {
}
self.selections
- .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
+ .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
.into_iter()
.any(|selection| {
// This is needed to cover a corner case, if we just check for an existing
@@ -3177,7 +3176,9 @@ impl Editor {
// Copy selections to primary selection buffer
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
if local {
- let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
+ let selections = self
+ .selections
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx));
let buffer_handle = self.buffer.read(cx).read(cx);
let mut text = String::new();
@@ -3333,8 +3334,8 @@ impl Editor {
.iter()
.map(|selection| {
(
- selection.start.to_offset(&snapshot),
- selection.end.to_offset(&snapshot),
+ selection.start.to_offset(&snapshot).0,
+ selection.end.to_offset(&snapshot).0,
)
})
.collect();
@@ -3376,7 +3377,7 @@ impl Editor {
return;
};
let inmemory_folds = display_snapshot
- .folds_in_range(0..display_snapshot.buffer_snapshot().len())
+ .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
.map(|fold| {
fold.range.start.text_anchor.to_point(&snapshot)
..fold.range.end.text_anchor.to_point(&snapshot)
@@ -3392,7 +3393,7 @@ impl Editor {
let background_executor = cx.background_executor().clone();
let editor_id = cx.entity().entity_id().as_u64() as ItemId;
let db_folds = display_snapshot
- .folds_in_range(0..display_snapshot.buffer_snapshot().len())
+ .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
.map(|fold| {
(
fold.range.start.text_anchor.to_offset(&snapshot),
@@ -3649,7 +3650,10 @@ impl Editor {
cx: &mut Context<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let tail = self.selections.newest::<usize>(&display_map).tail();
+ let tail = self
+ .selections
+ .newest::<MultiBufferOffset>(&display_map)
+ .tail();
let click_count = click_count.max(match self.selections.select_mode() {
SelectMode::Character => 1,
SelectMode::Word(_) => 2,
@@ -3758,7 +3762,7 @@ impl Editor {
auto_scroll = true;
}
_ => {
- start = buffer.anchor_before(0);
+ start = buffer.anchor_before(MultiBufferOffset(0));
end = buffer.anchor_before(buffer.len());
mode = SelectMode::All;
auto_scroll = false;
@@ -3971,7 +3975,9 @@ impl Editor {
fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.columnar_selection_state.take();
if let Some(pending_mode) = self.selections.pending_mode() {
- let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
+ let selections = self
+ .selections
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx));
self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
s.select(selections);
s.clear_pending();
@@ -4505,17 +4511,19 @@ impl Editor {
let new_anchor_selections = new_selections.iter().map(|e| &e.0);
let new_selection_deltas = new_selections.iter().map(|e| e.1);
let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
- let new_selections =
- resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
- .zip(new_selection_deltas)
- .map(|(selection, delta)| Selection {
- id: selection.id,
- start: selection.start + delta,
- end: selection.end + delta,
- reversed: selection.reversed,
- goal: SelectionGoal::None,
- })
- .collect::<Vec<_>>();
+ let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
+ new_anchor_selections,
+ &map,
+ )
+ .zip(new_selection_deltas)
+ .map(|(selection, delta)| Selection {
+ id: selection.id,
+ start: selection.start + delta,
+ end: selection.end + delta,
+ reversed: selection.reversed,
+ goal: SelectionGoal::None,
+ })
+ .collect::<Vec<_>>();
let mut i = 0;
for (position, delta, selection_id, pair) in new_autoclose_regions {
@@ -4651,7 +4659,9 @@ impl Editor {
self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
self.transact(window, cx, |this, window, cx| {
let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
- let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
+ let selections = this
+ .selections
+ .all::<MultiBufferOffset>(&this.display_snapshot(cx));
let multi_buffer = this.buffer.read(cx);
let buffer = multi_buffer.snapshot(cx);
selections
@@ -5151,7 +5161,9 @@ impl Editor {
/// If any empty selections is touching the start of its innermost containing autoclose
/// region, expand it to select the brackets.
fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
- let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
+ let selections = self
+ .selections
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx));
let buffer = self.buffer.read(cx).read(cx);
let new_selections = self
.selections_with_autoclose_regions(selections, &buffer)
@@ -5162,7 +5174,7 @@ impl Editor {
if let Some(region) = region {
let mut range = region.range.to_offset(&buffer);
- if selection.start == range.start && range.start >= region.pair.start.len() {
+ if selection.start == range.start && range.start.0 >= region.pair.start.len() {
range.start -= region.pair.start.len();
if buffer.contains_str_at(range.start, ®ion.pair.start)
&& buffer.contains_str_at(range.end, ®ion.pair.end)
@@ -5193,7 +5205,7 @@ impl Editor {
if buffer.contains_str_at(selection.start, &pair.end) {
let pair_start_len = pair.start.len();
if buffer.contains_str_at(
- selection.start.saturating_sub(pair_start_len),
+ selection.start.saturating_sub_usize(pair_start_len),
&pair.start,
) {
selection.start -= pair_start_len;
@@ -5330,7 +5342,7 @@ impl Editor {
(
multi_buffer.buffer(buffer.remote_id()).unwrap(),
buffer.version().clone(),
- excerpt_visible_range,
+ excerpt_visible_range.start.0..excerpt_visible_range.end.0,
),
))
}
@@ -6013,14 +6025,17 @@ impl Editor {
.start
.text_anchor
.to_offset(buffer)
- .saturating_sub(replace_range.start);
+ .saturating_sub(replace_range.start.0);
let lookahead = replace_range
.end
+ .0
.saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
let suffix = &old_text[lookbehind.min(old_text.len())..];
- let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
+ let selections = self
+ .selections
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx));
let mut ranges = Vec::new();
let mut linked_edits = HashMap::<_, Vec<_>>::default();
@@ -6031,8 +6046,8 @@ impl Editor {
let mut range = selection.range();
// if prefix is present, don't duplicate it
- if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
- range.start = range.start.saturating_sub(lookbehind);
+ if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
+ range.start = range.start.saturating_sub_usize(lookbehind);
// if suffix is also present, mimic the newest cursor and replace it
if selection.id != newest_anchor.id
@@ -7008,7 +7023,10 @@ impl Editor {
for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
match_ranges.extend(
regex
- .search(buffer_snapshot, Some(search_range.clone()))
+ .search(
+ buffer_snapshot,
+ Some(search_range.start.0..search_range.end.0),
+ )
.await
.into_iter()
.filter_map(|match_range| {
@@ -7055,12 +7073,12 @@ impl Editor {
}
let task = cx.background_spawn(async move {
let new_newlines = snapshot
- .buffer_chars_at(0)
+ .buffer_chars_at(MultiBufferOffset(0))
.filter_map(|(c, i)| {
if c == '\n' {
Some(
snapshot.buffer_snapshot().anchor_after(i)
- ..snapshot.buffer_snapshot().anchor_before(i + 1),
+ ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
)
} else {
None
@@ -7068,7 +7086,7 @@ impl Editor {
})
.collect::<Vec<_>>();
let existing_newlines = snapshot
- .folds_in_range(0..snapshot.buffer_snapshot().len())
+ .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
.filter_map(|fold| {
if fold.placeholder.type_tag == Some(type_id) {
Some(fold.range.start..fold.range.end)
@@ -7165,7 +7183,7 @@ impl Editor {
.is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
{
let multi_buffer_start = multi_buffer_snapshot
- .anchor_before(0)
+ .anchor_before(MultiBufferOffset(0))
.to_point(&multi_buffer_snapshot);
let multi_buffer_end = multi_buffer_snapshot
.anchor_after(multi_buffer_snapshot.len())
@@ -7597,7 +7615,7 @@ impl Editor {
let snapshot = self.buffer.read(cx).snapshot(cx);
let cursor_offset = self
.selections
- .newest::<usize>(&self.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
.head();
let insertion = edits.iter().find_map(|(range, text)| {
let range = range.to_offset(&snapshot);
@@ -8589,16 +8607,17 @@ impl Editor {
let snapshot = self.buffer.read(cx).snapshot(cx);
let offset = self
.selections
- .newest::<usize>(&self.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
.head();
- let excerpt = snapshot.excerpt_containing(offset..offset)?;
+ let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
+ let offset = excerpt.map_offset_to_buffer(offset);
let buffer_id = excerpt.buffer().remote_id();
let layer = excerpt.buffer().syntax_layer_at(offset)?;
let mut cursor = layer.node().walk();
- while cursor.goto_first_child_for_byte(offset).is_some() {
- if cursor.node().end_byte() == offset {
+ while cursor.goto_first_child_for_byte(offset.0).is_some() {
+ if cursor.node().end_byte() == offset.0 {
cursor.goto_next_sibling();
}
}
@@ -8610,7 +8629,7 @@ impl Editor {
let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
// Check if this node contains our offset
- if node_range.start <= offset && node_range.end >= offset {
+ if node_range.start <= offset.0 && node_range.end >= offset.0 {
// If it contains offset, check for task
if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
let buffer = self.buffer.read(cx).buffer(buffer_id)?;
@@ -9812,7 +9831,7 @@ impl Editor {
pub fn insert_snippet(
&mut self,
- insertion_ranges: &[Range<usize>],
+ insertion_ranges: &[Range<MultiBufferOffset>],
snippet: Snippet,
window: &mut Window,
cx: &mut Context<Self>,
@@ -9849,14 +9868,13 @@ impl Editor {
.flat_map(|tabstop_range| {
let mut delta = 0_isize;
insertion_ranges.iter().map(move |insertion_range| {
- let insertion_start = insertion_range.start as isize + delta;
- delta +=
- snippet.text.len() as isize - insertion_range.len() as isize;
-
- let start = ((insertion_start + tabstop_range.start) as usize)
- .min(snapshot.len());
- let end = ((insertion_start + tabstop_range.end) as usize)
- .min(snapshot.len());
+ let insertion_start = insertion_range.start + delta;
+ delta += snippet.text.len() as isize
+ - (insertion_range.end - insertion_range.start) as isize;
+
+ let start =
+ (insertion_start + tabstop_range.start).min(snapshot.len());
+ let end = (insertion_start + tabstop_range.end).min(snapshot.len());
snapshot.anchor_before(start)..snapshot.anchor_after(end)
})
})
@@ -10506,7 +10524,9 @@ impl Editor {
cx,
);
});
- let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
+ let selections = this
+ .selections
+ .all::<MultiBufferOffset>(&this.display_snapshot(cx));
this.change_selections(Default::default(), window, cx, |s| s.select(selections));
});
}
@@ -10523,7 +10543,7 @@ impl Editor {
self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
let selections = self
.selections
- .all::<usize>(&self.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
.into_iter()
.map(|s| s.range());
@@ -10531,7 +10551,9 @@ impl Editor {
this.buffer.update(cx, |buffer, cx| {
buffer.autoindent_ranges(selections, cx);
});
- let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
+ let selections = this
+ .selections
+ .all::<MultiBufferOffset>(&this.display_snapshot(cx));
this.change_selections(Default::default(), window, cx, |s| s.select(selections));
});
}
@@ -10569,7 +10591,7 @@ impl Editor {
} else {
// If there isn't a line after the range, delete the \n from the line before the
// start of the row range
- edit_start = edit_start.saturating_sub(1);
+ edit_start = edit_start.saturating_sub_usize(1);
(buffer.len(), rows.start.previous_row())
};
@@ -10820,7 +10842,9 @@ impl Editor {
boundaries.into_iter()
{
let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
- let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
+ let close_offset = end_after
+ .to_offset(&buffer)
+ .saturating_sub_usize(end_suffix_len);
new_selections.push(open_offset..open_offset);
new_selections.push(close_offset..close_offset);
}
@@ -10850,7 +10874,10 @@ impl Editor {
self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
let mut buffer_ids = HashSet::default();
let snapshot = self.buffer().read(cx).snapshot(cx);
- for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
+ for selection in self
+ .selections
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
+ {
buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
}
@@ -11265,7 +11292,7 @@ impl Editor {
.read(cx)
.base_text()
.as_rope()
- .slice(hunk.diff_base_byte_range.clone());
+ .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
let buffer_snapshot = buffer.snapshot();
let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
@@ -11705,7 +11732,7 @@ impl Editor {
let mut new_selections = Vec::new();
let mut edits = Vec::new();
- let mut selection_adjustment = 0i32;
+ let mut selection_adjustment = 0isize;
for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
let selection_is_empty = selection.is_empty();
@@ -11721,18 +11748,20 @@ impl Editor {
};
let text = buffer.text_for_range(start..end).collect::<String>();
- let old_length = text.len() as i32;
+ let old_length = text.len() as isize;
let text = callback(&text);
new_selections.push(Selection {
- start: (start as i32 - selection_adjustment) as usize,
- end: ((start + text.len()) as i32 - selection_adjustment) as usize,
+ start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
+ end: MultiBufferOffset(
+ ((start.0 + text.len()) as isize - selection_adjustment) as usize,
+ ),
goal: SelectionGoal::None,
id: selection.id,
reversed: selection.reversed,
});
- selection_adjustment += old_length - text.len() as i32;
+ selection_adjustment += old_length - text.len() as isize;
edits.push((start..end, text));
}
@@ -12149,7 +12178,7 @@ impl Editor {
let text_layout_details = &self.text_layout_details(window);
self.transact(window, cx, |this, window, cx| {
let edits = this.change_selections(Default::default(), window, cx, |s| {
- let mut edits: Vec<(Range<usize>, String)> = Default::default();
+ let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
s.move_with(|display_map, selection| {
if !selection.is_empty() {
return;
@@ -12160,10 +12189,10 @@ impl Editor {
if head.column() == display_map.line_len(head.row()) {
transpose_offset = display_map
.buffer_snapshot()
- .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
+ .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
}
- if transpose_offset == 0 {
+ if transpose_offset == MultiBufferOffset(0) {
return;
}
@@ -12178,11 +12207,11 @@ impl Editor {
let transpose_start = display_map
.buffer_snapshot()
- .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
+ .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
let transpose_end = display_map
.buffer_snapshot()
- .clip_offset(transpose_offset + 1, Bias::Right);
+ .clip_offset(transpose_offset + 1usize, Bias::Right);
if let Some(ch) = display_map
.buffer_snapshot()
.chars_at(transpose_start)
@@ -12197,7 +12226,9 @@ impl Editor {
});
this.buffer
.update(cx, |buffer, cx| buffer.edit(edits, None, cx));
- let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
+ let selections = this
+ .selections
+ .all::<MultiBufferOffset>(&this.display_snapshot(cx));
this.change_selections(Default::default(), window, cx, |s| {
s.select(selections);
});
@@ -12804,8 +12835,11 @@ impl Editor {
self.transact(window, cx, |this, window, cx| {
let had_active_edit_prediction = this.has_active_edit_prediction();
let display_map = this.display_snapshot(cx);
- let old_selections = this.selections.all::<usize>(&display_map);
- let cursor_offset = this.selections.last::<usize>(&display_map).head();
+ let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
+ let cursor_offset = this
+ .selections
+ .last::<MultiBufferOffset>(&display_map)
+ .head();
if let Some(mut clipboard_selections) = clipboard_selections {
let all_selections_were_entire_line =
@@ -12890,7 +12924,9 @@ impl Editor {
);
});
- let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
+ let selections = this
+ .selections
+ .all::<MultiBufferOffset>(&this.display_snapshot(cx));
this.change_selections(Default::default(), window, cx, |s| s.select(selections));
} else {
let url = url::Url::parse(&clipboard_text).ok();
@@ -12959,7 +12995,9 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) {
- let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
+ let selections = self
+ .selections
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx));
if selections.is_empty() {
log::warn!("There should always be at least one selection in Zed. This is a bug.");
@@ -14212,7 +14250,7 @@ impl Editor {
}
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
self.change_selections(Default::default(), window, cx, |s| {
- s.select_ranges(vec![0..0]);
+ s.select_ranges(vec![Anchor::min()..Anchor::min()]);
});
}
@@ -14301,7 +14339,9 @@ impl Editor {
pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
let buffer = self.buffer.read(cx).snapshot(cx);
- let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
+ let mut selection = self
+ .selections
+ .first::<MultiBufferOffset>(&self.display_snapshot(cx));
selection.set_head(buffer.len(), SelectionGoal::None);
self.change_selections(Default::default(), window, cx, |s| {
s.select(vec![selection]);
@@ -14310,9 +14350,8 @@ impl Editor {
pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
- let end = self.buffer.read(cx).read(cx).len();
self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges(vec![0..end]);
+ s.select_ranges(vec![Anchor::min()..Anchor::max()]);
});
}
@@ -14572,7 +14611,7 @@ impl Editor {
fn select_match_ranges(
&mut self,
- range: Range<usize>,
+ range: Range<MultiBufferOffset>,
reversed: bool,
replace_newest: bool,
auto_scroll: Option<Autoscroll>,
@@ -14611,7 +14650,7 @@ impl Editor {
cx: &mut Context<Self>,
) -> Result<()> {
let buffer = display_map.buffer_snapshot();
- let mut selections = self.selections.all::<usize>(&display_map);
+ let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
if let Some(mut select_next_state) = self.select_next_state.take() {
let query = &select_next_state.query;
if !select_next_state.done {
@@ -14621,14 +14660,15 @@ impl Editor {
let bytes_after_last_selection =
buffer.bytes_in_range(last_selection.end..buffer.len());
- let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
+ let bytes_before_first_selection =
+ buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
let query_matches = query
.stream_find_iter(bytes_after_last_selection)
.map(|result| (last_selection.end, result))
.chain(
query
.stream_find_iter(bytes_before_first_selection)
- .map(|result| (0, result)),
+ .map(|result| (MultiBufferOffset(0), result)),
);
for (start_offset, query_match) in query_matches {
@@ -14686,7 +14726,7 @@ impl Editor {
}
if let Some(next_selection) = selections_iter.peek() {
- if next_selection.range().len() == selection.range().len() {
+ if next_selection.len() == selection.len() {
let next_selected_text = buffer
.text_for_range(next_selection.range())
.collect::<String>();
@@ -14774,18 +14814,21 @@ impl Editor {
let mut new_selections = Vec::new();
- let reversed = self.selections.oldest::<usize>(&display_map).reversed;
+ let reversed = self
+ .selections
+ .oldest::<MultiBufferOffset>(&display_map)
+ .reversed;
let buffer = display_map.buffer_snapshot();
let query_matches = select_next_state
.query
- .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
+ .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
for query_match in query_matches.into_iter() {
let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
let offset_range = if reversed {
- query_match.end()..query_match.start()
+ MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
} else {
- query_match.start()..query_match.end()
+ MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
};
if !select_next_state.wordwise
@@ -14838,7 +14881,7 @@ impl Editor {
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = display_map.buffer_snapshot();
- let mut selections = self.selections.all::<usize>(&display_map);
+ let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
if let Some(mut select_prev_state) = self.select_prev_state.take() {
let query = &select_prev_state.query;
if !select_prev_state.done {
@@ -14847,7 +14890,7 @@ impl Editor {
let mut next_selected_range = None;
// When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
let bytes_before_last_selection =
- buffer.reversed_bytes_in_range(0..last_selection.start);
+ buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
let bytes_after_first_selection =
buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
let query_matches = query
@@ -14905,7 +14948,7 @@ impl Editor {
}
if let Some(next_selection) = selections_iter.peek() {
- if next_selection.range().len() == selection.range().len() {
+ if next_selection.len() == selection.len() {
let next_selected_text = buffer
.text_for_range(next_selection.range())
.collect::<String>();
@@ -15351,13 +15394,13 @@ impl Editor {
let buffer = self.buffer.read(cx).snapshot(cx);
let old_selections = self
.selections
- .all::<usize>(&self.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
.into_boxed_slice();
fn update_selection(
- selection: &Selection<usize>,
+ selection: &Selection<MultiBufferOffset>,
buffer_snap: &MultiBufferSnapshot,
- ) -> Option<Selection<usize>> {
+ ) -> Option<Selection<MultiBufferOffset>> {
let cursor = selection.head();
let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
for symbol in symbols.iter().rev() {
@@ -15409,7 +15452,7 @@ impl Editor {
};
let old_selections: Box<[_]> = self
.selections
- .all::<usize>(&self.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
.into();
if old_selections.is_empty() {
return;
@@ -15568,7 +15611,7 @@ impl Editor {
let buffer = self.buffer.read(cx).snapshot(cx);
let selections = self
.selections
- .all::<usize>(&self.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
.into_iter()
// subtracting the offset requires sorting
.sorted_by_key(|i| i.start);
@@ -15620,7 +15663,7 @@ impl Editor {
let mut selections = vec![];
for (id, parent, text) in full_edits {
let start = parent.start - offset;
- offset += parent.len() - text.len();
+ offset += (parent.end - parent.start) - text.len();
selections.push(Selection {
id,
start,
@@ -15642,7 +15685,7 @@ impl Editor {
) {
let old_selections: Box<[_]> = self
.selections
- .all::<usize>(&self.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
.into();
if old_selections.is_empty() {
return;
@@ -15658,8 +15701,18 @@ impl Editor {
.map(|selection| {
let old_range = selection.start..selection.end;
- if let Some(node) = buffer.syntax_next_sibling(old_range) {
- let new_range = node.byte_range();
+ let old_range =
+ old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
+ let excerpt = buffer.excerpt_containing(old_range.clone());
+
+ if let Some(mut excerpt) = excerpt
+ && let Some(node) = excerpt
+ .buffer()
+ .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
+ {
+ let new_range = excerpt.map_range_from_buffer(
+ BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
+ );
selected_sibling = true;
Selection {
id: selection.id,
@@ -15694,7 +15747,7 @@ impl Editor {
) {
let old_selections: Box<[_]> = self
.selections
- .all::<usize>(&self.display_snapshot(cx))
+ .all::<MultiBufferOffset>(&self.display_snapshot(cx))
.into();
if old_selections.is_empty() {
return;
@@ -15709,9 +15762,18 @@ impl Editor {
.iter()
.map(|selection| {
let old_range = selection.start..selection.end;
+ let old_range =
+ old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
+ let excerpt = buffer.excerpt_containing(old_range.clone());
- if let Some(node) = buffer.syntax_prev_sibling(old_range) {
- let new_range = node.byte_range();
+ if let Some(mut excerpt) = excerpt
+ && let Some(node) = excerpt
+ .buffer()
+ .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
+ {
+ let new_range = excerpt.map_range_from_buffer(
+ BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
+ );
selected_sibling = true;
Selection {
id: selection.id,
@@ -15860,7 +15922,7 @@ impl Editor {
fn fetch_runnable_ranges(
snapshot: &DisplaySnapshot,
range: Range<Anchor>,
- ) -> Vec<language::RunnableRange> {
+ ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
snapshot.buffer_snapshot().runnable_ranges(range).collect()
}
@@ -15868,12 +15930,12 @@ impl Editor {
project: Entity<Project>,
snapshot: DisplaySnapshot,
prefer_lsp: bool,
- runnable_ranges: Vec<RunnableRange>,
+ runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
cx: AsyncWindowContext,
) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
cx.spawn(async move |cx| {
let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
- for mut runnable in runnable_ranges {
+ for (run_range, mut runnable) in runnable_ranges {
let Some(tasks) = cx
.update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
.ok()
@@ -15891,10 +15953,7 @@ impl Editor {
continue;
}
- let point = runnable
- .run_range
- .start
- .to_point(&snapshot.buffer_snapshot());
+ let point = run_range.start.to_point(&snapshot.buffer_snapshot());
let Some(row) = snapshot
.buffer_snapshot()
.buffer_line_for_row(MultiBufferRow(point.row))
@@ -15909,9 +15968,7 @@ impl Editor {
(runnable.buffer_id, row),
RunnableTasks {
templates: tasks,
- offset: snapshot
- .buffer_snapshot()
- .anchor_before(runnable.run_range.start),
+ offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
context_range,
column: point.column,
extra_variables: runnable.extra_captures,
@@ -15998,7 +16055,7 @@ impl Editor {
let mut best_destination = None;
for (open, close) in enclosing_bracket_ranges {
let close = close.to_inclusive();
- let length = close.end() - open.start;
+ let length = *close.end() - open.start;
let inside = selection.start >= open.end && selection.end <= *close.start();
let in_bracket_range = open.to_inclusive().contains(&selection.head())
|| close.contains(&selection.head());
@@ -16257,7 +16314,9 @@ impl Editor {
cx: &mut Context<Self>,
) {
let buffer = self.buffer.read(cx).snapshot(cx);
- let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
+ let selection = self
+ .selections
+ .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
let mut active_group_id = None;
if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
@@ -16268,8 +16327,8 @@ impl Editor {
fn filtered<'a>(
severity: GoToDiagnosticSeverityFilter,
- diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
- ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
+ diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
+ ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
diagnostics
.filter(move |entry| severity.matches(entry.diagnostic.severity))
.filter(|entry| entry.range.start != entry.range.end)
@@ -16279,7 +16338,7 @@ impl Editor {
let before = filtered(
severity,
buffer
- .diagnostics_in_range(0..selection.start)
+ .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
.filter(|entry| entry.range.start <= selection.start),
);
let after = filtered(
@@ -16289,7 +16348,7 @@ impl Editor {
.filter(|entry| entry.range.start >= selection.start),
);
- let mut found: Option<DiagnosticEntryRef<usize>> = None;
+ let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
if direction == Direction::Prev {
'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
{
@@ -16681,7 +16740,7 @@ impl Editor {
};
let head = self
.selections
- .newest::<usize>(&self.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
.head();
let buffer = self.buffer.read(cx);
let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
@@ -17146,7 +17205,9 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Task<Result<Navigated>>> {
- let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
+ let selection = self
+ .selections
+ .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
let multi_buffer = self.buffer.read(cx);
let head = selection.head();
@@ -17420,7 +17481,8 @@ impl Editor {
this.take_rename(false, window, cx);
let buffer = this.buffer.read(cx).read(cx);
let cursor_offset = selection.head().to_offset(&buffer);
- let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
+ let rename_start =
+ cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
let rename_end = rename_start + rename_buffer_range.len();
let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
let mut old_highlight_id = None;
@@ -17442,8 +17504,16 @@ impl Editor {
let rename_editor = cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.buffer.update(cx, |buffer, cx| {
- buffer.edit([(0..0, old_name.clone())], None, cx)
+ buffer.edit(
+ [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
+ None,
+ cx,
+ )
});
+ let cursor_offset_in_rename_range =
+ MultiBufferOffset(cursor_offset_in_rename_range);
+ let cursor_offset_in_rename_range_end =
+ MultiBufferOffset(cursor_offset_in_rename_range_end);
let rename_selection_range = match cursor_offset_in_rename_range
.cmp(&cursor_offset_in_rename_range_end)
{
@@ -17458,7 +17528,7 @@ impl Editor {
cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
}
};
- if rename_selection_range.end > old_name.len() {
+ if rename_selection_range.end.0 > old_name.len() {
editor.select_all(&SelectAll, window, cx);
} else {
editor.change_selections(Default::default(), window, cx, |s| {
@@ -17623,7 +17693,7 @@ impl Editor {
let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
.head()
});
@@ -17922,7 +17992,7 @@ impl Editor {
let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
let is_valid = buffer
- .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
+ .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
.any(|entry| {
entry.diagnostic.is_primary
&& !entry.range.is_empty()
@@ -17954,7 +18024,7 @@ impl Editor {
fn activate_diagnostics(
&mut self,
buffer_id: BufferId,
- diagnostic: DiagnosticEntryRef<'_, usize>,
+ diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -18146,7 +18216,9 @@ impl Editor {
let new_inline_diagnostics = cx
.background_spawn(async move {
let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
- for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
+ for diagnostic_entry in
+ snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
+ {
let message = diagnostic_entry
.diagnostic
.message
@@ -18525,7 +18597,7 @@ impl Editor {
if self.buffer.read(cx).is_singleton() {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let has_folds = display_map
- .folds_in_range(0..display_map.buffer_snapshot().len())
+ .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
.next()
.is_some();
@@ -18728,7 +18800,10 @@ impl Editor {
let snapshot = self.buffer.read(cx).snapshot(cx);
let ranges = snapshot
- .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
+ .text_object_ranges(
+ MultiBufferOffset(0)..snapshot.len(),
+ TreeSitterOptions::default(),
+ )
.filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
.collect::<Vec<_>>();
@@ -35,7 +35,7 @@ use language_settings::Formatter;
use languages::markdown_lang;
use languages::rust_lang;
use lsp::CompletionParams;
-use multi_buffer::{IndentGuide, PathKey};
+use multi_buffer::{IndentGuide, MultiBufferOffset, MultiBufferOffsetUtf16, PathKey};
use parking_lot::Mutex;
use pretty_assertions::{assert_eq, assert_ne};
use project::{
@@ -197,7 +197,7 @@ fn test_edit_events(cx: &mut TestAppContext) {
// No event is emitted when the mutation is a no-op.
_ = editor2.update(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([0..0])
+ s.select_ranges([MultiBufferOffset(0)..MultiBufferOffset(0)])
});
editor.backspace(&Backspace, window, cx);
@@ -222,7 +222,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
_ = editor.update(cx, |editor, window, cx| {
editor.start_transaction_at(now, window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([2..4])
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(4)])
});
editor.insert("cd", window, cx);
@@ -230,38 +230,46 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "12cd56");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![4..4]
+ vec![MultiBufferOffset(4)..MultiBufferOffset(4)]
);
editor.start_transaction_at(now, window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([4..5])
+ s.select_ranges([MultiBufferOffset(4)..MultiBufferOffset(5)])
});
editor.insert("e", window, cx);
editor.end_transaction_at(now, cx);
assert_eq!(editor.text(cx), "12cde6");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![5..5]
+ vec![MultiBufferOffset(5)..MultiBufferOffset(5)]
);
now += group_interval + Duration::from_millis(1);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([2..2])
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(2)])
});
// Simulate an edit in another editor
buffer.update(cx, |buffer, cx| {
buffer.start_transaction_at(now, cx);
- buffer.edit([(0..1, "a")], None, cx);
- buffer.edit([(1..1, "b")], None, cx);
+ buffer.edit(
+ [(MultiBufferOffset(0)..MultiBufferOffset(1), "a")],
+ None,
+ cx,
+ );
+ buffer.edit(
+ [(MultiBufferOffset(1)..MultiBufferOffset(1), "b")],
+ None,
+ cx,
+ );
buffer.end_transaction_at(now, cx);
});
assert_eq!(editor.text(cx), "ab2cde6");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![3..3]
+ vec![MultiBufferOffset(3)..MultiBufferOffset(3)]
);
// Last transaction happened past the group interval in a different editor.
@@ -270,7 +278,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "12cde6");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![2..2]
+ vec![MultiBufferOffset(2)..MultiBufferOffset(2)]
);
// First two transactions happened within the group interval in this editor.
@@ -280,7 +288,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "123456");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![0..0]
+ vec![MultiBufferOffset(0)..MultiBufferOffset(0)]
);
// Redo the first two transactions together.
@@ -288,7 +296,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "12cde6");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![5..5]
+ vec![MultiBufferOffset(5)..MultiBufferOffset(5)]
);
// Redo the last transaction on its own.
@@ -296,7 +304,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "ab2cde6");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- vec![6..6]
+ vec![MultiBufferOffset(6)..MultiBufferOffset(6)]
);
// Test empty transactions.
@@ -329,7 +337,9 @@ fn test_ime_composition(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "äbcde");
assert_eq!(
editor.marked_text_ranges(cx),
- Some(vec![OffsetUtf16(0)..OffsetUtf16(1)])
+ Some(vec![
+ MultiBufferOffsetUtf16(OffsetUtf16(0))..MultiBufferOffsetUtf16(OffsetUtf16(1))
+ ])
);
// Finalize IME composition.
@@ -349,7 +359,9 @@ fn test_ime_composition(cx: &mut TestAppContext) {
editor.replace_and_mark_text_in_range(Some(0..1), "à", None, window, cx);
assert_eq!(
editor.marked_text_ranges(cx),
- Some(vec![OffsetUtf16(0)..OffsetUtf16(1)])
+ Some(vec![
+ MultiBufferOffsetUtf16(OffsetUtf16(0))..MultiBufferOffsetUtf16(OffsetUtf16(1))
+ ])
);
// Undoing during an IME composition cancels it.
@@ -362,7 +374,9 @@ fn test_ime_composition(cx: &mut TestAppContext) {
assert_eq!(editor.text(cx), "ābcdè");
assert_eq!(
editor.marked_text_ranges(cx),
- Some(vec![OffsetUtf16(4)..OffsetUtf16(5)])
+ Some(vec![
+ MultiBufferOffsetUtf16(OffsetUtf16(4))..MultiBufferOffsetUtf16(OffsetUtf16(5))
+ ])
);
// Finalize IME composition with an invalid replacement range, ensuring it gets clipped.
@@ -373,9 +387,9 @@ fn test_ime_composition(cx: &mut TestAppContext) {
// Start a new IME composition with multiple cursors.
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
s.select_ranges([
- OffsetUtf16(1)..OffsetUtf16(1),
- OffsetUtf16(3)..OffsetUtf16(3),
- OffsetUtf16(5)..OffsetUtf16(5),
+ MultiBufferOffsetUtf16(OffsetUtf16(1))..MultiBufferOffsetUtf16(OffsetUtf16(1)),
+ MultiBufferOffsetUtf16(OffsetUtf16(3))..MultiBufferOffsetUtf16(OffsetUtf16(3)),
+ MultiBufferOffsetUtf16(OffsetUtf16(5))..MultiBufferOffsetUtf16(OffsetUtf16(5)),
])
});
editor.replace_and_mark_text_in_range(Some(4..5), "XYZ", None, window, cx);
@@ -383,9 +397,9 @@ fn test_ime_composition(cx: &mut TestAppContext) {
assert_eq!(
editor.marked_text_ranges(cx),
Some(vec![
- OffsetUtf16(0)..OffsetUtf16(3),
- OffsetUtf16(4)..OffsetUtf16(7),
- OffsetUtf16(8)..OffsetUtf16(11)
+ MultiBufferOffsetUtf16(OffsetUtf16(0))..MultiBufferOffsetUtf16(OffsetUtf16(3)),
+ MultiBufferOffsetUtf16(OffsetUtf16(4))..MultiBufferOffsetUtf16(OffsetUtf16(7)),
+ MultiBufferOffsetUtf16(OffsetUtf16(8))..MultiBufferOffsetUtf16(OffsetUtf16(11))
])
);
@@ -395,9 +409,9 @@ fn test_ime_composition(cx: &mut TestAppContext) {
assert_eq!(
editor.marked_text_ranges(cx),
Some(vec![
- OffsetUtf16(1)..OffsetUtf16(2),
- OffsetUtf16(5)..OffsetUtf16(6),
- OffsetUtf16(9)..OffsetUtf16(10)
+ MultiBufferOffsetUtf16(OffsetUtf16(1))..MultiBufferOffsetUtf16(OffsetUtf16(2)),
+ MultiBufferOffsetUtf16(OffsetUtf16(5))..MultiBufferOffsetUtf16(OffsetUtf16(6)),
+ MultiBufferOffsetUtf16(OffsetUtf16(9))..MultiBufferOffsetUtf16(OffsetUtf16(10))
])
);
@@ -757,7 +771,11 @@ fn test_clone(cx: &mut TestAppContext) {
_ = editor.update(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges(selection_ranges.clone())
+ s.select_ranges(
+ selection_ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
});
editor.fold_creases(
vec![
@@ -794,9 +812,11 @@ fn test_clone(cx: &mut TestAppContext) {
);
assert_eq!(
cloned_snapshot
- .folds_in_range(0..text.len())
+ .folds_in_range(MultiBufferOffset(0)..MultiBufferOffset(text.len()))
+ .collect::<Vec<_>>(),
+ snapshot
+ .folds_in_range(MultiBufferOffset(0)..MultiBufferOffset(text.len()))
.collect::<Vec<_>>(),
- snapshot.folds_in_range(0..text.len()).collect::<Vec<_>>(),
);
assert_set_eq!(
cloned_editor
@@ -1418,7 +1438,11 @@ fn test_fold_at_level(cx: &mut TestAppContext) {
);
editor.change_selections(SelectionEffects::default(), window, cx, |s| {
- s.select_ranges(positions)
+ s.select_ranges(
+ positions
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
});
editor.fold_at_level(&FoldAtLevel(2), window, cx);
@@ -3700,7 +3724,11 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) {
let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx);
let mut editor = build_editor(buffer, window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([3..4, 11..12, 19..20])
+ s.select_ranges([
+ MultiBufferOffset(3)..MultiBufferOffset(4),
+ MultiBufferOffset(11)..MultiBufferOffset(12),
+ MultiBufferOffset(19)..MultiBufferOffset(20),
+ ])
});
editor
});
@@ -3708,12 +3736,24 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) {
_ = editor.update(cx, |editor, window, cx| {
// Edit the buffer directly, deleting ranges surrounding the editor's selections
editor.buffer.update(cx, |buffer, cx| {
- buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], None, cx);
+ buffer.edit(
+ [
+ (MultiBufferOffset(2)..MultiBufferOffset(5), ""),
+ (MultiBufferOffset(10)..MultiBufferOffset(13), ""),
+ (MultiBufferOffset(18)..MultiBufferOffset(21), ""),
+ ],
+ None,
+ cx,
+ );
assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent());
});
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- &[2..2, 7..7, 12..12],
+ &[
+ MultiBufferOffset(2)..MultiBufferOffset(2),
+ MultiBufferOffset(7)..MultiBufferOffset(7),
+ MultiBufferOffset(12)..MultiBufferOffset(12)
+ ],
);
editor.insert("Z", window, cx);
@@ -3722,7 +3762,11 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) {
// The selections are moved after the inserted characters
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- &[3..3, 9..9, 15..15],
+ &[
+ MultiBufferOffset(3)..MultiBufferOffset(3),
+ MultiBufferOffset(9)..MultiBufferOffset(9),
+ MultiBufferOffset(15)..MultiBufferOffset(15)
+ ],
);
});
}
@@ -4692,7 +4736,7 @@ async fn test_custom_newlines_cause_no_false_positive_diffs(
assert_eq!(
snapshot
.buffer_snapshot()
- .diff_hunks_in_range(0..snapshot.buffer_snapshot().len())
+ .diff_hunks_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
.collect::<Vec<_>>(),
Vec::new(),
"Should not have any diffs for files with custom newlines"
@@ -5964,27 +6008,27 @@ fn test_transpose(cx: &mut TestAppContext) {
let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), window, cx);
editor.set_style(EditorStyle::default(), window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1])
+ s.select_ranges([MultiBufferOffset(1)..MultiBufferOffset(1)])
});
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bac");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [2..2]
+ [MultiBufferOffset(2)..MultiBufferOffset(2)]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bca");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [3..3]
+ [MultiBufferOffset(3)..MultiBufferOffset(3)]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bac");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [3..3]
+ [MultiBufferOffset(3)..MultiBufferOffset(3)]
);
editor
@@ -5994,37 +6038,37 @@ fn test_transpose(cx: &mut TestAppContext) {
let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), window, cx);
editor.set_style(EditorStyle::default(), window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([3..3])
+ s.select_ranges([MultiBufferOffset(3)..MultiBufferOffset(3)])
});
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "acb\nde");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [3..3]
+ [MultiBufferOffset(3)..MultiBufferOffset(3)]
);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([4..4])
+ s.select_ranges([MultiBufferOffset(4)..MultiBufferOffset(4)])
});
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "acbd\ne");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [5..5]
+ [MultiBufferOffset(5)..MultiBufferOffset(5)]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "acbde\n");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [6..6]
+ [MultiBufferOffset(6)..MultiBufferOffset(6)]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "acbd\ne");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [6..6]
+ [MultiBufferOffset(6)..MultiBufferOffset(6)]
);
editor
@@ -6034,41 +6078,62 @@ fn test_transpose(cx: &mut TestAppContext) {
let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), window, cx);
editor.set_style(EditorStyle::default(), window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1, 2..2, 4..4])
+ s.select_ranges([
+ MultiBufferOffset(1)..MultiBufferOffset(1),
+ MultiBufferOffset(2)..MultiBufferOffset(2),
+ MultiBufferOffset(4)..MultiBufferOffset(4),
+ ])
});
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bacd\ne");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [2..2, 3..3, 5..5]
+ [
+ MultiBufferOffset(2)..MultiBufferOffset(2),
+ MultiBufferOffset(3)..MultiBufferOffset(3),
+ MultiBufferOffset(5)..MultiBufferOffset(5)
+ ]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bcade\n");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [3..3, 4..4, 6..6]
+ [
+ MultiBufferOffset(3)..MultiBufferOffset(3),
+ MultiBufferOffset(4)..MultiBufferOffset(4),
+ MultiBufferOffset(6)..MultiBufferOffset(6)
+ ]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bcda\ne");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [4..4, 6..6]
+ [
+ MultiBufferOffset(4)..MultiBufferOffset(4),
+ MultiBufferOffset(6)..MultiBufferOffset(6)
+ ]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bcade\n");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [4..4, 6..6]
+ [
+ MultiBufferOffset(4)..MultiBufferOffset(4),
+ MultiBufferOffset(6)..MultiBufferOffset(6)
+ ]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "bcaed\n");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [5..5, 6..6]
+ [
+ MultiBufferOffset(5)..MultiBufferOffset(5),
+ MultiBufferOffset(6)..MultiBufferOffset(6)
+ ]
);
editor
@@ -6078,27 +6143,27 @@ fn test_transpose(cx: &mut TestAppContext) {
let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), window, cx);
editor.set_style(EditorStyle::default(), window, cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([4..4])
+ s.select_ranges([MultiBufferOffset(4)..MultiBufferOffset(4)])
});
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "🏀🍐✋");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [8..8]
+ [MultiBufferOffset(8)..MultiBufferOffset(8)]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "🏀✋🍐");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [11..11]
+ [MultiBufferOffset(11)..MultiBufferOffset(11)]
);
editor.transpose(&Default::default(), window, cx);
assert_eq!(editor.text(cx), "🏀🍐✋");
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- [11..11]
+ [MultiBufferOffset(11)..MultiBufferOffset(11)]
);
editor
@@ -9731,7 +9796,11 @@ async fn test_autoindent(cx: &mut TestAppContext) {
editor.update_in(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([5..5, 8..8, 9..9])
+ s.select_ranges([
+ MultiBufferOffset(5)..MultiBufferOffset(5),
+ MultiBufferOffset(8)..MultiBufferOffset(8),
+ MultiBufferOffset(9)..MultiBufferOffset(9),
+ ])
});
editor.newline(&Newline, window, cx);
assert_eq!(editor.text(cx), "fn a(\n \n) {\n \n}\n");
@@ -9796,7 +9865,11 @@ async fn test_autoindent_disabled(cx: &mut TestAppContext) {
editor.update_in(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([5..5, 8..8, 9..9])
+ s.select_ranges([
+ MultiBufferOffset(5)..MultiBufferOffset(5),
+ MultiBufferOffset(8)..MultiBufferOffset(8),
+ MultiBufferOffset(9)..MultiBufferOffset(9),
+ ])
});
editor.newline(&Newline, window, cx);
assert_eq!(
@@ -10453,7 +10526,7 @@ async fn test_autoclose_with_embedded_language(cx: &mut TestAppContext) {
let snapshot = editor.snapshot(window, cx);
let cursors = editor
.selections
- .ranges::<usize>(&editor.display_snapshot(cx));
+ .ranges::<MultiBufferOffset>(&editor.display_snapshot(cx));
let languages = cursors
.iter()
.map(|c| snapshot.language_at(c.start).unwrap().name())
@@ -11143,17 +11216,26 @@ async fn test_snippet_placeholder_choices(cx: &mut TestAppContext) {
let snippet = Snippet::parse("type ${1|,i32,u32|} = $2").unwrap();
editor
- .insert_snippet(&insertion_ranges, snippet, window, cx)
+ .insert_snippet(
+ &insertion_ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>(),
+ snippet,
+ window,
+ cx,
+ )
.unwrap();
fn assert(editor: &mut Editor, cx: &mut Context<Editor>, marked_text: &str) {
let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false);
assert_eq!(editor.text(cx), expected_text);
assert_eq!(
- editor
- .selections
- .ranges::<usize>(&editor.display_snapshot(cx)),
+ editor.selections.ranges(&editor.display_snapshot(cx)),
selection_ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>()
);
}
@@ -11177,10 +11259,11 @@ async fn test_snippet_tabstop_navigation_with_placeholders(cx: &mut TestAppConte
let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false);
assert_eq!(editor.text(cx), expected_text);
assert_eq!(
- editor
- .selections
- .ranges::<usize>(&editor.display_snapshot(cx)),
+ editor.selections.ranges(&editor.display_snapshot(cx)),
selection_ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>()
);
}
@@ -11198,7 +11281,15 @@ async fn test_snippet_tabstop_navigation_with_placeholders(cx: &mut TestAppConte
let snippet = Snippet::parse("type ${1|,i32,u32|} = $2; $3").unwrap();
editor
- .insert_snippet(&insertion_ranges, snippet, window, cx)
+ .insert_snippet(
+ &insertion_ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>(),
+ snippet,
+ window,
+ cx,
+ )
.unwrap();
assert_state(
@@ -11646,7 +11737,7 @@ async fn test_redo_after_noop_format(cx: &mut TestAppContext) {
});
editor.update_in(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::default(), window, cx, |s| {
- s.select_ranges([0..0])
+ s.select_ranges([MultiBufferOffset(0)..MultiBufferOffset(0)])
});
});
assert!(!cx.read(|cx| editor.is_dirty(cx)));
@@ -11812,7 +11903,7 @@ async fn test_multibuffer_format_during_save(cx: &mut TestAppContext) {
SelectionEffects::scroll(Autoscroll::Next),
window,
cx,
- |s| s.select_ranges(Some(1..2)),
+ |s| s.select_ranges(Some(MultiBufferOffset(1)..MultiBufferOffset(2))),
);
editor.insert("|one|two|three|", window, cx);
});
@@ -11822,7 +11913,7 @@ async fn test_multibuffer_format_during_save(cx: &mut TestAppContext) {
SelectionEffects::scroll(Autoscroll::Next),
window,
cx,
- |s| s.select_ranges(Some(60..70)),
+ |s| s.select_ranges(Some(MultiBufferOffset(60)..MultiBufferOffset(70))),
);
editor.insert("|four|five|six|", window, cx);
});
@@ -11990,7 +12081,7 @@ async fn test_autosave_with_dirty_buffers(cx: &mut TestAppContext) {
SelectionEffects::scroll(Autoscroll::Next),
window,
cx,
- |s| s.select_ranges(Some(10..10)),
+ |s| s.select_ranges(Some(MultiBufferOffset(10)..MultiBufferOffset(10))),
);
editor.insert("// edited", window, cx);
});
@@ -13428,7 +13519,7 @@ async fn test_signature_help(cx: &mut TestAppContext) {
cx.update_editor(|editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([0..0])
+ s.select_ranges([MultiBufferOffset(0)..MultiBufferOffset(0)])
});
});
@@ -16413,7 +16504,11 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
);
assert_eq!(editor.text(cx), expected_text);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges(selection_ranges)
+ s.select_ranges(
+ selection_ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
});
editor.handle_input("X", window, cx);
@@ -16431,6 +16526,9 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
expected_selections
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>()
);
editor.newline(&Newline, window, cx);
@@ -16451,6 +16549,9 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
expected_selections
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>()
);
});
}
@@ -16826,7 +16927,7 @@ async fn test_following(cx: &mut TestAppContext) {
// Update the selections only
_ = leader.update(cx, |leader, window, cx| {
leader.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1])
+ s.select_ranges([MultiBufferOffset(1)..MultiBufferOffset(1)])
});
});
follower
@@ -16844,7 +16945,7 @@ async fn test_following(cx: &mut TestAppContext) {
_ = follower.update(cx, |follower, _, cx| {
assert_eq!(
follower.selections.ranges(&follower.display_snapshot(cx)),
- vec![1..1]
+ vec![MultiBufferOffset(1)..MultiBufferOffset(1)]
);
});
assert!(*is_still_following.borrow());
@@ -16879,7 +16980,7 @@ async fn test_following(cx: &mut TestAppContext) {
// via autoscroll, not via the leader's exact scroll position.
_ = leader.update(cx, |leader, window, cx| {
leader.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([0..0])
+ s.select_ranges([MultiBufferOffset(0)..MultiBufferOffset(0)])
});
leader.request_autoscroll(Autoscroll::newest(), cx);
leader.set_scroll_position(gpui::Point::new(1.5, 3.5), window, cx);
@@ -16900,7 +17001,7 @@ async fn test_following(cx: &mut TestAppContext) {
assert_eq!(follower.scroll_position(cx), gpui::Point::new(1.5, 0.0));
assert_eq!(
follower.selections.ranges(&follower.display_snapshot(cx)),
- vec![0..0]
+ vec![MultiBufferOffset(0)..MultiBufferOffset(0)]
);
});
assert!(*is_still_following.borrow());
@@ -16908,7 +17009,7 @@ async fn test_following(cx: &mut TestAppContext) {
// Creating a pending selection that precedes another selection
_ = leader.update(cx, |leader, window, cx| {
leader.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([1..1])
+ s.select_ranges([MultiBufferOffset(1)..MultiBufferOffset(1)])
});
leader.begin_selection(DisplayPoint::new(DisplayRow(0), 0), true, 1, window, cx);
});
@@ -16927,7 +17028,10 @@ async fn test_following(cx: &mut TestAppContext) {
_ = follower.update(cx, |follower, _, cx| {
assert_eq!(
follower.selections.ranges(&follower.display_snapshot(cx)),
- vec![0..0, 1..1]
+ vec![
+ MultiBufferOffset(0)..MultiBufferOffset(0),
+ MultiBufferOffset(1)..MultiBufferOffset(1)
+ ]
);
});
assert!(*is_still_following.borrow());
@@ -16951,13 +17055,17 @@ async fn test_following(cx: &mut TestAppContext) {
_ = follower.update(cx, |follower, _, cx| {
assert_eq!(
follower.selections.ranges(&follower.display_snapshot(cx)),
- vec![0..2]
+ vec![MultiBufferOffset(0)..MultiBufferOffset(2)]
);
});
// Scrolling locally breaks the follow
_ = follower.update(cx, |follower, window, cx| {
- let top_anchor = follower.buffer().read(cx).read(cx).anchor_after(0);
+ let top_anchor = follower
+ .buffer()
+ .read(cx)
+ .read(cx)
+ .anchor_after(MultiBufferOffset(0));
follower.set_scroll_anchor(
ScrollAnchor {
anchor: top_anchor,
@@ -19451,7 +19559,7 @@ async fn test_multibuffer_in_navigation_history(cx: &mut TestAppContext) {
SelectionEffects::scroll(Autoscroll::Next),
window,
cx,
- |s| s.select_ranges(Some(1..2)),
+ |s| s.select_ranges(Some(MultiBufferOffset(1)..MultiBufferOffset(2))),
);
editor.open_excerpts(&OpenExcerpts, window, cx);
});
@@ -19507,7 +19615,7 @@ async fn test_multibuffer_in_navigation_history(cx: &mut TestAppContext) {
SelectionEffects::scroll(Autoscroll::Next),
window,
cx,
- |s| s.select_ranges(Some(39..40)),
+ |s| s.select_ranges(Some(MultiBufferOffset(39)..MultiBufferOffset(40))),
);
editor.open_excerpts(&OpenExcerpts, window, cx);
});
@@ -19567,7 +19675,7 @@ async fn test_multibuffer_in_navigation_history(cx: &mut TestAppContext) {
SelectionEffects::scroll(Autoscroll::Next),
window,
cx,
- |s| s.select_ranges(Some(70..70)),
+ |s| s.select_ranges(Some(MultiBufferOffset(70)..MultiBufferOffset(70))),
);
editor.open_excerpts(&OpenExcerpts, window, cx);
});
@@ -22357,7 +22465,7 @@ async fn test_find_enclosing_node_with_task(cx: &mut TestAppContext) {
(buffer.read(cx).remote_id(), 3),
RunnableTasks {
templates: vec![],
- offset: snapshot.anchor_before(43),
+ offset: snapshot.anchor_before(MultiBufferOffset(43)),
column: 0,
extra_variables: HashMap::default(),
context_range: BufferOffset(43)..BufferOffset(85),
@@ -22367,7 +22475,7 @@ async fn test_find_enclosing_node_with_task(cx: &mut TestAppContext) {
(buffer.read(cx).remote_id(), 8),
RunnableTasks {
templates: vec![],
- offset: snapshot.anchor_before(86),
+ offset: snapshot.anchor_before(MultiBufferOffset(86)),
column: 0,
extra_variables: HashMap::default(),
context_range: BufferOffset(86)..BufferOffset(191),
@@ -25749,7 +25857,10 @@ fn assert_selection_ranges(marked_text: &str, editor: &mut Editor, cx: &mut Cont
assert_eq!(editor.text(cx), text);
assert_eq!(
editor.selections.ranges(&editor.display_snapshot(cx)),
- ranges,
+ ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>(),
"Assert selections are {}",
marked_text
);
@@ -25995,10 +26106,12 @@ pub fn handle_completion_request(
vec![complete_from_marker.clone(), replace_range_marker.clone()],
);
- let complete_from_position =
- cx.to_lsp(marked_ranges.remove(&complete_from_marker).unwrap()[0].start);
+ let complete_from_position = cx.to_lsp(MultiBufferOffset(
+ marked_ranges.remove(&complete_from_marker).unwrap()[0].start,
+ ));
+ let range = marked_ranges.remove(&replace_range_marker).unwrap()[0].clone();
let replace_range =
- cx.to_lsp_range(marked_ranges.remove(&replace_range_marker).unwrap()[0].clone());
+ cx.to_lsp_range(MultiBufferOffset(range.start)..MultiBufferOffset(range.end));
let mut request =
cx.set_request_handler::<lsp::request::Completion, _, _>(move |url, params, _| {
@@ -26059,13 +26172,18 @@ pub fn handle_completion_request_with_insert_and_replace(
],
);
- let complete_from_position =
- cx.to_lsp(marked_ranges.remove(&complete_from_marker).unwrap()[0].start);
+ let complete_from_position = cx.to_lsp(MultiBufferOffset(
+ marked_ranges.remove(&complete_from_marker).unwrap()[0].start,
+ ));
+ let range = marked_ranges.remove(&replace_range_marker).unwrap()[0].clone();
let replace_range =
- cx.to_lsp_range(marked_ranges.remove(&replace_range_marker).unwrap()[0].clone());
+ cx.to_lsp_range(MultiBufferOffset(range.start)..MultiBufferOffset(range.end));
let insert_range = match marked_ranges.remove(&insert_range_marker) {
- Some(ranges) if !ranges.is_empty() => cx.to_lsp_range(ranges[0].clone()),
+ Some(ranges) if !ranges.is_empty() => {
+ let range1 = ranges[0].clone();
+ cx.to_lsp_range(MultiBufferOffset(range1.start)..MultiBufferOffset(range1.end))
+ }
_ => lsp::Range {
start: replace_range.start,
end: complete_from_position,
@@ -26115,7 +26233,10 @@ fn handle_resolve_completion_request(
.iter()
.map(|(marked_string, new_text)| {
let (_, marked_ranges) = marked_text_ranges(marked_string, false);
- let replace_range = cx.to_lsp_range(marked_ranges[0].clone());
+ let replace_range = cx.to_lsp_range(
+ MultiBufferOffset(marked_ranges[0].start)
+ ..MultiBufferOffset(marked_ranges[0].end),
+ );
lsp::TextEdit::new(replace_range, new_text.to_string())
})
.collect::<Vec<_>>()
@@ -26199,7 +26320,7 @@ fn assert_hunk_revert(
let snapshot = editor.snapshot(window, cx);
let reverted_hunk_statuses = snapshot
.buffer_snapshot()
- .diff_hunks_in_range(0..snapshot.buffer_snapshot().len())
+ .diff_hunks_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
.map(|hunk| hunk.status().kind)
.collect::<Vec<_>>();
@@ -26823,7 +26944,9 @@ async fn test_newline_replacement_in_single_line(cx: &mut TestAppContext) {
editor.update(cx, |editor, cx| {
assert_eq!(editor.display_text(cx), "oops⋯⋯wow⋯");
});
- editor.update(cx, |editor, cx| editor.edit([(3..5, "")], cx));
+ editor.update(cx, |editor, cx| {
+ editor.edit([(MultiBufferOffset(3)..MultiBufferOffset(5), "")], cx)
+ });
cx.run_until_parked();
editor.update(cx, |editor, cx| {
assert_eq!(editor.display_text(cx), "oop⋯wow⋯");
@@ -27895,7 +28018,7 @@ async fn test_multibuffer_selections_with_folding(cx: &mut TestAppContext) {
// Scenario 1: Unfolded buffers, position cursor on "2", select all matches, then insert
cx.update_editor(|editor, window, cx| {
editor.change_selections(None.into(), window, cx, |s| {
- s.select_ranges([2..3]);
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(3)]);
});
});
cx.assert_excerpts_with_selections(indoc! {"
@@ -27952,7 +28075,7 @@ async fn test_multibuffer_selections_with_folding(cx: &mut TestAppContext) {
// Select "2" and select all matches
cx.update_editor(|editor, window, cx| {
editor.change_selections(None.into(), window, cx, |s| {
- s.select_ranges([2..3]);
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(3)]);
});
editor
.select_all_matches(&SelectAllMatches, window, cx)
@@ -28003,7 +28126,7 @@ async fn test_multibuffer_selections_with_folding(cx: &mut TestAppContext) {
// Select "2" and select all matches
cx.update_editor(|editor, window, cx| {
editor.change_selections(None.into(), window, cx, |s| {
- s.select_ranges([2..3]);
+ s.select_ranges([MultiBufferOffset(2)..MultiBufferOffset(3)]);
});
editor
.select_all_matches(&SelectAllMatches, window, cx)
@@ -67,7 +67,7 @@ impl<'a> sum_tree::Dimension<'a, GitBlameEntrySummary> for u32 {
struct GitBlameBuffer {
entries: SumTree<GitBlameEntry>,
buffer_snapshot: BufferSnapshot,
- buffer_edits: text::Subscription,
+ buffer_edits: text::Subscription<usize>,
commit_details: HashMap<Oid, ParsedCommitMessage>,
}
@@ -1,6 +1,7 @@
use crate::{Editor, RangeToAnchorExt};
use gpui::{Context, HighlightStyle, Window};
use language::CursorShape;
+use multi_buffer::MultiBufferOffset;
use theme::ActiveTheme;
enum MatchingBracketHighlight {}
@@ -15,7 +16,7 @@ impl Editor {
let snapshot = self.snapshot(window, cx);
let buffer_snapshot = snapshot.buffer_snapshot();
- let newest_selection = self.selections.newest::<usize>(&snapshot);
+ let newest_selection = self.selections.newest::<MultiBufferOffset>(&snapshot);
// Don't highlight brackets if the selection isn't empty
if !newest_selection.is_empty() {
return;
@@ -738,6 +738,7 @@ mod tests {
use gpui::Modifiers;
use indoc::indoc;
use lsp::request::{GotoDefinition, GotoTypeDefinition};
+ use multi_buffer::MultiBufferOffset;
use settings::InlayHintSettingsContent;
use util::{assert_set_eq, path};
use workspace::item::Item;
@@ -1067,8 +1068,8 @@ mod tests {
.clone();
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);
+ let anchor_range = snapshot.anchor_before(MultiBufferOffset(selection_range.start))
+ ..snapshot.anchor_after(MultiBufferOffset(selection_range.end));
editor.change_selections(Default::default(), window, cx, |s| {
s.set_pending_anchor_range(anchor_range, crate::SelectMode::Character)
});
@@ -1122,7 +1123,7 @@ mod tests {
}
"})[0]
.start;
- let hint_position = cx.to_lsp(hint_start_offset);
+ let hint_position = cx.to_lsp(MultiBufferOffset(hint_start_offset));
let target_range = cx.lsp_range(indoc! {"
struct «TestStruct»;
@@ -1179,8 +1180,8 @@ mod tests {
.unwrap();
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);
+ let previous_valid = MultiBufferOffset(inlay_range.start).to_display_point(&snapshot);
+ let next_valid = MultiBufferOffset(inlay_range.end).to_display_point(&snapshot);
assert_eq!(previous_valid.row(), next_valid.row());
assert!(previous_valid.column() < next_valid.column());
DisplayPoint::new(
@@ -1203,7 +1204,7 @@ mod tests {
let buffer_snapshot = editor.buffer().update(cx, |buffer, cx| buffer.snapshot(cx));
let expected_highlight = InlayHighlight {
inlay: InlayId::Hint(0),
- inlay_position: buffer_snapshot.anchor_after(inlay_range.start),
+ inlay_position: buffer_snapshot.anchor_after(MultiBufferOffset(inlay_range.start)),
range: 0..hint_label.len(),
};
assert_set_eq!(actual_highlights, vec![&expected_highlight]);
@@ -17,7 +17,7 @@ use itertools::Itertools;
use language::{DiagnosticEntry, Language, LanguageRegistry};
use lsp::DiagnosticSeverity;
use markdown::{Markdown, MarkdownElement, MarkdownStyle};
-use multi_buffer::{ToOffset, ToPoint};
+use multi_buffer::{MultiBufferOffset, ToOffset, ToPoint};
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart};
use settings::Settings;
use std::{borrow::Cow, cell::RefCell};
@@ -106,7 +106,7 @@ pub fn find_hovered_hint_part(
hovered_offset: InlayOffset,
) -> Option<(InlayHintLabelPart, Range<InlayOffset>)> {
if hovered_offset >= hint_start {
- let mut hovered_character = (hovered_offset - hint_start).0;
+ let mut hovered_character = hovered_offset - hint_start;
let mut part_start = hint_start;
for part in label_parts {
let part_len = part.value.chars().count();
@@ -316,12 +316,12 @@ fn show_hover(
} else {
snapshot
.buffer_snapshot()
- .diagnostics_with_buffer_ids_in_range::<usize>(offset..offset)
+ .diagnostics_with_buffer_ids_in_range::<MultiBufferOffset>(offset..offset)
.filter(|(_, diagnostic)| {
Some(diagnostic.diagnostic.group_id) != active_group_id
})
// Find the entry with the most specific range
- .min_by_key(|(_, entry)| entry.range.len())
+ .min_by_key(|(_, entry)| entry.range.end - entry.range.start)
};
let diagnostic_popover = if let Some((buffer_id, local_diagnostic)) = local_diagnostic {
@@ -1633,7 +1633,7 @@ mod tests {
}
"})[0]
.start;
- let hint_position = cx.to_lsp(hint_start_offset);
+ let hint_position = cx.to_lsp(MultiBufferOffset(hint_start_offset));
let new_type_target_range = cx.lsp_range(indoc! {"
struct TestStruct;
@@ -1708,8 +1708,8 @@ mod tests {
.unwrap();
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);
+ let previous_valid = MultiBufferOffset(inlay_range.start).to_display_point(&snapshot);
+ let next_valid = MultiBufferOffset(inlay_range.end).to_display_point(&snapshot);
assert_eq!(previous_valid.row(), next_valid.row());
assert!(previous_valid.column() < next_valid.column());
let exact_unclipped = DisplayPoint::new(
@@ -1819,7 +1819,8 @@ mod tests {
popover.symbol_range,
RangeInEditor::Inlay(InlayHighlight {
inlay: InlayId::Hint(0),
- inlay_position: buffer_snapshot.anchor_after(inlay_range.start),
+ inlay_position: buffer_snapshot
+ .anchor_after(MultiBufferOffset(inlay_range.start)),
range: ": ".len()..": ".len() + new_type_label.len(),
}),
"Popover range should match the new type label part"
@@ -1832,8 +1833,8 @@ mod tests {
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);
+ let previous_valid = MultiBufferOffset(inlay_range.start).to_display_point(&snapshot);
+ let next_valid = MultiBufferOffset(inlay_range.end).to_display_point(&snapshot);
assert_eq!(previous_valid.row(), next_valid.row());
assert!(previous_valid.column() < next_valid.column());
let exact_unclipped = DisplayPoint::new(
@@ -1873,7 +1874,8 @@ mod tests {
popover.symbol_range,
RangeInEditor::Inlay(InlayHighlight {
inlay: InlayId::Hint(0),
- inlay_position: buffer_snapshot.anchor_after(inlay_range.start),
+ inlay_position: buffer_snapshot
+ .anchor_after(MultiBufferOffset(inlay_range.start)),
range: ": ".len() + new_type_label.len() + "<".len()
..": ".len() + new_type_label.len() + "<".len() + struct_label.len(),
}),
@@ -645,9 +645,9 @@ impl Editor {
)
{
let highlight_start =
- (part_range.start - hint_start).0 + extra_shift_left;
+ (part_range.start - hint_start) + extra_shift_left;
let highlight_end =
- (part_range.end - hint_start).0 + extra_shift_right;
+ (part_range.end - hint_start) + extra_shift_right;
let highlight = InlayHighlight {
inlay: hovered_hint.id,
inlay_position: hovered_hint.position,
@@ -948,7 +948,7 @@ pub mod tests {
use language::{Language, LanguageConfig, LanguageMatcher};
use languages::rust_lang;
use lsp::FakeLanguageServer;
- use multi_buffer::MultiBuffer;
+ use multi_buffer::{MultiBuffer, MultiBufferOffset};
use parking_lot::Mutex;
use pretty_assertions::assert_eq;
use project::{FakeFs, Project};
@@ -1029,7 +1029,7 @@ pub mod tests {
editor
.update(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input("some change", window, cx);
})
@@ -1429,7 +1429,7 @@ pub mod tests {
rs_editor
.update(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input("some rs change", window, cx);
})
@@ -1461,7 +1461,7 @@ pub mod tests {
md_editor
.update(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input("some md change", window, cx);
})
@@ -1909,7 +1909,7 @@ pub mod tests {
editor
.update(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input(change_after_opening, window, cx);
})
@@ -1955,7 +1955,7 @@ pub mod tests {
task_editor
.update(&mut cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges([13..13])
+ s.select_ranges([MultiBufferOffset(13)..MultiBufferOffset(13)])
});
editor.handle_input(async_later_change, window, cx);
})
@@ -2706,7 +2706,7 @@ let c = 3;"#
let mut editor =
Editor::for_multibuffer(multi_buffer, Some(project.clone()), window, cx);
editor.change_selections(SelectionEffects::default(), window, cx, |s| {
- s.select_ranges([0..0])
+ s.select_ranges([MultiBufferOffset(0)..MultiBufferOffset(0)])
});
editor
});
@@ -21,6 +21,7 @@ use language::{
SelectionGoal, proto::serialize_anchor as serialize_text_anchor,
};
use lsp::DiagnosticSeverity;
+use multi_buffer::MultiBufferOffset;
use project::{
Project, ProjectItem as _, ProjectPath, lsp_store::FormatTrigger,
project_settings::ProjectSettings, search::SearchQuery,
@@ -1735,7 +1736,7 @@ impl SearchableItem for Editor {
let mut ranges = Vec::new();
let search_within_ranges = if search_within_ranges.is_empty() {
- vec![buffer.anchor_before(0)..buffer.anchor_after(buffer.len())]
+ vec![buffer.anchor_before(MultiBufferOffset(0))..buffer.anchor_after(buffer.len())]
} else {
search_within_ranges
};
@@ -1746,7 +1747,10 @@ impl SearchableItem for Editor {
{
ranges.extend(
query
- .search(search_buffer, Some(search_range.clone()))
+ .search(
+ search_buffer,
+ Some(search_range.start.0..search_range.end.0),
+ )
.await
.into_iter()
.map(|match_range| {
@@ -1,7 +1,7 @@
use anyhow::{Context as _, Result, anyhow};
use collections::HashMap;
use gpui::{Context, Entity, Window};
-use multi_buffer::{MultiBuffer, ToOffset};
+use multi_buffer::{BufferOffset, MultiBuffer, ToOffset};
use std::ops::Range;
use util::ResultExt as _;
@@ -546,9 +546,10 @@ pub(crate) fn handle_from(
if edit_range_offset.start != edit_range_offset.end {
continue;
}
- if let Some(selection) =
- buffer_selection_map.get_mut(&(edit_range_offset.start, edit_range_offset.end))
- {
+ if let Some(selection) = buffer_selection_map.get_mut(&(
+ BufferOffset(edit_range_offset.start),
+ BufferOffset(edit_range_offset.end),
+ )) {
if selection.0.head().bias() != text::Bias::Right
|| selection.0.tail().bias() != text::Bias::Right
{
@@ -621,7 +622,7 @@ mod jsx_tag_autoclose_tests {
use super::*;
use gpui::{AppContext as _, TestAppContext};
use languages::language;
- use multi_buffer::ExcerptRange;
+ use multi_buffer::{ExcerptRange, MultiBufferOffset};
use text::Selection;
async fn test_setup(cx: &mut TestAppContext) -> EditorTestContext {
@@ -842,9 +843,9 @@ mod jsx_tag_autoclose_tests {
cx.update_editor(|editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
selections.select(vec![
- Selection::from_offset(4),
- Selection::from_offset(9),
- Selection::from_offset(15),
+ Selection::from_offset(MultiBufferOffset(4)),
+ Selection::from_offset(MultiBufferOffset(9)),
+ Selection::from_offset(MultiBufferOffset(15)),
])
})
});
@@ -1,6 +1,7 @@
use collections::HashMap;
use gpui::{AppContext, Context, Window};
use itertools::Itertools;
+use multi_buffer::MultiBufferOffset;
use std::{ops::Range, time::Duration};
use text::{AnchorRangeExt, BufferId, ToPoint};
use util::ResultExt;
@@ -60,7 +61,9 @@ pub(super) fn refresh_linked_ranges(
editor
.update(cx, |editor, cx| {
let display_snapshot = editor.display_snapshot(cx);
- let selections = editor.selections.all::<usize>(&display_snapshot);
+ let selections = editor
+ .selections
+ .all::<MultiBufferOffset>(&display_snapshot);
let snapshot = display_snapshot.buffer_snapshot();
let buffer = editor.buffer.read(cx);
for selection in selections {
@@ -8,7 +8,7 @@ use crate::{
};
use gpui::{Pixels, WindowTextSystem};
use language::{CharClassifier, Point};
-use multi_buffer::{MultiBufferRow, MultiBufferSnapshot};
+use multi_buffer::{MultiBufferOffset, MultiBufferRow, MultiBufferSnapshot};
use serde::Deserialize;
use workspace::searchable::Direction;
@@ -358,28 +358,28 @@ pub fn adjust_greedy_deletion(
let mut whitespace_sequences = Vec::new();
let mut current_offset = trimmed_delete_range.start;
- let mut whitespace_sequence_length = 0;
- let mut whitespace_sequence_start = 0;
+ let mut whitespace_sequence_length = MultiBufferOffset(0);
+ let mut whitespace_sequence_start = MultiBufferOffset(0);
for ch in map
.buffer_snapshot()
.text_for_range(trimmed_delete_range.clone())
.flat_map(str::chars)
{
if ch.is_whitespace() {
- if whitespace_sequence_length == 0 {
+ if whitespace_sequence_length == MultiBufferOffset(0) {
whitespace_sequence_start = current_offset;
}
whitespace_sequence_length += 1;
} else {
- if whitespace_sequence_length >= 2 {
+ if whitespace_sequence_length >= MultiBufferOffset(2) {
whitespace_sequences.push((whitespace_sequence_start, current_offset));
}
- whitespace_sequence_start = 0;
- whitespace_sequence_length = 0;
+ whitespace_sequence_start = MultiBufferOffset(0);
+ whitespace_sequence_length = MultiBufferOffset(0);
}
current_offset += ch.len_utf8();
}
- if whitespace_sequence_length >= 2 {
+ if whitespace_sequence_length >= MultiBufferOffset(2) {
whitespace_sequences.push((whitespace_sequence_start, current_offset));
}
@@ -731,7 +731,7 @@ pub fn find_preceding_boundary_trail(
}
let trail = trail_offset
- .map(|trail_offset: usize| map.clip_point(trail_offset.to_display_point(map), Bias::Left));
+ .map(|trail_offset| map.clip_point(trail_offset.to_display_point(map), Bias::Left));
(
trail,
@@ -779,7 +779,7 @@ pub fn find_boundary_trail(
}
let trail = trail_offset
- .map(|trail_offset: usize| map.clip_point(trail_offset.to_display_point(map), Bias::Right));
+ .map(|trail_offset| map.clip_point(trail_offset.to_display_point(map), Bias::Right));
(
trail,
@@ -810,8 +810,8 @@ pub fn find_boundary_exclusive(
/// the [`DisplaySnapshot`]. The offsets are relative to the start of a buffer.
pub fn chars_after(
map: &DisplaySnapshot,
- mut offset: usize,
-) -> impl Iterator<Item = (char, Range<usize>)> + '_ {
+ mut offset: MultiBufferOffset,
+) -> impl Iterator<Item = (char, Range<MultiBufferOffset>)> + '_ {
map.buffer_snapshot().chars_at(offset).map(move |ch| {
let before = offset;
offset += ch.len_utf8();
@@ -824,8 +824,8 @@ pub fn chars_after(
/// the [`DisplaySnapshot`]. The offsets are relative to the start of a buffer.
pub fn chars_before(
map: &DisplaySnapshot,
- mut offset: usize,
-) -> impl Iterator<Item = (char, Range<usize>)> + '_ {
+ mut offset: MultiBufferOffset,
+) -> impl Iterator<Item = (char, Range<MultiBufferOffset>)> + '_ {
map.buffer_snapshot()
.reversed_chars_at(offset)
.map(move |ch| {
@@ -1018,8 +1018,9 @@ mod tests {
// add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary
let mut id = 0;
- let inlays = (0..buffer_snapshot.len())
+ let inlays = (0..buffer_snapshot.len().0)
.flat_map(|offset| {
+ let offset = MultiBufferOffset(offset);
[
Inlay::edit_prediction(
post_inc(&mut id),
@@ -1058,7 +1059,7 @@ mod tests {
),
snapshot
.buffer_snapshot()
- .offset_to_point(5)
+ .offset_to_point(MultiBufferOffset(5))
.to_display_point(&snapshot),
"Should not stop at inlays when looking for boundaries"
);
@@ -1,18 +1,18 @@
use std::{
cmp, fmt, iter, mem,
- ops::{Deref, DerefMut, Range, Sub},
+ ops::{AddAssign, Deref, DerefMut, Range, Sub},
sync::Arc,
};
use collections::HashMap;
use gpui::Pixels;
use itertools::Itertools as _;
-use language::{Bias, Point, Selection, SelectionGoal, TextDimension};
+use language::{Bias, Point, Selection, SelectionGoal};
+use multi_buffer::{MultiBufferDimension, MultiBufferOffset};
use util::post_inc;
use crate::{
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBufferSnapshot, SelectMode, ToOffset,
- ToPoint,
display_map::{DisplaySnapshot, ToDisplayPoint},
movement::TextLayoutDetails,
};
@@ -97,7 +97,7 @@ impl SelectionsCollection {
if self.pending.is_none() {
self.disjoint_anchors_arc()
} else {
- let all_offset_selections = self.all::<usize>(snapshot);
+ let all_offset_selections = self.all::<MultiBufferOffset>(snapshot);
all_offset_selections
.into_iter()
.map(|selection| selection_to_anchor_selection(selection, snapshot))
@@ -113,10 +113,10 @@ impl SelectionsCollection {
self.pending.as_mut().map(|pending| &mut pending.selection)
}
- pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
- &self,
- snapshot: &DisplaySnapshot,
- ) -> Option<Selection<D>> {
+ pub fn pending<D>(&self, snapshot: &DisplaySnapshot) -> Option<Selection<D>>
+ where
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
+ {
resolve_selections_wrapping_blocks(self.pending_anchor(), &snapshot).next()
}
@@ -124,9 +124,9 @@ impl SelectionsCollection {
self.pending.as_ref().map(|pending| pending.mode.clone())
}
- pub fn all<'a, D>(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<D>>
+ pub fn all<D>(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<D>>
where
- D: 'a + TextDimension + Ord + Sub<D, Output = D>,
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
{
let disjoint_anchors = &self.disjoint;
let mut disjoint =
@@ -204,13 +204,13 @@ impl SelectionsCollection {
}
}
- pub fn disjoint_in_range<'a, D>(
+ pub fn disjoint_in_range<D>(
&self,
range: Range<Anchor>,
snapshot: &DisplaySnapshot,
) -> Vec<Selection<D>>
where
- D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord + std::fmt::Debug,
{
let start_ix = match self
.disjoint
@@ -267,10 +267,10 @@ impl SelectionsCollection {
.unwrap()
}
- pub fn newest<D: TextDimension + Ord + Sub<D, Output = D>>(
- &self,
- snapshot: &DisplaySnapshot,
- ) -> Selection<D> {
+ pub fn newest<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
+ where
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
+ {
resolve_selections_wrapping_blocks([self.newest_anchor()], &snapshot)
.next()
.unwrap()
@@ -290,10 +290,10 @@ impl SelectionsCollection {
.unwrap()
}
- pub fn oldest<D: TextDimension + Ord + Sub<D, Output = D>>(
- &self,
- snapshot: &DisplaySnapshot,
- ) -> Selection<D> {
+ pub fn oldest<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
+ where
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
+ {
resolve_selections_wrapping_blocks([self.oldest_anchor()], &snapshot)
.next()
.unwrap()
@@ -306,27 +306,27 @@ impl SelectionsCollection {
.unwrap_or_else(|| self.disjoint.first().cloned().unwrap())
}
- pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
- &self,
- snapshot: &DisplaySnapshot,
- ) -> Selection<D> {
+ pub fn first<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
+ where
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
+ {
self.all(snapshot).first().unwrap().clone()
}
- pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
- &self,
- snapshot: &DisplaySnapshot,
- ) -> Selection<D> {
+ pub fn last<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
+ where
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
+ {
self.all(snapshot).last().unwrap().clone()
}
/// Returns a list of (potentially backwards!) ranges representing the selections.
/// Useful for test assertions, but prefer `.all()` instead.
#[cfg(any(test, feature = "test-support"))]
- pub fn ranges<D: TextDimension + Ord + Sub<D, Output = D>>(
- &self,
- snapshot: &DisplaySnapshot,
- ) -> Vec<Range<D>> {
+ pub fn ranges<D>(&self, snapshot: &DisplaySnapshot) -> Vec<Range<D>>
+ where
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
+ {
self.all::<D>(snapshot)
.iter()
.map(|s| {
@@ -509,7 +509,7 @@ impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
};
if filtered_selections.is_empty() {
- let default_anchor = self.snapshot.anchor_before(0);
+ let default_anchor = self.snapshot.anchor_before(MultiBufferOffset(0));
self.collection.disjoint = Arc::from([Selection {
id: post_inc(&mut self.collection.next_selection_id),
start: default_anchor,
@@ -590,7 +590,7 @@ impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
pub fn insert_range<T>(&mut self, range: Range<T>)
where
- T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
+ T: ToOffset,
{
let display_map = self.display_snapshot();
let mut selections = self.collection.all(&display_map);
@@ -656,7 +656,8 @@ impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
let map = self.display_snapshot();
let resolved_selections =
- resolve_selections_wrapping_blocks::<usize, _>(&selections, &map).collect::<Vec<_>>();
+ resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(&selections, &map)
+ .collect::<Vec<_>>();
self.select(resolved_selections);
}
@@ -673,7 +674,7 @@ impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
fn select_offset_ranges<I>(&mut self, ranges: I)
where
- I: IntoIterator<Item = Range<usize>>,
+ I: IntoIterator<Item = Range<MultiBufferOffset>>,
{
let selections = ranges
.into_iter()
@@ -808,13 +809,13 @@ impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
pub fn move_offsets_with(
&mut self,
- mut move_selection: impl FnMut(&MultiBufferSnapshot, &mut Selection<usize>),
+ mut move_selection: impl FnMut(&MultiBufferSnapshot, &mut Selection<MultiBufferOffset>),
) {
let mut changed = false;
let display_map = self.display_snapshot();
let selections = self
.collection
- .all::<usize>(&display_map)
+ .all::<MultiBufferOffset>(&display_map)
.into_iter()
.map(|selection| {
let mut moved_selection = selection.clone();
@@ -938,7 +939,7 @@ impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
let map = self.display_snapshot();
let resolved_selections =
resolve_selections_wrapping_blocks(adjusted_disjoint.iter(), &map).collect();
- self.select::<usize>(resolved_selections);
+ self.select::<MultiBufferOffset>(resolved_selections);
}
if let Some(pending) = pending.as_mut() {
@@ -981,7 +982,7 @@ impl DerefMut for MutableSelectionsCollection<'_, '_> {
}
fn selection_to_anchor_selection(
- selection: Selection<usize>,
+ selection: Selection<MultiBufferOffset>,
buffer: &MultiBufferSnapshot,
) -> Selection<Anchor> {
let end_bias = if selection.start == selection.end {
@@ -1054,7 +1055,7 @@ fn resolve_selections_display<'a>(
coalesce_selections(selections)
}
-/// Resolves the passed in anchors to [`TextDimension`]s `D`
+/// Resolves the passed in anchors to [`MultiBufferDimension`]s `D`
/// wrapping around blocks inbetween.
///
/// # Panics
@@ -1065,7 +1066,7 @@ pub(crate) fn resolve_selections_wrapping_blocks<'a, D, I>(
map: &'a DisplaySnapshot,
) -> impl 'a + Iterator<Item = Selection<D>>
where
- D: TextDimension + Ord + Sub<D, Output = D>,
+ D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
{
// Transforms `Anchor -> DisplayPoint -> Point -> DisplayPoint -> D`
@@ -1,13 +1,13 @@
use crate::actions::ShowSignatureHelp;
use crate::hover_popover::open_markdown_url;
-use crate::{Editor, EditorSettings, ToggleAutoSignatureHelp, hover_markdown_style};
+use crate::{BufferOffset, Editor, EditorSettings, ToggleAutoSignatureHelp, hover_markdown_style};
use gpui::{
App, Context, Entity, HighlightStyle, MouseButton, ScrollHandle, Size, StyledText, Task,
TextStyle, Window, combine_highlights,
};
use language::BufferSnapshot;
use markdown::{Markdown, MarkdownElement};
-use multi_buffer::{Anchor, ToOffset};
+use multi_buffer::{Anchor, MultiBufferOffset, ToOffset};
use settings::Settings;
use std::ops::Range;
use text::Rope;
@@ -82,7 +82,9 @@ impl Editor {
if !(self.signature_help_state.is_shown() || self.auto_signature_help_enabled(cx)) {
return false;
}
- let newest_selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
+ let newest_selection = self
+ .selections
+ .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
let head = newest_selection.head();
if !newest_selection.is_empty() && head != newest_selection.tail() {
@@ -92,14 +94,14 @@ impl Editor {
}
let buffer_snapshot = self.buffer().read(cx).snapshot(cx);
- let bracket_range = |position: usize| match (position, position + 1) {
- (0, b) if b <= buffer_snapshot.len() => 0..b,
- (0, b) => 0..b - 1,
+ let bracket_range = |position: MultiBufferOffset| match (position, position + 1usize) {
+ (MultiBufferOffset(0), b) if b <= buffer_snapshot.len() => MultiBufferOffset(0)..b,
+ (MultiBufferOffset(0), b) => MultiBufferOffset(0)..b - 1,
(a, b) if b <= buffer_snapshot.len() => a - 1..b,
(a, b) => a - 1..b - 1,
};
let not_quote_like_brackets =
- |buffer: &BufferSnapshot, start: Range<usize>, end: Range<usize>| {
+ |buffer: &BufferSnapshot, start: Range<BufferOffset>, end: Range<BufferOffset>| {
let text_start = buffer.text_for_range(start).collect::<String>();
let text_end = buffer.text_for_range(end).collect::<String>();
QUOTE_PAIRS
@@ -16,7 +16,7 @@ use gpui::{
AppContext as _, Context, Entity, EntityId, Font, FontFeatures, FontStyle, FontWeight, Pixels,
VisualTestContext, Window, font, size,
};
-use multi_buffer::ToPoint;
+use multi_buffer::{MultiBufferOffset, ToPoint};
use pretty_assertions::assert_eq;
use project::{Project, project_settings::DiagnosticSeverity};
use ui::{App, BorrowAppContext, px};
@@ -78,7 +78,7 @@ pub fn marked_display_snapshot(
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
let markers = markers
.into_iter()
- .map(|offset| offset.to_display_point(&snapshot))
+ .map(|offset| MultiBufferOffset(offset).to_display_point(&snapshot))
.collect();
(snapshot, markers)
@@ -94,7 +94,11 @@ pub fn select_ranges(
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
assert_eq!(editor.text(cx), unmarked_text);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
- s.select_ranges(text_ranges)
+ s.select_ranges(
+ text_ranges
+ .into_iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
});
}
@@ -108,7 +112,12 @@ pub fn assert_text_with_selections(
assert_eq!(editor.text(cx), unmarked_text, "text doesn't match");
let actual = generate_marked_text(
&editor.text(cx),
- &editor.selections.ranges(&editor.display_snapshot(cx)),
+ &editor
+ .selections
+ .ranges::<MultiBufferOffset>(&editor.display_snapshot(cx))
+ .into_iter()
+ .map(|range| range.start.0..range.end.0)
+ .collect::<Vec<_>>(),
marked_text.contains("«"),
);
assert_eq!(actual, marked_text, "Selections don't match");
@@ -7,6 +7,7 @@ use std::{
use anyhow::Result;
use language::{markdown_lang, rust_lang};
+use multi_buffer::MultiBufferOffset;
use serde_json::json;
use crate::{Editor, ToPoint};
@@ -333,50 +334,38 @@ impl EditorLspTestContext {
#[track_caller]
pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range {
let ranges = self.ranges(marked_text);
- self.to_lsp_range(ranges[0].clone())
+ self.to_lsp_range(MultiBufferOffset(ranges[0].start)..MultiBufferOffset(ranges[0].end))
}
#[expect(clippy::wrong_self_convention, reason = "This is test code")]
- pub fn to_lsp_range(&mut self, range: Range<usize>) -> lsp::Range {
+ pub fn to_lsp_range(&mut self, range: Range<MultiBufferOffset>) -> lsp::Range {
+ use language::ToPointUtf16;
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| {
let buffer = editor.buffer().read(cx);
- let start = point_to_lsp(
- buffer
- .point_to_buffer_offset(start_point, cx)
- .unwrap()
- .1
- .to_point_utf16(&buffer.read(cx)),
- );
- let end = point_to_lsp(
- buffer
- .point_to_buffer_offset(end_point, cx)
- .unwrap()
- .1
- .to_point_utf16(&buffer.read(cx)),
- );
-
+ let (start_buffer, start_offset) =
+ buffer.point_to_buffer_offset(start_point, cx).unwrap();
+ let start = point_to_lsp(start_offset.to_point_utf16(&start_buffer.read(cx)));
+ let (end_buffer, end_offset) = buffer.point_to_buffer_offset(end_point, cx).unwrap();
+ let end = point_to_lsp(end_offset.to_point_utf16(&end_buffer.read(cx)));
lsp::Range { start, end }
})
}
#[expect(clippy::wrong_self_convention, reason = "This is test code")]
- pub fn to_lsp(&mut self, offset: usize) -> lsp::Position {
+ pub fn to_lsp(&mut self, offset: MultiBufferOffset) -> lsp::Position {
+ use language::ToPointUtf16;
+
let snapshot = self.update_editor(|editor, window, cx| editor.snapshot(window, cx));
let point = offset.to_point(&snapshot.buffer_snapshot());
self.editor(|editor, _, cx| {
let buffer = editor.buffer().read(cx);
- point_to_lsp(
- buffer
- .point_to_buffer_offset(point, cx)
- .unwrap()
- .1
- .to_point_utf16(&buffer.read(cx)),
- )
+ let (buffer, offset) = buffer.point_to_buffer_offset(point, cx).unwrap();
+ point_to_lsp(offset.to_point_utf16(&buffer.read(cx)))
})
}
@@ -13,7 +13,7 @@ use gpui::{
};
use itertools::Itertools;
use language::{Buffer, BufferSnapshot, LanguageRegistry};
-use multi_buffer::{Anchor, ExcerptRange, MultiBufferRow};
+use multi_buffer::{Anchor, ExcerptRange, MultiBufferOffset, MultiBufferRow};
use parking_lot::RwLock;
use project::{FakeFs, Project};
use std::{
@@ -267,7 +267,7 @@ impl EditorTestContext {
let snapshot = self.editor.update_in(&mut self.cx, |editor, window, cx| {
editor.snapshot(window, cx)
});
- ranges[0].start.to_display_point(&snapshot)
+ MultiBufferOffset(ranges[0].start).to_display_point(&snapshot)
}
pub fn pixel_position(&mut self, marked_text: &str) -> Point<Pixels> {
@@ -373,7 +373,11 @@ impl EditorTestContext {
self.editor.update_in(&mut self.cx, |editor, window, cx| {
editor.set_text(unmarked_text, window, cx);
editor.change_selections(Default::default(), window, cx, |s| {
- s.select_ranges(selection_ranges)
+ s.select_ranges(
+ selection_ranges
+ .into_iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
})
});
state_context
@@ -390,7 +394,11 @@ impl EditorTestContext {
self.editor.update_in(&mut self.cx, |editor, window, cx| {
assert_eq!(editor.text(cx), unmarked_text);
editor.change_selections(Default::default(), window, cx, |s| {
- s.select_ranges(selection_ranges)
+ s.select_ranges(
+ selection_ranges
+ .into_iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
})
});
state_context
@@ -576,6 +584,7 @@ impl EditorTestContext {
.unwrap_or_default()
.iter()
.map(|range| range.to_offset(&snapshot.buffer_snapshot()))
+ .map(|range| range.start.0..range.end.0)
.collect()
});
assert_set_eq!(actual_ranges, expected_ranges);
@@ -591,6 +600,7 @@ impl EditorTestContext {
.unwrap_or_default()
.into_iter()
.map(|range| range.to_offset(&snapshot.buffer_snapshot()))
+ .map(|range| range.start.0..range.end.0)
.collect();
assert_set_eq!(actual_ranges, expected_ranges);
}
@@ -608,14 +618,16 @@ impl EditorTestContext {
fn editor_selections(&mut self) -> Vec<Range<usize>> {
self.editor
.update(&mut self.cx, |editor, cx| {
- editor.selections.all::<usize>(&editor.display_snapshot(cx))
+ editor
+ .selections
+ .all::<MultiBufferOffset>(&editor.display_snapshot(cx))
})
.into_iter()
.map(|s| {
if s.reversed {
- s.end..s.start
+ s.end.0..s.start.0
} else {
- s.start..s.end
+ s.start.0..s.end.0
}
})
.collect::<Vec<_>>()
@@ -711,7 +723,10 @@ pub fn assert_state_with_diff(
snapshot.buffer_snapshot().clone(),
editor
.selections
- .ranges::<usize>(&snapshot.display_snapshot),
+ .ranges::<MultiBufferOffset>(&snapshot.display_snapshot)
+ .into_iter()
+ .map(|range| range.start.0..range.end.0)
+ .collect::<Vec<_>>(),
)
});
@@ -1,6 +1,9 @@
use anyhow::{Context as _, Result};
use buffer_diff::{BufferDiff, BufferDiffSnapshot};
-use editor::{Editor, EditorEvent, MultiBuffer, SelectionEffects, multibuffer_context_lines};
+use editor::{
+ Editor, EditorEvent, MultiBuffer, MultiBufferOffset, SelectionEffects,
+ multibuffer_context_lines,
+};
use git::repository::{CommitDetails, CommitDiff, RepoPath};
use gpui::{
Action, AnyElement, AnyView, App, AppContext as _, AsyncApp, AsyncWindowContext, Context,
@@ -187,7 +190,7 @@ impl CommitView {
editor.update(cx, |editor, cx| {
editor.disable_header_for_buffer(metadata_buffer_id.unwrap(), cx);
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
- selections.select_ranges(vec![0..0]);
+ selections.select_ranges(vec![MultiBufferOffset(0)..MultiBufferOffset(0)]);
});
});
}
@@ -13,7 +13,8 @@ use anyhow::Context as _;
use askpass::AskPassDelegate;
use db::kvp::KEY_VALUE_STORE;
use editor::{
- Direction, Editor, EditorElement, EditorMode, MultiBuffer, actions::ExpandAllDiffHunks,
+ Direction, Editor, EditorElement, EditorMode, MultiBuffer, MultiBufferOffset,
+ actions::ExpandAllDiffHunks,
};
use futures::StreamExt as _;
use git::blame::ParsedCommitMessage;
@@ -1551,7 +1552,10 @@ impl GitPanel {
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<String> {
- let git_commit_language = self.commit_editor.read(cx).language_at(0, cx);
+ let git_commit_language = self
+ .commit_editor
+ .read(cx)
+ .language_at(MultiBufferOffset(0), cx);
let message = self.commit_editor.read(cx).text(cx);
if message.is_empty() {
return self
@@ -520,7 +520,8 @@ impl ProjectDiff {
if was_empty {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
// TODO select the very beginning (possibly inside a deletion)
- selections.select_ranges([0..0])
+ selections
+ .select_ranges([multi_buffer::Anchor::min()..multi_buffer::Anchor::min()])
});
}
if is_excerpt_newly_added
@@ -446,7 +446,7 @@ impl Render for TextDiffView {
#[cfg(test)]
mod tests {
use super::*;
- use editor::test::editor_test_context::assert_state_with_diff;
+ use editor::{MultiBufferOffset, test::editor_test_context::assert_state_with_diff};
use gpui::{TestAppContext, VisualContext};
use project::{FakeFs, Project};
use serde_json::json;
@@ -691,7 +691,11 @@ mod tests {
let (unmarked_text, selection_ranges) = marked_text_ranges(editor_text, false);
editor.set_text(unmarked_text, window, cx);
editor.change_selections(Default::default(), window, cx, |s| {
- s.select_ranges(selection_ranges)
+ s.select_ranges(
+ selection_ranges
+ .into_iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end)),
+ )
});
editor
@@ -1,4 +1,4 @@
-use editor::{Editor, EditorEvent, MultiBufferSnapshot};
+use editor::{Editor, EditorEvent, MBTextSummary, MultiBufferSnapshot};
use gpui::{App, Entity, FocusHandle, Focusable, Styled, Subscription, Task, WeakEntity};
use settings::{RegisterSetting, Settings};
use std::{fmt::Write, num::NonZeroU32, time::Duration};
@@ -55,7 +55,7 @@ impl UserCaretPosition {
let line_start = Point::new(selection_end.row, 0);
let chars_to_last_position = snapshot
- .text_summary_for_range::<text::TextSummary, _>(line_start..selection_end)
+ .text_summary_for_range::<MBTextSummary, _>(line_start..selection_end)
.chars as u32;
(selection_end.row, chars_to_last_position)
};
@@ -116,7 +116,7 @@ impl CursorPosition {
for selection in editor.selections.all_adjusted(&snapshot) {
let selection_summary = snapshot
.buffer_snapshot()
- .text_summary_for_range::<text::TextSummary, _>(
+ .text_summary_for_range::<MBTextSummary, _>(
selection.start..selection.end,
);
cursor_position.selected_count.characters +=
@@ -159,7 +159,7 @@ pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut Ap
cx,
|s| s.select_ranges([len..len]),
);
- if len > 0 {
+ if len.0 > 0 {
editor.insert("\n\n", window, cx);
}
editor.insert(&entry_heading, window, cx);
@@ -2083,7 +2083,7 @@ impl Buffer {
}
/// Gets a [`Subscription`] that tracks all of the changes to the buffer's text.
- pub fn subscribe(&mut self) -> Subscription {
+ pub fn subscribe(&mut self) -> Subscription<usize> {
self.text.subscribe()
}
@@ -1,6 +1,6 @@
use collections::VecDeque;
use copilot::Copilot;
-use editor::{Editor, EditorEvent, actions::MoveToEnd, scroll::Autoscroll};
+use editor::{Editor, EditorEvent, MultiBufferOffset, actions::MoveToEnd, scroll::Autoscroll};
use gpui::{
AnyView, App, Context, Corner, Entity, EventEmitter, FocusHandle, Focusable, IntoElement,
ParentElement, Render, Styled, Subscription, Task, WeakEntity, Window, actions, div,
@@ -231,7 +231,7 @@ impl LspLogView {
let last_offset = editor.buffer().read(cx).len(cx);
let newest_cursor_is_at_end = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
.start
>= last_offset;
editor.edit(
@@ -1,5 +1,5 @@
use command_palette_hooks::CommandPaletteFilter;
-use editor::{Anchor, Editor, ExcerptId, SelectionEffects, scroll::Autoscroll};
+use editor::{Anchor, Editor, ExcerptId, MultiBufferOffset, SelectionEffects, scroll::Autoscroll};
use gpui::{
App, AppContext as _, Context, Div, Entity, EntityId, EventEmitter, FocusHandle, Focusable,
Hsla, InteractiveElement, IntoElement, MouseButton, MouseDownEvent, MouseMoveEvent,
@@ -254,7 +254,7 @@ impl SyntaxTreeView {
let (buffer, range, excerpt_id) = editor_state.editor.update(cx, |editor, cx| {
let selection_range = editor
.selections
- .last::<usize>(&editor.display_snapshot(cx))
+ .last::<MultiBufferOffset>(&editor.display_snapshot(cx))
.range();
let multi_buffer = editor.buffer().read(cx);
let (buffer, range, excerpt_id) = snapshot
@@ -308,8 +308,8 @@ impl SyntaxTreeView {
// Within the active layer, find the syntax node under the cursor,
// and scroll to it.
let mut cursor = layer.node().walk();
- while cursor.goto_first_child_for_byte(range.start).is_some() {
- if !range.is_empty() && cursor.node().end_byte() == range.start {
+ while cursor.goto_first_child_for_byte(range.start.0).is_some() {
+ if !range.is_empty() && cursor.node().end_byte() == range.start.0 {
cursor.goto_next_sibling();
}
}
@@ -317,7 +317,7 @@ impl SyntaxTreeView {
// Ascend to the smallest ancestor that contains the range.
loop {
let node_range = cursor.node().byte_range();
- if node_range.start <= range.start && node_range.end >= range.end {
+ if node_range.start <= range.start.0 && node_range.end >= range.end.0 {
break;
}
if !cursor.goto_parent() {
@@ -4,7 +4,7 @@ use std::{ops::Range, path::PathBuf};
use anyhow::Result;
use editor::scroll::Autoscroll;
-use editor::{Editor, EditorEvent, SelectionEffects};
+use editor::{Editor, EditorEvent, MultiBufferOffset, SelectionEffects};
use gpui::{
App, ClickEvent, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
IntoElement, IsZero, ListState, ParentElement, Render, RetainAllImageCache, Styled,
@@ -281,7 +281,7 @@ impl MarkdownPreviewView {
let selection_range = editor.update(cx, |editor, cx| {
editor
.selections
- .last::<usize>(&editor.display_snapshot(cx))
+ .last::<MultiBufferOffset>(&editor.display_snapshot(cx))
.range()
});
this.selected_block = this.get_block_index_under_cursor(selection_range);
@@ -358,7 +358,7 @@ impl MarkdownPreviewView {
&self,
window: &mut Window,
cx: &mut Context<Self>,
- selection: Range<usize>,
+ selection: Range<MultiBufferOffset>,
) {
if let Some(state) = &self.active_editor {
state.editor.update(cx, |editor, cx| {
@@ -375,7 +375,7 @@ impl MarkdownPreviewView {
/// The absolute path of the file that is currently being previewed.
fn get_folder_for_active_editor(editor: &Editor, cx: &App) -> Option<PathBuf> {
- if let Some(file) = editor.file_at(0, cx) {
+ if let Some(file) = editor.file_at(MultiBufferOffset(0), cx) {
if let Some(file) = file.as_local() {
file.abs_path(cx).parent().map(|p| p.to_path_buf())
} else {
@@ -386,9 +386,9 @@ impl MarkdownPreviewView {
}
}
- fn get_block_index_under_cursor(&self, selection_range: Range<usize>) -> usize {
+ fn get_block_index_under_cursor(&self, selection_range: Range<MultiBufferOffset>) -> usize {
let mut block_index = None;
- let cursor = selection_range.start;
+ let cursor = selection_range.start.0;
let mut last_end = 0;
if let Some(content) = &self.contents {
@@ -524,7 +524,15 @@ impl Render for MarkdownPreviewView {
if e.checked() { "[x]" } else { "[ ]" };
editor.edit(
- vec![(e.source_range(), task_marker)],
+ vec![(
+ MultiBufferOffset(
+ e.source_range().start,
+ )
+ ..MultiBufferOffset(
+ e.source_range().end,
+ ),
+ task_marker,
+ )],
cx,
);
});
@@ -564,7 +572,8 @@ impl Render for MarkdownPreviewView {
this.move_cursor_to_block(
window,
cx,
- source_range.start..source_range.start,
+ MultiBufferOffset(source_range.start)
+ ..MultiBufferOffset(source_range.start),
);
}
},
@@ -1,8 +1,10 @@
+use crate::{MultiBufferDimension, MultiBufferOffset, MultiBufferOffsetUtf16};
+
use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
-use language::{OffsetUtf16, Point, TextDimension};
+use language::Point;
use std::{
cmp::Ordering,
- ops::{Range, Sub},
+ ops::{AddAssign, Range, Sub},
};
use sum_tree::Bias;
use text::BufferId;
@@ -162,7 +164,11 @@ impl Anchor {
pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
where
- D: TextDimension + Ord + Sub<D, Output = D>,
+ D: MultiBufferDimension
+ + Ord
+ + Sub<Output = D::TextDimension>
+ + AddAssign<D::TextDimension>,
+ D::TextDimension: Sub<Output = D::TextDimension> + Ord,
{
snapshot.summary_for_anchor(self)
}
@@ -182,10 +188,10 @@ impl Anchor {
}
impl ToOffset for Anchor {
- fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
+ fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> MultiBufferOffset {
self.summary(snapshot)
}
- fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
+ fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> MultiBufferOffsetUtf16 {
self.summary(snapshot)
}
}
@@ -203,7 +209,7 @@ pub trait AnchorRangeExt {
fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
fn includes(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
- fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
+ fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<MultiBufferOffset>;
fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
}
@@ -223,7 +229,7 @@ impl AnchorRangeExt for Range<Anchor> {
self.end.cmp(&other.start, buffer).is_ge() && self.start.cmp(&other.end, buffer).is_le()
}
- fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
+ fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<MultiBufferOffset> {
self.start.to_offset(content)..self.end.to_offset(content)
}
@@ -231,6 +237,3 @@ impl AnchorRangeExt for Range<Anchor> {
self.start.to_point(content)..self.end.to_point(content)
}
}
-
-#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
-pub struct Offset(pub usize);
@@ -7,7 +7,7 @@ mod transaction;
use self::transaction::History;
-pub use anchor::{Anchor, AnchorRangeExt, Offset};
+pub use anchor::{Anchor, AnchorRangeExt};
pub use position::{TypedOffset, TypedPoint, TypedRow};
use anyhow::{Result, anyhow};
@@ -43,13 +43,13 @@ use std::{
io,
iter::{self, FromIterator},
mem,
- ops::{Range, RangeBounds, Sub},
+ ops::{self, AddAssign, Range, RangeBounds, Sub},
rc::Rc,
str,
sync::Arc,
time::Duration,
};
-use sum_tree::{Bias, Cursor, Dimension, Dimensions, SumTree, Summary, TreeMap};
+use sum_tree::{Bias, Cursor, Dimension, Dimensions, SumTree, TreeMap};
use text::{
BufferId, Edit, LineIndent, TextSummary,
locator::Locator,
@@ -78,7 +78,7 @@ pub struct MultiBuffer {
paths_by_excerpt: HashMap<ExcerptId, PathKey>,
/// Mapping from buffer IDs to their diff states
diffs: HashMap<BufferId, DiffState>,
- subscriptions: Topic,
+ subscriptions: Topic<MultiBufferOffset>,
/// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
singleton: bool,
/// The history of the multi-buffer.
@@ -138,7 +138,7 @@ pub struct MultiBufferDiffHunk {
/// The excerpt that contains the diff hunk.
pub excerpt_id: ExcerptId,
/// The range within the buffer's diff base that this hunk corresponds to.
- pub diff_base_byte_range: Range<usize>,
+ pub diff_base_byte_range: Range<BufferOffset>,
/// Whether or not this hunk also appears in the 'secondary diff'.
pub secondary_status: DiffHunkSecondaryStatus,
}
@@ -159,7 +159,7 @@ impl MultiBufferDiffHunk {
}
pub fn is_created_file(&self) -> bool {
- self.diff_base_byte_range == (0..0)
+ self.diff_base_byte_range == (BufferOffset(0)..BufferOffset(0))
&& self.buffer_range == (text::Anchor::MIN..text::Anchor::MAX)
}
@@ -183,7 +183,7 @@ impl MultiBufferRow {
pub const MAX: Self = Self(u32::MAX);
}
-impl std::ops::Add<usize> for MultiBufferRow {
+impl ops::Add<usize> for MultiBufferRow {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
@@ -191,9 +191,305 @@ impl std::ops::Add<usize> for MultiBufferRow {
}
}
+pub trait MultiBufferDimension: 'static + Copy + Default + std::fmt::Debug {
+ type TextDimension: TextDimension;
+ fn from_summary(summary: &MBTextSummary) -> Self;
+
+ fn add_text_dim(&mut self, summary: &Self::TextDimension);
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary);
+}
+
+// todo(lw): MultiBufferPoint
+impl MultiBufferDimension for Point {
+ type TextDimension = Point;
+ fn from_summary(summary: &MBTextSummary) -> Self {
+ summary.lines
+ }
+
+ fn add_text_dim(&mut self, other: &Self::TextDimension) {
+ *self += *other;
+ }
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {
+ *self += summary.lines;
+ }
+}
+
+// todo(lw): MultiBufferPointUtf16
+impl MultiBufferDimension for PointUtf16 {
+ type TextDimension = PointUtf16;
+ fn from_summary(summary: &MBTextSummary) -> Self {
+ summary.lines_utf16()
+ }
+
+ fn add_text_dim(&mut self, other: &Self::TextDimension) {
+ *self += *other;
+ }
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {
+ *self += summary.lines_utf16();
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]
+pub struct MultiBufferOffset(pub usize);
+
+impl fmt::Display for MultiBufferOffset {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl rand::distr::uniform::SampleUniform for MultiBufferOffset {
+ type Sampler = MultiBufferOffsetUniformSampler;
+}
+
+pub struct MultiBufferOffsetUniformSampler {
+ sampler: rand::distr::uniform::UniformUsize,
+}
+
+impl rand::distr::uniform::UniformSampler for MultiBufferOffsetUniformSampler {
+ type X = MultiBufferOffset;
+
+ fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, rand::distr::uniform::Error>
+ where
+ B1: rand::distr::uniform::SampleBorrow<Self::X> + Sized,
+ B2: rand::distr::uniform::SampleBorrow<Self::X> + Sized,
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ let sampler = rand::distr::uniform::UniformUsize::new(low.0, high.0);
+ sampler.map(|sampler| MultiBufferOffsetUniformSampler { sampler })
+ }
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, rand::distr::uniform::Error>
+ where
+ B1: rand::distr::uniform::SampleBorrow<Self::X> + Sized,
+ B2: rand::distr::uniform::SampleBorrow<Self::X> + Sized,
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ let sampler = rand::distr::uniform::UniformUsize::new_inclusive(low.0, high.0);
+ sampler.map(|sampler| MultiBufferOffsetUniformSampler { sampler })
+ }
+
+ fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+ MultiBufferOffset(self.sampler.sample(rng))
+ }
+}
+impl MultiBufferDimension for MultiBufferOffset {
+ type TextDimension = usize;
+ fn from_summary(summary: &MBTextSummary) -> Self {
+ summary.len
+ }
+
+ fn add_text_dim(&mut self, other: &Self::TextDimension) {
+ self.0 += *other;
+ }
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {
+ *self += summary.len;
+ }
+}
+impl MultiBufferDimension for MultiBufferOffsetUtf16 {
+ type TextDimension = OffsetUtf16;
+ fn from_summary(summary: &MBTextSummary) -> Self {
+ MultiBufferOffsetUtf16(summary.len_utf16)
+ }
+
+ fn add_text_dim(&mut self, other: &Self::TextDimension) {
+ self.0 += *other;
+ }
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {
+ self.0 += summary.len_utf16;
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]
+pub struct BufferOffset(pub usize);
+
+impl TextDimension for BufferOffset {
+ fn from_text_summary(summary: &TextSummary) -> Self {
+ BufferOffset(usize::from_text_summary(summary))
+ }
+ fn from_chunk(chunk: rope::ChunkSlice) -> Self {
+ BufferOffset(usize::from_chunk(chunk))
+ }
+ fn add_assign(&mut self, other: &Self) {
+ TextDimension::add_assign(&mut self.0, &other.0);
+ }
+}
+impl<'a> sum_tree::Dimension<'a, rope::ChunkSummary> for BufferOffset {
+ fn zero(cx: ()) -> Self {
+ BufferOffset(<usize as sum_tree::Dimension<'a, rope::ChunkSummary>>::zero(cx))
+ }
+
+ fn add_summary(&mut self, summary: &'a rope::ChunkSummary, cx: ()) {
+ usize::add_summary(&mut self.0, summary, cx);
+ }
+}
+
+impl Sub for BufferOffset {
+ type Output = usize;
+
+ fn sub(self, other: BufferOffset) -> Self::Output {
+ self.0 - other.0
+ }
+}
+
+impl AddAssign<DimensionPair<usize, Point>> for BufferOffset {
+ fn add_assign(&mut self, other: DimensionPair<usize, Point>) {
+ self.0 += other.key;
+ }
+}
+
+impl language::ToPoint for BufferOffset {
+ fn to_point(&self, snapshot: &text::BufferSnapshot) -> Point {
+ self.0.to_point(snapshot)
+ }
+}
+
+impl language::ToPointUtf16 for BufferOffset {
+ fn to_point_utf16(&self, snapshot: &text::BufferSnapshot) -> PointUtf16 {
+ self.0.to_point_utf16(snapshot)
+ }
+}
+
+impl language::ToOffset for BufferOffset {
+ fn to_offset(&self, snapshot: &text::BufferSnapshot) -> usize {
+ self.0.to_offset(snapshot)
+ }
+}
+
+impl language::ToOffsetUtf16 for BufferOffset {
+ fn to_offset_utf16(&self, snapshot: &text::BufferSnapshot) -> OffsetUtf16 {
+ self.0.to_offset_utf16(snapshot)
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
+pub struct MultiBufferOffsetUtf16(pub OffsetUtf16);
+
+impl ops::Add<usize> for MultiBufferOffsetUtf16 {
+ type Output = MultiBufferOffsetUtf16;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ MultiBufferOffsetUtf16(OffsetUtf16(self.0.0 + rhs))
+ }
+}
+
+impl AddAssign<OffsetUtf16> for MultiBufferOffsetUtf16 {
+ fn add_assign(&mut self, rhs: OffsetUtf16) {
+ self.0 += rhs;
+ }
+}
+
+impl AddAssign<usize> for MultiBufferOffsetUtf16 {
+ fn add_assign(&mut self, rhs: usize) {
+ self.0.0 += rhs;
+ }
+}
+
+impl Sub for MultiBufferOffsetUtf16 {
+ type Output = OffsetUtf16;
+
+ fn sub(self, other: MultiBufferOffsetUtf16) -> Self::Output {
+ self.0 - other.0
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
+pub struct BufferOffsetUtf16(pub OffsetUtf16);
+
+impl MultiBufferOffset {
+ const ZERO: Self = Self(0);
+ pub fn saturating_sub(self, other: MultiBufferOffset) -> usize {
+ self.0.saturating_sub(other.0)
+ }
+ pub fn saturating_sub_usize(self, other: usize) -> MultiBufferOffset {
+ MultiBufferOffset(self.0.saturating_sub(other))
+ }
+}
+
+impl ops::Sub for MultiBufferOffset {
+ type Output = usize;
+
+ fn sub(self, other: MultiBufferOffset) -> Self::Output {
+ self.0 - other.0
+ }
+}
+
+impl ops::Sub<usize> for MultiBufferOffset {
+ type Output = Self;
+
+ fn sub(self, other: usize) -> Self::Output {
+ MultiBufferOffset(self.0 - other)
+ }
+}
+
+impl ops::SubAssign<usize> for MultiBufferOffset {
+ fn sub_assign(&mut self, other: usize) {
+ self.0 -= other;
+ }
+}
+
+impl ops::Add<usize> for BufferOffset {
+ type Output = Self;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ BufferOffset(self.0 + rhs)
+ }
+}
+
+impl ops::AddAssign<usize> for BufferOffset {
+ fn add_assign(&mut self, other: usize) {
+ self.0 += other;
+ }
+}
+
+impl ops::Add<usize> for MultiBufferOffset {
+ type Output = Self;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ MultiBufferOffset(self.0 + rhs)
+ }
+}
+
+impl ops::AddAssign<usize> for MultiBufferOffset {
+ fn add_assign(&mut self, other: usize) {
+ self.0 += other;
+ }
+}
+
+impl ops::Add<isize> for MultiBufferOffset {
+ type Output = Self;
+
+ fn add(self, rhs: isize) -> Self::Output {
+ MultiBufferOffset((self.0 as isize + rhs) as usize)
+ }
+}
+
+impl ops::Add for MultiBufferOffset {
+ type Output = Self;
+
+ fn add(self, rhs: MultiBufferOffset) -> Self::Output {
+ MultiBufferOffset(self.0 + rhs.0)
+ }
+}
+
+impl ops::AddAssign<MultiBufferOffset> for MultiBufferOffset {
+ fn add_assign(&mut self, other: MultiBufferOffset) {
+ self.0 += other.0;
+ }
+}
+
pub trait ToOffset: 'static + fmt::Debug {
- fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
- fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
+ fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> MultiBufferOffset;
+ fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> MultiBufferOffsetUtf16;
}
pub trait ToPoint: 'static + fmt::Debug {
@@ -255,7 +551,7 @@ pub struct MultiBufferSnapshot {
#[derive(Debug, Clone)]
enum DiffTransform {
BufferContent {
- summary: TextSummary,
+ summary: MBTextSummary,
inserted_hunk_info: Option<DiffTransformHunkInfo>,
},
DeletedHunk {
@@ -370,10 +666,12 @@ struct Excerpt {
#[derive(Clone)]
pub struct MultiBufferExcerpt<'a> {
excerpt: &'a Excerpt,
- diff_transforms: sum_tree::Cursor<'a, 'static, DiffTransform, DiffTransforms<usize>>,
- offset: usize,
- excerpt_offset: ExcerptDimension<usize>,
- buffer_offset: usize,
+ diff_transforms:
+ sum_tree::Cursor<'a, 'static, DiffTransform, DiffTransforms<MultiBufferOffset>>,
+ offset: MultiBufferOffset,
+ // todo unsure about this type
+ excerpt_offset: MultiBufferOffset,
+ buffer_offset: BufferOffset,
}
#[derive(Clone, Debug)]
@@ -408,13 +706,153 @@ pub struct ExcerptSummary {
/// The location of the last [`Excerpt`] being summarized
excerpt_locator: Locator,
widest_line_number: u32,
- text: TextSummary,
+ text: MBTextSummary,
}
#[derive(Debug, Clone)]
pub struct DiffTransformSummary {
- input: TextSummary,
- output: TextSummary,
+ input: MBTextSummary,
+ output: MBTextSummary,
+}
+
+/// Summary of a string of text.
+#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
+pub struct MBTextSummary {
+ /// Length in bytes.
+ pub len: MultiBufferOffset,
+ /// Length in UTF-8.
+ pub chars: usize,
+ /// Length in UTF-16 code units
+ pub len_utf16: OffsetUtf16,
+ /// A point representing the number of lines and the length of the last line.
+ ///
+ /// In other words, it marks the point after the last byte in the text, (if
+ /// EOF was a character, this would be its position).
+ pub lines: Point,
+ /// How many `char`s are in the first line
+ pub first_line_chars: u32,
+ /// How many `char`s are in the last line
+ pub last_line_chars: u32,
+ /// How many UTF-16 code units are in the last line
+ pub last_line_len_utf16: u32,
+ /// The row idx of the longest row
+ pub longest_row: u32,
+ /// How many `char`s are in the longest row
+ pub longest_row_chars: u32,
+}
+
+impl From<TextSummary> for MBTextSummary {
+ fn from(summary: TextSummary) -> Self {
+ MBTextSummary {
+ len: MultiBufferOffset(summary.len),
+ chars: summary.chars,
+ len_utf16: summary.len_utf16,
+ lines: summary.lines,
+ first_line_chars: summary.first_line_chars,
+ last_line_chars: summary.last_line_chars,
+ last_line_len_utf16: summary.last_line_len_utf16,
+ longest_row: summary.longest_row,
+ longest_row_chars: summary.longest_row_chars,
+ }
+ }
+}
+impl From<&str> for MBTextSummary {
+ fn from(text: &str) -> Self {
+ MBTextSummary::from(TextSummary::from(text))
+ }
+}
+
+impl MultiBufferDimension for MBTextSummary {
+ type TextDimension = TextSummary;
+
+ fn from_summary(summary: &MBTextSummary) -> Self {
+ *summary
+ }
+
+ fn add_text_dim(&mut self, summary: &Self::TextDimension) {
+ *self += *summary;
+ }
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {
+ *self += *summary;
+ }
+}
+
+impl AddAssign for MBTextSummary {
+ fn add_assign(&mut self, other: MBTextSummary) {
+ let joined_chars = self.last_line_chars + other.first_line_chars;
+ if joined_chars > self.longest_row_chars {
+ self.longest_row = self.lines.row;
+ self.longest_row_chars = joined_chars;
+ }
+ if other.longest_row_chars > self.longest_row_chars {
+ self.longest_row = self.lines.row + other.longest_row;
+ self.longest_row_chars = other.longest_row_chars;
+ }
+
+ if self.lines.row == 0 {
+ self.first_line_chars += other.first_line_chars;
+ }
+
+ if other.lines.row == 0 {
+ self.last_line_chars += other.first_line_chars;
+ self.last_line_len_utf16 += other.last_line_len_utf16;
+ } else {
+ self.last_line_chars = other.last_line_chars;
+ self.last_line_len_utf16 = other.last_line_len_utf16;
+ }
+
+ self.chars += other.chars;
+ self.len += other.len;
+ self.len_utf16 += other.len_utf16;
+ self.lines += other.lines;
+ }
+}
+
+impl AddAssign<TextSummary> for MBTextSummary {
+ fn add_assign(&mut self, other: TextSummary) {
+ *self += MBTextSummary::from(other);
+ }
+}
+
+impl MBTextSummary {
+ pub fn lines_utf16(&self) -> PointUtf16 {
+ PointUtf16 {
+ row: self.lines.row,
+ column: self.last_line_len_utf16,
+ }
+ }
+}
+
+impl<K, V> MultiBufferDimension for DimensionPair<K, V>
+where
+ K: MultiBufferDimension,
+ V: MultiBufferDimension,
+{
+ type TextDimension = DimensionPair<K::TextDimension, V::TextDimension>;
+
+ fn from_summary(summary: &MBTextSummary) -> Self {
+ Self {
+ key: K::from_summary(summary),
+ value: Some(V::from_summary(summary)),
+ }
+ }
+
+ fn add_text_dim(&mut self, summary: &Self::TextDimension) {
+ self.key.add_text_dim(&summary.key);
+ if let Some(value) = &mut self.value {
+ if let Some(other_value) = summary.value.as_ref() {
+ value.add_text_dim(other_value);
+ }
+ }
+ }
+
+ fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {
+ self.key.add_mb_text_summary(summary);
+ if let Some(value) = &mut self.value {
+ value.add_mb_text_summary(summary);
+ }
+ }
}
#[derive(Clone)]
@@ -422,53 +860,54 @@ pub struct MultiBufferRows<'a> {
point: Point,
is_empty: bool,
is_singleton: bool,
- cursor: MultiBufferCursor<'a, Point>,
+ cursor: MultiBufferCursor<'a, Point, Point>,
}
pub struct MultiBufferChunks<'a> {
excerpts: Cursor<'a, 'static, Excerpt, ExcerptOffset>,
- diff_transforms: Cursor<'a, 'static, DiffTransform, Dimensions<usize, ExcerptOffset>>,
+ diff_transforms:
+ Cursor<'a, 'static, DiffTransform, Dimensions<MultiBufferOffset, ExcerptOffset>>,
diffs: &'a TreeMap<BufferId, BufferDiffSnapshot>,
diff_base_chunks: Option<(BufferId, BufferChunks<'a>)>,
buffer_chunk: Option<Chunk<'a>>,
- range: Range<usize>,
+ range: Range<MultiBufferOffset>,
excerpt_offset_range: Range<ExcerptOffset>,
excerpt_chunks: Option<ExcerptChunks<'a>>,
language_aware: bool,
}
pub struct ReversedMultiBufferChunks<'a> {
- cursor: MultiBufferCursor<'a, usize>,
+ cursor: MultiBufferCursor<'a, MultiBufferOffset, BufferOffset>,
current_chunks: Option<rope::Chunks<'a>>,
- start: usize,
- offset: usize,
+ start: MultiBufferOffset,
+ offset: MultiBufferOffset,
}
pub struct MultiBufferBytes<'a> {
- range: Range<usize>,
- cursor: MultiBufferCursor<'a, usize>,
+ range: Range<MultiBufferOffset>,
+ cursor: MultiBufferCursor<'a, MultiBufferOffset, BufferOffset>,
excerpt_bytes: Option<text::Bytes<'a>>,
has_trailing_newline: bool,
chunk: &'a [u8],
}
pub struct ReversedMultiBufferBytes<'a> {
- range: Range<usize>,
+ range: Range<MultiBufferOffset>,
chunks: ReversedMultiBufferChunks<'a>,
chunk: &'a [u8],
}
#[derive(Clone)]
-struct DiffTransforms<D> {
- output_dimension: OutputDimension<D>,
- excerpt_dimension: ExcerptDimension<D>,
+struct DiffTransforms<MBD> {
+ output_dimension: OutputDimension<MBD>,
+ excerpt_dimension: ExcerptDimension<MBD>,
}
-impl<'a, D: TextDimension> Dimension<'a, DiffTransformSummary> for DiffTransforms<D> {
+impl<'a, MBD: MultiBufferDimension> Dimension<'a, DiffTransformSummary> for DiffTransforms<MBD> {
fn zero(cx: <DiffTransformSummary as sum_tree::Summary>::Context<'_>) -> Self {
Self {
output_dimension: OutputDimension::zero(cx),
- excerpt_dimension: <ExcerptDimension<D> as Dimension<'a, DiffTransformSummary>>::zero(
+ excerpt_dimension: <ExcerptDimension<MBD> as Dimension<'a, DiffTransformSummary>>::zero(
cx,
),
}
@@ -485,21 +924,21 @@ impl<'a, D: TextDimension> Dimension<'a, DiffTransformSummary> for DiffTransform
}
#[derive(Clone)]
-struct MultiBufferCursor<'a, D: TextDimension> {
- excerpts: Cursor<'a, 'static, Excerpt, ExcerptDimension<D>>,
- diff_transforms: Cursor<'a, 'static, DiffTransform, DiffTransforms<D>>,
+struct MultiBufferCursor<'a, MBD, BD> {
+ excerpts: Cursor<'a, 'static, Excerpt, ExcerptDimension<MBD>>,
+ diff_transforms: Cursor<'a, 'static, DiffTransform, DiffTransforms<MBD>>,
diffs: &'a TreeMap<BufferId, BufferDiffSnapshot>,
- cached_region: Option<MultiBufferRegion<'a, D>>,
+ cached_region: Option<MultiBufferRegion<'a, MBD, BD>>,
}
#[derive(Clone)]
-struct MultiBufferRegion<'a, D: TextDimension> {
+struct MultiBufferRegion<'a, MBD, BD> {
buffer: &'a BufferSnapshot,
is_main_buffer: bool,
diff_hunk_status: Option<DiffHunkStatus>,
excerpt: &'a Excerpt,
- buffer_range: Range<D>,
- range: Range<D>,
+ buffer_range: Range<BD>,
+ range: Range<MBD>,
has_trailing_newline: bool,
}
@@ -511,7 +950,7 @@ struct ExcerptChunks<'a> {
#[derive(Debug)]
struct BufferEdit {
- range: Range<usize>,
+ range: Range<BufferOffset>,
new_text: Arc<str>,
is_insertion: bool,
original_indent_column: Option<u32>,
@@ -693,7 +1132,7 @@ impl MultiBuffer {
self.singleton
}
- pub fn subscribe(&mut self) -> Subscription {
+ pub fn subscribe(&mut self) -> Subscription<MultiBufferOffset> {
self.subscriptions.subscribe()
}
@@ -711,7 +1150,7 @@ impl MultiBuffer {
// The `is_empty` signature doesn't match what clippy expects
#[allow(clippy::len_without_is_empty)]
- pub fn len(&self, cx: &App) -> usize {
+ pub fn len(&self, cx: &App) -> MultiBufferOffset {
self.read(cx).len()
}
@@ -750,7 +1189,7 @@ impl MultiBuffer {
// Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
fn edit_internal(
this: &mut MultiBuffer,
- edits: Vec<(Range<usize>, Arc<str>)>,
+ edits: Vec<(Range<MultiBufferOffset>, Arc<str>)>,
mut autoindent_mode: Option<AutoindentMode>,
cx: &mut Context<MultiBuffer>,
) {
@@ -849,13 +1288,13 @@ impl MultiBuffer {
}
fn convert_edits_to_buffer_edits(
- edits: Vec<(Range<usize>, Arc<str>)>,
+ edits: Vec<(Range<MultiBufferOffset>, Arc<str>)>,
snapshot: &MultiBufferSnapshot,
original_indent_columns: &[Option<u32>],
) -> (HashMap<BufferId, Vec<BufferEdit>>, Vec<ExcerptId>) {
let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
let mut edited_excerpt_ids = Vec::new();
- let mut cursor = snapshot.cursor::<usize>();
+ let mut cursor = snapshot.cursor::<MultiBufferOffset, BufferOffset>();
for (ix, (range, new_text)) in edits.into_iter().enumerate() {
let original_indent_column = original_indent_columns.get(ix).copied().flatten();
@@ -994,7 +1433,7 @@ impl MultiBuffer {
fn autoindent_ranges_internal(
this: &mut MultiBuffer,
- edits: Vec<(Range<usize>, Arc<str>)>,
+ edits: Vec<(Range<MultiBufferOffset>, Arc<str>)>,
cx: &mut Context<MultiBuffer>,
) {
let (buffer_edits, edited_excerpt_ids) =
@@ -1005,7 +1444,7 @@ impl MultiBuffer {
buffer_ids.push(buffer_id);
edits.sort_unstable_by_key(|edit| edit.range.start);
- let mut ranges: Vec<Range<usize>> = Vec::new();
+ let mut ranges: Vec<Range<BufferOffset>> = Vec::new();
for edit in edits {
if let Some(last_range) = ranges.last_mut()
&& edit.range.start <= last_range.end
@@ -1243,7 +1682,7 @@ impl MultiBuffer {
let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right);
prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone();
- let edit_start = ExcerptOffset::new(new_excerpts.summary().text.len);
+ let edit_start = ExcerptOffset::new(new_excerpts.summary().text.len.0);
new_excerpts.update_last(
|excerpt| {
excerpt.has_trailing_newline = true;
@@ -1287,7 +1726,7 @@ impl MultiBuffer {
new_excerpt_ids.push(ExcerptIdMapping { id, locator }, ());
}
- let edit_end = ExcerptOffset::new(new_excerpts.summary().text.len);
+ let edit_end = ExcerptOffset::new(new_excerpts.summary().text.len.0);
let suffix = cursor.suffix();
let changed_trailing_excerpt = suffix.is_empty();
@@ -1345,7 +1784,7 @@ impl MultiBuffer {
show_headers: _,
} = self.snapshot.get_mut();
let start = ExcerptOffset::new(0);
- let prev_len = ExcerptOffset::new(excerpts.summary().text.len);
+ let prev_len = ExcerptOffset::new(excerpts.summary().text.len.0);
*excerpts = Default::default();
*trailing_excerpt_update_count += 1;
*is_dirty = false;
@@ -1416,7 +1855,7 @@ impl MultiBuffer {
if let Some(excerpt) = excerpts.item()
&& excerpt.locator == *locator
{
- let excerpt_start = excerpts.start().1.clone();
+ let excerpt_start = excerpts.start().1;
let excerpt_end = ExcerptDimension(excerpt_start.0 + excerpt.text_summary.lines);
diff_transforms.seek_forward(&excerpt_start, Bias::Left);
@@ -1459,7 +1898,7 @@ impl MultiBuffer {
let snapshot = self.read(cx);
let offset = position.to_offset(&snapshot);
- let mut cursor = snapshot.cursor::<usize>();
+ let mut cursor = snapshot.cursor::<MultiBufferOffset, BufferOffset>();
cursor.seek(&offset);
cursor
.excerpt()
@@ -1487,7 +1926,7 @@ impl MultiBuffer {
&self,
point: T,
cx: &App,
- ) -> Option<(Entity<Buffer>, usize)> {
+ ) -> Option<(Entity<Buffer>, BufferOffset)> {
let snapshot = self.read(cx);
let (buffer, offset) = snapshot.point_to_buffer_offset(point)?;
Some((
@@ -1631,7 +2070,7 @@ impl MultiBuffer {
// Push an edit for the removal of this run of excerpts.
let old_end = cursor.start().1;
- let new_start = ExcerptOffset::new(new_excerpts.summary().text.len);
+ let new_start = ExcerptOffset::new(new_excerpts.summary().text.len.0);
edits.push(Edit {
old: old_start..old_end,
new: new_start..new_start,
@@ -1855,7 +2294,7 @@ impl MultiBuffer {
let buffer = buffer.read(cx);
language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
})
- .unwrap_or_else(move || self.language_settings_at(0, cx))
+ .unwrap_or_else(move || self.language_settings_at(MultiBufferOffset::default(), cx))
}
pub fn language_settings_at<'a, T: ToOffset>(
@@ -2007,7 +2446,7 @@ impl MultiBuffer {
pub fn single_hunk_is_expanded(&self, range: Range<Anchor>, cx: &App) -> bool {
let snapshot = self.read(cx);
- let mut cursor = snapshot.diff_transforms.cursor::<usize>(());
+ let mut cursor = snapshot.diff_transforms.cursor::<MultiBufferOffset>(());
let offset_range = range.to_offset(&snapshot);
cursor.seek(&offset_range.start, Bias::Left);
while let Some(item) = cursor.item() {
@@ -2024,13 +2463,13 @@ impl MultiBuffer {
pub fn has_expanded_diff_hunks_in_ranges(&self, ranges: &[Range<Anchor>], cx: &App) -> bool {
let snapshot = self.read(cx);
- let mut cursor = snapshot.diff_transforms.cursor::<usize>(());
+ let mut cursor = snapshot.diff_transforms.cursor::<MultiBufferOffset>(());
for range in ranges {
let range = range.to_point(&snapshot);
let start = snapshot.point_to_offset(Point::new(range.start.row, 0));
let end = snapshot.point_to_offset(Point::new(range.end.row + 1, 0));
- let start = start.saturating_sub(1);
- let end = snapshot.len().min(end + 1);
+ let start = start.saturating_sub_usize(1);
+ let end = snapshot.len().min(end + 1usize);
cursor.seek(&start, Bias::Right);
while let Some(item) = cursor.item() {
if *cursor.start() >= end {
@@ -2149,7 +2588,7 @@ impl MultiBuffer {
.buffer
.text_summary_for_range(excerpt.range.context.clone());
- let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
+ let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len.0);
let old_start_offset = cursor.start().1;
let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
let edit = Edit {
@@ -2255,7 +2694,7 @@ impl MultiBuffer {
.buffer
.text_summary_for_range(excerpt.range.context.clone());
- let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
+ let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len.0);
let old_start_offset = cursor.start().1;
let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
let edit = Edit {
@@ -2328,7 +2767,7 @@ impl MultiBuffer {
buffers: &HashMap<BufferId, BufferState>,
diffs: &HashMap<BufferId, DiffState>,
cx: &App,
- ) -> Vec<Edit<usize>> {
+ ) -> Vec<Edit<MultiBufferOffset>> {
let MultiBufferSnapshot {
excerpts,
diffs: buffer_diff,
@@ -2417,7 +2856,7 @@ impl MultiBuffer {
.map(|edit| {
let excerpt_old_start = cursor.start().1;
let excerpt_new_start =
- ExcerptOffset::new(new_excerpts.summary().text.len);
+ ExcerptOffset::new(new_excerpts.summary().text.len.0);
let old_start = excerpt_old_start + ExcerptOffset::new(edit.old.start);
let old_end = excerpt_old_start + ExcerptOffset::new(edit.old.end);
let new_start = excerpt_new_start + ExcerptOffset::new(edit.new.start);
@@ -2456,7 +2895,7 @@ impl MultiBuffer {
snapshot: &mut MultiBufferSnapshot,
excerpt_edits: Vec<text::Edit<ExcerptOffset>>,
change_kind: DiffChangeKind,
- ) -> Vec<Edit<usize>> {
+ ) -> Vec<Edit<MultiBufferOffset>> {
if excerpt_edits.is_empty() {
return vec![];
}
@@ -2464,7 +2903,7 @@ impl MultiBuffer {
let mut excerpts = snapshot.excerpts.cursor::<ExcerptOffset>(());
let mut old_diff_transforms = snapshot
.diff_transforms
- .cursor::<Dimensions<ExcerptOffset, usize>>(());
+ .cursor::<Dimensions<ExcerptOffset, MultiBufferOffset>>(());
let mut new_diff_transforms = SumTree::default();
let mut old_expanded_hunks = HashSet::default();
let mut output_edits = Vec::new();
@@ -2496,7 +2935,8 @@ impl MultiBuffer {
// Compute the start of the edit in output coordinates.
let edit_start_overshoot = (edit.old.start - old_diff_transforms.start().0).value;
let edit_old_start = old_diff_transforms.start().1 + edit_start_overshoot;
- let edit_new_start = (edit_old_start as isize + output_delta) as usize;
+ let edit_new_start =
+ MultiBufferOffset((edit_old_start.0 as isize + output_delta) as usize);
let changed_diff_hunks = Self::recompute_diff_transforms_for_edit(
&edit,
@@ -2588,7 +3028,10 @@ impl MultiBuffer {
fn recompute_diff_transforms_for_edit(
edit: &Edit<TypedOffset<Excerpt>>,
excerpts: &mut Cursor<Excerpt, TypedOffset<Excerpt>>,
- old_diff_transforms: &mut Cursor<DiffTransform, Dimensions<TypedOffset<Excerpt>, usize>>,
+ old_diff_transforms: &mut Cursor<
+ DiffTransform,
+ Dimensions<TypedOffset<Excerpt>, MultiBufferOffset>,
+ >,
new_diff_transforms: &mut SumTree<DiffTransform>,
end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, DiffTransformHunkInfo)>,
old_expanded_hunks: &mut HashSet<DiffTransformHunkInfo>,
@@ -2807,7 +3250,7 @@ impl MultiBuffer {
continue;
}
let summary_to_add = old_snapshot
- .text_summary_for_excerpt_offset_range::<TextSummary>(start_offset..end_offset);
+ .text_summary_for_excerpt_offset_range::<MBTextSummary>(start_offset..end_offset);
if !Self::extend_last_buffer_content_transform(
new_transforms,
@@ -2828,7 +3271,7 @@ impl MultiBuffer {
fn extend_last_buffer_content_transform(
new_transforms: &mut SumTree<DiffTransform>,
new_inserted_hunk_info: Option<DiffTransformHunkInfo>,
- summary_to_add: TextSummary,
+ summary_to_add: MBTextSummary,
) -> bool {
let mut did_extend = false;
new_transforms.update_last(
@@ -2914,14 +3357,14 @@ impl MultiBuffer {
use util::RandomCharIter;
let snapshot = self.read(cx);
- let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
+ let mut edits: Vec<(Range<MultiBufferOffset>, Arc<str>)> = Vec::new();
let mut last_end = None;
for _ in 0..edit_count {
if last_end.is_some_and(|last_end| last_end >= snapshot.len()) {
break;
}
- let new_start = last_end.map_or(0, |last_end| last_end + 1);
+ let new_start = last_end.map_or(MultiBufferOffset::ZERO, |last_end| last_end + 1usize);
let end =
snapshot.clip_offset(rng.random_range(new_start..=snapshot.len()), Bias::Right);
let start = snapshot.clip_offset(rng.random_range(new_start..=end), Bias::Right);
@@ -3078,18 +3521,21 @@ impl EventEmitter<Event> for MultiBuffer {}
impl MultiBufferSnapshot {
pub fn text(&self) -> String {
- self.chunks(0..self.len(), false)
+ self.chunks(MultiBufferOffset::ZERO..self.len(), false)
.map(|chunk| chunk.text)
.collect()
}
pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
- self.reversed_chunks_in_range(0..position.to_offset(self))
+ self.reversed_chunks_in_range(MultiBufferOffset::ZERO..position.to_offset(self))
.flat_map(|c| c.chars().rev())
}
- fn reversed_chunks_in_range(&self, range: Range<usize>) -> ReversedMultiBufferChunks<'_> {
- let mut cursor = self.cursor::<usize>();
+ fn reversed_chunks_in_range(
+ &self,
+ range: Range<MultiBufferOffset>,
+ ) -> ReversedMultiBufferChunks<'_> {
+ let mut cursor = self.cursor::<MultiBufferOffset, BufferOffset>();
cursor.seek(&range.end);
let current_chunks = cursor.region().as_ref().map(|region| {
let start_overshoot = range.start.saturating_sub(region.range.start);
@@ -3173,7 +3619,8 @@ impl MultiBufferSnapshot {
buffer_id: excerpt.buffer_id,
excerpt_id: excerpt.id,
buffer_range: hunk.buffer_range.clone(),
- diff_base_byte_range: hunk.diff_base_byte_range.clone(),
+ diff_base_byte_range: BufferOffset(hunk.diff_base_byte_range.start)
+ ..BufferOffset(hunk.diff_base_byte_range.end),
secondary_status: hunk.secondary_status,
})
})
@@ -3184,7 +3631,7 @@ impl MultiBufferSnapshot {
range: Range<T>,
) -> impl Iterator<Item = ExcerptId> + '_ {
let range = range.start.to_offset(self)..range.end.to_offset(self);
- let mut cursor = self.cursor::<usize>();
+ let mut cursor = self.cursor::<MultiBufferOffset, BufferOffset>();
cursor.seek(&range.start);
std::iter::from_fn(move || {
let region = cursor.region()?;
@@ -3201,7 +3648,7 @@ impl MultiBufferSnapshot {
range: Range<T>,
) -> impl Iterator<Item = BufferId> + '_ {
let range = range.start.to_offset(self)..range.end.to_offset(self);
- let mut cursor = self.cursor::<usize>();
+ let mut cursor = self.cursor::<MultiBufferOffset, BufferOffset>();
cursor.seek(&range.start);
std::iter::from_fn(move || {
let region = cursor.region()?;
@@ -3218,21 +3665,21 @@ impl MultiBufferSnapshot {
pub fn ranges_to_buffer_ranges<T: ToOffset>(
&self,
ranges: impl Iterator<Item = Range<T>>,
- ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId)> {
+ ) -> impl Iterator<Item = (&BufferSnapshot, Range<BufferOffset>, ExcerptId)> {
ranges.flat_map(|range| self.range_to_buffer_ranges(range).into_iter())
}
pub fn range_to_buffer_ranges<T: ToOffset>(
&self,
range: Range<T>,
- ) -> Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> {
+ ) -> Vec<(&BufferSnapshot, Range<BufferOffset>, ExcerptId)> {
let start = range.start.to_offset(self);
let end = range.end.to_offset(self);
- let mut cursor = self.cursor::<usize>();
+ let mut cursor = self.cursor::<MultiBufferOffset, BufferOffset>();
cursor.seek(&start);
- let mut result: Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> = Vec::new();
+ let mut result: Vec<(&BufferSnapshot, Range<BufferOffset>, ExcerptId)> = Vec::new();
while let Some(region) = cursor.region() {
if region.range.start > end {
break;
@@ -130,8 +130,8 @@ fn test_excerpt_boundaries_and_clipping(cx: &mut App) {
assert_eq!(
subscription.consume().into_inner(),
[Edit {
- old: 0..0,
- new: 0..10
+ old: MultiBufferOffset(0)..MultiBufferOffset(0),
+ new: MultiBufferOffset(0)..MultiBufferOffset(10)
}]
);
@@ -148,8 +148,8 @@ fn test_excerpt_boundaries_and_clipping(cx: &mut App) {
assert_eq!(
subscription.consume().into_inner(),
[Edit {
- old: 10..10,
- new: 10..22
+ old: MultiBufferOffset(10)..MultiBufferOffset(10),
+ new: MultiBufferOffset(10)..MultiBufferOffset(22)
}]
);
@@ -282,8 +282,8 @@ fn test_excerpt_boundaries_and_clipping(cx: &mut App) {
assert_eq!(
subscription.consume().into_inner(),
[Edit {
- old: 6..8,
- new: 6..7
+ old: MultiBufferOffset(6)..MultiBufferOffset(8),
+ new: MultiBufferOffset(6)..MultiBufferOffset(7)
}]
);
@@ -925,7 +925,7 @@ fn test_empty_diff_excerpt(cx: &mut TestAppContext) {
.next()
.unwrap();
- assert_eq!(hunk.diff_base_byte_range.start, 0);
+ assert_eq!(hunk.diff_base_byte_range.start, BufferOffset(0));
let buf2 = cx.new(|cx| Buffer::local("X", cx));
multibuffer.update(cx, |multibuffer, cx| {
@@ -971,10 +971,30 @@ fn test_singleton_multibuffer_anchors(cx: &mut App) {
assert_eq!(old_snapshot.text(), "abcd");
assert_eq!(new_snapshot.text(), "XabcdY");
- assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
- assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
- assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
- assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(0))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(0)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(0))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(1)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(4))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(5)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(4))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(6)
+ );
}
#[gpui::test]
@@ -989,12 +1009,28 @@ fn test_multibuffer_anchors(cx: &mut App) {
});
let old_snapshot = multibuffer.read(cx).snapshot(cx);
- assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
- assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
- assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
- assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
- assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
- assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(0))
+ .to_offset(&old_snapshot),
+ MultiBufferOffset(0)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(0))
+ .to_offset(&old_snapshot),
+ MultiBufferOffset(0)
+ );
+ assert_eq!(Anchor::min().to_offset(&old_snapshot), MultiBufferOffset(0));
+ assert_eq!(Anchor::min().to_offset(&old_snapshot), MultiBufferOffset(0));
+ assert_eq!(
+ Anchor::max().to_offset(&old_snapshot),
+ MultiBufferOffset(10)
+ );
+ assert_eq!(
+ Anchor::max().to_offset(&old_snapshot),
+ MultiBufferOffset(10)
+ );
buffer_1.update(cx, |buffer, cx| {
buffer.edit([(0..0, "W")], None, cx);
@@ -1009,16 +1045,66 @@ fn test_multibuffer_anchors(cx: &mut App) {
assert_eq!(old_snapshot.text(), "abcd\nefghi");
assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
- assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
- assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
- assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
- assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
- assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
- assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
- assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
- assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
- assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
- assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(0))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(0)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(0))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(1)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(1))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(2)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(1))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(2)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(2))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(3)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(2))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(3)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(5))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(7)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(5))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(8)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_before(MultiBufferOffset(10))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(13)
+ );
+ assert_eq!(
+ old_snapshot
+ .anchor_after(MultiBufferOffset(10))
+ .to_offset(&new_snapshot),
+ MultiBufferOffset(14)
+ );
}
#[gpui::test]
@@ -1066,26 +1152,30 @@ fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut App) {
// The current excerpts are from a different buffer, so we don't attempt to
// resolve the old text anchor in the new buffer.
assert_eq!(
- snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
- 0
+ snapshot_2.summary_for_anchor::<MultiBufferOffset>(
+ &snapshot_1.anchor_before(MultiBufferOffset(2))
+ ),
+ MultiBufferOffset(0)
);
assert_eq!(
- snapshot_2.summaries_for_anchors::<usize, _>(&[
- snapshot_1.anchor_before(2),
- snapshot_1.anchor_after(3)
+ snapshot_2.summaries_for_anchors::<MultiBufferOffset, _>(&[
+ snapshot_1.anchor_before(MultiBufferOffset(2)),
+ snapshot_1.anchor_after(MultiBufferOffset(3))
]),
- vec![0, 0]
+ vec![MultiBufferOffset(0), MultiBufferOffset(0)]
);
// Refresh anchors from the old snapshot. The return value indicates that both
// anchors lost their original excerpt.
- let refresh =
- snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
+ let refresh = snapshot_2.refresh_anchors(&[
+ snapshot_1.anchor_before(MultiBufferOffset(2)),
+ snapshot_1.anchor_after(MultiBufferOffset(3)),
+ ]);
assert_eq!(
refresh,
&[
- (0, snapshot_2.anchor_before(0), false),
- (1, snapshot_2.anchor_after(0), false),
+ (0, snapshot_2.anchor_before(MultiBufferOffset(0)), false),
+ (1, snapshot_2.anchor_after(MultiBufferOffset(0)), false),
]
);
@@ -1112,14 +1202,19 @@ fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut App) {
// The third anchor can't be resolved, since its excerpt has been removed,
// so it resolves to the same position as its predecessor.
let anchors = [
- snapshot_2.anchor_before(0),
- snapshot_2.anchor_after(2),
- snapshot_2.anchor_after(6),
- snapshot_2.anchor_after(14),
+ snapshot_2.anchor_before(MultiBufferOffset(0)),
+ snapshot_2.anchor_after(MultiBufferOffset(2)),
+ snapshot_2.anchor_after(MultiBufferOffset(6)),
+ snapshot_2.anchor_after(MultiBufferOffset(14)),
];
assert_eq!(
- snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
- &[0, 2, 9, 13]
+ snapshot_3.summaries_for_anchors::<MultiBufferOffset, _>(&anchors),
+ &[
+ MultiBufferOffset(0),
+ MultiBufferOffset(2),
+ MultiBufferOffset(9),
+ MultiBufferOffset(13)
+ ]
);
let new_anchors = snapshot_3.refresh_anchors(&anchors);
@@ -1128,8 +1223,13 @@ fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut App) {
&[(0, true), (1, true), (2, true), (3, true)]
);
assert_eq!(
- snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
- &[0, 2, 7, 13]
+ snapshot_3.summaries_for_anchors::<MultiBufferOffset, _>(new_anchors.iter().map(|a| &a.1)),
+ &[
+ MultiBufferOffset(0),
+ MultiBufferOffset(2),
+ MultiBufferOffset(7),
+ MultiBufferOffset(13)
+ ]
);
}
@@ -1371,7 +1471,7 @@ fn test_basic_diff_hunks(cx: &mut TestAppContext) {
assert_eq!(
snapshot
- .diff_hunks_in_range(0..snapshot.len())
+ .diff_hunks_in_range(MultiBufferOffset(0)..snapshot.len())
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0)
.collect::<Vec<_>>(),
&[0..4, 5..7]
@@ -2072,7 +2172,7 @@ fn test_diff_hunks_with_multiple_excerpts(cx: &mut TestAppContext) {
assert_eq!(
snapshot
- .diff_hunks_in_range(0..snapshot.len())
+ .diff_hunks_in_range(MultiBufferOffset(0)..snapshot.len())
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0)
.collect::<Vec<_>>(),
&[0..1, 2..4, 5..7, 9..10, 12..13, 14..17]
@@ -2636,14 +2736,16 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
30..=39 if !reference.excerpts.is_empty() => {
let multibuffer =
multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
- let offset =
- multibuffer.clip_offset(rng.random_range(0..=multibuffer.len()), Bias::Left);
+ let offset = multibuffer.clip_offset(
+ MultiBufferOffset(rng.random_range(0..=multibuffer.len().0)),
+ Bias::Left,
+ );
let bias = if rng.random() {
Bias::Left
} else {
Bias::Right
};
- log::info!("Creating anchor at {} with bias {:?}", offset, bias);
+ log::info!("Creating anchor at {} with bias {:?}", offset.0, bias);
anchors.push(multibuffer.anchor_at(offset, bias));
anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
}
@@ -2796,7 +2898,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let snapshot = multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
let actual_text = snapshot.text();
let actual_boundary_rows = snapshot
- .excerpt_boundaries_in_range(0..)
+ .excerpt_boundaries_in_range(MultiBufferOffset(0)..)
.map(|b| b.row)
.collect::<HashSet<_>>();
let actual_row_infos = snapshot.row_infos(MultiBufferRow(0)).collect::<Vec<_>>();
@@ -2874,9 +2976,14 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
})
.collect::<HashMap<_, _>>()
});
- for i in 0..snapshot.len() {
- let excerpt = snapshot.excerpt_containing(i..i).unwrap();
- assert_eq!(excerpt.buffer_range(), reference_ranges[&excerpt.id()]);
+ for i in 0..snapshot.len().0 {
+ let excerpt = snapshot
+ .excerpt_containing(MultiBufferOffset(i)..MultiBufferOffset(i))
+ .unwrap();
+ assert_eq!(
+ excerpt.buffer_range().start.0..excerpt.buffer_range().end.0,
+ reference_ranges[&excerpt.id()]
+ );
}
assert_consistent_line_numbers(&snapshot);
@@ -2897,7 +3004,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let start_ix = text_rope.clip_offset(rng.random_range(0..=end_ix), Bias::Left);
let text_for_range = snapshot
- .text_for_range(start_ix..end_ix)
+ .text_for_range(MultiBufferOffset(start_ix)..MultiBufferOffset(end_ix))
.collect::<String>();
assert_eq!(
text_for_range,
@@ -2906,9 +3013,12 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
start_ix..end_ix
);
- let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
+ let expected_summary =
+ MBTextSummary::from(TextSummary::from(&expected_text[start_ix..end_ix]));
assert_eq!(
- snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
+ snapshot.text_summary_for_range::<MBTextSummary, _>(
+ MultiBufferOffset(start_ix)..MultiBufferOffset(end_ix)
+ ),
expected_summary,
"incorrect summary for range {:?}",
start_ix..end_ix
@@ -2916,12 +3026,12 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
}
// Anchor resolution
- let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
+ let summaries = snapshot.summaries_for_anchors::<MultiBufferOffset, _>(&anchors);
assert_eq!(anchors.len(), summaries.len());
for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
assert!(resolved_offset <= snapshot.len());
assert_eq!(
- snapshot.summary_for_anchor::<usize>(anchor),
+ snapshot.summary_for_anchor::<MultiBufferOffset>(anchor),
resolved_offset,
"anchor: {:?}",
anchor
@@ -2931,7 +3041,9 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
for _ in 0..10 {
let end_ix = text_rope.clip_offset(rng.random_range(0..=text_rope.len()), Bias::Right);
assert_eq!(
- snapshot.reversed_chars_at(end_ix).collect::<String>(),
+ snapshot
+ .reversed_chars_at(MultiBufferOffset(end_ix))
+ .collect::<String>(),
expected_text[..end_ix].chars().rev().collect::<String>(),
);
}
@@ -2941,7 +3053,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let start_ix = rng.random_range(0..=end_ix);
assert_eq!(
snapshot
- .bytes_in_range(start_ix..end_ix)
+ .bytes_in_range(MultiBufferOffset(start_ix)..MultiBufferOffset(end_ix))
.flatten()
.copied()
.collect::<Vec<_>>(),
@@ -2964,8 +3076,13 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let mut text = old_snapshot.text();
for edit in edits {
- let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
- text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
+ let new_text: String = snapshot
+ .text_for_range(edit.new.start..edit.new.end)
+ .collect();
+ text.replace_range(
+ edit.new.start.0..edit.new.start.0 + (edit.old.end.0 - edit.old.start.0),
+ &new_text,
+ );
}
assert_eq!(text.to_string(), snapshot.text());
}
@@ -3038,7 +3155,11 @@ fn test_history(cx: &mut App) {
// Edit buffer 1 through the multibuffer
now += 2 * group_interval;
multibuffer.start_transaction_at(now, cx);
- multibuffer.edit([(2..2, "C")], None, cx);
+ multibuffer.edit(
+ [(MultiBufferOffset(2)..MultiBufferOffset(2), "C")],
+ None,
+ cx,
+ );
multibuffer.end_transaction_at(now, cx);
assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
@@ -3091,7 +3212,11 @@ fn test_history(cx: &mut App) {
// Redo stack gets cleared after an edit.
now += 2 * group_interval;
multibuffer.start_transaction_at(now, cx);
- multibuffer.edit([(0..0, "X")], None, cx);
+ multibuffer.edit(
+ [(MultiBufferOffset(0)..MultiBufferOffset(0), "X")],
+ None,
+ cx,
+ );
multibuffer.end_transaction_at(now, cx);
assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
multibuffer.redo(cx);
@@ -3320,7 +3445,7 @@ fn test_trailing_deletion_without_newline(cx: &mut TestAppContext) {
);
assert_eq!(snapshot.max_point(), Point::new(2, 0));
- assert_eq!(snapshot.len(), 8);
+ assert_eq!(snapshot.len().0, 8);
assert_eq!(
snapshot
@@ -3330,7 +3455,7 @@ fn test_trailing_deletion_without_newline(cx: &mut TestAppContext) {
);
let (_, translated_offset) = snapshot.point_to_buffer_offset(Point::new(2, 0)).unwrap();
- assert_eq!(translated_offset, "one\n".len());
+ assert_eq!(translated_offset.0, "one\n".len());
let (_, translated_point, _) = snapshot.point_to_buffer_point(Point::new(2, 0)).unwrap();
assert_eq!(translated_point, Point::new(1, 0));
@@ -3371,7 +3496,7 @@ fn test_trailing_deletion_without_newline(cx: &mut TestAppContext) {
let buffer_1_id = buffer_1.read_with(cx, |buffer_1, _| buffer_1.remote_id());
let (buffer, translated_offset) = snapshot.point_to_buffer_offset(Point::new(2, 0)).unwrap();
assert_eq!(buffer.remote_id(), buffer_1_id);
- assert_eq!(translated_offset, "one\n".len());
+ assert_eq!(translated_offset.0, "one\n".len());
let (buffer, translated_point, _) = snapshot.point_to_buffer_point(Point::new(2, 0)).unwrap();
assert_eq!(buffer.remote_id(), buffer_1_id);
assert_eq!(translated_point, Point::new(1, 0));
@@ -3439,7 +3564,7 @@ fn assert_excerpts_match(
fn assert_new_snapshot(
multibuffer: &Entity<MultiBuffer>,
snapshot: &mut MultiBufferSnapshot,
- subscription: &mut Subscription,
+ subscription: &mut Subscription<MultiBufferOffset>,
cx: &mut TestAppContext,
expected_diff: &str,
) {
@@ -3462,15 +3587,15 @@ fn assert_new_snapshot(
fn check_edits(
old_snapshot: &MultiBufferSnapshot,
new_snapshot: &MultiBufferSnapshot,
- edits: &[Edit<usize>],
+ edits: &[Edit<MultiBufferOffset>],
) {
let mut text = old_snapshot.text();
let new_text = new_snapshot.text();
for edit in edits.iter().rev() {
- if !text.is_char_boundary(edit.old.start)
- || !text.is_char_boundary(edit.old.end)
- || !new_text.is_char_boundary(edit.new.start)
- || !new_text.is_char_boundary(edit.new.end)
+ if !text.is_char_boundary(edit.old.start.0)
+ || !text.is_char_boundary(edit.old.end.0)
+ || !new_text.is_char_boundary(edit.new.start.0)
+ || !new_text.is_char_boundary(edit.new.end.0)
{
panic!(
"invalid edits: {:?}\nold text: {:?}\nnew text: {:?}",
@@ -3479,8 +3604,8 @@ fn check_edits(
}
text.replace_range(
- edit.old.start..edit.old.end,
- &new_text[edit.new.start..edit.new.end],
+ edit.old.start.0..edit.old.end.0,
+ &new_text[edit.new.start.0..edit.new.end.0],
);
}
@@ -3491,8 +3616,8 @@ fn check_edits(
fn assert_chunks_in_ranges(snapshot: &MultiBufferSnapshot) {
let full_text = snapshot.text();
for ix in 0..full_text.len() {
- let mut chunks = snapshot.chunks(0..snapshot.len(), false);
- chunks.seek(ix..snapshot.len());
+ let mut chunks = snapshot.chunks(MultiBufferOffset(0)..snapshot.len(), false);
+ chunks.seek(MultiBufferOffset(ix)..snapshot.len());
let tail = chunks.map(|chunk| chunk.text).collect::<String>();
assert_eq!(tail, &full_text[ix..], "seek to range: {:?}", ix..);
}
@@ -3522,44 +3647,49 @@ fn assert_position_translation(snapshot: &MultiBufferSnapshot) {
let mut offsets = Vec::new();
let mut points = Vec::new();
for offset in 0..=text.len() + 1 {
+ let offset = MultiBufferOffset(offset);
let clipped_left = snapshot.clip_offset(offset, Bias::Left);
let clipped_right = snapshot.clip_offset(offset, Bias::Right);
assert_eq!(
- clipped_left,
- text.clip_offset(offset, Bias::Left),
+ clipped_left.0,
+ text.clip_offset(offset.0, Bias::Left),
"clip_offset({offset:?}, Left)"
);
assert_eq!(
- clipped_right,
- text.clip_offset(offset, Bias::Right),
+ clipped_right.0,
+ text.clip_offset(offset.0, Bias::Right),
"clip_offset({offset:?}, Right)"
);
assert_eq!(
snapshot.offset_to_point(clipped_left),
- text.offset_to_point(clipped_left),
- "offset_to_point({clipped_left})"
+ text.offset_to_point(clipped_left.0),
+ "offset_to_point({})",
+ clipped_left.0
);
assert_eq!(
snapshot.offset_to_point(clipped_right),
- text.offset_to_point(clipped_right),
- "offset_to_point({clipped_right})"
+ text.offset_to_point(clipped_right.0),
+ "offset_to_point({})",
+ clipped_right.0
);
let anchor_after = snapshot.anchor_after(clipped_left);
assert_eq!(
anchor_after.to_offset(snapshot),
clipped_left,
- "anchor_after({clipped_left}).to_offset {anchor_after:?}"
+ "anchor_after({}).to_offset {anchor_after:?}",
+ clipped_left.0
);
let anchor_before = snapshot.anchor_before(clipped_left);
assert_eq!(
anchor_before.to_offset(snapshot),
clipped_left,
- "anchor_before({clipped_left}).to_offset"
+ "anchor_before({}).to_offset",
+ clipped_left.0
);
left_anchors.push(anchor_before);
right_anchors.push(anchor_after);
offsets.push(clipped_left);
- points.push(text.offset_to_point(clipped_left));
+ points.push(text.offset_to_point(clipped_left.0));
}
for row in 0..text.max_point().row {
@@ -3578,12 +3708,12 @@ fn assert_position_translation(snapshot: &MultiBufferSnapshot) {
"clip_point({point:?}, Right)"
);
assert_eq!(
- snapshot.point_to_offset(clipped_left),
+ snapshot.point_to_offset(clipped_left).0,
text.point_to_offset(clipped_left),
"point_to_offset({clipped_left:?})"
);
assert_eq!(
- snapshot.point_to_offset(clipped_right),
+ snapshot.point_to_offset(clipped_right).0,
text.point_to_offset(clipped_right),
"point_to_offset({clipped_right:?})"
);
@@ -3591,7 +3721,7 @@ fn assert_position_translation(snapshot: &MultiBufferSnapshot) {
}
assert_eq!(
- snapshot.summaries_for_anchors::<usize, _>(&left_anchors),
+ snapshot.summaries_for_anchors::<MultiBufferOffset, _>(&left_anchors),
offsets,
"left_anchors <-> offsets"
);
@@ -3601,7 +3731,7 @@ fn assert_position_translation(snapshot: &MultiBufferSnapshot) {
"left_anchors <-> points"
);
assert_eq!(
- snapshot.summaries_for_anchors::<usize, _>(&right_anchors),
+ snapshot.summaries_for_anchors::<MultiBufferOffset, _>(&right_anchors),
offsets,
"right_anchors <-> offsets"
);
@@ -3613,7 +3743,7 @@ fn assert_position_translation(snapshot: &MultiBufferSnapshot) {
for (anchors, bias) in [(&left_anchors, Bias::Left), (&right_anchors, Bias::Right)] {
for (ix, (offset, anchor)) in offsets.iter().zip(anchors).enumerate() {
- if ix > 0 && *offset == 252 && offset > &offsets[ix - 1] {
+ if ix > 0 && *offset == MultiBufferOffset(252) && offset > &offsets[ix - 1] {
let prev_anchor = left_anchors[ix - 1];
assert!(
anchor.cmp(&prev_anchor, snapshot).is_gt(),
@@ -3632,7 +3762,7 @@ fn assert_position_translation(snapshot: &MultiBufferSnapshot) {
}
if let Some((buffer, offset)) = snapshot.point_to_buffer_offset(snapshot.max_point()) {
- assert!(offset <= buffer.len());
+ assert!(offset.0 <= buffer.len());
}
if let Some((buffer, point, _)) = snapshot.point_to_buffer_point(snapshot.max_point()) {
assert!(point <= buffer.max_point());
@@ -3747,7 +3877,7 @@ fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
let snapshot = multibuffer.read(cx).snapshot(cx);
- let chunks = snapshot.chunks(0..snapshot.len(), false);
+ let chunks = snapshot.chunks(MultiBufferOffset(0)..snapshot.len(), false);
for chunk in chunks {
let chunk_text = chunk.text;
@@ -3879,24 +4009,24 @@ fn test_random_chunk_bitmaps_with_diffs(cx: &mut App, mut rng: StdRng) {
let mut ranges = Vec::new();
for _ in 0..rng.random_range(1..5) {
- if snapshot.len() == 0 {
+ if snapshot.len().0 == 0 {
break;
}
let diff_size = rng.random_range(5..1000);
- let mut start = rng.random_range(0..snapshot.len());
+ let mut start = rng.random_range(0..snapshot.len().0);
while !text.is_char_boundary(start) {
start = start.saturating_sub(1);
}
- let mut end = rng.random_range(start..snapshot.len().min(start + diff_size));
+ let mut end = rng.random_range(start..snapshot.len().0.min(start + diff_size));
while !text.is_char_boundary(end) {
end = end.saturating_add(1);
}
- let start_anchor = snapshot.anchor_after(start);
- let end_anchor = snapshot.anchor_before(end);
+ let start_anchor = snapshot.anchor_after(MultiBufferOffset(start));
+ let end_anchor = snapshot.anchor_before(MultiBufferOffset(end));
ranges.push(start_anchor..end_anchor);
}
multibuffer.expand_diff_hunks(ranges, cx);
@@ -3905,7 +4035,7 @@ fn test_random_chunk_bitmaps_with_diffs(cx: &mut App, mut rng: StdRng) {
let snapshot = multibuffer.read(cx).snapshot(cx);
- let chunks = snapshot.chunks(0..snapshot.len(), false);
+ let chunks = snapshot.chunks(MultiBufferOffset(0)..snapshot.len(), false);
for chunk in chunks {
let chunk_text = chunk.text;
@@ -1,14 +1,14 @@
use gpui::{App, Context, Entity};
-use language::{self, Buffer, TextDimension, TransactionId};
+use language::{self, Buffer, TransactionId};
use std::{
collections::HashMap,
- ops::{Range, Sub},
+ ops::{AddAssign, Range, Sub},
time::{Duration, Instant},
};
use sum_tree::Bias;
use text::BufferId;
-use crate::BufferState;
+use crate::{BufferState, MultiBufferDimension};
use super::{Event, ExcerptSummary, MultiBuffer};
@@ -320,7 +320,11 @@ impl MultiBuffer {
cx: &App,
) -> Vec<Range<D>>
where
- D: TextDimension + Ord + Sub<D, Output = D>,
+ D: MultiBufferDimension
+ + Ord
+ + Sub<D, Output = D::TextDimension>
+ + AddAssign<D::TextDimension>,
+ D::TextDimension: PartialOrd + Sub<D::TextDimension, Output = D::TextDimension>,
{
let Some(transaction) = self.history.transaction(transaction_id) else {
return Vec::new();
@@ -336,24 +340,34 @@ impl MultiBuffer {
};
let buffer = buffer_state.buffer.read(cx);
- for range in buffer.edited_ranges_for_transaction_id::<D>(*buffer_transaction) {
+ for range in
+ buffer.edited_ranges_for_transaction_id::<D::TextDimension>(*buffer_transaction)
+ {
for excerpt_id in &buffer_state.excerpts {
cursor.seek(excerpt_id, Bias::Left);
if let Some(excerpt) = cursor.item()
&& excerpt.locator == *excerpt_id
{
- let excerpt_buffer_start = excerpt.range.context.start.summary::<D>(buffer);
- let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(buffer);
+ let excerpt_buffer_start = excerpt
+ .range
+ .context
+ .start
+ .summary::<D::TextDimension>(buffer);
+ let excerpt_buffer_end = excerpt
+ .range
+ .context
+ .end
+ .summary::<D::TextDimension>(buffer);
let excerpt_range = excerpt_buffer_start..excerpt_buffer_end;
if excerpt_range.contains(&range.start)
&& excerpt_range.contains(&range.end)
{
- let excerpt_start = D::from_text_summary(&cursor.start().text);
+ let excerpt_start = D::from_summary(&cursor.start().text);
let mut start = excerpt_start;
- start.add_assign(&(range.start - excerpt_buffer_start));
+ start += range.start - excerpt_buffer_start;
let mut end = excerpt_start;
- end.add_assign(&(range.end - excerpt_buffer_start));
+ end += range.end - excerpt_buffer_start;
ranges.push(start..end);
break;
@@ -6,7 +6,7 @@ use std::{
use editor::scroll::ScrollOffset;
use editor::{Anchor, AnchorRangeExt, Editor, scroll::Autoscroll};
-use editor::{RowHighlightOptions, SelectionEffects};
+use editor::{MultiBufferOffset, RowHighlightOptions, SelectionEffects};
use fuzzy::StringMatch;
use gpui::{
App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, HighlightStyle,
@@ -247,7 +247,7 @@ impl PickerDelegate for OutlineViewDelegate {
let buffer = editor.buffer().read(cx).snapshot(cx);
let cursor_offset = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
.head();
(buffer, cursor_offset)
});
@@ -259,8 +259,8 @@ impl PickerDelegate for OutlineViewDelegate {
.map(|(ix, item)| {
let range = item.range.to_offset(&buffer);
let distance_to_closest_endpoint = cmp::min(
- (range.start as isize - cursor_offset as isize).abs(),
- (range.end as isize - cursor_offset as isize).abs(),
+ (range.start.0 as isize - cursor_offset.0 as isize).abs(),
+ (range.end.0 as isize - cursor_offset.0 as isize).abs(),
);
let depth = if range.contains(&cursor_offset) {
Some(item.depth)
@@ -7,7 +7,7 @@ use collections::{BTreeSet, HashMap, hash_map};
use command_palette_hooks::CommandPaletteFilter;
use db::kvp::KEY_VALUE_STORE;
use editor::{
- Editor, EditorEvent,
+ Editor, EditorEvent, MultiBufferOffset,
items::{
entry_diagnostic_aware_icon_decoration_and_color,
entry_diagnostic_aware_icon_name_and_color, entry_git_aware_label_color,
@@ -1925,7 +1925,9 @@ impl ProjectPanel {
self.filename_editor.update(cx, |editor, cx| {
editor.set_text(file_name, window, cx);
editor.change_selections(Default::default(), window, cx, |s| {
- s.select_ranges([selection])
+ s.select_ranges([
+ MultiBufferOffset(selection.start)..MultiBufferOffset(selection.end)
+ ])
});
});
self.update_visible_entries(None, true, true, window, cx);
@@ -1,5 +1,6 @@
use super::*;
use collections::HashSet;
+use editor::MultiBufferOffset;
use gpui::{Empty, Entity, TestAppContext, VisualTestContext, WindowHandle};
use pretty_assertions::assert_eq;
use project::FakeFs;
@@ -658,7 +659,9 @@ async fn test_editing_files(cx: &mut gpui::TestAppContext) {
let confirm = panel.update_in(cx, |panel, window, cx| {
panel.filename_editor.update(cx, |editor, cx| {
- let file_name_selections = editor.selections.all::<usize>(&editor.display_snapshot(cx));
+ let file_name_selections = editor
+ .selections
+ .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
assert_eq!(
file_name_selections.len(),
1,
@@ -666,12 +669,13 @@ async fn test_editing_files(cx: &mut gpui::TestAppContext) {
);
let file_name_selection = &file_name_selections[0];
assert_eq!(
- file_name_selection.start, 0,
+ file_name_selection.start,
+ MultiBufferOffset(0),
"Should select the file name from the start"
);
assert_eq!(
file_name_selection.end,
- "another-filename".len(),
+ MultiBufferOffset("another-filename".len()),
"Should not select file extension"
);
@@ -732,11 +736,11 @@ async fn test_editing_files(cx: &mut gpui::TestAppContext) {
panel.update_in(cx, |panel, window, cx| {
panel.filename_editor.update(cx, |editor, cx| {
- let file_name_selections = editor.selections.all::<usize>(&editor.display_snapshot(cx));
+ let file_name_selections = editor.selections.all::<MultiBufferOffset>(&editor.display_snapshot(cx));
assert_eq!(file_name_selections.len(), 1, "File editing should have a single selection, but got: {file_name_selections:?}");
let file_name_selection = &file_name_selections[0];
- assert_eq!(file_name_selection.start, 0, "Should select the file name from the start");
- assert_eq!(file_name_selection.end, "a-different-filename.tar".len(), "Should not select file extension, but still may select anything up to the last dot..");
+ assert_eq!(file_name_selection.start, MultiBufferOffset(0), "Should select the file name from the start");
+ assert_eq!(file_name_selection.end, MultiBufferOffset("a-different-filename.tar".len()), "Should not select file extension, but still may select anything up to the last dot..");
});
panel.cancel(&menu::Cancel, window, cx)
@@ -1218,7 +1222,9 @@ async fn test_copy_paste(cx: &mut gpui::TestAppContext) {
panel.update_in(cx, |panel, window, cx| {
panel.filename_editor.update(cx, |editor, cx| {
- let file_name_selections = editor.selections.all::<usize>(&editor.display_snapshot(cx));
+ let file_name_selections = editor
+ .selections
+ .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
assert_eq!(
file_name_selections.len(),
1,
@@ -1227,12 +1233,12 @@ async fn test_copy_paste(cx: &mut gpui::TestAppContext) {
let file_name_selection = &file_name_selections[0];
assert_eq!(
file_name_selection.start,
- "one".len(),
+ MultiBufferOffset("one".len()),
"Should select the file name disambiguation after the original file name"
);
assert_eq!(
file_name_selection.end,
- "one copy".len(),
+ MultiBufferOffset("one copy".len()),
"Should select the file name disambiguation until the extension"
);
});
@@ -4,7 +4,7 @@ use std::ops::Range;
use std::sync::Arc;
use anyhow::{Context as _, Result};
-use editor::Editor;
+use editor::{Editor, MultiBufferOffset};
use gpui::{App, Entity, WeakEntity, Window, prelude::*};
use language::{BufferSnapshot, Language, LanguageName, Point};
use project::{ProjectItem as _, WorktreeId};
@@ -478,7 +478,9 @@ fn get_language(editor: WeakEntity<Editor>, cx: &mut App) -> Option<Arc<Language
editor
.update(cx, |editor, cx| {
let display_snapshot = editor.display_snapshot(cx);
- let selection = editor.selections.newest::<usize>(&display_snapshot);
+ let selection = editor
+ .selections
+ .newest::<MultiBufferOffset>(&display_snapshot);
display_snapshot
.buffer_snapshot()
.language_at(selection.head())
@@ -32,7 +32,6 @@ impl Sub for OffsetUtf16 {
type Output = OffsetUtf16;
fn sub(self, other: Self) -> Self::Output {
- debug_assert!(other <= self);
Self(self.0 - other.0)
}
}
@@ -1534,39 +1534,63 @@ where
}
}
-impl<K, V> ops::Sub for DimensionPair<K, V>
+impl<R, R2, K, V> ops::Sub for DimensionPair<K, V>
where
- K: ops::Sub<K, Output = K>,
- V: ops::Sub<V, Output = V>,
+ K: ops::Sub<K, Output = R>,
+ V: ops::Sub<V, Output = R2>,
{
- type Output = Self;
+ type Output = DimensionPair<R, R2>;
fn sub(self, rhs: Self) -> Self::Output {
- Self {
+ DimensionPair {
key: self.key - rhs.key,
value: self.value.zip(rhs.value).map(|(a, b)| a - b),
}
}
}
+impl<R, R2, K, V> ops::AddAssign<DimensionPair<R, R2>> for DimensionPair<K, V>
+where
+ K: ops::AddAssign<R>,
+ V: ops::AddAssign<R2>,
+{
+ fn add_assign(&mut self, rhs: DimensionPair<R, R2>) {
+ self.key += rhs.key;
+ if let Some(value) = &mut self.value {
+ if let Some(other_value) = rhs.value {
+ *value += other_value;
+ } else {
+ self.value.take();
+ }
+ }
+ }
+}
+
+impl<D> std::ops::AddAssign<DimensionPair<Point, D>> for Point {
+ fn add_assign(&mut self, rhs: DimensionPair<Point, D>) {
+ *self += rhs.key;
+ }
+}
+
impl<K, V> cmp::Eq for DimensionPair<K, V> where K: cmp::Eq {}
-impl<'a, K, V> sum_tree::Dimension<'a, ChunkSummary> for DimensionPair<K, V>
+impl<'a, K, V, S> sum_tree::Dimension<'a, S> for DimensionPair<K, V>
where
- K: sum_tree::Dimension<'a, ChunkSummary>,
- V: sum_tree::Dimension<'a, ChunkSummary>,
+ S: sum_tree::Summary,
+ K: sum_tree::Dimension<'a, S>,
+ V: sum_tree::Dimension<'a, S>,
{
- fn zero(_cx: ()) -> Self {
+ fn zero(cx: S::Context<'_>) -> Self {
Self {
- key: K::zero(_cx),
- value: Some(V::zero(_cx)),
+ key: K::zero(cx),
+ value: Some(V::zero(cx)),
}
}
- fn add_summary(&mut self, summary: &'a ChunkSummary, _cx: ()) {
- self.key.add_summary(summary, _cx);
+ fn add_summary(&mut self, summary: &'a S, cx: S::Context<'_>) {
+ self.key.add_summary(summary, cx);
if let Some(value) = &mut self.value {
- value.add_summary(summary, _cx);
+ value.add_summary(summary, cx);
}
}
}
@@ -10,7 +10,7 @@ use any_vec::AnyVec;
use anyhow::Context as _;
use collections::HashMap;
use editor::{
- DisplayPoint, Editor, EditorSettings,
+ DisplayPoint, Editor, EditorSettings, MultiBufferOffset,
actions::{Backtab, Tab},
};
use futures::channel::oneshot;
@@ -868,7 +868,11 @@ impl BufferSearchBar {
.buffer()
.update(cx, |replacement_buffer, cx| {
let len = replacement_buffer.len(cx);
- replacement_buffer.edit([(0..len, replacement.unwrap())], None, cx);
+ replacement_buffer.edit(
+ [(MultiBufferOffset(0)..len, replacement.unwrap())],
+ None,
+ cx,
+ );
});
});
}
@@ -892,7 +896,7 @@ impl BufferSearchBar {
self.query_editor.update(cx, |query_editor, cx| {
query_editor.buffer().update(cx, |query_buffer, cx| {
let len = query_buffer.len(cx);
- query_buffer.edit([(0..len, query)], None, cx);
+ query_buffer.edit([(MultiBufferOffset(0)..len, query)], None, cx);
});
});
self.set_search_options(options, cx);
@@ -392,7 +392,7 @@ fn worktree_context(worktree_abs_path: &Path) -> TaskContext {
mod tests {
use std::{collections::HashMap, sync::Arc};
- use editor::{Editor, SelectionEffects};
+ use editor::{Editor, MultiBufferOffset, SelectionEffects};
use gpui::TestAppContext;
use language::{Language, LanguageConfig};
use project::{BasicContextProvider, FakeFs, Project, task_store::TaskStore};
@@ -539,7 +539,7 @@ mod tests {
// And now, let's select an identifier.
editor2.update_in(cx, |editor, window, cx| {
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
- selections.select_ranges([14..18])
+ selections.select_ranges([MultiBufferOffset(14)..MultiBufferOffset(18)])
})
});
@@ -130,9 +130,15 @@ impl<T: Copy> Selection<T> {
}
}
-impl Selection<usize> {
+impl<T: std::ops::Sub + Copy> Selection<T> {
+ pub fn len(&self) -> <T as std::ops::Sub>::Output {
+ self.end - self.start
+ }
+}
+
+impl<T: Copy + Eq> Selection<T> {
#[cfg(feature = "test-support")]
- pub fn from_offset(offset: usize) -> Self {
+ pub fn from_offset(offset: T) -> Self {
Selection {
id: 0,
start: offset,
@@ -142,7 +148,7 @@ impl Selection<usize> {
}
}
- pub fn equals(&self, offset_range: &Range<usize>) -> bool {
+ pub fn equals(&self, offset_range: &Range<T>) -> bool {
self.start == offset_range.start && self.end == offset_range.end
}
}
@@ -6,36 +6,55 @@ use std::{
};
#[derive(Default)]
-pub struct Topic(Mutex<Vec<Weak<Mutex<Patch<usize>>>>>);
+pub struct Topic<T>(Mutex<Vec<Weak<Mutex<Patch<T>>>>>);
-pub struct Subscription(Arc<Mutex<Patch<usize>>>);
+pub struct Subscription<T>(Arc<Mutex<Patch<T>>>);
-impl Topic {
- pub fn subscribe(&mut self) -> Subscription {
+impl<T: Default, TDelta> Topic<T>
+where
+ T: 'static
+ + Copy
+ + Ord
+ + std::ops::Sub<T, Output = TDelta>
+ + std::ops::Add<TDelta, Output = T>
+ + std::ops::AddAssign<TDelta>
+ + Default,
+ TDelta: Ord + Copy,
+{
+ pub fn subscribe(&mut self) -> Subscription<T> {
let subscription = Subscription(Default::default());
self.0.get_mut().push(Arc::downgrade(&subscription.0));
subscription
}
- pub fn publish(&self, edits: impl Clone + IntoIterator<Item = Edit<usize>>) {
+ pub fn publish(&self, edits: impl Clone + IntoIterator<Item = Edit<T>>) {
publish(&mut self.0.lock(), edits);
}
- pub fn publish_mut(&mut self, edits: impl Clone + IntoIterator<Item = Edit<usize>>) {
+ pub fn publish_mut(&mut self, edits: impl Clone + IntoIterator<Item = Edit<T>>) {
publish(self.0.get_mut(), edits);
}
}
-impl Subscription {
- pub fn consume(&self) -> Patch<usize> {
+impl<T: Default> Subscription<T> {
+ pub fn consume(&self) -> Patch<T> {
mem::take(&mut *self.0.lock())
}
}
-fn publish(
- subscriptions: &mut Vec<Weak<Mutex<Patch<usize>>>>,
- edits: impl Clone + IntoIterator<Item = Edit<usize>>,
-) {
+fn publish<T, TDelta>(
+ subscriptions: &mut Vec<Weak<Mutex<Patch<T>>>>,
+ edits: impl Clone + IntoIterator<Item = Edit<T>>,
+) where
+ T: 'static
+ + Copy
+ + Ord
+ + std::ops::Sub<T, Output = TDelta>
+ + std::ops::Add<TDelta, Output = T>
+ + std::ops::AddAssign<TDelta>
+ + Default,
+ TDelta: Ord + Copy,
+{
subscriptions.retain(|subscription| {
if let Some(subscription) = subscription.upgrade() {
let mut patch = subscription.lock();
@@ -54,7 +54,7 @@ pub struct Buffer {
deferred_ops: OperationQueue<Operation>,
deferred_replicas: HashSet<ReplicaId>,
pub lamport_clock: clock::Lamport,
- subscriptions: Topic,
+ subscriptions: Topic<usize>,
edit_id_resolvers: HashMap<clock::Lamport, Vec<oneshot::Sender<()>>>,
wait_for_version_txs: Vec<(clock::Global, oneshot::Sender<()>)>,
}
@@ -1619,7 +1619,7 @@ impl Buffer {
self.edited_ranges_for_edit_ids(&transaction.edit_ids)
}
- pub fn subscribe(&mut self) -> Subscription {
+ pub fn subscribe(&mut self) -> Subscription<usize> {
self.subscriptions.subscribe()
}
@@ -6,8 +6,8 @@ mod select;
use editor::display_map::DisplaySnapshot;
use editor::{
- DisplayPoint, Editor, EditorSettings, HideMouseCursorOrigin, SelectionEffects, ToOffset,
- ToPoint, movement,
+ DisplayPoint, Editor, EditorSettings, HideMouseCursorOrigin, MultiBufferOffset,
+ SelectionEffects, ToOffset, ToPoint, movement,
};
use gpui::actions;
use gpui::{Context, Window};
@@ -523,7 +523,7 @@ impl Vim {
..range.end.to_offset(&display_map, Bias::Left);
if !byte_range.is_empty() {
- let replacement_text = text.repeat(byte_range.len());
+ let replacement_text = text.repeat(byte_range.end - byte_range.start);
edits.push((byte_range, replacement_text));
}
}
@@ -620,7 +620,7 @@ impl Vim {
self.update_editor(cx, |_, editor, cx| {
let newest = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx));
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx));
editor.change_selections(Default::default(), window, cx, |s| s.select(vec![newest]));
});
}
@@ -1,10 +1,7 @@
-use std::{
- cmp::Ordering,
- ops::{Deref, DerefMut, Range},
-};
+use std::{cmp::Ordering, ops::Range};
use editor::{
- DisplayPoint,
+ DisplayPoint, MultiBufferOffset,
display_map::{DisplaySnapshot, ToDisplayPoint},
movement,
};
@@ -104,8 +101,8 @@ trait BoundedObject {
let next_end = self.next_end(map, end_search_start, outer)?;
let maybe_next_start = self.next_start(map, start_search_start, outer);
if let Some(next_start) = maybe_next_start
- && (*next_start < *next_end
- || *next_start == *next_end && self.can_be_zero_width(outer))
+ && (next_start.0 < next_end.0
+ || next_start.0 == next_end.0 && self.can_be_zero_width(outer))
&& !self.ambiguous_outer()
{
let closing = self.close_at_end(next_start, map, outer)?;
@@ -133,8 +130,8 @@ trait BoundedObject {
let previous_start = self.previous_start(map, start_search_end, outer)?;
let maybe_previous_end = self.previous_end(map, end_search_end, outer);
if let Some(previous_end) = maybe_previous_end
- && (*previous_end > *previous_start
- || *previous_end == *previous_start && self.can_be_zero_width(outer))
+ && (previous_end.0 > previous_start.0
+ || previous_end.0 == previous_start.0 && self.can_be_zero_width(outer))
&& !self.ambiguous_outer()
{
let closing = self.close_at_start(previous_end, map, outer)?;
@@ -151,30 +148,22 @@ trait BoundedObject {
}
}
-#[derive(Clone, Copy, PartialEq, Debug)]
-struct Offset(usize);
-impl Deref for Offset {
- type Target = usize;
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-impl DerefMut for Offset {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
-}
+#[derive(Clone, Copy, PartialEq, Debug, PartialOrd, Ord, Eq)]
+struct Offset(MultiBufferOffset);
impl Offset {
fn next(self, map: &DisplaySnapshot) -> Option<Self> {
- let next = Self(map.buffer_snapshot().clip_offset(*self + 1, Bias::Right));
- (*next > *self).then(|| next)
+ let next = Self(
+ map.buffer_snapshot()
+ .clip_offset(self.0 + 1usize, Bias::Right),
+ );
+ (next.0 > self.0).then(|| next)
}
fn previous(self, map: &DisplaySnapshot) -> Option<Self> {
- if *self == 0 {
+ if self.0 == MultiBufferOffset(0) {
return None;
}
Some(Self(
- map.buffer_snapshot().clip_offset(*self - 1, Bias::Left),
+ map.buffer_snapshot().clip_offset(self.0 - 1, Bias::Left),
))
}
fn range(
@@ -211,7 +200,7 @@ impl<B: BoundedObject> HelixTextObject for B {
let max_end = self.close_at_end(search_start, map, find_outer)?;
let min_start = self.close_at_start(max_end, map, find_outer)?;
- (*min_start <= *relative_to.start).then(|| min_start..max_end)
+ (min_start <= relative_to.start).then(|| min_start..max_end)
})
}
@@ -279,8 +268,8 @@ fn relative_range<B: BoundedObject>(
min_start..max_end
};
- let start = wanted_range.start.clone().to_display_point(map);
- let end = wanted_range.end.clone().to_display_point(map);
+ let start = wanted_range.start.0.to_display_point(map);
+ let end = wanted_range.end.0.to_display_point(map);
Some(start..end)
}
@@ -390,7 +379,7 @@ impl ImmediateBoundary {
impl BoundedObject for ImmediateBoundary {
fn next_start(&self, map: &DisplaySnapshot, from: Offset, outer: bool) -> Option<Offset> {
try_find_boundary(map, from, |left, right| {
- let classifier = map.buffer_snapshot().char_classifier_at(*from);
+ let classifier = map.buffer_snapshot().char_classifier_at(from.0);
if outer {
self.is_outer_start(left, right, classifier)
} else {
@@ -400,7 +389,7 @@ impl BoundedObject for ImmediateBoundary {
}
fn next_end(&self, map: &DisplaySnapshot, from: Offset, outer: bool) -> Option<Offset> {
try_find_boundary(map, from, |left, right| {
- let classifier = map.buffer_snapshot().char_classifier_at(*from);
+ let classifier = map.buffer_snapshot().char_classifier_at(from.0);
if outer {
self.is_outer_end(left, right, classifier)
} else {
@@ -410,7 +399,7 @@ impl BoundedObject for ImmediateBoundary {
}
fn previous_start(&self, map: &DisplaySnapshot, from: Offset, outer: bool) -> Option<Offset> {
try_find_preceding_boundary(map, from, |left, right| {
- let classifier = map.buffer_snapshot().char_classifier_at(*from);
+ let classifier = map.buffer_snapshot().char_classifier_at(from.0);
if outer {
self.is_outer_start(left, right, classifier)
} else {
@@ -420,7 +409,7 @@ impl BoundedObject for ImmediateBoundary {
}
fn previous_end(&self, map: &DisplaySnapshot, from: Offset, outer: bool) -> Option<Offset> {
try_find_preceding_boundary(map, from, |left, right| {
- let classifier = map.buffer_snapshot().char_classifier_at(*from);
+ let classifier = map.buffer_snapshot().char_classifier_at(from.0);
if outer {
self.is_outer_end(left, right, classifier)
} else {
@@ -572,7 +561,7 @@ impl FuzzyBoundary {
boundary_kind: Boundary,
) -> Option<Offset> {
let generate_boundary_data = |left, right, point: Offset| {
- let classifier = map.buffer_snapshot().char_classifier_at(*from);
+ let classifier = map.buffer_snapshot().char_classifier_at(from.0);
let reach_boundary = if outer && boundary_kind == Boundary::Start {
self.is_near_potential_outer_start(left, right, &classifier)
} else if !outer && boundary_kind == Boundary::Start {
@@ -598,9 +587,9 @@ impl FuzzyBoundary {
Ordering::Greater => !backward,
});
if backward {
- boundaries.max_by_key(|boundary| **boundary)
+ boundaries.max_by_key(|boundary| *boundary)
} else {
- boundaries.min_by_key(|boundary| **boundary)
+ boundaries.min_by_key(|boundary| *boundary)
}
}
}
@@ -662,15 +651,15 @@ fn try_find_boundary_data<T>(
) -> Option<T> {
let mut prev_ch = map
.buffer_snapshot()
- .reversed_chars_at(*from)
+ .reversed_chars_at(from.0)
.next()
.unwrap_or('\0');
- for ch in map.buffer_snapshot().chars_at(*from).chain(['\0']) {
+ for ch in map.buffer_snapshot().chars_at(from.0).chain(['\0']) {
if let Some(boundary_information) = boundary_information(prev_ch, ch, from) {
return Some(boundary_information);
}
- *from += ch.len_utf8();
+ from.0 += ch.len_utf8();
prev_ch = ch;
}
@@ -702,13 +691,21 @@ fn try_find_preceding_boundary_data<T>(
mut from: Offset,
is_boundary: impl Fn(char, char, Offset) -> Option<T>,
) -> Option<T> {
- let mut prev_ch = map.buffer_snapshot().chars_at(*from).next().unwrap_or('\0');
+ let mut prev_ch = map
+ .buffer_snapshot()
+ .chars_at(from.0)
+ .next()
+ .unwrap_or('\0');
- for ch in map.buffer_snapshot().reversed_chars_at(*from).chain(['\0']) {
+ for ch in map
+ .buffer_snapshot()
+ .reversed_chars_at(from.0)
+ .chain(['\0'])
+ {
if let Some(boundary_information) = is_boundary(ch, prev_ch, from) {
return Some(boundary_information);
}
- from.0 = from.0.saturating_sub(ch.len_utf8());
+ from.0.0 = from.0.0.saturating_sub(ch.len_utf8());
prev_ch = ch;
}
@@ -1,6 +1,6 @@
use std::ops::Range;
-use editor::{DisplayPoint, display_map::DisplaySnapshot};
+use editor::{DisplayPoint, MultiBufferOffset, display_map::DisplaySnapshot};
use gpui::Context;
use text::Bias;
use ui::Window;
@@ -111,7 +111,7 @@ fn find_next_valid_duplicate_space(
fn display_point_range_to_offset_range(
range: &Range<DisplayPoint>,
map: &DisplaySnapshot,
-) -> Range<usize> {
+) -> Range<MultiBufferOffset> {
range.start.to_offset(map, Bias::Left)..range.end.to_offset(map, Bias::Right)
}
@@ -125,7 +125,7 @@ impl Vim {
s.select_ranges(new_selections.into_iter().map(|(anchor, len)| {
let offset = anchor.to_offset(&snapshot);
if action.before {
- offset.saturating_sub(len)..offset
+ offset.saturating_sub_usize(len)..offset
} else {
offset..(offset + len)
}
@@ -1,5 +1,5 @@
use editor::{
- Anchor, Bias, DisplayPoint, Editor, RowExt, ToOffset, ToPoint,
+ Anchor, Bias, BufferOffset, DisplayPoint, Editor, MultiBufferOffset, RowExt, ToOffset, ToPoint,
display_map::{DisplayRow, DisplaySnapshot, FoldPoint, ToDisplayPoint},
movement::{
self, FindRange, TextLayoutDetails, find_boundary, find_preceding_boundary_display_point,
@@ -2143,7 +2143,7 @@ pub(crate) fn sentence_backwards(
if start_of_next_sentence < start {
times = times.saturating_sub(1);
}
- if times == 0 || offset == 0 {
+ if times == 0 || offset.0 == 0 {
return map.clip_point(
start_of_next_sentence
.to_offset(&map.buffer_snapshot())
@@ -2207,7 +2207,7 @@ pub(crate) fn sentence_forwards(
map.max_point()
}
-fn next_non_blank(map: &DisplaySnapshot, start: usize) -> usize {
+fn next_non_blank(map: &DisplaySnapshot, start: MultiBufferOffset) -> MultiBufferOffset {
for (c, o) in map.buffer_chars_at(start) {
if c == '\n' || !c.is_whitespace() {
return o;
@@ -2219,7 +2219,10 @@ fn next_non_blank(map: &DisplaySnapshot, start: usize) -> usize {
// given the offset after a ., !, or ? find the start of the next sentence.
// if this is not a sentence boundary, returns None.
-fn start_of_next_sentence(map: &DisplaySnapshot, end_of_sentence: usize) -> Option<usize> {
+fn start_of_next_sentence(
+ map: &DisplaySnapshot,
+ end_of_sentence: MultiBufferOffset,
+) -> Option<MultiBufferOffset> {
let chars = map.buffer_chars_at(end_of_sentence);
let mut seen_space = false;
@@ -2253,10 +2256,10 @@ fn go_to_line(map: &DisplaySnapshot, display_point: DisplayPoint, line: usize) -
.clip_point(Point::new((line - 1) as u32, point.column), Bias::Left),
);
let buffer_range = excerpt.buffer_range();
- if offset >= buffer_range.start && offset <= buffer_range.end {
+ if offset >= buffer_range.start.0 && offset <= buffer_range.end.0 {
let point = map
.buffer_snapshot()
- .offset_to_point(excerpt.map_offset_from_buffer(offset));
+ .offset_to_point(excerpt.map_offset_from_buffer(BufferOffset(offset)));
return map.clip_point(map.point_to_display_point(point, Bias::Left), Bias::Left);
}
let mut last_position = None;
@@ -2360,6 +2363,9 @@ fn matching_tag(map: &DisplaySnapshot, head: DisplayPoint) -> Option<DisplayPoin
}
fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint {
+ if !map.is_singleton() {
+ return display_point;
+ }
// https://github.com/vim/vim/blob/1d87e11a1ef201b26ed87585fba70182ad0c468a/runtime/doc/motion.txt#L1200
let display_point = map.clip_at_line_end(display_point);
let point = display_point.to_point(map);
@@ -2375,9 +2381,10 @@ fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint
// Attempt to find the smallest enclosing bracket range that also contains
// the offset, which only happens if the cursor is currently in a bracket.
let range_filter = |_buffer: &language::BufferSnapshot,
- opening_range: Range<usize>,
- closing_range: Range<usize>| {
- opening_range.contains(&offset) || closing_range.contains(&offset)
+ opening_range: Range<BufferOffset>,
+ closing_range: Range<BufferOffset>| {
+ opening_range.contains(&BufferOffset(offset.0))
+ || closing_range.contains(&BufferOffset(offset.0))
};
let bracket_ranges = snapshot
@@ -2840,7 +2847,7 @@ fn method_motion(
for _ in 0..times {
let point = map.display_point_to_point(display_point, Bias::Left);
- let offset = point.to_offset(&map.buffer_snapshot());
+ let offset = point.to_offset(&map.buffer_snapshot()).0;
let range = if direction == Direction::Prev {
0..offset
} else {
@@ -2869,7 +2876,7 @@ fn method_motion(
} else {
possibilities.min().unwrap_or(offset)
};
- let new_point = map.clip_point(dest.to_display_point(map), Bias::Left);
+ let new_point = map.clip_point(MultiBufferOffset(dest).to_display_point(map), Bias::Left);
if new_point == display_point {
break;
}
@@ -2890,7 +2897,7 @@ fn comment_motion(
for _ in 0..times {
let point = map.display_point_to_point(display_point, Bias::Left);
- let offset = point.to_offset(&map.buffer_snapshot());
+ let offset = point.to_offset(&map.buffer_snapshot()).0;
let range = if direction == Direction::Prev {
0..offset
} else {
@@ -2923,7 +2930,7 @@ fn comment_motion(
} else {
possibilities.min().unwrap_or(offset)
};
- let new_point = map.clip_point(dest.to_display_point(map), Bias::Left);
+ let new_point = map.clip_point(MultiBufferOffset(dest).to_display_point(map), Bias::Left);
if new_point == display_point {
break;
}
@@ -2946,7 +2953,7 @@ fn section_motion(
.display_point_to_point(display_point, Bias::Left)
.to_offset(&map.buffer_snapshot());
let range = if direction == Direction::Prev {
- 0..offset
+ MultiBufferOffset(0)..offset
} else {
offset..map.buffer_snapshot().len()
};
@@ -2977,7 +2984,7 @@ fn section_motion(
let relevant = if is_start { range.start } else { range.end };
if direction == Direction::Prev && relevant < offset {
Some(relevant)
- } else if direction == Direction::Next && relevant > offset + 1 {
+ } else if direction == Direction::Next && relevant > offset + 1usize {
Some(relevant)
} else {
None
@@ -2985,7 +2992,7 @@ fn section_motion(
});
let offset = if direction == Direction::Prev {
- possibilities.max().unwrap_or(0)
+ possibilities.max().unwrap_or(MultiBufferOffset(0))
} else {
possibilities.min().unwrap_or(map.buffer_snapshot().len())
};
@@ -211,9 +211,14 @@ fn find_target(
let mut pre_char = String::new();
// Backward scan to find the start of the number, but stop at start_offset
- for ch in snapshot.reversed_chars_at(offset + if offset < snapshot.len() { 1 } else { 0 }) {
+ let next_offset = if offset < snapshot.len() {
+ offset + 1usize
+ } else {
+ offset
+ };
+ for ch in snapshot.reversed_chars_at(next_offset) {
// Search boundaries
- if offset == 0 || ch.is_whitespace() || (need_range && offset <= start_offset) {
+ if offset.0 == 0 || ch.is_whitespace() || (need_range && offset <= start_offset) {
break;
}
@@ -1,4 +1,7 @@
-use editor::{DisplayPoint, RowExt, SelectionEffects, display_map::ToDisplayPoint, movement};
+use editor::{
+ DisplayPoint, MultiBufferOffset, RowExt, SelectionEffects, display_map::ToDisplayPoint,
+ movement,
+};
use gpui::{Action, Context, Window};
use language::{Bias, SelectionGoal};
use schemars::JsonSchema;
@@ -174,7 +177,10 @@ impl Vim {
original_indent_columns.push(original_indent_column);
}
- let cursor_offset = editor.selections.last::<usize>(&display_map).head();
+ let cursor_offset = editor
+ .selections
+ .last::<MultiBufferOffset>(&display_map)
+ .head();
if editor
.buffer()
.read(cx)
@@ -6,7 +6,7 @@ use crate::{
state::{Mode, Operator},
};
use editor::{
- Bias, DisplayPoint, Editor, ToOffset,
+ Bias, BufferOffset, DisplayPoint, Editor, MultiBufferOffset, ToOffset,
display_map::{DisplaySnapshot, ToDisplayPoint},
movement::{self, FindRange},
};
@@ -81,8 +81,8 @@ pub struct CandidateRange {
#[derive(Debug, Clone)]
pub struct CandidateWithRanges {
candidate: CandidateRange,
- open_range: Range<usize>,
- close_range: Range<usize>,
+ open_range: Range<MultiBufferOffset>,
+ close_range: Range<MultiBufferOffset>,
}
/// Selects text at the same indentation level.
@@ -120,7 +120,7 @@ struct CurlyBrackets {
opening: bool,
}
-fn cover_or_next<I: Iterator<Item = (Range<usize>, Range<usize>)>>(
+fn cover_or_next<I: Iterator<Item = (Range<MultiBufferOffset>, Range<MultiBufferOffset>)>>(
candidates: Option<I>,
caret: DisplayPoint,
map: &DisplaySnapshot,
@@ -128,7 +128,7 @@ fn cover_or_next<I: Iterator<Item = (Range<usize>, Range<usize>)>>(
let caret_offset = caret.to_offset(map, Bias::Left);
let mut covering = vec![];
let mut next_ones = vec![];
- let snapshot = &map.buffer_snapshot();
+ let snapshot = map.buffer_snapshot();
if let Some(ranges) = candidates {
for (open_range, close_range) in ranges {
@@ -171,7 +171,7 @@ fn cover_or_next<I: Iterator<Item = (Range<usize>, Range<usize>)>>(
if !next_ones.is_empty() {
return next_ones.into_iter().min_by_key(|r| {
let start = r.candidate.start.to_offset(map, Bias::Left);
- (start as isize - caret_offset as isize).abs()
+ (start.0 as isize - caret_offset.0 as isize).abs()
});
}
@@ -181,8 +181,8 @@ fn cover_or_next<I: Iterator<Item = (Range<usize>, Range<usize>)>>(
type DelimiterPredicate = dyn Fn(&BufferSnapshot, usize, usize) -> bool;
struct DelimiterRange {
- open: Range<usize>,
- close: Range<usize>,
+ open: Range<MultiBufferOffset>,
+ close: Range<MultiBufferOffset>,
}
impl DelimiterRange {
@@ -221,14 +221,14 @@ fn find_mini_delimiters(
.buffer_snapshot()
.bracket_ranges(visible_line_range)
.map(|ranges| {
- ranges.filter_map(move |(open, close)| {
+ ranges.filter_map(|(open, close)| {
// Convert the ranges from multibuffer space to buffer space as
// that is what `is_valid_delimiter` expects, otherwise it might
// panic as the values might be out of bounds.
let buffer_open = excerpt.map_range_to_buffer(open.clone());
let buffer_close = excerpt.map_range_to_buffer(close.clone());
- if is_valid_delimiter(buffer, buffer_open.start, buffer_close.start) {
+ if is_valid_delimiter(buffer, buffer_open.start.0, buffer_close.start.0) {
Some((open, close))
} else {
None
@@ -252,8 +252,12 @@ fn find_mini_delimiters(
Some(
DelimiterRange {
- open: open_bracket,
- close: close_bracket,
+ open: excerpt.map_range_from_buffer(
+ BufferOffset(open_bracket.start)..BufferOffset(open_bracket.end),
+ ),
+ close: excerpt.map_range_from_buffer(
+ BufferOffset(close_bracket.start)..BufferOffset(close_bracket.end),
+ ),
}
.to_display_range(map, around),
)
@@ -899,7 +903,7 @@ pub fn surrounding_html_tag(
// Find the most closest to current offset
let mut cursor = buffer.syntax_layer_at(offset)?.node().walk();
let mut last_child_node = cursor.node();
- while cursor.goto_first_child_for_byte(offset).is_some() {
+ while cursor.goto_first_child_for_byte(offset.0).is_some() {
last_child_node = cursor.node();
}
@@ -916,10 +920,16 @@ pub fn surrounding_html_tag(
- range.start.to_offset(map, Bias::Left)
<= 1
{
- offset <= last_child.end_byte()
+ offset.0 <= last_child.end_byte()
} else {
- range.start.to_offset(map, Bias::Left) >= first_child.start_byte()
- && range.end.to_offset(map, Bias::Left) <= last_child.start_byte() + 1
+ excerpt
+ .map_offset_to_buffer(range.start.to_offset(map, Bias::Left))
+ .0
+ >= first_child.start_byte()
+ && excerpt
+ .map_offset_to_buffer(range.end.to_offset(map, Bias::Left))
+ .0
+ <= last_child.start_byte() + 1
};
if open_tag.is_some() && open_tag == close_tag && is_valid {
let range = if around {
@@ -927,6 +937,7 @@ pub fn surrounding_html_tag(
} else {
first_child.byte_range().end..last_child.byte_range().start
};
+ let range = BufferOffset(range.start)..BufferOffset(range.end);
if excerpt.contains_buffer_range(range.clone()) {
let result = excerpt.map_range_from_buffer(range);
return Some(
@@ -1093,7 +1104,8 @@ fn text_object(
.collect();
matches.sort_by_key(|r| r.end - r.start);
if let Some(buffer_range) = matches.first() {
- let range = excerpt.map_range_from_buffer(buffer_range.clone());
+ let buffer_range = BufferOffset(buffer_range.start)..BufferOffset(buffer_range.end);
+ let range = excerpt.map_range_from_buffer(buffer_range);
return Some(range.start.to_display_point(map)..range.end.to_display_point(map));
}
@@ -1113,10 +1125,12 @@ fn text_object(
if let Some(buffer_range) = matches.first()
&& !buffer_range.is_empty()
{
- let range = excerpt.map_range_from_buffer(buffer_range.clone());
+ let buffer_range = BufferOffset(buffer_range.start)..BufferOffset(buffer_range.end);
+ let range = excerpt.map_range_from_buffer(buffer_range);
return Some(range.start.to_display_point(map)..range.end.to_display_point(map));
}
- let buffer_range = excerpt.map_range_from_buffer(around_range.clone());
+ let around_range = BufferOffset(around_range.start)..BufferOffset(around_range.end);
+ let buffer_range = excerpt.map_range_from_buffer(around_range);
return Some(buffer_range.start.to_display_point(map)..buffer_range.end.to_display_point(map));
}
@@ -1134,9 +1148,9 @@ fn argument(
fn comma_delimited_range_at(
buffer: &BufferSnapshot,
- mut offset: usize,
+ mut offset: BufferOffset,
include_comma: bool,
- ) -> Option<Range<usize>> {
+ ) -> Option<Range<BufferOffset>> {
// Seek to the first non-whitespace character
offset += buffer
.chars_at(offset)
@@ -1151,7 +1165,7 @@ fn argument(
}
// If the cursor is outside the brackets, ignore them
- if open.start == offset || close.end == offset {
+ if open.start == offset.0 || close.end == offset.0 {
return false;
}
@@ -1167,7 +1181,7 @@ fn argument(
let (open_bracket, close_bracket) =
buffer.innermost_enclosing_bracket_ranges(offset..offset, Some(&bracket_filter))?;
- let inner_bracket_range = open_bracket.end..close_bracket.start;
+ let inner_bracket_range = BufferOffset(open_bracket.end)..BufferOffset(close_bracket.start);
let layer = buffer.syntax_layer_at(offset)?;
let node = layer.node();
@@ -1186,7 +1200,7 @@ fn argument(
parent_covers_bracket_range = covers_bracket_range;
// Unable to find a child node with a parent that covers the bracket range, so no argument to select
- cursor.goto_first_child_for_byte(offset)?;
+ cursor.goto_first_child_for_byte(offset.0)?;
}
let mut argument_node = cursor.node();
@@ -1256,7 +1270,7 @@ fn argument(
}
}
- Some(start..end)
+ Some(BufferOffset(start)..BufferOffset(end))
}
let result = comma_delimited_range_at(buffer, excerpt.map_offset_to_buffer(offset), around)?;
@@ -1387,7 +1401,7 @@ fn is_possible_sentence_start(character: char) -> bool {
const SENTENCE_END_PUNCTUATION: &[char] = &['.', '!', '?'];
const SENTENCE_END_FILLERS: &[char] = &[')', ']', '"', '\''];
const SENTENCE_END_WHITESPACE: &[char] = &[' ', '\t', '\n'];
-fn is_sentence_end(map: &DisplaySnapshot, offset: usize) -> bool {
+fn is_sentence_end(map: &DisplaySnapshot, offset: MultiBufferOffset) -> bool {
let mut next_chars = map.buffer_chars_at(offset).peekable();
if let Some((char, _)) = next_chars.next() {
// We are at a double newline. This position is a sentence end.
@@ -4,7 +4,7 @@ use crate::{
object::{Object, surrounding_markers},
state::Mode,
};
-use editor::{Bias, movement};
+use editor::{Bias, MultiBufferOffset, movement};
use gpui::{Context, Window};
use language::BracketPair;
@@ -175,7 +175,7 @@ impl Vim {
while let Some((ch, offset)) = chars_and_offset.next() {
if ch.to_string() == pair.start {
let start = offset;
- let mut end = start + 1;
+ let mut end = start + 1usize;
if surround
&& let Some((next_ch, _)) = chars_and_offset.peek()
&& next_ch.eq(&' ')
@@ -193,7 +193,7 @@ impl Vim {
while let Some((ch, offset)) = reverse_chars_and_offsets.next() {
if ch.to_string() == pair.end {
let mut start = offset;
- let end = start + 1;
+ let end = start + 1usize;
if surround
&& let Some((next_ch, _)) = reverse_chars_and_offsets.peek()
&& next_ch.eq(&' ')
@@ -282,7 +282,7 @@ impl Vim {
// that the end replacement string does not exceed
// this value. Helpful when dealing with newlines.
let mut edit_len = 0;
- let mut open_range_end = 0;
+ let mut open_range_end = MultiBufferOffset(0);
let mut chars_and_offset = display_map
.buffer_chars_at(range.start.to_offset(&display_map, Bias::Left))
.peekable();
@@ -291,7 +291,7 @@ impl Vim {
if ch.to_string() == will_replace_pair.start {
let mut open_str = pair.start.clone();
let start = offset;
- open_range_end = start + 1;
+ open_range_end = start + 1usize;
while let Some((next_ch, _)) = chars_and_offset.next()
&& next_ch == ' '
{
@@ -322,7 +322,7 @@ impl Vim {
if ch.to_string() == will_replace_pair.end {
let mut close_str = String::new();
let mut start = offset;
- let end = start + 1;
+ let end = start + 1usize;
while let Some((next_ch, _)) = reverse_chars_and_offsets.next()
&& next_ch == ' '
&& close_str.len() < edit_len - 1
@@ -7,7 +7,7 @@ use std::{sync::Arc, time::Duration};
use collections::HashMap;
use command_palette::CommandPalette;
use editor::{
- AnchorRangeExt, DisplayPoint, Editor, EditorMode, MultiBuffer,
+ AnchorRangeExt, DisplayPoint, Editor, EditorMode, MultiBuffer, MultiBufferOffset,
actions::{DeleteLine, WrapSelectionsInTag},
code_context_menus::CodeContextMenu,
display_map::DisplayRow,
@@ -908,6 +908,9 @@ fn assert_pending_input(cx: &mut VimTestContext, expected: &str) {
.map(|highlight| highlight.to_offset(&snapshot.buffer_snapshot()))
.collect::<Vec<_>>(),
ranges
+ .iter()
+ .map(|range| MultiBufferOffset(range.start)..MultiBufferOffset(range.end))
+ .collect::<Vec<_>>()
)
});
}
@@ -967,7 +970,7 @@ async fn test_jk_delay(cx: &mut gpui::TestAppContext) {
.iter()
.map(|highlight| highlight.to_offset(&snapshot.buffer_snapshot()))
.collect::<Vec<_>>(),
- vec![0..1]
+ vec![MultiBufferOffset(0)..MultiBufferOffset(1)]
)
});
cx.executor().advance_clock(Duration::from_millis(500));
@@ -21,8 +21,8 @@ mod visual;
use collections::HashMap;
use editor::{
- Anchor, Bias, Editor, EditorEvent, EditorSettings, HideMouseCursorOrigin, SelectionEffects,
- ToPoint,
+ Anchor, Bias, Editor, EditorEvent, EditorSettings, HideMouseCursorOrigin, MultiBufferOffset,
+ SelectionEffects, ToPoint,
actions::Paste,
movement::{self, FindRange},
};
@@ -1388,7 +1388,7 @@ impl Vim {
let newest_selection_empty = editor.update(cx, |editor, cx| {
editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx))
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
.is_empty()
});
let editor = editor.read(cx);
@@ -1488,7 +1488,7 @@ impl Vim {
let snapshot = &editor.snapshot(window, cx);
let selection = editor
.selections
- .newest::<usize>(&snapshot.display_snapshot);
+ .newest::<MultiBufferOffset>(&snapshot.display_snapshot);
let snapshot = snapshot.buffer_snapshot();
let (range, kind) =
@@ -2,7 +2,7 @@ use std::sync::Arc;
use collections::HashMap;
use editor::{
- Bias, DisplayPoint, Editor, SelectionEffects,
+ Bias, DisplayPoint, Editor, MultiBufferOffset, SelectionEffects,
display_map::{DisplaySnapshot, ToDisplayPoint},
movement,
};
@@ -778,7 +778,7 @@ impl Vim {
{
let range = row_range.start.to_offset(&display_map, Bias::Right)
..row_range.end.to_offset(&display_map, Bias::Right);
- let text = text.repeat(range.len());
+ let text = text.repeat(range.end - range.start);
edits.push((range, text));
}
}
@@ -844,8 +844,8 @@ impl Vim {
return;
};
let vim_is_normal = self.mode == Mode::Normal;
- let mut start_selection = 0usize;
- let mut end_selection = 0usize;
+ let mut start_selection = MultiBufferOffset(0);
+ let mut end_selection = MultiBufferOffset(0);
self.update_editor(cx, |_, editor, _| {
editor.set_collapse_matches(false);
@@ -868,7 +868,7 @@ impl Vim {
self.update_editor(cx, |_, editor, cx| {
let latest = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx));
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx));
start_selection = latest.start;
end_selection = latest.end;
});
@@ -891,7 +891,7 @@ impl Vim {
self.update_editor(cx, |_, editor, cx| {
let latest = editor
.selections
- .newest::<usize>(&editor.display_snapshot(cx));
+ .newest::<MultiBufferOffset>(&editor.display_snapshot(cx));
if vim_is_normal {
start_selection = latest.start;
end_selection = latest.end;
@@ -2241,7 +2241,9 @@ mod tests {
use super::*;
use assets::Assets;
use collections::HashSet;
- use editor::{DisplayPoint, Editor, SelectionEffects, display_map::DisplayRow};
+ use editor::{
+ DisplayPoint, Editor, MultiBufferOffset, SelectionEffects, display_map::DisplayRow,
+ };
use gpui::{
Action, AnyWindowHandle, App, AssetSource, BorrowAppContext, SemanticVersion,
TestAppContext, UpdateGlobal, VisualTestContext, WindowHandle, actions,
@@ -3508,7 +3510,11 @@ mod tests {
assert!(!editor.is_dirty(cx));
assert_eq!(editor.title(cx), "untitled");
assert!(Arc::ptr_eq(
- &editor.buffer().read(cx).language_at(0, cx).unwrap(),
+ &editor
+ .buffer()
+ .read(cx)
+ .language_at(MultiBufferOffset(0), cx)
+ .unwrap(),
&languages::PLAIN_TEXT
));
editor.handle_input("hi", window, cx);
@@ -3542,7 +3548,12 @@ mod tests {
assert!(!editor.is_dirty(cx));
assert_eq!(editor.title(cx), "the-new-name.rs");
assert_eq!(
- editor.buffer().read(cx).language_at(0, cx).unwrap().name(),
+ editor
+ .buffer()
+ .read(cx)
+ .language_at(MultiBufferOffset(0), cx)
+ .unwrap()
+ .name(),
"Rust".into()
);
});
@@ -3648,7 +3659,11 @@ mod tests {
.update(cx, |_, window, cx| {
editor.update(cx, |editor, cx| {
assert!(Arc::ptr_eq(
- &editor.buffer().read(cx).language_at(0, cx).unwrap(),
+ &editor
+ .buffer()
+ .read(cx)
+ .language_at(MultiBufferOffset(0), cx)
+ .unwrap(),
&languages::PLAIN_TEXT
));
editor.handle_input("hi", window, cx);
@@ -3672,7 +3687,12 @@ mod tests {
editor.update(cx, |editor, cx| {
assert!(!editor.is_dirty(cx));
assert_eq!(
- editor.buffer().read(cx).language_at(0, cx).unwrap().name(),
+ editor
+ .buffer()
+ .read(cx)
+ .language_at(MultiBufferOffset(0), cx)
+ .unwrap()
+ .name(),
"Rust".into()
)
});