mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 02:17:35 +03:00
Introduce DisplayRow, MultiBufferRow newtypes and BufferRow type alias (#11656)
Part of https://github.com/zed-industries/zed/issues/8081 To avoid confusion and bugs when converting between various row `u32`'s, use different types for each. Further PRs should split `Point` into buffer and multi buffer variants and make the code more readable. Release Notes: - N/A --------- Co-authored-by: Piotr <piotr@zed.dev>
This commit is contained in:
parent
38f110852f
commit
df41435d1a
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -2325,6 +2325,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"lsp",
|
"lsp",
|
||||||
"menu",
|
"menu",
|
||||||
|
"multi_buffer",
|
||||||
"nanoid",
|
"nanoid",
|
||||||
"node_runtime",
|
"node_runtime",
|
||||||
"notifications",
|
"notifications",
|
||||||
@ -6282,6 +6283,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
"serde",
|
||||||
"settings",
|
"settings",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"sum_tree",
|
"sum_tree",
|
||||||
@ -11315,6 +11317,7 @@ dependencies = [
|
|||||||
"language",
|
"language",
|
||||||
"log",
|
"log",
|
||||||
"lsp",
|
"lsp",
|
||||||
|
"multi_buffer",
|
||||||
"nvim-rs",
|
"nvim-rs",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -18,7 +18,7 @@ use editor::{
|
|||||||
},
|
},
|
||||||
scroll::{Autoscroll, AutoscrollStrategy},
|
scroll::{Autoscroll, AutoscrollStrategy},
|
||||||
Anchor, Editor, EditorElement, EditorEvent, EditorStyle, MultiBuffer, MultiBufferSnapshot,
|
Anchor, Editor, EditorElement, EditorEvent, EditorStyle, MultiBuffer, MultiBufferSnapshot,
|
||||||
ToOffset as _, ToPoint,
|
RowExt, ToOffset as _, ToPoint,
|
||||||
};
|
};
|
||||||
use file_icons::FileIcons;
|
use file_icons::FileIcons;
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
@ -32,6 +32,7 @@ use gpui::{
|
|||||||
View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext,
|
View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext,
|
||||||
};
|
};
|
||||||
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _};
|
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use search::{buffer_search::DivRegistrar, BufferSearchBar};
|
use search::{buffer_search::DivRegistrar, BufferSearchBar};
|
||||||
@ -306,7 +307,7 @@ impl AssistantPanel {
|
|||||||
if point_selection.end.column == 0 {
|
if point_selection.end.column == 0 {
|
||||||
point_selection.end.row -= 1;
|
point_selection.end.row -= 1;
|
||||||
}
|
}
|
||||||
point_selection.end.column = snapshot.line_len(point_selection.end.row);
|
point_selection.end.column = snapshot.line_len(MultiBufferRow(point_selection.end.row));
|
||||||
}
|
}
|
||||||
|
|
||||||
let codegen_kind = if point_selection.start == point_selection.end {
|
let codegen_kind = if point_selection.start == point_selection.end {
|
||||||
@ -2168,7 +2169,7 @@ impl ConversationEditor {
|
|||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
let cursor_point = scroll_position.cursor.to_display_point(&snapshot);
|
let cursor_point = scroll_position.cursor.to_display_point(&snapshot);
|
||||||
let scroll_top =
|
let scroll_top =
|
||||||
cursor_point.row() as f32 - scroll_position.offset_before_cursor.y;
|
cursor_point.row().as_f32() - scroll_position.offset_before_cursor.y;
|
||||||
editor.set_scroll_position(
|
editor.set_scroll_position(
|
||||||
point(scroll_position.offset_before_cursor.x, scroll_top),
|
point(scroll_position.offset_before_cursor.x, scroll_top),
|
||||||
cx,
|
cx,
|
||||||
@ -2236,7 +2237,10 @@ impl ConversationEditor {
|
|||||||
self.editor.update(cx, |editor, cx| {
|
self.editor.update(cx, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
let cursor = editor.selections.newest_anchor().head();
|
let cursor = editor.selections.newest_anchor().head();
|
||||||
let cursor_row = cursor.to_display_point(&snapshot.display_snapshot).row() as f32;
|
let cursor_row = cursor
|
||||||
|
.to_display_point(&snapshot.display_snapshot)
|
||||||
|
.row()
|
||||||
|
.as_f32();
|
||||||
let scroll_position = editor
|
let scroll_position = editor
|
||||||
.scroll_manager
|
.scroll_manager
|
||||||
.anchor()
|
.anchor()
|
||||||
|
@ -7,6 +7,7 @@ use editor::{Anchor, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint};
|
|||||||
use futures::{channel::mpsc, SinkExt, Stream, StreamExt};
|
use futures::{channel::mpsc, SinkExt, Stream, StreamExt};
|
||||||
use gpui::{EventEmitter, Model, ModelContext, Task};
|
use gpui::{EventEmitter, Model, ModelContext, Task};
|
||||||
use language::{Rope, TransactionId};
|
use language::{Rope, TransactionId};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use std::{cmp, future, ops::Range};
|
use std::{cmp, future, ops::Range};
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
@ -100,7 +101,7 @@ impl Codegen {
|
|||||||
.suggested_indents(selection_start.row..selection_start.row + 1, cx)
|
.suggested_indents(selection_start.row..selection_start.row + 1, cx)
|
||||||
.into_values()
|
.into_values()
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or_else(|| snapshot.indent_size_for_line(selection_start.row));
|
.unwrap_or_else(|| snapshot.indent_size_for_line(MultiBufferRow(selection_start.row)));
|
||||||
|
|
||||||
let response = CompletionProvider::global(cx).complete(prompt);
|
let response = CompletionProvider::global(cx).complete(prompt);
|
||||||
self.generation = cx.spawn(|this, mut cx| {
|
self.generation = cx.spawn(|this, mut cx| {
|
||||||
|
@ -90,6 +90,7 @@ language = { workspace = true, features = ["test-support"] }
|
|||||||
live_kit_client = { workspace = true, features = ["test-support"] }
|
live_kit_client = { workspace = true, features = ["test-support"] }
|
||||||
lsp = { workspace = true, features = ["test-support"] }
|
lsp = { workspace = true, features = ["test-support"] }
|
||||||
menu.workspace = true
|
menu.workspace = true
|
||||||
|
multi_buffer = { workspace = true, features = ["test-support"] }
|
||||||
node_runtime.workspace = true
|
node_runtime.workspace = true
|
||||||
notifications = { workspace = true, features = ["test-support"] }
|
notifications = { workspace = true, features = ["test-support"] }
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
|
@ -9,6 +9,7 @@ use editor::{
|
|||||||
ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst, Redo, Rename,
|
ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst, Redo, Rename,
|
||||||
RevertSelectedHunks, ToggleCodeActions, Undo,
|
RevertSelectedHunks, ToggleCodeActions, Undo,
|
||||||
},
|
},
|
||||||
|
display_map::DisplayRow,
|
||||||
test::{
|
test::{
|
||||||
editor_hunks,
|
editor_hunks,
|
||||||
editor_test_context::{AssertionContextManager, EditorTestContext},
|
editor_test_context::{AssertionContextManager, EditorTestContext},
|
||||||
@ -24,6 +25,7 @@ use language::{
|
|||||||
language_settings::{AllLanguageSettings, InlayHintSettings},
|
language_settings::{AllLanguageSettings, InlayHintSettings},
|
||||||
FakeLspAdapter,
|
FakeLspAdapter,
|
||||||
};
|
};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use project::{
|
use project::{
|
||||||
project_settings::{InlineBlameSettings, ProjectSettings},
|
project_settings::{InlineBlameSettings, ProjectSettings},
|
||||||
SERVER_PROGRESS_DEBOUNCE_TIMEOUT,
|
SERVER_PROGRESS_DEBOUNCE_TIMEOUT,
|
||||||
@ -2114,14 +2116,30 @@ struct Row10;"#};
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
all_hunks,
|
all_hunks,
|
||||||
vec![
|
vec![
|
||||||
("".to_string(), DiffHunkStatus::Added, 1..3),
|
(
|
||||||
("struct Row2;\n".to_string(), DiffHunkStatus::Removed, 4..4),
|
"".to_string(),
|
||||||
("struct Row5;\n".to_string(), DiffHunkStatus::Modified, 6..7),
|
DiffHunkStatus::Added,
|
||||||
("struct Row8;\n".to_string(), DiffHunkStatus::Removed, 9..9),
|
DisplayRow(1)..DisplayRow(3)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"struct Row2;\n".to_string(),
|
||||||
|
DiffHunkStatus::Removed,
|
||||||
|
DisplayRow(4)..DisplayRow(4)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"struct Row5;\n".to_string(),
|
||||||
|
DiffHunkStatus::Modified,
|
||||||
|
DisplayRow(6)..DisplayRow(7)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"struct Row8;\n".to_string(),
|
||||||
|
DiffHunkStatus::Removed,
|
||||||
|
DisplayRow(9)..DisplayRow(9)
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"struct Row10;".to_string(),
|
"struct Row10;".to_string(),
|
||||||
DiffHunkStatus::Modified,
|
DiffHunkStatus::Modified,
|
||||||
10..10,
|
DisplayRow(10)..DisplayRow(10),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -2133,23 +2151,35 @@ struct Row10;"#};
|
|||||||
let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx);
|
let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expanded_hunks_background_highlights(editor, cx),
|
expanded_hunks_background_highlights(editor, cx),
|
||||||
vec![1..=2, 8..=8],
|
vec![DisplayRow(1)..=DisplayRow(2), DisplayRow(8)..=DisplayRow(8)],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
all_hunks,
|
all_hunks,
|
||||||
vec![
|
vec![
|
||||||
("".to_string(), DiffHunkStatus::Added, 1..3),
|
(
|
||||||
("struct Row2;\n".to_string(), DiffHunkStatus::Removed, 5..5),
|
"".to_string(),
|
||||||
("struct Row5;\n".to_string(), DiffHunkStatus::Modified, 8..9),
|
DiffHunkStatus::Added,
|
||||||
|
DisplayRow(1)..DisplayRow(3)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"struct Row2;\n".to_string(),
|
||||||
|
DiffHunkStatus::Removed,
|
||||||
|
DisplayRow(5)..DisplayRow(5)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"struct Row5;\n".to_string(),
|
||||||
|
DiffHunkStatus::Modified,
|
||||||
|
DisplayRow(8)..DisplayRow(9)
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"struct Row8;\n".to_string(),
|
"struct Row8;\n".to_string(),
|
||||||
DiffHunkStatus::Removed,
|
DiffHunkStatus::Removed,
|
||||||
12..12
|
DisplayRow(12)..DisplayRow(12)
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"struct Row10;".to_string(),
|
"struct Row10;".to_string(),
|
||||||
DiffHunkStatus::Modified,
|
DiffHunkStatus::Modified,
|
||||||
13..13,
|
DisplayRow(13)..DisplayRow(13),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -2173,7 +2203,7 @@ struct Row10;"#};
|
|||||||
vec![(
|
vec![(
|
||||||
"struct Row10;".to_string(),
|
"struct Row10;".to_string(),
|
||||||
DiffHunkStatus::Modified,
|
DiffHunkStatus::Modified,
|
||||||
10..10,
|
DisplayRow(10)..DisplayRow(10),
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(all_expanded_hunks, Vec::new());
|
assert_eq!(all_expanded_hunks, Vec::new());
|
||||||
@ -2184,14 +2214,14 @@ struct Row10;"#};
|
|||||||
let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx);
|
let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expanded_hunks_background_highlights(editor, cx),
|
expanded_hunks_background_highlights(editor, cx),
|
||||||
vec![5..=5]
|
vec![DisplayRow(5)..=DisplayRow(5)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
all_hunks,
|
all_hunks,
|
||||||
vec![(
|
vec![(
|
||||||
"struct Row10;".to_string(),
|
"struct Row10;".to_string(),
|
||||||
DiffHunkStatus::Modified,
|
DiffHunkStatus::Modified,
|
||||||
10..10,
|
DisplayRow(10)..DisplayRow(10),
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
assert_eq!(all_expanded_hunks, Vec::new());
|
assert_eq!(all_expanded_hunks, Vec::new());
|
||||||
@ -2330,7 +2360,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
|||||||
let blame = editor_b.blame().expect("editor_b should have blame now");
|
let blame = editor_b.blame().expect("editor_b should have blame now");
|
||||||
let entries = blame.update(cx, |blame, cx| {
|
let entries = blame.update(cx, |blame, cx| {
|
||||||
blame
|
blame
|
||||||
.blame_for_rows((0..4).map(Some), cx)
|
.blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2369,7 +2399,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
|||||||
let blame = editor_b.blame().expect("editor_b should have blame now");
|
let blame = editor_b.blame().expect("editor_b should have blame now");
|
||||||
let entries = blame.update(cx, |blame, cx| {
|
let entries = blame.update(cx, |blame, cx| {
|
||||||
blame
|
blame
|
||||||
.blame_for_rows((0..4).map(Some), cx)
|
.blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2396,7 +2426,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
|||||||
let blame = editor_b.blame().expect("editor_b should have blame now");
|
let blame = editor_b.blame().expect("editor_b should have blame now");
|
||||||
let entries = blame.update(cx, |blame, cx| {
|
let entries = blame.update(cx, |blame, cx| {
|
||||||
blame
|
blame
|
||||||
.blame_for_rows((0..4).map(Some), cx)
|
.blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::{BlockContext, TransformBlock},
|
display_map::{BlockContext, DisplayRow, TransformBlock},
|
||||||
DisplayPoint, GutterDimensions,
|
DisplayPoint, GutterDimensions,
|
||||||
};
|
};
|
||||||
use gpui::{px, AvailableSpace, Stateful, TestAppContext, VisualTestContext};
|
use gpui::{px, AvailableSpace, Stateful, TestAppContext, VisualTestContext};
|
||||||
@ -158,11 +158,11 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
(15, "collapsed context".into()),
|
(DisplayRow(15), "collapsed context".into()),
|
||||||
(16, "diagnostic header".into()),
|
(DisplayRow(16), "diagnostic header".into()),
|
||||||
(25, "collapsed context".into()),
|
(DisplayRow(25), "collapsed context".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -210,7 +210,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
|||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.selections.display_ranges(cx),
|
editor.selections.display_ranges(cx),
|
||||||
[DisplayPoint::new(12, 6)..DisplayPoint::new(12, 6)]
|
[DisplayPoint::new(DisplayRow(12), 6)..DisplayPoint::new(DisplayRow(12), 6)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -243,13 +243,13 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
(7, "path header block".into()),
|
(DisplayRow(7), "path header block".into()),
|
||||||
(9, "diagnostic header".into()),
|
(DisplayRow(9), "diagnostic header".into()),
|
||||||
(22, "collapsed context".into()),
|
(DisplayRow(22), "collapsed context".into()),
|
||||||
(23, "diagnostic header".into()),
|
(DisplayRow(23), "diagnostic header".into()),
|
||||||
(32, "collapsed context".into()),
|
(DisplayRow(32), "collapsed context".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -309,7 +309,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
|||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.selections.display_ranges(cx),
|
editor.selections.display_ranges(cx),
|
||||||
[DisplayPoint::new(19, 6)..DisplayPoint::new(19, 6)]
|
[DisplayPoint::new(DisplayRow(19), 6)..DisplayPoint::new(DisplayRow(19), 6)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -355,15 +355,15 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
(7, "collapsed context".into()),
|
(DisplayRow(7), "collapsed context".into()),
|
||||||
(8, "diagnostic header".into()),
|
(DisplayRow(8), "diagnostic header".into()),
|
||||||
(13, "path header block".into()),
|
(DisplayRow(13), "path header block".into()),
|
||||||
(15, "diagnostic header".into()),
|
(DisplayRow(15), "diagnostic header".into()),
|
||||||
(28, "collapsed context".into()),
|
(DisplayRow(28), "collapsed context".into()),
|
||||||
(29, "diagnostic header".into()),
|
(DisplayRow(29), "diagnostic header".into()),
|
||||||
(38, "collapsed context".into()),
|
(DisplayRow(38), "collapsed context".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -493,8 +493,8 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -539,10 +539,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
(6, "collapsed context".into()),
|
(DisplayRow(6), "collapsed context".into()),
|
||||||
(7, "diagnostic header".into()),
|
(DisplayRow(7), "diagnostic header".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -605,10 +605,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
(7, "collapsed context".into()),
|
(DisplayRow(7), "collapsed context".into()),
|
||||||
(8, "diagnostic header".into()),
|
(DisplayRow(8), "diagnostic header".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -661,10 +661,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor_blocks(&editor, cx),
|
editor_blocks(&editor, cx),
|
||||||
[
|
[
|
||||||
(0, "path header block".into()),
|
(DisplayRow(0), "path header block".into()),
|
||||||
(2, "diagnostic header".into()),
|
(DisplayRow(2), "diagnostic header".into()),
|
||||||
(7, "collapsed context".into()),
|
(DisplayRow(7), "collapsed context".into()),
|
||||||
(8, "diagnostic header".into()),
|
(DisplayRow(8), "diagnostic header".into()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -958,14 +958,17 @@ fn random_diagnostic(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor_blocks(editor: &View<Editor>, cx: &mut VisualTestContext) -> Vec<(u32, SharedString)> {
|
fn editor_blocks(
|
||||||
|
editor: &View<Editor>,
|
||||||
|
cx: &mut VisualTestContext,
|
||||||
|
) -> Vec<(DisplayRow, SharedString)> {
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
cx.draw(gpui::Point::default(), AvailableSpace::min_size(), |cx| {
|
cx.draw(gpui::Point::default(), AvailableSpace::min_size(), |cx| {
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
blocks.extend(
|
blocks.extend(
|
||||||
snapshot
|
snapshot
|
||||||
.blocks_in_range(0..snapshot.max_point().row())
|
.blocks_in_range(DisplayRow(0)..snapshot.max_point().row())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(ix, (row, block))| {
|
.filter_map(|(ix, (row, block))| {
|
||||||
let name: SharedString = match block {
|
let name: SharedString = match block {
|
||||||
|
@ -54,7 +54,7 @@ pub struct SelectToEndOfLine {
|
|||||||
pub struct ToggleCodeActions {
|
pub struct ToggleCodeActions {
|
||||||
// Display row from which the action was deployed.
|
// Display row from which the action was deployed.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub deployed_from_indicator: Option<u32>,
|
pub deployed_from_indicator: Option<DisplayRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Deserialize, Default)]
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
@ -77,12 +77,12 @@ pub struct ToggleComments {
|
|||||||
|
|
||||||
#[derive(PartialEq, Clone, Deserialize, Default)]
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
pub struct FoldAt {
|
pub struct FoldAt {
|
||||||
pub buffer_row: u32,
|
pub buffer_row: MultiBufferRow,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Deserialize, Default)]
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
pub struct UnfoldAt {
|
pub struct UnfoldAt {
|
||||||
pub buffer_row: u32,
|
pub buffer_row: MultiBufferRow,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Deserialize, Default)]
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
|
@ -23,8 +23,8 @@ mod inlay_map;
|
|||||||
mod tab_map;
|
mod tab_map;
|
||||||
mod wrap_map;
|
mod wrap_map;
|
||||||
|
|
||||||
use crate::EditorStyle;
|
|
||||||
use crate::{hover_links::InlayHighlight, movement::TextLayoutDetails, InlayId};
|
use crate::{hover_links::InlayHighlight, movement::TextLayoutDetails, InlayId};
|
||||||
|
use crate::{EditorStyle, RowExt};
|
||||||
pub use block_map::{BlockMap, BlockPoint};
|
pub use block_map::{BlockMap, BlockPoint};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use fold_map::FoldMap;
|
use fold_map::FoldMap;
|
||||||
@ -34,7 +34,11 @@ use language::{
|
|||||||
language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription,
|
language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription,
|
||||||
};
|
};
|
||||||
use lsp::DiagnosticSeverity;
|
use lsp::DiagnosticSeverity;
|
||||||
use multi_buffer::{Anchor, AnchorRangeExt, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint};
|
use multi_buffer::{
|
||||||
|
Anchor, AnchorRangeExt, MultiBuffer, MultiBufferPoint, MultiBufferRow, MultiBufferSnapshot,
|
||||||
|
ToOffset, ToPoint,
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
|
use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
|
||||||
use sum_tree::{Bias, TreeMap};
|
use sum_tree::{Bias, TreeMap};
|
||||||
use tab_map::TabMap;
|
use tab_map::TabMap;
|
||||||
@ -42,10 +46,11 @@ use tab_map::TabMap;
|
|||||||
use wrap_map::WrapMap;
|
use wrap_map::WrapMap;
|
||||||
|
|
||||||
pub use block_map::{
|
pub use block_map::{
|
||||||
BlockBufferRows as DisplayBufferRows, BlockChunks as DisplayChunks, BlockContext,
|
BlockBufferRows, BlockChunks as DisplayChunks, BlockContext, BlockDisposition, BlockId,
|
||||||
BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock,
|
BlockProperties, BlockStyle, RenderBlock, TransformBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::block_map::BlockRow;
|
||||||
pub use self::fold_map::{Fold, FoldId, FoldPoint};
|
pub use self::fold_map::{Fold, FoldId, FoldPoint};
|
||||||
pub use self::inlay_map::{InlayOffset, InlayPoint};
|
pub use self::inlay_map::{InlayOffset, InlayPoint};
|
||||||
pub(crate) use inlay_map::Inlay;
|
pub(crate) use inlay_map::Inlay;
|
||||||
@ -65,6 +70,17 @@ pub trait ToDisplayPoint {
|
|||||||
type TextHighlights = TreeMap<Option<TypeId>, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>;
|
type TextHighlights = TreeMap<Option<TypeId>, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>;
|
||||||
type InlayHighlights = TreeMap<TypeId, TreeMap<InlayId, (HighlightStyle, InlayHighlight)>>;
|
type InlayHighlights = TreeMap<TypeId, TreeMap<InlayId, (HighlightStyle, InlayHighlight)>>;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DisplayBufferRows<'a>(BlockBufferRows<'a>);
|
||||||
|
|
||||||
|
impl<'a> Iterator for DisplayBufferRows<'a> {
|
||||||
|
type Item = Option<DisplayRow>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next().map(|row| row.map(|r| DisplayRow(r.0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Decides how text in a [`MultiBuffer`] should be displayed in a buffer, handling inlay hints,
|
/// Decides how text in a [`MultiBuffer`] should be displayed in a buffer, handling inlay hints,
|
||||||
/// folding, hard tabs, soft wrapping, custom blocks (like diagnostics), and highlighting.
|
/// folding, hard tabs, soft wrapping, custom blocks (like diagnostics), and highlighting.
|
||||||
///
|
///
|
||||||
@ -382,15 +398,15 @@ impl DisplaySnapshot {
|
|||||||
self.buffer_snapshot.len() == 0
|
self.buffer_snapshot.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_rows(&self, start_row: u32) -> DisplayBufferRows {
|
pub fn display_rows(&self, start_row: DisplayRow) -> DisplayBufferRows {
|
||||||
self.block_snapshot.buffer_rows(start_row)
|
DisplayBufferRows(self.block_snapshot.buffer_rows(BlockRow(start_row.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_buffer_row(&self) -> u32 {
|
pub fn max_buffer_row(&self) -> MultiBufferRow {
|
||||||
self.buffer_snapshot.max_buffer_row()
|
self.buffer_snapshot.max_buffer_row()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prev_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
|
pub fn prev_line_boundary(&self, mut point: MultiBufferPoint) -> (Point, DisplayPoint) {
|
||||||
loop {
|
loop {
|
||||||
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||||
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Left);
|
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Left);
|
||||||
@ -408,7 +424,7 @@ impl DisplaySnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
|
pub fn next_line_boundary(&self, mut point: MultiBufferPoint) -> (Point, DisplayPoint) {
|
||||||
loop {
|
loop {
|
||||||
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||||
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Right);
|
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Right);
|
||||||
@ -429,13 +445,14 @@ impl DisplaySnapshot {
|
|||||||
// used by line_mode selections and tries to match vim behaviour
|
// used by line_mode selections and tries to match vim behaviour
|
||||||
pub fn expand_to_line(&self, range: Range<Point>) -> Range<Point> {
|
pub fn expand_to_line(&self, range: Range<Point>) -> Range<Point> {
|
||||||
let new_start = if range.start.row == 0 {
|
let new_start = if range.start.row == 0 {
|
||||||
Point::new(0, 0)
|
MultiBufferPoint::new(0, 0)
|
||||||
} else if range.start.row == self.max_buffer_row()
|
} else if range.start.row == self.max_buffer_row().0
|
||||||
|| (range.end.column > 0 && range.end.row == self.max_buffer_row())
|
|| (range.end.column > 0 && range.end.row == self.max_buffer_row().0)
|
||||||
{
|
{
|
||||||
Point::new(
|
MultiBufferPoint::new(
|
||||||
range.start.row - 1,
|
range.start.row - 1,
|
||||||
self.buffer_snapshot.line_len(range.start.row - 1),
|
self.buffer_snapshot
|
||||||
|
.line_len(MultiBufferRow(range.start.row - 1)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.prev_line_boundary(range.start).0
|
self.prev_line_boundary(range.start).0
|
||||||
@ -443,9 +460,9 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
let new_end = if range.end.column == 0 {
|
let new_end = if range.end.column == 0 {
|
||||||
range.end
|
range.end
|
||||||
} else if range.end.row < self.max_buffer_row() {
|
} else if range.end.row < self.max_buffer_row().0 {
|
||||||
self.buffer_snapshot
|
self.buffer_snapshot
|
||||||
.clip_point(Point::new(range.end.row + 1, 0), Bias::Left)
|
.clip_point(MultiBufferPoint::new(range.end.row + 1, 0), Bias::Left)
|
||||||
} else {
|
} else {
|
||||||
self.buffer_snapshot.max_point()
|
self.buffer_snapshot.max_point()
|
||||||
};
|
};
|
||||||
@ -453,7 +470,7 @@ impl DisplaySnapshot {
|
|||||||
new_start..new_end
|
new_start..new_end
|
||||||
}
|
}
|
||||||
|
|
||||||
fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
|
fn point_to_display_point(&self, point: MultiBufferPoint, bias: Bias) -> DisplayPoint {
|
||||||
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||||
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
||||||
@ -509,10 +526,10 @@ impl DisplaySnapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns text chunks starting at the given display row until the end of the file
|
/// Returns text chunks starting at the given display row until the end of the file
|
||||||
pub fn text_chunks(&self, display_row: u32) -> impl Iterator<Item = &str> {
|
pub fn text_chunks(&self, display_row: DisplayRow) -> impl Iterator<Item = &str> {
|
||||||
self.block_snapshot
|
self.block_snapshot
|
||||||
.chunks(
|
.chunks(
|
||||||
display_row..self.max_point().row() + 1,
|
display_row.0..self.max_point().row().next_row().0,
|
||||||
false,
|
false,
|
||||||
Highlights::default(),
|
Highlights::default(),
|
||||||
)
|
)
|
||||||
@ -520,8 +537,8 @@ impl DisplaySnapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns text chunks starting at the end of the given display row in reverse until the start of the file
|
/// Returns text chunks starting at the end of the given display row in reverse until the start of the file
|
||||||
pub fn reverse_text_chunks(&self, display_row: u32) -> impl Iterator<Item = &str> {
|
pub fn reverse_text_chunks(&self, display_row: DisplayRow) -> impl Iterator<Item = &str> {
|
||||||
(0..=display_row).rev().flat_map(|row| {
|
(0..=display_row.0).rev().flat_map(|row| {
|
||||||
self.block_snapshot
|
self.block_snapshot
|
||||||
.chunks(row..row + 1, false, Highlights::default())
|
.chunks(row..row + 1, false, Highlights::default())
|
||||||
.map(|h| h.text)
|
.map(|h| h.text)
|
||||||
@ -533,12 +550,12 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn chunks(
|
pub fn chunks(
|
||||||
&self,
|
&self,
|
||||||
display_rows: Range<u32>,
|
display_rows: Range<DisplayRow>,
|
||||||
language_aware: bool,
|
language_aware: bool,
|
||||||
highlight_styles: HighlightStyles,
|
highlight_styles: HighlightStyles,
|
||||||
) -> DisplayChunks<'_> {
|
) -> DisplayChunks<'_> {
|
||||||
self.block_snapshot.chunks(
|
self.block_snapshot.chunks(
|
||||||
display_rows,
|
display_rows.start.0..display_rows.end.0,
|
||||||
language_aware,
|
language_aware,
|
||||||
Highlights {
|
Highlights {
|
||||||
text_highlights: Some(&self.text_highlights),
|
text_highlights: Some(&self.text_highlights),
|
||||||
@ -550,7 +567,7 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn highlighted_chunks<'a>(
|
pub fn highlighted_chunks<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
display_rows: Range<u32>,
|
display_rows: Range<DisplayRow>,
|
||||||
language_aware: bool,
|
language_aware: bool,
|
||||||
editor_style: &'a EditorStyle,
|
editor_style: &'a EditorStyle,
|
||||||
) -> impl Iterator<Item = HighlightedChunk<'a>> {
|
) -> impl Iterator<Item = HighlightedChunk<'a>> {
|
||||||
@ -610,7 +627,7 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn layout_row(
|
pub fn layout_row(
|
||||||
&self,
|
&self,
|
||||||
display_row: u32,
|
display_row: DisplayRow,
|
||||||
TextLayoutDetails {
|
TextLayoutDetails {
|
||||||
text_system,
|
text_system,
|
||||||
editor_style,
|
editor_style,
|
||||||
@ -623,7 +640,7 @@ impl DisplaySnapshot {
|
|||||||
let mut runs = Vec::new();
|
let mut runs = Vec::new();
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
|
||||||
let range = display_row..display_row + 1;
|
let range = display_row..display_row.next_row();
|
||||||
for chunk in self.highlighted_chunks(range, false, &editor_style) {
|
for chunk in self.highlighted_chunks(range, false, &editor_style) {
|
||||||
line.push_str(chunk.chunk);
|
line.push_str(chunk.chunk);
|
||||||
|
|
||||||
@ -663,7 +680,7 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn display_column_for_x(
|
pub fn display_column_for_x(
|
||||||
&self,
|
&self,
|
||||||
display_row: u32,
|
display_row: DisplayRow,
|
||||||
x: Pixels,
|
x: Pixels,
|
||||||
details: &TextLayoutDetails,
|
details: &TextLayoutDetails,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
@ -732,7 +749,7 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn clip_at_line_end(&self, point: DisplayPoint) -> DisplayPoint {
|
pub fn clip_at_line_end(&self, point: DisplayPoint) -> DisplayPoint {
|
||||||
let mut point = point.0;
|
let mut point = point.0;
|
||||||
if point.column == self.line_len(point.row) {
|
if point.column == self.line_len(DisplayRow(point.row)) {
|
||||||
point.column = point.column.saturating_sub(1);
|
point.column = point.column.saturating_sub(1);
|
||||||
point = self.block_snapshot.clip_point(point, Bias::Left);
|
point = self.block_snapshot.clip_point(point, Bias::Left);
|
||||||
}
|
}
|
||||||
@ -748,36 +765,38 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn blocks_in_range(
|
pub fn blocks_in_range(
|
||||||
&self,
|
&self,
|
||||||
rows: Range<u32>,
|
rows: Range<DisplayRow>,
|
||||||
) -> impl Iterator<Item = (u32, &TransformBlock)> {
|
) -> impl Iterator<Item = (DisplayRow, &TransformBlock)> {
|
||||||
self.block_snapshot.blocks_in_range(rows)
|
self.block_snapshot
|
||||||
|
.blocks_in_range(rows.start.0..rows.end.0)
|
||||||
|
.map(|(row, block)| (DisplayRow(row), block))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intersects_fold<T: ToOffset>(&self, offset: T) -> bool {
|
pub fn intersects_fold<T: ToOffset>(&self, offset: T) -> bool {
|
||||||
self.fold_snapshot.intersects_fold(offset)
|
self.fold_snapshot.intersects_fold(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_line_folded(&self, buffer_row: u32) -> bool {
|
pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool {
|
||||||
self.fold_snapshot.is_line_folded(buffer_row)
|
self.fold_snapshot.is_line_folded(buffer_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_block_line(&self, display_row: u32) -> bool {
|
pub fn is_block_line(&self, display_row: DisplayRow) -> bool {
|
||||||
self.block_snapshot.is_block_line(display_row)
|
self.block_snapshot.is_block_line(BlockRow(display_row.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn soft_wrap_indent(&self, display_row: u32) -> Option<u32> {
|
pub fn soft_wrap_indent(&self, display_row: DisplayRow) -> Option<u32> {
|
||||||
let wrap_row = self
|
let wrap_row = self
|
||||||
.block_snapshot
|
.block_snapshot
|
||||||
.to_wrap_point(BlockPoint::new(display_row, 0))
|
.to_wrap_point(BlockPoint::new(display_row.0, 0))
|
||||||
.row();
|
.row();
|
||||||
self.wrap_snapshot.soft_wrap_indent(wrap_row)
|
self.wrap_snapshot.soft_wrap_indent(wrap_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text(&self) -> String {
|
pub fn text(&self) -> String {
|
||||||
self.text_chunks(0).collect()
|
self.text_chunks(DisplayRow(0)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line(&self, display_row: u32) -> String {
|
pub fn line(&self, display_row: DisplayRow) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
for chunk in self.text_chunks(display_row) {
|
for chunk in self.text_chunks(display_row) {
|
||||||
if let Some(ix) = chunk.find('\n') {
|
if let Some(ix) = chunk.find('\n') {
|
||||||
@ -790,7 +809,7 @@ impl DisplaySnapshot {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_indent_for_buffer_row(&self, buffer_row: u32) -> (u32, bool) {
|
pub fn line_indent_for_buffer_row(&self, buffer_row: MultiBufferRow) -> (u32, bool) {
|
||||||
let (buffer, range) = self
|
let (buffer, range) = self
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.buffer_line_for_row(buffer_row)
|
.buffer_line_for_row(buffer_row)
|
||||||
@ -812,15 +831,15 @@ impl DisplaySnapshot {
|
|||||||
(indent_size, is_blank)
|
(indent_size, is_blank)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_len(&self, row: u32) -> u32 {
|
pub fn line_len(&self, row: DisplayRow) -> u32 {
|
||||||
self.block_snapshot.line_len(row)
|
self.block_snapshot.line_len(BlockRow(row.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn longest_row(&self) -> u32 {
|
pub fn longest_row(&self) -> DisplayRow {
|
||||||
self.block_snapshot.longest_row()
|
DisplayRow(self.block_snapshot.longest_row())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fold_for_line(&self, buffer_row: u32) -> Option<FoldStatus> {
|
pub fn fold_for_line(&self, buffer_row: MultiBufferRow) -> Option<FoldStatus> {
|
||||||
if self.is_line_folded(buffer_row) {
|
if self.is_line_folded(buffer_row) {
|
||||||
Some(FoldStatus::Folded)
|
Some(FoldStatus::Folded)
|
||||||
} else if self.is_foldable(buffer_row) {
|
} else if self.is_foldable(buffer_row) {
|
||||||
@ -830,7 +849,7 @@ impl DisplaySnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_foldable(&self, buffer_row: u32) -> bool {
|
pub fn is_foldable(&self, buffer_row: MultiBufferRow) -> bool {
|
||||||
let max_row = self.buffer_snapshot.max_buffer_row();
|
let max_row = self.buffer_snapshot.max_buffer_row();
|
||||||
if buffer_row >= max_row {
|
if buffer_row >= max_row {
|
||||||
return false;
|
return false;
|
||||||
@ -841,8 +860,9 @@ impl DisplaySnapshot {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for next_row in (buffer_row + 1)..=max_row {
|
for next_row in (buffer_row.0 + 1)..=max_row.0 {
|
||||||
let (next_indent_size, next_line_is_blank) = self.line_indent_for_buffer_row(next_row);
|
let (next_indent_size, next_line_is_blank) =
|
||||||
|
self.line_indent_for_buffer_row(MultiBufferRow(next_row));
|
||||||
if next_indent_size > indent_size {
|
if next_indent_size > indent_size {
|
||||||
return true;
|
return true;
|
||||||
} else if !next_line_is_blank {
|
} else if !next_line_is_blank {
|
||||||
@ -853,20 +873,22 @@ impl DisplaySnapshot {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn foldable_range(&self, buffer_row: u32) -> Option<Range<Point>> {
|
pub fn foldable_range(&self, buffer_row: MultiBufferRow) -> Option<Range<Point>> {
|
||||||
let start = Point::new(buffer_row, self.buffer_snapshot.line_len(buffer_row));
|
let start = MultiBufferPoint::new(buffer_row.0, self.buffer_snapshot.line_len(buffer_row));
|
||||||
if self.is_foldable(start.row) && !self.is_line_folded(start.row) {
|
if self.is_foldable(MultiBufferRow(start.row))
|
||||||
|
&& !self.is_line_folded(MultiBufferRow(start.row))
|
||||||
|
{
|
||||||
let (start_indent, _) = self.line_indent_for_buffer_row(buffer_row);
|
let (start_indent, _) = self.line_indent_for_buffer_row(buffer_row);
|
||||||
let max_point = self.buffer_snapshot.max_point();
|
let max_point = self.buffer_snapshot.max_point();
|
||||||
let mut end = None;
|
let mut end = None;
|
||||||
|
|
||||||
for row in (buffer_row + 1)..=max_point.row {
|
for row in (buffer_row.0 + 1)..=max_point.row {
|
||||||
let (indent, is_blank) = self.line_indent_for_buffer_row(row);
|
let (indent, is_blank) = self.line_indent_for_buffer_row(MultiBufferRow(row));
|
||||||
if !is_blank && indent <= start_indent {
|
if !is_blank && indent <= start_indent {
|
||||||
let prev_row = row - 1;
|
let prev_row = row - 1;
|
||||||
end = Some(Point::new(
|
end = Some(Point::new(
|
||||||
prev_row,
|
prev_row,
|
||||||
self.buffer_snapshot.line_len(prev_row),
|
self.buffer_snapshot.line_len(MultiBufferRow(prev_row)),
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -903,27 +925,31 @@ impl Debug for DisplayPoint {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_fmt(format_args!(
|
f.write_fmt(format_args!(
|
||||||
"DisplayPoint({}, {})",
|
"DisplayPoint({}, {})",
|
||||||
self.row(),
|
self.row().0,
|
||||||
self.column()
|
self.column()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq, Deserialize, Hash)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct DisplayRow(pub u32);
|
||||||
|
|
||||||
impl DisplayPoint {
|
impl DisplayPoint {
|
||||||
pub fn new(row: u32, column: u32) -> Self {
|
pub fn new(row: DisplayRow, column: u32) -> Self {
|
||||||
Self(BlockPoint(Point::new(row, column)))
|
Self(BlockPoint(Point::new(row.0, column)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self::new(0, 0)
|
Self::new(DisplayRow(0), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_zero(&self) -> bool {
|
pub fn is_zero(&self) -> bool {
|
||||||
self.0.is_zero()
|
self.0.is_zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn row(self) -> u32 {
|
pub fn row(self) -> DisplayRow {
|
||||||
self.0.row
|
DisplayRow(self.0.row)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn column(self) -> u32 {
|
pub fn column(self) -> u32 {
|
||||||
@ -1171,7 +1197,7 @@ pub mod tests {
|
|||||||
let buffer = &snapshot.buffer_snapshot;
|
let buffer = &snapshot.buffer_snapshot;
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
let row = rng.gen_range(0..=buffer.max_point().row);
|
let row = rng.gen_range(0..=buffer.max_point().row);
|
||||||
let column = rng.gen_range(0..=buffer.line_len(row));
|
let column = rng.gen_range(0..=buffer.line_len(MultiBufferRow(row)));
|
||||||
let point = buffer.clip_point(Point::new(row, column), Left);
|
let point = buffer.clip_point(Point::new(row, column), Left);
|
||||||
|
|
||||||
let (prev_buffer_bound, prev_display_bound) = snapshot.prev_line_boundary(point);
|
let (prev_buffer_bound, prev_display_bound) = snapshot.prev_line_boundary(point);
|
||||||
@ -1216,12 +1242,12 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Movement
|
// Movement
|
||||||
let min_point = snapshot.clip_point(DisplayPoint::new(0, 0), Left);
|
let min_point = snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 0), Left);
|
||||||
let max_point = snapshot.clip_point(snapshot.max_point(), Right);
|
let max_point = snapshot.clip_point(snapshot.max_point(), Right);
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
let row = rng.gen_range(0..=snapshot.max_point().row());
|
let row = rng.gen_range(0..=snapshot.max_point().row().0);
|
||||||
let column = rng.gen_range(0..=snapshot.line_len(row));
|
let column = rng.gen_range(0..=snapshot.line_len(DisplayRow(row)));
|
||||||
let point = snapshot.clip_point(DisplayPoint::new(row, column), Left);
|
let point = snapshot.clip_point(DisplayPoint::new(DisplayRow(row), column), Left);
|
||||||
|
|
||||||
log::info!("Moving from point {:?}", point);
|
log::info!("Moving from point {:?}", point);
|
||||||
|
|
||||||
@ -1288,63 +1314,64 @@ pub mod tests {
|
|||||||
|
|
||||||
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.text_chunks(0).collect::<String>(),
|
snapshot.text_chunks(DisplayRow(0)).collect::<String>(),
|
||||||
"one two \nthree four \nfive\nsix seven \neight"
|
"one two \nthree four \nfive\nsix seven \neight"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.clip_point(DisplayPoint::new(0, 8), Bias::Left),
|
snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 8), Bias::Left),
|
||||||
DisplayPoint::new(0, 7)
|
DisplayPoint::new(DisplayRow(0), 7)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.clip_point(DisplayPoint::new(0, 8), Bias::Right),
|
snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 8), Bias::Right),
|
||||||
DisplayPoint::new(1, 0)
|
DisplayPoint::new(DisplayRow(1), 0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
movement::right(&snapshot, DisplayPoint::new(0, 7)),
|
movement::right(&snapshot, DisplayPoint::new(DisplayRow(0), 7)),
|
||||||
DisplayPoint::new(1, 0)
|
DisplayPoint::new(DisplayRow(1), 0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
movement::left(&snapshot, DisplayPoint::new(1, 0)),
|
movement::left(&snapshot, DisplayPoint::new(DisplayRow(1), 0)),
|
||||||
DisplayPoint::new(0, 7)
|
DisplayPoint::new(DisplayRow(0), 7)
|
||||||
);
|
);
|
||||||
|
|
||||||
let x = snapshot.x_for_display_point(DisplayPoint::new(1, 10), &text_layout_details);
|
let x = snapshot
|
||||||
|
.x_for_display_point(DisplayPoint::new(DisplayRow(1), 10), &text_layout_details);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
movement::up(
|
movement::up(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(1, 10),
|
DisplayPoint::new(DisplayRow(1), 10),
|
||||||
SelectionGoal::None,
|
SelectionGoal::None,
|
||||||
false,
|
false,
|
||||||
&text_layout_details,
|
&text_layout_details,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(0, 7),
|
DisplayPoint::new(DisplayRow(0), 7),
|
||||||
SelectionGoal::HorizontalPosition(x.0)
|
SelectionGoal::HorizontalPosition(x.0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
movement::down(
|
movement::down(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(0, 7),
|
DisplayPoint::new(DisplayRow(0), 7),
|
||||||
SelectionGoal::HorizontalPosition(x.0),
|
SelectionGoal::HorizontalPosition(x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(1, 10),
|
DisplayPoint::new(DisplayRow(1), 10),
|
||||||
SelectionGoal::HorizontalPosition(x.0)
|
SelectionGoal::HorizontalPosition(x.0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
movement::down(
|
movement::down(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(1, 10),
|
DisplayPoint::new(DisplayRow(1), 10),
|
||||||
SelectionGoal::HorizontalPosition(x.0),
|
SelectionGoal::HorizontalPosition(x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(2, 4),
|
DisplayPoint::new(DisplayRow(2), 4),
|
||||||
SelectionGoal::HorizontalPosition(x.0)
|
SelectionGoal::HorizontalPosition(x.0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -1356,7 +1383,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.text_chunks(1).collect::<String>(),
|
snapshot.text_chunks(DisplayRow(1)).collect::<String>(),
|
||||||
"three four \nfive\nsix and \nseven eight"
|
"three four \nfive\nsix and \nseven eight"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1367,7 +1394,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.text_chunks(1).collect::<String>(),
|
snapshot.text_chunks(DisplayRow(1)).collect::<String>(),
|
||||||
"three \nfour five\nsix and \nseven \neight"
|
"three \nfour five\nsix and \nseven \neight"
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@ -1388,9 +1415,18 @@ pub mod tests {
|
|||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit(
|
buffer.edit(
|
||||||
vec![
|
vec![
|
||||||
(Point::new(1, 0)..Point::new(1, 0), "\t"),
|
(
|
||||||
(Point::new(1, 1)..Point::new(1, 1), "\t"),
|
MultiBufferPoint::new(1, 0)..MultiBufferPoint::new(1, 0),
|
||||||
(Point::new(2, 1)..Point::new(2, 1), "\t"),
|
"\t",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
MultiBufferPoint::new(1, 1)..MultiBufferPoint::new(1, 1),
|
||||||
|
"\t",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
MultiBufferPoint::new(2, 1)..MultiBufferPoint::new(2, 1),
|
||||||
|
"\t",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
@ -1399,7 +1435,7 @@ pub mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.update(cx, |map, cx| map.snapshot(cx))
|
map.update(cx, |map, cx| map.snapshot(cx))
|
||||||
.text_chunks(1)
|
.text_chunks(DisplayRow(1))
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.lines()
|
.lines()
|
||||||
.next(),
|
.next(),
|
||||||
@ -1407,7 +1443,7 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.update(cx, |map, cx| map.snapshot(cx))
|
map.update(cx, |map, cx| map.snapshot(cx))
|
||||||
.text_chunks(2)
|
.text_chunks(DisplayRow(2))
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.lines()
|
.lines()
|
||||||
.next(),
|
.next(),
|
||||||
@ -1462,7 +1498,7 @@ pub mod tests {
|
|||||||
let map = cx
|
let map = cx
|
||||||
.new_model(|cx| DisplayMap::new(buffer, font("Helvetica"), font_size, None, 1, 1, cx));
|
.new_model(|cx| DisplayMap::new(buffer, font("Helvetica"), font_size, None, 1, 1, cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(DisplayRow(0)..DisplayRow(5), &map, &theme, cx)),
|
||||||
vec![
|
vec![
|
||||||
("fn ".to_string(), None),
|
("fn ".to_string(), None),
|
||||||
("outer".to_string(), Some(Hsla::blue())),
|
("outer".to_string(), Some(Hsla::blue())),
|
||||||
@ -1473,7 +1509,7 @@ pub mod tests {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(DisplayRow(3)..DisplayRow(5), &map, &theme, cx)),
|
||||||
vec![
|
vec![
|
||||||
(" fn ".to_string(), Some(Hsla::red())),
|
(" fn ".to_string(), Some(Hsla::red())),
|
||||||
("inner".to_string(), Some(Hsla::blue())),
|
("inner".to_string(), Some(Hsla::blue())),
|
||||||
@ -1482,10 +1518,13 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
map.update(cx, |map, cx| {
|
map.update(cx, |map, cx| {
|
||||||
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
|
map.fold(
|
||||||
|
vec![MultiBufferPoint::new(0, 6)..MultiBufferPoint::new(3, 2)],
|
||||||
|
cx,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| syntax_chunks(0..2, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(DisplayRow(0)..DisplayRow(2), &map, &theme, cx)),
|
||||||
vec![
|
vec![
|
||||||
("fn ".to_string(), None),
|
("fn ".to_string(), None),
|
||||||
("out".to_string(), Some(Hsla::blue())),
|
("out".to_string(), Some(Hsla::blue())),
|
||||||
@ -1548,7 +1587,7 @@ pub mod tests {
|
|||||||
DisplayMap::new(buffer, font("Courier"), font_size, Some(px(40.0)), 1, 1, cx)
|
DisplayMap::new(buffer, font("Courier"), font_size, Some(px(40.0)), 1, 1, cx)
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(DisplayRow(0)..DisplayRow(5), &map, &theme, cx)),
|
||||||
[
|
[
|
||||||
("fn \n".to_string(), None),
|
("fn \n".to_string(), None),
|
||||||
("oute\nr".to_string(), Some(Hsla::blue())),
|
("oute\nr".to_string(), Some(Hsla::blue())),
|
||||||
@ -1556,15 +1595,18 @@ pub mod tests {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(DisplayRow(3)..DisplayRow(5), &map, &theme, cx)),
|
||||||
[("{}\n\n".to_string(), None)]
|
[("{}\n\n".to_string(), None)]
|
||||||
);
|
);
|
||||||
|
|
||||||
map.update(cx, |map, cx| {
|
map.update(cx, |map, cx| {
|
||||||
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
|
map.fold(
|
||||||
|
vec![MultiBufferPoint::new(0, 6)..MultiBufferPoint::new(3, 2)],
|
||||||
|
cx,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| syntax_chunks(1..4, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(DisplayRow(1)..DisplayRow(4), &map, &theme, cx)),
|
||||||
[
|
[
|
||||||
("out".to_string(), Some(Hsla::blue())),
|
("out".to_string(), Some(Hsla::blue())),
|
||||||
("⋯\n".to_string(), None),
|
("⋯\n".to_string(), None),
|
||||||
@ -1636,7 +1678,7 @@ pub mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| chunks(0..10, &map, &theme, cx)),
|
cx.update(|cx| chunks(DisplayRow(0)..DisplayRow(10), &map, &theme, cx)),
|
||||||
[
|
[
|
||||||
("const ".to_string(), None, None),
|
("const ".to_string(), None, None),
|
||||||
("a".to_string(), None, Some(Hsla::blue())),
|
("a".to_string(), None, Some(Hsla::blue())),
|
||||||
@ -1732,45 +1774,57 @@ pub mod tests {
|
|||||||
let map = map.update(cx, |map, cx| map.snapshot(cx));
|
let map = map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
assert_eq!(map.text(), "✅ α\nβ \n🏀β γ");
|
assert_eq!(map.text(), "✅ α\nβ \n🏀β γ");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.text_chunks(0).collect::<String>(),
|
map.text_chunks(DisplayRow(0)).collect::<String>(),
|
||||||
"✅ α\nβ \n🏀β γ"
|
"✅ α\nβ \n🏀β γ"
|
||||||
);
|
);
|
||||||
assert_eq!(map.text_chunks(1).collect::<String>(), "β \n🏀β γ");
|
assert_eq!(
|
||||||
assert_eq!(map.text_chunks(2).collect::<String>(), "🏀β γ");
|
map.text_chunks(DisplayRow(1)).collect::<String>(),
|
||||||
|
"β \n🏀β γ"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map.text_chunks(DisplayRow(2)).collect::<String>(),
|
||||||
|
"🏀β γ"
|
||||||
|
);
|
||||||
|
|
||||||
let point = Point::new(0, "✅\t\t".len() as u32);
|
let point = MultiBufferPoint::new(0, "✅\t\t".len() as u32);
|
||||||
let display_point = DisplayPoint::new(0, "✅ ".len() as u32);
|
let display_point = DisplayPoint::new(DisplayRow(0), "✅ ".len() as u32);
|
||||||
assert_eq!(point.to_display_point(&map), display_point);
|
assert_eq!(point.to_display_point(&map), display_point);
|
||||||
assert_eq!(display_point.to_point(&map), point);
|
assert_eq!(display_point.to_point(&map), point);
|
||||||
|
|
||||||
let point = Point::new(1, "β\t".len() as u32);
|
let point = MultiBufferPoint::new(1, "β\t".len() as u32);
|
||||||
let display_point = DisplayPoint::new(1, "β ".len() as u32);
|
let display_point = DisplayPoint::new(DisplayRow(1), "β ".len() as u32);
|
||||||
assert_eq!(point.to_display_point(&map), display_point);
|
assert_eq!(point.to_display_point(&map), display_point);
|
||||||
assert_eq!(display_point.to_point(&map), point,);
|
assert_eq!(display_point.to_point(&map), point,);
|
||||||
|
|
||||||
let point = Point::new(2, "🏀β\t\t".len() as u32);
|
let point = MultiBufferPoint::new(2, "🏀β\t\t".len() as u32);
|
||||||
let display_point = DisplayPoint::new(2, "🏀β ".len() as u32);
|
let display_point = DisplayPoint::new(DisplayRow(2), "🏀β ".len() as u32);
|
||||||
assert_eq!(point.to_display_point(&map), display_point);
|
assert_eq!(point.to_display_point(&map), display_point);
|
||||||
assert_eq!(display_point.to_point(&map), point,);
|
assert_eq!(display_point.to_point(&map), point,);
|
||||||
|
|
||||||
// Display points inside of expanded tabs
|
// Display points inside of expanded tabs
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayPoint::new(0, "✅ ".len() as u32).to_point(&map),
|
DisplayPoint::new(DisplayRow(0), "✅ ".len() as u32).to_point(&map),
|
||||||
Point::new(0, "✅\t".len() as u32),
|
MultiBufferPoint::new(0, "✅\t".len() as u32),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayPoint::new(0, "✅ ".len() as u32).to_point(&map),
|
DisplayPoint::new(DisplayRow(0), "✅ ".len() as u32).to_point(&map),
|
||||||
Point::new(0, "✅".len() as u32),
|
MultiBufferPoint::new(0, "✅".len() as u32),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Clipping display points inside of multi-byte characters
|
// Clipping display points inside of multi-byte characters
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.clip_point(DisplayPoint::new(0, "✅".len() as u32 - 1), Left),
|
map.clip_point(
|
||||||
DisplayPoint::new(0, 0)
|
DisplayPoint::new(DisplayRow(0), "✅".len() as u32 - 1),
|
||||||
|
Left
|
||||||
|
),
|
||||||
|
DisplayPoint::new(DisplayRow(0), 0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.clip_point(DisplayPoint::new(0, "✅".len() as u32 - 1), Bias::Right),
|
map.clip_point(
|
||||||
DisplayPoint::new(0, "✅".len() as u32)
|
DisplayPoint::new(DisplayRow(0), "✅".len() as u32 - 1),
|
||||||
|
Bias::Right
|
||||||
|
),
|
||||||
|
DisplayPoint::new(DisplayRow(0), "✅".len() as u32)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1785,12 +1839,12 @@ pub mod tests {
|
|||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.update(cx, |map, cx| map.snapshot(cx)).max_point(),
|
map.update(cx, |map, cx| map.snapshot(cx)).max_point(),
|
||||||
DisplayPoint::new(1, 11)
|
DisplayPoint::new(DisplayRow(1), 11)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syntax_chunks(
|
fn syntax_chunks(
|
||||||
rows: Range<u32>,
|
rows: Range<DisplayRow>,
|
||||||
map: &Model<DisplayMap>,
|
map: &Model<DisplayMap>,
|
||||||
theme: &SyntaxTheme,
|
theme: &SyntaxTheme,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
@ -1802,7 +1856,7 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn chunks(
|
fn chunks(
|
||||||
rows: Range<u32>,
|
rows: Range<DisplayRow>,
|
||||||
map: &Model<DisplayMap>,
|
map: &Model<DisplayMap>,
|
||||||
theme: &SyntaxTheme,
|
theme: &SyntaxTheme,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
|
@ -6,7 +6,7 @@ use crate::{EditorStyle, GutterDimensions};
|
|||||||
use collections::{Bound, HashMap, HashSet};
|
use collections::{Bound, HashMap, HashSet};
|
||||||
use gpui::{AnyElement, Pixels, WindowContext};
|
use gpui::{AnyElement, Pixels, WindowContext};
|
||||||
use language::{BufferSnapshot, Chunk, Patch, Point};
|
use language::{BufferSnapshot, Chunk, Patch, Point};
|
||||||
use multi_buffer::{Anchor, ExcerptId, ExcerptRange, ToPoint as _};
|
use multi_buffer::{Anchor, ExcerptId, ExcerptRange, MultiBufferRow, ToPoint as _};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
@ -50,7 +50,7 @@ pub struct BlockId(usize);
|
|||||||
pub struct BlockPoint(pub Point);
|
pub struct BlockPoint(pub Point);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||||
struct BlockRow(u32);
|
pub struct BlockRow(pub(super) u32);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||||
struct WrapRow(u32);
|
struct WrapRow(u32);
|
||||||
@ -163,7 +163,7 @@ pub struct BlockChunks<'a> {
|
|||||||
pub struct BlockBufferRows<'a> {
|
pub struct BlockBufferRows<'a> {
|
||||||
transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,
|
transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,
|
||||||
input_buffer_rows: wrap_map::WrapBufferRows<'a>,
|
input_buffer_rows: wrap_map::WrapBufferRows<'a>,
|
||||||
output_row: u32,
|
output_row: BlockRow,
|
||||||
started: bool,
|
started: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ impl BlockMap {
|
|||||||
match block.disposition {
|
match block.disposition {
|
||||||
BlockDisposition::Above => position.column = 0,
|
BlockDisposition::Above => position.column = 0,
|
||||||
BlockDisposition::Below => {
|
BlockDisposition::Below => {
|
||||||
position.column = buffer.line_len(position.row)
|
position.column = buffer.line_len(MultiBufferRow(position.row))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let position = wrap_snapshot.make_wrap_point(position, Bias::Left);
|
let position = wrap_snapshot.make_wrap_point(position, Bias::Left);
|
||||||
@ -372,7 +372,7 @@ impl BlockMap {
|
|||||||
(
|
(
|
||||||
wrap_snapshot
|
wrap_snapshot
|
||||||
.make_wrap_point(
|
.make_wrap_point(
|
||||||
Point::new(excerpt_boundary.row, 0),
|
Point::new(excerpt_boundary.row.0, 0),
|
||||||
Bias::Left,
|
Bias::Left,
|
||||||
)
|
)
|
||||||
.row(),
|
.row(),
|
||||||
@ -633,12 +633,12 @@ impl BlockSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_rows(&self, start_row: u32) -> BlockBufferRows {
|
pub(super) fn buffer_rows(&self, start_row: BlockRow) -> BlockBufferRows {
|
||||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
||||||
cursor.seek(&BlockRow(start_row), Bias::Right, &());
|
cursor.seek(&start_row, Bias::Right, &());
|
||||||
let (output_start, input_start) = cursor.start();
|
let (output_start, input_start) = cursor.start();
|
||||||
let overshoot = if cursor.item().map_or(false, |t| t.is_isomorphic()) {
|
let overshoot = if cursor.item().map_or(false, |t| t.is_isomorphic()) {
|
||||||
start_row - output_start.0
|
start_row.0 - output_start.0
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
@ -676,7 +676,7 @@ impl BlockSnapshot {
|
|||||||
|
|
||||||
pub fn max_point(&self) -> BlockPoint {
|
pub fn max_point(&self) -> BlockPoint {
|
||||||
let row = self.transforms.summary().output_rows - 1;
|
let row = self.transforms.summary().output_rows - 1;
|
||||||
BlockPoint::new(row, self.line_len(row))
|
BlockPoint::new(row, self.line_len(BlockRow(row)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn longest_row(&self) -> u32 {
|
pub fn longest_row(&self) -> u32 {
|
||||||
@ -684,12 +684,12 @@ impl BlockSnapshot {
|
|||||||
self.to_block_point(WrapPoint::new(input_row, 0)).row
|
self.to_block_point(WrapPoint::new(input_row, 0)).row
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_len(&self, row: u32) -> u32 {
|
pub(super) fn line_len(&self, row: BlockRow) -> u32 {
|
||||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
||||||
cursor.seek(&BlockRow(row), Bias::Right, &());
|
cursor.seek(&BlockRow(row.0), Bias::Right, &());
|
||||||
if let Some(transform) = cursor.item() {
|
if let Some(transform) = cursor.item() {
|
||||||
let (output_start, input_start) = cursor.start();
|
let (output_start, input_start) = cursor.start();
|
||||||
let overshoot = row - output_start.0;
|
let overshoot = row.0 - output_start.0;
|
||||||
if transform.block.is_some() {
|
if transform.block.is_some() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@ -700,9 +700,9 @@ impl BlockSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_block_line(&self, row: u32) -> bool {
|
pub(super) fn is_block_line(&self, row: BlockRow) -> bool {
|
||||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
||||||
cursor.seek(&BlockRow(row), Bias::Right, &());
|
cursor.seek(&row, Bias::Right, &());
|
||||||
cursor.item().map_or(false, |t| t.block.is_some())
|
cursor.item().map_or(false, |t| t.block.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,16 +881,16 @@ impl<'a> Iterator for BlockChunks<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for BlockBufferRows<'a> {
|
impl<'a> Iterator for BlockBufferRows<'a> {
|
||||||
type Item = Option<u32>;
|
type Item = Option<BlockRow>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.started {
|
if self.started {
|
||||||
self.output_row += 1;
|
self.output_row.0 += 1;
|
||||||
} else {
|
} else {
|
||||||
self.started = true;
|
self.started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.output_row >= self.transforms.end(&()).0 .0 {
|
if self.output_row.0 >= self.transforms.end(&()).0 .0 {
|
||||||
self.transforms.next(&());
|
self.transforms.next(&());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,7 +898,7 @@ impl<'a> Iterator for BlockBufferRows<'a> {
|
|||||||
if transform.block.is_some() {
|
if transform.block.is_some() {
|
||||||
Some(None)
|
Some(None)
|
||||||
} else {
|
} else {
|
||||||
Some(self.input_buffer_rows.next().unwrap())
|
Some(self.input_buffer_rows.next().unwrap().map(BlockRow))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1154,7 +1154,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
snapshot
|
||||||
|
.buffer_rows(BlockRow(0))
|
||||||
|
.map(|row| row.map(|r| r.0))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
&[
|
&[
|
||||||
Some(0),
|
Some(0),
|
||||||
None,
|
None,
|
||||||
@ -1394,7 +1397,7 @@ mod tests {
|
|||||||
position.column = 0;
|
position.column = 0;
|
||||||
}
|
}
|
||||||
BlockDisposition::Below => {
|
BlockDisposition::Below => {
|
||||||
position.column = buffer_snapshot.line_len(position.row);
|
position.column = buffer_snapshot.line_len(MultiBufferRow(position.row));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let row = wraps_snapshot.make_wrap_point(position, Bias::Left).row();
|
let row = wraps_snapshot.make_wrap_point(position, Bias::Left).row();
|
||||||
@ -1410,7 +1413,7 @@ mod tests {
|
|||||||
expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map(
|
expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map(
|
||||||
|boundary| {
|
|boundary| {
|
||||||
let position =
|
let position =
|
||||||
wraps_snapshot.make_wrap_point(Point::new(boundary.row, 0), Bias::Left);
|
wraps_snapshot.make_wrap_point(Point::new(boundary.row.0, 0), Bias::Left);
|
||||||
(
|
(
|
||||||
position.row(),
|
position.row(),
|
||||||
ExpectedBlock::ExcerptHeader {
|
ExpectedBlock::ExcerptHeader {
|
||||||
@ -1427,7 +1430,9 @@ mod tests {
|
|||||||
expected_blocks.sort_unstable();
|
expected_blocks.sort_unstable();
|
||||||
let mut sorted_blocks_iter = expected_blocks.into_iter().peekable();
|
let mut sorted_blocks_iter = expected_blocks.into_iter().peekable();
|
||||||
|
|
||||||
let input_buffer_rows = buffer_snapshot.buffer_rows(0).collect::<Vec<_>>();
|
let input_buffer_rows = buffer_snapshot
|
||||||
|
.buffer_rows(MultiBufferRow(0))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let mut expected_buffer_rows = Vec::new();
|
let mut expected_buffer_rows = Vec::new();
|
||||||
let mut expected_text = String::new();
|
let mut expected_text = String::new();
|
||||||
let mut expected_block_positions = Vec::new();
|
let mut expected_block_positions = Vec::new();
|
||||||
@ -1498,7 +1503,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blocks_snapshot
|
blocks_snapshot
|
||||||
.buffer_rows(start_row as u32)
|
.buffer_rows(BlockRow(start_row as u32))
|
||||||
|
.map(|row| row.map(|r| r.0))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&expected_buffer_rows[start_row..]
|
&expected_buffer_rows[start_row..]
|
||||||
);
|
);
|
||||||
@ -1518,7 +1524,7 @@ mod tests {
|
|||||||
let row = row as u32;
|
let row = row as u32;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blocks_snapshot.line_len(row),
|
blocks_snapshot.line_len(BlockRow(row)),
|
||||||
line.len() as u32,
|
line.len() as u32,
|
||||||
"invalid line len for row {}",
|
"invalid line len for row {}",
|
||||||
row
|
row
|
||||||
|
@ -4,7 +4,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use gpui::{ElementId, HighlightStyle, Hsla};
|
use gpui::{ElementId, HighlightStyle, Hsla};
|
||||||
use language::{Chunk, Edit, Point, TextSummary};
|
use language::{Chunk, Edit, Point, TextSummary};
|
||||||
use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset};
|
use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{self, Ordering},
|
cmp::{self, Ordering},
|
||||||
iter,
|
iter,
|
||||||
@ -629,17 +629,17 @@ impl FoldSnapshot {
|
|||||||
cursor.item().map_or(false, |t| t.output_text.is_some())
|
cursor.item().map_or(false, |t| t.output_text.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_line_folded(&self, buffer_row: u32) -> bool {
|
pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool {
|
||||||
let mut inlay_point = self
|
let mut inlay_point = self
|
||||||
.inlay_snapshot
|
.inlay_snapshot
|
||||||
.to_inlay_point(Point::new(buffer_row, 0));
|
.to_inlay_point(Point::new(buffer_row.0, 0));
|
||||||
let mut cursor = self.transforms.cursor::<InlayPoint>();
|
let mut cursor = self.transforms.cursor::<InlayPoint>();
|
||||||
cursor.seek(&inlay_point, Bias::Right, &());
|
cursor.seek(&inlay_point, Bias::Right, &());
|
||||||
loop {
|
loop {
|
||||||
match cursor.item() {
|
match cursor.item() {
|
||||||
Some(transform) => {
|
Some(transform) => {
|
||||||
let buffer_point = self.inlay_snapshot.to_buffer_point(inlay_point);
|
let buffer_point = self.inlay_snapshot.to_buffer_point(inlay_point);
|
||||||
if buffer_point.row != buffer_row {
|
if buffer_point.row != buffer_row.0 {
|
||||||
return false;
|
return false;
|
||||||
} else if transform.output_text.is_some() {
|
} else if transform.output_text.is_some() {
|
||||||
return true;
|
return true;
|
||||||
@ -1549,7 +1549,7 @@ mod tests {
|
|||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
for row in 0..=buffer_snapshot.max_point().row {
|
for row in 0..=buffer_snapshot.max_point().row {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.is_line_folded(row),
|
snapshot.is_line_folded(MultiBufferRow(row)),
|
||||||
folded_buffer_rows.contains(&row),
|
folded_buffer_rows.contains(&row),
|
||||||
"expected buffer row {}{} to be folded",
|
"expected buffer row {}{} to be folded",
|
||||||
row,
|
row,
|
||||||
|
@ -2,7 +2,9 @@ use crate::{HighlightStyles, InlayId};
|
|||||||
use collections::{BTreeMap, BTreeSet};
|
use collections::{BTreeMap, BTreeSet};
|
||||||
use gpui::HighlightStyle;
|
use gpui::HighlightStyle;
|
||||||
use language::{Chunk, Edit, Point, TextSummary};
|
use language::{Chunk, Edit, Point, TextSummary};
|
||||||
use multi_buffer::{Anchor, MultiBufferChunks, MultiBufferRows, MultiBufferSnapshot, ToOffset};
|
use multi_buffer::{
|
||||||
|
Anchor, MultiBufferChunks, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, ToOffset,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
cmp,
|
cmp,
|
||||||
@ -182,7 +184,7 @@ pub struct InlayBufferRows<'a> {
|
|||||||
transforms: Cursor<'a, Transform, (InlayPoint, Point)>,
|
transforms: Cursor<'a, Transform, (InlayPoint, Point)>,
|
||||||
buffer_rows: MultiBufferRows<'a>,
|
buffer_rows: MultiBufferRows<'a>,
|
||||||
inlay_row: u32,
|
inlay_row: u32,
|
||||||
max_buffer_row: u32,
|
max_buffer_row: MultiBufferRow,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
@ -375,7 +377,7 @@ impl<'a> InlayBufferRows<'a> {
|
|||||||
self.transforms.seek(&inlay_point, Bias::Left, &());
|
self.transforms.seek(&inlay_point, Bias::Left, &());
|
||||||
|
|
||||||
let mut buffer_point = self.transforms.start().1;
|
let mut buffer_point = self.transforms.start().1;
|
||||||
let buffer_row = if row == 0 {
|
let buffer_row = MultiBufferRow(if row == 0 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
match self.transforms.item() {
|
match self.transforms.item() {
|
||||||
@ -383,9 +385,9 @@ impl<'a> InlayBufferRows<'a> {
|
|||||||
buffer_point += inlay_point.0 - self.transforms.start().0 .0;
|
buffer_point += inlay_point.0 - self.transforms.start().0 .0;
|
||||||
buffer_point.row
|
buffer_point.row
|
||||||
}
|
}
|
||||||
_ => cmp::min(buffer_point.row + 1, self.max_buffer_row),
|
_ => cmp::min(buffer_point.row + 1, self.max_buffer_row.0),
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
self.inlay_row = inlay_point.row();
|
self.inlay_row = inlay_point.row();
|
||||||
self.buffer_rows.seek(buffer_row);
|
self.buffer_rows.seek(buffer_row);
|
||||||
}
|
}
|
||||||
@ -986,17 +988,17 @@ impl InlaySnapshot {
|
|||||||
let inlay_point = InlayPoint::new(row, 0);
|
let inlay_point = InlayPoint::new(row, 0);
|
||||||
cursor.seek(&inlay_point, Bias::Left, &());
|
cursor.seek(&inlay_point, Bias::Left, &());
|
||||||
|
|
||||||
let max_buffer_row = self.buffer.max_point().row;
|
let max_buffer_row = MultiBufferRow(self.buffer.max_point().row);
|
||||||
let mut buffer_point = cursor.start().1;
|
let mut buffer_point = cursor.start().1;
|
||||||
let buffer_row = if row == 0 {
|
let buffer_row = if row == 0 {
|
||||||
0
|
MultiBufferRow(0)
|
||||||
} else {
|
} else {
|
||||||
match cursor.item() {
|
match cursor.item() {
|
||||||
Some(Transform::Isomorphic(_)) => {
|
Some(Transform::Isomorphic(_)) => {
|
||||||
buffer_point += inlay_point.0 - cursor.start().0 .0;
|
buffer_point += inlay_point.0 - cursor.start().0 .0;
|
||||||
buffer_point.row
|
MultiBufferRow(buffer_point.row)
|
||||||
}
|
}
|
||||||
_ => cmp::min(buffer_point.row + 1, max_buffer_row),
|
_ => cmp::min(MultiBufferRow(buffer_point.row + 1), max_buffer_row),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,18 +86,18 @@ use language::{
|
|||||||
CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
|
CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
|
||||||
Point, Selection, SelectionGoal, TransactionId,
|
Point, Selection, SelectionGoal, TransactionId,
|
||||||
};
|
};
|
||||||
use language::{Runnable, RunnableRange};
|
use language::{BufferRow, Runnable, RunnableRange};
|
||||||
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
||||||
|
|
||||||
use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
|
use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
|
||||||
use lsp::{DiagnosticSeverity, LanguageServerId};
|
use lsp::{DiagnosticSeverity, LanguageServerId};
|
||||||
use mouse_context_menu::MouseContextMenu;
|
use mouse_context_menu::MouseContextMenu;
|
||||||
use movement::TextLayoutDetails;
|
use movement::TextLayoutDetails;
|
||||||
use multi_buffer::ToOffsetUtf16;
|
|
||||||
pub use multi_buffer::{
|
pub use multi_buffer::{
|
||||||
Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
|
Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
|
||||||
ToPoint,
|
ToPoint,
|
||||||
};
|
};
|
||||||
|
use multi_buffer::{MultiBufferPoint, MultiBufferRow, ToOffsetUtf16};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use project::project_settings::{GitGutterSetting, ProjectSettings};
|
use project::project_settings::{GitGutterSetting, ProjectSettings};
|
||||||
@ -410,7 +410,7 @@ struct RunnableTasks {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct ResolvedTasks {
|
struct ResolvedTasks {
|
||||||
templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
|
templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
|
||||||
position: text::Point,
|
position: Anchor,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
|
/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
|
||||||
@ -505,7 +505,7 @@ pub struct Editor {
|
|||||||
>,
|
>,
|
||||||
last_bounds: Option<Bounds<Pixels>>,
|
last_bounds: Option<Bounds<Pixels>>,
|
||||||
expect_bounds_change: Option<Bounds<Pixels>>,
|
expect_bounds_change: Option<Bounds<Pixels>>,
|
||||||
tasks: HashMap<(BufferId, u32), (usize, RunnableTasks)>,
|
tasks: HashMap<(BufferId, BufferRow), (usize, RunnableTasks)>,
|
||||||
tasks_update_task: Option<Task<()>>,
|
tasks_update_task: Option<Task<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,7 +804,7 @@ impl ContextMenu {
|
|||||||
|
|
||||||
enum ContextMenuOrigin {
|
enum ContextMenuOrigin {
|
||||||
EditorPoint(DisplayPoint),
|
EditorPoint(DisplayPoint),
|
||||||
GutterIndicator(u32),
|
GutterIndicator(DisplayRow),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -1299,7 +1299,7 @@ struct CodeActionsMenu {
|
|||||||
buffer: Model<Buffer>,
|
buffer: Model<Buffer>,
|
||||||
selected_item: usize,
|
selected_item: usize,
|
||||||
scroll_handle: UniformListScrollHandle,
|
scroll_handle: UniformListScrollHandle,
|
||||||
deployed_from_indicator: Option<u32>,
|
deployed_from_indicator: Option<DisplayRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeActionsMenu {
|
impl CodeActionsMenu {
|
||||||
@ -2498,7 +2498,8 @@ impl Editor {
|
|||||||
let end_column = cmp::max(tail.column(), goal_column);
|
let end_column = cmp::max(tail.column(), goal_column);
|
||||||
let reversed = start_column < tail.column();
|
let reversed = start_column < tail.column();
|
||||||
|
|
||||||
let selection_ranges = (start_row..=end_row)
|
let selection_ranges = (start_row.0..=end_row.0)
|
||||||
|
.map(DisplayRow)
|
||||||
.filter_map(|row| {
|
.filter_map(|row| {
|
||||||
if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
|
if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
|
||||||
let start = display_map
|
let start = display_map
|
||||||
@ -2898,7 +2899,8 @@ impl Editor {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|selection| {
|
.map(|selection| {
|
||||||
let start_point = selection.start.to_point(&buffer);
|
let start_point = selection.start.to_point(&buffer);
|
||||||
let mut indent = buffer.indent_size_for_line(start_point.row);
|
let mut indent =
|
||||||
|
buffer.indent_size_for_line(MultiBufferRow(start_point.row));
|
||||||
indent.len = cmp::min(indent.len, start_point.column);
|
indent.len = cmp::min(indent.len, start_point.column);
|
||||||
let start = selection.start;
|
let start = selection.start;
|
||||||
let end = selection.end;
|
let end = selection.end;
|
||||||
@ -2951,7 +2953,7 @@ impl Editor {
|
|||||||
let max_len_of_delimiter =
|
let max_len_of_delimiter =
|
||||||
delimiters.iter().map(|delimiter| delimiter.len()).max()?;
|
delimiters.iter().map(|delimiter| delimiter.len()).max()?;
|
||||||
let (snapshot, range) =
|
let (snapshot, range) =
|
||||||
buffer.buffer_line_for_row(start_point.row)?;
|
buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
|
||||||
|
|
||||||
let mut index_of_first_non_whitespace = 0;
|
let mut index_of_first_non_whitespace = 0;
|
||||||
let comment_candidate = snapshot
|
let comment_candidate = snapshot
|
||||||
@ -3015,7 +3017,7 @@ impl Editor {
|
|||||||
let mut cursor = new_selection.end.to_point(&buffer);
|
let mut cursor = new_selection.end.to_point(&buffer);
|
||||||
if extra_newline_inserted {
|
if extra_newline_inserted {
|
||||||
cursor.row -= 1;
|
cursor.row -= 1;
|
||||||
cursor.column = buffer.line_len(cursor.row);
|
cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
|
||||||
}
|
}
|
||||||
new_selection.map(|_| cursor)
|
new_selection.map(|_| cursor)
|
||||||
})
|
})
|
||||||
@ -3075,7 +3077,7 @@ impl Editor {
|
|||||||
IndentKind::Space => " ".repeat(indent.len as usize),
|
IndentKind::Space => " ".repeat(indent.len as usize),
|
||||||
IndentKind::Tab => "\t".repeat(indent.len as usize),
|
IndentKind::Tab => "\t".repeat(indent.len as usize),
|
||||||
};
|
};
|
||||||
let point = Point::new(row, 0);
|
let point = Point::new(row.0, 0);
|
||||||
indent_edits.push((point..point, text));
|
indent_edits.push((point..point, text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3135,7 +3137,7 @@ impl Editor {
|
|||||||
IndentKind::Space => " ".repeat(indent.len as usize),
|
IndentKind::Space => " ".repeat(indent.len as usize),
|
||||||
IndentKind::Tab => "\t".repeat(indent.len as usize),
|
IndentKind::Tab => "\t".repeat(indent.len as usize),
|
||||||
};
|
};
|
||||||
let point = Point::new(row, 0);
|
let point = Point::new(row.0, 0);
|
||||||
indent_edits.push((point..point, text));
|
indent_edits.push((point..point, text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3852,17 +3854,13 @@ impl Editor {
|
|||||||
|
|
||||||
let spawned_test_task = this.update(&mut cx, |this, cx| {
|
let spawned_test_task = this.update(&mut cx, |this, cx| {
|
||||||
if this.focus_handle.is_focused(cx) {
|
if this.focus_handle.is_focused(cx) {
|
||||||
let display_row = action
|
let multibuffer_point = action
|
||||||
.deployed_from_indicator
|
.deployed_from_indicator
|
||||||
.map(|row| {
|
.map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
|
||||||
DisplayPoint::new(row, 0)
|
.unwrap_or_else(|| this.selections.newest::<Point>(cx).head());
|
||||||
.to_point(&snapshot.display_snapshot)
|
|
||||||
.row
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| this.selections.newest::<Point>(cx).head().row);
|
|
||||||
let (buffer, buffer_row) = snapshot
|
let (buffer, buffer_row) = snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.buffer_line_for_row(display_row)
|
.buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
|
||||||
.and_then(|(buffer_snapshot, range)| {
|
.and_then(|(buffer_snapshot, range)| {
|
||||||
this.buffer
|
this.buffer
|
||||||
.read(cx)
|
.read(cx)
|
||||||
@ -3934,7 +3932,9 @@ impl Editor {
|
|||||||
.map(|task| (kind.clone(), task))
|
.map(|task| (kind.clone(), task))
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
position: Point::new(buffer_row, tasks.1.column),
|
position: snapshot
|
||||||
|
.buffer_snapshot
|
||||||
|
.anchor_before(Point::new(multibuffer_point.row, tasks.1.column)),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let spawn_straight_away = tasks
|
let spawn_straight_away = tasks
|
||||||
@ -4496,7 +4496,7 @@ impl Editor {
|
|||||||
fn render_code_actions_indicator(
|
fn render_code_actions_indicator(
|
||||||
&self,
|
&self,
|
||||||
_style: &EditorStyle,
|
_style: &EditorStyle,
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
is_active: bool,
|
is_active: bool,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<IconButton> {
|
) -> Option<IconButton> {
|
||||||
@ -4525,7 +4525,7 @@ impl Editor {
|
|||||||
self.tasks.clear()
|
self.tasks.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_tasks(&mut self, key: (BufferId, u32), value: (usize, RunnableTasks)) {
|
fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: (usize, RunnableTasks)) {
|
||||||
if let Some(_) = self.tasks.insert(key, value) {
|
if let Some(_) = self.tasks.insert(key, value) {
|
||||||
// This case should hopefully be rare, but just in case...
|
// This case should hopefully be rare, but just in case...
|
||||||
log::error!("multiple different run targets found on a single line, only the last target will be rendered")
|
log::error!("multiple different run targets found on a single line, only the last target will be rendered")
|
||||||
@ -4536,7 +4536,7 @@ impl Editor {
|
|||||||
&self,
|
&self,
|
||||||
_style: &EditorStyle,
|
_style: &EditorStyle,
|
||||||
is_active: bool,
|
is_active: bool,
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> IconButton {
|
) -> IconButton {
|
||||||
IconButton::new("code_actions_indicator", ui::IconName::Play)
|
IconButton::new("code_actions_indicator", ui::IconName::Play)
|
||||||
@ -4556,7 +4556,7 @@ impl Editor {
|
|||||||
|
|
||||||
pub fn render_fold_indicators(
|
pub fn render_fold_indicators(
|
||||||
&mut self,
|
&mut self,
|
||||||
fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
|
fold_data: Vec<Option<(FoldStatus, MultiBufferRow, bool)>>,
|
||||||
_style: &EditorStyle,
|
_style: &EditorStyle,
|
||||||
gutter_hovered: bool,
|
gutter_hovered: bool,
|
||||||
_line_height: Pixels,
|
_line_height: Pixels,
|
||||||
@ -4775,7 +4775,7 @@ impl Editor {
|
|||||||
pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
|
pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
|
||||||
self.transact(cx, |this, cx| {
|
self.transact(cx, |this, cx| {
|
||||||
this.select_autoclose_pair(cx);
|
this.select_autoclose_pair(cx);
|
||||||
let mut selections = this.selections.all::<Point>(cx);
|
let mut selections = this.selections.all::<MultiBufferPoint>(cx);
|
||||||
if !this.selections.line_mode {
|
if !this.selections.line_mode {
|
||||||
let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
@ -4786,7 +4786,7 @@ impl Editor {
|
|||||||
.to_point(&display_map);
|
.to_point(&display_map);
|
||||||
if let Some((buffer, line_buffer_range)) = display_map
|
if let Some((buffer, line_buffer_range)) = display_map
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.buffer_line_for_row(old_head.row)
|
.buffer_line_for_row(MultiBufferRow(old_head.row))
|
||||||
{
|
{
|
||||||
let indent_size =
|
let indent_size =
|
||||||
buffer.indent_size_for_line(line_buffer_range.start.row);
|
buffer.indent_size_for_line(line_buffer_range.start.row);
|
||||||
@ -4800,7 +4800,7 @@ impl Editor {
|
|||||||
let indent_len = indent_len.get();
|
let indent_len = indent_len.get();
|
||||||
new_head = cmp::min(
|
new_head = cmp::min(
|
||||||
new_head,
|
new_head,
|
||||||
Point::new(
|
MultiBufferPoint::new(
|
||||||
old_head.row,
|
old_head.row,
|
||||||
((old_head.column - 1) / indent_len) * indent_len,
|
((old_head.column - 1) / indent_len) * indent_len,
|
||||||
),
|
),
|
||||||
@ -4875,8 +4875,10 @@ impl Editor {
|
|||||||
// If the selection is empty and the cursor is in the leading whitespace before the
|
// If the selection is empty and the cursor is in the leading whitespace before the
|
||||||
// suggested indentation, then auto-indent the line.
|
// suggested indentation, then auto-indent the line.
|
||||||
let cursor = selection.head();
|
let cursor = selection.head();
|
||||||
let current_indent = snapshot.indent_size_for_line(cursor.row);
|
let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
|
||||||
if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
|
if let Some(suggested_indent) =
|
||||||
|
suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
|
||||||
|
{
|
||||||
if cursor.column < suggested_indent.len
|
if cursor.column < suggested_indent.len
|
||||||
&& cursor.column <= current_indent.len
|
&& cursor.column <= current_indent.len
|
||||||
&& current_indent.len <= suggested_indent.len
|
&& current_indent.len <= suggested_indent.len
|
||||||
@ -4996,7 +4998,7 @@ impl Editor {
|
|||||||
let mut delta_for_end_row = 0;
|
let mut delta_for_end_row = 0;
|
||||||
let has_multiple_rows = start_row + 1 != end_row;
|
let has_multiple_rows = start_row + 1 != end_row;
|
||||||
for row in start_row..end_row {
|
for row in start_row..end_row {
|
||||||
let current_indent = snapshot.indent_size_for_line(row);
|
let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
|
||||||
let indent_delta = match (current_indent.kind, indent_kind) {
|
let indent_delta = match (current_indent.kind, indent_kind) {
|
||||||
(IndentKind::Space, IndentKind::Space) => {
|
(IndentKind::Space, IndentKind::Space) => {
|
||||||
let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
|
let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
|
||||||
@ -5054,11 +5056,11 @@ impl Editor {
|
|||||||
// previous selection.
|
// previous selection.
|
||||||
if let Some(last_row) = last_outdent {
|
if let Some(last_row) = last_outdent {
|
||||||
if last_row == rows.start {
|
if last_row == rows.start {
|
||||||
rows.start += 1;
|
rows.start = rows.start.next_row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let has_multiple_rows = rows.len() > 1;
|
let has_multiple_rows = rows.len() > 1;
|
||||||
for row in rows {
|
for row in rows.iter_rows() {
|
||||||
let indent_size = snapshot.indent_size_for_line(row);
|
let indent_size = snapshot.indent_size_for_line(row);
|
||||||
if indent_size.len > 0 {
|
if indent_size.len > 0 {
|
||||||
let deletion_len = match indent_size.kind {
|
let deletion_len = match indent_size.kind {
|
||||||
@ -5080,8 +5082,9 @@ impl Editor {
|
|||||||
} else {
|
} else {
|
||||||
selection.start.column - deletion_len
|
selection.start.column - deletion_len
|
||||||
};
|
};
|
||||||
deletion_ranges
|
deletion_ranges.push(
|
||||||
.push(Point::new(row, start)..Point::new(row, start + deletion_len));
|
Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
|
||||||
|
);
|
||||||
last_outdent = Some(row);
|
last_outdent = Some(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5127,23 +5130,23 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let buffer = &display_map.buffer_snapshot;
|
let buffer = &display_map.buffer_snapshot;
|
||||||
let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
|
let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
|
||||||
let edit_end;
|
let edit_end;
|
||||||
let cursor_buffer_row;
|
let cursor_buffer_row;
|
||||||
if buffer.max_point().row >= rows.end {
|
if buffer.max_point().row >= rows.end.0 {
|
||||||
// If there's a line after the range, delete the \n from the end of the row range
|
// If there's a line after the range, delete the \n from the end of the row range
|
||||||
// and position the cursor on the next line.
|
// and position the cursor on the next line.
|
||||||
edit_end = Point::new(rows.end, 0).to_offset(buffer);
|
edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
|
||||||
cursor_buffer_row = rows.end;
|
cursor_buffer_row = rows.end;
|
||||||
} else {
|
} else {
|
||||||
// If there isn't a line after the range, delete the \n from the line before the
|
// If there isn't a line after the range, delete the \n from the line before the
|
||||||
// start of the row range and position the cursor there.
|
// start of the row range and position the cursor there.
|
||||||
edit_start = edit_start.saturating_sub(1);
|
edit_start = edit_start.saturating_sub(1);
|
||||||
edit_end = buffer.len();
|
edit_end = buffer.len();
|
||||||
cursor_buffer_row = rows.start.saturating_sub(1);
|
cursor_buffer_row = rows.start.previous_row();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
|
let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
|
||||||
*cursor.column_mut() =
|
*cursor.column_mut() =
|
||||||
cmp::min(goal_display_column, display_map.line_len(cursor.row()));
|
cmp::min(goal_display_column, display_map.line_len(cursor.row()));
|
||||||
|
|
||||||
@ -5190,13 +5193,13 @@ impl Editor {
|
|||||||
if self.read_only(cx) {
|
if self.read_only(cx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut row_ranges = Vec::<Range<u32>>::new();
|
let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
|
||||||
for selection in self.selections.all::<Point>(cx) {
|
for selection in self.selections.all::<Point>(cx) {
|
||||||
let start = selection.start.row;
|
let start = MultiBufferRow(selection.start.row);
|
||||||
let end = if selection.start.row == selection.end.row {
|
let end = if selection.start.row == selection.end.row {
|
||||||
selection.start.row + 1
|
MultiBufferRow(selection.start.row + 1)
|
||||||
} else {
|
} else {
|
||||||
selection.end.row
|
MultiBufferRow(selection.end.row)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(last_row_range) = row_ranges.last_mut() {
|
if let Some(last_row_range) = row_ranges.last_mut() {
|
||||||
@ -5212,20 +5215,21 @@ impl Editor {
|
|||||||
let mut cursor_positions = Vec::new();
|
let mut cursor_positions = Vec::new();
|
||||||
for row_range in &row_ranges {
|
for row_range in &row_ranges {
|
||||||
let anchor = snapshot.anchor_before(Point::new(
|
let anchor = snapshot.anchor_before(Point::new(
|
||||||
row_range.end - 1,
|
row_range.end.previous_row().0,
|
||||||
snapshot.line_len(row_range.end - 1),
|
snapshot.line_len(row_range.end.previous_row()),
|
||||||
));
|
));
|
||||||
cursor_positions.push(anchor..anchor);
|
cursor_positions.push(anchor..anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.transact(cx, |this, cx| {
|
self.transact(cx, |this, cx| {
|
||||||
for row_range in row_ranges.into_iter().rev() {
|
for row_range in row_ranges.into_iter().rev() {
|
||||||
for row in row_range.rev() {
|
for row in row_range.iter_rows().rev() {
|
||||||
let end_of_line = Point::new(row, snapshot.line_len(row));
|
let end_of_line = Point::new(row.0, snapshot.line_len(row));
|
||||||
let indent = snapshot.indent_size_for_line(row + 1);
|
let next_line_row = row.next_row();
|
||||||
let start_of_next_line = Point::new(row + 1, indent.len);
|
let indent = snapshot.indent_size_for_line(next_line_row);
|
||||||
|
let start_of_next_line = Point::new(next_line_row.0, indent.len);
|
||||||
|
|
||||||
let replace = if snapshot.line_len(row + 1) > indent.len {
|
let replace = if snapshot.line_len(next_line_row) > indent.len {
|
||||||
" "
|
" "
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
@ -5342,7 +5346,7 @@ impl Editor {
|
|||||||
fn prepare_revert_change(
|
fn prepare_revert_change(
|
||||||
revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
|
revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
|
||||||
multi_buffer: &MultiBuffer,
|
multi_buffer: &MultiBuffer,
|
||||||
hunk: &DiffHunk<u32>,
|
hunk: &DiffHunk<MultiBufferRow>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let buffer = multi_buffer.buffer(hunk.buffer_id)?;
|
let buffer = multi_buffer.buffer(hunk.buffer_id)?;
|
||||||
@ -5396,8 +5400,11 @@ impl Editor {
|
|||||||
&mut selections,
|
&mut selections,
|
||||||
);
|
);
|
||||||
|
|
||||||
let start_point = Point::new(start_row, 0);
|
let start_point = Point::new(start_row.0, 0);
|
||||||
let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1));
|
let end_point = Point::new(
|
||||||
|
end_row.previous_row().0,
|
||||||
|
buffer.line_len(end_row.previous_row()),
|
||||||
|
);
|
||||||
let text = buffer
|
let text = buffer
|
||||||
.text_for_range(start_point..end_point)
|
.text_for_range(start_point..end_point)
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
@ -5411,8 +5418,9 @@ impl Editor {
|
|||||||
edits.push((start_point..end_point, lines.join("\n")));
|
edits.push((start_point..end_point, lines.join("\n")));
|
||||||
|
|
||||||
// Selections must change based on added and removed line count
|
// Selections must change based on added and removed line count
|
||||||
let start_row = start_point.row + added_lines as u32 - removed_lines as u32;
|
let start_row =
|
||||||
let end_row = start_row + lines_after.saturating_sub(1) as u32;
|
MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
|
||||||
|
let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
|
||||||
new_selections.push(Selection {
|
new_selections.push(Selection {
|
||||||
id: selection.id,
|
id: selection.id,
|
||||||
start: start_row,
|
start: start_row,
|
||||||
@ -5438,8 +5446,8 @@ impl Editor {
|
|||||||
let new_selections = new_selections
|
let new_selections = new_selections
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
let start_point = Point::new(s.start, 0);
|
let start_point = Point::new(s.start.0, 0);
|
||||||
let end_point = Point::new(s.end, buffer.line_len(s.end));
|
let end_point = Point::new(s.end.0, buffer.line_len(s.end));
|
||||||
Selection {
|
Selection {
|
||||||
id: s.id,
|
id: s.id,
|
||||||
start: buffer.point_to_offset(start_point),
|
start: buffer.point_to_offset(start_point),
|
||||||
@ -5602,14 +5610,17 @@ impl Editor {
|
|||||||
|
|
||||||
// Copy the text from the selected row region and splice it either at the start
|
// Copy the text from the selected row region and splice it either at the start
|
||||||
// or end of the region.
|
// or end of the region.
|
||||||
let start = Point::new(rows.start, 0);
|
let start = Point::new(rows.start.0, 0);
|
||||||
let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
|
let end = Point::new(
|
||||||
|
rows.end.previous_row().0,
|
||||||
|
buffer.line_len(rows.end.previous_row()),
|
||||||
|
);
|
||||||
let text = buffer
|
let text = buffer
|
||||||
.text_for_range(start..end)
|
.text_for_range(start..end)
|
||||||
.chain(Some("\n"))
|
.chain(Some("\n"))
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
let insert_location = if upwards {
|
let insert_location = if upwards {
|
||||||
Point::new(rows.end, 0)
|
Point::new(rows.end.0, 0)
|
||||||
} else {
|
} else {
|
||||||
start
|
start
|
||||||
};
|
};
|
||||||
@ -5656,11 +5667,17 @@ impl Editor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Move the text spanned by the row range to be before the line preceding the row range
|
// Move the text spanned by the row range to be before the line preceding the row range
|
||||||
if start_row > 0 {
|
if start_row.0 > 0 {
|
||||||
let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
|
let range_to_move = Point::new(
|
||||||
..Point::new(end_row - 1, buffer.line_len(end_row - 1));
|
start_row.previous_row().0,
|
||||||
|
buffer.line_len(start_row.previous_row()),
|
||||||
|
)
|
||||||
|
..Point::new(
|
||||||
|
end_row.previous_row().0,
|
||||||
|
buffer.line_len(end_row.previous_row()),
|
||||||
|
);
|
||||||
let insertion_point = display_map
|
let insertion_point = display_map
|
||||||
.prev_line_boundary(Point::new(start_row - 1, 0))
|
.prev_line_boundary(Point::new(start_row.previous_row().0, 0))
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
// Don't move lines across excerpts
|
// Don't move lines across excerpts
|
||||||
@ -5754,9 +5771,12 @@ impl Editor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Move the text spanned by the row range to be after the last line of the row range
|
// Move the text spanned by the row range to be after the last line of the row range
|
||||||
if end_row <= buffer.max_point().row {
|
if end_row.0 <= buffer.max_point().row {
|
||||||
let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
|
let range_to_move =
|
||||||
let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
|
MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
|
||||||
|
let insertion_point = display_map
|
||||||
|
.next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
|
||||||
|
.0;
|
||||||
|
|
||||||
// Don't move lines across excerpt boundaries
|
// Don't move lines across excerpt boundaries
|
||||||
if buffer
|
if buffer
|
||||||
@ -5906,7 +5926,9 @@ impl Editor {
|
|||||||
clipboard_selections.push(ClipboardSelection {
|
clipboard_selections.push(ClipboardSelection {
|
||||||
len,
|
len,
|
||||||
is_entire_line,
|
is_entire_line,
|
||||||
first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
|
first_line_indent: buffer
|
||||||
|
.indent_size_for_line(MultiBufferRow(selection.start.row))
|
||||||
|
.len,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5950,7 +5972,7 @@ impl Editor {
|
|||||||
clipboard_selections.push(ClipboardSelection {
|
clipboard_selections.push(ClipboardSelection {
|
||||||
len,
|
len,
|
||||||
is_entire_line,
|
is_entire_line,
|
||||||
first_line_indent: buffer.indent_size_for_line(start.row).len,
|
first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6847,8 +6869,8 @@ impl Editor {
|
|||||||
let max_point = display_map.buffer_snapshot.max_point();
|
let max_point = display_map.buffer_snapshot.max_point();
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
let rows = selection.spanned_rows(true, &display_map);
|
let rows = selection.spanned_rows(true, &display_map);
|
||||||
selection.start = Point::new(rows.start, 0);
|
selection.start = Point::new(rows.start.0, 0);
|
||||||
selection.end = cmp::min(max_point, Point::new(rows.end, 0));
|
selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
|
||||||
selection.reversed = false;
|
selection.reversed = false;
|
||||||
}
|
}
|
||||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
@ -6868,7 +6890,7 @@ impl Editor {
|
|||||||
let buffer = self.buffer.read(cx).read(cx);
|
let buffer = self.buffer.read(cx).read(cx);
|
||||||
for selection in selections {
|
for selection in selections {
|
||||||
for row in selection.start.row..selection.end.row {
|
for row in selection.start.row..selection.end.row {
|
||||||
let cursor = Point::new(row, buffer.line_len(row));
|
let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
|
||||||
new_selection_ranges.push(cursor..cursor);
|
new_selection_ranges.push(cursor..cursor);
|
||||||
}
|
}
|
||||||
new_selection_ranges.push(selection.end..selection.end);
|
new_selection_ranges.push(selection.end..selection.end);
|
||||||
@ -6903,10 +6925,10 @@ impl Editor {
|
|||||||
|
|
||||||
selections.clear();
|
selections.clear();
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
for row in range.start.row()..=range.end.row() {
|
for row in range.start.row().0..=range.end.row().0 {
|
||||||
if let Some(selection) = self.selections.build_columnar_selection(
|
if let Some(selection) = self.selections.build_columnar_selection(
|
||||||
&display_map,
|
&display_map,
|
||||||
row,
|
DisplayRow(row),
|
||||||
&positions,
|
&positions,
|
||||||
oldest_selection.reversed,
|
oldest_selection.reversed,
|
||||||
&text_layout_details,
|
&text_layout_details,
|
||||||
@ -6927,7 +6949,7 @@ impl Editor {
|
|||||||
let mut new_selections = Vec::new();
|
let mut new_selections = Vec::new();
|
||||||
if above == state.above {
|
if above == state.above {
|
||||||
let end_row = if above {
|
let end_row = if above {
|
||||||
0
|
DisplayRow(0)
|
||||||
} else {
|
} else {
|
||||||
display_map.max_point().row()
|
display_map.max_point().row()
|
||||||
};
|
};
|
||||||
@ -6950,9 +6972,9 @@ impl Editor {
|
|||||||
|
|
||||||
while row != end_row {
|
while row != end_row {
|
||||||
if above {
|
if above {
|
||||||
row -= 1;
|
row.0 -= 1;
|
||||||
} else {
|
} else {
|
||||||
row += 1;
|
row.0 += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_selection) = self.selections.build_columnar_selection(
|
if let Some(new_selection) = self.selections.build_columnar_selection(
|
||||||
@ -7386,7 +7408,7 @@ impl Editor {
|
|||||||
pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
|
pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
|
||||||
let text_layout_details = &self.text_layout_details(cx);
|
let text_layout_details = &self.text_layout_details(cx);
|
||||||
self.transact(cx, |this, cx| {
|
self.transact(cx, |this, cx| {
|
||||||
let mut selections = this.selections.all::<Point>(cx);
|
let mut selections = this.selections.all::<MultiBufferPoint>(cx);
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
let mut selection_edit_ranges = Vec::new();
|
let mut selection_edit_ranges = Vec::new();
|
||||||
let mut last_toggled_row = None;
|
let mut last_toggled_row = None;
|
||||||
@ -7396,11 +7418,11 @@ impl Editor {
|
|||||||
|
|
||||||
fn comment_prefix_range(
|
fn comment_prefix_range(
|
||||||
snapshot: &MultiBufferSnapshot,
|
snapshot: &MultiBufferSnapshot,
|
||||||
row: u32,
|
row: MultiBufferRow,
|
||||||
comment_prefix: &str,
|
comment_prefix: &str,
|
||||||
comment_prefix_whitespace: &str,
|
comment_prefix_whitespace: &str,
|
||||||
) -> Range<Point> {
|
) -> Range<Point> {
|
||||||
let start = Point::new(row, snapshot.indent_size_for_line(row).len);
|
let start = Point::new(row.0, snapshot.indent_size_for_line(row).len);
|
||||||
|
|
||||||
let mut line_bytes = snapshot
|
let mut line_bytes = snapshot
|
||||||
.bytes_in_range(start..snapshot.max_point())
|
.bytes_in_range(start..snapshot.max_point())
|
||||||
@ -7431,11 +7453,11 @@ impl Editor {
|
|||||||
|
|
||||||
fn comment_suffix_range(
|
fn comment_suffix_range(
|
||||||
snapshot: &MultiBufferSnapshot,
|
snapshot: &MultiBufferSnapshot,
|
||||||
row: u32,
|
row: MultiBufferRow,
|
||||||
comment_suffix: &str,
|
comment_suffix: &str,
|
||||||
comment_suffix_has_leading_space: bool,
|
comment_suffix_has_leading_space: bool,
|
||||||
) -> Range<Point> {
|
) -> Range<Point> {
|
||||||
let end = Point::new(row, snapshot.line_len(row));
|
let end = Point::new(row.0, snapshot.line_len(row));
|
||||||
let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
|
let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
|
||||||
|
|
||||||
let mut line_end_bytes = snapshot
|
let mut line_end_bytes = snapshot
|
||||||
@ -7464,7 +7486,9 @@ impl Editor {
|
|||||||
|
|
||||||
// TODO: Handle selections that cross excerpts
|
// TODO: Handle selections that cross excerpts
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
let start_column = snapshot.indent_size_for_line(selection.start.row).len;
|
let start_column = snapshot
|
||||||
|
.indent_size_for_line(MultiBufferRow(selection.start.row))
|
||||||
|
.len;
|
||||||
let language = if let Some(language) =
|
let language = if let Some(language) =
|
||||||
snapshot.language_scope_at(Point::new(selection.start.row, start_column))
|
snapshot.language_scope_at(Point::new(selection.start.row, start_column))
|
||||||
{
|
{
|
||||||
@ -7477,15 +7501,15 @@ impl Editor {
|
|||||||
|
|
||||||
// If multiple selections contain a given row, avoid processing that
|
// If multiple selections contain a given row, avoid processing that
|
||||||
// row more than once.
|
// row more than once.
|
||||||
let mut start_row = selection.start.row;
|
let mut start_row = MultiBufferRow(selection.start.row);
|
||||||
if last_toggled_row == Some(start_row) {
|
if last_toggled_row == Some(start_row) {
|
||||||
start_row += 1;
|
start_row = start_row.next_row();
|
||||||
}
|
}
|
||||||
let end_row =
|
let end_row =
|
||||||
if selection.end.row > selection.start.row && selection.end.column == 0 {
|
if selection.end.row > selection.start.row && selection.end.column == 0 {
|
||||||
selection.end.row - 1
|
MultiBufferRow(selection.end.row - 1)
|
||||||
} else {
|
} else {
|
||||||
selection.end.row
|
MultiBufferRow(selection.end.row)
|
||||||
};
|
};
|
||||||
last_toggled_row = Some(end_row);
|
last_toggled_row = Some(end_row);
|
||||||
|
|
||||||
@ -7506,7 +7530,8 @@ impl Editor {
|
|||||||
|
|
||||||
let mut all_selection_lines_are_comments = true;
|
let mut all_selection_lines_are_comments = true;
|
||||||
|
|
||||||
for row in start_row..=end_row {
|
for row in start_row.0..=end_row.0 {
|
||||||
|
let row = MultiBufferRow(row);
|
||||||
if start_row < end_row && snapshot.is_line_blank(row) {
|
if start_row < end_row && snapshot.is_line_blank(row) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -7596,7 +7621,7 @@ impl Editor {
|
|||||||
let snapshot = this.buffer.read(cx).read(cx);
|
let snapshot = this.buffer.read(cx).read(cx);
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
|
while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
|
||||||
match row.cmp(&selection.end.row) {
|
match row.cmp(&MultiBufferRow(selection.end.row)) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
suffixes_inserted.next();
|
suffixes_inserted.next();
|
||||||
continue;
|
continue;
|
||||||
@ -7782,7 +7807,7 @@ impl Editor {
|
|||||||
|
|
||||||
let row = snapshot
|
let row = snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.buffer_line_for_row(point.row)?
|
.buffer_line_for_row(MultiBufferRow(point.row))?
|
||||||
.1
|
.1
|
||||||
.start
|
.start
|
||||||
.row;
|
.row;
|
||||||
@ -8060,9 +8085,9 @@ impl Editor {
|
|||||||
&snapshot,
|
&snapshot,
|
||||||
selection.head(),
|
selection.head(),
|
||||||
false,
|
false,
|
||||||
snapshot
|
snapshot.buffer_snapshot.git_diff_hunks_in_range(
|
||||||
.buffer_snapshot
|
MultiBufferRow(selection.head().row + 1)..MultiBufferRow::MAX,
|
||||||
.git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
|
),
|
||||||
cx,
|
cx,
|
||||||
) {
|
) {
|
||||||
let wrapped_point = Point::zero();
|
let wrapped_point = Point::zero();
|
||||||
@ -8070,9 +8095,9 @@ impl Editor {
|
|||||||
&snapshot,
|
&snapshot,
|
||||||
wrapped_point,
|
wrapped_point,
|
||||||
true,
|
true,
|
||||||
snapshot
|
snapshot.buffer_snapshot.git_diff_hunks_in_range(
|
||||||
.buffer_snapshot
|
MultiBufferRow(wrapped_point.row + 1)..MultiBufferRow::MAX,
|
||||||
.git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
|
),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -8088,9 +8113,9 @@ impl Editor {
|
|||||||
&snapshot,
|
&snapshot,
|
||||||
selection.head(),
|
selection.head(),
|
||||||
false,
|
false,
|
||||||
snapshot
|
snapshot.buffer_snapshot.git_diff_hunks_in_range_rev(
|
||||||
.buffer_snapshot
|
MultiBufferRow(0)..MultiBufferRow(selection.head().row),
|
||||||
.git_diff_hunks_in_range_rev(0..selection.head().row),
|
),
|
||||||
cx,
|
cx,
|
||||||
) {
|
) {
|
||||||
let wrapped_point = snapshot.buffer_snapshot.max_point();
|
let wrapped_point = snapshot.buffer_snapshot.max_point();
|
||||||
@ -8098,9 +8123,9 @@ impl Editor {
|
|||||||
&snapshot,
|
&snapshot,
|
||||||
wrapped_point,
|
wrapped_point,
|
||||||
true,
|
true,
|
||||||
snapshot
|
snapshot.buffer_snapshot.git_diff_hunks_in_range_rev(
|
||||||
.buffer_snapshot
|
MultiBufferRow(0)..MultiBufferRow(wrapped_point.row),
|
||||||
.git_diff_hunks_in_range_rev(0..wrapped_point.row),
|
),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -8111,7 +8136,7 @@ impl Editor {
|
|||||||
snapshot: &DisplaySnapshot,
|
snapshot: &DisplaySnapshot,
|
||||||
initial_point: Point,
|
initial_point: Point,
|
||||||
is_wrapped: bool,
|
is_wrapped: bool,
|
||||||
hunks: impl Iterator<Item = DiffHunk<u32>>,
|
hunks: impl Iterator<Item = DiffHunk<MultiBufferRow>>,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let display_point = initial_point.to_display_point(snapshot);
|
let display_point = initial_point.to_display_point(snapshot);
|
||||||
@ -8972,11 +8997,11 @@ impl Editor {
|
|||||||
let mut primary_message = None;
|
let mut primary_message = None;
|
||||||
let mut group_end = Point::zero();
|
let mut group_end = Point::zero();
|
||||||
let diagnostic_group = buffer
|
let diagnostic_group = buffer
|
||||||
.diagnostic_group::<Point>(group_id)
|
.diagnostic_group::<MultiBufferPoint>(group_id)
|
||||||
.filter_map(|entry| {
|
.filter_map(|entry| {
|
||||||
if snapshot.is_line_folded(entry.range.start.row)
|
if snapshot.is_line_folded(MultiBufferRow(entry.range.start.row))
|
||||||
&& (entry.range.start.row == entry.range.end.row
|
&& (entry.range.start.row == entry.range.end.row
|
||||||
|| snapshot.is_line_folded(entry.range.end.row))
|
|| snapshot.is_line_folded(MultiBufferRow(entry.range.end.row)))
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -9117,7 +9142,7 @@ impl Editor {
|
|||||||
let buffer_start_row = range.start.row;
|
let buffer_start_row = range.start.row;
|
||||||
|
|
||||||
for row in (0..=range.end.row).rev() {
|
for row in (0..=range.end.row).rev() {
|
||||||
let fold_range = display_map.foldable_range(row);
|
let fold_range = display_map.foldable_range(MultiBufferRow(row));
|
||||||
|
|
||||||
if let Some(fold_range) = fold_range {
|
if let Some(fold_range) = fold_range {
|
||||||
if fold_range.end.row >= buffer_start_row {
|
if fold_range.end.row >= buffer_start_row {
|
||||||
@ -9159,7 +9184,7 @@ impl Editor {
|
|||||||
let mut start = range.start.to_point(&display_map);
|
let mut start = range.start.to_point(&display_map);
|
||||||
let mut end = range.end.to_point(&display_map);
|
let mut end = range.end.to_point(&display_map);
|
||||||
start.column = 0;
|
start.column = 0;
|
||||||
end.column = buffer.line_len(end.row);
|
end.column = buffer.line_len(MultiBufferRow(end.row));
|
||||||
start..end
|
start..end
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -9170,9 +9195,9 @@ impl Editor {
|
|||||||
pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
|
pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
|
|
||||||
let intersection_range = Point::new(unfold_at.buffer_row, 0)
|
let intersection_range = Point::new(unfold_at.buffer_row.0, 0)
|
||||||
..Point::new(
|
..Point::new(
|
||||||
unfold_at.buffer_row,
|
unfold_at.buffer_row.0,
|
||||||
display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
|
display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -9192,7 +9217,12 @@ impl Editor {
|
|||||||
let ranges = selections.into_iter().map(|s| {
|
let ranges = selections.into_iter().map(|s| {
|
||||||
if line_mode {
|
if line_mode {
|
||||||
let start = Point::new(s.start.row, 0);
|
let start = Point::new(s.start.row, 0);
|
||||||
let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
|
let end = Point::new(
|
||||||
|
s.end.row,
|
||||||
|
display_map
|
||||||
|
.buffer_snapshot
|
||||||
|
.line_len(MultiBufferRow(s.end.row)),
|
||||||
|
);
|
||||||
start..end
|
start..end
|
||||||
} else {
|
} else {
|
||||||
s.start..s.end
|
s.start..s.end
|
||||||
@ -9330,7 +9360,7 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
|
pub fn longest_row(&self, cx: &mut AppContext) -> DisplayRow {
|
||||||
self.display_map
|
self.display_map
|
||||||
.update(cx, |map, cx| map.snapshot(cx))
|
.update(cx, |map, cx| map.snapshot(cx))
|
||||||
.longest_row()
|
.longest_row()
|
||||||
@ -9595,7 +9625,7 @@ impl Editor {
|
|||||||
let cursor_anchor = self.selections.newest_anchor().head();
|
let cursor_anchor = self.selections.newest_anchor().head();
|
||||||
|
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||||
let buffer_row = cursor_anchor.to_point(&snapshot).row;
|
let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
|
||||||
|
|
||||||
snapshot.line_len(buffer_row) == 0
|
snapshot.line_len(buffer_row) == 0
|
||||||
}
|
}
|
||||||
@ -9776,7 +9806,7 @@ impl Editor {
|
|||||||
&mut self,
|
&mut self,
|
||||||
exclude_highlights: HashSet<TypeId>,
|
exclude_highlights: HashSet<TypeId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> BTreeMap<u32, Hsla> {
|
) -> BTreeMap<DisplayRow, Hsla> {
|
||||||
let snapshot = self.snapshot(cx);
|
let snapshot = self.snapshot(cx);
|
||||||
let mut used_highlight_orders = HashMap::default();
|
let mut used_highlight_orders = HashMap::default();
|
||||||
self.highlighted_rows
|
self.highlighted_rows
|
||||||
@ -9784,21 +9814,21 @@ impl Editor {
|
|||||||
.filter(|(type_id, _)| !exclude_highlights.contains(type_id))
|
.filter(|(type_id, _)| !exclude_highlights.contains(type_id))
|
||||||
.flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
|
.flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
|
||||||
.fold(
|
.fold(
|
||||||
BTreeMap::<u32, Hsla>::new(),
|
BTreeMap::<DisplayRow, Hsla>::new(),
|
||||||
|mut unique_rows, (highlight_order, anchor_range, hsla)| {
|
|mut unique_rows, (highlight_order, anchor_range, hsla)| {
|
||||||
let start_row = anchor_range.start().to_display_point(&snapshot).row();
|
let start_row = anchor_range.start().to_display_point(&snapshot).row();
|
||||||
let end_row = anchor_range.end().to_display_point(&snapshot).row();
|
let end_row = anchor_range.end().to_display_point(&snapshot).row();
|
||||||
for row in start_row..=end_row {
|
for row in start_row.0..=end_row.0 {
|
||||||
let used_index =
|
let used_index =
|
||||||
used_highlight_orders.entry(row).or_insert(*highlight_order);
|
used_highlight_orders.entry(row).or_insert(*highlight_order);
|
||||||
if highlight_order >= used_index {
|
if highlight_order >= used_index {
|
||||||
*used_index = *highlight_order;
|
*used_index = *highlight_order;
|
||||||
match hsla {
|
match hsla {
|
||||||
Some(hsla) => {
|
Some(hsla) => {
|
||||||
unique_rows.insert(row, *hsla);
|
unique_rows.insert(DisplayRow(row), *hsla);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
unique_rows.remove(&row);
|
unique_rows.remove(&DisplayRow(row));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10640,15 +10670,15 @@ impl Editor {
|
|||||||
fn hunks_for_selections(
|
fn hunks_for_selections(
|
||||||
multi_buffer_snapshot: &MultiBufferSnapshot,
|
multi_buffer_snapshot: &MultiBufferSnapshot,
|
||||||
selections: &[Selection<Anchor>],
|
selections: &[Selection<Anchor>],
|
||||||
) -> Vec<DiffHunk<u32>> {
|
) -> Vec<DiffHunk<MultiBufferRow>> {
|
||||||
let mut hunks = Vec::with_capacity(selections.len());
|
let mut hunks = Vec::with_capacity(selections.len());
|
||||||
let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
|
let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
|
||||||
HashMap::default();
|
HashMap::default();
|
||||||
let display_rows_for_selections = selections.iter().map(|selection| {
|
let buffer_rows_for_selections = selections.iter().map(|selection| {
|
||||||
let head = selection.head();
|
let head = selection.head();
|
||||||
let tail = selection.tail();
|
let tail = selection.tail();
|
||||||
let start = tail.to_point(&multi_buffer_snapshot).row;
|
let start = MultiBufferRow(tail.to_point(&multi_buffer_snapshot).row);
|
||||||
let end = head.to_point(&multi_buffer_snapshot).row;
|
let end = MultiBufferRow(head.to_point(&multi_buffer_snapshot).row);
|
||||||
if start > end {
|
if start > end {
|
||||||
end..start
|
end..start
|
||||||
} else {
|
} else {
|
||||||
@ -10656,12 +10686,13 @@ fn hunks_for_selections(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for selected_multi_buffer_rows in display_rows_for_selections {
|
for selected_multi_buffer_rows in buffer_rows_for_selections {
|
||||||
let query_rows = selected_multi_buffer_rows.start..selected_multi_buffer_rows.end + 1;
|
let query_rows =
|
||||||
|
selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row();
|
||||||
for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) {
|
for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) {
|
||||||
// Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
|
// Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
|
||||||
// when the caret is just above or just below the deleted hunk.
|
// when the caret is just above or just below the deleted hunk.
|
||||||
let allow_adjacent = hunk.status() == DiffHunkStatus::Removed;
|
let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
|
||||||
let related_to_selection = if allow_adjacent {
|
let related_to_selection = if allow_adjacent {
|
||||||
hunk.associated_range.overlaps(&query_rows)
|
hunk.associated_range.overlaps(&query_rows)
|
||||||
|| hunk.associated_range.start == query_rows.end
|
|| hunk.associated_range.start == query_rows.end
|
||||||
@ -10798,13 +10829,13 @@ fn consume_contiguous_rows(
|
|||||||
selection: &Selection<Point>,
|
selection: &Selection<Point>,
|
||||||
display_map: &DisplaySnapshot,
|
display_map: &DisplaySnapshot,
|
||||||
selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
|
selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
|
||||||
) -> (u32, u32) {
|
) -> (MultiBufferRow, MultiBufferRow) {
|
||||||
contiguous_row_selections.push(selection.clone());
|
contiguous_row_selections.push(selection.clone());
|
||||||
let start_row = selection.start.row;
|
let start_row = MultiBufferRow(selection.start.row);
|
||||||
let mut end_row = ending_row(selection, display_map);
|
let mut end_row = ending_row(selection, display_map);
|
||||||
|
|
||||||
while let Some(next_selection) = selections.peek() {
|
while let Some(next_selection) = selections.peek() {
|
||||||
if next_selection.start.row <= end_row {
|
if next_selection.start.row <= end_row.0 {
|
||||||
end_row = ending_row(next_selection, display_map);
|
end_row = ending_row(next_selection, display_map);
|
||||||
contiguous_row_selections.push(selections.next().unwrap().clone());
|
contiguous_row_selections.push(selections.next().unwrap().clone());
|
||||||
} else {
|
} else {
|
||||||
@ -10814,11 +10845,11 @@ fn consume_contiguous_rows(
|
|||||||
(start_row, end_row)
|
(start_row, end_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
|
fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
|
||||||
if next_selection.end.column > 0 || next_selection.is_empty() {
|
if next_selection.end.column > 0 || next_selection.is_empty() {
|
||||||
display_map.next_line_boundary(next_selection.end).0.row + 1
|
MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
|
||||||
} else {
|
} else {
|
||||||
next_selection.end.row
|
MultiBufferRow(next_selection.end.row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11300,7 +11331,7 @@ impl ViewInputHandler for Editor {
|
|||||||
let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
|
let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
|
||||||
let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
|
let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
|
||||||
+ self.gutter_dimensions.width;
|
+ self.gutter_dimensions.width;
|
||||||
let y = line_height * (start.row() as f32 - scroll_position.y);
|
let y = line_height * (start.row().as_f32() - scroll_position.y);
|
||||||
|
|
||||||
Some(Bounds {
|
Some(Bounds {
|
||||||
origin: element_bounds.origin + point(x, y),
|
origin: element_bounds.origin + point(x, y),
|
||||||
@ -11311,8 +11342,11 @@ impl ViewInputHandler for Editor {
|
|||||||
|
|
||||||
trait SelectionExt {
|
trait SelectionExt {
|
||||||
fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
|
fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
|
||||||
fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
|
fn spanned_rows(
|
||||||
-> Range<u32>;
|
&self,
|
||||||
|
include_end_if_at_line_start: bool,
|
||||||
|
map: &DisplaySnapshot,
|
||||||
|
) -> Range<MultiBufferRow>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
|
impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
|
||||||
@ -11336,7 +11370,7 @@ impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
|
|||||||
&self,
|
&self,
|
||||||
include_end_if_at_line_start: bool,
|
include_end_if_at_line_start: bool,
|
||||||
map: &DisplaySnapshot,
|
map: &DisplaySnapshot,
|
||||||
) -> Range<u32> {
|
) -> Range<MultiBufferRow> {
|
||||||
let start = self.start.to_point(&map.buffer_snapshot);
|
let start = self.start.to_point(&map.buffer_snapshot);
|
||||||
let mut end = self.end.to_point(&map.buffer_snapshot);
|
let mut end = self.end.to_point(&map.buffer_snapshot);
|
||||||
if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
|
if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
|
||||||
@ -11345,7 +11379,7 @@ impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
|
|||||||
|
|
||||||
let buffer_start = map.prev_line_boundary(start).0;
|
let buffer_start = map.prev_line_boundary(start).0;
|
||||||
let buffer_end = map.next_line_boundary(end).0;
|
let buffer_end = map.next_line_boundary(end).0;
|
||||||
buffer_start.row..buffer_end.row + 1
|
MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11609,3 +11643,91 @@ impl<T: ToOffset> RangeToAnchorExt for Range<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait RowExt {
|
||||||
|
fn as_f32(&self) -> f32;
|
||||||
|
|
||||||
|
fn next_row(&self) -> Self;
|
||||||
|
|
||||||
|
fn previous_row(&self) -> Self;
|
||||||
|
|
||||||
|
fn minus(&self, other: Self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RowExt for DisplayRow {
|
||||||
|
fn as_f32(&self) -> f32 {
|
||||||
|
self.0 as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_row(&self) -> Self {
|
||||||
|
Self(self.0 + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn previous_row(&self) -> Self {
|
||||||
|
Self(self.0.saturating_sub(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minus(&self, other: Self) -> u32 {
|
||||||
|
self.0 - other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RowExt for MultiBufferRow {
|
||||||
|
fn as_f32(&self) -> f32 {
|
||||||
|
self.0 as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_row(&self) -> Self {
|
||||||
|
Self(self.0 + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn previous_row(&self) -> Self {
|
||||||
|
Self(self.0.saturating_sub(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minus(&self, other: Self) -> u32 {
|
||||||
|
self.0 - other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait RowRangeExt {
|
||||||
|
type Row;
|
||||||
|
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RowRangeExt for Range<MultiBufferRow> {
|
||||||
|
type Row = MultiBufferRow;
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
(self.end.0 - self.start.0) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
|
||||||
|
(self.start.0..self.end.0).map(MultiBufferRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RowRangeExt for Range<DisplayRow> {
|
||||||
|
type Row = DisplayRow;
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
(self.end.0 - self.start.0) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
|
||||||
|
(self.start.0..self.end.0).map(DisplayRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hunk_status(hunk: &DiffHunk<MultiBufferRow>) -> DiffHunkStatus {
|
||||||
|
if hunk.diff_base_byte_range.is_empty() {
|
||||||
|
DiffHunkStatus::Added
|
||||||
|
} else if hunk.associated_range.is_empty() {
|
||||||
|
DiffHunkStatus::Removed
|
||||||
|
} else {
|
||||||
|
DiffHunkStatus::Modified
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -9,14 +9,15 @@ use crate::{
|
|||||||
hover_popover::{
|
hover_popover::{
|
||||||
self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
|
self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
|
||||||
},
|
},
|
||||||
|
hunk_status,
|
||||||
items::BufferSearchHighlights,
|
items::BufferSearchHighlights,
|
||||||
mouse_context_menu::{self, MouseContextMenu},
|
mouse_context_menu::{self, MouseContextMenu},
|
||||||
scroll::scroll_amount::ScrollAmount,
|
scroll::scroll_amount::ScrollAmount,
|
||||||
CodeActionsMenu, CursorShape, DisplayPoint, DocumentHighlightRead, DocumentHighlightWrite,
|
CodeActionsMenu, CursorShape, DisplayPoint, DisplayRow, DocumentHighlightRead,
|
||||||
Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts,
|
DocumentHighlightWrite, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
|
||||||
GutterDimensions, HalfPageDown, HalfPageUp, HoveredCursor, HunkToExpand, LineDown, LineUp,
|
ExpandExcerpts, GutterDimensions, HalfPageDown, HalfPageUp, HoveredCursor, HunkToExpand,
|
||||||
OpenExcerpts, PageDown, PageUp, Point, SelectPhase, Selection, SoftWrap, ToPoint,
|
LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase,
|
||||||
CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use client::ParticipantIndex;
|
use client::ParticipantIndex;
|
||||||
@ -35,7 +36,7 @@ use gpui::{
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::language_settings::ShowWhitespaceSetting;
|
use language::language_settings::ShowWhitespaceSetting;
|
||||||
use lsp::DiagnosticSeverity;
|
use lsp::DiagnosticSeverity;
|
||||||
use multi_buffer::Anchor;
|
use multi_buffer::{Anchor, MultiBufferPoint, MultiBufferRow};
|
||||||
use project::{
|
use project::{
|
||||||
project_settings::{GitGutterSetting, ProjectSettings},
|
project_settings::{GitGutterSetting, ProjectSettings},
|
||||||
ProjectPath,
|
ProjectPath,
|
||||||
@ -64,7 +65,7 @@ struct SelectionLayout {
|
|||||||
is_newest: bool,
|
is_newest: bool,
|
||||||
is_local: bool,
|
is_local: bool,
|
||||||
range: Range<DisplayPoint>,
|
range: Range<DisplayPoint>,
|
||||||
active_rows: Range<u32>,
|
active_rows: Range<DisplayRow>,
|
||||||
user_name: Option<SharedString>,
|
user_name: Option<SharedString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,16 +99,19 @@ impl SelectionLayout {
|
|||||||
{
|
{
|
||||||
if head.column() > 0 {
|
if head.column() > 0 {
|
||||||
head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left)
|
head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left)
|
||||||
} else if head.row() > 0 && head != map.max_point() {
|
} else if head.row().0 > 0 && head != map.max_point() {
|
||||||
head = map.clip_point(
|
head = map.clip_point(
|
||||||
DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)),
|
DisplayPoint::new(
|
||||||
|
head.row().previous_row(),
|
||||||
|
map.line_len(head.row().previous_row()),
|
||||||
|
),
|
||||||
Bias::Left,
|
Bias::Left,
|
||||||
);
|
);
|
||||||
// updating range.end is a no-op unless you're cursor is
|
// updating range.end is a no-op unless you're cursor is
|
||||||
// on the newline containing a multi-buffer divider
|
// on the newline containing a multi-buffer divider
|
||||||
// in which case the clip_point may have moved the head up
|
// in which case the clip_point may have moved the head up
|
||||||
// an additional row.
|
// an additional row.
|
||||||
range.end = DisplayPoint::new(head.row() + 1, 0);
|
range.end = DisplayPoint::new(head.row().next_row(), 0);
|
||||||
active_rows.end = head.row();
|
active_rows.end = head.row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,6 +133,8 @@ pub struct EditorElement {
|
|||||||
style: EditorStyle,
|
style: EditorStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DisplayRowDelta = u32;
|
||||||
|
|
||||||
impl EditorElement {
|
impl EditorElement {
|
||||||
pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self {
|
pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -706,12 +712,12 @@ impl EditorElement {
|
|||||||
start_anchor: Anchor,
|
start_anchor: Anchor,
|
||||||
end_anchor: Anchor,
|
end_anchor: Anchor,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
start_row: u32,
|
start_row: DisplayRow,
|
||||||
end_row: u32,
|
end_row: DisplayRow,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<(PlayerColor, Vec<SelectionLayout>)>,
|
Vec<(PlayerColor, Vec<SelectionLayout>)>,
|
||||||
BTreeMap<u32, bool>,
|
BTreeMap<DisplayRow, bool>,
|
||||||
Option<DisplayPoint>,
|
Option<DisplayPoint>,
|
||||||
) {
|
) {
|
||||||
let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
|
let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
|
||||||
@ -743,10 +749,11 @@ impl EditorElement {
|
|||||||
newest_selection_head = Some(layout.head);
|
newest_selection_head = Some(layout.head);
|
||||||
}
|
}
|
||||||
|
|
||||||
for row in cmp::max(layout.active_rows.start, start_row)
|
for row in cmp::max(layout.active_rows.start.0, start_row.0)
|
||||||
..=cmp::min(layout.active_rows.end, end_row)
|
..=cmp::min(layout.active_rows.end.0, end_row.0)
|
||||||
{
|
{
|
||||||
let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty);
|
let contains_non_empty_selection =
|
||||||
|
active_rows.entry(DisplayRow(row)).or_insert(!is_empty);
|
||||||
*contains_non_empty_selection |= !is_empty;
|
*contains_non_empty_selection |= !is_empty;
|
||||||
}
|
}
|
||||||
layouts.push(layout);
|
layouts.push(layout);
|
||||||
@ -826,7 +833,7 @@ impl EditorElement {
|
|||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
visible_anchor_range: Range<Anchor>,
|
visible_anchor_range: Range<Anchor>,
|
||||||
visible_display_row_range: Range<u32>,
|
visible_display_row_range: Range<DisplayRow>,
|
||||||
scroll_pixel_position: gpui::Point<Pixels>,
|
scroll_pixel_position: gpui::Point<Pixels>,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
@ -842,13 +849,14 @@ impl EditorElement {
|
|||||||
let row = display_range.start.row();
|
let row = display_range.start.row();
|
||||||
debug_assert!(row < visible_display_row_range.end);
|
debug_assert!(row < visible_display_row_range.end);
|
||||||
let line_layout = line_layouts
|
let line_layout = line_layouts
|
||||||
.get((row - visible_display_row_range.start) as usize)
|
.get(row.minus(visible_display_row_range.start) as usize)
|
||||||
.map(|l| &l.line)?;
|
.map(|l| &l.line)?;
|
||||||
|
|
||||||
let start_x = content_origin.x
|
let start_x = content_origin.x
|
||||||
+ line_layout.x_for_index(display_range.start.column() as usize)
|
+ line_layout.x_for_index(display_range.start.column() as usize)
|
||||||
- scroll_pixel_position.x;
|
- scroll_pixel_position.x;
|
||||||
let start_y = content_origin.y + row as f32 * line_height - scroll_pixel_position.y;
|
let start_y =
|
||||||
|
content_origin.y + row.as_f32() * line_height - scroll_pixel_position.y;
|
||||||
let end_x = content_origin.x
|
let end_x = content_origin.x
|
||||||
+ line_layout.x_for_index(display_range.end.column() as usize)
|
+ line_layout.x_for_index(display_range.end.column() as usize)
|
||||||
- scroll_pixel_position.x;
|
- scroll_pixel_position.x;
|
||||||
@ -927,7 +935,7 @@ impl EditorElement {
|
|||||||
&self,
|
&self,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
selections: &[(PlayerColor, Vec<SelectionLayout>)],
|
selections: &[(PlayerColor, Vec<SelectionLayout>)],
|
||||||
visible_display_row_range: Range<u32>,
|
visible_display_row_range: Range<DisplayRow>,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
text_hitbox: &Hitbox,
|
text_hitbox: &Hitbox,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
@ -951,7 +959,7 @@ impl EditorElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cursor_row_layout = &line_layouts
|
let cursor_row_layout = &line_layouts
|
||||||
[(cursor_position.row() - visible_display_row_range.start) as usize]
|
[cursor_position.row().minus(visible_display_row_range.start) as usize]
|
||||||
.line;
|
.line;
|
||||||
let cursor_column = cursor_position.column() as usize;
|
let cursor_column = cursor_position.column() as usize;
|
||||||
|
|
||||||
@ -999,7 +1007,8 @@ impl EditorElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let x = cursor_character_x - scroll_pixel_position.x;
|
let x = cursor_character_x - scroll_pixel_position.x;
|
||||||
let y = (cursor_position.row() as f32 - scroll_pixel_position.y / line_height)
|
let y = (cursor_position.row().as_f32()
|
||||||
|
- scroll_pixel_position.y / line_height)
|
||||||
* line_height;
|
* line_height;
|
||||||
if selection.is_newest {
|
if selection.is_newest {
|
||||||
editor.pixel_position_of_newest_cursor = Some(point(
|
editor.pixel_position_of_newest_cursor = Some(point(
|
||||||
@ -1009,7 +1018,7 @@ impl EditorElement {
|
|||||||
|
|
||||||
if autoscroll_containing_element {
|
if autoscroll_containing_element {
|
||||||
let top = text_hitbox.origin.y
|
let top = text_hitbox.origin.y
|
||||||
+ (cursor_position.row() as f32 - scroll_position.y - 3.).max(0.)
|
+ (cursor_position.row().as_f32() - scroll_position.y - 3.).max(0.)
|
||||||
* line_height;
|
* line_height;
|
||||||
let left = text_hitbox.origin.x
|
let left = text_hitbox.origin.x
|
||||||
+ (cursor_position.column() as f32 - scroll_position.x - 3.)
|
+ (cursor_position.column() as f32 - scroll_position.x - 3.)
|
||||||
@ -1017,7 +1026,7 @@ impl EditorElement {
|
|||||||
* em_width;
|
* em_width;
|
||||||
|
|
||||||
let bottom = text_hitbox.origin.y
|
let bottom = text_hitbox.origin.y
|
||||||
+ (cursor_position.row() as f32 - scroll_position.y + 4.)
|
+ (cursor_position.row().as_f32() - scroll_position.y + 4.)
|
||||||
* line_height;
|
* line_height;
|
||||||
let right = text_hitbox.origin.x
|
let right = text_hitbox.origin.x
|
||||||
+ (cursor_position.column() as f32 - scroll_position.x + 4.)
|
+ (cursor_position.column() as f32 - scroll_position.x + 4.)
|
||||||
@ -1040,7 +1049,7 @@ impl EditorElement {
|
|||||||
let cursor_name = selection.user_name.clone().map(|name| CursorName {
|
let cursor_name = selection.user_name.clone().map(|name| CursorName {
|
||||||
string: name,
|
string: name,
|
||||||
color: self.style.background,
|
color: self.style.background,
|
||||||
is_top_row: cursor_position.row() == 0,
|
is_top_row: cursor_position.row().0 == 0,
|
||||||
});
|
});
|
||||||
cursor.layout(content_origin, cursor_name, cx);
|
cursor.layout(content_origin, cursor_name, cx);
|
||||||
cursors.push(cursor);
|
cursors.push(cursor);
|
||||||
@ -1112,10 +1121,10 @@ impl EditorElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let height = bounds.size.height;
|
let height = bounds.size.height;
|
||||||
let total_rows = snapshot.max_point().row() as f32 + rows_per_page;
|
let total_rows = snapshot.max_point().row().as_f32() + rows_per_page;
|
||||||
let px_per_row = height / total_rows;
|
let px_per_row = height / total_rows;
|
||||||
let thumb_height = (rows_per_page * px_per_row).max(ScrollbarLayout::MIN_THUMB_HEIGHT);
|
let thumb_height = (rows_per_page * px_per_row).max(ScrollbarLayout::MIN_THUMB_HEIGHT);
|
||||||
let row_height = (height - thumb_height) / snapshot.max_point().row() as f32;
|
let row_height = (height - thumb_height) / snapshot.max_point().row().as_f32();
|
||||||
|
|
||||||
Some(ScrollbarLayout {
|
Some(ScrollbarLayout {
|
||||||
hitbox: cx.insert_hitbox(track_bounds, false),
|
hitbox: cx.insert_hitbox(track_bounds, false),
|
||||||
@ -1129,7 +1138,7 @@ impl EditorElement {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn layout_gutter_fold_indicators(
|
fn layout_gutter_fold_indicators(
|
||||||
&self,
|
&self,
|
||||||
fold_statuses: Vec<Option<(FoldStatus, u32, bool)>>,
|
fold_statuses: Vec<Option<(FoldStatus, MultiBufferRow, bool)>>,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
gutter_dimensions: &GutterDimensions,
|
gutter_dimensions: &GutterDimensions,
|
||||||
gutter_settings: crate::editor_settings::Gutter,
|
gutter_settings: crate::editor_settings::Gutter,
|
||||||
@ -1181,18 +1190,22 @@ impl EditorElement {
|
|||||||
&self,
|
&self,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
gutter_hitbox: &Hitbox,
|
gutter_hitbox: &Hitbox,
|
||||||
display_rows: Range<u32>,
|
display_rows: Range<DisplayRow>,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Vec<(DisplayDiffHunk, Option<Hitbox>)> {
|
) -> Vec<(DisplayDiffHunk, Option<Hitbox>)> {
|
||||||
let buffer_snapshot = &snapshot.buffer_snapshot;
|
let buffer_snapshot = &snapshot.buffer_snapshot;
|
||||||
|
|
||||||
let buffer_start_row = DisplayPoint::new(display_rows.start, 0)
|
let buffer_start_row = MultiBufferRow(
|
||||||
|
DisplayPoint::new(display_rows.start, 0)
|
||||||
.to_point(snapshot)
|
.to_point(snapshot)
|
||||||
.row;
|
.row,
|
||||||
let buffer_end_row = DisplayPoint::new(display_rows.end, 0)
|
);
|
||||||
|
let buffer_end_row = MultiBufferRow(
|
||||||
|
DisplayPoint::new(display_rows.end, 0)
|
||||||
.to_point(snapshot)
|
.to_point(snapshot)
|
||||||
.row;
|
.row,
|
||||||
|
);
|
||||||
|
|
||||||
let expanded_hunk_display_rows = self.editor.update(cx, |editor, _| {
|
let expanded_hunk_display_rows = self.editor.update(cx, |editor, _| {
|
||||||
editor
|
editor
|
||||||
@ -1249,7 +1262,7 @@ impl EditorElement {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn layout_inline_blame(
|
fn layout_inline_blame(
|
||||||
&self,
|
&self,
|
||||||
display_row: u32,
|
display_row: DisplayRow,
|
||||||
display_snapshot: &DisplaySnapshot,
|
display_snapshot: &DisplaySnapshot,
|
||||||
line_layout: &LineWithInvisibles,
|
line_layout: &LineWithInvisibles,
|
||||||
em_width: Pixels,
|
em_width: Pixels,
|
||||||
@ -1273,7 +1286,7 @@ impl EditorElement {
|
|||||||
.map(|(w, _)| w.clone());
|
.map(|(w, _)| w.clone());
|
||||||
|
|
||||||
let display_point = DisplayPoint::new(display_row, 0);
|
let display_point = DisplayPoint::new(display_row, 0);
|
||||||
let buffer_row = display_point.to_point(display_snapshot).row;
|
let buffer_row = MultiBufferRow(display_point.to_point(display_snapshot).row);
|
||||||
|
|
||||||
let blame = self.editor.read(cx).blame.clone()?;
|
let blame = self.editor.read(cx).blame.clone()?;
|
||||||
let blame_entry = blame
|
let blame_entry = blame
|
||||||
@ -1286,7 +1299,7 @@ impl EditorElement {
|
|||||||
render_inline_blame_entry(&blame, blame_entry, &self.style, workspace, cx);
|
render_inline_blame_entry(&blame, blame_entry, &self.style, workspace, cx);
|
||||||
|
|
||||||
let start_y = content_origin.y
|
let start_y = content_origin.y
|
||||||
+ line_height * (display_row as f32 - scroll_pixel_position.y / line_height);
|
+ line_height * (display_row.as_f32() - scroll_pixel_position.y / line_height);
|
||||||
|
|
||||||
let start_x = {
|
let start_x = {
|
||||||
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 6.;
|
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 6.;
|
||||||
@ -1315,7 +1328,7 @@ impl EditorElement {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn layout_blame_entries(
|
fn layout_blame_entries(
|
||||||
&self,
|
&self,
|
||||||
buffer_rows: impl Iterator<Item = Option<u32>>,
|
buffer_rows: impl Iterator<Item = Option<MultiBufferRow>>,
|
||||||
em_width: Pixels,
|
em_width: Pixels,
|
||||||
scroll_position: gpui::Point<f32>,
|
scroll_position: gpui::Point<f32>,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
@ -1399,7 +1412,7 @@ impl EditorElement {
|
|||||||
actions
|
actions
|
||||||
.tasks
|
.tasks
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|tasks| tasks.position.row)
|
.map(|tasks| tasks.position.to_display_point(snapshot).row())
|
||||||
.or_else(|| *deployed_from_indicator)
|
.or_else(|| *deployed_from_indicator)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -1407,19 +1420,16 @@ impl EditorElement {
|
|||||||
editor
|
editor
|
||||||
.tasks
|
.tasks
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|((_, row), (multibuffer_offset, _))| {
|
.filter_map(|(_, (multibuffer_offset, _))| {
|
||||||
if snapshot.is_line_folded(*row) {
|
let multibuffer_point = multibuffer_offset.to_point(&snapshot.buffer_snapshot);
|
||||||
|
let multibuffer_row = MultiBufferRow(multibuffer_point.row);
|
||||||
|
if snapshot.is_line_folded(multibuffer_row) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let display_row = snapshot
|
let display_row = multibuffer_point.to_display_point(snapshot).row();
|
||||||
.buffer_snapshot
|
|
||||||
.offset_to_point(*multibuffer_offset)
|
|
||||||
.to_display_point(&snapshot.display_snapshot)
|
|
||||||
.row();
|
|
||||||
|
|
||||||
let button = editor.render_run_indicator(
|
let button = editor.render_run_indicator(
|
||||||
&self.style,
|
&self.style,
|
||||||
Some(*row) == active_task_indicator_row,
|
Some(display_row) == active_task_indicator_row,
|
||||||
display_row,
|
display_row,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
@ -1489,10 +1499,10 @@ impl EditorElement {
|
|||||||
fn calculate_relative_line_numbers(
|
fn calculate_relative_line_numbers(
|
||||||
&self,
|
&self,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
rows: &Range<u32>,
|
rows: &Range<DisplayRow>,
|
||||||
relative_to: Option<u32>,
|
relative_to: Option<DisplayRow>,
|
||||||
) -> HashMap<u32, u32> {
|
) -> HashMap<DisplayRow, DisplayRowDelta> {
|
||||||
let mut relative_rows: HashMap<u32, u32> = Default::default();
|
let mut relative_rows: HashMap<DisplayRow, DisplayRowDelta> = Default::default();
|
||||||
let Some(relative_to) = relative_to else {
|
let Some(relative_to) = relative_to else {
|
||||||
return relative_rows;
|
return relative_rows;
|
||||||
};
|
};
|
||||||
@ -1501,17 +1511,17 @@ impl EditorElement {
|
|||||||
let end = rows.end.max(relative_to);
|
let end = rows.end.max(relative_to);
|
||||||
|
|
||||||
let buffer_rows = snapshot
|
let buffer_rows = snapshot
|
||||||
.buffer_rows(start)
|
.display_rows(start)
|
||||||
.take(1 + (end - start) as usize)
|
.take(1 + end.minus(start) as usize)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let head_idx = relative_to - start;
|
let head_idx = relative_to.minus(start);
|
||||||
let mut delta = 1;
|
let mut delta = 1;
|
||||||
let mut i = head_idx + 1;
|
let mut i = head_idx + 1;
|
||||||
while i < buffer_rows.len() as u32 {
|
while i < buffer_rows.len() as u32 {
|
||||||
if buffer_rows[i as usize].is_some() {
|
if buffer_rows[i as usize].is_some() {
|
||||||
if rows.contains(&(i + start)) {
|
if rows.contains(&DisplayRow(i + start.0)) {
|
||||||
relative_rows.insert(i + start, delta);
|
relative_rows.insert(DisplayRow(i + start.0), delta);
|
||||||
}
|
}
|
||||||
delta += 1;
|
delta += 1;
|
||||||
}
|
}
|
||||||
@ -1526,8 +1536,8 @@ impl EditorElement {
|
|||||||
while i > 0 {
|
while i > 0 {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
if buffer_rows[i as usize].is_some() {
|
if buffer_rows[i as usize].is_some() {
|
||||||
if rows.contains(&(i + start)) {
|
if rows.contains(&DisplayRow(i + start.0)) {
|
||||||
relative_rows.insert(i + start, delta);
|
relative_rows.insert(DisplayRow(i + start.0), delta);
|
||||||
}
|
}
|
||||||
delta += 1;
|
delta += 1;
|
||||||
}
|
}
|
||||||
@ -1538,15 +1548,15 @@ impl EditorElement {
|
|||||||
|
|
||||||
fn layout_line_numbers(
|
fn layout_line_numbers(
|
||||||
&self,
|
&self,
|
||||||
rows: Range<u32>,
|
rows: Range<DisplayRow>,
|
||||||
buffer_rows: impl Iterator<Item = Option<u32>>,
|
buffer_rows: impl Iterator<Item = Option<DisplayRow>>,
|
||||||
active_rows: &BTreeMap<u32, bool>,
|
active_rows: &BTreeMap<DisplayRow, bool>,
|
||||||
newest_selection_head: Option<DisplayPoint>,
|
newest_selection_head: Option<DisplayPoint>,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
cx: &WindowContext,
|
cx: &WindowContext,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<Option<ShapedLine>>,
|
Vec<Option<ShapedLine>>,
|
||||||
Vec<Option<(FoldStatus, BufferRow, bool)>>,
|
Vec<Option<(FoldStatus, MultiBufferRow, bool)>>,
|
||||||
) {
|
) {
|
||||||
let editor = self.editor.read(cx);
|
let editor = self.editor.read(cx);
|
||||||
let is_singleton = editor.is_singleton(cx);
|
let is_singleton = editor.is_singleton(cx);
|
||||||
@ -1581,20 +1591,20 @@ impl EditorElement {
|
|||||||
let relative_rows = self.calculate_relative_line_numbers(snapshot, &rows, relative_to);
|
let relative_rows = self.calculate_relative_line_numbers(snapshot, &rows, relative_to);
|
||||||
|
|
||||||
for (ix, row) in buffer_rows.into_iter().enumerate() {
|
for (ix, row) in buffer_rows.into_iter().enumerate() {
|
||||||
let display_row = rows.start + ix as u32;
|
let display_row = DisplayRow(rows.start.0 + ix as u32);
|
||||||
let (active, color) = if active_rows.contains_key(&display_row) {
|
let (active, color) = if active_rows.contains_key(&display_row) {
|
||||||
(true, cx.theme().colors().editor_active_line_number)
|
(true, cx.theme().colors().editor_active_line_number)
|
||||||
} else {
|
} else {
|
||||||
(false, cx.theme().colors().editor_line_number)
|
(false, cx.theme().colors().editor_line_number)
|
||||||
};
|
};
|
||||||
if let Some(buffer_row) = row {
|
if let Some(display_row) = row {
|
||||||
if include_line_numbers {
|
if include_line_numbers {
|
||||||
line_number.clear();
|
line_number.clear();
|
||||||
let default_number = buffer_row + 1;
|
let default_number = display_row.0 + 1;
|
||||||
let number = relative_rows
|
let number = relative_rows
|
||||||
.get(&(ix as u32 + rows.start))
|
.get(&DisplayRow(ix as u32 + rows.start.0))
|
||||||
.unwrap_or(&default_number);
|
.unwrap_or(&default_number);
|
||||||
write!(&mut line_number, "{}", number).unwrap();
|
write!(&mut line_number, "{number}").unwrap();
|
||||||
let run = TextRun {
|
let run = TextRun {
|
||||||
len: line_number.len(),
|
len: line_number.len(),
|
||||||
font: self.style.text.font(),
|
font: self.style.text.font(),
|
||||||
@ -1613,9 +1623,12 @@ impl EditorElement {
|
|||||||
fold_statuses.push(
|
fold_statuses.push(
|
||||||
is_singleton
|
is_singleton
|
||||||
.then(|| {
|
.then(|| {
|
||||||
|
let multibuffer_point =
|
||||||
|
DisplayPoint::new(display_row, 0).to_point(snapshot);
|
||||||
|
let multibuffer_row = MultiBufferRow(multibuffer_point.row);
|
||||||
snapshot
|
snapshot
|
||||||
.fold_for_line(buffer_row)
|
.fold_for_line(multibuffer_row)
|
||||||
.map(|fold_status| (fold_status, buffer_row, active))
|
.map(|fold_status| (fold_status, multibuffer_row, active))
|
||||||
})
|
})
|
||||||
.flatten(),
|
.flatten(),
|
||||||
)
|
)
|
||||||
@ -1631,7 +1644,7 @@ impl EditorElement {
|
|||||||
|
|
||||||
fn layout_lines(
|
fn layout_lines(
|
||||||
&self,
|
&self,
|
||||||
rows: Range<u32>,
|
rows: Range<DisplayRow>,
|
||||||
line_number_layouts: &[Option<ShapedLine>],
|
line_number_layouts: &[Option<ShapedLine>],
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
cx: &WindowContext,
|
cx: &WindowContext,
|
||||||
@ -1650,7 +1663,7 @@ impl EditorElement {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or("", AsRef::as_ref)
|
.map_or("", AsRef::as_ref)
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.skip(rows.start as usize)
|
.skip(rows.start.0 as usize)
|
||||||
.chain(iter::repeat(""))
|
.chain(iter::repeat(""))
|
||||||
.take(rows.len());
|
.take(rows.len());
|
||||||
placeholder_lines
|
placeholder_lines
|
||||||
@ -1689,7 +1702,7 @@ impl EditorElement {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_blocks(
|
fn build_blocks(
|
||||||
&self,
|
&self,
|
||||||
rows: Range<u32>,
|
rows: Range<DisplayRow>,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
hitbox: &Hitbox,
|
hitbox: &Hitbox,
|
||||||
text_hitbox: &Hitbox,
|
text_hitbox: &Hitbox,
|
||||||
@ -1712,7 +1725,7 @@ impl EditorElement {
|
|||||||
let render_block = |block: &TransformBlock,
|
let render_block = |block: &TransformBlock,
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
block_id: usize,
|
block_id: usize,
|
||||||
block_row_start: u32,
|
block_row_start: DisplayRow,
|
||||||
cx: &mut WindowContext| {
|
cx: &mut WindowContext| {
|
||||||
let mut element = match block {
|
let mut element = match block {
|
||||||
TransformBlock::Custom(block) => {
|
TransformBlock::Custom(block) => {
|
||||||
@ -1722,7 +1735,7 @@ impl EditorElement {
|
|||||||
.to_display_point(snapshot);
|
.to_display_point(snapshot);
|
||||||
let anchor_x = text_x
|
let anchor_x = text_x
|
||||||
+ if rows.contains(&align_to.row()) {
|
+ if rows.contains(&align_to.row()) {
|
||||||
line_layouts[(align_to.row() - rows.start) as usize]
|
line_layouts[align_to.row().minus(rows.start) as usize]
|
||||||
.line
|
.line
|
||||||
.x_for_index(align_to.column() as usize)
|
.x_for_index(align_to.column() as usize)
|
||||||
} else {
|
} else {
|
||||||
@ -1788,7 +1801,7 @@ impl EditorElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let line_offset_from_top =
|
let line_offset_from_top =
|
||||||
block_row_start + *height as u32 + offset_from_excerpt_start
|
block_row_start.0 + *height as u32 + offset_from_excerpt_start
|
||||||
- snapshot
|
- snapshot
|
||||||
.scroll_anchor
|
.scroll_anchor
|
||||||
.scroll_position(&snapshot.display_snapshot)
|
.scroll_position(&snapshot.display_snapshot)
|
||||||
@ -2040,7 +2053,7 @@ impl EditorElement {
|
|||||||
let mut origin = hitbox.origin
|
let mut origin = hitbox.origin
|
||||||
+ point(
|
+ point(
|
||||||
Pixels::ZERO,
|
Pixels::ZERO,
|
||||||
block.row as f32 * line_height - scroll_pixel_position.y,
|
block.row.as_f32() * line_height - scroll_pixel_position.y,
|
||||||
);
|
);
|
||||||
if !matches!(block.style, BlockStyle::Sticky) {
|
if !matches!(block.style, BlockStyle::Sticky) {
|
||||||
origin += point(-scroll_pixel_position.x, Pixels::ZERO);
|
origin += point(-scroll_pixel_position.x, Pixels::ZERO);
|
||||||
@ -2058,7 +2071,7 @@ impl EditorElement {
|
|||||||
hitbox: &Hitbox,
|
hitbox: &Hitbox,
|
||||||
text_hitbox: &Hitbox,
|
text_hitbox: &Hitbox,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
start_row: u32,
|
start_row: DisplayRow,
|
||||||
scroll_pixel_position: gpui::Point<Pixels>,
|
scroll_pixel_position: gpui::Point<Pixels>,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
newest_selection_head: DisplayPoint,
|
newest_selection_head: DisplayPoint,
|
||||||
@ -2084,21 +2097,17 @@ impl EditorElement {
|
|||||||
|
|
||||||
let (x, y) = match position {
|
let (x, y) = match position {
|
||||||
crate::ContextMenuOrigin::EditorPoint(point) => {
|
crate::ContextMenuOrigin::EditorPoint(point) => {
|
||||||
let cursor_row_layout = &line_layouts[(point.row() - start_row) as usize].line;
|
let cursor_row_layout = &line_layouts[point.row().minus(start_row) as usize].line;
|
||||||
let x = cursor_row_layout.x_for_index(point.column() as usize)
|
let x = cursor_row_layout.x_for_index(point.column() as usize)
|
||||||
- scroll_pixel_position.x;
|
- scroll_pixel_position.x;
|
||||||
let y = (point.row() + 1) as f32 * line_height - scroll_pixel_position.y;
|
let y = point.row().next_row().as_f32() * line_height - scroll_pixel_position.y;
|
||||||
(x, y)
|
(x, y)
|
||||||
}
|
}
|
||||||
crate::ContextMenuOrigin::GutterIndicator(row) => {
|
crate::ContextMenuOrigin::GutterIndicator(row) => {
|
||||||
// Context menu was spawned via a click on a gutter. Ensure it's a bit closer to the indicator than just a plain first column of the
|
// Context menu was spawned via a click on a gutter. Ensure it's a bit closer to the indicator than just a plain first column of the
|
||||||
// text field.
|
// text field.
|
||||||
let snapshot = self.editor.update(cx, |this, cx| this.snapshot(cx));
|
|
||||||
let row = Point::new(row, 0)
|
|
||||||
.to_display_point(&snapshot.display_snapshot)
|
|
||||||
.row();
|
|
||||||
let x = -gutter_overshoot;
|
let x = -gutter_overshoot;
|
||||||
let y = (row + 1) as f32 * line_height - scroll_pixel_position.y;
|
let y = row.next_row().as_f32() * line_height - scroll_pixel_position.y;
|
||||||
(x, y)
|
(x, y)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2143,7 +2152,7 @@ impl EditorElement {
|
|||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
hitbox: &Hitbox,
|
hitbox: &Hitbox,
|
||||||
text_hitbox: &Hitbox,
|
text_hitbox: &Hitbox,
|
||||||
visible_display_row_range: Range<u32>,
|
visible_display_row_range: Range<DisplayRow>,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
scroll_pixel_position: gpui::Point<Pixels>,
|
scroll_pixel_position: gpui::Point<Pixels>,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
@ -2184,12 +2193,12 @@ impl EditorElement {
|
|||||||
|
|
||||||
// This is safe because we check on layout whether the required row is available
|
// This is safe because we check on layout whether the required row is available
|
||||||
let hovered_row_layout =
|
let hovered_row_layout =
|
||||||
&line_layouts[(position.row() - visible_display_row_range.start) as usize].line;
|
&line_layouts[position.row().minus(visible_display_row_range.start) as usize].line;
|
||||||
|
|
||||||
// Compute Hovered Point
|
// Compute Hovered Point
|
||||||
let x =
|
let x =
|
||||||
hovered_row_layout.x_for_index(position.column() as usize) - scroll_pixel_position.x;
|
hovered_row_layout.x_for_index(position.column() as usize) - scroll_pixel_position.x;
|
||||||
let y = position.row() as f32 * line_height - scroll_pixel_position.y;
|
let y = position.row().as_f32() * line_height - scroll_pixel_position.y;
|
||||||
let hovered_point = content_origin + point(x, y);
|
let hovered_point = content_origin + point(x, y);
|
||||||
|
|
||||||
let mut overall_height = Pixels::ZERO;
|
let mut overall_height = Pixels::ZERO;
|
||||||
@ -2265,10 +2274,14 @@ impl EditorElement {
|
|||||||
if let EditorMode::Full = layout.mode {
|
if let EditorMode::Full = layout.mode {
|
||||||
let mut active_rows = layout.active_rows.iter().peekable();
|
let mut active_rows = layout.active_rows.iter().peekable();
|
||||||
while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
|
while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
|
||||||
let mut end_row = *start_row;
|
let mut end_row = start_row.0;
|
||||||
while active_rows.peek().map_or(false, |r| {
|
while active_rows
|
||||||
*r.0 == end_row + 1 && r.1 == contains_non_empty_selection
|
.peek()
|
||||||
}) {
|
.map_or(false, |(active_row, has_selection)| {
|
||||||
|
active_row.0 == end_row + 1
|
||||||
|
&& *has_selection == contains_non_empty_selection
|
||||||
|
})
|
||||||
|
{
|
||||||
active_rows.next().unwrap();
|
active_rows.next().unwrap();
|
||||||
end_row += 1;
|
end_row += 1;
|
||||||
}
|
}
|
||||||
@ -2277,12 +2290,12 @@ impl EditorElement {
|
|||||||
let origin = point(
|
let origin = point(
|
||||||
layout.hitbox.origin.x,
|
layout.hitbox.origin.x,
|
||||||
layout.hitbox.origin.y
|
layout.hitbox.origin.y
|
||||||
+ (*start_row as f32 - scroll_top)
|
+ (start_row.as_f32() - scroll_top)
|
||||||
* layout.position_map.line_height,
|
* layout.position_map.line_height,
|
||||||
);
|
);
|
||||||
let size = size(
|
let size = size(
|
||||||
layout.hitbox.size.width,
|
layout.hitbox.size.width,
|
||||||
layout.position_map.line_height * (end_row - start_row + 1) as f32,
|
layout.position_map.line_height * (end_row - start_row.0 + 1) as f32,
|
||||||
);
|
);
|
||||||
let active_line_bg = cx.theme().colors().editor_active_line_background;
|
let active_line_bg = cx.theme().colors().editor_active_line_background;
|
||||||
cx.paint_quad(fill(Bounds { origin, size }, active_line_bg));
|
cx.paint_quad(fill(Bounds { origin, size }, active_line_bg));
|
||||||
@ -2290,28 +2303,28 @@ impl EditorElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut paint_highlight =
|
let mut paint_highlight =
|
||||||
|highlight_row_start: u32, highlight_row_end: u32, color| {
|
|highlight_row_start: DisplayRow, highlight_row_end: DisplayRow, color| {
|
||||||
let origin = point(
|
let origin = point(
|
||||||
layout.hitbox.origin.x,
|
layout.hitbox.origin.x,
|
||||||
layout.hitbox.origin.y
|
layout.hitbox.origin.y
|
||||||
+ (highlight_row_start as f32 - scroll_top)
|
+ (highlight_row_start.as_f32() - scroll_top)
|
||||||
* layout.position_map.line_height,
|
* layout.position_map.line_height,
|
||||||
);
|
);
|
||||||
let size = size(
|
let size = size(
|
||||||
layout.hitbox.size.width,
|
layout.hitbox.size.width,
|
||||||
layout.position_map.line_height
|
layout.position_map.line_height
|
||||||
* (highlight_row_end + 1 - highlight_row_start) as f32,
|
* highlight_row_end.next_row().minus(highlight_row_start) as f32,
|
||||||
);
|
);
|
||||||
cx.paint_quad(fill(Bounds { origin, size }, color));
|
cx.paint_quad(fill(Bounds { origin, size }, color));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut current_paint: Option<(Hsla, Range<u32>)> = None;
|
let mut current_paint: Option<(Hsla, Range<DisplayRow>)> = None;
|
||||||
for (&new_row, &new_color) in &layout.highlighted_rows {
|
for (&new_row, &new_color) in &layout.highlighted_rows {
|
||||||
match &mut current_paint {
|
match &mut current_paint {
|
||||||
Some((current_color, current_range)) => {
|
Some((current_color, current_range)) => {
|
||||||
let current_color = *current_color;
|
let current_color = *current_color;
|
||||||
let new_range_started =
|
let new_range_started = current_color != new_color
|
||||||
current_color != new_color || current_range.end + 1 != new_row;
|
|| current_range.end.next_row() != new_row;
|
||||||
if new_range_started {
|
if new_range_started {
|
||||||
paint_highlight(
|
paint_highlight(
|
||||||
current_range.start,
|
current_range.start,
|
||||||
@ -2321,7 +2334,7 @@ impl EditorElement {
|
|||||||
current_paint = Some((new_color, new_row..new_row));
|
current_paint = Some((new_color, new_row..new_row));
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
current_range.end += 1;
|
current_range.end = current_range.end.next_row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => current_paint = Some((new_color, new_row..new_row)),
|
None => current_paint = Some((new_color, new_row..new_row)),
|
||||||
@ -2494,7 +2507,7 @@ impl EditorElement {
|
|||||||
|
|
||||||
match hunk {
|
match hunk {
|
||||||
DisplayDiffHunk::Folded { display_row, .. } => {
|
DisplayDiffHunk::Folded { display_row, .. } => {
|
||||||
let start_y = *display_row as f32 * line_height - scroll_top;
|
let start_y = display_row.as_f32() * line_height - scroll_top;
|
||||||
let end_y = start_y + line_height;
|
let end_y = start_y + line_height;
|
||||||
|
|
||||||
let width = 0.275 * line_height;
|
let width = 0.275 * line_height;
|
||||||
@ -2527,8 +2540,8 @@ impl EditorElement {
|
|||||||
})
|
})
|
||||||
.unwrap_or(end_row);
|
.unwrap_or(end_row);
|
||||||
|
|
||||||
let start_y = start_row as f32 * line_height - scroll_top;
|
let start_y = start_row.as_f32() * line_height - scroll_top;
|
||||||
let end_y = end_row_in_current_excerpt as f32 * line_height - scroll_top;
|
let end_y = end_row_in_current_excerpt.as_f32() * line_height - scroll_top;
|
||||||
|
|
||||||
let width = 0.275 * line_height;
|
let width = 0.275 * line_height;
|
||||||
let highlight_origin = bounds.origin + point(-width, start_y);
|
let highlight_origin = bounds.origin + point(-width, start_y);
|
||||||
@ -2539,7 +2552,7 @@ impl EditorElement {
|
|||||||
let row = display_row_range.start;
|
let row = display_row_range.start;
|
||||||
|
|
||||||
let offset = line_height / 2.;
|
let offset = line_height / 2.;
|
||||||
let start_y = row as f32 * line_height - offset - scroll_top;
|
let start_y = row.as_f32() * line_height - offset - scroll_top;
|
||||||
let end_y = start_y + line_height;
|
let end_y = start_y + line_height;
|
||||||
|
|
||||||
let width = 0.35 * line_height;
|
let width = 0.35 * line_height;
|
||||||
@ -2648,7 +2661,7 @@ impl EditorElement {
|
|||||||
.show_whitespaces;
|
.show_whitespaces;
|
||||||
|
|
||||||
for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
|
for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
|
||||||
let row = layout.visible_display_row_range.start + ix as u32;
|
let row = DisplayRow(layout.visible_display_row_range.start.0 + ix as u32);
|
||||||
line_with_invisibles.draw(
|
line_with_invisibles.draw(
|
||||||
layout,
|
layout,
|
||||||
row,
|
row,
|
||||||
@ -2879,20 +2892,22 @@ impl EditorElement {
|
|||||||
if scrollbar_settings.git_diff {
|
if scrollbar_settings.git_diff {
|
||||||
let marker_row_ranges = snapshot
|
let marker_row_ranges = snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.git_diff_hunks_in_range(0..max_point.row)
|
.git_diff_hunks_in_range(
|
||||||
|
MultiBufferRow::MIN..MultiBufferRow::MAX,
|
||||||
|
)
|
||||||
.map(|hunk| {
|
.map(|hunk| {
|
||||||
let start_display_row =
|
let start_display_row =
|
||||||
Point::new(hunk.associated_range.start, 0)
|
MultiBufferPoint::new(hunk.associated_range.start.0, 0)
|
||||||
.to_display_point(&snapshot.display_snapshot)
|
.to_display_point(&snapshot.display_snapshot)
|
||||||
.row();
|
.row();
|
||||||
let mut end_display_row =
|
let mut end_display_row =
|
||||||
Point::new(hunk.associated_range.end, 0)
|
MultiBufferPoint::new(hunk.associated_range.end.0, 0)
|
||||||
.to_display_point(&snapshot.display_snapshot)
|
.to_display_point(&snapshot.display_snapshot)
|
||||||
.row();
|
.row();
|
||||||
if end_display_row != start_display_row {
|
if end_display_row != start_display_row {
|
||||||
end_display_row -= 1;
|
end_display_row.0 -= 1;
|
||||||
}
|
}
|
||||||
let color = match hunk.status() {
|
let color = match hunk_status(&hunk) {
|
||||||
DiffHunkStatus::Added => theme.status().created,
|
DiffHunkStatus::Added => theme.status().created,
|
||||||
DiffHunkStatus::Modified => theme.status().modified,
|
DiffHunkStatus::Modified => theme.status().modified,
|
||||||
DiffHunkStatus::Removed => theme.status().deleted,
|
DiffHunkStatus::Removed => theme.status().deleted,
|
||||||
@ -3018,7 +3033,8 @@ impl EditorElement {
|
|||||||
let row_range = if range.end.column() == 0 {
|
let row_range = if range.end.column() == 0 {
|
||||||
cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
|
cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
|
||||||
} else {
|
} else {
|
||||||
cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
|
cmp::max(range.start.row(), start_row)
|
||||||
|
..cmp::min(range.end.row().next_row(), end_row)
|
||||||
};
|
};
|
||||||
|
|
||||||
let highlighted_range = HighlightedRange {
|
let highlighted_range = HighlightedRange {
|
||||||
@ -3026,13 +3042,13 @@ impl EditorElement {
|
|||||||
line_height: layout.position_map.line_height,
|
line_height: layout.position_map.line_height,
|
||||||
corner_radius,
|
corner_radius,
|
||||||
start_y: layout.content_origin.y
|
start_y: layout.content_origin.y
|
||||||
+ row_range.start as f32 * layout.position_map.line_height
|
+ row_range.start.as_f32() * layout.position_map.line_height
|
||||||
- layout.position_map.scroll_pixel_position.y,
|
- layout.position_map.scroll_pixel_position.y,
|
||||||
lines: row_range
|
lines: row_range
|
||||||
.into_iter()
|
.iter_rows()
|
||||||
.map(|row| {
|
.map(|row| {
|
||||||
let line_layout =
|
let line_layout =
|
||||||
&layout.position_map.line_layouts[(row - start_row) as usize].line;
|
&layout.position_map.line_layouts[row.minus(start_row) as usize].line;
|
||||||
HighlightedRangeLine {
|
HighlightedRangeLine {
|
||||||
start_x: if row == range.start.row() {
|
start_x: if row == range.start.row() {
|
||||||
layout.content_origin.x
|
layout.content_origin.x
|
||||||
@ -3281,14 +3297,20 @@ impl EditorElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &WindowContext) -> Pixels {
|
fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &WindowContext) -> Pixels {
|
||||||
let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
|
let digit_count = snapshot
|
||||||
|
.max_buffer_row()
|
||||||
|
.next_row()
|
||||||
|
.as_f32()
|
||||||
|
.log10()
|
||||||
|
.floor() as usize
|
||||||
|
+ 1;
|
||||||
self.column_pixels(digit_count, cx)
|
self.column_pixels(digit_count, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint_gutter_button(
|
fn prepaint_gutter_button(
|
||||||
button: IconButton,
|
button: IconButton,
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
gutter_dimensions: &GutterDimensions,
|
gutter_dimensions: &GutterDimensions,
|
||||||
scroll_pixel_position: gpui::Point<Pixels>,
|
scroll_pixel_position: gpui::Point<Pixels>,
|
||||||
@ -3312,7 +3334,7 @@ fn prepaint_gutter_button(
|
|||||||
- blame_width;
|
- blame_width;
|
||||||
x += available_width / 2.;
|
x += available_width / 2.;
|
||||||
|
|
||||||
let mut y = row as f32 * line_height - scroll_pixel_position.y;
|
let mut y = row.as_f32() * line_height - scroll_pixel_position.y;
|
||||||
y += (line_height - indicator_size.height) / 2.;
|
y += (line_height - indicator_size.height) / 2.;
|
||||||
|
|
||||||
button.prepaint_as_root(gutter_hitbox.origin + point(x, y), available_space, cx);
|
button.prepaint_as_root(gutter_hitbox.origin + point(x, y), available_space, cx);
|
||||||
@ -3563,15 +3585,15 @@ impl LineWithInvisibles {
|
|||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
layout: &EditorLayout,
|
layout: &EditorLayout,
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
whitespace_setting: ShowWhitespaceSetting,
|
whitespace_setting: ShowWhitespaceSetting,
|
||||||
selection_ranges: &[Range<DisplayPoint>],
|
selection_ranges: &[Range<DisplayPoint>],
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
let line_height = layout.position_map.line_height;
|
let line_height = layout.position_map.line_height;
|
||||||
let line_y =
|
let line_y = line_height
|
||||||
line_height * (row as f32 - layout.position_map.scroll_pixel_position.y / line_height);
|
* (row.as_f32() - layout.position_map.scroll_pixel_position.y / line_height);
|
||||||
|
|
||||||
let line_origin =
|
let line_origin =
|
||||||
content_origin + gpui::point(-layout.position_map.scroll_pixel_position.x, line_y);
|
content_origin + gpui::point(-layout.position_map.scroll_pixel_position.x, line_y);
|
||||||
@ -3596,7 +3618,7 @@ impl LineWithInvisibles {
|
|||||||
layout: &EditorLayout,
|
layout: &EditorLayout,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
line_y: Pixels,
|
line_y: Pixels,
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
whitespace_setting: ShowWhitespaceSetting,
|
whitespace_setting: ShowWhitespaceSetting,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
@ -3806,19 +3828,20 @@ impl Element for EditorElement {
|
|||||||
let mut scroll_position = snapshot.scroll_position();
|
let mut scroll_position = snapshot.scroll_position();
|
||||||
// The scroll position is a fractional point, the whole number of which represents
|
// The scroll position is a fractional point, the whole number of which represents
|
||||||
// the top of the window in terms of display rows.
|
// the top of the window in terms of display rows.
|
||||||
let start_row = scroll_position.y as u32;
|
let start_row = DisplayRow(scroll_position.y as u32);
|
||||||
let height_in_lines = bounds.size.height / line_height;
|
let height_in_lines = bounds.size.height / line_height;
|
||||||
let max_row = snapshot.max_point().row();
|
let max_row = snapshot.max_point().row();
|
||||||
let end_row = cmp::min(
|
let end_row = cmp::min(
|
||||||
(scroll_position.y + height_in_lines).ceil() as u32,
|
(scroll_position.y + height_in_lines).ceil() as u32,
|
||||||
max_row + 1,
|
max_row.next_row().0,
|
||||||
);
|
);
|
||||||
|
let end_row = DisplayRow(end_row);
|
||||||
|
|
||||||
let buffer_rows = snapshot
|
let buffer_rows = snapshot
|
||||||
.buffer_rows(start_row)
|
.display_rows(start_row)
|
||||||
.take((start_row..end_row).len());
|
.take((start_row..end_row).len());
|
||||||
|
|
||||||
let start_anchor = if start_row == 0 {
|
let start_anchor = if start_row == Default::default() {
|
||||||
Anchor::min()
|
Anchor::min()
|
||||||
} else {
|
} else {
|
||||||
snapshot.buffer_snapshot.anchor_before(
|
snapshot.buffer_snapshot.anchor_before(
|
||||||
@ -3914,7 +3937,7 @@ impl Element for EditorElement {
|
|||||||
if let Some(newest_selection_head) = newest_selection_head {
|
if let Some(newest_selection_head) = newest_selection_head {
|
||||||
let display_row = newest_selection_head.row();
|
let display_row = newest_selection_head.row();
|
||||||
if (start_row..end_row).contains(&display_row) {
|
if (start_row..end_row).contains(&display_row) {
|
||||||
let line_layout = &line_layouts[(display_row - start_row) as usize];
|
let line_layout = &line_layouts[display_row.minus(start_row) as usize];
|
||||||
inline_blame = self.layout_inline_blame(
|
inline_blame = self.layout_inline_blame(
|
||||||
display_row,
|
display_row,
|
||||||
&snapshot.display_snapshot,
|
&snapshot.display_snapshot,
|
||||||
@ -3929,7 +3952,11 @@ impl Element for EditorElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let blamed_display_rows = self.layout_blame_entries(
|
let blamed_display_rows = self.layout_blame_entries(
|
||||||
buffer_rows,
|
buffer_rows.map(|display_row| {
|
||||||
|
display_row.map(|row| {
|
||||||
|
MultiBufferRow(DisplayPoint::new(row, 0).to_point(&snapshot).row)
|
||||||
|
})
|
||||||
|
}),
|
||||||
em_width,
|
em_width,
|
||||||
scroll_position,
|
scroll_position,
|
||||||
line_height,
|
line_height,
|
||||||
@ -3940,7 +3967,7 @@ impl Element for EditorElement {
|
|||||||
|
|
||||||
let scroll_max = point(
|
let scroll_max = point(
|
||||||
((scroll_width - text_hitbox.size.width) / em_width).max(0.0),
|
((scroll_width - text_hitbox.size.width) / em_width).max(0.0),
|
||||||
max_row as f32,
|
max_row.as_f32(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.editor.update(cx, |editor, cx| {
|
self.editor.update(cx, |editor, cx| {
|
||||||
@ -4041,7 +4068,7 @@ impl Element for EditorElement {
|
|||||||
newest_selection_head.to_point(&snapshot.display_snapshot);
|
newest_selection_head.to_point(&snapshot.display_snapshot);
|
||||||
let buffer = snapshot
|
let buffer = snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.buffer_line_for_row(newest_selection_point.row);
|
.buffer_line_for_row(MultiBufferRow(newest_selection_point.row));
|
||||||
if let Some((buffer, range)) = buffer {
|
if let Some((buffer, range)) = buffer {
|
||||||
let buffer_id = buffer.remote_id();
|
let buffer_id = buffer.remote_id();
|
||||||
let row = range.start.row;
|
let row = range.start.row;
|
||||||
@ -4263,8 +4290,6 @@ impl IntoElement for EditorElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BufferRow = u32;
|
|
||||||
|
|
||||||
pub struct EditorLayout {
|
pub struct EditorLayout {
|
||||||
position_map: Arc<PositionMap>,
|
position_map: Arc<PositionMap>,
|
||||||
hitbox: Hitbox,
|
hitbox: Hitbox,
|
||||||
@ -4275,9 +4300,9 @@ pub struct EditorLayout {
|
|||||||
scrollbar_layout: Option<ScrollbarLayout>,
|
scrollbar_layout: Option<ScrollbarLayout>,
|
||||||
mode: EditorMode,
|
mode: EditorMode,
|
||||||
wrap_guides: SmallVec<[(Pixels, bool); 2]>,
|
wrap_guides: SmallVec<[(Pixels, bool); 2]>,
|
||||||
visible_display_row_range: Range<u32>,
|
visible_display_row_range: Range<DisplayRow>,
|
||||||
active_rows: BTreeMap<u32, bool>,
|
active_rows: BTreeMap<DisplayRow, bool>,
|
||||||
highlighted_rows: BTreeMap<u32, Hsla>,
|
highlighted_rows: BTreeMap<DisplayRow, Hsla>,
|
||||||
line_numbers: Vec<Option<ShapedLine>>,
|
line_numbers: Vec<Option<ShapedLine>>,
|
||||||
display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)>,
|
display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)>,
|
||||||
blamed_display_rows: Option<Vec<AnyElement>>,
|
blamed_display_rows: Option<Vec<AnyElement>>,
|
||||||
@ -4339,7 +4364,7 @@ impl ScrollbarLayout {
|
|||||||
|
|
||||||
fn marker_quads_for_ranges(
|
fn marker_quads_for_ranges(
|
||||||
&self,
|
&self,
|
||||||
row_ranges: impl IntoIterator<Item = ColoredRange<u32>>,
|
row_ranges: impl IntoIterator<Item = ColoredRange<DisplayRow>>,
|
||||||
column: Option<usize>,
|
column: Option<usize>,
|
||||||
) -> Vec<PaintQuad> {
|
) -> Vec<PaintQuad> {
|
||||||
struct MinMax {
|
struct MinMax {
|
||||||
@ -4370,7 +4395,7 @@ impl ScrollbarLayout {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let row_to_y = |row: u32| row as f32 * self.row_height;
|
let row_to_y = |row: DisplayRow| row.as_f32() * self.row_height;
|
||||||
let mut pixel_ranges = row_ranges
|
let mut pixel_ranges = row_ranges
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|range| {
|
.map(|range| {
|
||||||
@ -4475,7 +4500,7 @@ impl PositionMap {
|
|||||||
(0, x)
|
(0, x)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut exact_unclipped = DisplayPoint::new(row, column);
|
let mut exact_unclipped = DisplayPoint::new(DisplayRow(row), column);
|
||||||
let previous_valid = self.snapshot.clip_point(exact_unclipped, Bias::Left);
|
let previous_valid = self.snapshot.clip_point(exact_unclipped, Bias::Left);
|
||||||
let next_valid = self.snapshot.clip_point(exact_unclipped, Bias::Right);
|
let next_valid = self.snapshot.clip_point(exact_unclipped, Bias::Right);
|
||||||
|
|
||||||
@ -4491,14 +4516,14 @@ impl PositionMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct BlockLayout {
|
struct BlockLayout {
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
element: AnyElement,
|
element: AnyElement,
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
style: BlockStyle,
|
style: BlockStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_line(
|
fn layout_line(
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
style: &EditorStyle,
|
style: &EditorStyle,
|
||||||
cx: &WindowContext,
|
cx: &WindowContext,
|
||||||
@ -4835,10 +4860,10 @@ mod tests {
|
|||||||
.update_window(*window, |_, cx| {
|
.update_window(*window, |_, cx| {
|
||||||
element
|
element
|
||||||
.layout_line_numbers(
|
.layout_line_numbers(
|
||||||
0..6,
|
DisplayRow(0)..DisplayRow(6),
|
||||||
(0..6).map(Some),
|
(0..6).map(DisplayRow).map(Some),
|
||||||
&Default::default(),
|
&Default::default(),
|
||||||
Some(DisplayPoint::new(0, 0)),
|
Some(DisplayPoint::new(DisplayRow(0), 0)),
|
||||||
&snapshot,
|
&snapshot,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
@ -4850,39 +4875,51 @@ mod tests {
|
|||||||
let relative_rows = window
|
let relative_rows = window
|
||||||
.update(cx, |editor, cx| {
|
.update(cx, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
element.calculate_relative_line_numbers(&snapshot, &(0..6), Some(3))
|
element.calculate_relative_line_numbers(
|
||||||
|
&snapshot,
|
||||||
|
&(DisplayRow(0)..DisplayRow(6)),
|
||||||
|
Some(DisplayRow(3)),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(relative_rows[&0], 3);
|
assert_eq!(relative_rows[&DisplayRow(0)], 3);
|
||||||
assert_eq!(relative_rows[&1], 2);
|
assert_eq!(relative_rows[&DisplayRow(1)], 2);
|
||||||
assert_eq!(relative_rows[&2], 1);
|
assert_eq!(relative_rows[&DisplayRow(2)], 1);
|
||||||
// current line has no relative number
|
// current line has no relative number
|
||||||
assert_eq!(relative_rows[&4], 1);
|
assert_eq!(relative_rows[&DisplayRow(4)], 1);
|
||||||
assert_eq!(relative_rows[&5], 2);
|
assert_eq!(relative_rows[&DisplayRow(5)], 2);
|
||||||
|
|
||||||
// works if cursor is before screen
|
// works if cursor is before screen
|
||||||
let relative_rows = window
|
let relative_rows = window
|
||||||
.update(cx, |editor, cx| {
|
.update(cx, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
element.calculate_relative_line_numbers(&snapshot, &(3..6), Some(1))
|
element.calculate_relative_line_numbers(
|
||||||
|
&snapshot,
|
||||||
|
&(DisplayRow(3)..DisplayRow(6)),
|
||||||
|
Some(DisplayRow(1)),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(relative_rows.len(), 3);
|
assert_eq!(relative_rows.len(), 3);
|
||||||
assert_eq!(relative_rows[&3], 2);
|
assert_eq!(relative_rows[&DisplayRow(3)], 2);
|
||||||
assert_eq!(relative_rows[&4], 3);
|
assert_eq!(relative_rows[&DisplayRow(4)], 3);
|
||||||
assert_eq!(relative_rows[&5], 4);
|
assert_eq!(relative_rows[&DisplayRow(5)], 4);
|
||||||
|
|
||||||
// works if cursor is after screen
|
// works if cursor is after screen
|
||||||
let relative_rows = window
|
let relative_rows = window
|
||||||
.update(cx, |editor, cx| {
|
.update(cx, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
element.calculate_relative_line_numbers(&snapshot, &(0..3), Some(6))
|
element.calculate_relative_line_numbers(
|
||||||
|
&snapshot,
|
||||||
|
&(DisplayRow(0)..DisplayRow(3)),
|
||||||
|
Some(DisplayRow(6)),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(relative_rows.len(), 3);
|
assert_eq!(relative_rows.len(), 3);
|
||||||
assert_eq!(relative_rows[&0], 5);
|
assert_eq!(relative_rows[&DisplayRow(0)], 5);
|
||||||
assert_eq!(relative_rows[&1], 4);
|
assert_eq!(relative_rows[&DisplayRow(1)], 4);
|
||||||
assert_eq!(relative_rows[&2], 3);
|
assert_eq!(relative_rows[&DisplayRow(2)], 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
@ -4918,30 +4955,39 @@ mod tests {
|
|||||||
let local_selections = &state.selections[0].1;
|
let local_selections = &state.selections[0].1;
|
||||||
assert_eq!(local_selections.len(), 3);
|
assert_eq!(local_selections.len(), 3);
|
||||||
// moves cursor back one line
|
// moves cursor back one line
|
||||||
assert_eq!(local_selections[0].head, DisplayPoint::new(0, 6));
|
assert_eq!(
|
||||||
|
local_selections[0].head,
|
||||||
|
DisplayPoint::new(DisplayRow(0), 6)
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_selections[0].range,
|
local_selections[0].range,
|
||||||
DisplayPoint::new(0, 0)..DisplayPoint::new(1, 0)
|
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(1), 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
// moves cursor back one column
|
// moves cursor back one column
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_selections[1].range,
|
local_selections[1].range,
|
||||||
DisplayPoint::new(3, 2)..DisplayPoint::new(3, 3)
|
DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(3), 3)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
local_selections[1].head,
|
||||||
|
DisplayPoint::new(DisplayRow(3), 2)
|
||||||
);
|
);
|
||||||
assert_eq!(local_selections[1].head, DisplayPoint::new(3, 2));
|
|
||||||
|
|
||||||
// leaves cursor on the max point
|
// leaves cursor on the max point
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_selections[2].range,
|
local_selections[2].range,
|
||||||
DisplayPoint::new(5, 6)..DisplayPoint::new(6, 0)
|
DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(6), 0)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
local_selections[2].head,
|
||||||
|
DisplayPoint::new(DisplayRow(6), 0)
|
||||||
);
|
);
|
||||||
assert_eq!(local_selections[2].head, DisplayPoint::new(6, 0));
|
|
||||||
|
|
||||||
// active lines does not include 1 (even though the range of the selection does)
|
// active lines does not include 1 (even though the range of the selection does)
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
state.active_rows.keys().cloned().collect::<Vec<u32>>(),
|
state.active_rows.keys().cloned().collect::<Vec<_>>(),
|
||||||
vec![0, 3, 5, 6]
|
vec![DisplayRow(0), DisplayRow(3), DisplayRow(5), DisplayRow(6)]
|
||||||
);
|
);
|
||||||
|
|
||||||
// multi-buffer support
|
// multi-buffer support
|
||||||
@ -4987,8 +5033,8 @@ mod tests {
|
|||||||
editor.cursor_shape = CursorShape::Block;
|
editor.cursor_shape = CursorShape::Block;
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([
|
s.select_display_ranges([
|
||||||
DisplayPoint::new(4, 0)..DisplayPoint::new(7, 0),
|
DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(7), 0),
|
||||||
DisplayPoint::new(10, 0)..DisplayPoint::new(13, 0),
|
DisplayPoint::new(DisplayRow(10), 0)..DisplayPoint::new(DisplayRow(13), 0),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -5004,16 +5050,22 @@ mod tests {
|
|||||||
// and doesn't allow selection to bleed through
|
// and doesn't allow selection to bleed through
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_selections[0].range,
|
local_selections[0].range,
|
||||||
DisplayPoint::new(4, 0)..DisplayPoint::new(6, 0)
|
DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(6), 0)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
local_selections[0].head,
|
||||||
|
DisplayPoint::new(DisplayRow(5), 0)
|
||||||
);
|
);
|
||||||
assert_eq!(local_selections[0].head, DisplayPoint::new(5, 0));
|
|
||||||
// moves cursor on buffer boundary back two lines
|
// moves cursor on buffer boundary back two lines
|
||||||
// and doesn't allow selection to bleed through
|
// and doesn't allow selection to bleed through
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_selections[1].range,
|
local_selections[1].range,
|
||||||
DisplayPoint::new(10, 0)..DisplayPoint::new(11, 0)
|
DisplayPoint::new(DisplayRow(10), 0)..DisplayPoint::new(DisplayRow(11), 0)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
local_selections[1].head,
|
||||||
|
DisplayPoint::new(DisplayRow(10), 0)
|
||||||
);
|
);
|
||||||
assert_eq!(local_selections[1].head, DisplayPoint::new(10, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
@ -5303,7 +5355,7 @@ fn compute_auto_height_layout(
|
|||||||
snapshot = editor.snapshot(cx);
|
snapshot = editor.snapshot(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let scroll_height = Pixels::from(snapshot.max_point().row() + 1) * line_height;
|
let scroll_height = Pixels::from(snapshot.max_point().row().next_row().0) * line_height;
|
||||||
let height = scroll_height
|
let height = scroll_height
|
||||||
.max(line_height)
|
.max(line_height)
|
||||||
.min(line_height * max_lines as f32);
|
.min(line_height * max_lines as f32);
|
||||||
|
@ -4,29 +4,29 @@ use std::ops::Range;
|
|||||||
|
|
||||||
use git::diff::{DiffHunk, DiffHunkStatus};
|
use git::diff::{DiffHunk, DiffHunkStatus};
|
||||||
use language::Point;
|
use language::Point;
|
||||||
use multi_buffer::Anchor;
|
use multi_buffer::{Anchor, MultiBufferRow};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||||
AnchorRangeExt,
|
hunk_status, AnchorRangeExt, DisplayRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum DisplayDiffHunk {
|
pub enum DisplayDiffHunk {
|
||||||
Folded {
|
Folded {
|
||||||
display_row: u32,
|
display_row: DisplayRow,
|
||||||
},
|
},
|
||||||
|
|
||||||
Unfolded {
|
Unfolded {
|
||||||
diff_base_byte_range: Range<usize>,
|
diff_base_byte_range: Range<usize>,
|
||||||
display_row_range: Range<u32>,
|
display_row_range: Range<DisplayRow>,
|
||||||
multi_buffer_range: Range<Anchor>,
|
multi_buffer_range: Range<Anchor>,
|
||||||
status: DiffHunkStatus,
|
status: DiffHunkStatus,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayDiffHunk {
|
impl DisplayDiffHunk {
|
||||||
pub fn start_display_row(&self) -> u32 {
|
pub fn start_display_row(&self) -> DisplayRow {
|
||||||
match self {
|
match self {
|
||||||
&DisplayDiffHunk::Folded { display_row } => display_row,
|
&DisplayDiffHunk::Folded { display_row } => display_row,
|
||||||
DisplayDiffHunk::Unfolded {
|
DisplayDiffHunk::Unfolded {
|
||||||
@ -35,7 +35,7 @@ impl DisplayDiffHunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_display_row(&self, display_row: u32) -> bool {
|
pub fn contains_display_row(&self, display_row: DisplayRow) -> bool {
|
||||||
let range = match self {
|
let range = match self {
|
||||||
&DisplayDiffHunk::Folded { display_row } => display_row..=display_row,
|
&DisplayDiffHunk::Folded { display_row } => display_row..=display_row,
|
||||||
|
|
||||||
@ -48,21 +48,26 @@ impl DisplayDiffHunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_hunk_to_display(hunk: &DiffHunk<u32>, snapshot: &DisplaySnapshot) -> DisplayDiffHunk {
|
pub fn diff_hunk_to_display(
|
||||||
let hunk_start_point = Point::new(hunk.associated_range.start, 0);
|
hunk: &DiffHunk<MultiBufferRow>,
|
||||||
let hunk_start_point_sub = Point::new(hunk.associated_range.start.saturating_sub(1), 0);
|
snapshot: &DisplaySnapshot,
|
||||||
|
) -> DisplayDiffHunk {
|
||||||
|
let hunk_start_point = Point::new(hunk.associated_range.start.0, 0);
|
||||||
|
let hunk_start_point_sub = Point::new(hunk.associated_range.start.0.saturating_sub(1), 0);
|
||||||
let hunk_end_point_sub = Point::new(
|
let hunk_end_point_sub = Point::new(
|
||||||
hunk.associated_range
|
hunk.associated_range
|
||||||
.end
|
.end
|
||||||
|
.0
|
||||||
.saturating_sub(1)
|
.saturating_sub(1)
|
||||||
.max(hunk.associated_range.start),
|
.max(hunk.associated_range.start.0),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let is_removal = hunk.status() == DiffHunkStatus::Removed;
|
let status = hunk_status(hunk);
|
||||||
|
let is_removal = status == DiffHunkStatus::Removed;
|
||||||
|
|
||||||
let folds_start = Point::new(hunk.associated_range.start.saturating_sub(2), 0);
|
let folds_start = Point::new(hunk.associated_range.start.0.saturating_sub(2), 0);
|
||||||
let folds_end = Point::new(hunk.associated_range.end + 2, 0);
|
let folds_end = Point::new(hunk.associated_range.end.0 + 2, 0);
|
||||||
let folds_range = folds_start..folds_end;
|
let folds_range = folds_start..folds_end;
|
||||||
|
|
||||||
let containing_fold = snapshot.folds_in_range(folds_range).find(|fold| {
|
let containing_fold = snapshot.folds_in_range(folds_range).find(|fold| {
|
||||||
@ -83,7 +88,7 @@ pub fn diff_hunk_to_display(hunk: &DiffHunk<u32>, snapshot: &DisplaySnapshot) ->
|
|||||||
let start = hunk_start_point.to_display_point(snapshot).row();
|
let start = hunk_start_point.to_display_point(snapshot).row();
|
||||||
|
|
||||||
let hunk_end_row = hunk.associated_range.end.max(hunk.associated_range.start);
|
let hunk_end_row = hunk.associated_range.end.max(hunk.associated_range.start);
|
||||||
let hunk_end_point = Point::new(hunk_end_row, 0);
|
let hunk_end_point = Point::new(hunk_end_row.0, 0);
|
||||||
|
|
||||||
let multi_buffer_start = snapshot.buffer_snapshot.anchor_after(hunk_start_point);
|
let multi_buffer_start = snapshot.buffer_snapshot.anchor_after(hunk_start_point);
|
||||||
let multi_buffer_end = snapshot.buffer_snapshot.anchor_before(hunk_end_point);
|
let multi_buffer_end = snapshot.buffer_snapshot.anchor_before(hunk_end_point);
|
||||||
@ -92,7 +97,7 @@ pub fn diff_hunk_to_display(hunk: &DiffHunk<u32>, snapshot: &DisplaySnapshot) ->
|
|||||||
DisplayDiffHunk::Unfolded {
|
DisplayDiffHunk::Unfolded {
|
||||||
display_row_range: start..end,
|
display_row_range: start..end,
|
||||||
multi_buffer_range: multi_buffer_start..multi_buffer_end,
|
multi_buffer_range: multi_buffer_start..multi_buffer_end,
|
||||||
status: hunk.status(),
|
status,
|
||||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,11 +105,11 @@ pub fn diff_hunk_to_display(hunk: &DiffHunk<u32>, snapshot: &DisplaySnapshot) ->
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::editor_tests::init_test;
|
|
||||||
use crate::Point;
|
use crate::Point;
|
||||||
|
use crate::{editor_tests::init_test, hunk_status};
|
||||||
use gpui::{Context, TestAppContext};
|
use gpui::{Context, TestAppContext};
|
||||||
use language::Capability::ReadWrite;
|
use language::Capability::ReadWrite;
|
||||||
use multi_buffer::{ExcerptRange, MultiBuffer};
|
use multi_buffer::{ExcerptRange, MultiBuffer, MultiBufferRow};
|
||||||
use project::{FakeFs, Project};
|
use project::{FakeFs, Project};
|
||||||
use unindent::Unindent;
|
use unindent::Unindent;
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
@ -257,26 +262,41 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
(DiffHunkStatus::Modified, 1..2),
|
(
|
||||||
(DiffHunkStatus::Modified, 2..3),
|
DiffHunkStatus::Modified,
|
||||||
|
MultiBufferRow(1)..MultiBufferRow(2),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DiffHunkStatus::Modified,
|
||||||
|
MultiBufferRow(2)..MultiBufferRow(3),
|
||||||
|
),
|
||||||
//TODO: Define better when and where removed hunks show up at range extremities
|
//TODO: Define better when and where removed hunks show up at range extremities
|
||||||
(DiffHunkStatus::Removed, 6..6),
|
(
|
||||||
(DiffHunkStatus::Removed, 8..8),
|
DiffHunkStatus::Removed,
|
||||||
(DiffHunkStatus::Added, 10..11),
|
MultiBufferRow(6)..MultiBufferRow(6),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DiffHunkStatus::Removed,
|
||||||
|
MultiBufferRow(8)..MultiBufferRow(8),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DiffHunkStatus::Added,
|
||||||
|
MultiBufferRow(10)..MultiBufferRow(11),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot
|
snapshot
|
||||||
.git_diff_hunks_in_range(0..12)
|
.git_diff_hunks_in_range(MultiBufferRow(0)..MultiBufferRow(12))
|
||||||
.map(|hunk| (hunk.status(), hunk.associated_range))
|
.map(|hunk| (hunk_status(&hunk), hunk.associated_range))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&expected,
|
&expected,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot
|
snapshot
|
||||||
.git_diff_hunks_in_range_rev(0..12)
|
.git_diff_hunks_in_range_rev(MultiBufferRow(0)..MultiBufferRow(12))
|
||||||
.map(|hunk| (hunk.status(), hunk.associated_range))
|
.map(|hunk| (hunk_status(&hunk), hunk.associated_range))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
expected
|
expected
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -8,6 +8,7 @@ use git::{
|
|||||||
};
|
};
|
||||||
use gpui::{Model, ModelContext, Subscription, Task};
|
use gpui::{Model, ModelContext, Subscription, Task};
|
||||||
use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
|
use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use project::{Item, Project};
|
use project::{Item, Project};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use sum_tree::SumTree;
|
use sum_tree::SumTree;
|
||||||
@ -185,7 +186,7 @@ impl GitBlame {
|
|||||||
|
|
||||||
pub fn blame_for_rows<'a>(
|
pub fn blame_for_rows<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
rows: impl 'a + IntoIterator<Item = Option<u32>>,
|
rows: impl 'a + IntoIterator<Item = Option<MultiBufferRow>>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> impl 'a + Iterator<Item = Option<BlameEntry>> {
|
) -> impl 'a + Iterator<Item = Option<BlameEntry>> {
|
||||||
self.sync(cx);
|
self.sync(cx);
|
||||||
@ -193,7 +194,7 @@ impl GitBlame {
|
|||||||
let mut cursor = self.entries.cursor::<u32>();
|
let mut cursor = self.entries.cursor::<u32>();
|
||||||
rows.into_iter().map(move |row| {
|
rows.into_iter().map(move |row| {
|
||||||
let row = row?;
|
let row = row?;
|
||||||
cursor.seek_forward(&row, Bias::Right, &());
|
cursor.seek_forward(&row.0, Bias::Right, &());
|
||||||
cursor.item()?.blame.clone()
|
cursor.item()?.blame.clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -532,7 +533,7 @@ mod tests {
|
|||||||
($blame:expr, $rows:expr, $expected:expr, $cx:expr) => {
|
($blame:expr, $rows:expr, $expected:expr, $cx:expr) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
$blame
|
$blame
|
||||||
.blame_for_rows($rows.map(Some), $cx)
|
.blame_for_rows($rows.map(MultiBufferRow).map(Some), $cx)
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
$expected
|
$expected
|
||||||
);
|
);
|
||||||
@ -597,7 +598,7 @@ mod tests {
|
|||||||
blame.update(cx, |blame, cx| {
|
blame.update(cx, |blame, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blame
|
blame
|
||||||
.blame_for_rows((0..1).map(Some), cx)
|
.blame_for_rows((0..1).map(MultiBufferRow).map(Some), cx)
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![None]
|
vec![None]
|
||||||
);
|
);
|
||||||
@ -661,7 +662,7 @@ mod tests {
|
|||||||
// All lines
|
// All lines
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blame
|
blame
|
||||||
.blame_for_rows((0..8).map(Some), cx)
|
.blame_for_rows((0..8).map(MultiBufferRow).map(Some), cx)
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
Some(blame_entry("1b1b1b", 0..1)),
|
Some(blame_entry("1b1b1b", 0..1)),
|
||||||
@ -677,7 +678,7 @@ mod tests {
|
|||||||
// Subset of lines
|
// Subset of lines
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blame
|
blame
|
||||||
.blame_for_rows((1..4).map(Some), cx)
|
.blame_for_rows((1..4).map(MultiBufferRow).map(Some), cx)
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
Some(blame_entry("0d0d0d", 1..2)),
|
Some(blame_entry("0d0d0d", 1..2)),
|
||||||
@ -688,7 +689,7 @@ mod tests {
|
|||||||
// Subset of lines, with some not displayed
|
// Subset of lines, with some not displayed
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blame
|
blame
|
||||||
.blame_for_rows(vec![Some(1), None, None], cx)
|
.blame_for_rows(vec![Some(MultiBufferRow(1)), None, None], cx)
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![Some(blame_entry("0d0d0d", 1..2)), None, None]
|
vec![Some(blame_entry("0d0d0d", 1..2)), None, None]
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
display_map::{InlayOffset, ToDisplayPoint},
|
display_map::{InlayOffset, ToDisplayPoint},
|
||||||
hover_links::{InlayHighlight, RangeInEditor},
|
hover_links::{InlayHighlight, RangeInEditor},
|
||||||
Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSettings, EditorSnapshot, EditorStyle,
|
Anchor, AnchorRangeExt, DisplayPoint, DisplayRow, Editor, EditorSettings, EditorSnapshot,
|
||||||
ExcerptId, Hover, RangeToAnchorExt,
|
EditorStyle, ExcerptId, Hover, RangeToAnchorExt,
|
||||||
};
|
};
|
||||||
use futures::{stream::FuturesUnordered, FutureExt};
|
use futures::{stream::FuturesUnordered, FutureExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@ -440,7 +440,7 @@ impl HoverState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
style: &EditorStyle,
|
style: &EditorStyle,
|
||||||
visible_rows: Range<u32>,
|
visible_rows: Range<DisplayRow>,
|
||||||
max_size: Size<Pixels>,
|
max_size: Size<Pixels>,
|
||||||
workspace: Option<WeakView<Workspace>>,
|
workspace: Option<WeakView<Workspace>>,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
|
@ -7,7 +7,9 @@ use collections::{hash_map, HashMap, HashSet};
|
|||||||
use git::diff::{DiffHunk, DiffHunkStatus};
|
use git::diff::{DiffHunk, DiffHunkStatus};
|
||||||
use gpui::{AppContext, Hsla, Model, Task, View};
|
use gpui::{AppContext, Hsla, Model, Task, View};
|
||||||
use language::Buffer;
|
use language::Buffer;
|
||||||
use multi_buffer::{Anchor, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToPoint};
|
use multi_buffer::{
|
||||||
|
Anchor, ExcerptRange, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, ToPoint,
|
||||||
|
};
|
||||||
use text::{BufferId, Point};
|
use text::{BufferId, Point};
|
||||||
use ui::{
|
use ui::{
|
||||||
div, ActiveTheme, Context as _, IntoElement, ParentElement, Styled, ViewContext, VisualContext,
|
div, ActiveTheme, Context as _, IntoElement, ParentElement, Styled, ViewContext, VisualContext,
|
||||||
@ -16,9 +18,9 @@ use util::{debug_panic, RangeExt};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
git::{diff_hunk_to_display, DisplayDiffHunk},
|
git::{diff_hunk_to_display, DisplayDiffHunk},
|
||||||
hunks_for_selections, BlockDisposition, BlockId, BlockProperties, BlockStyle, DiffRowHighlight,
|
hunk_status, hunks_for_selections, BlockDisposition, BlockId, BlockProperties, BlockStyle,
|
||||||
Editor, EditorSnapshot, ExpandAllHunkDiffs, RangeToAnchorExt, RevertSelectedHunks,
|
DiffRowHighlight, Editor, EditorSnapshot, ExpandAllHunkDiffs, RangeToAnchorExt,
|
||||||
ToDisplayPoint, ToggleHunkDiff,
|
RevertSelectedHunks, ToDisplayPoint, ToggleHunkDiff,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -90,11 +92,11 @@ impl Editor {
|
|||||||
let hunks = snapshot
|
let hunks = snapshot
|
||||||
.display_snapshot
|
.display_snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.git_diff_hunks_in_range(0..u32::MAX)
|
.git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX)
|
||||||
.filter(|hunk| {
|
.filter(|hunk| {
|
||||||
let hunk_display_row_range = Point::new(hunk.associated_range.start, 0)
|
let hunk_display_row_range = Point::new(hunk.associated_range.start.0, 0)
|
||||||
.to_display_point(&snapshot.display_snapshot)
|
.to_display_point(&snapshot.display_snapshot)
|
||||||
..Point::new(hunk.associated_range.end, 0)
|
..Point::new(hunk.associated_range.end.0, 0)
|
||||||
.to_display_point(&snapshot.display_snapshot);
|
.to_display_point(&snapshot.display_snapshot);
|
||||||
let row_range_end =
|
let row_range_end =
|
||||||
display_rows_with_expanded_hunks.get(&hunk_display_row_range.start.row());
|
display_rows_with_expanded_hunks.get(&hunk_display_row_range.start.row());
|
||||||
@ -105,7 +107,7 @@ impl Editor {
|
|||||||
|
|
||||||
fn toggle_hunks_expanded(
|
fn toggle_hunks_expanded(
|
||||||
&mut self,
|
&mut self,
|
||||||
hunks_to_toggle: Vec<DiffHunk<u32>>,
|
hunks_to_toggle: Vec<DiffHunk<MultiBufferRow>>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let previous_toggle_task = self.expanded_hunks.hunk_update_tasks.remove(&None);
|
let previous_toggle_task = self.expanded_hunks.hunk_update_tasks.remove(&None);
|
||||||
@ -176,10 +178,10 @@ impl Editor {
|
|||||||
});
|
});
|
||||||
for remaining_hunk in hunks_to_toggle {
|
for remaining_hunk in hunks_to_toggle {
|
||||||
let remaining_hunk_point_range =
|
let remaining_hunk_point_range =
|
||||||
Point::new(remaining_hunk.associated_range.start, 0)
|
Point::new(remaining_hunk.associated_range.start.0, 0)
|
||||||
..Point::new(remaining_hunk.associated_range.end, 0);
|
..Point::new(remaining_hunk.associated_range.end.0, 0);
|
||||||
hunks_to_expand.push(HunkToExpand {
|
hunks_to_expand.push(HunkToExpand {
|
||||||
status: remaining_hunk.status(),
|
status: hunk_status(&remaining_hunk),
|
||||||
multi_buffer_range: remaining_hunk_point_range
|
multi_buffer_range: remaining_hunk_point_range
|
||||||
.to_anchors(&snapshot.buffer_snapshot),
|
.to_anchors(&snapshot.buffer_snapshot),
|
||||||
diff_base_byte_range: remaining_hunk.diff_base_byte_range.clone(),
|
diff_base_byte_range: remaining_hunk.diff_base_byte_range.clone(),
|
||||||
@ -374,9 +376,10 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
let buffer_snapshot = buffer.read(cx).snapshot();
|
let mut recalculated_hunks = snapshot
|
||||||
let mut recalculated_hunks = buffer_snapshot
|
.buffer_snapshot
|
||||||
.git_diff_hunks_in_row_range(0..u32::MAX)
|
.git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX)
|
||||||
|
.filter(|hunk| hunk.buffer_id == buffer_id)
|
||||||
.fuse()
|
.fuse()
|
||||||
.peekable();
|
.peekable();
|
||||||
let mut highlights_to_remove =
|
let mut highlights_to_remove =
|
||||||
@ -402,7 +405,7 @@ impl Editor {
|
|||||||
.to_display_point(&snapshot)
|
.to_display_point(&snapshot)
|
||||||
.row();
|
.row();
|
||||||
while let Some(buffer_hunk) = recalculated_hunks.peek() {
|
while let Some(buffer_hunk) = recalculated_hunks.peek() {
|
||||||
match diff_hunk_to_display(buffer_hunk, &snapshot) {
|
match diff_hunk_to_display(&buffer_hunk, &snapshot) {
|
||||||
DisplayDiffHunk::Folded { display_row } => {
|
DisplayDiffHunk::Folded { display_row } => {
|
||||||
recalculated_hunks.next();
|
recalculated_hunks.next();
|
||||||
if !expanded_hunk.folded
|
if !expanded_hunk.folded
|
||||||
@ -441,7 +444,7 @@ impl Editor {
|
|||||||
} else {
|
} else {
|
||||||
if !expanded_hunk.folded
|
if !expanded_hunk.folded
|
||||||
&& expanded_hunk_display_range == hunk_display_range
|
&& expanded_hunk_display_range == hunk_display_range
|
||||||
&& expanded_hunk.status == buffer_hunk.status()
|
&& expanded_hunk.status == hunk_status(buffer_hunk)
|
||||||
&& expanded_hunk.diff_base_byte_range
|
&& expanded_hunk.diff_base_byte_range
|
||||||
== buffer_hunk.diff_base_byte_range
|
== buffer_hunk.diff_base_byte_range
|
||||||
{
|
{
|
||||||
@ -614,15 +617,17 @@ fn editor_with_deleted_text(
|
|||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
|
|
||||||
let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row() as u8);
|
let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row().0 as u8);
|
||||||
(editor_height, editor)
|
(editor_height, editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_diff_hunk(
|
fn buffer_diff_hunk(
|
||||||
buffer_snapshot: &MultiBufferSnapshot,
|
buffer_snapshot: &MultiBufferSnapshot,
|
||||||
row_range: Range<Point>,
|
row_range: Range<Point>,
|
||||||
) -> Option<DiffHunk<u32>> {
|
) -> Option<DiffHunk<MultiBufferRow>> {
|
||||||
let mut hunks = buffer_snapshot.git_diff_hunks_in_range(row_range.start.row..row_range.end.row);
|
let mut hunks = buffer_snapshot.git_diff_hunks_in_range(
|
||||||
|
MultiBufferRow(row_range.start.row)..MultiBufferRow(row_range.end.row),
|
||||||
|
);
|
||||||
let hunk = hunks.next()?;
|
let hunk = hunks.next()?;
|
||||||
let second_hunk = hunks.next();
|
let second_hunk = hunks.next();
|
||||||
if second_hunk.is_none() {
|
if second_hunk.is_none() {
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
//! in editor given a given motion (e.g. it handles converting a "move left" command into coordinates in editor). It is exposed mostly for use by vim crate.
|
//! in editor given a given motion (e.g. it handles converting a "move left" command into coordinates in editor). It is exposed mostly for use by vim crate.
|
||||||
|
|
||||||
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
|
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
|
||||||
use crate::{char_kind, scroll::ScrollAnchor, CharKind, EditorStyle, ToOffset, ToPoint};
|
use crate::{
|
||||||
|
char_kind, scroll::ScrollAnchor, CharKind, DisplayRow, EditorStyle, RowExt, ToOffset, ToPoint,
|
||||||
|
};
|
||||||
use gpui::{px, Pixels, WindowTextSystem};
|
use gpui::{px, Pixels, WindowTextSystem};
|
||||||
use language::Point;
|
use language::Point;
|
||||||
use multi_buffer::MultiBufferSnapshot;
|
use multi_buffer::{MultiBufferRow, MultiBufferSnapshot};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use std::{ops::Range, sync::Arc};
|
use std::{ops::Range, sync::Arc};
|
||||||
@ -35,7 +37,7 @@ pub struct TextLayoutDetails {
|
|||||||
pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {
|
pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {
|
||||||
if point.column() > 0 {
|
if point.column() > 0 {
|
||||||
*point.column_mut() -= 1;
|
*point.column_mut() -= 1;
|
||||||
} else if point.row() > 0 {
|
} else if point.row().0 > 0 {
|
||||||
*point.row_mut() -= 1;
|
*point.row_mut() -= 1;
|
||||||
*point.column_mut() = map.line_len(point.row());
|
*point.column_mut() = map.line_len(point.row());
|
||||||
}
|
}
|
||||||
@ -127,7 +129,7 @@ pub(crate) fn up_by_rows(
|
|||||||
_ => map.x_for_display_point(start, text_layout_details),
|
_ => map.x_for_display_point(start, text_layout_details),
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev_row = start.row().saturating_sub(row_count);
|
let prev_row = DisplayRow(start.row().0.saturating_sub(row_count));
|
||||||
let mut point = map.clip_point(
|
let mut point = map.clip_point(
|
||||||
DisplayPoint::new(prev_row, map.line_len(prev_row)),
|
DisplayPoint::new(prev_row, map.line_len(prev_row)),
|
||||||
Bias::Left,
|
Bias::Left,
|
||||||
@ -137,7 +139,7 @@ pub(crate) fn up_by_rows(
|
|||||||
} else if preserve_column_at_start {
|
} else if preserve_column_at_start {
|
||||||
return (start, goal);
|
return (start, goal);
|
||||||
} else {
|
} else {
|
||||||
point = DisplayPoint::new(0, 0);
|
point = DisplayPoint::new(DisplayRow(0), 0);
|
||||||
goal_x = px(0.);
|
goal_x = px(0.);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +168,7 @@ pub(crate) fn down_by_rows(
|
|||||||
_ => map.x_for_display_point(start, text_layout_details),
|
_ => map.x_for_display_point(start, text_layout_details),
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_row = start.row() + row_count;
|
let new_row = DisplayRow(start.row().0 + row_count);
|
||||||
let mut point = map.clip_point(DisplayPoint::new(new_row, 0), Bias::Right);
|
let mut point = map.clip_point(DisplayPoint::new(new_row, 0), Bias::Right);
|
||||||
if point.row() > start.row() {
|
if point.row() > start.row() {
|
||||||
*point.column_mut() = map.display_column_for_x(point.row(), goal_x, text_layout_details)
|
*point.column_mut() = map.display_column_for_x(point.row(), goal_x, text_layout_details)
|
||||||
@ -220,7 +222,9 @@ pub fn indented_line_beginning(
|
|||||||
let soft_line_start = map.clip_point(DisplayPoint::new(display_point.row(), 0), Bias::Right);
|
let soft_line_start = map.clip_point(DisplayPoint::new(display_point.row(), 0), Bias::Right);
|
||||||
let indent_start = Point::new(
|
let indent_start = Point::new(
|
||||||
point.row,
|
point.row,
|
||||||
map.buffer_snapshot.indent_size_for_line(point.row).len,
|
map.buffer_snapshot
|
||||||
|
.indent_size_for_line(MultiBufferRow(point.row))
|
||||||
|
.len,
|
||||||
)
|
)
|
||||||
.to_display_point(map);
|
.to_display_point(map);
|
||||||
let line_start = map.prev_line_boundary(point).1;
|
let line_start = map.prev_line_boundary(point).1;
|
||||||
@ -326,7 +330,7 @@ pub fn start_of_paragraph(
|
|||||||
|
|
||||||
let mut found_non_blank_line = false;
|
let mut found_non_blank_line = false;
|
||||||
for row in (0..point.row + 1).rev() {
|
for row in (0..point.row + 1).rev() {
|
||||||
let blank = map.buffer_snapshot.is_line_blank(row);
|
let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row));
|
||||||
if found_non_blank_line && blank {
|
if found_non_blank_line && blank {
|
||||||
if count <= 1 {
|
if count <= 1 {
|
||||||
return Point::new(row, 0).to_display_point(map);
|
return Point::new(row, 0).to_display_point(map);
|
||||||
@ -349,13 +353,13 @@ pub fn end_of_paragraph(
|
|||||||
mut count: usize,
|
mut count: usize,
|
||||||
) -> DisplayPoint {
|
) -> DisplayPoint {
|
||||||
let point = display_point.to_point(map);
|
let point = display_point.to_point(map);
|
||||||
if point.row == map.max_buffer_row() {
|
if point.row == map.max_buffer_row().0 {
|
||||||
return map.max_point();
|
return map.max_point();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut found_non_blank_line = false;
|
let mut found_non_blank_line = false;
|
||||||
for row in point.row..map.max_buffer_row() + 1 {
|
for row in point.row..map.max_buffer_row().next_row().0 {
|
||||||
let blank = map.buffer_snapshot.is_line_blank(row);
|
let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row));
|
||||||
if found_non_blank_line && blank {
|
if found_non_blank_line && blank {
|
||||||
if count <= 1 {
|
if count <= 1 {
|
||||||
return Point::new(row, 0).to_display_point(map);
|
return Point::new(row, 0).to_display_point(map);
|
||||||
@ -549,13 +553,16 @@ pub fn split_display_range_by_lines(
|
|||||||
|
|
||||||
let mut start = range.start;
|
let mut start = range.start;
|
||||||
// Loop over all the covered rows until the one containing the range end
|
// Loop over all the covered rows until the one containing the range end
|
||||||
for row in range.start.row()..range.end.row() {
|
for row in range.start.row().0..range.end.row().0 {
|
||||||
let row_end_column = map.line_len(row);
|
let row_end_column = map.line_len(DisplayRow(row));
|
||||||
let end = map.clip_point(DisplayPoint::new(row, row_end_column), Bias::Left);
|
let end = map.clip_point(
|
||||||
|
DisplayPoint::new(DisplayRow(row), row_end_column),
|
||||||
|
Bias::Left,
|
||||||
|
);
|
||||||
if start != end {
|
if start != end {
|
||||||
result.push(start..end);
|
result.push(start..end);
|
||||||
}
|
}
|
||||||
start = map.clip_point(DisplayPoint::new(row + 1, 0), Bias::Left);
|
start = map.clip_point(DisplayPoint::new(DisplayRow(row + 1), 0), Bias::Left);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the final range from the start of the last end to the original range end.
|
// Add the final range from the start of the last end to the original range end.
|
||||||
@ -570,7 +577,7 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
display_map::Inlay,
|
display_map::Inlay,
|
||||||
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
|
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
|
||||||
Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer,
|
Buffer, DisplayMap, DisplayRow, ExcerptRange, InlayId, MultiBuffer,
|
||||||
};
|
};
|
||||||
use gpui::{font, Context as _};
|
use gpui::{font, Context as _};
|
||||||
use language::Capability;
|
use language::Capability;
|
||||||
@ -900,126 +907,126 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
|
assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
|
||||||
|
|
||||||
let col_2_x =
|
let col_2_x = snapshot
|
||||||
snapshot.x_for_display_point(DisplayPoint::new(2, 2), &text_layout_details);
|
.x_for_display_point(DisplayPoint::new(DisplayRow(2), 2), &text_layout_details);
|
||||||
|
|
||||||
// Can't move up into the first excerpt's header
|
// Can't move up into the first excerpt's header
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
up(
|
up(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(2, 2),
|
DisplayPoint::new(DisplayRow(2), 2),
|
||||||
SelectionGoal::HorizontalPosition(col_2_x.0),
|
SelectionGoal::HorizontalPosition(col_2_x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(2, 0),
|
DisplayPoint::new(DisplayRow(2), 0),
|
||||||
SelectionGoal::HorizontalPosition(0.0)
|
SelectionGoal::HorizontalPosition(0.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
up(
|
up(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(2, 0),
|
DisplayPoint::new(DisplayRow(2), 0),
|
||||||
SelectionGoal::None,
|
SelectionGoal::None,
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(2, 0),
|
DisplayPoint::new(DisplayRow(2), 0),
|
||||||
SelectionGoal::HorizontalPosition(0.0)
|
SelectionGoal::HorizontalPosition(0.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let col_4_x =
|
let col_4_x = snapshot
|
||||||
snapshot.x_for_display_point(DisplayPoint::new(3, 4), &text_layout_details);
|
.x_for_display_point(DisplayPoint::new(DisplayRow(3), 4), &text_layout_details);
|
||||||
|
|
||||||
// Move up and down within first excerpt
|
// Move up and down within first excerpt
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
up(
|
up(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(3, 4),
|
DisplayPoint::new(DisplayRow(3), 4),
|
||||||
SelectionGoal::HorizontalPosition(col_4_x.0),
|
SelectionGoal::HorizontalPosition(col_4_x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(2, 3),
|
DisplayPoint::new(DisplayRow(2), 3),
|
||||||
SelectionGoal::HorizontalPosition(col_4_x.0)
|
SelectionGoal::HorizontalPosition(col_4_x.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
down(
|
down(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(2, 3),
|
DisplayPoint::new(DisplayRow(2), 3),
|
||||||
SelectionGoal::HorizontalPosition(col_4_x.0),
|
SelectionGoal::HorizontalPosition(col_4_x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(3, 4),
|
DisplayPoint::new(DisplayRow(3), 4),
|
||||||
SelectionGoal::HorizontalPosition(col_4_x.0)
|
SelectionGoal::HorizontalPosition(col_4_x.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let col_5_x =
|
let col_5_x = snapshot
|
||||||
snapshot.x_for_display_point(DisplayPoint::new(6, 5), &text_layout_details);
|
.x_for_display_point(DisplayPoint::new(DisplayRow(6), 5), &text_layout_details);
|
||||||
|
|
||||||
// Move up and down across second excerpt's header
|
// Move up and down across second excerpt's header
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
up(
|
up(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(6, 5),
|
DisplayPoint::new(DisplayRow(6), 5),
|
||||||
SelectionGoal::HorizontalPosition(col_5_x.0),
|
SelectionGoal::HorizontalPosition(col_5_x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(3, 4),
|
DisplayPoint::new(DisplayRow(3), 4),
|
||||||
SelectionGoal::HorizontalPosition(col_5_x.0)
|
SelectionGoal::HorizontalPosition(col_5_x.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
down(
|
down(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(3, 4),
|
DisplayPoint::new(DisplayRow(3), 4),
|
||||||
SelectionGoal::HorizontalPosition(col_5_x.0),
|
SelectionGoal::HorizontalPosition(col_5_x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(6, 5),
|
DisplayPoint::new(DisplayRow(6), 5),
|
||||||
SelectionGoal::HorizontalPosition(col_5_x.0)
|
SelectionGoal::HorizontalPosition(col_5_x.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let max_point_x =
|
let max_point_x = snapshot
|
||||||
snapshot.x_for_display_point(DisplayPoint::new(7, 2), &text_layout_details);
|
.x_for_display_point(DisplayPoint::new(DisplayRow(7), 2), &text_layout_details);
|
||||||
|
|
||||||
// Can't move down off the end
|
// Can't move down off the end
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
down(
|
down(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(7, 0),
|
DisplayPoint::new(DisplayRow(7), 0),
|
||||||
SelectionGoal::HorizontalPosition(0.0),
|
SelectionGoal::HorizontalPosition(0.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(7, 2),
|
DisplayPoint::new(DisplayRow(7), 2),
|
||||||
SelectionGoal::HorizontalPosition(max_point_x.0)
|
SelectionGoal::HorizontalPosition(max_point_x.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
down(
|
down(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
DisplayPoint::new(7, 2),
|
DisplayPoint::new(DisplayRow(7), 2),
|
||||||
SelectionGoal::HorizontalPosition(max_point_x.0),
|
SelectionGoal::HorizontalPosition(max_point_x.0),
|
||||||
false,
|
false,
|
||||||
&text_layout_details
|
&text_layout_details
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(7, 2),
|
DisplayPoint::new(DisplayRow(7), 2),
|
||||||
SelectionGoal::HorizontalPosition(max_point_x.0)
|
SelectionGoal::HorizontalPosition(max_point_x.0)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -6,8 +6,8 @@ use crate::{
|
|||||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||||
hover_popover::hide_hover,
|
hover_popover::hide_hover,
|
||||||
persistence::DB,
|
persistence::DB,
|
||||||
Anchor, DisplayPoint, Editor, EditorEvent, EditorMode, EditorSettings, InlayHintRefreshReason,
|
Anchor, DisplayPoint, DisplayRow, Editor, EditorEvent, EditorMode, EditorSettings,
|
||||||
MultiBufferSnapshot, ToPoint,
|
InlayHintRefreshReason, MultiBufferSnapshot, RowExt, ToPoint,
|
||||||
};
|
};
|
||||||
pub use autoscroll::{Autoscroll, AutoscrollStrategy};
|
pub use autoscroll::{Autoscroll, AutoscrollStrategy};
|
||||||
use gpui::{point, px, AppContext, Entity, Global, Pixels, Task, ViewContext, WindowContext};
|
use gpui::{point, px, AppContext, Entity, Global, Pixels, Task, ViewContext, WindowContext};
|
||||||
@ -48,7 +48,7 @@ impl ScrollAnchor {
|
|||||||
if self.anchor == Anchor::min() {
|
if self.anchor == Anchor::min() {
|
||||||
scroll_position.y = 0.;
|
scroll_position.y = 0.;
|
||||||
} else {
|
} else {
|
||||||
let scroll_top = self.anchor.to_display_point(snapshot).row() as f32;
|
let scroll_top = self.anchor.to_display_point(snapshot).row().as_f32();
|
||||||
scroll_position.y = scroll_top + scroll_position.y;
|
scroll_position.y = scroll_top + scroll_position.y;
|
||||||
}
|
}
|
||||||
scroll_position
|
scroll_position
|
||||||
@ -200,7 +200,7 @@ impl ScrollManager {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let scroll_top_buffer_point =
|
let scroll_top_buffer_point =
|
||||||
DisplayPoint::new(scroll_position.y as u32, 0).to_point(&map);
|
DisplayPoint::new(DisplayRow(scroll_position.y as u32), 0).to_point(&map);
|
||||||
let top_anchor = map
|
let top_anchor = map
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.anchor_at(scroll_top_buffer_point, Bias::Right);
|
.anchor_at(scroll_top_buffer_point, Bias::Right);
|
||||||
@ -210,7 +210,7 @@ impl ScrollManager {
|
|||||||
anchor: top_anchor,
|
anchor: top_anchor,
|
||||||
offset: point(
|
offset: point(
|
||||||
scroll_position.x.max(0.),
|
scroll_position.x.max(0.),
|
||||||
scroll_position.y - top_anchor.to_display_point(&map).row() as f32,
|
scroll_position.y - top_anchor.to_display_point(&map).row().as_f32(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
scroll_top_buffer_point.row,
|
scroll_top_buffer_point.row,
|
||||||
@ -472,7 +472,7 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(visible_lines) = self.visible_line_count() {
|
if let Some(visible_lines) = self.visible_line_count() {
|
||||||
if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
if newest_head.row() < DisplayRow(screen_top.row().0 + visible_lines as u32) {
|
||||||
return Ordering::Equal;
|
return Ordering::Equal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ impl Editor {
|
|||||||
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
|
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
|
||||||
|
|
||||||
let mut new_screen_top = self.selections.newest_display(cx).head();
|
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||||
*new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
|
*new_screen_top.row_mut() = new_screen_top.row().0.saturating_sub(scroll_margin_rows);
|
||||||
*new_screen_top.column_mut() = 0;
|
*new_screen_top.column_mut() = 0;
|
||||||
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||||
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||||
@ -60,7 +60,7 @@ impl Editor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut new_screen_top = self.selections.newest_display(cx).head();
|
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||||
*new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
|
*new_screen_top.row_mut() = new_screen_top.row().0.saturating_sub(visible_rows / 2);
|
||||||
*new_screen_top.column_mut() = 0;
|
*new_screen_top.column_mut() = 0;
|
||||||
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||||
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||||
@ -86,6 +86,7 @@ impl Editor {
|
|||||||
let mut new_screen_top = self.selections.newest_display(cx).head();
|
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||||
*new_screen_top.row_mut() = new_screen_top
|
*new_screen_top.row_mut() = new_screen_top
|
||||||
.row()
|
.row()
|
||||||
|
.0
|
||||||
.saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
|
.saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
|
||||||
*new_screen_top.column_mut() = 0;
|
*new_screen_top.column_mut() = 0;
|
||||||
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||||
|
@ -5,7 +5,8 @@ use gpui::{px, Bounds, Pixels, ViewContext};
|
|||||||
use language::Point;
|
use language::Point;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::ToDisplayPoint, DiffRowHighlight, Editor, EditorMode, LineWithInvisibles,
|
display_map::ToDisplayPoint, DiffRowHighlight, DisplayRow, Editor, EditorMode,
|
||||||
|
LineWithInvisibles, RowExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
@ -88,9 +89,9 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
|
let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
|
||||||
(display_map.max_point().row() as f32 - visible_lines + 1.).max(0.)
|
(display_map.max_point().row().as_f32() - visible_lines + 1.).max(0.)
|
||||||
} else {
|
} else {
|
||||||
display_map.max_point().row() as f32
|
display_map.max_point().row().as_f32()
|
||||||
};
|
};
|
||||||
if scroll_position.y > max_scroll_top {
|
if scroll_position.y > max_scroll_top {
|
||||||
scroll_position.y = max_scroll_top;
|
scroll_position.y = max_scroll_top;
|
||||||
@ -113,7 +114,7 @@ impl Editor {
|
|||||||
)
|
)
|
||||||
.first_entry()
|
.first_entry()
|
||||||
{
|
{
|
||||||
target_top = *first_highlighted_row.key() as f32;
|
target_top = first_highlighted_row.key().as_f32();
|
||||||
target_bottom = target_top + 1.;
|
target_bottom = target_top + 1.;
|
||||||
} else {
|
} else {
|
||||||
let selections = self.selections.all::<Point>(cx);
|
let selections = self.selections.all::<Point>(cx);
|
||||||
@ -122,14 +123,16 @@ impl Editor {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.head()
|
.head()
|
||||||
.to_display_point(&display_map)
|
.to_display_point(&display_map)
|
||||||
.row() as f32;
|
.row()
|
||||||
|
.as_f32();
|
||||||
target_bottom = selections
|
target_bottom = selections
|
||||||
.last()
|
.last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.head()
|
.head()
|
||||||
.to_display_point(&display_map)
|
.to_display_point(&display_map)
|
||||||
.row() as f32
|
.row()
|
||||||
+ 1.0;
|
.next_row()
|
||||||
|
.as_f32();
|
||||||
|
|
||||||
// If the selections can't all fit on screen, scroll to the newest.
|
// If the selections can't all fit on screen, scroll to the newest.
|
||||||
if autoscroll == Autoscroll::newest()
|
if autoscroll == Autoscroll::newest()
|
||||||
@ -141,7 +144,8 @@ impl Editor {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.head()
|
.head()
|
||||||
.to_display_point(&display_map)
|
.to_display_point(&display_map)
|
||||||
.row() as f32;
|
.row()
|
||||||
|
.as_f32();
|
||||||
target_top = newest_selection_top;
|
target_top = newest_selection_top;
|
||||||
target_bottom = newest_selection_top + 1.;
|
target_bottom = newest_selection_top + 1.;
|
||||||
}
|
}
|
||||||
@ -227,7 +231,7 @@ impl Editor {
|
|||||||
|
|
||||||
pub(crate) fn autoscroll_horizontally(
|
pub(crate) fn autoscroll_horizontally(
|
||||||
&mut self,
|
&mut self,
|
||||||
start_row: u32,
|
start_row: DisplayRow,
|
||||||
viewport_width: Pixels,
|
viewport_width: Pixels,
|
||||||
scroll_width: Pixels,
|
scroll_width: Pixels,
|
||||||
max_glyph_width: Pixels,
|
max_glyph_width: Pixels,
|
||||||
@ -245,16 +249,18 @@ impl Editor {
|
|||||||
target_right = px(0.);
|
target_right = px(0.);
|
||||||
for selection in selections {
|
for selection in selections {
|
||||||
let head = selection.head().to_display_point(&display_map);
|
let head = selection.head().to_display_point(&display_map);
|
||||||
if head.row() >= start_row && head.row() < start_row + layouts.len() as u32 {
|
if head.row() >= start_row
|
||||||
|
&& head.row() < DisplayRow(start_row.0 + layouts.len() as u32)
|
||||||
|
{
|
||||||
let start_column = head.column().saturating_sub(3);
|
let start_column = head.column().saturating_sub(3);
|
||||||
let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3);
|
let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3);
|
||||||
target_left = target_left.min(
|
target_left = target_left.min(
|
||||||
layouts[(head.row() - start_row) as usize]
|
layouts[head.row().minus(start_row) as usize]
|
||||||
.line
|
.line
|
||||||
.x_for_index(start_column as usize),
|
.x_for_index(start_column as usize),
|
||||||
);
|
);
|
||||||
target_right = target_right.max(
|
target_right = target_right.max(
|
||||||
layouts[(head.row() - start_row) as usize]
|
layouts[head.row().minus(start_row) as usize]
|
||||||
.line
|
.line
|
||||||
.x_for_index(end_column as usize)
|
.x_for_index(end_column as usize)
|
||||||
+ max_glyph_width,
|
+ max_glyph_width,
|
||||||
|
@ -14,7 +14,8 @@ use util::post_inc;
|
|||||||
use crate::{
|
use crate::{
|
||||||
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||||
movement::TextLayoutDetails,
|
movement::TextLayoutDetails,
|
||||||
Anchor, DisplayPoint, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, ToOffset,
|
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode,
|
||||||
|
ToOffset,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -308,7 +309,7 @@ impl SelectionsCollection {
|
|||||||
pub fn build_columnar_selection(
|
pub fn build_columnar_selection(
|
||||||
&mut self,
|
&mut self,
|
||||||
display_map: &DisplaySnapshot,
|
display_map: &DisplaySnapshot,
|
||||||
row: u32,
|
row: DisplayRow,
|
||||||
positions: &Range<Pixels>,
|
positions: &Range<Pixels>,
|
||||||
reversed: bool,
|
reversed: bool,
|
||||||
text_layout_details: &TextLayoutDetails,
|
text_layout_details: &TextLayoutDetails,
|
||||||
|
@ -81,23 +81,30 @@ pub fn editor_hunks(
|
|||||||
editor: &Editor,
|
editor: &Editor,
|
||||||
snapshot: &DisplaySnapshot,
|
snapshot: &DisplaySnapshot,
|
||||||
cx: &mut ViewContext<'_, Editor>,
|
cx: &mut ViewContext<'_, Editor>,
|
||||||
) -> Vec<(String, git::diff::DiffHunkStatus, core::ops::Range<u32>)> {
|
) -> Vec<(
|
||||||
|
String,
|
||||||
|
git::diff::DiffHunkStatus,
|
||||||
|
std::ops::Range<crate::DisplayRow>,
|
||||||
|
)> {
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use text::Point;
|
use text::Point;
|
||||||
|
|
||||||
|
use crate::hunk_status;
|
||||||
|
|
||||||
snapshot
|
snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.git_diff_hunks_in_range(0..u32::MAX)
|
.git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX)
|
||||||
.map(|hunk| {
|
.map(|hunk| {
|
||||||
let display_range = Point::new(hunk.associated_range.start, 0)
|
let display_range = Point::new(hunk.associated_range.start.0, 0)
|
||||||
.to_display_point(snapshot)
|
.to_display_point(snapshot)
|
||||||
.row()
|
.row()
|
||||||
..Point::new(hunk.associated_range.end, 0)
|
..Point::new(hunk.associated_range.end.0, 0)
|
||||||
.to_display_point(snapshot)
|
.to_display_point(snapshot)
|
||||||
.row();
|
.row();
|
||||||
let (_, buffer, _) = editor
|
let (_, buffer, _) = editor
|
||||||
.buffer()
|
.buffer()
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.excerpt_containing(Point::new(hunk.associated_range.start, 0), cx)
|
.excerpt_containing(Point::new(hunk.associated_range.start.0, 0), cx)
|
||||||
.expect("no excerpt for expanded buffer's hunk start");
|
.expect("no excerpt for expanded buffer's hunk start");
|
||||||
let diff_base = buffer
|
let diff_base = buffer
|
||||||
.read(cx)
|
.read(cx)
|
||||||
@ -105,7 +112,7 @@ pub fn editor_hunks(
|
|||||||
.expect("should have a diff base for expanded hunk")
|
.expect("should have a diff base for expanded hunk")
|
||||||
.slice(hunk.diff_base_byte_range.clone())
|
.slice(hunk.diff_base_byte_range.clone())
|
||||||
.to_string();
|
.to_string();
|
||||||
(diff_base, hunk.status(), display_range)
|
(diff_base, hunk_status(&hunk), display_range)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -115,7 +122,11 @@ pub fn expanded_hunks(
|
|||||||
editor: &Editor,
|
editor: &Editor,
|
||||||
snapshot: &DisplaySnapshot,
|
snapshot: &DisplaySnapshot,
|
||||||
cx: &mut ViewContext<'_, Editor>,
|
cx: &mut ViewContext<'_, Editor>,
|
||||||
) -> Vec<(String, git::diff::DiffHunkStatus, core::ops::Range<u32>)> {
|
) -> Vec<(
|
||||||
|
String,
|
||||||
|
git::diff::DiffHunkStatus,
|
||||||
|
std::ops::Range<crate::DisplayRow>,
|
||||||
|
)> {
|
||||||
editor
|
editor
|
||||||
.expanded_hunks
|
.expanded_hunks
|
||||||
.hunks(false)
|
.hunks(false)
|
||||||
@ -150,7 +161,9 @@ pub fn expanded_hunks(
|
|||||||
pub fn expanded_hunks_background_highlights(
|
pub fn expanded_hunks_background_highlights(
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
cx: &mut gpui::WindowContext,
|
cx: &mut gpui::WindowContext,
|
||||||
) -> Vec<std::ops::RangeInclusive<u32>> {
|
) -> Vec<std::ops::RangeInclusive<crate::DisplayRow>> {
|
||||||
|
use crate::DisplayRow;
|
||||||
|
|
||||||
let mut highlights = Vec::new();
|
let mut highlights = Vec::new();
|
||||||
|
|
||||||
let mut range_start = 0;
|
let mut range_start = 0;
|
||||||
@ -159,19 +172,19 @@ pub fn expanded_hunks_background_highlights(
|
|||||||
{
|
{
|
||||||
match previous_highlighted_row {
|
match previous_highlighted_row {
|
||||||
Some(previous_row) => {
|
Some(previous_row) => {
|
||||||
if previous_row + 1 != highlighted_row {
|
if previous_row + 1 != highlighted_row.0 {
|
||||||
highlights.push(range_start..=previous_row);
|
highlights.push(DisplayRow(range_start)..=DisplayRow(previous_row));
|
||||||
range_start = highlighted_row;
|
range_start = highlighted_row.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
range_start = highlighted_row;
|
range_start = highlighted_row.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
previous_highlighted_row = Some(highlighted_row);
|
previous_highlighted_row = Some(highlighted_row.0);
|
||||||
}
|
}
|
||||||
if let Some(previous_row) = previous_highlighted_row {
|
if let Some(previous_row) = previous_highlighted_row {
|
||||||
highlights.push(range_start..=previous_row);
|
highlights.push(DisplayRow(range_start)..=DisplayRow(previous_row));
|
||||||
}
|
}
|
||||||
|
|
||||||
highlights
|
highlights
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer,
|
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer,
|
||||||
|
RowExt,
|
||||||
};
|
};
|
||||||
use collections::BTreeMap;
|
use collections::BTreeMap;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
@ -256,7 +257,7 @@ impl EditorTestContext {
|
|||||||
let details = editor.text_layout_details(cx);
|
let details = editor.text_layout_details(cx);
|
||||||
|
|
||||||
let y = pixel_position.y
|
let y = pixel_position.y
|
||||||
+ line_height * (display_point.row() as f32 - newest_point.row() as f32);
|
+ line_height * (display_point.row().as_f32() - newest_point.row().as_f32());
|
||||||
let x = pixel_position.x + snapshot.x_for_display_point(display_point, &details)
|
let x = pixel_position.x + snapshot.x_for_display_point(display_point, &details)
|
||||||
- snapshot.x_for_display_point(newest_point, &details);
|
- snapshot.x_for_display_point(newest_point, &details);
|
||||||
Point::new(x, y)
|
Point::new(x, y)
|
||||||
|
@ -30,18 +30,6 @@ pub struct DiffHunk<T> {
|
|||||||
pub diff_base_byte_range: Range<usize>,
|
pub diff_base_byte_range: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiffHunk<u32> {
|
|
||||||
pub fn status(&self) -> DiffHunkStatus {
|
|
||||||
if self.diff_base_byte_range.is_empty() {
|
|
||||||
DiffHunkStatus::Added
|
|
||||||
} else if self.associated_range.is_empty() {
|
|
||||||
DiffHunkStatus::Removed
|
|
||||||
} else {
|
|
||||||
DiffHunkStatus::Modified
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl sum_tree::Item for DiffHunk<Anchor> {
|
impl sum_tree::Item for DiffHunk<Anchor> {
|
||||||
type Summary = DiffHunkSummary;
|
type Summary = DiffHunkSummary;
|
||||||
|
|
||||||
|
@ -352,6 +352,7 @@ mod tests {
|
|||||||
editor
|
editor
|
||||||
.highlighted_display_rows(HashSet::default(), cx)
|
.highlighted_display_rows(HashSet::default(), cx)
|
||||||
.into_keys()
|
.into_keys()
|
||||||
|
.map(|r| r.0)
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,8 @@ pub enum Capability {
|
|||||||
ReadOnly,
|
ReadOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BufferRow = u32;
|
||||||
|
|
||||||
/// An in-memory representation of a source code file, including its text,
|
/// An in-memory representation of a source code file, including its text,
|
||||||
/// syntax trees, git status, and diagnostics.
|
/// syntax trees, git status, and diagnostics.
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
@ -3104,7 +3106,7 @@ impl BufferSnapshot {
|
|||||||
/// row range.
|
/// row range.
|
||||||
pub fn git_diff_hunks_in_row_range(
|
pub fn git_diff_hunks_in_row_range(
|
||||||
&self,
|
&self,
|
||||||
range: Range<u32>,
|
range: Range<BufferRow>,
|
||||||
) -> impl '_ + Iterator<Item = git::diff::DiffHunk<u32>> {
|
) -> impl '_ + Iterator<Item = git::diff::DiffHunk<u32>> {
|
||||||
self.git_diff.hunks_in_row_range(range, self)
|
self.git_diff.hunks_in_row_range(range, self)
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ log.workspace = true
|
|||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
smallvec.workspace = true
|
smallvec.workspace = true
|
||||||
sum_tree.workspace = true
|
sum_tree.workspace = true
|
||||||
text.workspace = true
|
text.workspace = true
|
||||||
|
@ -11,9 +11,9 @@ use itertools::Itertools;
|
|||||||
use language::{
|
use language::{
|
||||||
char_kind,
|
char_kind,
|
||||||
language_settings::{language_settings, LanguageSettings},
|
language_settings::{language_settings, LanguageSettings},
|
||||||
AutoindentMode, Buffer, BufferChunks, BufferSnapshot, Capability, CharKind, Chunk, CursorShape,
|
AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharKind, Chunk,
|
||||||
DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16,
|
CursorShape, DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt,
|
||||||
Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _,
|
OffsetUtf16, Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _,
|
||||||
ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,
|
ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -100,6 +100,16 @@ pub enum Event {
|
|||||||
DiagnosticsUpdated,
|
DiagnosticsUpdated,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MultiBufferPoint = Point;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, serde::Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct MultiBufferRow(pub u32);
|
||||||
|
|
||||||
|
impl MultiBufferRow {
|
||||||
|
pub const MIN: Self = Self(0);
|
||||||
|
pub const MAX: Self = Self(u32::MAX);
|
||||||
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct History {
|
struct History {
|
||||||
next_transaction_id: TransactionId,
|
next_transaction_id: TransactionId,
|
||||||
@ -165,8 +175,7 @@ pub struct MultiBufferSnapshot {
|
|||||||
/// A boundary between [`Excerpt`]s in a [`MultiBuffer`]
|
/// A boundary between [`Excerpt`]s in a [`MultiBuffer`]
|
||||||
pub struct ExcerptBoundary {
|
pub struct ExcerptBoundary {
|
||||||
pub id: ExcerptId,
|
pub id: ExcerptId,
|
||||||
/// The row in the `MultiBuffer` where the boundary is located
|
pub row: MultiBufferRow,
|
||||||
pub row: u32,
|
|
||||||
pub buffer: BufferSnapshot,
|
pub buffer: BufferSnapshot,
|
||||||
pub range: ExcerptRange<text::Anchor>,
|
pub range: ExcerptRange<text::Anchor>,
|
||||||
/// It's possible to have multiple excerpts in the same buffer,
|
/// It's possible to have multiple excerpts in the same buffer,
|
||||||
@ -190,7 +199,7 @@ struct Excerpt {
|
|||||||
/// The range of the buffer to be shown in the excerpt
|
/// The range of the buffer to be shown in the excerpt
|
||||||
range: ExcerptRange<text::Anchor>,
|
range: ExcerptRange<text::Anchor>,
|
||||||
/// The last row in the excerpted slice of the buffer
|
/// The last row in the excerpted slice of the buffer
|
||||||
max_buffer_row: u32,
|
max_buffer_row: BufferRow,
|
||||||
/// A summary of the text in the excerpt
|
/// A summary of the text in the excerpt
|
||||||
text_summary: TextSummary,
|
text_summary: TextSummary,
|
||||||
has_trailing_newline: bool,
|
has_trailing_newline: bool,
|
||||||
@ -229,7 +238,7 @@ struct ExcerptSummary {
|
|||||||
/// The location of the last [`Excerpt`] being summarized
|
/// The location of the last [`Excerpt`] being summarized
|
||||||
excerpt_locator: Locator,
|
excerpt_locator: Locator,
|
||||||
/// The maximum row of the [`Excerpt`]s being summarized
|
/// The maximum row of the [`Excerpt`]s being summarized
|
||||||
max_buffer_row: u32,
|
max_buffer_row: MultiBufferRow,
|
||||||
text: TextSummary,
|
text: TextSummary,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2111,8 +2120,8 @@ impl MultiBufferSnapshot {
|
|||||||
self.chunks(range, false).map(|chunk| chunk.text)
|
self.chunks(range, false).map(|chunk| chunk.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_line_blank(&self, row: u32) -> bool {
|
pub fn is_line_blank(&self, row: MultiBufferRow) -> bool {
|
||||||
self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
|
self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row)))
|
||||||
.all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
|
.all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2181,7 +2190,7 @@ impl MultiBufferSnapshot {
|
|||||||
self.excerpts.summary().text.len == 0
|
self.excerpts.summary().text.len == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_buffer_row(&self) -> u32 {
|
pub fn max_buffer_row(&self) -> MultiBufferRow {
|
||||||
self.excerpts.summary().max_buffer_row
|
self.excerpts.summary().max_buffer_row
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2312,7 +2321,7 @@ impl MultiBufferSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows {
|
pub fn buffer_rows(&self, start_row: MultiBufferRow) -> MultiBufferRows {
|
||||||
let mut result = MultiBufferRows {
|
let mut result = MultiBufferRows {
|
||||||
buffer_row_range: 0..0,
|
buffer_row_range: 0..0,
|
||||||
excerpts: self.excerpts.cursor(),
|
excerpts: self.excerpts.cursor(),
|
||||||
@ -2509,7 +2518,7 @@ impl MultiBufferSnapshot {
|
|||||||
&self,
|
&self,
|
||||||
rows: impl IntoIterator<Item = u32>,
|
rows: impl IntoIterator<Item = u32>,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> BTreeMap<u32, IndentSize> {
|
) -> BTreeMap<MultiBufferRow, IndentSize> {
|
||||||
let mut result = BTreeMap::new();
|
let mut result = BTreeMap::new();
|
||||||
|
|
||||||
let mut rows_for_excerpt = Vec::new();
|
let mut rows_for_excerpt = Vec::new();
|
||||||
@ -2555,16 +2564,19 @@ impl MultiBufferSnapshot {
|
|||||||
let buffer_indents = excerpt
|
let buffer_indents = excerpt
|
||||||
.buffer
|
.buffer
|
||||||
.suggested_indents(buffer_rows, single_indent_size);
|
.suggested_indents(buffer_rows, single_indent_size);
|
||||||
let multibuffer_indents = buffer_indents
|
let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| {
|
||||||
.into_iter()
|
(
|
||||||
.map(|(row, indent)| (start_multibuffer_row + row - start_buffer_row, indent));
|
MultiBufferRow(start_multibuffer_row + row - start_buffer_row),
|
||||||
|
indent,
|
||||||
|
)
|
||||||
|
});
|
||||||
result.extend(multibuffer_indents);
|
result.extend(multibuffer_indents);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
|
pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {
|
||||||
if let Some((buffer, range)) = self.buffer_line_for_row(row) {
|
if let Some((buffer, range)) = self.buffer_line_for_row(row) {
|
||||||
let mut size = buffer.indent_size_for_line(range.start.row);
|
let mut size = buffer.indent_size_for_line(range.start.row);
|
||||||
size.len = size
|
size.len = size
|
||||||
@ -2577,9 +2589,9 @@ impl MultiBufferSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
|
pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
|
||||||
while row > 0 {
|
while row.0 > 0 {
|
||||||
row -= 1;
|
row.0 -= 1;
|
||||||
if !self.is_line_blank(row) {
|
if !self.is_line_blank(row) {
|
||||||
return Some(row);
|
return Some(row);
|
||||||
}
|
}
|
||||||
@ -2587,7 +2599,7 @@ impl MultiBufferSnapshot {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_len(&self, row: u32) -> u32 {
|
pub fn line_len(&self, row: MultiBufferRow) -> u32 {
|
||||||
if let Some((_, range)) = self.buffer_line_for_row(row) {
|
if let Some((_, range)) = self.buffer_line_for_row(row) {
|
||||||
range.end.column - range.start.column
|
range.end.column - range.start.column
|
||||||
} else {
|
} else {
|
||||||
@ -2595,15 +2607,18 @@ impl MultiBufferSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
|
pub fn buffer_line_for_row(
|
||||||
|
&self,
|
||||||
|
row: MultiBufferRow,
|
||||||
|
) -> Option<(&BufferSnapshot, Range<Point>)> {
|
||||||
let mut cursor = self.excerpts.cursor::<Point>();
|
let mut cursor = self.excerpts.cursor::<Point>();
|
||||||
let point = Point::new(row, 0);
|
let point = Point::new(row.0, 0);
|
||||||
cursor.seek(&point, Bias::Right, &());
|
cursor.seek(&point, Bias::Right, &());
|
||||||
if cursor.item().is_none() && *cursor.start() == point {
|
if cursor.item().is_none() && *cursor.start() == point {
|
||||||
cursor.prev(&());
|
cursor.prev(&());
|
||||||
}
|
}
|
||||||
if let Some(excerpt) = cursor.item() {
|
if let Some(excerpt) = cursor.item() {
|
||||||
let overshoot = row - cursor.start().row;
|
let overshoot = row.0 - cursor.start().row;
|
||||||
let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
|
let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
|
||||||
let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
|
let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
|
||||||
let buffer_row = excerpt_start.row + overshoot;
|
let buffer_row = excerpt_start.row + overshoot;
|
||||||
@ -3028,7 +3043,7 @@ impl MultiBufferSnapshot {
|
|||||||
let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
|
let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
|
||||||
let boundary = ExcerptBoundary {
|
let boundary = ExcerptBoundary {
|
||||||
id: excerpt.id,
|
id: excerpt.id,
|
||||||
row: cursor.start().1.row,
|
row: MultiBufferRow(cursor.start().1.row),
|
||||||
buffer: excerpt.buffer.clone(),
|
buffer: excerpt.buffer.clone(),
|
||||||
range: excerpt.range.clone(),
|
range: excerpt.range.clone(),
|
||||||
starts_new_buffer,
|
starts_new_buffer,
|
||||||
@ -3312,11 +3327,11 @@ impl MultiBufferSnapshot {
|
|||||||
|
|
||||||
pub fn git_diff_hunks_in_range_rev(
|
pub fn git_diff_hunks_in_range_rev(
|
||||||
&self,
|
&self,
|
||||||
row_range: Range<u32>,
|
row_range: Range<MultiBufferRow>,
|
||||||
) -> impl Iterator<Item = DiffHunk<u32>> + '_ {
|
) -> impl Iterator<Item = DiffHunk<MultiBufferRow>> + '_ {
|
||||||
let mut cursor = self.excerpts.cursor::<Point>();
|
let mut cursor = self.excerpts.cursor::<Point>();
|
||||||
|
|
||||||
cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &());
|
cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &());
|
||||||
if cursor.item().is_none() {
|
if cursor.item().is_none() {
|
||||||
cursor.prev(&());
|
cursor.prev(&());
|
||||||
}
|
}
|
||||||
@ -3325,7 +3340,7 @@ impl MultiBufferSnapshot {
|
|||||||
let excerpt = cursor.item()?;
|
let excerpt = cursor.item()?;
|
||||||
let multibuffer_start = *cursor.start();
|
let multibuffer_start = *cursor.start();
|
||||||
let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
|
let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
|
||||||
if multibuffer_start.row >= row_range.end {
|
if multibuffer_start.row >= row_range.end.0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3334,15 +3349,15 @@ impl MultiBufferSnapshot {
|
|||||||
let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
|
let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
|
||||||
let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
|
let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
|
||||||
|
|
||||||
if row_range.start > multibuffer_start.row {
|
if row_range.start.0 > multibuffer_start.row {
|
||||||
let buffer_start_point =
|
let buffer_start_point =
|
||||||
excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0);
|
excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0);
|
||||||
buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
|
buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
if row_range.end < multibuffer_end.row {
|
if row_range.end.0 < multibuffer_end.row {
|
||||||
let buffer_end_point =
|
let buffer_end_point =
|
||||||
excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0);
|
excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0);
|
||||||
buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
|
buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3363,7 +3378,7 @@ impl MultiBufferSnapshot {
|
|||||||
.saturating_sub(excerpt_start_point.row);
|
.saturating_sub(excerpt_start_point.row);
|
||||||
|
|
||||||
DiffHunk {
|
DiffHunk {
|
||||||
associated_range: start..end,
|
associated_range: MultiBufferRow(start)..MultiBufferRow(end),
|
||||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||||
buffer_range: hunk.buffer_range.clone(),
|
buffer_range: hunk.buffer_range.clone(),
|
||||||
buffer_id: hunk.buffer_id,
|
buffer_id: hunk.buffer_id,
|
||||||
@ -3379,11 +3394,11 @@ impl MultiBufferSnapshot {
|
|||||||
|
|
||||||
pub fn git_diff_hunks_in_range(
|
pub fn git_diff_hunks_in_range(
|
||||||
&self,
|
&self,
|
||||||
row_range: Range<u32>,
|
row_range: Range<MultiBufferRow>,
|
||||||
) -> impl Iterator<Item = DiffHunk<u32>> + '_ {
|
) -> impl Iterator<Item = DiffHunk<MultiBufferRow>> + '_ {
|
||||||
let mut cursor = self.excerpts.cursor::<Point>();
|
let mut cursor = self.excerpts.cursor::<Point>();
|
||||||
|
|
||||||
cursor.seek(&Point::new(row_range.start, 0), Bias::Left, &());
|
cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &());
|
||||||
|
|
||||||
std::iter::from_fn(move || {
|
std::iter::from_fn(move || {
|
||||||
let excerpt = cursor.item()?;
|
let excerpt = cursor.item()?;
|
||||||
@ -3392,25 +3407,25 @@ impl MultiBufferSnapshot {
|
|||||||
let mut buffer_start = excerpt.range.context.start;
|
let mut buffer_start = excerpt.range.context.start;
|
||||||
let mut buffer_end = excerpt.range.context.end;
|
let mut buffer_end = excerpt.range.context.end;
|
||||||
|
|
||||||
let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end) {
|
let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) {
|
||||||
cmp::Ordering::Less => {
|
cmp::Ordering::Less => {
|
||||||
let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
|
let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
|
||||||
let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
|
let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
|
||||||
|
|
||||||
if row_range.start > multibuffer_start.row {
|
if row_range.start.0 > multibuffer_start.row {
|
||||||
let buffer_start_point = excerpt_start_point
|
let buffer_start_point = excerpt_start_point
|
||||||
+ Point::new(row_range.start - multibuffer_start.row, 0);
|
+ Point::new(row_range.start.0 - multibuffer_start.row, 0);
|
||||||
buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
|
buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
if row_range.end < multibuffer_end.row {
|
if row_range.end.0 < multibuffer_end.row {
|
||||||
let buffer_end_point = excerpt_start_point
|
let buffer_end_point = excerpt_start_point
|
||||||
+ Point::new(row_range.end - multibuffer_start.row, 0);
|
+ Point::new(row_range.end.0 - multibuffer_start.row, 0);
|
||||||
buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
|
buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
|
||||||
}
|
}
|
||||||
excerpt_start_point.row..excerpt_end_point.row
|
excerpt_start_point.row..excerpt_end_point.row
|
||||||
}
|
}
|
||||||
cmp::Ordering::Equal if row_range.end == 0 => {
|
cmp::Ordering::Equal if row_range.end.0 == 0 => {
|
||||||
buffer_end = buffer_start;
|
buffer_end = buffer_start;
|
||||||
0..0
|
0..0
|
||||||
}
|
}
|
||||||
@ -3422,7 +3437,7 @@ impl MultiBufferSnapshot {
|
|||||||
.git_diff_hunks_intersecting_range(buffer_start..buffer_end)
|
.git_diff_hunks_intersecting_range(buffer_start..buffer_end)
|
||||||
.map(move |hunk| {
|
.map(move |hunk| {
|
||||||
let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 {
|
let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 {
|
||||||
0..1
|
MultiBufferRow(0)..MultiBufferRow(1)
|
||||||
} else {
|
} else {
|
||||||
let start = multibuffer_start.row
|
let start = multibuffer_start.row
|
||||||
+ hunk
|
+ hunk
|
||||||
@ -3435,7 +3450,7 @@ impl MultiBufferSnapshot {
|
|||||||
.end
|
.end
|
||||||
.min(excerpt_rows.end + 1)
|
.min(excerpt_rows.end + 1)
|
||||||
.saturating_sub(excerpt_rows.start);
|
.saturating_sub(excerpt_rows.start);
|
||||||
start..end
|
MultiBufferRow(start)..MultiBufferRow(end)
|
||||||
};
|
};
|
||||||
DiffHunk {
|
DiffHunk {
|
||||||
associated_range: buffer_range,
|
associated_range: buffer_range,
|
||||||
@ -4096,7 +4111,7 @@ impl sum_tree::Item for Excerpt {
|
|||||||
ExcerptSummary {
|
ExcerptSummary {
|
||||||
excerpt_id: self.id,
|
excerpt_id: self.id,
|
||||||
excerpt_locator: self.locator.clone(),
|
excerpt_locator: self.locator.clone(),
|
||||||
max_buffer_row: self.max_buffer_row,
|
max_buffer_row: MultiBufferRow(self.max_buffer_row),
|
||||||
text,
|
text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4198,22 +4213,22 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MultiBufferRows<'a> {
|
impl<'a> MultiBufferRows<'a> {
|
||||||
pub fn seek(&mut self, row: u32) {
|
pub fn seek(&mut self, row: MultiBufferRow) {
|
||||||
self.buffer_row_range = 0..0;
|
self.buffer_row_range = 0..0;
|
||||||
|
|
||||||
self.excerpts
|
self.excerpts
|
||||||
.seek_forward(&Point::new(row, 0), Bias::Right, &());
|
.seek_forward(&Point::new(row.0, 0), Bias::Right, &());
|
||||||
if self.excerpts.item().is_none() {
|
if self.excerpts.item().is_none() {
|
||||||
self.excerpts.prev(&());
|
self.excerpts.prev(&());
|
||||||
|
|
||||||
if self.excerpts.item().is_none() && row == 0 {
|
if self.excerpts.item().is_none() && row.0 == 0 {
|
||||||
self.buffer_row_range = 0..1;
|
self.buffer_row_range = 0..1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(excerpt) = self.excerpts.item() {
|
if let Some(excerpt) = self.excerpts.item() {
|
||||||
let overshoot = row - self.excerpts.start().row;
|
let overshoot = row.0 - self.excerpts.start().row;
|
||||||
let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
|
let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
|
||||||
self.buffer_row_range.start = excerpt_start + overshoot;
|
self.buffer_row_range.start = excerpt_start + overshoot;
|
||||||
self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
|
self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
|
||||||
@ -4546,7 +4561,7 @@ mod tests {
|
|||||||
assert_eq!(snapshot.text(), buffer.read(cx).text());
|
assert_eq!(snapshot.text(), buffer.read(cx).text());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
|
||||||
(0..buffer.read(cx).row_count())
|
(0..buffer.read(cx).row_count())
|
||||||
.map(Some)
|
.map(Some)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
@ -4557,7 +4572,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(snapshot.text(), buffer.read(cx).text());
|
assert_eq!(snapshot.text(), buffer.read(cx).text());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
|
||||||
(0..buffer.read(cx).row_count())
|
(0..buffer.read(cx).row_count())
|
||||||
.map(Some)
|
.map(Some)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
@ -4685,27 +4700,33 @@ mod tests {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
|
||||||
[Some(1), Some(2), Some(3), Some(4), Some(3)]
|
[Some(1), Some(2), Some(3), Some(4), Some(3)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(2).collect::<Vec<_>>(),
|
snapshot.buffer_rows(MultiBufferRow(2)).collect::<Vec<_>>(),
|
||||||
[Some(3), Some(4), Some(3)]
|
[Some(3), Some(4), Some(3)]
|
||||||
);
|
);
|
||||||
assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
|
assert_eq!(
|
||||||
assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
|
snapshot.buffer_rows(MultiBufferRow(4)).collect::<Vec<_>>(),
|
||||||
|
[Some(3)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.buffer_rows(MultiBufferRow(5)).collect::<Vec<_>>(),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
|
boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
|
||||||
&[
|
&[
|
||||||
(0, "bbbb\nccccc".to_string(), true),
|
(MultiBufferRow(0), "bbbb\nccccc".to_string(), true),
|
||||||
(2, "ddd\neeee".to_string(), false),
|
(MultiBufferRow(2), "ddd\neeee".to_string(), false),
|
||||||
(4, "jj".to_string(), true),
|
(MultiBufferRow(4), "jj".to_string(), true),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
|
boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
|
||||||
&[(0, "bbbb\nccccc".to_string(), true)]
|
&[(MultiBufferRow(0), "bbbb\nccccc".to_string(), true)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
|
boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
|
||||||
@ -4717,19 +4738,19 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
|
boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
|
||||||
&[(2, "ddd\neeee".to_string(), false)]
|
&[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
|
boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
|
||||||
&[(2, "ddd\neeee".to_string(), false)]
|
&[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
|
boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
|
||||||
&[(2, "ddd\neeee".to_string(), false)]
|
&[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
|
boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
|
||||||
&[(4, "jj".to_string(), true)]
|
&[(MultiBufferRow(4), "jj".to_string(), true)]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
|
boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
|
||||||
@ -4812,7 +4833,7 @@ mod tests {
|
|||||||
fn boundaries_in_range(
|
fn boundaries_in_range(
|
||||||
range: Range<Point>,
|
range: Range<Point>,
|
||||||
snapshot: &MultiBufferSnapshot,
|
snapshot: &MultiBufferSnapshot,
|
||||||
) -> Vec<(u32, String, bool)> {
|
) -> Vec<(MultiBufferRow, String, bool)> {
|
||||||
snapshot
|
snapshot
|
||||||
.excerpt_boundaries_in_range(range)
|
.excerpt_boundaries_in_range(range)
|
||||||
.map(|boundary| {
|
.map(|boundary| {
|
||||||
@ -5100,8 +5121,14 @@ mod tests {
|
|||||||
|
|
||||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||||
assert_eq!(snapshot.text(), "");
|
assert_eq!(snapshot.text(), "");
|
||||||
assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
|
assert_eq!(
|
||||||
assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
|
snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
|
||||||
|
&[Some(0)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.buffer_rows(MultiBufferRow(1)).collect::<Vec<_>>(),
|
||||||
|
&[]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
@ -5518,14 +5545,16 @@ mod tests {
|
|||||||
log::info!("MultiBuffer text: {:?}", expected_text);
|
log::info!("MultiBuffer text: {:?}", expected_text);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
|
||||||
expected_buffer_rows,
|
expected_buffer_rows,
|
||||||
);
|
);
|
||||||
|
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
let start_row = rng.gen_range(0..=expected_buffer_rows.len());
|
let start_row = rng.gen_range(0..=expected_buffer_rows.len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
|
snapshot
|
||||||
|
.buffer_rows(MultiBufferRow(start_row as u32))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
&expected_buffer_rows[start_row..],
|
&expected_buffer_rows[start_row..],
|
||||||
"buffer_rows({})",
|
"buffer_rows({})",
|
||||||
start_row
|
start_row
|
||||||
@ -5533,7 +5562,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.max_buffer_row(),
|
snapshot.max_buffer_row().0,
|
||||||
expected_buffer_rows.into_iter().flatten().max().unwrap()
|
expected_buffer_rows.into_iter().flatten().max().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -5666,7 +5695,7 @@ mod tests {
|
|||||||
|
|
||||||
for (row, line) in expected_text.split('\n').enumerate() {
|
for (row, line) in expected_text.split('\n').enumerate() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.line_len(row as u32),
|
snapshot.line_len(MultiBufferRow(row as u32)),
|
||||||
line.len() as u32,
|
line.len() as u32,
|
||||||
"line_len({}).",
|
"line_len({}).",
|
||||||
row
|
row
|
||||||
|
@ -486,6 +486,7 @@ mod tests {
|
|||||||
editor
|
editor
|
||||||
.highlighted_display_rows(HashSet::default(), cx)
|
.highlighted_display_rows(HashSet::default(), cx)
|
||||||
.into_keys()
|
.into_keys()
|
||||||
|
.map(|r| r.0)
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1090,7 +1090,7 @@ mod tests {
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use editor::{DisplayPoint, Editor};
|
use editor::{display_map::DisplayRow, DisplayPoint, Editor};
|
||||||
use gpui::{Context, Hsla, TestAppContext, VisualTestContext};
|
use gpui::{Context, Hsla, TestAppContext, VisualTestContext};
|
||||||
use language::Buffer;
|
use language::Buffer;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
@ -1157,8 +1157,8 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[
|
&[
|
||||||
DisplayPoint::new(2, 17)..DisplayPoint::new(2, 19),
|
DisplayPoint::new(DisplayRow(2), 17)..DisplayPoint::new(DisplayRow(2), 19),
|
||||||
DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),
|
DisplayPoint::new(DisplayRow(2), 43)..DisplayPoint::new(DisplayRow(2), 45),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -1172,7 +1172,7 @@ mod tests {
|
|||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),]
|
&[DisplayPoint::new(DisplayRow(2), 43)..DisplayPoint::new(DisplayRow(2), 45),]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1186,13 +1186,13 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[
|
&[
|
||||||
DisplayPoint::new(0, 24)..DisplayPoint::new(0, 26),
|
DisplayPoint::new(DisplayRow(0), 24)..DisplayPoint::new(DisplayRow(0), 26),
|
||||||
DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43),
|
DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43),
|
||||||
DisplayPoint::new(2, 71)..DisplayPoint::new(2, 73),
|
DisplayPoint::new(DisplayRow(2), 71)..DisplayPoint::new(DisplayRow(2), 73),
|
||||||
DisplayPoint::new(3, 1)..DisplayPoint::new(3, 3),
|
DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 3),
|
||||||
DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13),
|
DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13),
|
||||||
DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58),
|
DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58),
|
||||||
DisplayPoint::new(3, 60)..DisplayPoint::new(3, 62),
|
DisplayPoint::new(DisplayRow(3), 60)..DisplayPoint::new(DisplayRow(3), 62),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -1207,16 +1207,18 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[
|
&[
|
||||||
DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43),
|
DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43),
|
||||||
DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13),
|
DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13),
|
||||||
DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58),
|
DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)])
|
s.select_display_ranges([
|
||||||
|
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)
|
||||||
|
])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, cx| {
|
search_bar.update(cx, |search_bar, cx| {
|
||||||
@ -1224,7 +1226,7 @@ mod tests {
|
|||||||
search_bar.select_next_match(&SelectNextMatch, cx);
|
search_bar.select_next_match(&SelectNextMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
|
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1235,7 +1237,7 @@ mod tests {
|
|||||||
search_bar.select_next_match(&SelectNextMatch, cx);
|
search_bar.select_next_match(&SelectNextMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
|
[DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1246,7 +1248,7 @@ mod tests {
|
|||||||
search_bar.select_next_match(&SelectNextMatch, cx);
|
search_bar.select_next_match(&SelectNextMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
|
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1257,7 +1259,7 @@ mod tests {
|
|||||||
search_bar.select_next_match(&SelectNextMatch, cx);
|
search_bar.select_next_match(&SelectNextMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
|
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1268,7 +1270,7 @@ mod tests {
|
|||||||
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
|
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1279,7 +1281,7 @@ mod tests {
|
|||||||
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
|
[DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1290,7 +1292,7 @@ mod tests {
|
|||||||
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
|
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1301,7 +1303,9 @@ mod tests {
|
|||||||
// the closest match to the left.
|
// the closest match to the left.
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)])
|
s.select_display_ranges([
|
||||||
|
DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)
|
||||||
|
])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, cx| {
|
search_bar.update(cx, |search_bar, cx| {
|
||||||
@ -1309,7 +1313,7 @@ mod tests {
|
|||||||
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
|
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1320,7 +1324,9 @@ mod tests {
|
|||||||
// closest match to the right.
|
// closest match to the right.
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)])
|
s.select_display_ranges([
|
||||||
|
DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)
|
||||||
|
])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, cx| {
|
search_bar.update(cx, |search_bar, cx| {
|
||||||
@ -1328,7 +1334,7 @@ mod tests {
|
|||||||
search_bar.select_next_match(&SelectNextMatch, cx);
|
search_bar.select_next_match(&SelectNextMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
|
[DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1339,7 +1345,9 @@ mod tests {
|
|||||||
// the last match.
|
// the last match.
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(3, 60)..DisplayPoint::new(3, 60)])
|
s.select_display_ranges([
|
||||||
|
DisplayPoint::new(DisplayRow(3), 60)..DisplayPoint::new(DisplayRow(3), 60)
|
||||||
|
])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, cx| {
|
search_bar.update(cx, |search_bar, cx| {
|
||||||
@ -1347,7 +1355,7 @@ mod tests {
|
|||||||
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
|
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1358,7 +1366,9 @@ mod tests {
|
|||||||
// first match.
|
// first match.
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(3, 60)..DisplayPoint::new(3, 60)])
|
s.select_display_ranges([
|
||||||
|
DisplayPoint::new(DisplayRow(3), 60)..DisplayPoint::new(DisplayRow(3), 60)
|
||||||
|
])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, cx| {
|
search_bar.update(cx, |search_bar, cx| {
|
||||||
@ -1366,7 +1376,7 @@ mod tests {
|
|||||||
search_bar.select_next_match(&SelectNextMatch, cx);
|
search_bar.select_next_match(&SelectNextMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
|
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1377,7 +1387,9 @@ mod tests {
|
|||||||
// selects the last match.
|
// selects the last match.
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)])
|
s.select_display_ranges([
|
||||||
|
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)
|
||||||
|
])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, cx| {
|
search_bar.update(cx, |search_bar, cx| {
|
||||||
@ -1385,7 +1397,7 @@ mod tests {
|
|||||||
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
search_bar.select_prev_match(&SelectPrevMatch, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
|
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
search_bar.update(cx, |search_bar, _| {
|
search_bar.update(cx, |search_bar, _| {
|
||||||
@ -1414,7 +1426,7 @@ mod tests {
|
|||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),]
|
&[DisplayPoint::new(DisplayRow(2), 43)..DisplayPoint::new(DisplayRow(2), 45),]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1439,7 +1451,7 @@ mod tests {
|
|||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[DisplayPoint::new(0, 35)..DisplayPoint::new(0, 40),]
|
&[DisplayPoint::new(DisplayRow(0), 35)..DisplayPoint::new(DisplayRow(0), 40),]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2041,8 +2053,8 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
display_points_of(editor.all_text_background_highlights(cx)),
|
display_points_of(editor.all_text_background_highlights(cx)),
|
||||||
&[
|
&[
|
||||||
DisplayPoint::new(0, 10)..DisplayPoint::new(0, 20),
|
DisplayPoint::new(DisplayRow(0), 10)..DisplayPoint::new(DisplayRow(0), 20),
|
||||||
DisplayPoint::new(1, 9)..DisplayPoint::new(1, 19),
|
DisplayPoint::new(DisplayRow(1), 9)..DisplayPoint::new(DisplayRow(1), 19),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1688,7 +1688,7 @@ fn register_workspace_action_for_present_search<A: Action>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use editor::DisplayPoint;
|
use editor::{display_map::DisplayRow, DisplayPoint};
|
||||||
use gpui::{Action, TestAppContext, WindowHandle};
|
use gpui::{Action, TestAppContext, WindowHandle};
|
||||||
use project::FakeFs;
|
use project::FakeFs;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
@ -1730,15 +1730,15 @@ pub mod tests {
|
|||||||
.update(cx, |editor, cx| editor.all_text_background_highlights(cx)),
|
.update(cx, |editor, cx| editor.all_text_background_highlights(cx)),
|
||||||
&[
|
&[
|
||||||
(
|
(
|
||||||
DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35),
|
DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35),
|
||||||
match_background_color
|
match_background_color
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40),
|
DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40),
|
||||||
match_background_color
|
match_background_color
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9),
|
DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9),
|
||||||
match_background_color
|
match_background_color
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -1748,7 +1748,7 @@ pub mod tests {
|
|||||||
search_view
|
search_view
|
||||||
.results_editor
|
.results_editor
|
||||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35)]
|
[DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35)]
|
||||||
);
|
);
|
||||||
|
|
||||||
search_view.select_match(Direction::Next, cx);
|
search_view.select_match(Direction::Next, cx);
|
||||||
@ -1761,7 +1761,7 @@ pub mod tests {
|
|||||||
search_view
|
search_view
|
||||||
.results_editor
|
.results_editor
|
||||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40)]
|
[DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40)]
|
||||||
);
|
);
|
||||||
search_view.select_match(Direction::Next, cx);
|
search_view.select_match(Direction::Next, cx);
|
||||||
})
|
})
|
||||||
@ -1774,7 +1774,7 @@ pub mod tests {
|
|||||||
search_view
|
search_view
|
||||||
.results_editor
|
.results_editor
|
||||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9)]
|
[DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9)]
|
||||||
);
|
);
|
||||||
search_view.select_match(Direction::Next, cx);
|
search_view.select_match(Direction::Next, cx);
|
||||||
})
|
})
|
||||||
@ -1787,7 +1787,7 @@ pub mod tests {
|
|||||||
search_view
|
search_view
|
||||||
.results_editor
|
.results_editor
|
||||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35)]
|
[DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35)]
|
||||||
);
|
);
|
||||||
search_view.select_match(Direction::Prev, cx);
|
search_view.select_match(Direction::Prev, cx);
|
||||||
})
|
})
|
||||||
@ -1800,7 +1800,7 @@ pub mod tests {
|
|||||||
search_view
|
search_view
|
||||||
.results_editor
|
.results_editor
|
||||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9)]
|
[DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9)]
|
||||||
);
|
);
|
||||||
search_view.select_match(Direction::Prev, cx);
|
search_view.select_match(Direction::Prev, cx);
|
||||||
})
|
})
|
||||||
@ -1813,7 +1813,7 @@ pub mod tests {
|
|||||||
search_view
|
search_view
|
||||||
.results_editor
|
.results_editor
|
||||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||||
[DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40)]
|
[DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40)]
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -26,6 +26,7 @@ gpui.workspace = true
|
|||||||
itertools.workspace = true
|
itertools.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
multi_buffer.workspace = true
|
||||||
nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = [
|
nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = [
|
||||||
"use_tokio",
|
"use_tokio",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
use editor::{
|
use editor::{
|
||||||
display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint},
|
display_map::{DisplayRow, DisplaySnapshot, FoldPoint, ToDisplayPoint},
|
||||||
movement::{
|
movement::{
|
||||||
self, find_boundary, find_preceding_boundary_display_point, FindRange, TextLayoutDetails,
|
self, find_boundary, find_preceding_boundary_display_point, FindRange, TextLayoutDetails,
|
||||||
},
|
},
|
||||||
scroll::Autoscroll,
|
scroll::Autoscroll,
|
||||||
Anchor, Bias, DisplayPoint, ToOffset,
|
Anchor, Bias, DisplayPoint, RowExt, ToOffset,
|
||||||
};
|
};
|
||||||
use gpui::{actions, impl_actions, px, ViewContext, WindowContext};
|
use gpui::{actions, impl_actions, px, ViewContext, WindowContext};
|
||||||
use language::{char_kind, CharKind, Point, Selection, SelectionGoal};
|
use language::{char_kind, CharKind, Point, Selection, SelectionGoal};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
@ -843,7 +844,7 @@ impl Motion {
|
|||||||
selection.end = map.clip_point(selection.end, Bias::Right);
|
selection.end = map.clip_point(selection.end, Bias::Right);
|
||||||
// Don't reset the end here
|
// Don't reset the end here
|
||||||
return Some(selection.start..selection.end);
|
return Some(selection.start..selection.end);
|
||||||
} else if selection.start.row() > 0 {
|
} else if selection.start.row().0 > 0 {
|
||||||
*selection.start.row_mut() -= 1;
|
*selection.start.row_mut() -= 1;
|
||||||
*selection.start.column_mut() = map.line_len(selection.start.row());
|
*selection.start.column_mut() = map.line_len(selection.start.row());
|
||||||
selection.start = map.clip_point(selection.start, Bias::Left);
|
selection.start = map.clip_point(selection.start, Bias::Left);
|
||||||
@ -860,10 +861,10 @@ impl Motion {
|
|||||||
ignore_punctuation: _,
|
ignore_punctuation: _,
|
||||||
} = self
|
} = self
|
||||||
{
|
{
|
||||||
let start_row = selection.start.to_point(&map).row;
|
let start_row = MultiBufferRow(selection.start.to_point(&map).row);
|
||||||
if selection.end.to_point(&map).row > start_row {
|
if selection.end.to_point(&map).row > start_row.0 {
|
||||||
selection.end =
|
selection.end =
|
||||||
Point::new(start_row, map.buffer_snapshot.line_len(start_row))
|
Point::new(start_row.0, map.buffer_snapshot.line_len(start_row))
|
||||||
.to_display_point(&map)
|
.to_display_point(&map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -997,7 +998,7 @@ fn up_down_buffer_rows(
|
|||||||
map.fold_snapshot
|
map.fold_snapshot
|
||||||
.clip_point(FoldPoint::new(start.row(), 0), Bias::Left),
|
.clip_point(FoldPoint::new(start.row(), 0), Bias::Left),
|
||||||
);
|
);
|
||||||
let select_nth_wrapped_row = point.row() - begin_folded_line.row();
|
let select_nth_wrapped_row = point.row().0 - begin_folded_line.row().0;
|
||||||
|
|
||||||
let (goal_wrap, goal_x) = match goal {
|
let (goal_wrap, goal_x) = match goal {
|
||||||
SelectionGoal::WrappedHorizontalPosition((row, x)) => (row, x),
|
SelectionGoal::WrappedHorizontalPosition((row, x)) => (row, x),
|
||||||
@ -1020,7 +1021,7 @@ fn up_down_buffer_rows(
|
|||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < goal_wrap && begin_folded_line.row() < map.max_point().row() {
|
while i < goal_wrap && begin_folded_line.row() < map.max_point().row() {
|
||||||
let next_folded_line = DisplayPoint::new(begin_folded_line.row() + 1, 0);
|
let next_folded_line = DisplayPoint::new(begin_folded_line.row().next_row(), 0);
|
||||||
if map
|
if map
|
||||||
.display_point_to_fold_point(next_folded_line, Bias::Right)
|
.display_point_to_fold_point(next_folded_line, Bias::Right)
|
||||||
.row()
|
.row()
|
||||||
@ -1215,7 +1216,7 @@ fn previous_word_end(
|
|||||||
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
|
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
|
||||||
let mut point = point.to_point(map);
|
let mut point = point.to_point(map);
|
||||||
|
|
||||||
if point.column < map.buffer_snapshot.line_len(point.row) {
|
if point.column < map.buffer_snapshot.line_len(MultiBufferRow(point.row)) {
|
||||||
point.column += 1;
|
point.column += 1;
|
||||||
}
|
}
|
||||||
for _ in 0..times {
|
for _ in 0..times {
|
||||||
@ -1375,7 +1376,7 @@ fn previous_subword_end(
|
|||||||
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
|
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
|
||||||
let mut point = point.to_point(map);
|
let mut point = point.to_point(map);
|
||||||
|
|
||||||
if point.column < map.buffer_snapshot.line_len(point.row) {
|
if point.column < map.buffer_snapshot.line_len(MultiBufferRow(point.row)) {
|
||||||
point.column += 1;
|
point.column += 1;
|
||||||
}
|
}
|
||||||
for _ in 0..times {
|
for _ in 0..times {
|
||||||
@ -1497,7 +1498,7 @@ fn end_of_document(
|
|||||||
let new_row = if let Some(line) = line {
|
let new_row = if let Some(line) = line {
|
||||||
(line - 1) as u32
|
(line - 1) as u32
|
||||||
} else {
|
} else {
|
||||||
map.max_buffer_row()
|
map.max_buffer_row().0
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_point = Point::new(new_row, point.column());
|
let new_point = Point::new(new_row, point.column());
|
||||||
@ -1672,22 +1673,24 @@ fn window_top(
|
|||||||
.anchor
|
.anchor
|
||||||
.to_display_point(map);
|
.to_display_point(map);
|
||||||
|
|
||||||
if first_visible_line.row() != 0 && text_layout_details.vertical_scroll_margin as usize > times
|
if first_visible_line.row() != DisplayRow(0)
|
||||||
|
&& text_layout_details.vertical_scroll_margin as usize > times
|
||||||
{
|
{
|
||||||
times = text_layout_details.vertical_scroll_margin.ceil() as usize;
|
times = text_layout_details.vertical_scroll_margin.ceil() as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(visible_rows) = text_layout_details.visible_rows {
|
if let Some(visible_rows) = text_layout_details.visible_rows {
|
||||||
let bottom_row = first_visible_line.row() + visible_rows as u32;
|
let bottom_row = first_visible_line.row().0 + visible_rows as u32;
|
||||||
let new_row = (first_visible_line.row() + (times as u32))
|
let new_row = (first_visible_line.row().0 + (times as u32))
|
||||||
.min(bottom_row)
|
.min(bottom_row)
|
||||||
.min(map.max_point().row());
|
.min(map.max_point().row().0);
|
||||||
let new_col = point.column().min(map.line_len(first_visible_line.row()));
|
let new_col = point.column().min(map.line_len(first_visible_line.row()));
|
||||||
|
|
||||||
let new_point = DisplayPoint::new(new_row, new_col);
|
let new_point = DisplayPoint::new(DisplayRow(new_row), new_col);
|
||||||
(map.clip_point(new_point, Bias::Left), SelectionGoal::None)
|
(map.clip_point(new_point, Bias::Left), SelectionGoal::None)
|
||||||
} else {
|
} else {
|
||||||
let new_row = (first_visible_line.row() + (times as u32)).min(map.max_point().row());
|
let new_row =
|
||||||
|
DisplayRow((first_visible_line.row().0 + (times as u32)).min(map.max_point().row().0));
|
||||||
let new_col = point.column().min(map.line_len(first_visible_line.row()));
|
let new_col = point.column().min(map.line_len(first_visible_line.row()));
|
||||||
|
|
||||||
let new_point = DisplayPoint::new(new_row, new_col);
|
let new_point = DisplayPoint::new(new_row, new_col);
|
||||||
@ -1707,10 +1710,11 @@ fn window_middle(
|
|||||||
.to_display_point(map);
|
.to_display_point(map);
|
||||||
|
|
||||||
let max_visible_rows =
|
let max_visible_rows =
|
||||||
(visible_rows as u32).min(map.max_point().row() - first_visible_line.row());
|
(visible_rows as u32).min(map.max_point().row().0 - first_visible_line.row().0);
|
||||||
|
|
||||||
let new_row =
|
let new_row =
|
||||||
(first_visible_line.row() + (max_visible_rows / 2)).min(map.max_point().row());
|
(first_visible_line.row().0 + (max_visible_rows / 2)).min(map.max_point().row().0);
|
||||||
|
let new_row = DisplayRow(new_row);
|
||||||
let new_col = point.column().min(map.line_len(new_row));
|
let new_col = point.column().min(map.line_len(new_row));
|
||||||
let new_point = DisplayPoint::new(new_row, new_col);
|
let new_point = DisplayPoint::new(new_row, new_col);
|
||||||
(map.clip_point(new_point, Bias::Left), SelectionGoal::None)
|
(map.clip_point(new_point, Bias::Left), SelectionGoal::None)
|
||||||
@ -1730,18 +1734,19 @@ fn window_bottom(
|
|||||||
.scroll_anchor
|
.scroll_anchor
|
||||||
.anchor
|
.anchor
|
||||||
.to_display_point(map);
|
.to_display_point(map);
|
||||||
let bottom_row = first_visible_line.row()
|
let bottom_row = first_visible_line.row().0
|
||||||
+ (visible_rows + text_layout_details.scroll_anchor.offset.y - 1.).floor() as u32;
|
+ (visible_rows + text_layout_details.scroll_anchor.offset.y - 1.).floor() as u32;
|
||||||
if bottom_row < map.max_point().row()
|
if bottom_row < map.max_point().row().0
|
||||||
&& text_layout_details.vertical_scroll_margin as usize > times
|
&& text_layout_details.vertical_scroll_margin as usize > times
|
||||||
{
|
{
|
||||||
times = text_layout_details.vertical_scroll_margin.ceil() as usize;
|
times = text_layout_details.vertical_scroll_margin.ceil() as usize;
|
||||||
}
|
}
|
||||||
let bottom_row_capped = bottom_row.min(map.max_point().row());
|
let bottom_row_capped = bottom_row.min(map.max_point().row().0);
|
||||||
let new_row = if bottom_row_capped.saturating_sub(times as u32) < first_visible_line.row() {
|
let new_row = if bottom_row_capped.saturating_sub(times as u32) < first_visible_line.row().0
|
||||||
|
{
|
||||||
first_visible_line.row()
|
first_visible_line.row()
|
||||||
} else {
|
} else {
|
||||||
bottom_row_capped.saturating_sub(times as u32)
|
DisplayRow(bottom_row_capped.saturating_sub(times as u32))
|
||||||
};
|
};
|
||||||
let new_col = point.column().min(map.line_len(new_row));
|
let new_col = point.column().min(map.line_len(new_row));
|
||||||
let new_point = DisplayPoint::new(new_row, new_col);
|
let new_point = DisplayPoint::new(new_row, new_col);
|
||||||
|
@ -25,6 +25,7 @@ use editor::Bias;
|
|||||||
use gpui::{actions, ViewContext, WindowContext};
|
use gpui::{actions, ViewContext, WindowContext};
|
||||||
use language::{Point, SelectionGoal};
|
use language::{Point, SelectionGoal};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
@ -314,7 +315,7 @@ fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContex
|
|||||||
.collect();
|
.collect();
|
||||||
let edits = selection_start_rows.into_iter().map(|row| {
|
let edits = selection_start_rows.into_iter().map(|row| {
|
||||||
let indent = snapshot
|
let indent = snapshot
|
||||||
.indent_size_for_line(row)
|
.indent_size_for_line(MultiBufferRow(row))
|
||||||
.chars()
|
.chars()
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
let start_of_line = Point::new(row, 0);
|
let start_of_line = Point::new(row, 0);
|
||||||
@ -349,10 +350,10 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex
|
|||||||
.collect();
|
.collect();
|
||||||
let edits = selection_end_rows.into_iter().map(|row| {
|
let edits = selection_end_rows.into_iter().map(|row| {
|
||||||
let indent = snapshot
|
let indent = snapshot
|
||||||
.indent_size_for_line(row)
|
.indent_size_for_line(MultiBufferRow(row))
|
||||||
.chars()
|
.chars()
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
let end_of_line = Point::new(row, snapshot.line_len(row));
|
let end_of_line = Point::new(row, snapshot.line_len(MultiBufferRow(row)));
|
||||||
(end_of_line..end_of_line, "\n".to_string() + &indent)
|
(end_of_line..end_of_line, "\n".to_string() + &indent)
|
||||||
});
|
});
|
||||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use editor::scroll::Autoscroll;
|
use editor::scroll::Autoscroll;
|
||||||
use gpui::ViewContext;
|
use gpui::ViewContext;
|
||||||
use language::{Bias, Point};
|
use language::{Bias, Point};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -48,8 +49,10 @@ where
|
|||||||
match vim.state().mode {
|
match vim.state().mode {
|
||||||
Mode::VisualLine => {
|
Mode::VisualLine => {
|
||||||
let start = Point::new(selection.start.row, 0);
|
let start = Point::new(selection.start.row, 0);
|
||||||
let end =
|
let end = Point::new(
|
||||||
Point::new(selection.end.row, snapshot.line_len(selection.end.row));
|
selection.end.row,
|
||||||
|
snapshot.line_len(MultiBufferRow(selection.end.row)),
|
||||||
|
);
|
||||||
ranges.push(start..end);
|
ranges.push(start..end);
|
||||||
cursor_positions.push(start..start);
|
cursor_positions.push(start..start);
|
||||||
}
|
}
|
||||||
@ -71,7 +74,7 @@ where
|
|||||||
}
|
}
|
||||||
ranges.push(start..end);
|
ranges.push(start..end);
|
||||||
|
|
||||||
if end.column == snapshot.line_len(end.row) {
|
if end.column == snapshot.line_len(MultiBufferRow(end.row)) {
|
||||||
end = snapshot.clip_point(end - Point::new(0, 1), Bias::Left);
|
end = snapshot.clip_point(end - Point::new(0, 1), Bias::Left);
|
||||||
}
|
}
|
||||||
cursor_positions.push(end..end)
|
cursor_positions.push(end..end)
|
||||||
|
@ -7,6 +7,7 @@ use editor::{
|
|||||||
};
|
};
|
||||||
use gpui::WindowContext;
|
use gpui::WindowContext;
|
||||||
use language::{Point, Selection};
|
use language::{Point, Selection};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
|
|
||||||
pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
||||||
vim.stop_recording();
|
vim.stop_recording();
|
||||||
@ -29,7 +30,7 @@ pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &m
|
|||||||
if selection.is_empty()
|
if selection.is_empty()
|
||||||
&& map
|
&& map
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.line_len(selection.start.to_point(&map).row)
|
.line_len(MultiBufferRow(selection.start.to_point(&map).row))
|
||||||
== 0
|
== 0
|
||||||
{
|
{
|
||||||
selection.end = map
|
selection.end = map
|
||||||
@ -79,7 +80,7 @@ pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut Windo
|
|||||||
let mut move_selection_start_to_previous_line =
|
let mut move_selection_start_to_previous_line =
|
||||||
|map: &DisplaySnapshot, selection: &mut Selection<DisplayPoint>| {
|
|map: &DisplaySnapshot, selection: &mut Selection<DisplayPoint>| {
|
||||||
let start = selection.start.to_offset(map, Bias::Left);
|
let start = selection.start.to_offset(map, Bias::Left);
|
||||||
if selection.start.row() > 0 {
|
if selection.start.row().0 > 0 {
|
||||||
should_move_to_start.insert(selection.id);
|
should_move_to_start.insert(selection.id);
|
||||||
selection.start = (start - '\n'.len_utf8()).to_display_point(map);
|
selection.start = (start - '\n'.len_utf8()).to_display_point(map);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ use std::cmp;
|
|||||||
|
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::ToDisplayPoint, movement, scroll::Autoscroll, ClipboardSelection, DisplayPoint,
|
display_map::ToDisplayPoint, movement, scroll::Autoscroll, ClipboardSelection, DisplayPoint,
|
||||||
|
RowExt,
|
||||||
};
|
};
|
||||||
use gpui::{impl_actions, AppContext, ViewContext};
|
use gpui::{impl_actions, AppContext, ViewContext};
|
||||||
use language::{Bias, SelectionGoal};
|
use language::{Bias, SelectionGoal};
|
||||||
@ -99,13 +100,13 @@ fn paste(_: &mut Workspace, action: &Paste, cx: &mut ViewContext<Workspace>) {
|
|||||||
.map(|selection| cmp::min(selection.start.column(), selection.end.column()))
|
.map(|selection| cmp::min(selection.start.column(), selection.end.column()))
|
||||||
.min()
|
.min()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut row = current_selections.last().unwrap().end.row() + 1;
|
let mut row = current_selections.last().unwrap().end.row().next_row();
|
||||||
while i < clipboard_selections.len() {
|
while i < clipboard_selections.len() {
|
||||||
let cursor =
|
let cursor =
|
||||||
display_map.clip_point(DisplayPoint::new(row, left), Bias::Left);
|
display_map.clip_point(DisplayPoint::new(row, left), Bias::Left);
|
||||||
selections_to_process.push((cursor..cursor, false));
|
selections_to_process.push((cursor..cursor, false));
|
||||||
i += 1;
|
i += 1;
|
||||||
row += 1;
|
row.0 += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::Vim;
|
use crate::Vim;
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::ToDisplayPoint, scroll::ScrollAmount, DisplayPoint, Editor, EditorSettings,
|
display_map::{DisplayRow, ToDisplayPoint},
|
||||||
|
scroll::ScrollAmount,
|
||||||
|
DisplayPoint, Editor, EditorSettings,
|
||||||
};
|
};
|
||||||
use gpui::{actions, ViewContext};
|
use gpui::{actions, ViewContext};
|
||||||
use language::Bias;
|
use language::Bias;
|
||||||
@ -85,11 +87,13 @@ fn scroll_editor(
|
|||||||
|
|
||||||
if preserve_cursor_position {
|
if preserve_cursor_position {
|
||||||
let old_top = old_top_anchor.to_display_point(map);
|
let old_top = old_top_anchor.to_display_point(map);
|
||||||
let new_row = top.row() + selection.head().row() - old_top.row();
|
let new_row =
|
||||||
|
DisplayRow(top.row().0 + selection.head().row().0 - old_top.row().0);
|
||||||
head = map.clip_point(DisplayPoint::new(new_row, head.column()), Bias::Left)
|
head = map.clip_point(DisplayPoint::new(new_row, head.column()), Bias::Left)
|
||||||
}
|
}
|
||||||
let min_row = top.row() + vertical_scroll_margin as u32;
|
let min_row = DisplayRow(top.row().0 + vertical_scroll_margin as u32);
|
||||||
let max_row = top.row() + visible_rows - vertical_scroll_margin as u32 - 1;
|
let max_row =
|
||||||
|
DisplayRow(top.row().0 + visible_rows - vertical_scroll_margin as u32 - 1);
|
||||||
|
|
||||||
let new_head = if head.row() < min_row {
|
let new_head = if head.row() < min_row {
|
||||||
map.clip_point(DisplayPoint::new(min_row, head.column()), Bias::Left)
|
map.clip_point(DisplayPoint::new(min_row, head.column()), Bias::Left)
|
||||||
|
@ -509,7 +509,7 @@ fn parse_replace_all(query: &str) -> Replacement {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use editor::DisplayPoint;
|
use editor::{display_map::DisplayRow, DisplayPoint};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use search::BufferSearchBar;
|
use search::BufferSearchBar;
|
||||||
|
|
||||||
@ -582,7 +582,7 @@ mod test {
|
|||||||
let highlights = editor.all_text_background_highlights(cx);
|
let highlights = editor.all_text_background_highlights(cx);
|
||||||
assert_eq!(3, highlights.len());
|
assert_eq!(3, highlights.len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2),
|
DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 2),
|
||||||
highlights[0].0
|
highlights[0].0
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,7 @@ use itertools::Itertools;
|
|||||||
|
|
||||||
use gpui::{actions, impl_actions, ViewContext, WindowContext};
|
use gpui::{actions, impl_actions, ViewContext, WindowContext};
|
||||||
use language::{char_kind, BufferSnapshot, CharKind, Point, Selection};
|
use language::{char_kind, BufferSnapshot, CharKind, Point, Selection};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
@ -724,7 +725,7 @@ fn paragraph(
|
|||||||
let paragraph_end_row = paragraph_end.row();
|
let paragraph_end_row = paragraph_end.row();
|
||||||
let paragraph_ends_with_eof = paragraph_end_row == map.max_point().row();
|
let paragraph_ends_with_eof = paragraph_end_row == map.max_point().row();
|
||||||
let point = relative_to.to_point(map);
|
let point = relative_to.to_point(map);
|
||||||
let current_line_is_empty = map.buffer_snapshot.is_line_blank(point.row);
|
let current_line_is_empty = map.buffer_snapshot.is_line_blank(MultiBufferRow(point.row));
|
||||||
|
|
||||||
if around {
|
if around {
|
||||||
if paragraph_ends_with_eof {
|
if paragraph_ends_with_eof {
|
||||||
@ -733,13 +734,13 @@ fn paragraph(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let paragraph_start_row = paragraph_start.row();
|
let paragraph_start_row = paragraph_start.row();
|
||||||
if paragraph_start_row != 0 {
|
if paragraph_start_row.0 != 0 {
|
||||||
let previous_paragraph_last_line_start =
|
let previous_paragraph_last_line_start =
|
||||||
Point::new(paragraph_start_row - 1, 0).to_display_point(map);
|
Point::new(paragraph_start_row.0 - 1, 0).to_display_point(map);
|
||||||
paragraph_start = start_of_paragraph(map, previous_paragraph_last_line_start);
|
paragraph_start = start_of_paragraph(map, previous_paragraph_last_line_start);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let next_paragraph_start = Point::new(paragraph_end_row + 1, 0).to_display_point(map);
|
let next_paragraph_start = Point::new(paragraph_end_row.0 + 1, 0).to_display_point(map);
|
||||||
paragraph_end = end_of_paragraph(map, next_paragraph_start);
|
paragraph_end = end_of_paragraph(map, next_paragraph_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -756,10 +757,10 @@ pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) ->
|
|||||||
return DisplayPoint::zero();
|
return DisplayPoint::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_current_line_blank = map.buffer_snapshot.is_line_blank(point.row);
|
let is_current_line_blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(point.row));
|
||||||
|
|
||||||
for row in (0..point.row).rev() {
|
for row in (0..point.row).rev() {
|
||||||
let blank = map.buffer_snapshot.is_line_blank(row);
|
let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row));
|
||||||
if blank != is_current_line_blank {
|
if blank != is_current_line_blank {
|
||||||
return Point::new(row + 1, 0).to_display_point(map);
|
return Point::new(row + 1, 0).to_display_point(map);
|
||||||
}
|
}
|
||||||
@ -773,17 +774,20 @@ pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) ->
|
|||||||
/// The trailing newline is excluded from the paragraph.
|
/// The trailing newline is excluded from the paragraph.
|
||||||
pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint {
|
pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint {
|
||||||
let point = display_point.to_point(map);
|
let point = display_point.to_point(map);
|
||||||
if point.row == map.max_buffer_row() {
|
if point.row == map.max_buffer_row().0 {
|
||||||
return map.max_point();
|
return map.max_point();
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_current_line_blank = map.buffer_snapshot.is_line_blank(point.row);
|
let is_current_line_blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(point.row));
|
||||||
|
|
||||||
for row in point.row + 1..map.max_buffer_row() + 1 {
|
for row in point.row + 1..map.max_buffer_row().0 + 1 {
|
||||||
let blank = map.buffer_snapshot.is_line_blank(row);
|
let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row));
|
||||||
if blank != is_current_line_blank {
|
if blank != is_current_line_blank {
|
||||||
let previous_row = row - 1;
|
let previous_row = row - 1;
|
||||||
return Point::new(previous_row, map.buffer_snapshot.line_len(previous_row))
|
return Point::new(
|
||||||
|
previous_row,
|
||||||
|
map.buffer_snapshot.line_len(MultiBufferRow(previous_row)),
|
||||||
|
)
|
||||||
.to_display_point(map);
|
.to_display_point(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ mod vim_test_context;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use command_palette::CommandPalette;
|
use command_palette::CommandPalette;
|
||||||
use editor::DisplayPoint;
|
use editor::{display_map::DisplayRow, DisplayPoint};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext};
|
use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext};
|
||||||
pub use neovim_backed_binding_test_context::*;
|
pub use neovim_backed_binding_test_context::*;
|
||||||
@ -235,7 +235,7 @@ async fn test_selection_on_search(cx: &mut gpui::TestAppContext) {
|
|||||||
let highlights = editor.all_text_background_highlights(cx);
|
let highlights = editor.all_text_background_highlights(cx);
|
||||||
assert_eq!(3, highlights.len());
|
assert_eq!(3, highlights.len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2),
|
DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 2),
|
||||||
highlights[0].0
|
highlights[0].0
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ use std::time::Duration;
|
|||||||
use editor::{ClipboardSelection, Editor};
|
use editor::{ClipboardSelection, Editor};
|
||||||
use gpui::{ClipboardItem, ViewContext};
|
use gpui::{ClipboardItem, ViewContext};
|
||||||
use language::{CharKind, Point};
|
use language::{CharKind, Point};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
|
||||||
use crate::{state::Mode, UseSystemClipboard, Vim, VimSettings};
|
use crate::{state::Mode, UseSystemClipboard, Vim, VimSettings};
|
||||||
@ -74,10 +75,10 @@ fn copy_selections_content_internal(
|
|||||||
// contains a newline (so that delete works as expected). We undo that change
|
// contains a newline (so that delete works as expected). We undo that change
|
||||||
// here.
|
// here.
|
||||||
let is_last_line = linewise
|
let is_last_line = linewise
|
||||||
&& end.row == buffer.max_buffer_row()
|
&& end.row == buffer.max_buffer_row().0
|
||||||
&& buffer.max_point().column > 0
|
&& buffer.max_point().column > 0
|
||||||
&& start.row < buffer.max_buffer_row()
|
&& start.row < buffer.max_buffer_row().0
|
||||||
&& start == Point::new(start.row, buffer.line_len(start.row));
|
&& start == Point::new(start.row, buffer.line_len(MultiBufferRow(start.row)));
|
||||||
|
|
||||||
if is_last_line {
|
if is_last_line {
|
||||||
start = Point::new(start.row + 1, 0);
|
start = Point::new(start.row + 1, 0);
|
||||||
@ -96,7 +97,7 @@ fn copy_selections_content_internal(
|
|||||||
clipboard_selections.push(ClipboardSelection {
|
clipboard_selections.push(ClipboardSelection {
|
||||||
len: text.len() - initial_len,
|
len: text.len() - initial_len,
|
||||||
is_entire_line: linewise,
|
is_entire_line: linewise,
|
||||||
first_line_indent: buffer.indent_size_for_line(start.row).len,
|
first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use editor::{
|
|||||||
};
|
};
|
||||||
use gpui::{actions, ViewContext, WindowContext};
|
use gpui::{actions, ViewContext, WindowContext};
|
||||||
use language::{Point, Selection, SelectionGoal};
|
use language::{Point, Selection, SelectionGoal};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use search::BufferSearchBar;
|
use search::BufferSearchBar;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{searchable::Direction, Workspace};
|
use workspace::{searchable::Direction, Workspace};
|
||||||
@ -251,9 +252,9 @@ pub fn visual_block_motion(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if tail.row() > head.row() {
|
if tail.row() > head.row() {
|
||||||
row -= 1
|
row.0 -= 1
|
||||||
} else {
|
} else {
|
||||||
row += 1
|
row.0 += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,8 +314,10 @@ pub fn visual_object(object: Object, cx: &mut WindowContext) {
|
|||||||
// trailing newline is included in its selection from the beginning.
|
// trailing newline is included in its selection from the beginning.
|
||||||
if object == Object::Paragraph && range.start != range.end {
|
if object == Object::Paragraph && range.start != range.end {
|
||||||
let row_of_selection_end_line = selection.end.to_point(map).row;
|
let row_of_selection_end_line = selection.end.to_point(map).row;
|
||||||
let new_selection_end =
|
let new_selection_end = if map
|
||||||
if map.buffer_snapshot.line_len(row_of_selection_end_line) == 0
|
.buffer_snapshot
|
||||||
|
.line_len(MultiBufferRow(row_of_selection_end_line))
|
||||||
|
== 0
|
||||||
{
|
{
|
||||||
Point::new(row_of_selection_end_line + 1, 0)
|
Point::new(row_of_selection_end_line + 1, 0)
|
||||||
} else {
|
} else {
|
||||||
|
@ -910,7 +910,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use assets::Assets;
|
use assets::Assets;
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
use editor::{scroll::Autoscroll, DisplayPoint, Editor};
|
use editor::{display_map::DisplayRow, scroll::Autoscroll, DisplayPoint, Editor};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, Action, AnyWindowHandle, AppContext, AssetSource, BorrowAppContext, Entity,
|
actions, Action, AnyWindowHandle, AppContext, AssetSource, BorrowAppContext, Entity,
|
||||||
TestAppContext, VisualTestContext, WindowHandle,
|
TestAppContext, VisualTestContext, WindowHandle,
|
||||||
@ -2229,9 +2229,8 @@ mod tests {
|
|||||||
.update(cx, |_, cx| {
|
.update(cx, |_, cx| {
|
||||||
editor1.update(cx, |editor, cx| {
|
editor1.update(cx, |editor, cx| {
|
||||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
s.select_display_ranges(
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(10), 0)
|
||||||
[DisplayPoint::new(10, 0)..DisplayPoint::new(10, 0)],
|
..DisplayPoint::new(DisplayRow(10), 0)])
|
||||||
)
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -2256,9 +2255,8 @@ mod tests {
|
|||||||
.update(cx, |_, cx| {
|
.update(cx, |_, cx| {
|
||||||
editor3.update(cx, |editor, cx| {
|
editor3.update(cx, |editor, cx| {
|
||||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
s.select_display_ranges(
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(12), 0)
|
||||||
[DisplayPoint::new(12, 0)..DisplayPoint::new(12, 0)],
|
..DisplayPoint::new(DisplayRow(12), 0)])
|
||||||
)
|
|
||||||
});
|
});
|
||||||
editor.newline(&Default::default(), cx);
|
editor.newline(&Default::default(), cx);
|
||||||
editor.newline(&Default::default(), cx);
|
editor.newline(&Default::default(), cx);
|
||||||
@ -2279,7 +2277,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file3.clone(), DisplayPoint::new(16, 0), 12.5)
|
(file3.clone(), DisplayPoint::new(DisplayRow(16), 0), 12.5)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2289,7 +2287,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file3.clone(), DisplayPoint::new(0, 0), 0.)
|
(file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2299,7 +2297,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file2.clone(), DisplayPoint::new(0, 0), 0.)
|
(file2.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2309,7 +2307,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file1.clone(), DisplayPoint::new(10, 0), 0.)
|
(file1.clone(), DisplayPoint::new(DisplayRow(10), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2319,7 +2317,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file1.clone(), DisplayPoint::new(0, 0), 0.)
|
(file1.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Go back one more time and ensure we don't navigate past the first item in the history.
|
// Go back one more time and ensure we don't navigate past the first item in the history.
|
||||||
@ -2330,7 +2328,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file1.clone(), DisplayPoint::new(0, 0), 0.)
|
(file1.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2340,7 +2338,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file1.clone(), DisplayPoint::new(10, 0), 0.)
|
(file1.clone(), DisplayPoint::new(DisplayRow(10), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2350,7 +2348,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file2.clone(), DisplayPoint::new(0, 0), 0.)
|
(file2.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Go forward to an item that has been closed, ensuring it gets re-opened at the same
|
// Go forward to an item that has been closed, ensuring it gets re-opened at the same
|
||||||
@ -2373,7 +2371,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file3.clone(), DisplayPoint::new(0, 0), 0.)
|
(file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2383,7 +2381,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file3.clone(), DisplayPoint::new(16, 0), 12.5)
|
(file3.clone(), DisplayPoint::new(DisplayRow(16), 0), 12.5)
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
@ -2393,7 +2391,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file3.clone(), DisplayPoint::new(0, 0), 0.)
|
(file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Go back to an item that has been closed and removed from disk
|
// Go back to an item that has been closed and removed from disk
|
||||||
@ -2422,7 +2420,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file2.clone(), DisplayPoint::new(0, 0), 0.)
|
(file2.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
||||||
@ -2431,7 +2429,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file3.clone(), DisplayPoint::new(0, 0), 0.)
|
(file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Modify file to collapse multiple nav history entries into the same location.
|
// Modify file to collapse multiple nav history entries into the same location.
|
||||||
@ -2440,9 +2438,8 @@ mod tests {
|
|||||||
.update(cx, |_, cx| {
|
.update(cx, |_, cx| {
|
||||||
editor1.update(cx, |editor, cx| {
|
editor1.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges(
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(15), 0)
|
||||||
[DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)],
|
..DisplayPoint::new(DisplayRow(15), 0)])
|
||||||
)
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -2452,9 +2449,8 @@ mod tests {
|
|||||||
.update(cx, |_, cx| {
|
.update(cx, |_, cx| {
|
||||||
editor1.update(cx, |editor, cx| {
|
editor1.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(3), 0)
|
||||||
DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)
|
..DisplayPoint::new(DisplayRow(3), 0)])
|
||||||
])
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -2464,9 +2460,8 @@ mod tests {
|
|||||||
.update(cx, |_, cx| {
|
.update(cx, |_, cx| {
|
||||||
editor1.update(cx, |editor, cx| {
|
editor1.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(13), 0)
|
||||||
DisplayPoint::new(13, 0)..DisplayPoint::new(13, 0)
|
..DisplayPoint::new(DisplayRow(13), 0)])
|
||||||
])
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -2477,9 +2472,8 @@ mod tests {
|
|||||||
editor1.update(cx, |editor, cx| {
|
editor1.update(cx, |editor, cx| {
|
||||||
editor.transact(cx, |editor, cx| {
|
editor.transact(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(2), 0)
|
||||||
DisplayPoint::new(2, 0)..DisplayPoint::new(14, 0)
|
..DisplayPoint::new(DisplayRow(14), 0)])
|
||||||
])
|
|
||||||
});
|
});
|
||||||
editor.insert("", cx);
|
editor.insert("", cx);
|
||||||
})
|
})
|
||||||
@ -2491,7 +2485,8 @@ mod tests {
|
|||||||
.update(cx, |_, cx| {
|
.update(cx, |_, cx| {
|
||||||
editor1.update(cx, |editor, cx| {
|
editor1.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |s| {
|
editor.change_selections(None, cx, |s| {
|
||||||
s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)])
|
s.select_display_ranges([DisplayPoint::new(DisplayRow(1), 0)
|
||||||
|
..DisplayPoint::new(DisplayRow(1), 0)])
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -2503,7 +2498,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file1.clone(), DisplayPoint::new(2, 0), 0.)
|
(file1.clone(), DisplayPoint::new(DisplayRow(2), 0), 0.)
|
||||||
);
|
);
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
@ -2512,7 +2507,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
active_location(&workspace, cx),
|
active_location(&workspace, cx),
|
||||||
(file1.clone(), DisplayPoint::new(3, 0), 0.)
|
(file1.clone(), DisplayPoint::new(DisplayRow(3), 0), 0.)
|
||||||
);
|
);
|
||||||
|
|
||||||
fn active_location(
|
fn active_location(
|
||||||
|
Loading…
Reference in New Issue
Block a user